1 /* abstract base class for all nip objects
2 */
3
4 /*
5
6 Copyright (C) 1991-2003 The National Gallery
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 */
23
24 /*
25
26 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
27
28 */
29
30 /*
31 #define DEBUG
32 */
33
34 #include "ip.h"
35
36 /* Our signals.
37 */
38 enum {
39 SIG_DESTROY, /* End lifetime */
40 SIG_CHANGED, /* iObject has changed somehow */
41 SIG_LAST
42 };
43
44 static GObjectClass *parent_class = NULL;
45
46 static guint iobject_signals[SIG_LAST] = { 0 };
47
48 /* Don't emit "destroy" immediately, do it from the _dispose handler.
49 */
50 void *
iobject_destroy(iObject * iobject)51 iobject_destroy( iObject *iobject )
52 {
53 #ifdef DEBUG
54 printf( "iobject_destroy: " );
55 iobject_print( iobject );
56 #endif /*DEBUG*/
57
58 if( !iobject->in_destruction )
59 g_object_run_dispose( G_OBJECT( iobject ) );
60
61 return( NULL );
62 }
63
64 void *
iobject_changed(iObject * iobject)65 iobject_changed( iObject *iobject )
66 {
67 g_return_val_if_fail( iobject != NULL, NULL );
68 g_return_val_if_fail( IS_IOBJECT( iobject ), NULL );
69
70 #ifdef DEBUG
71 printf( "iobject_changed: " );
72 iobject_print( iobject );
73 #endif /*DEBUG*/
74
75 g_signal_emit( G_OBJECT( iobject ), iobject_signals[SIG_CHANGED], 0 );
76
77 return( NULL );
78 }
79
80 void *
iobject_info(iObject * iobject,VipsBuf * buf)81 iobject_info( iObject *iobject, VipsBuf *buf )
82 {
83 iObjectClass *iobject_class = IOBJECT_GET_CLASS( iobject );
84
85 g_return_val_if_fail( iobject != NULL, NULL );
86 g_return_val_if_fail( IS_IOBJECT( iobject ), NULL );
87
88 if( iobject_class->info )
89 iobject_class->info( iobject, buf );
90
91 return( NULL );
92 }
93
94 static void
iobject_dispose(GObject * gobject)95 iobject_dispose( GObject *gobject )
96 {
97 iObject *iobject = IOBJECT( gobject );
98
99 #ifdef DEBUG
100 printf( "iobject_dispose: " );
101 iobject_print( iobject );
102 #endif /*DEBUG*/
103
104 if( !iobject->in_destruction ) {
105 iobject->in_destruction = TRUE;
106 g_signal_emit( G_OBJECT( iobject ),
107 iobject_signals[SIG_DESTROY], 0 );
108 iobject->in_destruction = FALSE;
109 }
110
111 G_OBJECT_CLASS( parent_class )->dispose( gobject );
112 }
113
114 static void
iobject_finalize(GObject * gobject)115 iobject_finalize( GObject *gobject )
116 {
117 iObject *iobject = IOBJECT( gobject );
118
119 #ifdef DEBUG
120 printf( "iobject_finalize: " );
121 iobject_print( iobject );
122 #endif /*DEBUG*/
123
124 /* Unlike GTK, we allow floating objects to be finalized. Handy if a
125 * _new() fails. So don't assert( !iobject->floating );
126 */
127
128 IM_FREE( iobject->name );
129 IM_FREE( iobject->caption );
130
131 G_OBJECT_CLASS( parent_class )->finalize( gobject );
132 }
133
134 static void
iobject_real_destroy(iObject * iobject)135 iobject_real_destroy( iObject *iobject )
136 {
137 }
138
139 static void
iobject_real_changed(iObject * iobject)140 iobject_real_changed( iObject *iobject )
141 {
142 iObjectClass *iobject_class = IOBJECT_GET_CLASS( iobject );
143
144 if( iobject_class->generate_caption )
145 IM_SETSTR( iobject->caption,
146 iobject_class->generate_caption( iobject ) );
147 }
148
149 static void
iobject_real_info(iObject * iobject,VipsBuf * buf)150 iobject_real_info( iObject *iobject, VipsBuf *buf )
151 {
152 if( iobject->name )
153 vips_buf_appendf( buf, "name = \"%s\"\n", iobject->name );
154 if( iobject->caption )
155 vips_buf_appendf( buf, "caption = \"%s\"\n", iobject->caption );
156 vips_buf_appendf( buf, "iObject :: \"%s\"\n",
157 G_OBJECT_TYPE_NAME( iobject ) );
158 }
159
160 static void
iobject_class_init(iObjectClass * class)161 iobject_class_init( iObjectClass *class )
162 {
163 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
164
165 parent_class = g_type_class_peek_parent( class );
166
167 gobject_class->dispose = iobject_dispose;
168 gobject_class->finalize = iobject_finalize;
169
170 class->destroy = iobject_real_destroy;
171 class->changed = iobject_real_changed;
172 class->info = iobject_real_info;
173 class->generate_caption = NULL;
174
175 class->user_name = _( "Object" );
176
177 /* Create signals.
178 */
179 iobject_signals[SIG_DESTROY] = g_signal_new( "destroy",
180 G_TYPE_FROM_CLASS( gobject_class ),
181 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
182 G_STRUCT_OFFSET( iObjectClass, destroy ),
183 NULL, NULL,
184 g_cclosure_marshal_VOID__VOID,
185 G_TYPE_NONE, 0 );
186 iobject_signals[SIG_CHANGED] = g_signal_new( "changed",
187 G_OBJECT_CLASS_TYPE( gobject_class ),
188 G_SIGNAL_RUN_FIRST,
189 G_STRUCT_OFFSET( iObjectClass, changed ),
190 NULL, NULL,
191 g_cclosure_marshal_VOID__VOID,
192 G_TYPE_NONE, 0 );
193 }
194
195 static void
iobject_init(iObject * iobject)196 iobject_init( iObject *iobject )
197 {
198 #ifdef DEBUG
199 printf( "iobject_init: " );
200 iobject_print( iobject );
201 #endif /*DEBUG*/
202
203 /* Init our instance fields.
204 */
205 iobject->name = NULL;
206 iobject->caption = NULL;
207 iobject->floating = TRUE;
208 iobject->in_destruction = FALSE;
209 }
210
211 GType
iobject_get_type(void)212 iobject_get_type( void )
213 {
214 static GType iobject_type = 0;
215
216 if( !iobject_type ) {
217 static const GTypeInfo info = {
218 sizeof( iObjectClass ),
219 NULL, /* base_init */
220 NULL, /* base_finalize */
221 (GClassInitFunc) iobject_class_init,
222 NULL, /* class_finalize */
223 NULL, /* class_data */
224 sizeof( iObject ),
225 32, /* n_preallocs */
226 (GInstanceInitFunc) iobject_init,
227 };
228
229 iobject_type = g_type_register_static( G_TYPE_OBJECT,
230 "iObject", &info, 0 );
231 }
232
233 return( iobject_type );
234 }
235
236 /* Test the name field ... handy with map.
237 */
238 void *
iobject_test_name(iObject * iobject,const char * name)239 iobject_test_name( iObject *iobject, const char *name )
240 {
241 g_return_val_if_fail( iobject != NULL, NULL );
242 g_return_val_if_fail( IS_IOBJECT( iobject ), NULL );
243
244 if( iobject->name && strcmp( iobject->name, name ) == 0 )
245 return( iobject );
246
247 return( NULL );
248 }
249
250 void *
iobject_print(iObject * iobject)251 iobject_print( iObject *iobject )
252 {
253 g_print( "%s \"%s\" (%p)\n",
254 G_OBJECT_TYPE_NAME( iobject ),
255 NN( iobject->name ),
256 iobject );
257
258 return( NULL );
259 }
260
261 void
iobject_set(iObject * iobject,const char * name,const char * caption)262 iobject_set( iObject *iobject, const char *name, const char *caption )
263 {
264 gboolean changed = FALSE;
265
266 g_return_if_fail( iobject != NULL );
267 g_return_if_fail( IS_IOBJECT( iobject ) );
268
269 if( name && name != iobject->name ) {
270 IM_SETSTR( iobject->name, name );
271 changed = TRUE;
272 }
273 if( caption && caption != iobject->caption ) {
274 IM_SETSTR( iobject->caption, caption );
275 changed = TRUE;
276 }
277
278 if( changed )
279 iobject_changed( iobject );
280
281 #ifdef DEBUG
282 printf( "iobject_set: " );
283 iobject_print( iobject );
284 #endif /*DEBUG*/
285 }
286
287 void
iobject_sink(iObject * iobject)288 iobject_sink( iObject *iobject )
289 {
290 g_assert( IS_IOBJECT( iobject ) );
291
292 if( iobject->floating ) {
293 iobject->floating = FALSE;
294 g_object_unref( G_OBJECT( iobject ) );
295 }
296 }
297
298 void
iobject_dump(iObject * iobject)299 iobject_dump( iObject *iobject )
300 {
301 char txt[1000];
302 VipsBuf buf = VIPS_BUF_STATIC( txt );
303
304 iobject_info( iobject, &buf );
305 printf( "%s", vips_buf_all( &buf ) );
306 }
307