1 /*
2  * $Id: helperFuncs.c,v 1.11 2005/01/01 15:27:54 baum Exp $
3  *
4  * This file implements some helper functions
5  *
6  * Copyright (c) 2001 - 2005 Peter G. Baum  http://www.dr-baum.net
7  *
8  * See the file "license.terms" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  */
12 
13 /*
14    History:
15    2013-07: removed gnoclGetWidgetOptions func, moved to parseOptions.c
16    2013-06: added str_replace
17    2012-03: added trim
18    2010-10: added stringtype
19    2010-07: added cmds2list
20    2009-01: added getIdx
21    2009-01: added gnoclGetWigdetGeometry
22         05: added gnoclPosOffset from text.c
23    2003-04: added gnoclPixbufFromObj
24    2002-12: removed gnoclEventToString
25             joined with convert.c
26         09: gnoclFindLabel, gnoclLabelParseULine
27    2001-07: Begin of developement
28  */
29 
30 #include "gnocl.h"
31 #include <gdk-pixbuf/gdk-pixbuf.h>
32 
33 typedef struct
34 {
35 	GtkWidget *widget;
36 	GtkType   type;
37 } FindWidgetStruct;
38 
39 /**
40  Remove white spaces on both sides of a string.
41 **/
42 
trim(char * s)43 char *trim ( char *s )
44 {
45 	char *ptr;
46 
47 	if ( !s )
48 	{
49 		return NULL;   // handle NULL string
50 	}
51 
52 	if ( !*s )
53 	{
54 		return s;      // handle empty string
55 	}
56 
57 	for ( ptr = s + strlen ( s ) - 1; ( ptr >= s ) && isspace ( *ptr ); --ptr );
58 
59 	ptr[1] = '\0';
60 	return s;
61 }
62 
63 
64 /**
65 \brief	Write fucntion and step to stdout.
66 **/
debugStep(gchar * str,gdouble i)67 void debugStep ( gchar *str, gdouble i )
68 {
69 	g_print ( "%s %2.01f\n", str, i );
70 }
71 
72 /**
73 \brief	Obtain the height and width of a pango string in pixels.
74 **/
getTextWidth(GtkWidget * widget,char * family,int ptsize,int weight,int normalstyle,char * stringtomeasure,int * wdret,int * htret)75 void getTextWidth ( GtkWidget *widget, char * family , int ptsize , int weight , int normalstyle ,
76 					char * stringtomeasure ,
77 					int * wdret , int * htret )
78 {
79 	PangoFontDescription * fd = pango_font_description_new ( );
80 
81 	pango_font_description_set_family ( fd, family );
82 	pango_font_description_set_style ( fd, normalstyle ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC );
83 	pango_font_description_set_variant ( fd, PANGO_VARIANT_NORMAL );
84 	pango_font_description_set_weight ( fd, ( PangoWeight ) weight );
85 	pango_font_description_set_stretch ( fd, PANGO_STRETCH_NORMAL );
86 	pango_font_description_set_size ( fd, ptsize * PANGO_SCALE );
87 
88 	PangoContext * context = gtk_widget_get_pango_context ( widget ) ;
89 
90 	PangoLayout * layout = pango_layout_new ( context );
91 	pango_layout_set_text ( layout, stringtomeasure, -1 );
92 	pango_layout_set_font_description ( layout, fd );
93 	pango_layout_get_pixel_size ( layout, wdret , htret );
94 	g_object_unref ( layout );
95 }
96 
97 
98 /**
99 \brief Return Units
100 **/
101 
getUnits(gchar * str)102 gchar * getUnits ( gchar *str )
103 {
104 
105 	gint ret = 0;
106 
107 	static const char *units[] =
108 	{
109 		"pixel", "points", "inch", "mm",
110 		NULL
111 	};
112 
113 	enum unitIdx
114 	{
115 		PixelIdx, PointsIdx, InchIdx, MmIdx
116 	};
117 
118 	getIdx ( units, str, &ret );
119 
120 	if ( ret )
121 	{
122 		return str;
123 	}
124 
125 	else
126 	{
127 		return NULL;
128 	}
129 
130 }
131 
132 /**
133 \brief	Return the number of items in a space separated list.
134 **/
listLength(char * str)135 int listLength ( char *str )
136 {
137 
138 	int len;
139 
140 	char * pch;
141 	len = 0;
142 
143 	pch = strtok ( str, " " );
144 
145 	while ( pch != NULL )
146 	{
147 		pch = strtok ( NULL, " " );
148 		len++;
149 	}
150 
151 	return len;
152 }
153 
154 /**
155 \brief	Return substring of range idx to len from string str.
156 **/
substring(char * str,int idx,int len)157 char *substring ( char *str, int idx, int len )
158 {
159 
160 	int i;
161 	char *to;
162 
163 	i =  strlen ( str ) ;
164 	to = ( char* ) malloc ( i );
165 
166 	strncpy ( to, str + idx, len );
167 	return to;
168 
169 }
170 
171 /**
172 \brief Programming utility function that lists parameters.
173 **/
listParameters(int objc,Tcl_Obj * const objv[],char * str)174 void listParameters ( int objc, Tcl_Obj * const objv[], char *str )
175 {
176 	gint i = 0;
177 
178 	g_print ( "---------------\n" );
179 	printf ( "%s\n", str );
180 
181 	while ( i < objc )
182 	{
183 		g_print ( "  %d = %s\n", i, Tcl_GetString ( objv[i] ) );
184 		i++;
185 	}
186 
187 }
188 
189 /**
190 \brief	Return the number of items in a CSV data string.
191 **/
getSize(char * str1,char * sep)192 int getSize ( char *str1, char *sep )
193 {
194 	char *pch;
195 	int  i;
196 	char str2[256];
197 
198 	/* get a copy of the data string */
199 	sprintf ( str2, "%s", str1 );
200 
201 	i = 0;
202 	pch = strtok ( str2, sep );
203 
204 	while ( pch != NULL )
205 	{
206 		pch = strtok ( NULL, sep );
207 		i++;
208 	}
209 
210 	return i;
211 }
212 
213 /**
214 /brief 	Convert a string of CSV decimal numbers into an array of doubles.
215 **/
getdoubles(char * str1,gdouble myFloats[])216 int getdoubles ( char *str1, gdouble myFloats[] )
217 {
218 	char * pch;
219 	int  i;
220 	char str2[strlen ( str1 ) ];
221 
222 	/* get a copy of the data string */
223 	sprintf ( str2, "%s", str1 );
224 
225 	i = 0;
226 	pch = strtok ( str2, "," );
227 
228 	while ( pch != NULL )
229 	{
230 		myFloats[i] = atof ( pch );
231 		pch = strtok ( NULL, "," );
232 		i++;
233 	}
234 
235 	return i;
236 
237 }
238 
239 /**
240 \brief    Compare string with list of acceptable choices. Return index of any match.
241 \note     For use in conjuction with switch to determine action based upon one of a range of choices given choices.
242 \see      getIDx
243 **/
compare(char * str,char * choices[])244 int compare ( char *str, char *choices[] )
245 {
246 
247 	int i;
248 
249 	for ( i = 0; choices[i] != NULL ; i++ )
250 	{
251 		if ( strcmp ( str, choices[i] ) == 0 )
252 		{
253 			return i;
254 		}
255 	}
256 }
257 
258 /**
259 \brief Return a NULL terminated string array as a list.
260 **/
cmds2list(gchar * arr[])261 gchar * cmds2list ( gchar *arr[] )
262 {
263 
264 	gchar buffer[512];
265 	char *ptr;
266 	gint len = 0;
267 
268 	sprintf ( buffer, "%s", "" );
269 
270 	while ( ptr != NULL )
271 	{
272 		sprintf ( buffer, "%s %s", buffer, arr[len] );
273 		ptr = arr[++len];
274 	}
275 
276 	return buffer;
277 }
278 
279 /**
280 \brief	A programming utility function, it returns the type of option string received.
281 **/
stringtype(int type)282 gchar *stringtype ( int type )
283 {
284 	switch ( type )
285 	{
286 		case GNOCL_STR_EMPTY:
287 			{
288 				return "empty";
289 			}
290 		case GNOCL_STR_STR:
291 			{
292 				return "string";
293 			}
294 		case GNOCL_STR_STOCK:
295 			{
296 				return "stockItem";
297 			}
298 		case GNOCL_STR_FILE:
299 			{
300 				return "file";
301 			}
302 		case GNOCL_STR_TRANSLATE:
303 			{
304 				return "translate";
305 			}
306 		case GNOCL_STR_UNDERLINE:
307 			{
308 				return "underline";
309 			}
310 		case GNOCL_STR_MARKUP:
311 			{
312 				return "markup";
313 			}
314 		case GNOCL_STR_BUFFER:
315 			{
316 				return "pixBuf";
317 			}
318 	}
319 
320 	return "unknown";
321 
322 }
323 
324 /**
325 \brief append to string
326 **/
str_append(const char * s1,const char * s2)327 char *str_append ( const char *s1, const char *s2 )
328 {
329 	char *s0 = malloc ( strlen ( s1 ) + strlen ( s2 ) + 1 );
330 	strcpy ( s0, s1 );
331 	strcat ( s0, s2 );
332 	return s0;
333 }
334 
335 /**
336 \brief	prepend to string
337 **/
str_prepend(const char * s1,const char * s2)338 char *str_prepend ( const char *s1, const char *s2 )
339 {
340 	char *s0 = malloc ( strlen ( s1 ) + strlen ( s2 ) + 1 );
341 	strcpy ( s0, s2 );
342 	strcat ( s0, s1 );
343 	return s0;
344 }
345 
346 
347 /**
348 \brief	replace all occurances of substring.
349 **/
str_replace(const char * string,const char * substr,const char * replacement)350 char *str_replace ( const char *string, const char *substr, const char *replacement )
351 {
352 	char *tok = NULL;
353 	char *newstr = NULL;
354 	char *oldstr = NULL;
355 	char *head = NULL;
356 
357 	/* if either substr or replacement is NULL, duplicate string a let caller handle it */
358 	if ( substr == NULL || replacement == NULL ) return strdup ( string );
359 
360 	newstr = strdup ( string );
361 	head = newstr;
362 
363 	while ( ( tok = strstr ( head, substr ) ) )
364 	{
365 		oldstr = newstr;
366 		newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) + 1 );
367 
368 		/*failed to alloc mem, free old string and return NULL */
369 		if ( newstr == NULL )
370 		{
371 			free ( oldstr );
372 			return NULL;
373 		}
374 
375 		memcpy ( newstr, oldstr, tok - oldstr );
376 		memcpy ( newstr + ( tok - oldstr ), replacement, strlen ( replacement ) );
377 		memcpy ( newstr + ( tok - oldstr ) + strlen ( replacement ), tok + strlen ( substr ), strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) );
378 		memset ( newstr + strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) , 0, 1 );
379 		/* move back head right after the last replacement */
380 		head = newstr + ( tok - oldstr ) + strlen ( replacement );
381 		free ( oldstr );
382 	}
383 
384 	return newstr;
385 }
386 
387 /**
388 \brief      Get index of matched string in an NULL terminated array of strings.
389 \author     William J Giddings
390 \date       05/05/09
391 \param      gchar *opts[]   Pointer the array containing keywords
392 \param      gchar *str      Pointer to the string to match
393 \param      gint *idx       Pointer to int which contains the matched index
394 \return     boolean, returns 0 is match found else -1
395 \note       Useful for making choices from a list and processing with switch.
396 **/
getIdx(gchar * opts[],gchar * str,gint * idx)397 int getIdx ( gchar *opts[], gchar *str, gint *idx )
398 {
399 #ifdef DEBUG_HELPERFUNCS
400 	g_print ( "helperFuncs getIdx\n" );
401 	g_printf ( "\topts = %s\n", opts );
402 	g_printf ( "\tstr = %s\n", str );
403 	g_printf ( "\tidx = %s\n", *idx );
404 #endif
405 
406 	int i = 0;
407 
408 	while ( opts[i] != NULL ) /* go through array until NULL encountered */
409 	{
410 
411 		if ( strcmp ( str , opts[i] ) == 0 )
412 		{
413 			*idx = i;
414 			return 0;
415 		}
416 
417 		i++;
418 	}
419 
420 	/* must be an error here! */
421 	return -1;
422 }
423 
424 
425 /**
426 \author     William J Giddings
427 \date       15/01/09
428 **/
gnoclGetWidgetGeometry(GtkWidget * widget)429 char *gnoclGetWidgetGeometry ( GtkWidget *widget )
430 {
431 	gint x, y;
432 	gint w, h;
433 	char txt[500];
434 
435 	x = widget->allocation.x;
436 	y = widget->allocation.y;
437 	w = widget->allocation.width;
438 	h = widget->allocation.height;
439 
440 	sprintf ( txt, "%d %d %d %d", x, y, w, h );
441 
442 	return txt;
443 }
444 
445 
446 /**
447 \brief      Find the "internal children" of a container widget.
448 **/
findChildIntern(GtkWidget * widget,gpointer data)449 static void findChildIntern ( GtkWidget *widget, gpointer data )
450 {
451 	FindWidgetStruct *fw = ( FindWidgetStruct * ) data;
452 
453 	if ( fw->widget == NULL )
454 	{
455 		if ( GTK_CHECK_TYPE ( widget, fw->type ) )
456 		{
457 			fw->widget = widget;
458 		}
459 
460 		else if ( GTK_IS_CONTAINER ( widget ) )
461 		{
462 			gtk_container_foreach ( GTK_CONTAINER ( widget ), findChildIntern, data );
463 		}
464 	}
465 }
466 
467 /**
468 \brief
469 **/
gnoclFindChild(GtkWidget * widget,GtkType type)470 GtkWidget *gnoclFindChild ( GtkWidget *widget, GtkType type )
471 {
472 	FindWidgetStruct fw;
473 	fw.widget = NULL;
474 	fw.type = type;
475 	findChildIntern ( widget, &fw );
476 	return fw.widget;
477 }
478 
479 
480 /**
481 **/
gnoclPosOffset(Tcl_Interp * interp,const char * txt,int * offset)482 int gnoclPosOffset ( Tcl_Interp *interp, const char *txt, int *offset )
483 {
484 	*offset = 0;
485 	/* pos[+-]offset */
486 
487 	if ( *txt == '+' || *txt == '-' )
488 	{
489 		if ( sscanf ( txt + 1, "%d", offset ) != 1 )
490 		{
491 			Tcl_AppendResult ( interp, "invalid offset \"", txt + 1, "\"", NULL );
492 			return TCL_ERROR;
493 		}
494 
495 		if ( *txt == '-' )
496 			*offset *= -1;
497 
498 		for ( ++txt; isdigit ( *txt ); ++txt )
499 			;
500 	}
501 
502 	if ( *txt )
503 	{
504 		Tcl_AppendResult ( interp, "invalid appendix \"", txt, "\"", NULL );
505 		return TCL_ERROR;
506 	}
507 
508 	return TCL_OK;
509 }
510 
511 /**
512 \brief Substitute percentage marker with values and then execute script.
513 
514 **/
gnoclPercentSubstAndEval(Tcl_Interp * interp,GnoclPercSubst * ps,const char * orig_script,int background)515 int gnoclPercentSubstAndEval ( Tcl_Interp *interp, GnoclPercSubst *ps, const char *orig_script, int background )
516 {
517 
518 #ifdef DEBUG_HELPERFUNCS
519 	g_print ( "gnoclPercentSubstAndEval\n" );
520 #endif
521 
522 	int        len = strlen ( orig_script );
523 	const char *old_perc = orig_script;
524 	const char *perc;
525 	GString    *script = g_string_sized_new ( len + 20 );
526 	int        ret;
527 
528 	for ( ; ( perc = strchr ( old_perc, '%' ) ) != NULL; old_perc = perc + 2 )
529 	{
530 		g_string_sprintfa ( script, "%.*s", perc - old_perc, old_perc );
531 
532 #ifdef DEBUG_HELPERFUNCS
533 		printf ( "\t1) script: \"%s\"\n", script->str );
534 #endif
535 
536 		if ( perc[1] == '%' )
537 			g_string_append_c ( script, '%' );
538 		else
539 		{
540 			int k = 0;
541 
542 			while ( ps[k].c && ps[k].c != perc[1] )
543 				++k;
544 
545 			if ( ps[k].c == 0 )
546 			{
547 #ifdef DEBUG_HELPERFUNCS
548 				printf ( "\t2) DEBUG: unknown percent substitution %c\n", perc[1] );
549 #endif
550 				/*
551 				Tcl_AppendResult( interp, "unknown percent substitution" ,
552 				      (char *)NULL );
553 				g_string_free( script, 1 );
554 				return TCL_ERROR;
555 				*/
556 				g_string_append_c ( script, '%' );
557 				g_string_append_c ( script, perc[1] );
558 			}
559 
560 			else
561 			{
562 				switch ( ps[k].type )
563 				{
564 					case GNOCL_STRING:
565 						/* FIXME: escape special characters: ' ', '\n', '\\' ...
566 						   or use Tcl_EvalObj? */
567 
568 						if ( ps[k].val.str != NULL )
569 						{
570 							/* handle special characters correctly
571 							   TODO: would it be better to escape
572 							         special characters?
573 							*/
574 							char *txt = Tcl_Merge ( 1, &ps[k].val.str );
575 							g_string_append ( script, txt );
576 #ifdef DEBUG_HELPERFUNCS
577 							printf ( "\t3) percent string: \"%s\" -> \"%s\"\n", ps[k].val.str, txt );
578 #endif
579 							Tcl_Free ( txt );
580 							//g_string_free (txt,1);
581 						}
582 
583 						else
584 							g_string_append ( script, "{}" );
585 
586 						break;
587 
588 					case GNOCL_OBJ:
589 
590 						if ( ps[k].val.obj != NULL )
591 						{
592 							/* embedden 0s should be UTF encoded. Should
593 							   therefor also work. */
594 							/*
595 							g_string_sprintfa( script, "%s",
596 							      Tcl_GetString( ps[k].val.obj ) );
597 							*/
598 							const char *argv[2] = { NULL, NULL };
599 							char *txt;
600 							argv[0] = Tcl_GetString ( ps[k].val.obj );
601 							txt = Tcl_Merge ( 1, argv );
602 							g_string_append ( script, txt );
603 							Tcl_Free ( txt );
604 
605 						}
606 
607 						else
608 							g_string_append ( script, "{}" );
609 
610 						break;
611 
612 					case GNOCL_INT:
613 						g_string_sprintfa ( script, "%d", ps[k].val.i );
614 
615 						break;
616 
617 					case GNOCL_BOOL:
618 						g_string_sprintfa ( script, "%d", ps[k].val.b != 0 );
619 
620 						break;
621 
622 					case GNOCL_DOUBLE:
623 						g_string_sprintfa ( script, "%f", ps[k].val.d );
624 
625 						break;
626 
627 					default:
628 						assert ( 0 );
629 
630 						break;
631 				}
632 			}
633 		}
634 	}
635 
636 	g_string_append ( script, old_perc );
637 
638 	/* Tcl_EvalObj would be faster and more elegant, but incompatible: eg. two consecutive percent substitutions without space */
639 	ret = Tcl_EvalEx ( interp, script->str, -1, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT );
640 
641 #ifdef DEBUG_HELPERFUNCS
642 	printf ( "\t4) DEBUG: script in percEval: %s -> %d %s\n", script->str, ret, Tcl_GetString ( Tcl_GetObjResult ( interp ) ) );
643 #endif
644 
645 	g_string_free ( script, 1 );
646 
647 	if ( background && ret != TCL_OK )
648 	{
649 		Tcl_BackgroundError ( interp );
650 	}
651 
652 	return ret;
653 }
654 
655 /**
656 \brief
657 **/
gnoclAttachVariable(GnoclOption * newVar,char ** oldVar,const char * signal,GObject * obj,GCallback gtkFunc,Tcl_Interp * interp,Tcl_VarTraceProc tclFunc,gpointer data)658 int gnoclAttachVariable ( GnoclOption *newVar, char **oldVar, const char *signal, GObject *obj,
659 						  GCallback gtkFunc, Tcl_Interp *interp, Tcl_VarTraceProc tclFunc, gpointer data )
660 {
661 	if ( *oldVar && ( newVar == NULL || newVar->status == GNOCL_STATUS_CHANGED ) )
662 		Tcl_UntraceVar ( interp, *oldVar, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY,
663 						 tclFunc, data );
664 
665 	if ( newVar == NULL || newVar->status != GNOCL_STATUS_CHANGED
666 			|| newVar->val.str[0] == 0 )
667 	{
668 		/* no new variable -> delete all */
669 		if ( *oldVar )
670 		{
671 			g_signal_handlers_disconnect_matched ( obj,
672 												   G_SIGNAL_MATCH_FUNC, 0, 0, NULL, ( gpointer * ) gtkFunc, NULL );
673 			g_free ( *oldVar );
674 			*oldVar = NULL;
675 		}
676 	}
677 
678 	else
679 	{
680 		if ( *oldVar == NULL )    /* new variable but old didn't exist */
681 			g_signal_connect ( obj, signal, gtkFunc, data );
682 		else                      /* new variable and old did exist */
683 			g_free ( *oldVar );
684 
685 		*oldVar = newVar->val.str;    /* transfer ownership */
686 
687 		newVar->val.str = NULL;
688 
689 		Tcl_TraceVar ( interp, *oldVar, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY,
690 					   tclFunc, data );
691 	}
692 
693 	return TCL_OK;
694 }
695 
696 /**
697 \brief  Provides tracer function on variables
698  */
gnoclAttachOptCmdAndVar(GnoclOption * newCmd,char ** oldCmd,GnoclOption * newVar,char ** oldVar,const char * signal,GObject * obj,GCallback gtkFunc,Tcl_Interp * interp,Tcl_VarTraceProc tclFunc,gpointer data)699 int gnoclAttachOptCmdAndVar ( GnoclOption *newCmd, char **oldCmd, GnoclOption *newVar, char **oldVar,
700 							  const char *signal, GObject *obj, GCallback gtkFunc, Tcl_Interp *interp,
701 							  Tcl_VarTraceProc tclFunc, gpointer data )
702 {
703 	const int wasConnected = *oldVar != NULL || *oldCmd != NULL;
704 
705 	/* handle variable */
706 
707 	if ( newVar == NULL || newVar->status == GNOCL_STATUS_CHANGED )
708 	{
709 		if ( *oldVar )
710 		{
711 			Tcl_UntraceVar ( interp, *oldVar, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY, tclFunc, data );
712 			g_free ( *oldVar );
713 			*oldVar = NULL;
714 		}
715 	}
716 
717 	if ( newVar && newVar->status == GNOCL_STATUS_CHANGED && *newVar->val.str != '\0' )
718 	{
719 		*oldVar = g_strdup ( newVar->val.str );
720 		Tcl_TraceVar ( interp, *oldVar, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY, tclFunc, data );
721 	}
722 
723 	/* handle command */
724 
725 	if ( newCmd == NULL || newCmd->status == GNOCL_STATUS_CHANGED )
726 	{
727 		if ( *oldCmd )
728 		{
729 			g_free ( *oldCmd );
730 			*oldCmd = NULL;
731 		}
732 	}
733 
734 	if ( newCmd && newCmd->status == GNOCL_STATUS_CHANGED && *newCmd->val.str != '\0' )
735 	{
736 		*oldCmd = g_strdup ( newCmd->val.str );
737 	}
738 
739 	/* if cmd or var is set, we need the gtkFunc */
740 
741 	if ( *oldVar || *oldCmd )
742 	{
743 		if ( wasConnected == 0 )
744 		{
745 			g_signal_connect ( G_OBJECT ( obj ), signal, gtkFunc, data );
746 		}
747 	}
748 
749 	else if ( wasConnected )
750 	{
751 		g_signal_handlers_disconnect_matched ( G_OBJECT ( obj ), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, ( gpointer * ) gtkFunc, NULL );
752 	}
753 
754 	return TCL_OK;
755 }
756 
757 
758 
759 /**
760 **/
gnoclGet2Boolean(Tcl_Interp * interp,Tcl_Obj * obj,int * b1,int * b2)761 int gnoclGet2Boolean ( Tcl_Interp *interp, Tcl_Obj *obj, int *b1, int *b2 )
762 {
763 	int no;
764 
765 	if ( Tcl_ListObjLength ( interp, obj, &no ) == TCL_OK
766 			&& ( no == 2 || no == 1 ) )
767 	{
768 		if ( no == 1 )
769 		{
770 			if ( Tcl_GetBooleanFromObj ( interp, obj, b1 ) != TCL_OK )
771 				return TCL_ERROR;
772 
773 			*b2 = *b1;
774 
775 			return TCL_OK;
776 		}
777 
778 		else
779 		{
780 			Tcl_Obj *tp;
781 
782 			if ( Tcl_ListObjIndex ( interp, obj, 0, &tp ) == TCL_OK )
783 			{
784 				if ( Tcl_GetBooleanFromObj ( interp, tp, b1 ) != TCL_OK )
785 					return TCL_ERROR;
786 
787 				if ( Tcl_ListObjIndex ( interp, obj, 1, &tp ) == TCL_OK )
788 				{
789 					if ( Tcl_GetBooleanFromObj ( interp, tp, b2 ) != TCL_OK )
790 						return TCL_ERROR;
791 				}
792 
793 				return TCL_OK;
794 			}
795 		}
796 	}
797 
798 	Tcl_AppendResult ( interp, "Expected boolean value or list of "
799 
800 					   "two boolean values but got \"", Tcl_GetString ( obj ), "\"", NULL );
801 
802 	return TCL_ERROR;
803 }
804 
805 /**
806 **/
gnoclGet2Int(Tcl_Interp * interp,Tcl_Obj * obj,int * b1,int * b2)807 int gnoclGet2Int ( Tcl_Interp *interp, Tcl_Obj *obj, int *b1, int *b2 )
808 {
809 	int no;
810 
811 	if ( Tcl_ListObjLength ( interp, obj, &no ) == TCL_OK
812 			&& ( no == 2 || no == 1 ) )
813 	{
814 		if ( no == 1 )
815 		{
816 			if ( Tcl_GetIntFromObj ( interp, obj, b1 ) != TCL_OK )
817 				return TCL_ERROR;
818 
819 			*b2 = *b1;
820 
821 			return TCL_OK;
822 		}
823 
824 		else
825 		{
826 			Tcl_Obj *tp;
827 
828 			if ( Tcl_ListObjIndex ( interp, obj, 0, &tp ) == TCL_OK )
829 			{
830 				if ( Tcl_GetIntFromObj ( interp, tp, b1 ) != TCL_OK )
831 					return TCL_ERROR;
832 
833 				if ( Tcl_ListObjIndex ( interp, obj, 1, &tp ) == TCL_OK )
834 				{
835 					if ( Tcl_GetIntFromObj ( interp, tp, b2 ) != TCL_OK )
836 						return TCL_ERROR;
837 				}
838 
839 				return TCL_OK;
840 			}
841 		}
842 	}
843 
844 	Tcl_AppendResult ( interp, "Expected integer value or list of "
845 					   "two integer values but got \"", Tcl_GetString ( obj ), "\"", NULL );
846 
847 	return TCL_ERROR;
848 }
849 
850 /**
851 **/
gnoclGet2Double(Tcl_Interp * interp,Tcl_Obj * obj,double * b1,double * b2)852 int gnoclGet2Double ( Tcl_Interp *interp, Tcl_Obj *obj, double *b1, double *b2 )
853 {
854 	int no;
855 
856 	if ( Tcl_ListObjLength ( interp, obj, &no ) == TCL_OK
857 			&& ( no == 2 || no == 1 ) )
858 	{
859 		if ( no == 1 )
860 		{
861 			if ( Tcl_GetDoubleFromObj ( interp, obj, b1 ) != TCL_OK )
862 			{
863 				return TCL_ERROR;
864 			}
865 
866 			*b2 = *b1;
867 
868 			return TCL_OK;
869 		}
870 
871 		else
872 		{
873 			Tcl_Obj *tp;
874 
875 			if ( Tcl_ListObjIndex ( interp, obj, 0, &tp ) == TCL_OK )
876 			{
877 				if ( Tcl_GetDoubleFromObj ( interp, tp, b1 ) != TCL_OK )
878 				{
879 					return TCL_ERROR;
880 				}
881 
882 				if ( Tcl_ListObjIndex ( interp, obj, 1, &tp ) == TCL_OK )
883 				{
884 					if ( Tcl_GetDoubleFromObj ( interp, tp, b2 ) != TCL_OK )
885 					{
886 						return TCL_ERROR;
887 					}
888 				}
889 
890 				return TCL_OK;
891 			}
892 		}
893 	}
894 
895 	Tcl_AppendResult ( interp, "Expected float value or list of "
896 
897 					   "two float values but got \"", Tcl_GetString ( obj ), "\"", NULL );
898 
899 	return TCL_ERROR;
900 }
901 
902 
903 
904 /**
905  */
getScrollbarPolicy(Tcl_Interp * interp,Tcl_Obj * obj,GtkPolicyType * pol)906 static int getScrollbarPolicy ( Tcl_Interp *interp, Tcl_Obj *obj, GtkPolicyType *pol )
907 {
908 	const char *txt[] = { "always", "never", "automatic", NULL };
909 	GtkPolicyType policies[] =
910 	{
911 		GTK_POLICY_ALWAYS, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC
912 	};
913 	int on;
914 
915 	if ( Tcl_GetBooleanFromObj ( NULL, obj, &on ) == TCL_OK )
916 	{
917 		*pol = on ? GTK_POLICY_ALWAYS : GTK_POLICY_NEVER;
918 	}
919 
920 	else
921 	{
922 		int idx;
923 
924 		if ( Tcl_GetIndexFromObj ( interp, obj, txt, "scrollbar policy", TCL_EXACT, &idx ) != TCL_OK )
925 		{
926 			return TCL_ERROR;
927 		}
928 
929 		*pol = policies[idx];
930 	}
931 
932 	return TCL_OK;
933 }
934 
935 
936 
937 /**
938  */
gnoclGetScrollbarPolicy(Tcl_Interp * interp,Tcl_Obj * obj,GtkPolicyType * hor,GtkPolicyType * vert)939 int gnoclGetScrollbarPolicy ( Tcl_Interp *interp, Tcl_Obj *obj, GtkPolicyType *hor, GtkPolicyType *vert )
940 {
941 	int no;
942 
943 	if ( Tcl_ListObjLength ( interp, obj, &no ) != TCL_OK  || no > 2 )
944 	{
945 		Tcl_SetResult ( interp, "policy must be either a single value "
946 						"or a list with two elements.", TCL_STATIC );
947 		return TCL_ERROR;
948 	}
949 
950 	if ( no == 1 )
951 	{
952 		if ( getScrollbarPolicy ( interp, obj, hor ) != TCL_OK )
953 			return TCL_ERROR;
954 
955 		*vert = *hor;
956 	}
957 
958 	else
959 	{
960 		Tcl_Obj *tp;
961 
962 		if ( Tcl_ListObjIndex ( interp, obj, 0, &tp ) != TCL_OK )
963 			return TCL_ERROR;
964 
965 		if ( getScrollbarPolicy ( interp, tp, hor ) != TCL_OK )
966 			return TCL_ERROR;
967 
968 		if ( Tcl_ListObjIndex ( interp, obj, 1, &tp ) != TCL_OK )
969 			return TCL_ERROR;
970 
971 		if ( getScrollbarPolicy ( interp, tp, vert ) != TCL_OK )
972 			return TCL_ERROR;
973 	}
974 
975 	return TCL_OK;
976 }
977 
978 
979 
980 /**
981  */
gnoclGetSelectionMode(Tcl_Interp * interp,Tcl_Obj * obj,GtkSelectionMode * selection)982 int gnoclGetSelectionMode ( Tcl_Interp *interp, Tcl_Obj *obj, GtkSelectionMode *selection )
983 {
984 	const char *txt[] = { "single", "browse", "multiple", "extended", NULL };
985 	GtkSelectionMode modes[] = { GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, GTK_SELECTION_EXTENDED };
986 
987 	int idx;
988 
989 	if ( Tcl_GetIndexFromObj ( interp, obj, txt, "selection modes",
990 							   TCL_EXACT, &idx ) != TCL_OK )
991 		return TCL_ERROR;
992 
993 	*selection = modes[idx];
994 
995 	return TCL_OK;
996 }
997 
998 
999 
1000 /**
1001  */
gnoclGetOrientationType(Tcl_Interp * interp,Tcl_Obj * obj,GtkOrientation * orient)1002 int gnoclGetOrientationType ( Tcl_Interp *interp, Tcl_Obj *obj, GtkOrientation *orient )
1003 {
1004 	const char *txt[] = { "horizontal", "vertical", NULL };
1005 	GtkOrientation types[] = { GTK_ORIENTATION_HORIZONTAL, GTK_ORIENTATION_VERTICAL };
1006 
1007 	int idx;
1008 
1009 	if ( Tcl_GetIndexFromObj ( interp, obj, txt, "orientation", TCL_EXACT, &idx ) != TCL_OK )
1010 	{
1011 		return TCL_ERROR;
1012 	}
1013 
1014 	*orient = types[idx];
1015 
1016 	return TCL_OK;
1017 }
1018 
1019 
1020 /**
1021  */
gnoclGetWindowType(Tcl_Interp * interp,Tcl_Obj * obj,GtkWindowType * type)1022 int gnoclGetWindowType ( Tcl_Interp *interp, Tcl_Obj *obj, GtkWindowType *type )
1023 {
1024 	const char *txt[] = { "popup", "toplevel", NULL };
1025 
1026 	GtkWindowType types[] = { GTK_WINDOW_POPUP, GTK_WINDOW_TOPLEVEL };
1027 
1028 	int idx;
1029 
1030 	if ( Tcl_GetIndexFromObj ( interp, obj, txt, "types", TCL_EXACT, &idx ) != TCL_OK )
1031 	{
1032 		return TCL_ERROR;
1033 	}
1034 
1035 	*type = types[idx];
1036 
1037 	return TCL_OK;
1038 }
1039 
1040 
1041 /**
1042 \brief	This function simply loads a single file from disk into memory.
1043 **/
gnoclPixbufFromObj(Tcl_Interp * interp,GnoclOption * opt)1044 GdkPixbuf *gnoclPixbufFromObj ( Tcl_Interp *interp, GnoclOption *opt )
1045 {
1046 	char *txt = gnoclGetString ( opt->val.obj );
1047 	GError *error = NULL;
1048 	GdkPixbuf *pix = gdk_pixbuf_new_from_file ( txt, &error );
1049 
1050 	assert ( gnoclGetStringType ( opt->val.obj ) == GNOCL_STR_FILE );
1051 
1052 	if ( pix == NULL )
1053 	{
1054 		Tcl_SetResult ( interp, error->message, TCL_VOLATILE );
1055 		g_error_free ( error );
1056 		return NULL;
1057 	}
1058 
1059 	return pix;
1060 }
1061 
1062 /**
1063 \brief      Read in a list of images and bitmasks, composite them to a single
1064             pixbuf and then return a pointer to the pixbuf to the calling function
1065 \note      This assumes that the images to be composite and the masks are ALL of
1066             matching sizes. There is no attempt to reposition or resize graphics.
1067             Key Library Functions
1068             GtkWidget  *gtk_image_new_from_file (const gchar *filename);
1069             GtkWidget  *gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf);
1070             void gtk_image_get_image (GtkImage *image, GdkImage **gdk_image, GdkBitmap **mask);
1071             GtkWidget  *gtk_image_new_from_image (GdkImage *image, GdkBitmap *mask);
1072             GdkPixbuf  *gtk_image_get_pixbuf (GtkImage *image);
1073             void gdk_pixbuf_render_threshold_alpha (GdkPixbuf *pixbuf,GdkBitmap *bitmap, int src_x,
1074                 int src_y, int dest_x, int dest_y, int width, int height, int alpha_threshold);
1075             ie. gdk_pixbuf_render_threshold_alpha (pb,mp,0,0,0,0,-1,-1,128);
1076  */
gnoclBlendPixbufFromObj(Tcl_Interp * interp,GnoclOption * opt)1077 GdkPixbuf *gnoclBlendPixbufFromObj ( Tcl_Interp *interp, GnoclOption *opt )
1078 {
1079 
1080 	GdkPixbuf *pixbuf = NULL;
1081 	GError *err = NULL;
1082 	GtkWidget *gtk_image = NULL;
1083 	GtkWidget *gtk_image_blend = NULL;
1084 	GdkImage *gdk_image = NULL;
1085 	GdkBitmap *gdk_bitmap = NULL;
1086 
1087 	char * pch;
1088 
1089 	printf ( "helperFuncs/gnoclBlendPixbufFromObj pixbuf %s\n", Tcl_GetString ( opt->val.obj ) );
1090 
1091 	pch = strtok ( Tcl_GetString ( opt->val.obj ), " " );
1092 	int aa = 0;
1093 	int bb = 0;
1094 
1095 	while ( pch != NULL )
1096 	{
1097 		switch ( aa )
1098 		{
1099 			case 0:
1100 				{
1101 					g_print ( "pch = %s\n", pch );
1102 					pixbuf = gdk_pixbuf_new_from_file ( pch , &err );
1103 
1104 					if ( err != NULL )
1105 					{
1106 						g_warning ( "%s", err->message );
1107 						g_error_free ( err );
1108 						return NULL;
1109 					}
1110 
1111 					/* error checking over, create the image */
1112 					gtk_image = gtk_image_new_from_pixbuf ( pixbuf );
1113 
1114 					/* create a gdk_image from this, dump any alpha channel */
1115 
1116 					if ( gdk_image == NULL )
1117 					{
1118 
1119 						/* get the size of the pixbuf */
1120 
1121 						g_print ( "make a new gdk_image\n" );
1122 						gdk_image = gdk_image_new (
1123 										GDK_IMAGE_FASTEST,
1124 										gdk_visual_get_system(),
1125 										gdk_pixbuf_get_width ( pixbuf ),
1126 										gdk_pixbuf_get_height ( pixbuf ) );
1127 					}
1128 
1129 					g_print ( "AAA\n" );
1130 					gtk_image_get_image ( GTK_IMAGE ( gtk_image ), &gdk_image, NULL );
1131 					g_print ( "BBB\n" );
1132 
1133 				}
1134 
1135 				break;
1136 			case 1:
1137 				{
1138 
1139 					pixbuf = gdk_pixbuf_new_from_file ( pch, &err );
1140 
1141 					if ( err != NULL )
1142 					{
1143 						g_warning ( "%s", err->message );
1144 						g_error_free ( err );
1145 						return NULL;
1146 					}
1147 
1148 					/* error checking over, create the clipping mask */
1149 					gdk_pixbuf_render_threshold_alpha ( pixbuf, gdk_bitmap, 0, 0, 0, 0, -1, -1, 1 );
1150 				}
1151 
1152 				break;
1153 		}
1154 
1155 		if ( aa < 3 )
1156 		{
1157 			aa++;
1158 		}
1159 
1160 		else
1161 		{
1162 			aa = 0;
1163 		}
1164 
1165 		pch = strtok ( NULL, " " );
1166 
1167 		/* do the actual compositing onto the buffer background */
1168 
1169 		gtk_image_blend = gtk_image_new_from_image ( gdk_image, gdk_bitmap );
1170 
1171 		g_print ( "composite images now!\n" );
1172 
1173 
1174 	}
1175 
1176 	if ( 0 )
1177 	{
1178 		return gtk_image_get_pixbuf ( gtk_image_blend );
1179 	}
1180 
1181 	else
1182 	{
1183 		return pixbuf;
1184 	}
1185 }
1186 
1187 /* reverse:  reverse string s in place */
reverse(char s[])1188 void reverse ( char s[] )
1189 {
1190 	int i, j;
1191 	char c;
1192 
1193 	for ( i = 0, j = strlen ( s ) - 1; i < j; i++, j-- )
1194 	{
1195 		c = s[i];
1196 		s[i] = s[j];
1197 		s[j] = c;
1198 	}
1199 }
1200 
1201 
1202 /**
1203 \brief	convert n to characters in s
1204 **/
itoa(int n,char s[])1205 void itoa ( int n, char s[] )
1206 {
1207 	int i, sign;
1208 
1209 	if ( ( sign = n ) < 0 ) /* record sign */
1210 		n = -n;          /* make n positive */
1211 
1212 	i = 0;
1213 
1214 	do  /* generate digits in reverse order */
1215 	{
1216 		s[i++] = n % 10 + '0';   /* get next digit */
1217 	}
1218 	while ( ( n /= 10 ) > 0 );   /* delete it */
1219 
1220 	if ( sign < 0 )
1221 		s[i++] = '-';
1222 
1223 	s[i] = '\0';
1224 	reverse ( s );
1225 }
1226 
1227 /**
1228 \brief	Simple check to see if a file exists.
1229 **/
exists(const char * fname)1230 int exists ( const char *fname )
1231 {
1232 	FILE *file;
1233 
1234 	if ( file = fopen ( fname, "r" ) )
1235 	{
1236 		fclose ( file );
1237 		return 1;
1238 	}
1239 
1240 	return 0;
1241 }
1242