1 /* Watch stuff in the prefs workspace.
2  */
3 
4 /*
5 
6     Copyright (C) 1991-2003 The National Gallery
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your watch) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License along
19     with this program; if not, write to the Free Software Foundation, Inc.,
20     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 
22  */
23 
24 /*
25 
26     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
27 
28  */
29 
30 /*
31 #define DEBUG
32  */
33 
34 #include "ip.h"
35 
36 static iContainerClass *watchgroup_parent_class = NULL;
37 
38 /* Our signals.
39  */
40 enum {
41 	SIG_WATCH_CHANGED,	/* "changed" on one of our watches */
42 	SIG_LAST
43 };
44 
45 static guint watchgroup_signals[SIG_LAST] = { 0 };
46 
47 static void
watchgroup_changed(Watchgroup * watchgroup,Watch * watch)48 watchgroup_changed( Watchgroup *watchgroup, Watch *watch )
49 {
50 	g_signal_emit( G_OBJECT( watchgroup ),
51 		watchgroup_signals[SIG_WATCH_CHANGED], 0, watch );
52 }
53 
54 static void
watchgroup_class_init(WatchgroupClass * class)55 watchgroup_class_init( WatchgroupClass *class )
56 {
57 	watchgroup_parent_class = g_type_class_peek_parent( class );
58 
59 	watchgroup_signals[SIG_WATCH_CHANGED] = g_signal_new( "watch_changed",
60 		G_OBJECT_CLASS_TYPE( class ),
61 		G_SIGNAL_RUN_FIRST,
62 		G_STRUCT_OFFSET( WatchgroupClass, watch_changed ),
63 		NULL, NULL,
64 		g_cclosure_marshal_VOID__OBJECT,
65 		G_TYPE_NONE, 1,
66 		TYPE_WATCH );
67 }
68 
69 static void
watchgroup_init(Watchgroup * watchgroup)70 watchgroup_init( Watchgroup *watchgroup )
71 {
72 #ifdef DEBUG
73 	printf( "watchgroup_init\n" );
74 #endif /*DEBUG*/
75 
76 	watchgroup->auto_save_timeout = 0;
77 }
78 
79 GType
watchgroup_get_type(void)80 watchgroup_get_type( void )
81 {
82 	static GType watchgroup_type = 0;
83 
84 	if( !watchgroup_type ) {
85 		static const GTypeInfo info = {
86 			sizeof( WatchgroupClass ),
87 			NULL,           /* base_init */
88 			NULL,           /* base_finalize */
89 			(GClassInitFunc) watchgroup_class_init,
90 			NULL,           /* class_finalize */
91 			NULL,           /* class_data */
92 			sizeof( Watchgroup ),
93 			32,             /* n_preallocs */
94 			(GInstanceInitFunc) watchgroup_init,
95 		};
96 
97 		watchgroup_type = g_type_register_static( TYPE_ICONTAINER,
98 			"Watchgroup", &info, 0 );
99 	}
100 
101 	return( watchgroup_type );
102 }
103 
104 Watchgroup *
watchgroup_new(Workspaceroot * workspaceroot,const char * name)105 watchgroup_new( Workspaceroot *workspaceroot, const char *name )
106 {
107 	Watchgroup *watchgroup = WATCHGROUP(
108 		g_object_new( TYPE_WATCHGROUP, NULL ) );
109 
110 	/* Assume it's a static string.
111 	 */
112 	watchgroup->name = name;
113 
114 	watchgroup->workspaceroot = workspaceroot;
115 	icontainer_set_hash( ICONTAINER( watchgroup ) );
116 
117 	return( watchgroup );
118 }
119 
120 /* Get the ws we are storing prefs in, and check it looks OK.
121  */
122 static Workspace *
watchgroup_get_workspace(Watchgroup * watchgroup)123 watchgroup_get_workspace( Watchgroup *watchgroup )
124 {
125 	Compile *compile;
126 	Symbol *sym;
127 
128 	if( !watchgroup->workspaceroot->sym )
129 		return( NULL );
130 
131 	compile = watchgroup->workspaceroot->sym->expr->compile;
132 
133 	if( !(sym = compile_lookup( compile, watchgroup->name )) ||
134 		!sym->expr->compile ||
135 		sym->type != SYM_WORKSPACE ||
136 		!sym->ws )
137 		return( NULL );
138 
139 	return( sym->ws );
140 }
141 
142 static void
watchgroup_save(Watchgroup * watchgroup)143 watchgroup_save( Watchgroup *watchgroup )
144 {
145 	Workspace *ws;
146 
147 	if( (ws = watchgroup_get_workspace( watchgroup )) ) {
148 		Workspacegroup *wsg = workspace_get_workspacegroup( ws );
149 		Filemodel *filemodel = FILEMODEL( wsg );
150 
151 		if( filemodel->modified ) {
152 			symbol_recalculate_all();
153 
154 			/* Ignore error returns ... hmm! Tricky: we can come
155 			 * here during shutdown.
156 			 */
157 			(void) filemodel_top_save( filemodel,
158 				filemodel->filename );
159 
160 			filemodel_set_modified( filemodel, FALSE );
161 		}
162 	}
163 }
164 
165 static gboolean
watchgroup_dirty_timeout_cb(Watchgroup * watchgroup)166 watchgroup_dirty_timeout_cb( Watchgroup *watchgroup )
167 {
168 	watchgroup->auto_save_timeout = 0;
169 
170 	watchgroup_save( watchgroup );
171 
172 	return( FALSE );
173 }
174 
175 void
watchgroup_dirty(Watchgroup * watchgroup)176 watchgroup_dirty( Watchgroup *watchgroup )
177 {
178 	Workspace *ws;
179 
180 	/* Find the preferences workspace.
181 	 */
182 	if( (ws = watchgroup_get_workspace( watchgroup )) ) {
183 		Workspacegroup *wsg = workspace_get_workspacegroup( ws );
184 
185 		/* Mark ws dirty, start save timer.
186 		 */
187 		filemodel_set_modified( FILEMODEL( wsg ), TRUE );
188 
189 		IM_FREEF( g_source_remove, watchgroup->auto_save_timeout );
190 		watchgroup->auto_save_timeout = g_timeout_add( 1000,
191 			(GSourceFunc) watchgroup_dirty_timeout_cb, watchgroup );
192 	}
193 }
194 
195 void
watchgroup_flush(Watchgroup * watchgroup)196 watchgroup_flush( Watchgroup *watchgroup )
197 {
198 	/* Do we have a pending save?
199 	 */
200 	if( watchgroup->auto_save_timeout ) {
201 		watchgroup_save( watchgroup );
202 
203 		IM_FREEF( g_source_remove, watchgroup->auto_save_timeout );
204 	}
205 }
206 
207 static iContainerClass *watch_parent_class = NULL;
208 static GSList *watch_all = NULL;
209 
210 static void
watch_finalize(GObject * gobject)211 watch_finalize( GObject *gobject )
212 {
213 	Watch *watch;
214 
215 	g_return_if_fail( gobject != NULL );
216 	g_return_if_fail( IS_WATCH( gobject ) );
217 
218 	watch = WATCH( gobject );
219 
220 #ifdef DEBUG
221 	printf( "watch_finalize: %s\n", NN( IOBJECT( watch )->name ) );
222 #endif /*DEBUG*/
223 
224 	watch_all = g_slist_remove( watch_all, watch );
225 
226 	G_OBJECT_CLASS( watch_parent_class )->finalize( gobject );
227 }
228 
229 static void
watch_dispose(GObject * gobject)230 watch_dispose( GObject *gobject )
231 {
232 	Watch *watch;
233 
234 	g_return_if_fail( gobject != NULL );
235 	g_return_if_fail( IS_WATCH( gobject ) );
236 
237 	watch = WATCH( gobject );
238 
239 #ifdef DEBUG
240 	printf( "watch_dispose: %s\n", NN( IOBJECT( watch )->name ) );
241 #endif /*DEBUG*/
242 
243 	/* My instance destroy stuff.
244 	 */
245 	FREESID( watch->destroy_sid, watch->row );
246 	FREESID( watch->changed_sid, watch->row );
247 	watch->row = NULL;
248 
249 	G_OBJECT_CLASS( watch_parent_class )->dispose( gobject );
250 }
251 
252 static void
watch_changed(iObject * iobject)253 watch_changed( iObject *iobject )
254 {
255 	Watch *watch = WATCH( iobject );
256 	Watchgroup *watchgroup = WATCHGROUP( ICONTAINER( watch )->parent );
257 
258 	/* Emit on our group too. Can get here before our parent is linked on,
259 	 * careful.
260 	 */
261 	if( watchgroup )
262 		watchgroup_changed( WATCHGROUP( ICONTAINER( watch )->parent ),
263 			watch );
264 
265 	IOBJECT_CLASS( watch_parent_class )->changed( iobject );
266 }
267 
268 static void
watch_class_init(WatchClass * class)269 watch_class_init( WatchClass *class )
270 {
271 	GObjectClass *gobject_class = (GObjectClass *) class;
272 	iObjectClass *iobject_class = (iObjectClass *) class;
273 	WatchClass *watch_class = (WatchClass *) class;
274 
275 	watch_parent_class = g_type_class_peek_parent( class );
276 
277 	gobject_class->finalize = watch_finalize;
278 	gobject_class->dispose = watch_dispose;
279 
280 	iobject_class->changed = watch_changed;
281 
282 	watch_class->update = NULL;
283 	watch_class->get_value = NULL;
284 }
285 
286 static void
watch_init(Watch * watch)287 watch_init( Watch *watch )
288 {
289 	watch->row = NULL;
290 	watch->ok = FALSE;
291 	watch->destroy_sid = 0;
292 	watch->changed_sid = 0;
293 
294 	watch_all = g_slist_prepend( watch_all, watch );
295 }
296 
297 GType
watch_get_type(void)298 watch_get_type( void )
299 {
300 	static GType watch_type = 0;
301 
302 	if( !watch_type ) {
303 		static const GTypeInfo info = {
304 			sizeof( WatchClass ),
305 			NULL,           /* base_init */
306 			NULL,           /* base_finalize */
307 			(GClassInitFunc) watch_class_init,
308 			NULL,           /* class_finalize */
309 			NULL,           /* class_data */
310 			sizeof( Watch ),
311 			32,             /* n_preallocs */
312 			(GInstanceInitFunc) watch_init,
313 		};
314 
315 		watch_type = g_type_register_static( TYPE_ICONTAINER,
316 			"Watch", &info, 0 );
317 	}
318 
319 	return( watch_type );
320 }
321 
322 static void
watch_link(Watch * watch,Watchgroup * watchgroup,const char * name)323 watch_link( Watch *watch, Watchgroup *watchgroup, const char *name )
324 {
325 	iobject_set( IOBJECT( watch ), name, NULL );
326 	icontainer_child_add( ICONTAINER( watchgroup ),
327 		ICONTAINER( watch ), -1 );
328 }
329 
330 static void
watch_destroy_cb(Row * row,Watch * watch)331 watch_destroy_cb( Row *row, Watch *watch )
332 {
333 #ifdef DEBUG
334 	printf( "watch_destroy_cb\n" );
335 #endif /*DEBUG*/
336 
337 	watch->row = NULL;
338 	watch->ok = FALSE;
339 	watch->destroy_sid = 0;
340 	watch->changed_sid = 0;
341 }
342 
343 /* The row we are watching has changed.
344  */
345 static void
watch_changed_cb(Row * row,Watch * watch)346 watch_changed_cb( Row *row, Watch *watch )
347 {
348 #ifdef DEBUG
349 	printf( "watch_changed_cb: %s\n", NN( IOBJECT( watch )->name ) );
350 #endif /*DEBUG*/
351 
352 	if( row->expr )
353 		watch->ok = WATCH_GET_CLASS( watch )->update( watch );
354 
355 	iobject_changed( IOBJECT( watch ) );
356 }
357 
358 /* Make sure we're linked to the thing we watch.
359  */
360 static void
watch_attach(Watch * watch)361 watch_attach( Watch *watch )
362 {
363 	Watchgroup *watchgroup = WATCHGROUP( ICONTAINER( watch )->parent );
364 	const char *name = IOBJECT( watch )->name;
365 	Workspace *ws;
366 	Symbol *sym;
367 
368 	if( watch->row )
369 		return;
370 
371 	if( (ws = watchgroup_get_workspace( watchgroup )) &&
372 		ws->sym->expr &&
373 		ws->sym->expr->compile &&
374 		(sym = compile_lookup( ws->sym->expr->compile, name )) &&
375 		sym->expr->row ) {
376 		watch->row = sym->expr->row;
377 		watch->destroy_sid =
378 			g_signal_connect( G_OBJECT( watch->row ), "destroy",
379 				G_CALLBACK( watch_destroy_cb ), watch );
380 		watch->changed_sid =
381 			g_signal_connect( G_OBJECT( watch->row ), "changed",
382 				G_CALLBACK( watch_changed_cb ), watch );
383 	}
384 }
385 
386 Watch *
watch_find(Watchgroup * watchgroup,const char * name)387 watch_find( Watchgroup *watchgroup, const char *name )
388 {
389 	return( (Watch *)
390 		(icontainer_child_lookup( ICONTAINER( watchgroup ), name )) );
391 }
392 
393 static gboolean
watch_get(Watch * watch,void ** out)394 watch_get( Watch *watch, void **out )
395 {
396 #ifdef DEBUG
397 	printf( "watch_get: %s\n", NN( IOBJECT( watch )->name ) );
398 #endif /*DEBUG*/
399 
400 	watch_attach( watch );
401 
402 	if( !watch->row )
403 		return( FALSE );
404 
405 	if( !watch->ok )
406 		watch->ok = WATCH_GET_CLASS( watch )->update( watch );
407 
408 	if( !watch->ok )
409 		return( FALSE );
410 
411 	*out = WATCH_GET_CLASS( watch )->get_value( watch );
412 
413 	return( TRUE );
414 }
415 
416 static void *
watch_relink(Watch * watch)417 watch_relink( Watch *watch )
418 {
419 	if( !watch->row ) {
420 		watch_attach( watch );
421 		if( watch->row )
422 			iobject_changed( IOBJECT( watch ) );
423 	}
424 
425 	return( NULL );
426 }
427 
428 void
watch_relink_all(void)429 watch_relink_all( void )
430 {
431 	slist_map( watch_all, (SListMapFn) watch_relink, NULL );
432 }
433 
434 void
watch_vset(Watch * watch,const char * fmt,va_list args)435 watch_vset( Watch *watch, const char *fmt, va_list args )
436 {
437 	Watchgroup *watchgroup = WATCHGROUP( ICONTAINER( watch )->parent );
438 
439 	Workspace *ws;
440 
441 	/* In case we try to set after prefs has gone.
442 	 */
443 	if( !(ws = watchgroup_get_workspace( watchgroup )) ||
444 		ws->in_dispose )
445 		return;
446 
447 	if( watch->row &&
448 		watch->row->child_rhs &&
449 		watch->row->child_rhs->itext ) {
450 		iText *itext = ITEXT( watch->row->child_rhs->itext );
451 		char buf[256];
452 
453 		(void) im_vsnprintf( buf, 256, fmt, args );
454 
455 		if( itext_set_formula( itext, buf ) ) {
456 #ifdef DEBUG
457 			printf( "watch_vset: %s = %s\n",
458 				IOBJECT( watch )->name, buf );
459 #endif /*DEBUG*/
460 
461 			itext_set_edited( itext, TRUE );
462 			if( watch->row->sym )
463 				expr_dirty( watch->row->sym->expr,
464 					link_serial_new() );
465 			watchgroup_dirty(
466 				WATCHGROUP( ICONTAINER( watch )->parent ) );
467 		}
468 	}
469 }
470 
471 void
watch_set(Watch * watch,const char * fmt,...)472 watch_set( Watch *watch, const char *fmt, ... )
473 {
474 	va_list args;
475 
476 	va_start( args, fmt );
477 	watch_vset( watch, fmt, args );
478 	va_end( args );
479 }
480 
481 static WatchClass *watch_double_parent_class = NULL;
482 
483 static gboolean
watch_double_update(Watch * watch)484 watch_double_update( Watch *watch )
485 {
486 	WatchDouble *watch_double = WATCH_DOUBLE( watch );
487 	PElement *root = &watch->row->expr->root;
488 
489 #ifdef DEBUG
490 	printf( "watch_double_update\n" );
491 #endif /*DEBUG*/
492 
493 	if( PEISNOVAL( root ) )
494 		return( FALSE );
495 	if( !PEISREAL( root ) ) {
496 		heap_error_typecheck( root, IOBJECT( watch )->name, "real" );
497 		return( FALSE );
498 	}
499 
500 	watch_double->value = PEGETREAL( root );
501 
502 	return( TRUE );
503 }
504 
505 static void *
watch_double_get_value(Watch * watch)506 watch_double_get_value( Watch *watch )
507 {
508 	WatchDouble *watch_double = WATCH_DOUBLE( watch );
509 
510 	return( (void *) &watch_double->value );
511 }
512 
513 static void
watch_double_class_init(WatchDoubleClass * class)514 watch_double_class_init( WatchDoubleClass *class )
515 {
516 	WatchClass *watch_class = (WatchClass *) class;
517 
518 	watch_double_parent_class = g_type_class_peek_parent( class );
519 
520 	watch_class->update = watch_double_update;
521 	watch_class->get_value = watch_double_get_value;
522 }
523 
524 static void
watch_double_init(WatchDouble * watch_double)525 watch_double_init( WatchDouble *watch_double )
526 {
527 #ifdef DEBUG
528 	printf( "watch_double_init\n" );
529 #endif /*DEBUG*/
530 
531 	watch_double->value = -1.0;
532 }
533 
534 GType
watch_double_get_type(void)535 watch_double_get_type( void )
536 {
537 	static GType watch_double_type = 0;
538 
539 	if( !watch_double_type ) {
540 		static const GTypeInfo info = {
541 			sizeof( WatchDoubleClass ),
542 			NULL,           /* base_init */
543 			NULL,           /* base_finalize */
544 			(GClassInitFunc) watch_double_class_init,
545 			NULL,           /* class_finalize */
546 			NULL,           /* class_data */
547 			sizeof( WatchDouble ),
548 			32,             /* n_preallocs */
549 			(GInstanceInitFunc) watch_double_init,
550 		};
551 
552 		watch_double_type = g_type_register_static( TYPE_WATCH,
553 			"WatchDouble", &info, 0 );
554 	}
555 
556 	return( watch_double_type );
557 }
558 
559 static Watch *
watch_double_new(Watchgroup * watchgroup,const char * name)560 watch_double_new( Watchgroup *watchgroup, const char *name )
561 {
562 	WatchDouble *watch_double = WATCH_DOUBLE(
563 		g_object_new( TYPE_WATCH_DOUBLE, NULL ) );
564 
565 	watch_link( WATCH( watch_double ), watchgroup, name );
566 
567 	return( WATCH( watch_double ) );
568 }
569 
570 double
watch_double_get(Watchgroup * watchgroup,const char * name,double fallback)571 watch_double_get( Watchgroup *watchgroup, const char *name, double fallback )
572 {
573 	Watch *watch;
574 	void *value;
575 
576 	if( !watchgroup )
577 		return( fallback );
578 
579 	if( !(watch = watch_find( watchgroup, name )) )
580 		watch = watch_double_new( watchgroup, name );
581 
582 	g_assert( IS_WATCH_DOUBLE( watch ) );
583 
584 	if( !watch_get( watch, &value ) )
585 		return( fallback );
586 
587 	return( *((double *) value) );
588 }
589 
590 static WatchClass *watch_int_parent_class = NULL;
591 
592 static gboolean
watch_int_update(Watch * watch)593 watch_int_update( Watch *watch )
594 {
595 	WatchInt *watch_int = WATCH_INT( watch );
596 	Expr *expr = watch->row->expr;
597 	PElement *root;
598 
599 #ifdef DEBUG
600 	printf( "watch_int_update: %s\n", NN( IOBJECT( watch )->name ) );
601 #endif /*DEBUG*/
602 
603 	/* Can get called during shutdown :-( main_watchgroup_changed_cb() can
604 	 * call us before destroying the row, but after killing the expr.
605 	 */
606 	if( !expr )
607 		return( FALSE );
608 	root = &expr->root;
609 	if( PEISNOVAL( root ) )
610 		return( FALSE );
611 	if( !PEISREAL( root ) ) {
612 		heap_error_typecheck( root, IOBJECT( watch )->name, "real" );
613 		return( FALSE );
614 	}
615 
616 	watch_int->value = IM_RINT( PEGETREAL( root ) );
617 
618 	return( TRUE );
619 }
620 
621 static void *
watch_int_get_value(Watch * watch)622 watch_int_get_value( Watch *watch )
623 {
624 	WatchInt *watch_int = WATCH_INT( watch );
625 
626 	return( (void *) &watch_int->value );
627 }
628 
629 static void
watch_int_class_init(WatchIntClass * class)630 watch_int_class_init( WatchIntClass *class )
631 {
632 	WatchClass *watch_class = (WatchClass *) class;
633 
634 	watch_int_parent_class = g_type_class_peek_parent( class );
635 
636 	watch_class->update = watch_int_update;
637 	watch_class->get_value = watch_int_get_value;
638 }
639 
640 static void
watch_int_init(WatchInt * watch_int)641 watch_int_init( WatchInt *watch_int )
642 {
643 #ifdef DEBUG
644 	printf( "watch_int_init\n" );
645 #endif /*DEBUG*/
646 
647 	watch_int->value = -1;
648 }
649 
650 GType
watch_int_get_type(void)651 watch_int_get_type( void )
652 {
653 	static GType watch_int_type = 0;
654 
655 	if( !watch_int_type ) {
656 		static const GTypeInfo info = {
657 			sizeof( WatchIntClass ),
658 			NULL,           /* base_init */
659 			NULL,           /* base_finalize */
660 			(GClassInitFunc) watch_int_class_init,
661 			NULL,           /* class_finalize */
662 			NULL,           /* class_data */
663 			sizeof( WatchInt ),
664 			32,             /* n_preallocs */
665 			(GInstanceInitFunc) watch_int_init,
666 		};
667 
668 		watch_int_type = g_type_register_static( TYPE_WATCH,
669 			"WatchInt", &info, 0 );
670 	}
671 
672 	return( watch_int_type );
673 }
674 
675 static Watch *
watch_int_new(Watchgroup * watchgroup,const char * name)676 watch_int_new( Watchgroup *watchgroup, const char *name )
677 {
678 	WatchInt *watch_int = WATCH_INT( g_object_new( TYPE_WATCH_INT, NULL ) );
679 
680 	watch_link( WATCH( watch_int ), watchgroup, name );
681 
682 	return( WATCH( watch_int ) );
683 }
684 
685 int
watch_int_get(Watchgroup * watchgroup,const char * name,int fallback)686 watch_int_get( Watchgroup *watchgroup, const char *name, int fallback )
687 {
688 	Watch *watch;
689 	void *value;
690 
691 	if( !watchgroup ||
692 		!name )
693 		return( fallback );
694 
695 	if( !(watch = watch_find( watchgroup, name )) )
696 		watch = watch_int_new( watchgroup, name );
697 
698 	g_assert( IS_WATCH_INT( watch ) );
699 
700 	if( !watch_get( watch, &value ) )
701 		return( fallback );
702 
703 	return( *((int *) value) );
704 }
705 
706 static WatchClass *watch_path_parent_class = NULL;
707 
708 static void
watch_path_finalize(GObject * gobject)709 watch_path_finalize( GObject *gobject )
710 {
711 	WatchPath *watch_path;
712 
713 	g_return_if_fail( gobject != NULL );
714 	g_return_if_fail( IS_WATCH_PATH( gobject ) );
715 
716 #ifdef DEBUG
717 	printf( "watch_path_finalize\n" );
718 #endif /*DEBUG*/
719 
720 	watch_path = WATCH_PATH( gobject );
721 
722 	/* My instance destroy stuff.
723 	 */
724 	IM_FREEF( slist_free_all, watch_path->value );
725 
726 	G_OBJECT_CLASS( watch_path_parent_class )->finalize( gobject );
727 }
728 
729 static gboolean
watch_path_update(Watch * watch)730 watch_path_update( Watch *watch )
731 {
732 	WatchPath *watch_path = WATCH_PATH( watch );
733 	PElement *root = &watch->row->expr->root;
734 	GSList *value;
735 
736 #ifdef DEBUG
737 	printf( "watch_path_update\n" );
738 #endif /*DEBUG*/
739 
740 	if( !heap_get_lstring( root, &value ) )
741 		return( FALSE );
742 
743 	IM_FREEF( slist_free_all, watch_path->value );
744 	watch_path->value = value;
745 
746 	return( TRUE );
747 }
748 
749 static void *
watch_path_get_value(Watch * watch)750 watch_path_get_value( Watch *watch )
751 {
752 	WatchPath *watch_path = WATCH_PATH( watch );
753 
754 	return( (void *) &watch_path->value );
755 }
756 
757 static void
watch_path_class_init(WatchPathClass * class)758 watch_path_class_init( WatchPathClass *class )
759 {
760 	GObjectClass *gobject_class = (GObjectClass *) class;
761 	WatchClass *watch_class = (WatchClass *) class;
762 
763 	watch_path_parent_class = g_type_class_peek_parent( class );
764 
765 	gobject_class->finalize = watch_path_finalize;
766 
767 	watch_class->update = watch_path_update;
768 	watch_class->get_value = watch_path_get_value;
769 }
770 
771 static void
watch_path_init(WatchPath * watch_path)772 watch_path_init( WatchPath *watch_path )
773 {
774 #ifdef DEBUG
775 	printf( "watch_path_init\n" );
776 #endif /*DEBUG*/
777 
778 	watch_path->value = NULL;
779 }
780 
781 GType
watch_path_get_type(void)782 watch_path_get_type( void )
783 {
784 	static GType watch_path_type = 0;
785 
786 	if( !watch_path_type ) {
787 		static const GTypeInfo info = {
788 			sizeof( WatchPathClass ),
789 			NULL,           /* base_init */
790 			NULL,           /* base_finalize */
791 			(GClassInitFunc) watch_path_class_init,
792 			NULL,           /* class_finalize */
793 			NULL,           /* class_data */
794 			sizeof( WatchPath ),
795 			32,             /* n_preallocs */
796 			(GInstanceInitFunc) watch_path_init,
797 		};
798 
799 		watch_path_type = g_type_register_static( TYPE_WATCH,
800 			"WatchPath", &info, 0 );
801 	}
802 
803 	return( watch_path_type );
804 }
805 
806 static Watch *
watch_path_new(Watchgroup * watchgroup,const char * name)807 watch_path_new( Watchgroup *watchgroup, const char *name )
808 {
809 	WatchPath *watch_path = WATCH_PATH(
810 		g_object_new( TYPE_WATCH_PATH, NULL ) );
811 
812 	watch_link( WATCH( watch_path ), watchgroup, name );
813 
814 	return( WATCH( watch_path ) );
815 }
816 
817 GSList *
watch_path_get(Watchgroup * watchgroup,const char * name,GSList * fallback)818 watch_path_get( Watchgroup *watchgroup, const char *name, GSList *fallback )
819 {
820 	Watch *watch;
821 	void *value;
822 
823 	if( !watchgroup )
824 		return( fallback );
825 
826 	if( !(watch = watch_find( watchgroup, name )) )
827 		watch = watch_path_new( watchgroup, name );
828 
829 	g_assert( IS_WATCH_PATH( watch ) );
830 
831 	if( !watch_get( watch, &value ) )
832 		return( fallback );
833 
834 	return( *((GSList **) value) );
835 }
836 
837 static WatchClass *watch_bool_parent_class = NULL;
838 
839 static gboolean
watch_bool_update(Watch * watch)840 watch_bool_update( Watch *watch )
841 {
842 	WatchBool *watch_bool = WATCH_BOOL( watch );
843 	PElement *root = &watch->row->expr->root;
844 
845 #ifdef DEBUG
846 	printf( "watch_bool_update: %s\n", NN( IOBJECT( watch )->name ) );
847 #endif /*DEBUG*/
848 
849 	if( PEISNOVAL( root ) )
850 		return( FALSE );
851 	if( !PEISBOOL( root ) ) {
852 		heap_error_typecheck( root, IOBJECT( watch )->name, "bool" );
853 		return( FALSE );
854 	}
855 
856 	watch_bool->value = PEGETBOOL( root );
857 
858 	return( TRUE );
859 }
860 
861 static void *
watch_bool_get_value(Watch * watch)862 watch_bool_get_value( Watch *watch )
863 {
864 	WatchBool *watch_bool = WATCH_BOOL( watch );
865 
866 	return( (void *) &watch_bool->value );
867 }
868 
869 static void
watch_bool_class_init(WatchBoolClass * class)870 watch_bool_class_init( WatchBoolClass *class )
871 {
872 	WatchClass *watch_class = (WatchClass *) class;
873 
874 	watch_bool_parent_class = g_type_class_peek_parent( class );
875 
876 	watch_class->update = watch_bool_update;
877 	watch_class->get_value = watch_bool_get_value;
878 }
879 
880 static void
watch_bool_init(WatchBool * watch_bool)881 watch_bool_init( WatchBool *watch_bool )
882 {
883 #ifdef DEBUG
884 	printf( "watch_bool_init\n" );
885 #endif /*DEBUG*/
886 
887 	watch_bool->value = FALSE;
888 }
889 
890 GType
watch_bool_get_type(void)891 watch_bool_get_type( void )
892 {
893 	static GType watch_bool_type = 0;
894 
895 	if( !watch_bool_type ) {
896 		static const GTypeInfo info = {
897 			sizeof( WatchBoolClass ),
898 			NULL,           /* base_init */
899 			NULL,           /* base_finalize */
900 			(GClassInitFunc) watch_bool_class_init,
901 			NULL,           /* class_finalize */
902 			NULL,           /* class_data */
903 			sizeof( WatchBool ),
904 			32,             /* n_preallocs */
905 			(GInstanceInitFunc) watch_bool_init,
906 		};
907 
908 		watch_bool_type = g_type_register_static( TYPE_WATCH,
909 			"WatchBool", &info, 0 );
910 	}
911 
912 	return( watch_bool_type );
913 }
914 
915 static Watch *
watch_bool_new(Watchgroup * watchgroup,const char * name)916 watch_bool_new( Watchgroup *watchgroup, const char *name )
917 {
918 	WatchBool *watch_bool = WATCH_BOOL(
919 		g_object_new( TYPE_WATCH_BOOL, NULL ) );
920 
921 	watch_link( WATCH( watch_bool ), watchgroup, name );
922 
923 	return( WATCH( watch_bool ) );
924 }
925 
926 gboolean
watch_bool_get(Watchgroup * watchgroup,const char * name,gboolean fallback)927 watch_bool_get( Watchgroup *watchgroup, const char *name, gboolean fallback )
928 {
929 	Watch *watch;
930 	void *value;
931 
932 	if( !watchgroup )
933 		return( fallback );
934 
935 	if( !(watch = watch_find( watchgroup, name )) )
936 		watch = watch_bool_new( watchgroup, name );
937 
938 	g_assert( IS_WATCH_BOOL( watch ) );
939 
940 	if( !watch_get( watch, &value ) )
941 		return( fallback );
942 
943 	return( *((gboolean *) value) );
944 }
945 
946 static WatchClass *watch_string_parent_class = NULL;
947 
948 static void
watch_string_finalize(GObject * gobject)949 watch_string_finalize( GObject *gobject )
950 {
951 	WatchString *watch_string;
952 
953 	g_return_if_fail( gobject != NULL );
954 	g_return_if_fail( IS_WATCH_STRING( gobject ) );
955 
956 #ifdef DEBUG
957 	printf( "watch_string_finalize\n" );
958 #endif /*DEBUG*/
959 
960 	watch_string = WATCH_STRING( gobject );
961 
962 	/* My instance destroy stuff.
963 	 */
964 	IM_FREE( watch_string->value );
965 
966 	G_OBJECT_CLASS( watch_string_parent_class )->finalize( gobject );
967 }
968 
969 static gboolean
watch_string_update(Watch * watch)970 watch_string_update( Watch *watch )
971 {
972 	WatchString *watch_string = WATCH_STRING( watch );
973 	PElement *root = &watch->row->expr->root;
974 	char value[1024];
975 
976 #ifdef DEBUG
977 	printf( "watch_string_update\n" );
978 #endif /*DEBUG*/
979 
980 	if( !heap_get_string( root, value, 1024 ) )
981 		return( FALSE );
982 
983 	IM_SETSTR( watch_string->value, value );
984 
985 	return( TRUE );
986 }
987 
988 static void *
watch_string_get_value(Watch * watch)989 watch_string_get_value( Watch *watch )
990 {
991 	WatchString *watch_string = WATCH_STRING( watch );
992 
993 	return( (void *) &watch_string->value );
994 }
995 
996 static void
watch_string_class_init(WatchStringClass * class)997 watch_string_class_init( WatchStringClass *class )
998 {
999 	GObjectClass *gobject_class = (GObjectClass *) class;
1000 	WatchClass *watch_class = (WatchClass *) class;
1001 
1002 	watch_string_parent_class = g_type_class_peek_parent( class );
1003 
1004 	gobject_class->finalize = watch_string_finalize;
1005 
1006 	watch_class->update = watch_string_update;
1007 	watch_class->get_value = watch_string_get_value;
1008 }
1009 
1010 static void
watch_string_init(WatchString * watch_string)1011 watch_string_init( WatchString *watch_string )
1012 {
1013 #ifdef DEBUG
1014 	printf( "watch_string_init\n" );
1015 #endif /*DEBUG*/
1016 
1017 	watch_string->value = NULL;
1018 }
1019 
1020 GType
watch_string_get_type(void)1021 watch_string_get_type( void )
1022 {
1023 	static GType watch_string_type = 0;
1024 
1025 	if( !watch_string_type ) {
1026 		static const GTypeInfo info = {
1027 			sizeof( WatchStringClass ),
1028 			NULL,           /* base_init */
1029 			NULL,           /* base_finalize */
1030 			(GClassInitFunc) watch_string_class_init,
1031 			NULL,           /* class_finalize */
1032 			NULL,           /* class_data */
1033 			sizeof( WatchString ),
1034 			32,             /* n_preallocs */
1035 			(GInstanceInitFunc) watch_string_init,
1036 		};
1037 
1038 		watch_string_type = g_type_register_static( TYPE_WATCH,
1039 			"WatchString", &info, 0 );
1040 	}
1041 
1042 	return( watch_string_type );
1043 }
1044 
1045 static Watch *
watch_string_new(Watchgroup * watchgroup,const char * name)1046 watch_string_new( Watchgroup *watchgroup, const char *name )
1047 {
1048 	WatchString *watch_string = WATCH_STRING(
1049 		g_object_new( TYPE_WATCH_STRING, NULL ) );
1050 
1051 	watch_link( WATCH( watch_string ), watchgroup, name );
1052 
1053 	return( WATCH( watch_string ) );
1054 }
1055 
1056 const char *
watch_string_get(Watchgroup * watchgroup,const char * name,const char * fallback)1057 watch_string_get( Watchgroup *watchgroup,
1058 	const char *name, const char *fallback )
1059 {
1060 	Watch *watch;
1061 	void *value;
1062 
1063 	if( !watchgroup )
1064 		return( fallback );
1065 
1066 	if( !(watch = watch_find( watchgroup, name )) )
1067 		watch = watch_string_new( watchgroup, name );
1068 
1069 	g_assert( IS_WATCH_STRING( watch ) );
1070 
1071 	if( !watch_get( watch, &value ) )
1072 		return( fallback );
1073 
1074 	return( *((const char **) value) );
1075 }
1076 
1077