1 /* gegl-chant contains incantations to that produce the boilerplate
2  * needed to write GEGL operation plug-ins. It abstracts away inheritance
3  * by giving a limited amount of base classes, and reduced creation of
4  * a properties struct and registration of properties for that structure to
5  * a minimum amount of code through use of the C preprocessor. You should
6  * look at the operations implemented using chanting (they #include this file)
7  * to see how it is used in practice.
8  *
9  * GEGL is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * GEGL is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
21  *
22  * 2006-2008 © Øyvind Kolås.
23  */
24 
25 
26 #ifdef GEGL_OP_C_SOURCE
27 #define __GEGL_HEADER(x) #x
28 #define _GEGL_HEADER(x) __GEGL_HEADER(x)
29 #define GEGL_HEADER(x) _GEGL_HEADER(x)
30 
31 #define GEGL_OP_C_FILE GEGL_HEADER(GEGL_OP_C_SOURCE)
32 #endif
33 
34 #ifndef GEGL_OP_NAME
35 #define GEGL_OP_NAME op
36 #error "define GEGL_OP_NAME"
37 
38 #endif
39 
40 #ifndef GEGL_OP_C_FILE
41 #ifdef GEGL_CHANT_C_FILE
42 #error   GEGL_OP_C_FILE not defined, %s/GEGL_CHANT_C_FILE/GEGL_OP_C_FILE/
43 #endif
44 #error "GEGL_OP_C_FILE not defined"
45 #endif
46 
47 /* XXX: */
48 #ifdef GEGL_CHANT_TYPE_POINT_RENDER
49 #error "GEGL_CHANT_TYPE_POINT_RENDER should be replaced with GEGL_OP_POINT_RENDER"
50 #endif
51 
52 #ifdef GEGL_CHANT_PROPERTIES
53 #error "GEGL_CHANT_PROPERTIES should be replaced with GEGL_PROPERTIES"
54 #endif
55 
56 #include <gegl-plugin.h>
57 
58 G_BEGIN_DECLS
59 
60 typedef struct _GeglProperties  GeglProperties;
61 typedef struct _GeglOp   GeglOp;
62 
63 
64 static void gegl_op_init_properties     (GeglOp   *self);
65 static void gegl_op_class_intern_init   (gpointer     klass);
66 static gpointer gegl_op_parent_class = NULL;
67 
68 #define define_register_type_(a) \
69 void gegl_op_##a##_register_type     (GTypeModule *module);\
70 GType gegl_op_##a##_get_type (void);
71 #define define_register_type(a) define_register_type_(a)
72 define_register_type(GEGL_OP_NAME)
73 #undef define_register_type
74 #undef define_register_type_
75 
76 #define GEGL_DEFINE_DYNAMIC_OPERATION_EXTENDED(C_FILE, TypeName, type_name, TYPE_PARENT, flags, CODE) \
77 static void     type_name##_init              (TypeName        *self);  \
78 static void     gegl_op_class_init            (TypeName##Class *klass); \
79 static void     type_name##_class_finalize    (TypeName##Class *klass); \
80 static GType    type_name##_type_id = 0;                                \
81 static void     type_name##_class_chant_intern_init (gpointer klass)    \
82   {                                                                     \
83     gegl_op_parent_class = g_type_class_peek_parent (klass);            \
84     gegl_op_class_intern_init (klass);                                  \
85     gegl_op_class_init ((TypeName##Class*) klass);                      \
86   }                                                                     \
87 GType                                                            \
88 type_name##_get_type (void)                                             \
89   {                                                                     \
90     return type_name##_type_id;                                         \
91   }                                                                     \
92 void                                                             \
93 type_name##_register_type (GTypeModule *type_module)                    \
94   {                                                                     \
95     gchar  tempname[256];                                               \
96     gchar *p;                                                           \
97     const GTypeInfo g_define_type_info =                                \
98     {                                                                   \
99       sizeof (TypeName##Class),                                         \
100       (GBaseInitFunc) NULL,                                             \
101       (GBaseFinalizeFunc) NULL,                                         \
102       (GClassInitFunc) type_name##_class_chant_intern_init,             \
103       (GClassFinalizeFunc) type_name##_class_finalize,                  \
104       NULL,   /* class_data */                                          \
105       sizeof (TypeName),                                                \
106       0,      /* n_preallocs */                                         \
107       (GInstanceInitFunc) type_name##_init,                             \
108       NULL    /* value_table */                                         \
109     };                                                                  \
110     g_snprintf (tempname, sizeof (tempname),                            \
111                 "%s", #TypeName C_FILE);                                \
112     for (p = tempname; *p; p++)                                         \
113       if (*p=='.') *p='_';                                              \
114                                                                         \
115     type_name##_type_id = g_type_module_register_type (type_module,     \
116                                                        TYPE_PARENT,     \
117                                                        tempname,        \
118                                                        &g_define_type_info, \
119                                                        (GTypeFlags) flags); \
120     { CODE ; }                                                          \
121   }
122 
123 #define GEGL_DEFINE_DYNAMIC_OPERATION_(T_P, C_FILE, opname) GEGL_DEFINE_DYNAMIC_OPERATION_EXTENDED(C_FILE, GeglOp, gegl_op_##opname, T_P, 0, {})
124 #define GEGL_DEFINE_DYNAMIC_OPERATION__(a,b,c) GEGL_DEFINE_DYNAMIC_OPERATION_(a,b,c)
125 #define GEGL_DEFINE_DYNAMIC_OPERATION(T_P) GEGL_DEFINE_DYNAMIC_OPERATION__(T_P, GEGL_OP_C_FILE, GEGL_OP_NAME)
126 
127 
128 #define GEGL_PROPERTIES(op) ((GeglProperties *) (((GeglOp*)(op))->properties))
129 
130 #define MKCLASS(a)  MKCLASS2(a)
131 #define MKCLASS2(a) a##Class
132 
133 #ifdef GEGL_OP_BASE
134 #define GEGL_OP_Parent GeglOperation
135 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION
136 #endif
137 
138 #ifdef GEGL_OP_POINT_FILTER
139 #define GEGL_OP_Parent GeglOperationPointFilter
140 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_POINT_FILTER
141 #endif
142 
143 #ifdef GEGL_OP_POINT_COMPOSER
144 #define GEGL_OP_Parent GeglOperationPointComposer
145 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_POINT_COMPOSER
146 #endif
147 
148 #ifdef GEGL_OP_POINT_COMPOSER3
149 #define GEGL_OP_Parent GeglOperationPointComposer3
150 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_POINT_COMPOSER3
151 #endif
152 
153 #ifdef GEGL_OP_POINT_RENDER
154 #define GEGL_OP_Parent GeglOperationPointRender
155 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_POINT_RENDER
156 #endif
157 
158 #ifdef GEGL_OP_AREA_FILTER
159 #define GEGL_OP_Parent GeglOperationAreaFilter
160 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_AREA_FILTER
161 #endif
162 
163 #ifdef GEGL_OP_FILTER
164 #define GEGL_OP_Parent GeglOperationFilter
165 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_FILTER
166 #endif
167 
168 #ifdef GEGL_OP_TEMPORAL
169 #define GEGL_OP_Parent GeglOperationTemporal
170 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_TEMPORAL
171 #endif
172 
173 #ifdef GEGL_OP_SOURCE
174 #define GEGL_OP_Parent GeglOperationSource
175 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_SOURCE
176 #endif
177 
178 #ifdef GEGL_OP_SINK
179 #define GEGL_OP_Parent GeglOperationSink
180 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_SINK
181 #endif
182 
183 #ifdef GEGL_OP_COMPOSER
184 #define GEGL_OP_Parent GeglOperationComposer
185 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_COMPOSER
186 #endif
187 
188 #ifdef GEGL_OP_COMPOSER3
189 #define GEGL_OP_Parent GeglOperationComposer3
190 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_COMPOSER3
191 #endif
192 
193 #ifdef GEGL_OP_META
194 #include <operation/gegl-operation-meta.h>
195 #define GEGL_OP_Parent GeglOperationMeta
196 #define GEGL_OP_PARENT GEGL_TYPE_OPERATION_META
197 #endif
198 
199 
200 #ifdef GEGL_OP_Parent
201 struct _GeglOp
202 {
203   GEGL_OP_Parent parent_instance;
204   gpointer       properties;
205 };
206 
207 typedef struct
208 {
209   MKCLASS(GEGL_OP_Parent)  parent_class;
210 } GeglOpClass;
211 
212 GEGL_DEFINE_DYNAMIC_OPERATION(GEGL_OP_PARENT)
213 
214 #else
215 //#error  "no parent class specified"
216 #endif
217 
218 
219 #define GEGL_OP(obj)  ((GeglOp*)(obj))
220 
221 /* if GEGL_OP_CUSTOM is defined you have to provide the following
222  * code or your own implementation of it
223  */
224 #ifndef GEGL_OP_CUSTOM
225 
226 #define define_init_(a) \
227   static void gegl_op_##a##_init (GeglOp *self) { gegl_op_init_properties (self); }\
228   static void gegl_op_##a##_class_finalize (GeglOpClass *self) { }
229 #define define_init(a) define_init_(a)
230 define_init(GEGL_OP_NAME)
231 #undef define_init
232 #undef define_init_
233 
234 static const GeglModuleInfo modinfo =
235 {
236   GEGL_MODULE_ABI_VERSION
237 };
238 
239 /* prototypes added to silence warnings from gcc for -Wmissing-prototypes*/
240 gboolean                gegl_module_register (GTypeModule *module);
241 const GeglModuleInfo  * gegl_module_query    (GTypeModule *module);
242 
243 #ifndef GEGL_OP_BUNDLE
244 G_MODULE_EXPORT const GeglModuleInfo *
gegl_module_query(GTypeModule * module)245 gegl_module_query (GTypeModule *module)
246 {
247   return &modinfo;
248 }
249 
250 G_MODULE_EXPORT gboolean
gegl_module_register(GTypeModule * module)251 gegl_module_register (GTypeModule *module)
252 {
253 #define do_reg_(a) gegl_op_##a##_register_type (module)
254 #define do_reg(b) do_reg_(b)
255   do_reg(GEGL_OP_NAME);
256 #undef do_reg
257   return TRUE;
258 }
259 #endif
260 #endif
261 
262 
263 #define description(blurb)
264 #define value_range(min,max)
265 #define ui_range(min,max)
266 #define ui_gamma(gamma)
267 #define ui_steps(small_increment, big_increment)
268 #define ui_meta(key,val)
269 #define ui_digits(digits)
270 
271 #define ITEM(name,label,def_val, type)
272 #define ITEM2(name,label,def_val,type) ITEM(name,label,def_val,type)
273 
274 /* enum registration */
275 
276 #define property_double(name, label, def_val)     ITEM(name,label,def_val,double)
277 #define property_int(name, label, def_val)        ITEM(name,label,def_val,int)
278 #define property_string(name, label, def_val)     ITEM(name,label,def_val,string)
279 #define property_file_path(name, label, def_val)  ITEM(name,label,def_val,string)
280 #define property_uri(name, label, def_val)        ITEM(name,label,def_val,string)
281 #define property_boolean(name, label, def_val)    ITEM(name,label,def_val,boolean)
282 #define property_pointer(name, label, def_val)    ITEM(name,label,def_val,pointer)
283 #define property_object(name, label, def_val)     ITEM2(name,label,def_val,object)
284 #define property_enum(name, label, enm, enum_name, def_val)  ITEM(name,label,def_val,pointer)
285 #define property_seed(name, label, rand_name)     ITEM(name,label,def_val,uint)
286 #define property_format(name, label, def_val)     ITEM(name,label,def_val,pointer)
287 #define property_curve(name, label, def_val)      ITEM2(name,label,def_val,object)
288 #define property_path(name, label, def_val)       ITEM2(name,label,def_val,object)
289 #define property_color(name, label, def_val)      ITEM2(name,label,def_val,object)
290 #define property_audio_fragment(name, label, def_val)      ITEM2(name,label,NULL,object)
291 
292 #define enum_start(enum_name)   typedef enum {
293 #define enum_value(value, nick, name)    value ,
294 #define enum_value_skip(value)           value ,
295 #define enum_end(enum)          } enum ;
296 
297 #include GEGL_OP_C_FILE
298 
299 #undef enum_start
300 #undef enum_value
301 #undef enum_value_skip
302 #undef enum_end
303 
304 #ifdef GETTEXT_PACKAGE
305 static const gchar *gegl_op_gettext_package G_GNUC_UNUSED = GETTEXT_PACKAGE;
306 #else
307 static const gchar *gegl_op_gettext_package G_GNUC_UNUSED = NULL;
308 #endif
309 
310 #define enum_start(enum_name)          \
311 static GType enum_name ## _get_type (void) G_GNUC_CONST; \
312 static GType enum_name ## _get_type (void)               \
313 {                                                 \
314   static GType etype = 0;                         \
315   if (etype == 0) {                               \
316     static GEnumValue values[] = {
317 
318 #define enum_value(value, nick, name)                \
319       { value, name, nick },
320 
321 #define enum_value_skip(value)
322 
323 #define enum_end(enum)                                            \
324       { 0, NULL, NULL }                                           \
325     };                                                            \
326     if (gegl_op_gettext_package)                                  \
327       {                                                           \
328         guint i;                                                   \
329         for (i = 0; i < G_N_ELEMENTS (values); i++)               \
330           if (values[i].value_name)                               \
331             values[i].value_name =                                \
332               dgettext (GETTEXT_PACKAGE, values[i].value_name);   \
333       }                                                           \
334     etype = g_enum_register_static (#enum, values);               \
335   }                                                               \
336   return etype;                                                   \
337 }
338 
339 #include GEGL_OP_C_FILE
340 
341 #undef property_double
342 #undef property_int
343 #undef property_string
344 #undef property_boolean
345 #undef property_file_path
346 #undef property_uri
347 #undef property_object
348 #undef property_pointer
349 #undef property_format
350 #undef property_enum
351 #undef property_seed
352 #undef property_curve
353 #undef property_color
354 #undef property_audio_fragment
355 #undef property_path
356 #undef enum_start
357 #undef enum_value
358 #undef enum_value_skip
359 #undef enum_end
360 #define enum_start(enum_name)
361 #define enum_value(value, nick, name)
362 #define enum_value_skip(value)
363 #define enum_end(enum)
364 
365 /* Properties */
366 
367 struct _GeglProperties
368 {
369   gpointer user_data; /* for use by the op implementation */
370 #define property_double(name, label, def_val)          gdouble     name;
371 #define property_int(name, label, def_val)             gint        name;
372 #define property_string(name, label, def_val)          gchar      *name;
373 #define property_boolean(name, label, def_val)         gboolean    name;
374 #define property_file_path(name, label, def_val)       gchar      *name;
375 #define property_uri(name, label, def_val)             gchar      *name;
376 #define property_object(name, label, def_val)          GObject    *name;
377 #define property_curve(name, label, def_val)           GeglCurve  *name;
378 #define property_color(name, label, def_val)           GeglColor  *name;
379 #define property_audio_fragment(name, label, def_val)  GeglAudioFragment  *name;
380 #define property_path(name, label, def_val)            GeglPath   *name; gulong path_changed_handler;
381 #define property_pointer(name, label, def_val)         gpointer    name;
382 #define property_format(name, label, def_val)          gpointer    name;
383 #define property_enum(name, label, enum, enum_name, def_val) enum        name;
384 #define property_seed(name, label, rand_name)          guint       name;\
385                                                        GeglRandom *rand_name;
386 
387 #include GEGL_OP_C_FILE
388 
389 #undef property_double
390 #undef property_int
391 #undef property_string
392 #undef property_boolean
393 #undef property_file_path
394 #undef property_uri
395 #undef property_object
396 #undef property_pointer
397 #undef property_format
398 #undef property_enum
399 #undef property_seed
400 #undef property_curve
401 #undef property_color
402 #undef property_audio_fragment
403 #undef property_path
404 };
405 
406 #define GEGL_OP_OPERATION(obj) ((Operation*)(obj))
407 
408 enum
409 {
410   PROP_0,
411 
412 #undef ITEM
413 #define ITEM(name,label,def_val, type)             PROP_##name,
414 #define ITEM2(name,label,def_val, type)            ITEM(name,label,def_val,type)
415 
416 #define property_double(name, label, def_val)     ITEM(name,label,def_val,double)
417 #define property_int(name, label, def_val)        ITEM(name,label,def_val,int)
418 #define property_string(name, label, def_val)     ITEM(name,label,def_val,string)
419 #define property_file_path(name, label, def_val)  ITEM(name,label,def_val,string)
420 #define property_uri(name, label, def_val)        ITEM(name,label,def_val,string)
421 #define property_boolean(name, label, def_val)    ITEM(name,label,def_val,boolean)
422 #define property_object(name, label, def_val)     ITEM2(name,label,def_val,object)
423 #define property_curve(name, label, def_val)      ITEM2(name,label,def_val,object)
424 #define property_color(name, label, def_val)      ITEM2(name,label,def_val,object)
425 #define property_audio_fragment(name, label, def_val) ITEM2(name,label,def_val,object)
426 #define property_path(name, label, def_val)       ITEM2(name,label,def_val,object)
427 #define property_pointer(name, label, def_val)    ITEM(name,label,def_val,pointer)
428 #define property_format(name, label, def_val)     ITEM(name,label,def_val,pointer)
429 #define property_enum(name, label, enm, enum_name, def_val) ITEM(name,label,def_val,enum)
430 #define property_seed(name, label, rand_name)     ITEM(name,label,def_val,uint)
431 
432 #include GEGL_OP_C_FILE
433 
434 #undef ITEM
435 #define ITEM(name,label,def_val, type) \
436     case PROP_##name:                                         \
437       g_value_set_##type (value, properties->name);           \
438       break;
439 #define ITEM2(name,label,def_val, type)            ITEM(name,label,def_val,type)
440 
441   PROP_LAST
442 };
443 
444 static void
get_property(GObject * gobject,guint property_id,GValue * value,GParamSpec * pspec)445 get_property (GObject      *gobject,
446               guint         property_id,
447               GValue       *value,
448               GParamSpec   *pspec)
449 {
450   GeglProperties *properties;
451 
452   properties = GEGL_PROPERTIES(gobject);
453 
454   switch (property_id)
455   {
456 
457 #include GEGL_OP_C_FILE
458 
459 #undef property_double
460 #undef property_int
461 #undef property_string
462 #undef property_boolean
463 #undef property_file_path
464 #undef property_uri
465 #undef property_object
466 #undef property_pointer
467 #undef property_format
468 #undef property_enum
469 #undef property_seed
470 #undef property_curve
471 #undef property_color
472 #undef property_audio_fragment
473 #undef property_path
474     default:
475       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
476       break;
477   }
478   if (properties) {}; /* silence gcc */
479 }
480 
481 static void
set_property(GObject * gobject,guint property_id,const GValue * value,GParamSpec * pspec)482 set_property (GObject      *gobject,
483               guint         property_id,
484               const GValue *value,
485               GParamSpec   *pspec)
486 {
487   GeglProperties *properties;
488 
489   properties = GEGL_PROPERTIES(gobject);
490 
491   switch (property_id)
492   {
493 #define property_double(name, label, def_val)                         \
494     case PROP_##name:                                                 \
495       properties->name = g_value_get_double (value);                  \
496       break;
497 #define property_int(name, label, def_val)                            \
498     case PROP_##name:                                                 \
499       properties->name = g_value_get_int (value);                     \
500       break;
501 #define property_string(name, label, def_val)                         \
502     case PROP_##name:                                                 \
503       g_free (properties->name);                                      \
504       properties->name = g_value_dup_string (value);                  \
505       break;
506 #define property_boolean(name, label, def_val)                        \
507     case PROP_##name:                                                 \
508       properties->name = g_value_get_boolean (value);                 \
509       break;
510 #define property_file_path(name, label, def_val)                      \
511     case PROP_##name:                                                 \
512       g_free (properties->name);                                      \
513       properties->name = g_value_dup_string (value);                  \
514       break;
515 #define property_uri(name, label, def_val)                            \
516     case PROP_##name:                                                 \
517       g_free (properties->name);                                      \
518       properties->name = g_value_dup_string (value);                  \
519       break;
520 #define property_object(name, label, def_val)                         \
521     case PROP_##name:                                                 \
522       g_clear_object (&properties->name);                             \
523       properties->name = G_OBJECT (g_value_dup_object (value));       \
524       break;
525 #define property_curve(name, label, def_val)                          \
526     case PROP_##name:                                                 \
527       g_clear_object (&properties->name);                             \
528       properties->name = GEGL_CURVE (g_value_dup_object (value));     \
529       break;
530 #define property_color(name, label, def_val)                          \
531     case PROP_##name:                                                 \
532       g_clear_object (&properties->name);                             \
533       properties->name = GEGL_COLOR (g_value_dup_object (value));     \
534       break;
535 #define property_audio_fragment(name, label, def_val)                 \
536     case PROP_##name:                                                 \
537       g_clear_object (&properties->name);                             \
538       properties->name =                                              \
539         GEGL_AUDIO_FRAGMENT (g_value_dup_object (value));              \
540       break;
541 #define property_path(name, label, def_val)                           \
542     case PROP_##name:                                                 \
543       if (properties->name != NULL)                                   \
544         {                                                             \
545           if (properties->path_changed_handler)                       \
546             g_signal_handler_disconnect (G_OBJECT (properties->name), \
547                                          properties->path_changed_handler); \
548           properties->path_changed_handler = 0;                       \
549           g_object_unref (properties->name);                          \
550         }                                                             \
551       properties->name = GEGL_PATH (g_value_dup_object (value));      \
552       if (properties->name != NULL)                                   \
553         {                                                             \
554           properties->path_changed_handler =                          \
555             g_signal_connect (G_OBJECT (properties->name), "changed", \
556                               G_CALLBACK(path_changed), gobject);     \
557          }                                                            \
558       break;
559 #define property_pointer(name, label, def_val)                        \
560     case PROP_##name:                                                 \
561       properties->name = g_value_get_pointer (value);                 \
562       break;
563 #define property_format(name, label, def_val)                         \
564     case PROP_##name:                                                 \
565       properties->name = g_value_get_pointer (value);                 \
566       break;
567 #define property_enum(name, label, enum, enum_name, def_val)          \
568     case PROP_##name:                                                 \
569       properties->name = (enum) g_value_get_enum (value);             \
570       break;
571 #define property_seed(name, label, rand_name)                         \
572     case PROP_##name:                                                 \
573       properties->name = g_value_get_uint (value);                     \
574       if (!properties->rand_name)                                     \
575         properties->rand_name = gegl_random_new_with_seed (properties->name);\
576       else                                                            \
577         gegl_random_set_seed (properties->rand_name, properties->name);\
578       break;
579 
580 #include GEGL_OP_C_FILE
581 
582 #undef property_double
583 #undef property_int
584 #undef property_string
585 #undef property_boolean
586 #undef property_file_path
587 #undef property_uri
588 #undef property_object
589 #undef property_pointer
590 #undef property_curve
591 #undef property_color
592 #undef property_audio_fragment
593 #undef property_path
594 #undef property_format
595 #undef property_enum
596 #undef property_seed
597 
598     default:
599       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
600       break;
601   }
602 
603   if (properties) {}; /* silence gcc */
604 }
605 
gegl_op_destroy_notify(gpointer data)606 static void gegl_op_destroy_notify (gpointer data)
607 {
608   GeglProperties *properties = GEGL_PROPERTIES (data);
609 
610 #define property_double(name, label, def_val)
611 #define property_int(name, label, def_val)
612 #define property_string(name, label, ...)      \
613   g_clear_pointer (&properties->name, g_free);
614 #define property_boolean(name, label, def_val)
615 #define property_file_path(name, label, def_val)    \
616   g_clear_pointer (&properties->name, g_free);
617 #define property_uri(name, label, def_val)          \
618   g_clear_pointer (&properties->name, g_free);
619 #define property_object(name, label, def_val)       \
620   g_clear_object (&properties->name);
621 #define property_curve(name, label, def_val)       \
622   g_clear_object (&properties->name);
623 #define property_color(name, label, def_val)       \
624   g_clear_object (&properties->name);
625 #define property_audio_fragment(name, label, def_val) \
626   g_clear_object (&properties->name);
627 #define property_path(name, label, def_val)         \
628   g_clear_object (&properties->name);
629 #define property_pointer(name, label, ...)
630 #define property_format(name, label, ...)
631 #define property_enum(name, label, ...)
632 #define property_seed(name, label, ...)
633 
634 #include GEGL_OP_C_FILE
635 
636 #undef property_double
637 #undef property_int
638 #undef property_string
639 #undef property_boolean
640 #undef property_file_path
641 #undef property_uri
642 #undef property_object
643 #undef property_pointer
644 #undef property_format
645 #undef property_enum
646 #undef property_seed
647 #undef property_curve
648 #undef property_color
649 #undef property_audio_fragment
650 #undef property_path
651 
652   g_slice_free (GeglProperties, properties);
653 }
654 
655 static GObject *
gegl_op_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)656 gegl_op_constructor (GType                  type,
657                      guint                  n_construct_properties,
658                      GObjectConstructParam *construct_properties)
659 {
660   GObject *obj;
661   GeglProperties *properties;
662 
663   obj = G_OBJECT_CLASS (gegl_op_parent_class)->constructor (
664             type, n_construct_properties, construct_properties);
665 
666   /* create dummy colors and vectors */
667   properties = GEGL_PROPERTIES (obj);
668 
669 #define property_double(name, label, def_val)
670 #define property_int(name, label, def_val)
671 #define property_string(name, label, def_val)
672 #define property_boolean(name, label, def_val)
673 #define property_file_path(name, label, def_val)
674 #define property_uri(name, label, def_val)
675 #define property_object(name, label, def_val)
676 #define property_pointer(name, label, def_val)
677 #define property_format(name, label, def_val)
678 #define property_curve(name, label, def_val)
679 #define property_audio_fragment(name, label, def_val)\
680     if (properties->name == NULL)                   \
681     {properties->name = gegl_audio_fragment_new(48000, 2, 0, 8192);}
682 #define property_color(name, label, def_val)\
683     if (properties->name == NULL)                   \
684     {properties->name = gegl_color_new(def_val?def_val:"black");}
685 #define property_path(name, label, def_val)
686 #define property_enum(name, ...)
687 #define property_seed(name, label, rand_name)    \
688     if (properties->rand_name == NULL)              \
689       {properties->rand_name = gegl_random_new_with_seed (0);}
690 
691 #include GEGL_OP_C_FILE
692 
693 #undef property_double
694 #undef property_int
695 #undef property_string
696 #undef property_boolean
697 #undef property_file_path
698 #undef property_uri
699 #undef property_object
700 #undef property_pointer
701 #undef property_format
702 #undef property_enum
703 #undef property_seed
704 #undef property_curve
705 #undef property_color
706 #undef property_audio_fragment
707 #undef property_path
708 
709   g_object_set_data_full (obj, "chant-data", obj, gegl_op_destroy_notify);
710   properties ++; /* evil hack to silence gcc */
711   return obj;
712 }
713 
has_key(GParamSpec * pspec,const gchar * key,const gchar * value)714 static gboolean has_key (GParamSpec *pspec,
715                          const gchar *key,
716                          const gchar *value)
717 {
718   const char *set_value = gegl_param_spec_get_property_key (pspec, key);
719   if (set_value && g_str_equal (value, set_value))
720     return TRUE;
721   return FALSE;
722 }
723 
724 static void
param_spec_update_ui(GParamSpec * pspec,gboolean ui_range_set,gboolean ui_steps_set,gboolean ui_digits_set)725 param_spec_update_ui (GParamSpec *pspec,
726                       gboolean    ui_range_set,
727                       gboolean    ui_steps_set,
728                       gboolean    ui_digits_set)
729 {
730   if (GEGL_IS_PARAM_SPEC_DOUBLE (pspec))
731     {
732       GeglParamSpecDouble *upspec = GEGL_PARAM_SPEC_DOUBLE (pspec);
733       GParamSpecDouble    *vpspec = G_PARAM_SPEC_DOUBLE (pspec);
734 
735       if (!ui_steps_set)
736         {
737           if (!ui_range_set)
738           {
739             upspec->ui_maximum = vpspec->maximum;
740             upspec->ui_minimum = vpspec->minimum;
741           }
742 
743           if (has_key (pspec, "unit", "degree"))
744             {
745               upspec->ui_step_small = 1.0;
746               upspec->ui_step_big = 15.0;
747             }
748           else if (upspec->ui_maximum <= 5.0)
749             {
750               upspec->ui_step_small = 0.001;
751               upspec->ui_step_big   = 0.100;
752             }
753           else if (upspec->ui_maximum <= 50)
754             {
755               upspec->ui_step_small = 0.01;
756               upspec->ui_step_big   = 1.00;
757             }
758           else if (upspec->ui_maximum <= 500)
759             {
760               upspec->ui_step_small = 1.0;
761               upspec->ui_step_big   = 10.0;
762             }
763           else if (upspec->ui_maximum <= 5000)
764             {
765               upspec->ui_step_small = 1.0;
766               upspec->ui_step_big   = 100.0;
767             }
768         }
769 
770       if (!ui_digits_set)
771       {
772         if (has_key (pspec, "unit", "degrees"))
773         {
774           upspec->ui_digits = 2;
775         }
776         else if (upspec->ui_maximum <= 5.0)
777           {
778             upspec->ui_digits = 4;
779           }
780         if (upspec->ui_maximum <= 50.0)
781           {
782             upspec->ui_digits = 3;
783           }
784         else if (upspec->ui_maximum <= 500)
785           {
786             upspec->ui_digits = 2;
787           }
788         else
789           {
790             upspec->ui_digits = 1;
791           }
792       }
793     }
794   else if (GEGL_IS_PARAM_SPEC_INT (pspec))
795     {
796       GeglParamSpecInt *upspec = GEGL_PARAM_SPEC_INT (pspec);
797       GParamSpecInt    *vpspec = G_PARAM_SPEC_INT (pspec);
798 
799       if (!ui_steps_set)
800         {
801           if (!ui_range_set)
802           {
803             upspec->ui_maximum = vpspec->maximum;
804             upspec->ui_minimum = vpspec->minimum;
805           }
806 
807          if (upspec->ui_maximum <= 5)
808            {
809              upspec->ui_step_small = 1;
810              upspec->ui_step_big   = 2;
811            }
812          else if (upspec->ui_maximum <= 50)
813            {
814              upspec->ui_step_small = 1;
815              upspec->ui_step_big   = 5;
816            }
817          else if (upspec->ui_maximum <= 500)
818            {
819              upspec->ui_step_small = 1;
820              upspec->ui_step_big   = 10;
821            }
822          else if (upspec->ui_maximum <= 5000)
823            {
824              upspec->ui_step_small = 1;
825              upspec->ui_step_big   = 100;
826            }
827         }
828     }
829 }
830 
831 static void
gegl_op_class_intern_init(gpointer klass)832 gegl_op_class_intern_init (gpointer klass)
833 {
834   GObjectClass *object_class = G_OBJECT_CLASS (klass);
835   int current_prop = -1;
836   gboolean G_GNUC_UNUSED ui_range_set = FALSE;
837   gboolean G_GNUC_UNUSED ui_steps_set = FALSE;
838   gboolean G_GNUC_UNUSED ui_digits_set = FALSE;
839   GParamFlags flags G_GNUC_UNUSED = (GParamFlags)(G_PARAM_READWRITE | G_PARAM_CONSTRUCT | GEGL_PARAM_PAD_INPUT);
840 
841   object_class->set_property = set_property;
842   object_class->get_property = get_property;
843   object_class->constructor  = gegl_op_constructor;
844 
845   {
846     GParamSpec *pspec = NULL;
847 
848 #undef description
849 #undef value_range
850 #undef ui_range
851 #undef ui_steps
852 #undef ui_gamma
853 #undef ui_meta
854 #undef ui_digits
855 
856 #define REGISTER_IF_ANY \
857     if (pspec && current_prop >=0) {\
858       param_spec_update_ui (pspec, ui_range_set, ui_steps_set, ui_digits_set);\
859       g_object_class_install_property (object_class, current_prop, pspec);\
860       pspec = NULL; current_prop = -1;\
861       ui_range_set = ui_steps_set = ui_digits_set = FALSE;\
862     }
863 
864 #define description(blurb) \
865     pspec->_blurb = g_strdup (blurb);
866 #define value_range(min,max) \
867     vpspec->minimum = min; vpspec->maximum = max; \
868     upspec->ui_minimum = min; upspec->ui_maximum = max;
869 #define ui_range(min,max) \
870     upspec->ui_minimum = min; upspec->ui_maximum = max;\
871     ui_range_set = TRUE;
872 #define ui_steps(step_small,step_big) \
873     upspec->ui_step_small = step_small; upspec->ui_step_big = step_big; \
874     ui_steps_set = TRUE;
875 #define ui_gamma(gamma) \
876     upspec->ui_gamma = gamma;
877 #define ui_meta(key,val) \
878     gegl_param_spec_set_property_key(pspec, key, val);
879 #define ui_digits(digits) \
880     upspec->ui_digits = digits; \
881     ui_digits_set = TRUE;
882 
883 #define property_double(name, label, def_val) \
884     REGISTER_IF_ANY  \
885   }{ GParamSpec *pspec = \
886        gegl_param_spec_double (#name, label, NULL,-G_MAXDOUBLE,G_MAXDOUBLE,def_val,-100,100,1.0,flags);\
887      GeglParamSpecDouble *upspec G_GNUC_UNUSED = GEGL_PARAM_SPEC_DOUBLE (pspec);\
888      GParamSpecDouble    *vpspec G_GNUC_UNUSED = G_PARAM_SPEC_DOUBLE (pspec);\
889      current_prop = PROP_##name ;
890 
891 #define property_int(name, label, def_val) \
892     REGISTER_IF_ANY  \
893   }{ GParamSpec *pspec = \
894        gegl_param_spec_int (#name, label, NULL,G_MININT,G_MAXINT,def_val,-100,100,1.0,flags);\
895      GeglParamSpecInt *upspec G_GNUC_UNUSED = GEGL_PARAM_SPEC_INT (pspec);\
896      GParamSpecInt    *vpspec G_GNUC_UNUSED = G_PARAM_SPEC_INT (pspec);\
897      current_prop = PROP_##name ;
898 
899 #define property_string(name, label, def_val) \
900     REGISTER_IF_ANY  \
901   }{ GParamSpec *pspec = \
902        g_param_spec_string (#name, label, NULL, def_val, flags);\
903      current_prop = PROP_##name ;
904 
905 #define property_boolean(name, label, def_val) \
906     REGISTER_IF_ANY  \
907   }{ GParamSpec *pspec = \
908        g_param_spec_boolean (#name, label, NULL, def_val, flags);\
909      current_prop = PROP_##name ;
910 
911 #define property_file_path(name, label, def_val) \
912     REGISTER_IF_ANY  \
913   }{ GParamSpec *pspec = \
914        gegl_param_spec_file_path (#name, label, NULL, FALSE, FALSE, def_val, flags);\
915      current_prop = PROP_##name ;
916 
917 #define property_uri(name, label, def_val) \
918     REGISTER_IF_ANY  \
919   }{ GParamSpec *pspec = \
920        gegl_param_spec_uri (#name, label, NULL, FALSE, FALSE, def_val, flags);\
921      current_prop = PROP_##name ;
922 
923 #define property_object(name, label, type) \
924     REGISTER_IF_ANY  \
925   }{ GParamSpec *pspec = \
926        g_param_spec_object (#name, label, NULL, type, flags);\
927      current_prop = PROP_##name ;
928 
929 #define property_curve(name, label, def_val) \
930     REGISTER_IF_ANY  \
931   }{  GeglCurve *_gegl_op_default_curve = gegl_curve_new_default (); \
932     GParamSpec *pspec = \
933        gegl_param_spec_curve (#name, label, NULL, _gegl_op_default_curve, flags);\
934      current_prop = PROP_##name ;\
935      g_object_unref (_gegl_op_default_curve);\
936 
937 #define property_color(name, label, def_val) \
938     REGISTER_IF_ANY  \
939   }{ GParamSpec *pspec = \
940        gegl_param_spec_color_from_string (#name, label, NULL, def_val, flags);\
941      current_prop = PROP_##name ;
942 
943 #define property_audio_fragment(name, label, def_val) \
944     REGISTER_IF_ANY  \
945   }{ GParamSpec *pspec = \
946        gegl_param_spec_audio_fragment (#name, label, NULL, flags);\
947      current_prop = PROP_##name ;
948 
949 #define property_path(name, label, def_val) \
950     REGISTER_IF_ANY  \
951   }{ GParamSpec *pspec = \
952        gegl_param_spec_path (#name, label, NULL, def_val, flags);\
953      current_prop = PROP_##name ;
954 
955 #define property_pointer(name, label, def_val) \
956     REGISTER_IF_ANY  \
957   }{ GParamSpec *pspec = \
958        g_param_spec_pointer (#name, label, NULL, flags);\
959      current_prop = PROP_##name ;
960 
961 #define property_format(name, label, def_val) \
962     REGISTER_IF_ANY  \
963   }{ GParamSpec *pspec = \
964        gegl_param_spec_format (#name, label, NULL, flags);\
965      current_prop = PROP_##name ;
966 
967 #define property_enum(name, label, enum, enum_name, def_val)                   \
968     REGISTER_IF_ANY  \
969   }{ GParamSpec *pspec = gegl_param_spec_enum (#name, label, NULL, enum_name ##_get_type(), def_val, flags);       \
970     current_prop = PROP_##name ;
971 
972 #define property_seed(name, label, rand_name)    \
973     REGISTER_IF_ANY  \
974   }{ GParamSpec *pspec = gegl_param_spec_seed (#name, label, NULL, flags);       \
975     current_prop = PROP_##name ;
976 
977 #include GEGL_OP_C_FILE
978 
979     REGISTER_IF_ANY
980   }
981 
982 #undef REGISTER_IF_ANY
983 #undef description
984 #undef value_range
985 #undef ui_range
986 #undef ui_steps
987 #undef ui_gamma
988 #undef ui_meta
989 #undef property_double
990 #undef property_int
991 #undef property_string
992 #undef property_enum
993 #undef property_seed
994 #undef property_pointer
995 #undef property_path
996 #undef property_curve
997 #undef property_color
998 #undef property_audio_fragment
999 #undef property_object
1000 #undef property_format
1001 
1002 }
1003 
1004 static void
gegl_op_init_properties(GeglOp * self)1005 gegl_op_init_properties (GeglOp *self)
1006 {
1007   self->properties = g_slice_new0 (GeglProperties);
1008 }
1009 
1010 G_END_DECLS
1011