1 /* abstract base class for all vips objects
2 *
3 * Edited from nip's base class, 15/10/08
4 *
5 * 29/5/18
6 * - added vips_argument_get_id()
7 */
8
9 /*
10
11 Copyright (C) 1991-2003 The National Gallery
12
13 This library is free software; you can redistribute it and/or
14 modify it under the terms of the GNU Lesser General Public
15 License as published by the Free Software Foundation; either
16 version 2.1 of the License, or (at your option) any later version.
17
18 This library is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
22
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 02110-1301 USA
27
28 */
29
30 /*
31
32 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
33
34 */
35
36 /*
37 #define DEBUG
38 #define VIPS_DEBUG
39 #define DEBUG_REF
40 */
41
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif /*HAVE_CONFIG_H*/
45 #include <vips/intl.h>
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <stdarg.h>
51
52 #include <vips/vips.h>
53 #include <vips/internal.h>
54 #include <vips/debug.h>
55
56 #include <gobject/gvaluecollector.h>
57
58 #include "vipsmarshal.h"
59
60 /**
61 * SECTION: object
62 * @short_description: the VIPS base object class
63 * @stability: Stable
64 * @see_also: <link linkend="VipsOperation">operation</link>
65 * @include: vips/vips.h
66 *
67 * The #VipsObject class and associated types and macros.
68 *
69 * #VipsObject is the base class for all objects in libvips. It has the
70 * following major features:
71 *
72 * <emphasis>Functional class creation</emphasis> Vips objects have a very
73 * regular lifecycle: initialise, build, use, destroy. They behave rather like
74 * function calls and are free of side-effects.
75 *
76 * <emphasis>Run-time introspection</emphasis> Vips objects can be fully
77 * introspected at run-time. There is no need for separate source-code
78 * analysis.
79 *
80 * <emphasis>Command-line interface</emphasis> Any vips object can be run from
81 * the command-line with the `vips` driver program.
82 *
83 * ## The #VipsObject lifecycle
84 *
85 * #VipsObject s have a strictly defined lifecycle, split broadly as construct
86 * and then use. In detail, the stages are:
87 *
88 * 1. g_object_new(). The #VipsObject is created with g_object_new(). Objects
89 * in this state are blank slates and need to have their various parameters
90 * set.
91 *
92 * 2. g_object_set(). You loop over the #VipsArgument that the object has
93 * defined with vips_argument_map(). Arguments have a set of flags attached to
94 * them for required, optional, input, output, type, and so on. You must set
95 * all required arguments.
96 *
97 * 3. vips_object_build(). Call this to construct the object and get it ready
98 * for use. Building an object happens in four stages, see below.
99 *
100 * 4. g_object_get(). The object has now been built. You can read out any
101 * computed values.
102 *
103 * 5. g_object_unref(). When you are done with an object, you can unref it.
104 * See the section on reference counting for an explanation of the convention
105 * that #VipsObject uses. When the last ref to an object is released, the
106 * object is closed. Objects close in three stages, see below.
107 *
108 * The stages inside vips_object_build() are:
109 *
110 * 1. Chain up through the object's @build class methods. At each stage,
111 * each class does any initial setup and checking, then chains up to its
112 * superclass.
113 *
114 * 2. The innermost @build method inside #VipsObject itself checks that all
115 * input arguments have been set and then returns.
116 *
117 * 3. All object @build methods now finish executing, from innermost to
118 * outermost. They know all input arguments have been checked and supplied, so
119 * now they set all output arguments.
120 *
121 * 4. vips_object_build() finishes the process by checking that all output
122 * objects have been set, and then triggering the #VipsObject::postbuild
123 * signal. #VipsObject::postbuild only runs if the object has constructed
124 * successfuly.
125 *
126 * #VipsOperation has a cache of recent operation objects, see that class for
127 * an explanation of vips_cache_operation_build().
128 *
129 * Finally the stages inside close are:
130 *
131 * 1. #VipsObject::preclose. This is emitted at the start of
132 * the #VipsObject dispose. The object is still functioning.
133 *
134 * 2. #VipsObject::close. This runs just after all #VipsArgument held by
135 * the object have been released.
136 *
137 * 3. #VipsObject::postclose. This runs right at the end. The object
138 * pointer is still valid, but nothing else is.
139 *
140 * ## #VipsArgument
141 *
142 * libvips has a simple mechanism for automating at least some aspects of
143 * %GObject properties. You add a set of macros to your _class_init() which
144 * describe the arguments, and set the get and set functions to the vips ones.
145 *
146 * See <link linkend="extending">extending</link> for a complete example.
147 *
148 * ## The #VipsObject reference counting convention
149 *
150 * #VipsObject has a set of conventions to simplify reference counting.
151 *
152 * 1. All input %GObject have a ref added to them, owned by the object. When a
153 * #VipsObject is unreffed, all of these refs to input objects are
154 * automatically dropped.
155 *
156 * 2. All output %GObject hold a ref to the object. When a %GObject which is an
157 * output of a #VipsObject is disposed, it must drop this reference.
158 * #VipsObject which are outputs of other #VipsObject will do this
159 * automatically.
160 *
161 * See #VipsOperation for an example of #VipsObject reference counting.
162 *
163 */
164
165 /**
166 * VipsArgumentFlags:
167 * @VIPS_ARGUMENT_NONE: no flags
168 * @VIPS_ARGUMENT_REQUIRED: must be set in the constructor
169 * @VIPS_ARGUMENT_CONSTRUCT: can only be set in the constructor
170 * @VIPS_ARGUMENT_SET_ONCE: can only be set once
171 * @VIPS_ARGUMENT_SET_ALWAYS: don't do use-before-set checks
172 * @VIPS_ARGUMENT_INPUT: is an input argument (one we depend on)
173 * @VIPS_ARGUMENT_OUTPUT: is an output argument (depends on us)
174 * @VIPS_ARGUMENT_DEPRECATED: just there for back-compat, hide
175 * @VIPS_ARGUMENT_MODIFY: the input argument will be modified
176 *
177 * Flags we associate with each object argument.
178 *
179 * Have separate input & output flags. Both set is an error; neither set is OK.
180 *
181 * Input gobjects are automatically reffed, output gobjects automatically ref
182 * us. We also automatically watch for "destroy" and unlink.
183 *
184 * @VIPS_ARGUMENT_SET_ALWAYS is handy for arguments which are set from C. For
185 * example, VipsImage::width is a property that gives access to the Xsize
186 * member of struct _VipsImage. We default its 'assigned' to TRUE
187 * since the field is always set directly by C.
188 *
189 * @VIPS_ARGUMENT_DEPRECATED arguments are not shown in help text, are not
190 * looked for if required, are not checked for "have-been-set". You can
191 * deprecate a required argument, but you must obviously add a new required
192 * argument if you do.
193 *
194 * Input args with @VIPS_ARGUMENT_MODIFY will be modified by the operation.
195 * This is used for things like the in-place drawing operations.
196 */
197
198 /* Our signals.
199 */
200 enum {
201 SIG_POSTBUILD,
202 SIG_PRECLOSE,
203 SIG_CLOSE,
204 SIG_POSTCLOSE,
205 SIG_LAST
206 };
207
208 /* Table of all objects, handy for debugging.
209 */
210 static GHashTable *vips__object_all = NULL;
211 static GMutex *vips__object_all_lock = NULL;
212
213 static guint vips_object_signals[SIG_LAST] = { 0 };
214
215 /* This has to be externally visible for compatibility with older libvipses.
216 */
217 int _vips__argument_id = 1;
218
219 /* Keep a cache of nickname -> GType lookups.
220 */
221 static GHashTable *vips__object_nickname_table = NULL;
222
223 G_DEFINE_ABSTRACT_TYPE( VipsObject, vips_object, G_TYPE_OBJECT );
224
225 /**
226 * vips_argument_get_id: (skip)
227 *
228 * Allocate a new property id. See g_object_class_install_property().
229 *
230 * Returns: a new property id > 0
231 */
232 int
vips_argument_get_id(void)233 vips_argument_get_id( void )
234 {
235 int id;
236
237 /* We probably don't need to lock: glib seems to single-thread class
238 * creation.
239 */
240 id = _vips__argument_id++;
241
242 return( id );
243 }
244
245 /* Don't call this directly, see vips_object_build().
246 */
247 static int
vips_object_postbuild(VipsObject * object)248 vips_object_postbuild( VipsObject *object )
249 {
250 int result;
251
252 #ifdef DEBUG
253 printf( "vips_object_postbuild: " );
254 vips_object_print_name( object );
255 printf( "\n" );
256 #endif /*DEBUG*/
257
258 g_signal_emit( object, vips_object_signals[SIG_POSTBUILD], 0, &result );
259
260 return( result );
261 }
262
263 void
vips_object_preclose(VipsObject * object)264 vips_object_preclose( VipsObject *object )
265 {
266 if( !object->preclose ) {
267 object->preclose = TRUE;
268
269 #ifdef DEBUG
270 printf( "vips_object_preclose: " );
271 vips_object_print_name( object );
272 printf( "\n" );
273 #endif /*DEBUG*/
274
275 g_signal_emit( object, vips_object_signals[SIG_PRECLOSE], 0 );
276 }
277 }
278
279 static void
vips_object_close(VipsObject * object)280 vips_object_close( VipsObject *object )
281 {
282 if( !object->close ) {
283 object->close = TRUE;
284
285 #ifdef DEBUG
286 printf( "vips_object_close: " );
287 vips_object_print_name( object );
288 printf( "\n" );
289 #endif /*DEBUG*/
290
291 g_signal_emit( object, vips_object_signals[SIG_CLOSE], 0 );
292 }
293 }
294
295 static void
vips_object_postclose(VipsObject * object)296 vips_object_postclose( VipsObject *object )
297 {
298 if( !object->postclose ) {
299 object->postclose = TRUE;
300
301 #ifdef DEBUG
302 printf( "vips_object_postclose: " );
303 vips_object_print_name( object );
304 printf( "\n" );
305 #endif /*DEBUG*/
306
307 g_signal_emit( object, vips_object_signals[SIG_POSTCLOSE], 0 );
308 }
309 }
310
311 static void *
vips_object_check_required(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)312 vips_object_check_required( VipsObject *object, GParamSpec *pspec,
313 VipsArgumentClass *argument_class,
314 VipsArgumentInstance *argument_instance,
315 void *a, void *b )
316 {
317 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
318
319 int *result = (int *) a;
320 VipsArgumentFlags *iomask = (VipsArgumentFlags *) b;
321
322 VIPS_DEBUG_MSG( "vips_object_check_required: %s\n",
323 g_param_spec_get_name( pspec ) );
324 VIPS_DEBUG_MSG( "\trequired: %d\n",
325 argument_class->flags & VIPS_ARGUMENT_REQUIRED );
326 VIPS_DEBUG_MSG( "\tconstruct: %d\n",
327 argument_class->flags & VIPS_ARGUMENT_CONSTRUCT );
328 VIPS_DEBUG_MSG( "\tinput: %d\n",
329 argument_class->flags & VIPS_ARGUMENT_INPUT );
330 VIPS_DEBUG_MSG( "\toutput: %d\n",
331 argument_class->flags & VIPS_ARGUMENT_OUTPUT );
332 VIPS_DEBUG_MSG( "\tassigned: %d\n",
333 argument_instance->assigned );
334
335 if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
336 (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
337 !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) &&
338 (argument_class->flags & *iomask) &&
339 !argument_instance->assigned ) {
340 vips_error( class->nickname,
341 _( "parameter %s not set" ),
342 g_param_spec_get_name( pspec ) );
343 *result = -1;
344 }
345
346 return( NULL );
347 }
348
349 int
vips_object_build(VipsObject * object)350 vips_object_build( VipsObject *object )
351 {
352 VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
353
354 /* Input and output args must both be set.
355 */
356 VipsArgumentFlags iomask =
357 VIPS_ARGUMENT_INPUT | VIPS_ARGUMENT_OUTPUT;
358
359 int result;
360
361 #ifdef DEBUG
362 printf( "vips_object_build: " );
363 vips_object_print_name( object );
364 printf( "\n" );
365 #endif /*DEBUG*/
366
367 if( object_class->build( object ) )
368 return( -1 );
369
370 /* Check all required arguments have been supplied, don't stop on 1st
371 * error.
372 */
373 result = 0;
374 (void) vips_argument_map( object,
375 vips_object_check_required, &result, &iomask );
376
377 /* ... more checks go here.
378 */
379 object->constructed = TRUE;
380
381 /* Only postbuild on success.
382 */
383 if( !result )
384 result = vips_object_postbuild( object );
385
386 return( result );
387 }
388
389 /**
390 * vips_object_summary_class: (skip)
391 * @klass: class to summarise
392 * @buf: write summary here
393 *
394 * Generate a human-readable summary for a class.
395 */
396 void
vips_object_summary_class(VipsObjectClass * klass,VipsBuf * buf)397 vips_object_summary_class( VipsObjectClass *klass, VipsBuf *buf )
398 {
399 klass->summary_class( klass, buf );
400 }
401
402 /**
403 * vips_object_summary: (skip)
404 * @object: object to summarise
405 * @buf: write summary here
406 *
407 * Generate a human-readable summary for an object.
408 */
409 void
vips_object_summary(VipsObject * object,VipsBuf * buf)410 vips_object_summary( VipsObject *object, VipsBuf *buf )
411 {
412 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
413
414 class->summary( object, buf );
415 }
416
417 /**
418 * vips_object_dump: (skip)
419 * @object: object to dump
420 * @buf: write dump here
421 *
422 * Dump everything that vips knows about an object to a string.
423 */
424 void
vips_object_dump(VipsObject * object,VipsBuf * buf)425 vips_object_dump( VipsObject *object, VipsBuf *buf )
426 {
427 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
428
429 class->dump( object, buf );
430 }
431
432 void
vips_object_print_summary_class(VipsObjectClass * class)433 vips_object_print_summary_class( VipsObjectClass *class )
434 {
435 char str[2048];
436 VipsBuf buf = VIPS_BUF_STATIC( str );
437
438 vips_object_summary_class( class, &buf );
439 printf( "%s\n", vips_buf_all( &buf ) );
440 }
441
442 void
vips_object_print_summary(VipsObject * object)443 vips_object_print_summary( VipsObject *object )
444 {
445 char str[2048];
446 VipsBuf buf = VIPS_BUF_STATIC( str );
447
448 vips_object_summary( object, &buf );
449 printf( "%s\n", vips_buf_all( &buf ) );
450 }
451
452 void
vips_object_print_dump(VipsObject * object)453 vips_object_print_dump( VipsObject *object )
454 {
455 char str[32768];
456 VipsBuf buf = VIPS_BUF_STATIC( str );
457
458 vips_object_dump( object, &buf );
459 printf( "%s\n", vips_buf_all( &buf ) );
460 }
461
462 void
vips_object_print_name(VipsObject * object)463 vips_object_print_name( VipsObject *object )
464 {
465 printf( "%s (%p)", G_OBJECT_TYPE_NAME( object ), object );
466 }
467
468 gboolean
vips_object_sanity(VipsObject * object)469 vips_object_sanity( VipsObject *object )
470 {
471 VipsObjectClass *class;
472 char str[1000];
473 VipsBuf buf = VIPS_BUF_STATIC( str );
474
475 if( !object ) {
476 printf( "vips_object_sanity: null object\n" );
477
478 return( FALSE );
479 }
480
481 class = VIPS_OBJECT_GET_CLASS( object );
482 class->sanity( object, &buf );
483 if( !vips_buf_is_empty( &buf ) ) {
484 printf( "sanity failure: " );
485 vips_object_print_name( object );
486 printf( " %s\n", vips_buf_all( &buf ) );
487
488 return( FALSE );
489 }
490
491 return( TRUE );
492 }
493
494 /* On a rewind, we dispose the old contents of the object and
495 * reconstruct. This is used in things like im_pincheck() where a "w"
496 * image has to be rewound and become a "p" image.
497 *
498 * Override in subclasses if you want to preserve some fields, see image.c.
499 */
500 void
vips_object_rewind(VipsObject * object)501 vips_object_rewind( VipsObject *object )
502 {
503 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
504
505 class->rewind( object );
506 }
507
508 /* Extra stuff we track for properties to do our argument handling.
509 */
510
511 static void
vips_argument_instance_detach(VipsArgumentInstance * argument_instance)512 vips_argument_instance_detach( VipsArgumentInstance *argument_instance )
513 {
514 VipsObject *object = argument_instance->object;
515 VipsArgumentClass *argument_class = argument_instance->argument_class;
516
517 if( argument_instance->close_id ) {
518 /* If close_id is set, the argument must be a gobject of some
519 * sort, so we can fetch it.
520 */
521 GObject *member = G_STRUCT_MEMBER( GObject *, object,
522 argument_class->offset );
523
524 if( g_signal_handler_is_connected( member,
525 argument_instance->close_id ) )
526 g_signal_handler_disconnect( member,
527 argument_instance->close_id );
528 argument_instance->close_id = 0;
529 }
530
531 if( argument_instance->invalidate_id ) {
532 GObject *member = G_STRUCT_MEMBER( GObject *, object,
533 argument_class->offset );
534
535 if( g_signal_handler_is_connected( member,
536 argument_instance->invalidate_id ) )
537 g_signal_handler_disconnect( member,
538 argument_instance->invalidate_id );
539 argument_instance->invalidate_id = 0;
540 }
541 }
542
543 /* Free a VipsArgumentInstance ... VipsArgumentClass can just be g_free()d.
544 */
545 static void
vips_argument_instance_free(VipsArgumentInstance * argument_instance)546 vips_argument_instance_free( VipsArgumentInstance *argument_instance )
547 {
548 vips_argument_instance_detach( argument_instance );
549 g_free( argument_instance );
550 }
551
552 VipsArgument *
vips__argument_table_lookup(VipsArgumentTable * table,GParamSpec * pspec)553 vips__argument_table_lookup( VipsArgumentTable *table, GParamSpec *pspec )
554 {
555 VipsArgument *argument;
556
557 g_mutex_lock( vips__global_lock );
558 argument = (VipsArgument *) g_hash_table_lookup( table, pspec );
559 g_mutex_unlock( vips__global_lock );
560
561 return( argument );
562 }
563
564 static void
vips_argument_table_replace(VipsArgumentTable * table,VipsArgument * argument)565 vips_argument_table_replace( VipsArgumentTable *table, VipsArgument *argument )
566 {
567 g_hash_table_replace( table, argument->pspec, argument );
568 }
569
570 static void
vips_argument_table_destroy(VipsArgumentTable * table)571 vips_argument_table_destroy( VipsArgumentTable *table )
572 {
573 g_hash_table_destroy( table );
574 }
575
576 /**
577 * vips_argument_map: (skip)
578 * @object: object whose args should be enumerated
579 * @fn: call this function for every argument
580 * @a: client data
581 * @b: client data
582 *
583 * Loop over the vips_arguments to an object. Stop when @fn returns non-%NULL
584 * and return that value.
585 *
586 * Returns: %NULL if @fn returns %NULL for all arguments, otherwise the first
587 * non-%NULL value from @fn.
588 */
589 void *
vips_argument_map(VipsObject * object,VipsArgumentMapFn fn,void * a,void * b)590 vips_argument_map( VipsObject *object,
591 VipsArgumentMapFn fn, void *a, void *b )
592 {
593 /* Make sure we can't go during the loop. This can happen if eg. we
594 * flush an arg that refs us.
595 */
596 g_object_ref( object );
597
598 VIPS_ARGUMENT_FOR_ALL( object,
599 pspec, argument_class, argument_instance ) {
600 void *result;
601
602 /* argument_instance should not be NULL.
603 */
604 g_assert( argument_instance );
605
606 if( (result = fn( object, pspec,
607 argument_class, argument_instance, a, b )) ) {
608 g_object_unref( object );
609 return( result );
610 }
611 } VIPS_ARGUMENT_FOR_ALL_END
612
613 g_object_unref( object );
614
615 return( NULL );
616 }
617
618 /**
619 * vips_argument_class_map: (skip)
620 *
621 * And loop over a class. Same as ^^, but with no VipsArgumentInstance.
622 */
623 void *
vips_argument_class_map(VipsObjectClass * object_class,VipsArgumentClassMapFn fn,void * a,void * b)624 vips_argument_class_map( VipsObjectClass *object_class,
625 VipsArgumentClassMapFn fn, void *a, void *b )
626 {
627 GSList *p;
628
629 for( p = object_class->argument_table_traverse; p; p = p->next ) {
630 VipsArgumentClass *arg_class =
631 (VipsArgumentClass *) p->data;
632 VipsArgument *argument = (VipsArgument *) arg_class;
633 GParamSpec *pspec = argument->pspec;
634
635 void *result;
636
637 if( (result =
638 fn( object_class, pspec, arg_class, a, b )) )
639 return( result );
640 }
641
642 return( NULL );
643 }
644
645 /* Does an vipsargument need an argument to write to? For example, an image
646 * output needs a filename, a double output just prints.
647 */
648 gboolean
vips_argument_class_needsstring(VipsArgumentClass * argument_class)649 vips_argument_class_needsstring( VipsArgumentClass *argument_class )
650 {
651 GParamSpec *pspec = ((VipsArgument *) argument_class)->pspec;
652
653 GType otype;
654 VipsObjectClass *oclass;
655
656 if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) )
657 /* Bools, input or output, don't need args.
658 */
659 return( FALSE );
660
661 if( argument_class->flags & VIPS_ARGUMENT_INPUT )
662 /* All other inputs need something.
663 */
664 return( TRUE );
665
666 /* Just output objects.
667 */
668
669 if( (otype = G_PARAM_SPEC_VALUE_TYPE( pspec )) &&
670 g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
671 (oclass = g_type_class_ref( otype )) )
672 /* For now, only vipsobject subclasses can ask for args.
673 */
674 return( oclass->output_needs_arg );
675 else
676 return( FALSE );
677 }
678
679 /* Create a VipsArgumentInstance for each installed argument property. Ideally
680 * we'd do this during _init() but g_object_class_find_property() does not seem
681 * to work then :-( so we have to delay it until first access. See
682 * vips__argument_get_instance().
683 */
684 static void
vips_argument_init(VipsObject * object)685 vips_argument_init( VipsObject *object )
686 {
687 if( !object->argument_table ) {
688 #ifdef DEBUG
689 printf( "vips_argument_init: " );
690 vips_object_print_name( object );
691 printf( "\n" );
692 #endif /*DEBUG*/
693
694 object->argument_table = g_hash_table_new_full( g_direct_hash,
695 g_direct_equal, NULL,
696 (GDestroyNotify) vips_argument_instance_free );
697
698 /* Make a VipsArgumentInstance for each installed argument
699 * property. We can't use vips_argument_map() since that does
700 * some sanity checks that won't pass until all arg instance
701 * are built.
702 */
703 VIPS_ARGUMENT_FOR_ALL( object,
704 pspec, argument_class, argument_instance ) {
705 #ifdef DEBUG
706 printf( "vips_argument_init: "
707 "adding instance argument for %s\n",
708 g_param_spec_get_name( pspec ) );
709 #endif /*DEBUG*/
710
711 /* argument_instance should be NULL since we've not
712 * set it yet.
713 */
714 g_assert( argument_instance == NULL );
715
716 argument_instance = g_new( VipsArgumentInstance, 1 );
717
718 ((VipsArgument *) argument_instance)->pspec = pspec;
719 argument_instance->argument_class = argument_class;
720 argument_instance->object = object;
721 /* SET_ALWAYS args default to assigned.
722 */
723 argument_instance->assigned =
724 argument_class->flags &
725 VIPS_ARGUMENT_SET_ALWAYS;
726 argument_instance->close_id = 0;
727 argument_instance->invalidate_id = 0;
728
729 vips_argument_table_replace( object->argument_table,
730 (VipsArgument *) argument_instance );
731 } VIPS_ARGUMENT_FOR_ALL_END
732 }
733 }
734
735 /**
736 * vips__argument_get_instance: (skip)
737 *
738 * Convenience ... given the VipsArgumentClass, get the VipsArgumentInstance.
739 */
740 VipsArgumentInstance *
vips__argument_get_instance(VipsArgumentClass * argument_class,VipsObject * object)741 vips__argument_get_instance( VipsArgumentClass *argument_class,
742 VipsObject *object )
743 {
744 /* Make sure the instance args are built.
745 */
746 vips_argument_init( object );
747
748 return( (VipsArgumentInstance *)
749 vips__argument_table_lookup( object->argument_table,
750 ((VipsArgument *) argument_class)->pspec ) );
751 }
752
753 /**
754 * vips_object_get_argument: (skip)
755 * @object: the object to fetch the args from
756 * @name: arg to fetch
757 * @pspec: (transfer none): the pspec for this arg
758 * @argument_class: (transfer none): the argument_class for this arg
759 * @argument_instance: (transfer none): the argument_instance for this arg
760 *
761 * Look up the three things you need to work with a vips argument.
762 *
763 * Returns: 0 on success, or -1 on error.
764 */
765 int
vips_object_get_argument(VipsObject * object,const char * name,GParamSpec ** pspec,VipsArgumentClass ** argument_class,VipsArgumentInstance ** argument_instance)766 vips_object_get_argument( VipsObject *object, const char *name,
767 GParamSpec **pspec,
768 VipsArgumentClass **argument_class,
769 VipsArgumentInstance **argument_instance )
770 {
771 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
772
773 if( !(*pspec = g_object_class_find_property(
774 G_OBJECT_CLASS( class ), name )) ) {
775 vips_error( class->nickname,
776 _( "no property named `%s'" ), name );
777 return( -1 );
778 }
779
780 if( !(*argument_class = (VipsArgumentClass *)
781 vips__argument_table_lookup( class->argument_table,
782 *pspec )) ) {
783 vips_error( class->nickname,
784 _( "no vips argument named `%s'" ), name );
785 return( -1 );
786 }
787 if( !(*argument_instance = vips__argument_get_instance(
788 *argument_class, object )) ) {
789 vips_error( class->nickname,
790 _( "argument `%s' has no instance" ), name );
791 return( -1 );
792 }
793
794 return( 0 );
795 }
796
797 /**
798 * vips_object_argument_isset:
799 * @object: the object to fetch the args from
800 * @name: arg to fetch
801 *
802 * Convenience: has an argument been assigned. Useful for bindings.
803 *
804 * Returns: %TRUE if the argument has been assigned.
805 */
806 gboolean
vips_object_argument_isset(VipsObject * object,const char * name)807 vips_object_argument_isset( VipsObject *object, const char *name )
808 {
809 GParamSpec *pspec;
810 VipsArgumentClass *argument_class;
811 VipsArgumentInstance *argument_instance;
812
813 if( vips_object_get_argument( object, name,
814 &pspec, &argument_class, &argument_instance ) )
815 return( FALSE );
816
817 return( argument_instance->assigned );
818 }
819
820 /**
821 * vips_object_get_argument_flags:
822 * @object: the object to fetch the args from
823 * @name: arg to fetch
824 *
825 * Convenience: get the flags for an argument. Useful for bindings.
826 *
827 * Returns: The #VipsArgumentFlags for this argument.
828 */
829 VipsArgumentFlags
vips_object_get_argument_flags(VipsObject * object,const char * name)830 vips_object_get_argument_flags( VipsObject *object, const char *name )
831 {
832 GParamSpec *pspec;
833 VipsArgumentClass *argument_class;
834 VipsArgumentInstance *argument_instance;
835
836 if( vips_object_get_argument( object, name,
837 &pspec, &argument_class, &argument_instance ) )
838 return( 0 );
839
840 return( argument_class->flags );
841 }
842
843 /**
844 * vips_object_get_argument_priority:
845 * @object: the object to fetch the args from
846 * @name: arg to fetch
847 *
848 * Convenience: get the priority for an argument. Useful for bindings.
849 *
850 * Returns: The priority of this argument.
851 */
852 int
vips_object_get_argument_priority(VipsObject * object,const char * name)853 vips_object_get_argument_priority( VipsObject *object, const char *name )
854 {
855 GParamSpec *pspec;
856 VipsArgumentClass *argument_class;
857 VipsArgumentInstance *argument_instance;
858
859 if( vips_object_get_argument( object, name,
860 &pspec, &argument_class, &argument_instance ) )
861 return( 0 );
862
863 return( argument_class->priority );
864 }
865
866 static void
vips_object_clear_member(VipsArgumentInstance * argument_instance)867 vips_object_clear_member( VipsArgumentInstance *argument_instance )
868 {
869 VipsObject *object = argument_instance->object;
870 VipsArgumentClass *argument_class = argument_instance->argument_class;
871 GObject **member = &G_STRUCT_MEMBER( GObject *, object,
872 argument_class->offset );
873
874 vips_argument_instance_detach( argument_instance );
875
876 if( *member ) {
877 if( argument_class->flags & VIPS_ARGUMENT_INPUT ) {
878 #ifdef DEBUG_REF
879 printf( "vips_object_clear_member: vips object: " );
880 vips_object_print_name( object );
881 printf( " no longer refers to gobject %s (%p)\n",
882 G_OBJECT_TYPE_NAME( *member ), *member );
883 printf( " count down to %d\n",
884 G_OBJECT( *member )->ref_count - 1 );
885 #endif /*DEBUG_REF*/
886
887 /* We reffed the object.
888 */
889 g_object_unref( *member );
890 }
891 else if( argument_class->flags & VIPS_ARGUMENT_OUTPUT ) {
892 #ifdef DEBUG_REF
893 printf( "vips_object_clear_member: gobject %s (%p)\n",
894 G_OBJECT_TYPE_NAME( *member ), *member );
895 printf( " no longer refers to vips object: " );
896 vips_object_print_name( object );
897 printf( " count down to %d\n",
898 G_OBJECT( object )->ref_count - 1 );
899 #endif /*DEBUG_REF*/
900
901 g_object_unref( object );
902 }
903
904 *member = NULL;
905 }
906 }
907
908 /* Free any args which are holding resources.
909 */
910 static void *
vips_object_dispose_argument(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)911 vips_object_dispose_argument( VipsObject *object, GParamSpec *pspec,
912 VipsArgumentClass *argument_class,
913 VipsArgumentInstance *argument_instance,
914 void *a, void *b )
915 {
916 g_assert( ((VipsArgument *) argument_class)->pspec == pspec );
917 g_assert( ((VipsArgument *) argument_instance)->pspec == pspec );
918
919 if( G_IS_PARAM_SPEC_OBJECT( pspec ) ||
920 G_IS_PARAM_SPEC_BOXED( pspec ) ) {
921 #ifdef DEBUG
922 printf( "vips_object_dispose_argument: " );
923 vips_object_print_name( object );
924 printf( ".%s\n", g_param_spec_get_name( pspec ) );
925 #endif /*DEBUG*/
926
927 g_object_set( object,
928 g_param_spec_get_name( pspec ), NULL,
929 NULL );
930 }
931
932 return( NULL );
933 }
934
935 /* Free all args on this object which may be holding resources.
936 *
937 * Note that this is not the same as vips_object_unref_outputs(). That
938 * looks for output objects which may have been created during _build() which
939 * hold refs to this object and unrefs them.
940 *
941 * This function looks for objects which this object holds refs to and which
942 * may be holding sub-resources and zaps them.
943 */
944 static void
vips_argument_dispose_all(VipsObject * object)945 vips_argument_dispose_all( VipsObject *object )
946 {
947 #ifdef DEBUG
948 printf( "vips_argument_dispose_all: " );
949 vips_object_print_name( object );
950 printf( "\n" );
951 #endif /*DEBUG*/
952
953 vips_argument_map( object, vips_object_dispose_argument, NULL, NULL );
954 }
955
956 /* Free any args which are holding memory.
957 */
958 static void *
vips_object_free_argument(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)959 vips_object_free_argument( VipsObject *object, GParamSpec *pspec,
960 VipsArgumentClass *argument_class,
961 VipsArgumentInstance *argument_instance,
962 void *a, void *b )
963 {
964 g_assert( ((VipsArgument *) argument_class)->pspec == pspec );
965 g_assert( ((VipsArgument *) argument_instance)->pspec == pspec );
966
967 if( G_IS_PARAM_SPEC_STRING( pspec ) ) {
968 #ifdef DEBUG
969 printf( "vips_object_free_argument: " );
970 vips_object_print_name( object );
971 printf( ".%s\n", g_param_spec_get_name( pspec ) );
972 #endif /*DEBUG*/
973
974 g_object_set( object,
975 g_param_spec_get_name( pspec ), NULL,
976 NULL );
977 }
978
979 return( NULL );
980 }
981
982 /* Free args which hold memory. Things like strings need to be freed right at
983 * the end in case anyone is still using them.
984 */
985 static void
vips_argument_free_all(VipsObject * object)986 vips_argument_free_all( VipsObject *object )
987 {
988 #ifdef DEBUG
989 printf( "vips_argument_free_all: " );
990 vips_object_print_name( object );
991 printf( "\n" );
992 #endif /*DEBUG*/
993
994 vips_argument_map( object, vips_object_free_argument, NULL, NULL );
995 }
996
997 static void
vips_object_dispose(GObject * gobject)998 vips_object_dispose( GObject *gobject )
999 {
1000 VipsObject *object = VIPS_OBJECT( gobject );
1001
1002 #ifdef DEBUG
1003 printf( "vips_object_dispose: " );
1004 vips_object_print_name( object );
1005 printf( "\n" );
1006 #endif /*DEBUG*/
1007
1008 /* Our subclasses should have already called this. Run it again, just
1009 * in case.
1010 */
1011 #ifdef DEBUG
1012 if( !object->preclose )
1013 printf( "vips_object_dispose: pre-close missing!\n" );
1014 #endif /*DEBUG*/
1015 vips_object_preclose( object );
1016
1017 /* Clear all our arguments: they may be holding resources we should
1018 * drop.
1019 */
1020 vips_argument_dispose_all( object );
1021
1022 vips_object_close( object );
1023
1024 vips_object_postclose( object );
1025
1026 vips_argument_free_all( object );
1027
1028 VIPS_FREEF( vips_argument_table_destroy, object->argument_table );
1029
1030 G_OBJECT_CLASS( vips_object_parent_class )->dispose( gobject );
1031 }
1032
1033 static void
vips_object_finalize(GObject * gobject)1034 vips_object_finalize( GObject *gobject )
1035 {
1036 VipsObject *object = VIPS_OBJECT( gobject );
1037
1038 #ifdef DEBUG
1039 printf( "vips_object_finalize: " );
1040 vips_object_print_name( object );
1041 printf( "\n" );
1042 #endif /*DEBUG*/
1043
1044 /* I'd like to have post-close in here, but you can't emit signals
1045 * from finalize, sadly.
1046 */
1047
1048 g_mutex_lock( vips__object_all_lock );
1049 g_hash_table_remove( vips__object_all, object );
1050 g_mutex_unlock( vips__object_all_lock );
1051
1052 G_OBJECT_CLASS( vips_object_parent_class )->finalize( gobject );
1053 }
1054
1055 static void
vips_object_arg_invalidate(GObject * argument,VipsArgumentInstance * argument_instance)1056 vips_object_arg_invalidate( GObject *argument,
1057 VipsArgumentInstance *argument_instance )
1058 {
1059 /* Image @argument has signalled "invalidate" ... resignal on our
1060 * operation.
1061 */
1062 if( VIPS_IS_OPERATION( argument_instance->object ) )
1063 vips_operation_invalidate(
1064 VIPS_OPERATION( argument_instance->object ) );
1065 }
1066
1067 static void
vips_object_arg_close(GObject * argument,VipsArgumentInstance * argument_instance)1068 vips_object_arg_close( GObject *argument,
1069 VipsArgumentInstance *argument_instance )
1070 {
1071 VipsObject *object = argument_instance->object;
1072 GParamSpec *pspec = ((VipsArgument *) argument_instance)->pspec;
1073
1074 /* Argument had reffed us ... now it's being closed, so we NULL out
1075 * the pointer to unref.
1076 */
1077 g_object_set( object,
1078 g_param_spec_get_name( pspec ), NULL,
1079 NULL );
1080 }
1081
1082 /* Set a member to an object. Handle the ref counts and signal
1083 * connect/disconnect.
1084 */
1085 void
vips__object_set_member(VipsObject * object,GParamSpec * pspec,GObject ** member,GObject * argument)1086 vips__object_set_member( VipsObject *object, GParamSpec *pspec,
1087 GObject **member, GObject *argument )
1088 {
1089 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
1090 VipsArgumentClass *argument_class = (VipsArgumentClass *)
1091 vips__argument_table_lookup( class->argument_table, pspec );
1092 VipsArgumentInstance *argument_instance =
1093 vips__argument_get_instance( argument_class, object );
1094 GType otype = G_PARAM_SPEC_VALUE_TYPE( pspec );
1095
1096 g_assert( argument_instance );
1097
1098 vips_object_clear_member( argument_instance );
1099
1100 g_assert( !*member );
1101 *member = argument;
1102
1103 if( *member ) {
1104 if( argument_class->flags & VIPS_ARGUMENT_INPUT ) {
1105 #ifdef DEBUG_REF
1106 printf( "vips__object_set_member: vips object: " );
1107 vips_object_print_name( object );
1108 printf( " refers to gobject %s (%p)\n",
1109 G_OBJECT_TYPE_NAME( *member ), *member );
1110 printf( " count up to %d\n",
1111 G_OBJECT( *member )->ref_count );
1112 #endif /*DEBUG_REF*/
1113
1114 /* Ref the argument.
1115 */
1116 g_object_ref( *member );
1117 }
1118 else if( argument_class->flags & VIPS_ARGUMENT_OUTPUT ) {
1119 #ifdef DEBUG_REF
1120 printf( "vips__object_set_member: gobject %s (%p)\n",
1121 G_OBJECT_TYPE_NAME( *member ), *member );
1122 printf( " refers to vips object: " );
1123 vips_object_print_name( object );
1124 printf( " count up to %d\n",
1125 G_OBJECT (object)->ref_count );
1126 #endif /*DEBUG_REF*/
1127
1128 /* The argument reffs us.
1129 */
1130 g_object_ref( object );
1131 }
1132 }
1133
1134 if( *member &&
1135 g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) {
1136 if( argument_class->flags & VIPS_ARGUMENT_INPUT ) {
1137 g_assert( !argument_instance->invalidate_id );
1138
1139 argument_instance->invalidate_id =
1140 g_signal_connect( *member, "invalidate",
1141 G_CALLBACK(
1142 vips_object_arg_invalidate ),
1143 argument_instance );
1144 }
1145 else if( argument_class->flags & VIPS_ARGUMENT_OUTPUT ) {
1146 g_assert( !argument_instance->close_id );
1147
1148 argument_instance->close_id =
1149 g_signal_connect( *member, "close",
1150 G_CALLBACK( vips_object_arg_close ),
1151 argument_instance );
1152 }
1153 }
1154 }
1155
1156 /* Is a value NULL? We allow multiple sets of NULL so props can be cleared.
1157 * The pspec gives the value type, for consistency with the way value types
1158 * are detected in set and get.
1159 */
1160 gboolean
vips_value_is_null(GParamSpec * pspec,const GValue * value)1161 vips_value_is_null( GParamSpec *pspec, const GValue *value )
1162 {
1163 if( G_IS_PARAM_SPEC_STRING( pspec ) &&
1164 !g_value_get_string( value ) )
1165 return( TRUE );
1166 if( G_IS_PARAM_SPEC_OBJECT( pspec ) &&
1167 !g_value_get_object( value ) )
1168 return( TRUE );
1169 if( G_IS_PARAM_SPEC_POINTER( pspec ) &&
1170 !g_value_get_pointer( value ) )
1171 return( TRUE );
1172 if( G_IS_PARAM_SPEC_BOXED( pspec ) &&
1173 !g_value_get_boxed( value ) )
1174 return( TRUE );
1175
1176 return( FALSE );
1177 }
1178
1179 /* Also used by subclasses, so not static.
1180 */
1181 void
vips_object_set_property(GObject * gobject,guint property_id,const GValue * value,GParamSpec * pspec)1182 vips_object_set_property( GObject *gobject,
1183 guint property_id, const GValue *value, GParamSpec *pspec )
1184 {
1185 VipsObject *object = VIPS_OBJECT( gobject );
1186 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( gobject );
1187 VipsArgumentClass *argument_class = (VipsArgumentClass *)
1188 vips__argument_table_lookup( class->argument_table, pspec );
1189 VipsArgumentInstance *argument_instance =
1190 vips__argument_get_instance( argument_class, object );
1191
1192 g_assert( argument_instance );
1193
1194 #ifdef DEBUG
1195 printf( "vips_object_set_property: " );
1196 vips_object_print_name( object );
1197 printf( ".%s\n", g_param_spec_get_name( pspec ) );
1198
1199 /* This can crash horribly with some values, have it as a separate
1200 * chunk so we can easily comment it out.
1201 */
1202 {
1203 char *str_value;
1204
1205 str_value = g_strdup_value_contents( value );
1206 printf( "\t%s\n", str_value );
1207 g_free( str_value );
1208 }
1209 #endif /*DEBUG*/
1210
1211 g_assert( ((VipsArgument *) argument_class)->pspec == pspec );
1212 g_assert( ((VipsArgument *) argument_instance)->pspec == pspec );
1213
1214 /* If this is a construct-only argument, we can only set before we've
1215 * built.
1216 */
1217 if( argument_class->flags & VIPS_ARGUMENT_CONSTRUCT &&
1218 object->constructed &&
1219 !vips_value_is_null( pspec, value ) ) {
1220 g_warning( "%s: %s can't assign '%s' after construct",
1221 G_STRLOC,
1222 G_OBJECT_TYPE_NAME( gobject ),
1223 g_param_spec_get_name( pspec ) );
1224 return;
1225 }
1226
1227 /* If this is a set-once argument, check we've not set it before.
1228 */
1229 if( argument_class->flags & VIPS_ARGUMENT_SET_ONCE &&
1230 argument_instance->assigned &&
1231 !vips_value_is_null( pspec, value ) ) {
1232 g_warning( "%s: %s can only assign '%s' once",
1233 G_STRLOC,
1234 G_OBJECT_TYPE_NAME( gobject ),
1235 g_param_spec_get_name( pspec ) );
1236 return;
1237 }
1238
1239 /* We can't use a switch since some param specs don't have fundamental
1240 * types and are hence not compile-time constants, argh.
1241 */
1242 if( G_IS_PARAM_SPEC_STRING( pspec ) ) {
1243 char **member = &G_STRUCT_MEMBER( char *, object,
1244 argument_class->offset );
1245
1246 if( *member )
1247 g_free( *member );
1248 *member = g_value_dup_string( value );
1249 }
1250 else if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
1251 GObject **member = &G_STRUCT_MEMBER( GObject *, object,
1252 argument_class->offset );
1253
1254 vips__object_set_member( object, pspec, member,
1255 g_value_get_object( value ) );
1256 }
1257 else if( G_IS_PARAM_SPEC_INT( pspec ) ) {
1258 int *member = &G_STRUCT_MEMBER( int, object,
1259 argument_class->offset );
1260
1261 *member = g_value_get_int( value );
1262 }
1263 else if( G_IS_PARAM_SPEC_UINT64( pspec ) ) {
1264 guint64 *member = &G_STRUCT_MEMBER( guint64, object,
1265 argument_class->offset );
1266
1267 *member = g_value_get_uint64( value );
1268 }
1269 else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
1270 gboolean *member = &G_STRUCT_MEMBER( gboolean, object,
1271 argument_class->offset );
1272
1273 *member = g_value_get_boolean( value );
1274 }
1275 else if( G_IS_PARAM_SPEC_ENUM( pspec ) ) {
1276 int *member = &G_STRUCT_MEMBER( int, object,
1277 argument_class->offset );
1278
1279 *member = g_value_get_enum( value );
1280 }
1281 else if( G_IS_PARAM_SPEC_FLAGS( pspec ) ) {
1282 int *member = &G_STRUCT_MEMBER( int, object,
1283 argument_class->offset );
1284
1285 *member = g_value_get_flags( value );
1286 }
1287 else if( G_IS_PARAM_SPEC_POINTER( pspec ) ) {
1288 gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
1289 argument_class->offset );
1290
1291 *member = g_value_get_pointer( value );
1292 }
1293 else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) {
1294 double *member = &G_STRUCT_MEMBER( double, object,
1295 argument_class->offset );
1296
1297 *member = g_value_get_double( value );
1298 }
1299 else if( G_IS_PARAM_SPEC_BOXED( pspec ) ) {
1300 gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
1301 argument_class->offset );
1302
1303 if( *member ) {
1304 g_boxed_free( G_PARAM_SPEC_VALUE_TYPE( pspec ),
1305 *member );
1306 *member = NULL;
1307 }
1308
1309 /* Copy the boxed into our pointer (will use eg.
1310 * vips__object_vector_dup()).
1311 */
1312 *member = g_value_dup_boxed( value );
1313 }
1314 else {
1315 g_warning( "%s: %s.%s unimplemented property type %s",
1316 G_STRLOC,
1317 G_OBJECT_TYPE_NAME( gobject ),
1318 g_param_spec_get_name( pspec ),
1319 g_type_name( G_PARAM_SPEC_VALUE_TYPE( pspec ) ) );
1320 }
1321
1322 /* Note that it's now been set.
1323 */
1324 argument_instance->assigned = TRUE;
1325 }
1326
1327 /* Also used by subclasses, so not static.
1328 */
1329 void
vips_object_get_property(GObject * gobject,guint property_id,GValue * value,GParamSpec * pspec)1330 vips_object_get_property( GObject *gobject,
1331 guint property_id, GValue *value, GParamSpec *pspec )
1332 {
1333 VipsObject *object = VIPS_OBJECT( gobject );
1334 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( gobject );
1335 VipsArgumentClass *argument_class = (VipsArgumentClass *)
1336 vips__argument_table_lookup( class->argument_table, pspec );
1337 VipsArgumentInstance *argument_instance =
1338 vips__argument_get_instance( argument_class, object );
1339
1340 g_assert( ((VipsArgument *) argument_class)->pspec == pspec );
1341
1342 if( !argument_instance->assigned ) {
1343 /* Set the value to the default. Things like Ruby
1344 * gobject-introspection will walk objects during GC, and we
1345 * can find ourselves fetching object values between init and
1346 * build.
1347 */
1348 g_param_value_set_default( pspec, value );
1349 return;
1350 }
1351
1352 if( G_IS_PARAM_SPEC_STRING( pspec ) ) {
1353 char *member = G_STRUCT_MEMBER( char *, object,
1354 argument_class->offset );
1355
1356 g_value_set_string( value, member );
1357 }
1358 else if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
1359 GObject **member = &G_STRUCT_MEMBER( GObject *, object,
1360 argument_class->offset );
1361
1362 g_value_set_object( value, *member );
1363 }
1364 else if( G_IS_PARAM_SPEC_INT( pspec ) ) {
1365 int *member = &G_STRUCT_MEMBER( int, object,
1366 argument_class->offset );
1367
1368 g_value_set_int( value, *member );
1369 }
1370 else if( G_IS_PARAM_SPEC_UINT64( pspec ) ) {
1371 guint64 *member = &G_STRUCT_MEMBER( guint64, object,
1372 argument_class->offset );
1373
1374 g_value_set_uint64( value, *member );
1375 }
1376 else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
1377 gboolean *member = &G_STRUCT_MEMBER( gboolean, object,
1378 argument_class->offset );
1379
1380 g_value_set_boolean( value, *member );
1381 }
1382 else if( G_IS_PARAM_SPEC_ENUM( pspec ) ) {
1383 int *member = &G_STRUCT_MEMBER( int, object,
1384 argument_class->offset );
1385
1386 g_value_set_enum( value, *member );
1387 }
1388 else if( G_IS_PARAM_SPEC_FLAGS( pspec ) ) {
1389 int *member = &G_STRUCT_MEMBER( int, object,
1390 argument_class->offset );
1391
1392 g_value_set_flags( value, *member );
1393 }
1394 else if( G_IS_PARAM_SPEC_POINTER( pspec ) ) {
1395 gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
1396 argument_class->offset );
1397
1398 g_value_set_pointer( value, *member );
1399 }
1400 else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) {
1401 double *member = &G_STRUCT_MEMBER( double, object,
1402 argument_class->offset );
1403
1404 g_value_set_double( value, *member );
1405 }
1406 else if( G_IS_PARAM_SPEC_BOXED( pspec ) ) {
1407 gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
1408 argument_class->offset );
1409
1410 /* Copy the boxed into our pointer (will use eg.
1411 * vips__object_vector_dup ()).
1412 */
1413 g_value_set_boxed( value, *member );
1414 }
1415 else {
1416 g_warning( "%s: %s.%s unimplemented property type %s",
1417 G_STRLOC,
1418 G_OBJECT_TYPE_NAME( gobject ),
1419 g_param_spec_get_name( pspec ),
1420 g_type_name( G_PARAM_SPEC_VALUE_TYPE( pspec ) ) );
1421 }
1422 }
1423
1424 static int
vips_object_real_build(VipsObject * object)1425 vips_object_real_build( VipsObject *object )
1426 {
1427 VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
1428
1429 /* Only test input args, output ones can be set by our subclasses as
1430 * they build. See vips_object_build() above.
1431 */
1432 VipsArgumentFlags iomask = VIPS_ARGUMENT_INPUT;
1433
1434 int result;
1435
1436 #ifdef DEBUG
1437 printf( "vips_object_real_build: " );
1438 vips_object_print_name( object );
1439 printf( "\n" );
1440 #endif /*DEBUG*/
1441
1442 g_assert( !object->constructed );
1443
1444 /* It'd be nice if this just copied a pointer rather than did a
1445 * strdup(). Set these here rather than in object_init, so that the
1446 * class gets a chance to set them.
1447 */
1448 g_object_set( object,
1449 "nickname", object_class->nickname,
1450 "description", object_class->description, NULL );
1451
1452 /* Check all required input arguments have been supplied, don't stop
1453 * on 1st error.
1454 */
1455 result = 0;
1456 (void) vips_argument_map( object,
1457 vips_object_check_required, &result, &iomask );
1458
1459 return( result );
1460 }
1461
1462 static int
vips_object_real_postbuild(VipsObject * object,void * data)1463 vips_object_real_postbuild( VipsObject *object, void *data )
1464 {
1465 #ifdef DEBUG
1466 printf( "vips_object_real_postbuild: " );
1467 vips_object_print_name( object );
1468 printf( "\n" );
1469 #endif /*DEBUG*/
1470
1471 g_assert( object->constructed );
1472
1473 return( 0 );
1474 }
1475
1476 static void
vips_object_real_summary_class(VipsObjectClass * class,VipsBuf * buf)1477 vips_object_real_summary_class( VipsObjectClass *class, VipsBuf *buf )
1478 {
1479 vips_buf_appendf( buf, "%s", G_OBJECT_CLASS_NAME( class ) );
1480 if( class->nickname )
1481 vips_buf_appendf( buf, " (%s)", class->nickname );
1482 if( class->description )
1483 vips_buf_appendf( buf, ", %s", class->description );
1484 }
1485
1486 static void
vips_object_real_summary(VipsObject * object,VipsBuf * buf)1487 vips_object_real_summary( VipsObject *object, VipsBuf *buf )
1488 {
1489 }
1490
1491 static void
vips_object_real_dump(VipsObject * object,VipsBuf * buf)1492 vips_object_real_dump( VipsObject *object, VipsBuf *buf )
1493 {
1494 vips_buf_appendf( buf, " %s (%p) count=%d",
1495 G_OBJECT_TYPE_NAME( object ),
1496 object,
1497 G_OBJECT( object )->ref_count );
1498
1499 if( object->local_memory )
1500 vips_buf_appendf( buf, " %zd bytes", object->local_memory );
1501 }
1502
1503 static void
vips_object_real_sanity(VipsObject * object,VipsBuf * buf)1504 vips_object_real_sanity( VipsObject *object, VipsBuf *buf )
1505 {
1506 }
1507
1508 static void
vips_object_real_rewind(VipsObject * object)1509 vips_object_real_rewind( VipsObject *object )
1510 {
1511 #ifdef DEBUG
1512 printf( "vips_object_real_rewind\n" );
1513 vips_object_print_name( object );
1514 printf( "\n" );
1515 #endif /*DEBUG*/
1516
1517 g_object_run_dispose( G_OBJECT( object ) );
1518
1519 object->constructed = FALSE;
1520 object->preclose = FALSE;
1521 object->close = FALSE;
1522 object->postclose = FALSE;
1523 }
1524
1525 static VipsObject *
vips_object_real_new_from_string(const char * string)1526 vips_object_real_new_from_string( const char *string )
1527 {
1528 GType type;
1529
1530 vips_check_init();
1531
1532 /* The main arg selects the subclass.
1533 */
1534 if( !(type = vips_type_find( NULL, string )) ) {
1535 vips_error( "VipsObject",
1536 _( "class \"%s\" not found" ), string );
1537 return( NULL );
1538 }
1539
1540 return( VIPS_OBJECT( g_object_new( type, NULL ) ) );
1541 }
1542
1543 static void
vips_object_real_to_string(VipsObject * object,VipsBuf * buf)1544 vips_object_real_to_string( VipsObject *object, VipsBuf *buf )
1545 {
1546 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
1547
1548 /* Just "bicubic" or whatever.
1549 */
1550 vips_buf_appends( buf, class->nickname );
1551 }
1552
1553 static void
transform_string_double(const GValue * src_value,GValue * dest_value)1554 transform_string_double( const GValue *src_value, GValue *dest_value )
1555 {
1556 g_value_set_double( dest_value,
1557 g_ascii_strtod( g_value_get_string( src_value ), NULL ) );
1558 }
1559
1560 static void
vips_object_class_init(VipsObjectClass * class)1561 vips_object_class_init( VipsObjectClass *class )
1562 {
1563 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
1564
1565 if( !vips__object_all ) {
1566 vips__object_all = g_hash_table_new(
1567 g_direct_hash, g_direct_equal );
1568 vips__object_all_lock = vips_g_mutex_new();
1569 }
1570
1571 gobject_class->dispose = vips_object_dispose;
1572 gobject_class->finalize = vips_object_finalize;
1573 gobject_class->set_property = vips_object_set_property;
1574 gobject_class->get_property = vips_object_get_property;
1575
1576 class->build = vips_object_real_build;
1577 class->postbuild = vips_object_real_postbuild;
1578 class->summary_class = vips_object_real_summary_class;
1579 class->summary = vips_object_real_summary;
1580 class->dump = vips_object_real_dump;
1581 class->sanity = vips_object_real_sanity;
1582 class->rewind = vips_object_real_rewind;
1583 class->new_from_string = vips_object_real_new_from_string;
1584 class->to_string = vips_object_real_to_string;
1585 class->nickname = "object";
1586 class->description = _( "base class" );
1587
1588 /* Table of VipsArgumentClass ... we can just g_free() them.
1589 */
1590 class->argument_table = g_hash_table_new_full(
1591 g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_free );
1592 class->argument_table_traverse = NULL;
1593
1594 /* For setting double arguments from the command-line.
1595 */
1596 g_value_register_transform_func( G_TYPE_STRING, G_TYPE_DOUBLE,
1597 transform_string_double );
1598
1599 VIPS_ARG_STRING( class, "nickname", 1,
1600 _( "Nickname" ),
1601 _( "Class nickname" ),
1602 VIPS_ARGUMENT_SET_ONCE,
1603 G_STRUCT_OFFSET( VipsObject, nickname ),
1604 "" );
1605
1606 VIPS_ARG_STRING( class, "description", 2,
1607 _( "Description" ),
1608 _( "Class description" ),
1609 VIPS_ARGUMENT_SET_ONCE,
1610 G_STRUCT_OFFSET( VipsObject, description ),
1611 "" );
1612
1613 /**
1614 * VipsObject::postbuild:
1615 * @object: the object that has been built
1616 *
1617 * The ::postbuild signal is emitted once just after successful object
1618 * construction. Return non-zero to cause object construction to fail.
1619 */
1620 vips_object_signals[SIG_POSTBUILD] = g_signal_new( "postbuild",
1621 G_TYPE_FROM_CLASS( class ),
1622 G_SIGNAL_RUN_LAST,
1623 G_STRUCT_OFFSET( VipsObjectClass, postbuild ),
1624 NULL, NULL,
1625 vips_INT__VOID,
1626 G_TYPE_INT, 0 );
1627
1628 /**
1629 * VipsObject::preclose:
1630 * @object: the object that is to close
1631 *
1632 * The ::preclose signal is emitted once just before object close
1633 * starts. The oject is still alive.
1634 */
1635 vips_object_signals[SIG_PRECLOSE] = g_signal_new( "preclose",
1636 G_TYPE_FROM_CLASS( class ),
1637 G_SIGNAL_RUN_LAST,
1638 G_STRUCT_OFFSET( VipsObjectClass, preclose ),
1639 NULL, NULL,
1640 g_cclosure_marshal_VOID__VOID,
1641 G_TYPE_NONE, 0 );
1642
1643 /**
1644 * VipsObject::close:
1645 * @object: the object that is closing
1646 *
1647 * The ::close signal is emitted once during object close. The object
1648 * is dying and may not work.
1649 */
1650 vips_object_signals[SIG_CLOSE] = g_signal_new( "close",
1651 G_TYPE_FROM_CLASS( class ),
1652 G_SIGNAL_RUN_LAST,
1653 G_STRUCT_OFFSET( VipsObjectClass, close ),
1654 NULL, NULL,
1655 g_cclosure_marshal_VOID__VOID,
1656 G_TYPE_NONE, 0 );
1657
1658 /**
1659 * VipsObject::postclose:
1660 * @object: the object that has closed
1661 *
1662 * The ::postclose signal is emitted once after object close. The
1663 * object pointer is still valid, but nothing else.
1664 */
1665 vips_object_signals[SIG_POSTCLOSE] = g_signal_new( "postclose",
1666 G_TYPE_FROM_CLASS( class ),
1667 G_SIGNAL_RUN_LAST,
1668 G_STRUCT_OFFSET( VipsObjectClass, postclose ),
1669 NULL, NULL,
1670 g_cclosure_marshal_VOID__VOID,
1671 G_TYPE_NONE, 0 );
1672
1673 }
1674
1675 static void
vips_object_init(VipsObject * object)1676 vips_object_init( VipsObject *object )
1677 {
1678 #ifdef DEBUG
1679 printf( "vips_object_init: " );
1680 vips_object_print_name( object );
1681 printf( "\n" );
1682 #endif /*DEBUG*/
1683
1684 g_mutex_lock( vips__object_all_lock );
1685 g_hash_table_insert( vips__object_all, object, object );
1686 g_mutex_unlock( vips__object_all_lock );
1687 }
1688
1689 static void *
traverse_find_required_priority(void * data,void * a,void * b)1690 traverse_find_required_priority( void *data, void *a, void *b )
1691 {
1692 VipsArgumentClass *argument_class = (VipsArgumentClass *) data;
1693 int priority = GPOINTER_TO_INT( a );
1694
1695 if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
1696 !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) &&
1697 argument_class->priority == priority )
1698 return( argument_class );
1699
1700 return( NULL );
1701 }
1702
1703 static gint
traverse_sort(gconstpointer a,gconstpointer b,void * user_data)1704 traverse_sort( gconstpointer a, gconstpointer b, void *user_data )
1705 {
1706 VipsArgumentClass *class1 = (VipsArgumentClass *) a;
1707 VipsArgumentClass *class2 = (VipsArgumentClass *) b;
1708
1709 return( class1->priority - class2->priority );
1710 }
1711
1712 /* Add a vipsargument ... automate some stuff with this.
1713 */
1714 void
vips_object_class_install_argument(VipsObjectClass * object_class,GParamSpec * pspec,VipsArgumentFlags flags,int priority,guint offset)1715 vips_object_class_install_argument( VipsObjectClass *object_class,
1716 GParamSpec *pspec, VipsArgumentFlags flags, int priority, guint offset )
1717 {
1718 VipsArgumentClass *argument_class = g_new( VipsArgumentClass, 1 );
1719
1720 GSList *argument_table_traverse;
1721 VipsArgumentClass *ac;
1722
1723 #ifdef DEBUG
1724 printf( "vips_object_class_install_argument: %p %s %s\n",
1725 object_class,
1726 g_type_name( G_TYPE_FROM_CLASS( object_class ) ),
1727 g_param_spec_get_name( pspec ) );
1728 #endif /*DEBUG*/
1729
1730 /* object_class->argument* is shared, so we must lock.
1731 */
1732 g_mutex_lock( vips__global_lock );
1733
1734 /* Must be a new one.
1735 */
1736 g_assert( !g_hash_table_lookup( object_class->argument_table, pspec ) );
1737
1738 /* Mustn't have INPUT and OUTPUT both set.
1739 */
1740 g_assert( !(
1741 (flags & VIPS_ARGUMENT_INPUT) &&
1742 (flags & VIPS_ARGUMENT_OUTPUT)) );
1743
1744 ((VipsArgument *) argument_class)->pspec = pspec;
1745 argument_class->object_class = object_class;
1746 argument_class->flags = flags;
1747 argument_class->priority = priority;
1748 argument_class->offset = offset;
1749
1750 vips_argument_table_replace( object_class->argument_table,
1751 (VipsArgument *) argument_class );
1752
1753 /* If this is the first argument for a new subclass, we need to clone
1754 * the traverse list we inherit.
1755 */
1756 if( object_class->argument_table_traverse_gtype !=
1757 G_TYPE_FROM_CLASS( object_class ) ) {
1758 #ifdef DEBUG
1759 printf( "vips_object_class_install_argument: "
1760 "cloning traverse\n" );
1761 #endif /*DEBUG*/
1762
1763 object_class->argument_table_traverse =
1764 g_slist_copy( object_class->argument_table_traverse );
1765 object_class->argument_table_traverse_gtype =
1766 G_TYPE_FROM_CLASS( object_class );
1767 }
1768
1769 /* We read argument_table_traverse without a lock (eg. see
1770 * vips_argument_map()), so we must be very careful updating it.
1771 */
1772 argument_table_traverse =
1773 g_slist_copy( object_class->argument_table_traverse );
1774
1775 /* We keep traverse sorted by priority, so we musn't have duplicate
1776 * priority values in required args.
1777 */
1778 if( (flags & VIPS_ARGUMENT_REQUIRED) &&
1779 !(flags & VIPS_ARGUMENT_DEPRECATED) &&
1780 (ac = vips_slist_map2( argument_table_traverse,
1781 traverse_find_required_priority,
1782 GINT_TO_POINTER( priority ), NULL )) )
1783 g_warning( "vips_object_class_install_argument: "
1784 "%s.%s, %s.%s duplicate priority",
1785 g_type_name( G_TYPE_FROM_CLASS( object_class ) ),
1786 g_param_spec_get_name( pspec ),
1787 g_type_name( G_TYPE_FROM_CLASS( ac->object_class ) ),
1788 g_param_spec_get_name( ((VipsArgument *) ac)->pspec ) );
1789
1790 /* Warn about optional boolean args which default TRUE. These won't
1791 * work from the CLI, since simple GOption switches don't allow
1792 * `=false`.
1793 */
1794 if( !(flags & VIPS_ARGUMENT_REQUIRED) &&
1795 !(flags & VIPS_ARGUMENT_DEPRECATED) &&
1796 G_IS_PARAM_SPEC_BOOLEAN( pspec ) &&
1797 G_PARAM_SPEC_BOOLEAN( pspec )->default_value )
1798 g_warning( "vips_object_class_install_argument: "
1799 "default TRUE BOOL arg %s.%s",
1800 g_type_name( G_TYPE_FROM_CLASS( object_class ) ),
1801 g_param_spec_get_name( pspec ) );
1802
1803 argument_table_traverse = g_slist_prepend(
1804 argument_table_traverse, argument_class );
1805 argument_table_traverse = g_slist_sort(
1806 argument_table_traverse, (GCompareFunc) traverse_sort );
1807 VIPS_SWAP( GSList *,
1808 argument_table_traverse,
1809 object_class->argument_table_traverse );
1810
1811 g_slist_free( argument_table_traverse );
1812
1813 #ifdef DEBUG
1814 {
1815 GSList *p;
1816
1817 printf( "%d items on traverse %p\n",
1818 g_slist_length( object_class->argument_table_traverse ),
1819 &object_class->argument_table_traverse );
1820 for( p = object_class->argument_table_traverse; p; p = p->next ) {
1821 VipsArgumentClass *argument_class =
1822 (VipsArgumentClass *) p->data;
1823
1824 printf( "\t%p %s\n",
1825 argument_class,
1826 g_param_spec_get_name(
1827 ((VipsArgument *) argument_class)->pspec ) );
1828 }
1829 }
1830 #endif /*DEBUG*/
1831
1832 g_mutex_unlock( vips__global_lock );
1833 }
1834
1835 static void
vips_object_no_value(VipsObject * object,const char * name)1836 vips_object_no_value( VipsObject *object, const char *name )
1837 {
1838 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
1839
1840 GParamSpec *pspec;
1841 VipsArgumentClass *argument_class;
1842 VipsArgumentInstance *argument_instance;
1843
1844 if( vips_object_get_argument( object, name,
1845 &pspec, &argument_class, &argument_instance ) )
1846 g_assert_not_reached();
1847
1848 if( strcmp( name, g_param_spec_get_name( pspec ) ) == 0 )
1849 vips_error( class->nickname,
1850 _( "no value supplied for argument '%s'" ), name );
1851 else
1852 vips_error( class->nickname,
1853 _( "no value supplied for argument '%s' ('%s')" ),
1854 name,
1855 g_param_spec_get_name( pspec ) );
1856 }
1857
1858 /* Set a named arg from a string.
1859 */
1860 int
vips_object_set_argument_from_string(VipsObject * object,const char * name,const char * value)1861 vips_object_set_argument_from_string( VipsObject *object,
1862 const char *name, const char *value )
1863 {
1864 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
1865
1866 GParamSpec *pspec;
1867 VipsArgumentClass *argument_class;
1868 VipsArgumentInstance *argument_instance;
1869 VipsObjectClass *oclass;
1870 GType otype;
1871
1872 GValue gvalue = { 0 };
1873
1874 VIPS_DEBUG_MSG( "vips_object_set_argument_from_string: %s = %s\n",
1875 name, value );
1876
1877 if( vips_object_get_argument( object, name,
1878 &pspec, &argument_class, &argument_instance ) )
1879 return( -1 );
1880
1881 otype = G_PARAM_SPEC_VALUE_TYPE( pspec );
1882
1883 g_assert( argument_class->flags & VIPS_ARGUMENT_INPUT );
1884
1885 if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) {
1886 VipsImage *out;
1887 VipsOperationFlags flags;
1888 VipsAccess access;
1889 char filename[VIPS_PATH_MAX];
1890 char option_string[VIPS_PATH_MAX];
1891
1892 flags = 0;
1893 if( VIPS_IS_OPERATION( object ) )
1894 flags = vips_operation_get_flags(
1895 VIPS_OPERATION( object ) );
1896
1897 if( flags &
1898 (VIPS_OPERATION_SEQUENTIAL_UNBUFFERED |
1899 VIPS_OPERATION_SEQUENTIAL) )
1900 access = VIPS_ACCESS_SEQUENTIAL;
1901 else
1902 access = VIPS_ACCESS_RANDOM;
1903
1904 if( !value ) {
1905 vips_object_no_value( object, name );
1906 return( -1 );
1907 }
1908 vips__filename_split8( value, filename, option_string );
1909
1910 if( strcmp( "stdin", filename ) == 0 ) {
1911 VipsSource *source;
1912
1913 if( !(source =
1914 vips_source_new_from_descriptor( 0 )) )
1915 return( -1 );
1916 if( !(out = vips_image_new_from_source( source,
1917 option_string,
1918 "access", access,
1919 NULL )) ) {
1920 VIPS_UNREF( source );
1921 return( -1 );
1922 }
1923 VIPS_UNREF( source );
1924 }
1925 else {
1926 if( !(out = vips_image_new_from_file( value,
1927 "access", access,
1928 NULL )) )
1929 return( -1 );
1930 }
1931
1932 g_value_init( &gvalue, VIPS_TYPE_IMAGE );
1933 g_value_set_object( &gvalue, out );
1934
1935 /* Setting gvalue will have upped @out's count again,
1936 * go back to 1 so that gvalue has the only ref.
1937 */
1938 g_object_unref( out );
1939 }
1940 else if( g_type_is_a( otype, VIPS_TYPE_SOURCE ) ) {
1941 VipsSource *source;
1942
1943 if( !value ) {
1944 vips_object_no_value( object, name );
1945 return( -1 );
1946 }
1947
1948 if( !(source = vips_source_new_from_options( value )) )
1949 return( -1 );
1950
1951 g_value_init( &gvalue, VIPS_TYPE_SOURCE );
1952 g_value_set_object( &gvalue, source );
1953
1954 /* Setting gvalue will have upped @out's count again,
1955 * go back to 1 so that gvalue has the only ref.
1956 */
1957 g_object_unref( source );
1958 }
1959 else if( g_type_is_a( otype, VIPS_TYPE_ARRAY_IMAGE ) ) {
1960 /* We have to have a special case for this, we can't just rely
1961 * on transform_g_string_array_image(), since we need to be
1962 * able to set the access hint on the image.
1963 */
1964 VipsArrayImage *array_image;
1965 VipsOperationFlags flags;
1966 VipsAccess access;
1967
1968 if( !value ) {
1969 vips_object_no_value( object, name );
1970 return( -1 );
1971 }
1972
1973 flags = 0;
1974 if( VIPS_IS_OPERATION( object ) )
1975 flags = vips_operation_get_flags(
1976 VIPS_OPERATION( object ) );
1977
1978 if( flags & (VIPS_OPERATION_SEQUENTIAL_UNBUFFERED |
1979 VIPS_OPERATION_SEQUENTIAL) )
1980 access = VIPS_ACCESS_SEQUENTIAL;
1981 else
1982 access = VIPS_ACCESS_RANDOM;
1983
1984 if( !(array_image =
1985 vips_array_image_new_from_string( value, access )) )
1986 return( -1 );
1987
1988 g_value_init( &gvalue, VIPS_TYPE_ARRAY_IMAGE );
1989 g_value_set_boxed( &gvalue, array_image );
1990
1991 /* Setting gvalue will have upped @array_image's count again,
1992 * go back to 1 so that gvalue has the only ref.
1993 */
1994 vips_area_unref( VIPS_AREA( array_image ) );
1995 }
1996 else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
1997 (oclass = g_type_class_ref( otype )) ) {
1998 VipsObject *new_object;
1999
2000 if( !value ) {
2001 vips_object_no_value( object, name );
2002 return( -1 );
2003 }
2004
2005 if( !(new_object =
2006 vips_object_new_from_string( oclass, value )) )
2007 return( -1 );
2008
2009 /* Not necessarily a VipsOperation subclass so we don't use
2010 * the cache. We could have a separate case for this.
2011 */
2012 if( vips_object_build( new_object ) ) {
2013 g_object_unref( new_object );
2014 return( -1 );
2015 }
2016
2017 g_value_init( &gvalue, G_TYPE_OBJECT );
2018 g_value_set_object( &gvalue, new_object );
2019
2020 /* The GValue now has a ref, we can drop ours.
2021 */
2022 g_object_unref( new_object );
2023 }
2024 else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
2025 gboolean b;
2026
2027 b = TRUE;
2028 if( value &&
2029 (g_ascii_strcasecmp( value, "false" ) == 0 ||
2030 g_ascii_strcasecmp( value, "no" ) == 0 ||
2031 strcmp( value, "0" ) == 0) )
2032 b = FALSE;
2033
2034 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2035 g_value_set_boolean( &gvalue, b );
2036 }
2037 else if( G_IS_PARAM_SPEC_INT( pspec ) ) {
2038 int i;
2039
2040 if( !value ) {
2041 vips_object_no_value( object, name );
2042 return( -1 );
2043 }
2044
2045 if( sscanf( value, "%d", &i ) != 1 ) {
2046 vips_error( class->nickname,
2047 _( "'%s' is not an integer" ), value );
2048 return( -1 );
2049 }
2050
2051 g_value_init( &gvalue, G_TYPE_INT );
2052 g_value_set_int( &gvalue, i );
2053 }
2054 else if( G_IS_PARAM_SPEC_UINT64( pspec ) ) {
2055 /* Not allways the same as guint64 :-( argh.
2056 */
2057 long long l;
2058
2059 if( !value ) {
2060 vips_object_no_value( object, name );
2061 return( -1 );
2062 }
2063
2064 if( sscanf( value, "%lld", &l ) != 1 ) {
2065 vips_error( class->nickname,
2066 _( "'%s' is not an integer" ), value );
2067 return( -1 );
2068 }
2069
2070 g_value_init( &gvalue, G_TYPE_UINT64 );
2071 g_value_set_uint64( &gvalue, l );
2072 }
2073 else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) {
2074 double d;
2075
2076 if( !value ) {
2077 vips_object_no_value( object, name );
2078 return( -1 );
2079 }
2080
2081 if( sscanf( value, "%lg", &d ) != 1 ) {
2082 vips_error( class->nickname,
2083 _( "'%s' is not a double" ), value );
2084 return( -1 );
2085 }
2086
2087 g_value_init( &gvalue, G_TYPE_DOUBLE );
2088 g_value_set_double( &gvalue, d );
2089 }
2090 else if( G_IS_PARAM_SPEC_ENUM( pspec ) ) {
2091 int i;
2092
2093 if( !value ) {
2094 vips_object_no_value( object, name );
2095 return( -1 );
2096 }
2097
2098 if( (i = vips_enum_from_nick( class->nickname,
2099 otype, value )) < 0 )
2100 return( -1 );
2101
2102 g_value_init( &gvalue, otype );
2103 g_value_set_enum( &gvalue, i );
2104 }
2105 else if( G_IS_PARAM_SPEC_FLAGS( pspec ) ) {
2106 /* Allow a symbolic name, or an int.
2107 */
2108 int i;
2109
2110 if( !value ) {
2111 vips_object_no_value( object, name );
2112 return( -1 );
2113 }
2114
2115 if( sscanf( value, "%d", &i ) != 1 &&
2116 (i = vips_flags_from_nick( class->nickname,
2117 otype, value )) < 0 ) {
2118 vips_error( class->nickname,
2119 _( "'%s' is not an integer" ), value );
2120 return( -1 );
2121 }
2122
2123 g_value_init( &gvalue, otype );
2124 g_value_set_flags( &gvalue, i );
2125 }
2126 else {
2127 if( !value ) {
2128 vips_object_no_value( object, name );
2129 return( -1 );
2130 }
2131
2132 g_value_init( &gvalue, G_TYPE_STRING );
2133 g_value_set_string( &gvalue, value );
2134 }
2135
2136 g_object_set_property( G_OBJECT( object ), name, &gvalue );
2137 g_value_unset( &gvalue );
2138
2139 return( 0 );
2140 }
2141
2142 /* Does an vipsargument need an argument to write to? For example, an image
2143 * output needs a filename, a double output just prints.
2144 */
2145 gboolean
vips_object_argument_needsstring(VipsObject * object,const char * name)2146 vips_object_argument_needsstring( VipsObject *object, const char *name )
2147 {
2148 GParamSpec *pspec;
2149 VipsArgumentClass *argument_class;
2150 VipsArgumentInstance *argument_instance;
2151
2152 #ifdef DEBUG
2153 printf( "vips_object_argument_needsstring: %s\n", name );
2154 #endif /*DEBUG*/
2155
2156 if( vips_object_get_argument( object, name,
2157 &pspec, &argument_class, &argument_instance ) )
2158 return( -1 );
2159
2160 return( vips_argument_class_needsstring( argument_class ) );
2161 }
2162
2163 static void
vips_object_print_arg(VipsObject * object,GParamSpec * pspec,VipsBuf * buf)2164 vips_object_print_arg( VipsObject *object, GParamSpec *pspec, VipsBuf *buf )
2165 {
2166 GType type = G_PARAM_SPEC_VALUE_TYPE( pspec );
2167 const char *name = g_param_spec_get_name( pspec );
2168 GValue value = { 0, };
2169 char *str_value;
2170
2171 g_value_init( &value, type );
2172 g_object_get_property( G_OBJECT( object ), name, &value );
2173 str_value = g_strdup_value_contents( &value );
2174 vips_buf_appends( buf, str_value );
2175 g_free( str_value );
2176 g_value_unset( &value );
2177 }
2178
2179 /* Is a filename a target, ie. it is of the form ".jpg". Any trailing options
2180 * have already been stripped. Watch out for cases like "./x.jpg".
2181 */
2182 static gboolean
vips_filename_istarget(const char * filename)2183 vips_filename_istarget( const char *filename )
2184 {
2185 const char *p;
2186
2187 return( (p = strrchr( filename, '.' )) && p == filename );
2188 }
2189
2190 /* Write a named arg to the string. If the arg does not need a string (see
2191 * above), arg will be NULL.
2192 */
2193 int
vips_object_get_argument_to_string(VipsObject * object,const char * name,const char * arg)2194 vips_object_get_argument_to_string( VipsObject *object,
2195 const char *name, const char *arg )
2196 {
2197 GParamSpec *pspec;
2198 GType otype;
2199 VipsArgumentClass *argument_class;
2200 VipsArgumentInstance *argument_instance;
2201 VipsObjectClass *oclass;
2202
2203 #ifdef DEBUG
2204 printf( "vips_object_get_argument_to_string: %s -> %s\n",
2205 name, arg );
2206 #endif /*DEBUG*/
2207
2208 if( vips_object_get_argument( object, name,
2209 &pspec, &argument_class, &argument_instance ) )
2210 return( -1 );
2211
2212 otype = G_PARAM_SPEC_VALUE_TYPE( pspec );
2213
2214 g_assert( argument_class->flags & VIPS_ARGUMENT_OUTPUT );
2215
2216 if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) {
2217 VipsImage *in;
2218 char filename[VIPS_PATH_MAX];
2219 char option_string[VIPS_PATH_MAX];
2220
2221 vips__filename_split8( arg, filename, option_string );
2222
2223 if( vips_filename_istarget( filename ) ) {
2224 VipsTarget *target;
2225
2226 if( !(target = vips_target_new_to_descriptor( 1 )) )
2227 return( -1 );
2228 g_object_get( object, name, &in, NULL );
2229 if( vips_image_write_to_target( in,
2230 arg, target, NULL ) ) {
2231 VIPS_UNREF( in );
2232 VIPS_UNREF( target );
2233 return( -1 );
2234 }
2235 VIPS_UNREF( in );
2236 VIPS_UNREF( target );
2237 }
2238 else {
2239 /* Pull out the image and write it.
2240 */
2241 g_object_get( object, name, &in, NULL );
2242 if( vips_image_write_to_file( in, arg, NULL ) ) {
2243 VIPS_UNREF( in );
2244 return( -1 );
2245 }
2246 VIPS_UNREF( in );
2247 }
2248 }
2249 else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
2250 (oclass = g_type_class_ref( otype )) &&
2251 oclass->output_to_arg ) {
2252 VipsObject *value;
2253
2254 g_object_get( object, name, &value, NULL );
2255 if( oclass->output_to_arg( value, arg ) ) {
2256 g_object_unref( value );
2257 return( -1 );
2258 }
2259 g_object_unref( value );
2260 }
2261 else {
2262 char str[1000];
2263 VipsBuf buf = VIPS_BUF_STATIC( str );
2264
2265 vips_object_print_arg( object, pspec, &buf );
2266 printf( "%s\n", vips_buf_all( &buf ) );
2267 }
2268
2269 return( 0 );
2270 }
2271
2272 static void *
vips_argument_is_required(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)2273 vips_argument_is_required( VipsObject *object,
2274 GParamSpec *pspec,
2275 VipsArgumentClass *argument_class,
2276 VipsArgumentInstance *argument_instance,
2277 void *a, void *b )
2278 {
2279 if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
2280 (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
2281 (argument_class->flags & VIPS_ARGUMENT_INPUT) &&
2282 !argument_instance->assigned )
2283 return( pspec );
2284
2285 return( NULL );
2286 }
2287
2288 /* Find the first unassigned required input arg.
2289 */
2290 static GParamSpec *
vips_object_find_required(VipsObject * object)2291 vips_object_find_required( VipsObject *object )
2292 {
2293 return( (GParamSpec *) vips_argument_map( object,
2294 vips_argument_is_required, NULL, NULL ) );
2295 }
2296
2297 typedef struct _VipsNameFlagsPair {
2298 const char **names;
2299 int *flags;
2300 } VipsNameFlagsPair;
2301
2302 static void *
vips_object_find_args(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)2303 vips_object_find_args( VipsObject *object,
2304 GParamSpec *pspec,
2305 VipsArgumentClass *argument_class,
2306 VipsArgumentInstance *argument_instance,
2307 void *a, void *b )
2308 {
2309 VipsNameFlagsPair *pair = (VipsNameFlagsPair *) a;
2310 int *i = (int *) b;
2311
2312 pair->names[*i] = g_param_spec_get_name( pspec );
2313 pair->flags[*i] = (int) argument_class->flags;
2314
2315 *i += 1;
2316
2317 return( NULL );
2318 }
2319
2320 /**
2321 * vips_object_get_args: (skip)
2322 * @object: object whose args should be retrieved
2323 * @names: (transfer none) (array length=n_args) (allow-none): output array of %GParamSpec names
2324 * @flags: (transfer none) (array length=n_args) (allow-none): output array of #VipsArgumentFlags
2325 * @n_args: (allow-none): length of output arrays
2326 *
2327 * Get all %GParamSpec names and #VipsArgumentFlags for an object.
2328 *
2329 * This is handy for language bindings. From C, it's usually more convenient to
2330 * use vips_argument_map().
2331 *
2332 * Returns: 0 on success, -1 on error
2333 */
2334 int
vips_object_get_args(VipsObject * object,const char *** names,int ** flags,int * n_args)2335 vips_object_get_args( VipsObject *object,
2336 const char ***names, int **flags, int *n_args )
2337 {
2338 VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
2339 int n = g_slist_length( object_class->argument_table_traverse );
2340
2341 VipsNameFlagsPair pair;
2342 int i;
2343
2344 pair.names = VIPS_ARRAY( object, n, const char * );
2345 pair.flags = VIPS_ARRAY( object, n, int );
2346 if( !pair.names ||
2347 !pair.flags )
2348 return( -1 );
2349
2350 i = 0;
2351 (void) vips_argument_map( object,
2352 vips_object_find_args, &pair, &i );
2353
2354 if( names )
2355 *names = pair.names;
2356 if( flags )
2357 *flags = pair.flags;
2358 if( n_args )
2359 *n_args = n;
2360
2361 return( 0 );
2362 }
2363
2364 /**
2365 * vips_object_new: (skip)
2366 * @type: object to create
2367 * @set: set arguments with this
2368 * @a: client data
2369 * @b: client data
2370 *
2371 * g_object_new() the object, set any arguments with @set, call
2372 * vips_object_build() and return the complete object.
2373 *
2374 * Returns: the new object
2375 */
2376 VipsObject *
vips_object_new(GType type,VipsObjectSetArguments set,void * a,void * b)2377 vips_object_new( GType type, VipsObjectSetArguments set, void *a, void *b )
2378 {
2379 VipsObject *object;
2380
2381 vips_check_init();
2382
2383 object = VIPS_OBJECT( g_object_new( type, NULL ) );
2384
2385 if( set && set( object, a, b ) ) {
2386 g_object_unref( object );
2387 return( NULL );
2388 }
2389
2390 if( vips_object_build( object ) ) {
2391 g_object_unref( object );
2392 return( NULL );
2393 }
2394
2395 return( object );
2396 }
2397
2398 /**
2399 * vips_object_set_valist:
2400 * @object: object to set arguments on
2401 * @ap: %NULL-terminated list of argument/value pairs
2402 *
2403 * See vips_object_set().
2404 *
2405 * Returns: 0 on success, -1 on error
2406 */
2407 int
vips_object_set_valist(VipsObject * object,va_list ap)2408 vips_object_set_valist( VipsObject *object, va_list ap )
2409 {
2410 char *name;
2411
2412 VIPS_DEBUG_MSG( "vips_object_set_valist:\n" );
2413
2414 for( name = va_arg( ap, char * ); name; name = va_arg( ap, char * ) ) {
2415 GParamSpec *pspec;
2416 VipsArgumentClass *argument_class;
2417 VipsArgumentInstance *argument_instance;
2418
2419 VIPS_DEBUG_MSG( "\tname = '%s' (%p)\n", name, name );
2420
2421 if( vips_object_get_argument( VIPS_OBJECT( object ), name,
2422 &pspec, &argument_class, &argument_instance ) )
2423 return( -1 );
2424
2425 VIPS_ARGUMENT_COLLECT_SET( pspec, argument_class, ap );
2426
2427 g_object_set_property( G_OBJECT( object ), name, &value );
2428
2429 VIPS_ARGUMENT_COLLECT_GET( pspec, argument_class, ap );
2430
2431 VIPS_ARGUMENT_COLLECT_END
2432 }
2433
2434 return( 0 );
2435 }
2436
2437 /**
2438 * vips_object_set:
2439 * @object: object to set arguments on
2440 * @...: %NULL-terminated list of argument/value pairs
2441 *
2442 * Set a list of vips object arguments. For example:
2443 *
2444 * |[
2445 * vips_object_set (operation,
2446 * "input", in,
2447 * "output", &out,
2448 * NULL);
2449 * ]|
2450 *
2451 * Input arguments are given in-line, output arguments are given as pointers
2452 * to where the output value should be written.
2453 *
2454 * See also: vips_object_set_valist(), vips_object_set_from_string().
2455 *
2456 * Returns: 0 on success, -1 on error
2457 */
2458 int
vips_object_set(VipsObject * object,...)2459 vips_object_set( VipsObject *object, ... )
2460 {
2461 va_list ap;
2462 int result;
2463
2464 va_start( ap, object );
2465 result = vips_object_set_valist( object, ap );
2466 va_end( ap );
2467
2468 return( result );
2469 }
2470
2471 /* Set object args from a string. @p should be the initial left bracket and
2472 * there should be no tokens after the matching right bracket. @p is modified.
2473 */
2474 static int
vips_object_set_args(VipsObject * object,const char * p)2475 vips_object_set_args( VipsObject *object, const char *p )
2476 {
2477 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
2478
2479 VipsToken token;
2480 char string[VIPS_PATH_MAX];
2481 char string2[VIPS_PATH_MAX];
2482 GParamSpec *pspec;
2483 VipsArgumentClass *argument_class;
2484 VipsArgumentInstance *argument_instance;
2485
2486 if( !(p = vips__token_need( p, VIPS_TOKEN_LEFT,
2487 string, VIPS_PATH_MAX )) )
2488 return( -1 );
2489
2490 if( !(p = vips__token_segment( p, &token, string, VIPS_PATH_MAX )) )
2491 return( -1 );
2492
2493 for(;;) {
2494 if( token == VIPS_TOKEN_RIGHT )
2495 break;
2496 if( token != VIPS_TOKEN_STRING ) {
2497 vips_error( class->nickname,
2498 _( "expected string or ), saw %s" ),
2499 vips_enum_nick( VIPS_TYPE_TOKEN, token ) );
2500 return( -1 );
2501 }
2502
2503 /* We have to look for a '=', ']' or a ',' to see if string is
2504 * a param name or a value.
2505 */
2506 if( !(p = vips__token_segment( p, &token,
2507 string2, VIPS_PATH_MAX )) )
2508 return( -1 );
2509 if( token == VIPS_TOKEN_EQUALS ) {
2510 if( !(p = vips__token_segment_need( p, VIPS_TOKEN_STRING,
2511 string2, VIPS_PATH_MAX )) )
2512 return( -1 );
2513 if( vips_object_set_argument_from_string( object,
2514 string, string2 ) )
2515 return( -1 );
2516
2517 if( !(p = vips__token_must( p, &token,
2518 string2, VIPS_PATH_MAX )) )
2519 return( -1 );
2520 }
2521 else if( g_object_class_find_property(
2522 G_OBJECT_GET_CLASS( object ), string ) &&
2523 !vips_object_get_argument( object, string,
2524 &pspec, &argument_class, &argument_instance ) &&
2525 (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
2526 (argument_class->flags & VIPS_ARGUMENT_INPUT) &&
2527 G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
2528 /* The string is the name of an optional
2529 * input boolean ... set it!
2530 */
2531 if( !argument_instance->assigned )
2532 g_object_set( object, string, TRUE, NULL );
2533 }
2534 else if( (pspec = vips_object_find_required( object )) ) {
2535 if( vips_object_set_argument_from_string( object,
2536 g_param_spec_get_name( pspec ), string ) )
2537 return( -1 );
2538 }
2539 else {
2540 vips_error( class->nickname,
2541 _( "unable to set '%s'" ), string );
2542 return( -1 );
2543 }
2544
2545 /* Now must be a , or a ).
2546 */
2547 if( token == VIPS_TOKEN_COMMA ) {
2548 if( !(p = vips__token_must( p, &token,
2549 string, VIPS_PATH_MAX )) )
2550 return( -1 );
2551 }
2552 else if( token != VIPS_TOKEN_RIGHT ) {
2553 vips_error( class->nickname,
2554 "%s", _( "not , or ) after parameter" ) );
2555 return( -1 );
2556 }
2557 }
2558
2559 if( (p = vips__token_get( p, &token, string, VIPS_PATH_MAX )) ) {
2560 vips_error( class->nickname,
2561 "%s", _( "extra tokens after ')'" ) );
2562 return( -1 );
2563 }
2564
2565 return( 0 );
2566 }
2567
2568 /**
2569 * vips_object_set_from_string:
2570 * @object: object to set arguments on
2571 * @string: arguments as a string
2572 *
2573 * Set object arguments from a string. The string can be something like
2574 * "a=12", or "a = 12, b = 13", or "fred". The string can optionally be
2575 * enclosed in brackets.
2576 *
2577 * You'd typically use this between creating the object and building it.
2578 *
2579 * See also: vips_object_set(), vips_object_build(),
2580 * vips_cache_operation_buildp().
2581 *
2582 * Returns: 0 on success, -1 on error
2583 */
2584 int
vips_object_set_from_string(VipsObject * object,const char * string)2585 vips_object_set_from_string( VipsObject *object, const char *string )
2586 {
2587 const char *q;
2588 VipsToken token;
2589 char buffer[VIPS_PATH_MAX];
2590 char str[VIPS_PATH_MAX];
2591
2592 vips_strncpy( buffer, string, VIPS_PATH_MAX );
2593
2594 /* Does string start with a bracket? If it doesn't, enclose the whole
2595 * thing in [].
2596 */
2597 if( !(q = vips__token_get( buffer, &token, str, VIPS_PATH_MAX )) ||
2598 token != VIPS_TOKEN_LEFT )
2599 vips_snprintf( buffer, VIPS_PATH_MAX, "[%s]", string );
2600 else
2601 vips_strncpy( buffer, string, VIPS_PATH_MAX );
2602
2603 return( vips_object_set_args( object, buffer ) );
2604 }
2605
2606 VipsObject *
vips_object_new_from_string(VipsObjectClass * object_class,const char * p)2607 vips_object_new_from_string( VipsObjectClass *object_class, const char *p )
2608 {
2609 const char *q;
2610 char str[VIPS_PATH_MAX];
2611 VipsObject *object;
2612
2613 g_assert( object_class );
2614 g_assert( object_class->new_from_string );
2615
2616 /* Find the start of the optional args on the end of the string, take
2617 * everything before that as the principal arg for the constructor.
2618 */
2619 if( (q = vips__find_rightmost_brackets( p )) )
2620 vips_strncpy( str, p, VIPS_MIN( VIPS_PATH_MAX, q - p + 1 ) );
2621 else
2622 vips_strncpy( str, p, VIPS_PATH_MAX );
2623 if( !(object = object_class->new_from_string( str )) )
2624 return( NULL );
2625
2626 /* More tokens there? Set any other args.
2627 */
2628 if( q &&
2629 vips_object_set_from_string( object, q ) ) {
2630 g_object_unref( object );
2631 return( NULL );
2632 }
2633
2634 return( object );
2635 }
2636
2637 static void *
vips_object_to_string_required(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)2638 vips_object_to_string_required( VipsObject *object,
2639 GParamSpec *pspec,
2640 VipsArgumentClass *argument_class,
2641 VipsArgumentInstance *argument_instance,
2642 void *a, void *b )
2643 {
2644 VipsBuf *buf = (VipsBuf *) a;
2645 gboolean *first = (gboolean *) b;
2646
2647 if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) ) {
2648 if( *first ) {
2649 vips_buf_appends( buf, "(" );
2650 *first = FALSE;
2651 }
2652 else {
2653 vips_buf_appends( buf, "," );
2654 }
2655
2656 vips_object_print_arg( object, pspec, buf );
2657 }
2658
2659 return( NULL );
2660 }
2661
2662 static void *
vips_object_to_string_optional(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)2663 vips_object_to_string_optional( VipsObject *object,
2664 GParamSpec *pspec,
2665 VipsArgumentClass *argument_class,
2666 VipsArgumentInstance *argument_instance,
2667 void *a, void *b )
2668 {
2669 VipsBuf *buf = (VipsBuf *) a;
2670 gboolean *first = (gboolean *) b;
2671
2672 if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
2673 argument_instance->assigned ) {
2674 if( *first ) {
2675 vips_buf_appends( buf, "(" );
2676 *first = FALSE;
2677 }
2678 else {
2679 vips_buf_appends( buf, "," );
2680 }
2681
2682 vips_buf_appends( buf, g_param_spec_get_name( pspec ) );
2683 vips_buf_appends( buf, "=" );
2684 vips_object_print_arg( object, pspec, buf );
2685 }
2686
2687 return( NULL );
2688 }
2689
2690 /**
2691 * vips_object_to_string:
2692 * @object: object to stringify
2693 * @buf: write string here
2694 *
2695 * The inverse of vips_object_new_from_string(): turn @object into eg.
2696 * "VipsInterpolateSnohalo1(blur=.333333)".
2697 */
2698 void
vips_object_to_string(VipsObject * object,VipsBuf * buf)2699 vips_object_to_string( VipsObject *object, VipsBuf *buf )
2700 {
2701 VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
2702
2703 gboolean first;
2704
2705 g_assert( object_class->to_string );
2706
2707 /* Nicknames are not guaranteed to be unique, so use the full type
2708 * name.
2709 */
2710 object_class->to_string( object, buf );
2711 first = TRUE;
2712 (void) vips_argument_map( object,
2713 vips_object_to_string_required, buf, &first );
2714 (void) vips_argument_map( object,
2715 vips_object_to_string_optional, buf, &first );
2716 if( !first )
2717 vips_buf_appends( buf, ")" );
2718 }
2719
2720 typedef struct {
2721 VipsSListMap2Fn fn;
2722 void *a;
2723 void *b;
2724 void *result;
2725 } VipsObjectMapArgs;
2726
2727 static void
vips_object_map_sub(VipsObject * key,VipsObject * value,VipsObjectMapArgs * args)2728 vips_object_map_sub( VipsObject *key, VipsObject *value,
2729 VipsObjectMapArgs *args )
2730 {
2731 if( !args->result )
2732 args->result = args->fn( key, args->a, args->b );
2733 }
2734
2735 /**
2736 * vips_object_map: (skip)
2737 * @fn: function to call for all objects
2738 * @a: client data
2739 * @b: client data
2740 *
2741 * Call a function for all alive objects.
2742 * Stop when @fn returns non-%NULL and return that value.
2743 *
2744 * Returns: %NULL if @fn returns %NULL for all arguments, otherwise the first
2745 * non-%NULL value from @fn.
2746 */
2747 void *
vips_object_map(VipsSListMap2Fn fn,void * a,void * b)2748 vips_object_map( VipsSListMap2Fn fn, void *a, void *b )
2749 {
2750 VipsObjectMapArgs args;
2751
2752 args.fn = fn;
2753 args.a = a;
2754 args.b = b;
2755 args.result = NULL;
2756
2757 /* We must test vips__object_all before we lock because the lock is
2758 * only created when the first object is created.
2759 */
2760 if( vips__object_all ) {
2761 g_mutex_lock( vips__object_all_lock );
2762 g_hash_table_foreach( vips__object_all,
2763 (GHFunc) vips_object_map_sub, &args );
2764 g_mutex_unlock( vips__object_all_lock );
2765 }
2766
2767 return( args.result );
2768 }
2769
2770 /**
2771 * vips_type_map: (skip)
2772 * @base: base type
2773 * @fn: call this function for every type
2774 * @a: client data
2775 * @b: client data
2776 *
2777 * Map over a type's children. Stop when @fn returns non-%NULL
2778 * and return that value.
2779 *
2780 * Returns: %NULL if @fn returns %NULL for all arguments, otherwise the first
2781 * non-%NULL value from @fn.
2782 */
2783 void *
vips_type_map(GType base,VipsTypeMap2Fn fn,void * a,void * b)2784 vips_type_map( GType base, VipsTypeMap2Fn fn, void *a, void *b )
2785 {
2786 GType *child;
2787 guint n_children;
2788 unsigned int i;
2789 void *result;
2790
2791 child = g_type_children( base, &n_children );
2792 result = NULL;
2793 for( i = 0; i < n_children && !result; i++ )
2794 result = fn( child[i], a, b );
2795 g_free( child );
2796
2797 return( result );
2798 }
2799
2800 /**
2801 * vips_type_map_all: (skip)
2802 * @base: base type
2803 * @fn: call this function for every type
2804 * @a: client data
2805 *
2806 * Map over a type's children, direct and indirect. Stop when @fn returns
2807 * non-%NULL and return that value.
2808 *
2809 * Returns: %NULL if @fn returns %NULL for all arguments, otherwise the first
2810 * non-%NULL value from @fn.
2811 */
2812 void *
vips_type_map_all(GType base,VipsTypeMapFn fn,void * a)2813 vips_type_map_all( GType base, VipsTypeMapFn fn, void *a )
2814 {
2815 void *result;
2816
2817 if( !(result = fn( base, a )) )
2818 result = vips_type_map( base,
2819 (VipsTypeMap2Fn) vips_type_map_all, fn, a );
2820
2821 return( result );
2822 }
2823
2824 /**
2825 * vips_class_map_all: (skip)
2826 * @type: base type
2827 * @fn: call this function for every type
2828 * @a: client data
2829 *
2830 * Loop over all the subclasses of @type. Non-abstract classes only.
2831 * Stop when @fn returns
2832 * non-%NULL and return that value.
2833 *
2834 * Returns: %NULL if @fn returns %NULL for all arguments, otherwise the first
2835 * non-%NULL value from @fn.
2836 */
2837 void *
vips_class_map_all(GType type,VipsClassMapFn fn,void * a)2838 vips_class_map_all( GType type, VipsClassMapFn fn, void *a )
2839 {
2840 void *result;
2841
2842 /* Avoid abstract classes. Use type_map_all for them.
2843 */
2844 if( !G_TYPE_IS_ABSTRACT( type ) ) {
2845 /* We never unref this ref, but we never unload classes
2846 * anyway, so so what.
2847 */
2848 if( (result = fn(
2849 VIPS_OBJECT_CLASS( g_type_class_ref( type ) ), a )) )
2850 return( result );
2851 }
2852
2853 if( (result = vips_type_map( type,
2854 (VipsTypeMap2Fn) vips_class_map_all, fn, a )) )
2855 return( result );
2856
2857 return( NULL );
2858 }
2859
2860 /* How deeply nested is a class ... used to indent class lists.
2861 */
2862 int
vips_type_depth(GType type)2863 vips_type_depth( GType type )
2864 {
2865 int depth;
2866
2867 depth = 0;
2868 while( type != VIPS_TYPE_OBJECT &&
2869 (type = g_type_parent( type )) )
2870 depth += 1;
2871
2872 return( depth );
2873 }
2874
2875 static void *
test_name(VipsObjectClass * class,const char * nickname)2876 test_name( VipsObjectClass *class, const char *nickname )
2877 {
2878 if( g_ascii_strcasecmp( class->nickname, nickname ) == 0 )
2879 return( class );
2880
2881 /* Check the class name too, why not.
2882 */
2883 if( g_ascii_strcasecmp( G_OBJECT_CLASS_NAME( class ), nickname ) == 0 )
2884 return( class );
2885
2886 return( NULL );
2887 }
2888
2889 /**
2890 * vips_class_find:
2891 * @basename: name of base class
2892 * @nickname: search for a class with this nickname
2893 *
2894 * Search below @basename, return the first class whose name or @nickname
2895 * matches.
2896 *
2897 * See also: vips_type_find()
2898 *
2899 * Returns: (transfer none): the found class.
2900 */
2901 const VipsObjectClass *
vips_class_find(const char * basename,const char * nickname)2902 vips_class_find( const char *basename, const char *nickname )
2903 {
2904 const char *classname = basename ? basename : "VipsObject";
2905
2906 VipsObjectClass *class;
2907 GType base;
2908
2909 if( !(base = g_type_from_name( classname )) )
2910 return( NULL );
2911 class = vips_class_map_all( base,
2912 (VipsClassMapFn) test_name, (void *) nickname );
2913
2914 return( class );
2915 }
2916
2917 /* What we store for each nickname. We can't just store the type with
2918 * GINT_TO_POINTER() since GType is 64 bits on some platforms.
2919 */
2920 typedef struct _NicknameGType {
2921 const char *nickname;
2922 GType type;
2923 gboolean duplicate;
2924 } NicknameGType;
2925
2926 static void *
vips_class_add_hash(VipsObjectClass * class,GHashTable * table)2927 vips_class_add_hash( VipsObjectClass *class, GHashTable *table )
2928 {
2929 GType type = G_OBJECT_CLASS_TYPE( class );
2930 NicknameGType *hit;
2931
2932 hit = (NicknameGType *)
2933 g_hash_table_lookup( table, (void *) class->nickname );
2934
2935 /* If this is not a unique name, mark as a duplicate. In this case
2936 * we'll need to fall back to a search.
2937 */
2938 if( hit )
2939 hit->duplicate = TRUE;
2940 else {
2941 hit = g_new( NicknameGType, 1 );
2942 hit->nickname = class->nickname;
2943 hit->type = type;
2944 hit->duplicate = FALSE;
2945 g_hash_table_insert( table, (void *) hit->nickname, hit );
2946 }
2947
2948 return( NULL );
2949 }
2950
2951 static void *
vips_class_build_hash_cb(void * dummy)2952 vips_class_build_hash_cb( void *dummy )
2953 {
2954 GType base;
2955
2956 vips__object_nickname_table =
2957 g_hash_table_new( g_str_hash, g_str_equal );
2958
2959 base = g_type_from_name( "VipsObject" );
2960 g_assert( base );
2961
2962 vips_class_map_all( base,
2963 (VipsClassMapFn) vips_class_add_hash,
2964 (void *) vips__object_nickname_table );
2965
2966 return( NULL );
2967 }
2968
2969 /**
2970 * vips_type_find:
2971 * @basename: name of base class
2972 * @nickname: search for a class with this nickname
2973 *
2974 * Search below @basename, return the %GType of the class whose name or
2975 * @nickname matches, or 0 for not found.
2976 * If @basename is NULL, the whole of #VipsObject is searched.
2977 *
2978 * This function uses a cache, so it should be quick.
2979 *
2980 * See also: vips_class_find()
2981 *
2982 * Returns: the %GType of the class, or 0 if the class is not found.
2983 */
2984 GType
vips_type_find(const char * basename,const char * nickname)2985 vips_type_find( const char *basename, const char *nickname )
2986 {
2987 static GOnce once = G_ONCE_INIT;
2988
2989 const char *classname = basename ? basename : "VipsObject";
2990
2991 NicknameGType *hit;
2992 GType base;
2993 GType type;
2994
2995 VIPS_ONCE( &once, vips_class_build_hash_cb, NULL );
2996
2997 hit = (NicknameGType *)
2998 g_hash_table_lookup( vips__object_nickname_table,
2999 (void *) nickname );
3000
3001 /* We must only search below basename ... check that the cache hit is
3002 * in the right part of the tree.
3003 */
3004 if( !(base = g_type_from_name( classname )) )
3005 return( 0 );
3006 if( hit &&
3007 !hit->duplicate &&
3008 g_type_is_a( hit->type, base ) )
3009 type = hit->type;
3010 else {
3011 const VipsObjectClass *class;
3012
3013 if( !(class = vips_class_find( basename, nickname )) )
3014 return( 0 );
3015
3016 type = G_OBJECT_CLASS_TYPE( class );
3017 }
3018
3019 return( type );
3020 }
3021
3022 /**
3023 * vips_nickname_find:
3024 * @type: #GType to search for
3025 *
3026 * Return the VIPS nickname for a %GType. Handy for language bindings.
3027 *
3028 * Returns: (transfer none): the class nickname.
3029 */
3030 const char *
vips_nickname_find(GType type)3031 vips_nickname_find( GType type )
3032 {
3033 gpointer p;
3034 VipsObjectClass *class;
3035
3036 if( type &&
3037 (p = g_type_class_ref( type )) &&
3038 VIPS_IS_OBJECT_CLASS( p ) &&
3039 (class = VIPS_OBJECT_CLASS( p )) )
3040 return( class->nickname );
3041
3042 return( NULL );
3043 }
3044
3045 /* The vips_object_local() macro uses this as its callback.
3046 */
3047 void
vips_object_local_cb(VipsObject * vobject,GObject * gobject)3048 vips_object_local_cb( VipsObject *vobject, GObject *gobject )
3049 {
3050 VIPS_FREEF( g_object_unref, gobject );
3051 }
3052
3053 typedef struct {
3054 VipsObject **array;
3055 int n;
3056 } VipsObjectLocal;
3057
3058 static void
vips_object_local_array_cb(VipsObject * parent,VipsObjectLocal * local)3059 vips_object_local_array_cb( VipsObject *parent, VipsObjectLocal *local )
3060 {
3061 int i;
3062
3063 for( i = 0; i < local->n; i++ )
3064 VIPS_FREEF( g_object_unref, local->array[i] );
3065
3066 VIPS_FREEF( g_free, local->array );
3067 VIPS_FREEF( g_free, local );
3068 }
3069
3070 /**
3071 * vips_object_local_array: (skip)
3072 * @parent: objects unref when this object unrefs
3073 * @n: array size
3074 *
3075 * Make an array of NULL VipsObject pointers. When @parent closes, every
3076 * non-NULL pointer in the array will be unreffed and the array will be
3077 * freed. Handy for creating a set of temporary images for a function.
3078 *
3079 * The array is NULL-terminated, ie. contains an extra NULL element at the
3080 * end.
3081 *
3082 * Example:
3083 *
3084 * |[
3085 * VipsObject **t;
3086 *
3087 * t = vips_object_local_array( parent, 5 );
3088 * if(
3089 * vips_add( a, b, &t[0], NULL ) ||
3090 * vips_invert( t[0], &t[1], NULL ) ||
3091 * vips_add( t[1], t[0], &t[2], NULL ) ||
3092 * vips_costra( t[2], out, NULL ) )
3093 * return( -1 );
3094 * ]|
3095 *
3096 * See also: vips_object_local().
3097 *
3098 * Returns: an array of NULL pointers of length @n
3099 */
3100 VipsObject **
vips_object_local_array(VipsObject * parent,int n)3101 vips_object_local_array( VipsObject *parent, int n )
3102 {
3103 VipsObjectLocal *local;
3104
3105 local = g_new( VipsObjectLocal, 1 );
3106 local->n = n;
3107 /* Make the array 1 too long so we can be sure there's a NULL
3108 * terminator.
3109 */
3110 local->array = g_new0( VipsObject *, n + 1 );
3111
3112 g_signal_connect( parent, "close",
3113 G_CALLBACK( vips_object_local_array_cb ), local );
3114
3115 return( local->array );
3116 }
3117
3118 void
vips_object_set_static(VipsObject * object,gboolean static_object)3119 vips_object_set_static( VipsObject *object, gboolean static_object )
3120 {
3121 object->static_object = static_object;
3122 }
3123
3124 static void *
vips_object_n_static_cb(VipsObject * object,int * n,void * b)3125 vips_object_n_static_cb( VipsObject *object, int *n, void *b )
3126 {
3127 if( object->static_object )
3128 *n += 1;
3129
3130 return( NULL );
3131 }
3132
3133 static int
vips_object_n_static(void)3134 vips_object_n_static( void )
3135 {
3136 int n;
3137
3138 n = 0;
3139 vips_object_map(
3140 (VipsSListMap2Fn) vips_object_n_static_cb, &n, NULL );
3141
3142 return( n );
3143 }
3144
3145 static void *
vips_object_print_all_cb(VipsObject * object,int * n,void * b)3146 vips_object_print_all_cb( VipsObject *object, int *n, void *b )
3147 {
3148 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
3149
3150 char str[32768];
3151 VipsBuf buf = VIPS_BUF_STATIC( str );
3152
3153 fprintf( stderr, "%d) %s (%p)",
3154 *n, G_OBJECT_TYPE_NAME( object ), object );
3155 if( object->local_memory )
3156 fprintf( stderr, " %zd bytes", object->local_memory );
3157 fprintf( stderr, ", count=%d", G_OBJECT( object )->ref_count );
3158 fprintf( stderr, "\n" );
3159
3160 vips_object_summary_class( class, &buf );
3161 vips_buf_appends( &buf, ", " );
3162 vips_object_summary( object, &buf );
3163 fprintf( stderr, "%s\n", vips_buf_all( &buf ) );
3164
3165 *n += 1;
3166
3167 return( NULL );
3168 }
3169
3170 int
vips__object_leak(void)3171 vips__object_leak( void )
3172 {
3173 int n_leaks;
3174
3175 n_leaks = 0;
3176
3177 /* Don't count static objects.
3178 */
3179 if( vips__object_all &&
3180 g_hash_table_size( vips__object_all ) >
3181 vips_object_n_static() ) {
3182 fprintf( stderr, "%d objects alive:\n",
3183 g_hash_table_size( vips__object_all ) );
3184
3185 vips_object_map(
3186 (VipsSListMap2Fn) vips_object_print_all_cb,
3187 &n_leaks, NULL );
3188 }
3189
3190 return( n_leaks );
3191 }
3192
3193 void
vips_object_print_all(void)3194 vips_object_print_all( void )
3195 {
3196 (void) vips__object_leak();
3197 (void) vips__type_leak();
3198 }
3199
3200 static void *
vips_object_sanity_all_cb(VipsObject * object,void * a,void * b)3201 vips_object_sanity_all_cb( VipsObject *object, void *a, void *b )
3202 {
3203 (void) vips_object_sanity( object );
3204
3205 return( NULL );
3206 }
3207
3208 void
vips_object_sanity_all(void)3209 vips_object_sanity_all( void )
3210 {
3211 vips_object_map(
3212 (VipsSListMap2Fn) vips_object_sanity_all_cb, NULL, NULL );
3213 }
3214
3215 static void *
vips_object_unref_outputs_sub(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)3216 vips_object_unref_outputs_sub( VipsObject *object,
3217 GParamSpec *pspec,
3218 VipsArgumentClass *argument_class,
3219 VipsArgumentInstance *argument_instance,
3220 void *a, void *b )
3221 {
3222 if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&
3223 G_IS_PARAM_SPEC_OBJECT( pspec ) &&
3224 argument_instance->assigned ) {
3225 GObject *value;
3226
3227 g_object_get( object,
3228 g_param_spec_get_name( pspec ), &value, NULL );
3229
3230 /* Doing the get refs the object, so unref the get, then unref
3231 * again since this an an output object of the operation.
3232 */
3233 g_object_unref( value );
3234 g_object_unref( value );
3235 }
3236
3237 return( NULL );
3238 }
3239
3240 /**
3241 * vips_object_unref_outputs:
3242 * @object: object to drop output refs from
3243 *
3244 * Unref all assigned output objects. Useful for language bindings.
3245 *
3246 * After an object is built, all output args are owned by the caller. If
3247 * something goes wrong before then, we have to unref the outputs that have
3248 * been made so far. This function can also be useful for callers when
3249 * they've finished processing outputs themselves.
3250 *
3251 * See also: vips_cache_operation_build().
3252 */
3253 void
vips_object_unref_outputs(VipsObject * object)3254 vips_object_unref_outputs( VipsObject *object )
3255 {
3256 (void) vips_argument_map( object,
3257 vips_object_unref_outputs_sub, NULL, NULL );
3258 }
3259
3260 /**
3261 * vips_object_get_description:
3262 * @object: object to fetch description from
3263 *
3264 * Fetch the object description. Useful for language bindings.
3265 *
3266 * @object.description is only avaliable after _build(), which can be too
3267 * late. This function fetches from the instance, if possible, but falls back
3268 * to the class description if we are too early.
3269 *
3270 * Returns: the object description
3271 */
3272 const char *
vips_object_get_description(VipsObject * object)3273 vips_object_get_description( VipsObject *object )
3274 {
3275 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
3276
3277 if( object->description )
3278 return( object->description ) ;
3279 else
3280 return( class->description ) ;
3281 }
3282