1 /*
2  *  $Id: text.c,v 1.7 2005-01-01 15:27:54 baum Exp $
3  *
4  *  This file implements the text widget
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  *  Modification of the the GtkSourceView undo/redo provided by Ross Burton (ross@burtonini.com)
12  */
13 
14 /**
15  * CURRENTLY ACCEPTS :
16  * 		$w get markup start end
17  * 		$w get start end -markup 1
18  **/
19 
20 
21 /*
22 	to do
23 		document
24 			-acceptTab
25 			-tabs
26 */
27 /*
28    History:
29    2013-07: added command, options
30    2013-05: added -onDragEnd
31    2013-04: resolved problem with tag sub-command "ranges"
32    2013-02: serialize command now returns buffer data as string
33    2013-01: added subcommands isToplevelFocus and hasGlobalFocus
34    2012-12	corrected -accepttTab to -acceptsTab
35    2012-11  added -data option to text tag
36 			fixed problems with:
37 				getIndex subcommand
38 				tag get  subcommand
39 			added %r(ow) %c(col) substitution string parameters for
40 			-onMotion signal handler
41    2012-10	added -onDestroy
42    2012-09	cget -baseFont implemented
43 			resetUndo
44    2012-08  migrated to the use of TextParams to hold widget details
45 			implemented -variable option
46    2012-07	added grabFocus, same effect as setting the -hasFocus option
47    2012-06  added selectionBounds to get widget command.
48    2011-07  added tag sub-commands
49 				names, raise, lower
50     		insert command now detects pango markup text
51 			added -markupTags
52    2011-06  added tag -underline option 'error'
53    2011-06  added -hasToolTip, -onQueryTooltip,
54    			added tag options
55    				-data
56    2011-04  added tag options
57 				-marginAccumulate -backgroundFullHeight	-backgroundStipple
58 				-direction -editable -foregroundStipple -indent -language
59 				-leftMargin -name -pixelsInsideWrap -rightMargin -rise
60 				-scale -tabs -variant -weight
61    2011-04  added -inputMethod, -onPreeditChanged
62    2011-02  added undo/redo functionality
63    2010-05	added tag option -paragraph
64    2010-04	added -onDeleteFromCursor, -onInsertAtCursor, -onMoveCursor, -onMoveViewport
65 			added lorem - insert some dummy text for preview purposes
66    2010-03	added getIndex, return line / char info at location x y in textview
67    2010-01	added -buffer
68    2010-01	added -doOnCutClipboard, -doOnCopyClipboard, -doOnPasteClipboard
69    2009-01	added -text option to allow plain text creation at startup
70    2008-04	renamed function gnoclOptOnInsertText to  gnoclOptOnTextInsert
71    2009-04	added commands save, load, (aka serialize, deserialize)
72    2009-02	added -onScroll and -widthRequest
73    			added commands search and replace
74    2009-01	added -heightRequest
75    2008-06	added new options -onEntry and -onLeave
76    				(required modification of the text widget signal mask)
77    2008-06  added   <id> getSelectionBounds, returns range currently selected
78                     <id> -onInsertText script
79    [not finnished] 2008-03: XYgetCursor -retrive row/col position under window coordinates, XY
80    [not finnished] 2008-03: cget retrieve current setting for specified option, based upon entry.c
81 
82    2008-03: added tag delete <tagname> command
83    2008-03: added command 'class', return class of widget, ie. text
84    2007-11: extened tag command to include apply / remove
85    2007-11: added extended list of tag options to include
86            -onEvent
87    2007-10: added new options to the text widget
88            -baseFont
89            -baseColor
90            -onButtonPress
91            -onButtonRelease
92            -onKeyPress
93            -onKeyRelease
94            -onMotion
95            -dropTargets -test this option
96            -dragTargets -test this option
97    2003-03: added scrollToPosition
98         11: switched from GnoclWidgetOptions to GnoclOption
99    2002-05: transition to gtk 2.0: move from gtkText to gtkTextView
100    2001-06: Begin of developement
101 
102    TODO:
103     * set a clear pango mode, ie no other tags a can be created, non-deleted
104     * marks
105  */
106 
107 /**
108 \page page_text gnocl::text
109 \htmlinclude text.html
110 **/
111 
112 #include "gnocl.h"
113 #include "gnoclparams.h"
114 #include "./textUndo/undo_manager.h"
115 
116 static int textFunc ( ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *  const objv[] );
117 static int cget ( Tcl_Interp *interp, GtkTextView *text, GnoclOption options[], int idx );
118 static void gnoclGetTagRanges ( Tcl_Interp * interp, GtkTextBuffer * buffer, gchar * tagName );
119 static void getTagName ( GtkTextTag *tag, gpointer data );
120 static void gnoclGetTagProperties ( GtkTextTag * tag, Tcl_Obj *resList );
121 
122 static int setTextVariable ( TextParams *para, const char *val );
123 static void changedFunc ( GtkWidget *widget, gpointer data );
124 static void destroyFunc ( GtkWidget *widget, gpointer data );
125 static int setVal ( GtkTextBuffer *buffer, const char *txt );
126 static char *traceFunc ( ClientData data, Tcl_Interp *interp, const char *name1, const char *name2,	int flags );
127 static int doCommand ( TextParams *para, const char *val, int background );
128 
129 static gint usemarkup = 0;
130 
131 
132 /***********************************************************************
133  * trace funcs
134 ***********************************************************************/
135 
136 /**
137 \brief
138 **/
destroyFunc(GtkWidget * widget,gpointer data)139 static void destroyFunc ( GtkWidget *widget, gpointer data )
140 {
141 #ifdef DEBUG_TEXT
142 	printf ( "%s\n", __FUNCTION__ );
143 #endif
144 
145 
146 	TextParams *para = ( TextParams * ) data;
147 
148 	gnoclForgetWidgetFromName ( para->name );
149 	Tcl_DeleteCommand ( para->interp, para->name );
150 
151 	gnoclAttachOptCmdAndVar (
152 		NULL, &para->onChanged,
153 		NULL, &para->textVariable,
154 		"changed", G_OBJECT ( para->textView ),
155 		G_CALLBACK ( changedFunc ), para->interp, traceFunc, para );
156 
157 	g_free ( para->textVariable );
158 	g_free ( para->name );
159 	g_free ( para );
160 }
161 
162 /**
163 \brief
164 **/
changedFunc(GtkWidget * widget,gpointer data)165 static void changedFunc ( GtkWidget *widget, gpointer data )
166 {
167 #ifdef DEBUG_TEXT
168 	printf ( "%s\n", __FUNCTION__ );
169 #endif
170 
171 	TextParams *para = ( TextParams * ) data;
172 
173 	GtkScrolledWindow *scrolled = para->scrolled;
174 	GtkTextView *text = GTK_TEXT_VIEW ( gtk_bin_get_child ( GTK_BIN ( scrolled ) ) );
175 	GtkTextBuffer *buffer = gtk_text_view_get_buffer ( text );
176 
177 	GtkTextIter start, end;
178 	gtk_text_buffer_get_bounds ( buffer, &start, &end );
179 	const char *val = gtk_text_buffer_get_text ( buffer, &start, &end, FALSE );
180 
181 	//g_print ( "....%s\n", val );
182 
183 
184 	//const char *val = gtk_label_get_text ( para->label );
185 	setTextVariable ( para, val );
186 	//doCommand ( para, val, 1 );
187 }
188 
189 /**
190 \brief
191 **/
setTextVariable(TextParams * para,const char * val)192 static int setTextVariable ( TextParams *para,	const char *val )
193 {
194 #ifdef DEBUG_TEXT
195 	printf ( "%s\n", __FUNCTION__ );;
196 #endif
197 
198 
199 	if ( para->textVariable && para->inSetVar == 0 )
200 	{
201 		const char *ret;
202 		para->inSetVar = 1;
203 		ret = Tcl_SetVar ( para->interp, para->textVariable, val, TCL_GLOBAL_ONLY );
204 		para->inSetVar = 0;
205 		return ret == NULL ? TCL_ERROR : TCL_OK;
206 	}
207 
208 	return TCL_OK;
209 }
210 
211 /**
212 \brief
213 **/
setVal(GtkTextBuffer * buffer,const char * txt)214 static int setVal ( GtkTextBuffer *buffer, const char *txt )
215 {
216 	int blocked;
217 	blocked = g_signal_handlers_block_matched ( G_OBJECT ( buffer ), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, ( gpointer * ) changedFunc, NULL );
218 	//gtk_label_set_text ( label, txt );
219 
220 	gtk_text_buffer_set_text ( buffer, txt, -1 );
221 
222 	//gtk_label_set_markup ( label, txt );
223 
224 	//OptLabelFull ( label, txt );
225 
226 	if ( blocked )
227 	{
228 		g_signal_handlers_unblock_matched ( G_OBJECT ( buffer ), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, ( gpointer * ) changedFunc, NULL );
229 	}
230 
231 	return TCL_OK;
232 }
233 
234 /**
235 \brief
236 **/
traceFunc(ClientData data,Tcl_Interp * interp,const char * name1,const char * name2,int flags)237 static char *traceFunc ( ClientData data, Tcl_Interp *interp, const char *name1, const char *name2,	int flags )
238 {
239 	TextParams *para = ( TextParams * ) data;
240 
241 	GtkScrolledWindow *scrolled = para->scrolled;
242 	GtkTextView *text = GTK_TEXT_VIEW ( gtk_bin_get_child ( GTK_BIN ( scrolled ) ) );
243 	GtkTextBuffer *buffer = gtk_text_view_get_buffer ( text );
244 
245 
246 	if ( para->inSetVar == 0 && name1 )
247 	{
248 		const char *txt = name1 ? Tcl_GetVar2 ( interp, name1, name2, 0 ) : NULL;
249 
250 		if ( txt )
251 		{
252 			setVal ( buffer, txt );
253 			doCommand ( para, txt, 1 );
254 		}
255 	}
256 
257 	return NULL;
258 }
259 
260 /**
261 \brief
262 **/
doCommand(TextParams * para,const char * val,int background)263 static int doCommand ( TextParams *para, const char *val, int background )
264 {
265 	if ( para->onChanged )
266 	{
267 		GnoclPercSubst ps[] =
268 		{
269 			{ 'w', GNOCL_STRING },  /* widget */
270 			{ 'v', GNOCL_STRING },  /* value */
271 			{ 0 }
272 		};
273 
274 		ps[0].val.str = para->name;
275 		ps[1].val.str = val;
276 
277 		return gnoclPercentSubstAndEval ( para->interp, ps, para->onChanged, background );
278 	}
279 
280 	return TCL_OK;
281 }
282 
283 
284 /***********************************************************************/
stripMarkup(GtkTextBuffer * buffer,GtkTextIter * start,GtkTextIter * end)285 gchar *stripMarkup ( GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end )
286 {
287 	GtkTextIter *iter;
288 
289 	iter = gtk_text_iter_copy ( start );
290 
291 	gchar *str = NULL;
292 	gunichar ch;
293 
294 	/* parse each position in the selection */
295 	while ( gtk_text_iter_equal ( iter, end ) == 0 )
296 	{
297 		ch = gtk_text_iter_get_char ( iter );
298 		str = str_append ( str, ch );
299 		gtk_text_iter_forward_cursor_position ( iter ); //OK
300 	}
301 
302 	return str;
303 }
304 
305 /**
306 \brief	Return text with Pango markup
307 \notes	Pango has a weight markup format compared to HTML or the textBuff
308 		Basically, it means there are problems when overlapping markup tags.
309 		Whatever is opened has to be closed, and then the overlap re-opened.
310 
311 		eg: this will work
312 		The buffer will return this..
313 		<b>aaa<i> bbb</b> <u>ccc</u></i> ddd</u>
314 		But this is pango!
315 		<b>aaa<i> bbb</i></b><i> <u>ccc</u></i><u> ddd</u>
316 
317 \date	23/06/13
318 **/
getMarkUpString(Tcl_Interp * interp,GtkTextBuffer * buffer,GtkTextIter * start,GtkTextIter * end)319 Tcl_Obj *getMarkUpString ( Tcl_Interp *interp, GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end )
320 {
321 #if 1
322 	g_print ( "%s usemarkup = %d\n", __FUNCTION__, usemarkup );
323 #endif
324 
325 	Tcl_Obj *res;
326 
327 	GtkTextIter *iter;
328 	gunichar ch;
329 	GList *q;
330 	GList *onList = NULL, *offList = NULL, *revList = NULL;
331 	gchar *tagName = NULL;
332 
333 	res = Tcl_NewStringObj ( "", 0 );
334 	iter = gtk_text_iter_copy ( start );
335 
336 	/* parse each position in the selection */
337 	while ( gtk_text_iter_equal ( iter, end ) == 0 )
338 	{
339 
340 		/* process tagOff before any subsequent tagOn */
341 		offList = gtk_text_iter_get_toggled_tags ( iter, 0 );
342 		onList = gtk_text_iter_get_toggled_tags ( iter, 1 );
343 
344 		if ( onList != NULL )
345 		{
346 			/* get a reverse list */
347 			for ( q = onList ; q != NULL; q = q->next )
348 			{
349 				tagName = ( GTK_TEXT_TAG ( q->data )->name );
350 				Tcl_AppendStringsToObj ( res, tagName, ( char * ) NULL );
351 			}
352 		}
353 
354 		if ( offList != NULL )
355 		{
356 			/* get off tags */
357 			onList = gtk_text_iter_get_tags ( iter );
358 
359 			for ( q = onList ; q != NULL; q = q->next )
360 			{
361 				tagName = ( GTK_TEXT_TAG ( q->data )->name );
362 				revList = g_slist_prepend ( revList, tagName );
363 			}
364 
365 			/* turn off tags in order of priority, ie reverse the list */
366 			for ( q = revList ; q != NULL; q = q->next )
367 			{
368 				tagName = q->data ;
369 
370 				if ( strncmp ( tagName, "<span", 5 ) == 0 )
371 				{
372 					tagName = "span";
373 				}
374 
375 				Tcl_AppendStringsToObj ( res, str_replace ( tagName, "<", "</" ), ( char * ) NULL );
376 			}
377 
378 			for ( q = offList ; q != NULL; q = q->next )
379 			{
380 				tagName = ( GTK_TEXT_TAG ( q->data )->name );
381 
382 				if ( strncmp ( tagName, "<span", 5 ) == 0 )
383 				{
384 					tagName = "<span>";
385 				}
386 
387 				Tcl_AppendStringsToObj ( res, str_replace ( tagName, "<", "</" ), ( char * ) NULL );
388 			}
389 
390 			for ( q = onList ; q != NULL; q = q->next )
391 			{
392 				tagName = ( GTK_TEXT_TAG ( q->data )->name );
393 				Tcl_AppendStringsToObj ( res, tagName, ( char * ) NULL );
394 			}
395 
396 			g_slist_free ( onList );  onList = NULL;
397 			g_slist_free ( revList ); revList = NULL;
398 			g_slist_free ( offList ); offList = NULL;
399 
400 		}
401 
402 		/* end of markup block */
403 
404 		/* get character */
405 		ch = gtk_text_iter_get_char ( iter );
406 		Tcl_AppendStringsToObj ( res, &ch, ( char * ) NULL );
407 
408 		/* turnOff span? */
409 		gtk_text_iter_forward_cursor_position ( iter ); //OK
410 	}
411 
412 	/* terminate tags at end of line */
413 	if ( gtk_text_iter_backward_to_tag_toggle ( iter, NULL ) )
414 	{
415 		offList = gtk_text_iter_get_tags ( iter );
416 
417 		if ( 1 )
418 		{
419 			for ( q = offList ; q != NULL; q = q->next )
420 			{
421 				tagName = ( GTK_TEXT_TAG ( q->data )->name );
422 				revList = g_slist_prepend ( revList, tagName );
423 			}
424 
425 
426 			for ( q = revList ; q != NULL; q = q->next )
427 			{
428 				tagName = q->data ;
429 
430 				if ( strncmp ( tagName, "<span", 5 ) == 0 )
431 				{
432 					tagName = "<span>";
433 				}
434 
435 				Tcl_AppendStringsToObj ( res, str_replace ( tagName, "<", "</" ), ( char * ) NULL );
436 			}
437 		}
438 
439 		else
440 		{
441 			for ( q = offList ; q != NULL; q = q->next )
442 			{
443 				tagName = ( GTK_TEXT_TAG ( q->data )->name );
444 
445 				if ( strncmp ( tagName, "<span", 5 ) == 0 )
446 				{
447 					tagName = "<span>";
448 				}
449 
450 				Tcl_AppendStringsToObj ( res, str_replace ( tagName, "<", "</" ), ( char * ) NULL );
451 			}
452 		}
453 	}
454 
455 	gtk_text_iter_free ( iter );
456 
457 	g_slist_free ( onList );  onList = NULL;
458 	g_slist_free ( revList ); revList = NULL;
459 	g_slist_free ( offList ); offList = NULL;
460 
461 #ifdef DEBUG_TEXT
462 	g_print ( "done!\n" );
463 #endif
464 
465 	//g_print ( "TEXT = %s\n", Tcl_GetStringFromObj ( res, NULL ) );
466 
467 	gchar *text = NULL;
468 
469 	if (  pango_parse_markup ( Tcl_GetStringFromObj ( res, NULL ), -1 , NULL, NULL, &text, NULL, NULL ) == 0 )
470 	{
471 		g_print ( "WARNING! Malformed Pango Strings: %s\n", text );
472 		Tcl_SetStringObj ( res, "", 0 );
473 		Tcl_AppendStringsToObj ( res, gtk_text_buffer_get_text ( buffer, start, end, 0 ), ( char * ) NULL );
474 
475 	}
476 
477 	return res;
478 }
479 
480 
481 
482 /**
483 \brief	Return text with Pango markup -WORKING VERSION
484 **/
getMarkUpString_(Tcl_Interp * interp,GtkTextBuffer * buffer,GtkTextIter * start,GtkTextIter * end)485 Tcl_Obj *getMarkUpString_ ( Tcl_Interp *interp, GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end )
486 {
487 #ifdef DEBUG_TEXT
488 	g_print ( "%s usemarkup = %d\n", __FUNCTION__, usemarkup );
489 #endif
490 
491 	Tcl_Obj *res;
492 
493 	GtkTextIter *iter;
494 	gunichar ch;
495 	GList *p, *q, *list;
496 
497 	GList *onList = NULL, *offList = NULL, *revList = NULL;
498 
499 	gchar *tagName = NULL;
500 	gchar *onTag = NULL;
501 	gchar *offTag = NULL;
502 
503 	gchar openList[128] = "";
504 	gchar closeList[128] = "";
505 
506 	res = Tcl_NewStringObj ( "", 0 );
507 
508 	iter = gtk_text_iter_copy ( start );
509 
510 	/* parse each position in the selection */
511 	while ( gtk_text_iter_equal ( iter, end ) == 0 )
512 	{
513 
514 		/* process tagOff before any subsequent tagOn */
515 		offList = gtk_text_iter_get_toggled_tags ( iter, 0 );
516 		onList = gtk_text_iter_get_toggled_tags ( iter, 1 );
517 
518 		if ( onList != NULL )
519 		{
520 
521 			/* get a reverse list */
522 			for ( q = onList ; q != NULL; q = q->next )
523 			{
524 				tagName = ( GTK_TEXT_TAG ( q->data )->name );
525 				revList = g_slist_prepend ( revList, tagName );
526 				Tcl_AppendStringsToObj ( res, tagName, ( char * ) NULL );
527 			}
528 
529 
530 			for ( q = revList ; q != NULL; q = q->next )
531 			{
532 				tagName = q->data ;
533 			}
534 
535 			g_slist_free ( revList );
536 			revList = NULL;
537 
538 		}
539 
540 		if ( offList != NULL )
541 		{
542 			/* turn off tags */
543 			onList = gtk_text_iter_get_tags ( iter );
544 
545 			for ( q = onList ; q != NULL; q = q->next )
546 			{
547 				tagName = ( GTK_TEXT_TAG ( q->data )->name );
548 				revList = g_slist_prepend ( revList, tagName );
549 			}
550 
551 			for ( q = revList ; q != NULL; q = q->next )
552 			{
553 				Tcl_AppendStringsToObj ( res, str_replace ( q->data, "<", "</" ), ( char * ) NULL );
554 			}
555 
556 			for ( q = offList ; q != NULL; q = q->next )
557 			{
558 				tagName = ( GTK_TEXT_TAG ( q->data )->name );
559 				Tcl_AppendStringsToObj ( res, str_replace ( tagName, "<", "</" ), ( char * ) NULL );
560 			}
561 
562 			for ( q = onList ; q != NULL; q = q->next )
563 			{
564 				tagName = ( GTK_TEXT_TAG ( q->data )->name );
565 				Tcl_AppendStringsToObj ( res, tagName, ( char * ) NULL );
566 			}
567 
568 			g_slist_free ( onList );  onList = NULL;
569 			g_slist_free ( revList ); revList = NULL;
570 			g_slist_free ( offList ); offList = NULL;
571 
572 		}
573 
574 		/* end of markup block */
575 
576 		/* get character */
577 		ch = gtk_text_iter_get_char ( iter );
578 		Tcl_AppendStringsToObj ( res, &ch, ( char * ) NULL );
579 
580 		/* turnOff span? */
581 		gtk_text_iter_forward_cursor_position ( iter ); //OK
582 	}
583 
584 	/* terminate tags at end of line */
585 	if ( gtk_text_iter_backward_to_tag_toggle ( iter, NULL ) )
586 	{
587 		offList = gtk_text_iter_get_tags ( iter );
588 
589 		for ( q = offList ; q != NULL; q = q->next )
590 		{
591 			tagName = ( GTK_TEXT_TAG ( q->data )->name );
592 
593 			Tcl_AppendStringsToObj ( res, str_replace ( tagName, "<", "</" ), ( char * ) NULL );
594 		}
595 	}
596 
597 	gtk_text_iter_free ( iter );
598 
599 	g_slist_free ( onList );  onList = NULL;
600 	g_slist_free ( revList ); revList = NULL;
601 	g_slist_free ( offList ); offList = NULL;
602 
603 #ifdef DEBUG_TEXT
604 	g_print ( "done!\n" );
605 #endif
606 
607 	return res;
608 }
609 
610 /**
611 \brief  Serialize the content of the textbuffer in an ascii format
612 \note   Currently supports tags only.
613 **/
dumpAll(Tcl_Interp * interp,GtkTextBuffer * buffer,GtkTextIter * start,GtkTextIter * end)614 static Tcl_Obj *dumpAll ( Tcl_Interp *interp, GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end )
615 {
616 
617 #ifdef DEBUG_TEXT
618 	g_print ( "%s\n", __FUNCTION__ );
619 #endif
620 
621 	Tcl_Obj *res;
622 
623 	GtkTextIter *iter;
624 	gunichar ch;
625 	GSList *p, *onList, *offList;
626 
627 	gchar *tagName = NULL;
628 	gchar *onTag = NULL;
629 	gchar *offTag = NULL;
630 
631 	gint l;
632 
633 	res = Tcl_NewStringObj ( "", 0 );
634 
635 	iter = gtk_text_iter_copy ( start );
636 
637 	while ( gtk_text_iter_equal ( iter, end ) == 0 )
638 	{
639 		/* process tagOff before any subsequent tagOn */
640 		offList = gtk_text_iter_get_toggled_tags ( iter, 0 );
641 
642 		for ( p = offList; p != NULL; p = p->next )
643 		{
644 			tagName = ( GTK_TEXT_TAG ( p->data )->name );
645 			l = strlen ( tagName );
646 			char str[l-2];
647 			strncpy ( str, tagName + 2, l - 1 );
648 			Tcl_AppendStringsToObj ( res, tagName, ( char * ) NULL );
649 		}
650 
651 		/* process tagOn */
652 
653 
654 		onList = gtk_text_iter_get_toggled_tags ( iter, 1 );
655 
656 		for ( p = onList; p != NULL; p = p->next )
657 		{
658 			tagName = ( GTK_TEXT_TAG ( p->data )->name );
659 			Tcl_AppendStringsToObj ( res, tagName, ( char * ) NULL );
660 		}
661 
662 		/* get character */
663 		ch = gtk_text_iter_get_char ( iter );
664 		Tcl_AppendStringsToObj ( res, &ch, ( char * ) NULL );
665 
666 		/* turnOff span? */
667 		gtk_text_iter_forward_char ( iter );
668 	}
669 
670 	gtk_text_iter_free ( iter );
671 
672 
673 #ifdef DEBUG_TEXT
674 	g_print ( "done!\n" );
675 #endif
676 
677 	return res;
678 }
679 
680 
681 
682 
683 /**
684 \brief	Return a Tcl list of text attributes.
685 GtkJustification justification;
686 GtkTextDirection direction;
687 PangoFontDescription *font;
688 gdouble font_scale;
689 gint left_margin;
690 gint indent;
691 gint right_margin;
692 gint pixels_above_lines;
693 gint pixels_below_lines;
694 gint pixels_inside_wrap;
695 PangoTabArray *tabs;
696 GtkWrapMode wrap_mode;
697 PangoLanguage *language;
698 guint invisible : 1;
699 guint bg_full_height : 1;
700 guint editable : 1;
701 guint realized : 1;
702 
703 **/
getAttributes(Tcl_Interp * interp,GtkTextAttributes * values)704 static getAttributes ( Tcl_Interp *interp, GtkTextAttributes *values )
705 {
706 #ifdef DEBUG_TEXT
707 	g_print ( " % s\n", __FUNCTION__ );
708 #endif
709 
710 
711 	Tcl_Obj *resList;
712 
713 	resList = Tcl_NewListObj ( 0, NULL );
714 
715 	gchar *justify;
716 	gchar *direction;
717 	gchar *font;
718 
719 	justify = "left";
720 	direction = "none";
721 	font = "";
722 
723 	font = pango_font_description_to_string ( values->font );
724 
725 	switch ( values->justification )
726 	{
727 		case GTK_JUSTIFY_LEFT:
728 			{
729 				justify = "left";
730 			}
731 			break;
732 		case GTK_JUSTIFY_RIGHT:
733 			{
734 				justify = "right";
735 			}			break;
736 		case GTK_JUSTIFY_CENTER:
737 			{
738 				justify = "center";
739 			}			break;
740 		case GTK_JUSTIFY_FILL:
741 			{
742 				justify = "fill";
743 			}			break;
744 		default:
745 			{
746 
747 #ifdef DEBUG_TEXT
748 				g_print ( "no justify %s\n", __FUNCTION__ );
749 #endif
750 
751 			}
752 	}
753 
754 	switch ( values->direction )
755 	{
756 		case GTK_TEXT_DIR_NONE:
757 			{
758 				direction = "none";
759 			}
760 			break;
761 		case GTK_TEXT_DIR_LTR:
762 			{
763 				direction = "left - to - right";
764 			}
765 			break;
766 		case GTK_TEXT_DIR_RTL:
767 			{
768 				direction = "right - to - left";
769 			}
770 			break;
771 		default:
772 			{
773 #ifdef DEBUG_TEXT
774 				g_print ( "no direction %s\n", __FUNCTION__ );
775 #endif
776 
777 			}
778 	}
779 
780 
781 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "justification", -1 ) );
782 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( justify, -1 ) );
783 
784 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "direction", -1  ) );
785 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( direction, -1 ) );
786 
787 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "font", -1  ) );
788 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( font, -1 ) );
789 
790 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "font_scale", -1  ) );
791 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewDoubleObj ( values->font_scale ) );
792 
793 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "left_margin", -1  ) );
794 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( values->left_margin ) );
795 
796 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "indent", -1  ) );
797 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( values->indent ) );
798 
799 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "right_margin", -1  ) );
800 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( values->right_margin ) );
801 
802 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "pixels_above_lines", -1  ) );
803 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( values-> pixels_above_lines ) );
804 
805 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "pixels_below_lines", -1  ) );
806 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( values->pixels_below_lines ) );
807 
808 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "pixels_inside_wrap", -1  ) );
809 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( values->pixels_inside_wrap ) );
810 
811 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "tabs", -1  ) );
812 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "tab - array", -1 ) );
813 
814 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "wrap_mode", -1  ) );
815 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "wrap", -1 ) );
816 
817 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "language", -1  ) );
818 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "text - language", -1 ) );
819 
820 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "invisible", -1  ) );
821 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( values->invisible ) );
822 
823 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "bg_full_height", -1  ) );
824 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( values->bg_full_height ) );
825 
826 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "editable", -1  ) );
827 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( 1 ) );
828 
829 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( "realized", -1  ) );
830 	Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( values->realized ) );
831 
832 	Tcl_SetObjResult ( interp, resList );
833 
834 }
835 
836 
837 /**
838 \brief     Search through the GtkTextBuffer from startPos to endPos.
839 If a match is found, add it to a list of row col indices.
840 When search complete, return the list to the calling function.
841 **/
searchWord(GtkTextBuffer * buffer,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[],int cmdNo,int isTextWidget)842 static int searchWord ( GtkTextBuffer *buffer, Tcl_Interp *interp, int objc, Tcl_Obj * const objv[], int cmdNo, int isTextWidget )
843 {
844 
845 	listParameters ( objc,  objv, __FUNCTION__ );
846 
847 	int res, row1, col1, row2, col2;
848 	GtkTextIter start, begin, end;
849 	Tcl_Obj *resList;
850 
851 	resList = Tcl_NewListObj ( 0, NULL );
852 
853 	/*  default with the start of the buffer */
854 	gtk_text_buffer_get_start_iter ( buffer, &start );
855 
856 	while ( gtk_text_iter_forward_search ( &start, ( gchar*  ) Tcl_GetString ( objv[cmdNo+2] ), 0, &begin, &end, NULL ) != NULL )
857 	{
858 #ifdef DEBUG_TEXT
859 		g_print ( "*  search forwards % s\n", ( gchar*  ) Tcl_GetString ( objv[cmdNo+2] ) );
860 #endif
861 		/*  return the index of the found location */
862 		row1 = gtk_text_iter_get_line ( &begin );
863 		col1 = gtk_text_iter_get_line_offset ( &begin );
864 		row2 = gtk_text_iter_get_line ( &end );
865 		col2 = gtk_text_iter_get_line_offset ( &end );
866 
867 		Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( row1 ) );
868 		Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( col1 ) );
869 		Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( row2 ) );
870 		Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( col2 ) );
871 
872 		start = end;
873 
874 	}
875 
876 	Tcl_SetObjResult ( interp, resList );
877 
878 	/*  return the total number of items returned in the list */
879 	return TCL_OK;
880 }
881 
882 /**
883 \brief
884 **/
gnoclOptText(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)885 static int gnoclOptText ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret )
886 {
887 	GtkWidget *container;
888 	container =  gtk_widget_get_parent ( obj );
889 
890 #ifdef DEBUG_TEXT
891 	g_print ( "INSERT SOME INITIAL TEXT\n" );
892 #endif
893 
894 	return TCL_OK;
895 }
896 
897 /**
898 \brief	Set equidistant tab stops meausure in pixels.
899 http://developer.gnome.org/pango/stable/pango-Tab-Stops.html
900 **/
gnoclOptTabs(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)901 static int gnoclOptTabs ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret )
902 {
903 
904 #ifdef DEBUG_TEXT
905 	g_print ( "%s SET SOME INITIAL TABS\n", __FUNCTION__ );
906 #endif
907 
908 	gint pos;
909 
910 	Tcl_GetIntFromObj ( interp, opt->val.obj, &pos );
911 
912 	PangoTabArray *tab_array = pango_tab_array_new_with_positions ( 1, TRUE, PANGO_TAB_LEFT, pos );
913 	gtk_text_view_set_tabs ( GTK_TEXT_VIEW ( obj ), tab_array );
914 
915 	/*
916 	 * An alternative way...
917 	*/
918 	/*
919 	PangoTabArray *tab_array;
920 	gint initial_size,tab_index, location;
921 	PangoTabAlign alignment;
922 
923 	initial_size = 2;
924 
925 	tab_array = pango_tab_array_new (initial_size,1);
926 
927 	pango_tab_array_set_tab (tab_array,0,PANGO_TAB_LEFT, 100);
928 	pango_tab_array_set_tab (tab_array,1,PANGO_TAB_LEFT, 200);
929 
930 	gtk_text_view_set_tabs ( GTK_TEXT_VIEW ( obj ), tab_array );
931 
932 	pango_tab_array_free (tab_array);
933 	*/
934 	return TCL_OK;
935 }
936 
937 /**
938 \brief	Set text tag attribute.
939 \notes  Keywords:
940         raise
941         lower
942         top
943         bottom
944 **/
gnoclOptTextTagPriority(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)945 static int gnoclOptTextTagPriority ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret )
946 {
947 
948 #ifdef DEBUG_TEXT
949 	debugStep ( __FUNCTION__, 1.0 );
950 #endif
951 
952 	static char *opts[] =
953 	{
954 		"raise", "lower", "top", "bottom",
955 		NULL
956 	};
957 
958 	static enum  popupOptionsIdx
959 	{
960 		raiseIdx, lowerIdx, topIdx, bottomIdx
961 	};
962 
963 	gint idx;
964 
965 	gint priority;
966 
967 	gint max;
968 
969 	GtkTextTag *tag;
970 
971 	tag = GTK_TEXT_TAG ( obj );
972 
973 	max = gtk_text_tag_table_get_size ( tag->table );
974 
975 	priority = gtk_text_tag_get_priority ( tag );
976 
977 	getIdx ( opts,  Tcl_GetStringFromObj ( opt->val.obj, NULL ), &idx );
978 
979 	switch ( idx )
980 	{
981 		case raiseIdx:
982 			{
983 				priority++;
984 			}
985 			break;
986 		case lowerIdx:
987 			{
988 				priority--;
989 			}
990 			break;
991 		case topIdx:
992 			{
993 				priority = max - 1;
994 			}
995 			break;
996 		case bottomIdx:
997 			{
998 				priority = 0;
999 			}
1000 			break;
1001 		default:
1002 			{
1003 				Tcl_GetIntFromObj ( interp, opt->val.obj, &priority );
1004 			}
1005 	}
1006 
1007 	/* check limits */
1008 	if ( priority < 0 )
1009 	{
1010 		priority = 0;
1011 	}
1012 
1013 	if ( priority >= max )
1014 	{
1015 		priority--;
1016 	}
1017 
1018 	gtk_text_tag_set_priority ( tag, priority );
1019 
1020 	return TCL_OK;
1021 }
1022 
1023 /**
1024 \brief	Set text tag attribute.
1025 **/
gnoclOptTagBackgroundStipple(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)1026 static int gnoclOptTagBackgroundStipple ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret )
1027 {
1028 	GtkWidget *container;
1029 	container =  gtk_widget_get_parent ( obj );
1030 
1031 #ifdef DEBUG_TEXT
1032 	debugStep ( __FUNCTION__, 1.0 );
1033 	g_print ( "Feature not yet implemented\n" );
1034 #endif
1035 
1036 	return TCL_OK;
1037 }
1038 
1039 /**
1040 \brief	Set text tag attribute.
1041 **/
gnoclOptTagTextDirection(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)1042 static int gnoclOptTagTextDirection ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret )
1043 {
1044 
1045 #ifdef DEBUG_TEXT
1046 	debugStep ( __FUNCTION__, 1.0 );
1047 #endif
1048 
1049 	/* options: leftRight | rightLeft | none */
1050 
1051 	/*
1052 	typedef enum
1053 	{
1054 	GTK_TEXT_DIR_NONE,
1055 	GTK_TEXT_DIR_LTR,
1056 	GTK_TEXT_DIR_RTL,
1057 	} GtkTextDirection;
1058 	*/
1059 
1060 	int idx;
1061 
1062 	const char *txt[] = { "none", "leftRight", "rightLeft", NULL };
1063 
1064 	if ( Tcl_GetIndexFromObj ( NULL, opt->val.obj, txt, NULL, TCL_EXACT, &idx ) != TCL_OK )
1065 	{
1066 		Tcl_AppendResult ( interp, "Unknown direction \"", Tcl_GetString ( opt->val.obj ), "\". Must be one of none, leftRight or rightLeft.", NULL );
1067 		return TCL_ERROR;
1068 	}
1069 
1070 	g_object_set ( obj, opt->propName, idx, NULL );
1071 
1072 	return TCL_OK;
1073 }
1074 
1075 /**
1076 \brief	Set text tag attribute.
1077 **/
gnoclOptTextTagForegroundStipple(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)1078 static int gnoclOptTextTagForegroundStipple ( Tcl_Interp * interp, GnoclOption * opt, GObject * obj, Tcl_Obj **ret )
1079 {
1080 	GtkWidget *container;
1081 	container =  gtk_widget_get_parent ( obj );
1082 
1083 #ifdef DEBUG_TEXT
1084 	debugStep ( __FUNCTION__, 1.0 );
1085 	g_print ( "Feature not yet implemented\n" );
1086 #endif
1087 
1088 	return TCL_OK;
1089 }
1090 
1091 /**
1092 \brief	Set text tag attribute.
1093 **/
gnocOptTextTagLanguage(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)1094 static int gnocOptTextTagLanguage ( Tcl_Interp * interp, GnoclOption * opt, GObject * obj, Tcl_Obj **ret )
1095 {
1096 
1097 	gchar *lang;
1098 	gint i;
1099 
1100 	lang = Tcl_GetStringFromObj ( opt->val.obj, NULL );
1101 
1102 #ifdef DEBUG_TEXT
1103 	debugStep ( __FUNCTION__, 1.0 );
1104 	g_print ( "Language = %s\n", lang );
1105 #endif
1106 
1107 	i = getLanguage ( lang );
1108 
1109 #ifdef DEBUG_TEXT
1110 	g_print ( "idx = %d\n", i );
1111 #endif
1112 
1113 
1114 
1115 	return TCL_OK;
1116 }
1117 
1118 /**
1119 \brief	Set text tag attribute.
1120 **/
gnoclOptTextTagTabs(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)1121 static int gnoclOptTextTagTabs ( Tcl_Interp * interp, GnoclOption * opt, GObject * obj, Tcl_Obj **ret )
1122 {
1123 
1124 
1125 #ifdef DEBUG_TEXT
1126 	debugStep ( __FUNCTION__, 1.0 );
1127 	g_print ( "Feature not yet implemented\n" );
1128 #endif
1129 
1130 	return TCL_OK;
1131 }
1132 
1133 /**
1134 \brief	Set text tag attribute.
1135 **/
gnoclOptTextTagVariant(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)1136 static int gnoclOptTextTagVariant ( Tcl_Interp * interp, GnoclOption * opt, GObject * obj, Tcl_Obj **ret )
1137 {
1138 
1139 #ifdef DEBUG_TEXT
1140 	debugStep ( __FUNCTION__, 1.0 );
1141 	g_print ( "Feature not yet implemented\n" );
1142 #endif
1143 
1144 	return TCL_OK;
1145 }
1146 
1147 
1148 /**
1149 \brief
1150 */
doOnTextEnterLeave(GtkWidget * widget,GdkEventMotion * event,gpointer data)1151 static gboolean doOnTextEnterLeave ( GtkWidget * widget, GdkEventMotion * event, 	gpointer data )
1152 {
1153 	GnoclCommandData *cs = ( GnoclCommandData *  ) data;
1154 
1155 	GnoclPercSubst ps[] =
1156 	{
1157 		{ 'w', GNOCL_STRING },  /*  widget */
1158 		{ 0 }
1159 	};
1160 
1161 	ps[0].val.str = gnoclGetNameFromWidget ( widget );
1162 
1163 	/*  TODO: gnocl::buttonStateToList -> {MOD1 MOD3 BUTTON2...} */
1164 	gnoclPercentSubstAndEval ( cs->interp, ps, cs->command, 1 );
1165 	return 0;
1166 }
1167 
1168 
1169 /**
1170 \brief	Add default set of tag with pango compliant tagnames.
1171 **/
gnoclOptMarkupTags(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)1172 static int gnoclOptMarkupTags ( Tcl_Interp * interp, GnoclOption * opt, GObject * obj, Tcl_Obj **ret )
1173 {
1174 #ifdef DEBUG_TEXT
1175 	g_print ( "%s %d\n", __FUNCTION__, Tcl_GetString ( opt->val.obj ) );
1176 #endif
1177 
1178 	extern gint usemarkup;
1179 
1180 	assert ( strcmp ( opt->optName, "-markupTags" ) == 0 );
1181 
1182 	/* modify this to destroy tags */
1183 	if ( strcmp ( Tcl_GetString ( opt->val.obj ), "1" ) == 0 )
1184 	{
1185 		usemarkup = 1;
1186 		/* create default markup tag set */
1187 	}
1188 
1189 	else
1190 	{
1191 		return TCL_OK;
1192 		usemarkup = 1;
1193 		/* delete markup tags */
1194 	}
1195 
1196 #ifdef DEBUG_TEXT
1197 	g_print ( "usemarkup = %d\n", usemarkup );
1198 #endif
1199 
1200 	GtkTextBuffer *buffer = gtk_text_view_get_buffer ( GTK_TEXT_VIEW ( obj ) );
1201 
1202 	/* convenience tags */
1203 	// 'b','i','s','u','tt','sub','sup','small','big'
1204 	gtk_text_buffer_create_tag ( buffer, "<b>", "weight", PANGO_WEIGHT_BOLD, NULL );
1205 	gtk_text_buffer_create_tag ( buffer, "<i>", "style", PANGO_STYLE_ITALIC, NULL );
1206 	gtk_text_buffer_create_tag ( buffer, "<s>", "strikethrough", 1, NULL );
1207 	gtk_text_buffer_create_tag ( buffer, "<u>", "underline", PANGO_UNDERLINE_SINGLE, NULL );
1208 	gtk_text_buffer_create_tag ( buffer, "<tt>", "font", "Monospace", NULL );
1209 	gtk_text_buffer_create_tag ( buffer, "<sub>", "scale", PANGO_SCALE_SMALL, "rise", -10, NULL );
1210 	gtk_text_buffer_create_tag ( buffer, "<sup>", "scale", PANGO_SCALE_SMALL, "rise",  +10, NULL );
1211 	gtk_text_buffer_create_tag ( buffer, "<small>", "scale", PANGO_SCALE_SMALL, NULL );
1212 	gtk_text_buffer_create_tag ( buffer, "<big>", "scale", PANGO_SCALE_LARGE, NULL );
1213 
1214 	/* foreground colours */
1215 	// 'red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'black', 'gray', 'white'
1216 	gtk_text_buffer_create_tag ( buffer, "<span foreground='red'>",   "foreground", "red", NULL );
1217 	gtk_text_buffer_create_tag ( buffer, "<span foreground='green'>", "foreground", "green", NULL );
1218 	gtk_text_buffer_create_tag ( buffer, "<span foreground='blue'>",  "foreground", "blue", NULL );
1219 
1220 	gtk_text_buffer_create_tag ( buffer, "<span foreground='black'>", "foreground", "black", NULL );
1221 	gtk_text_buffer_create_tag ( buffer, "<span foreground='gray'>",  "foreground", "gray", NULL );
1222 	gtk_text_buffer_create_tag ( buffer, "<span foreground='white'>", "foreground", "white", NULL );
1223 
1224 	/* background colours */
1225 	// 'red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'black', 'gray', 'white'
1226 	gtk_text_buffer_create_tag ( buffer, "<span background='cyan'>",    "background", "cyan", NULL );
1227 	gtk_text_buffer_create_tag ( buffer, "<span background='magenta'>", "background", "magenta", NULL );
1228 	gtk_text_buffer_create_tag ( buffer, "<span background='yellow'>",  "background", "yellow", NULL );
1229 	gtk_text_buffer_create_tag ( buffer, "<span background='orange'>",  "background", "orange", NULL );
1230 
1231 
1232 	gtk_text_buffer_create_tag ( buffer, "<span background='black'>", "background", "black", NULL );
1233 	gtk_text_buffer_create_tag ( buffer, "<span background='gray'>",  "background", "gray", NULL );
1234 	gtk_text_buffer_create_tag ( buffer, "<span background='white'>", "background", "white", NULL );
1235 
1236 	/* default typefaces */
1237 	// 'serif' or 'sans'
1238 	gtk_text_buffer_create_tag ( buffer, "<span face='sans'>", "font", "serif", NULL );
1239 	gtk_text_buffer_create_tag ( buffer, "<span face='serif'>", "font", "sans", NULL );
1240 
1241 	/* font scaling */
1242 	// 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'
1243 	gtk_text_buffer_create_tag ( buffer, "<span size='xx-small'>", "scale", PANGO_SCALE_XX_SMALL, NULL );
1244 	gtk_text_buffer_create_tag ( buffer, "<span size='x-small'>" , "scale", PANGO_SCALE_X_SMALL, NULL );
1245 	gtk_text_buffer_create_tag ( buffer, "<span size='small'>"   , "scale", PANGO_SCALE_SMALL, NULL );
1246 	gtk_text_buffer_create_tag ( buffer, "<span size='medium'>"  , "scale", PANGO_SCALE_MEDIUM, NULL );
1247 	gtk_text_buffer_create_tag ( buffer, "<span size='large'>"   , "scale", PANGO_SCALE_LARGE, NULL );
1248 	gtk_text_buffer_create_tag ( buffer, "<span size='x-large'>" , "scale", PANGO_SCALE_X_LARGE, NULL );
1249 	gtk_text_buffer_create_tag ( buffer, "<span size='xx-large'>", "scale", PANGO_SCALE_XX_LARGE, NULL );
1250 
1251 	/* font weight */
1252 	//'ultralight', 'light', 'normal', 'bold', 'ultrabold', 'heavy'
1253 	gtk_text_buffer_create_tag ( buffer, "<span weight='light'>"    , "weight", PANGO_WEIGHT_LIGHT, NULL );
1254 	gtk_text_buffer_create_tag ( buffer, "<span weight='normal'>"   , "weight", PANGO_WEIGHT_NORMAL, NULL );
1255 	gtk_text_buffer_create_tag ( buffer, "<span weight='bold'>"     , "weight", PANGO_WEIGHT_BOLD, NULL );
1256 	gtk_text_buffer_create_tag ( buffer, "<span weight='ultrabold'>", "weight", PANGO_WEIGHT_ULTRABOLD, NULL );
1257 	gtk_text_buffer_create_tag ( buffer, "<span weight='heavy'>"    , "weight", PANGO_WEIGHT_HEAVY, NULL );
1258 
1259 	/* variant */
1260 	// 'normal' or 'smallcaps'
1261 	gtk_text_buffer_create_tag ( buffer, "<span variant='normal'>"    , "variant", PANGO_VARIANT_NORMAL, NULL );
1262 	gtk_text_buffer_create_tag ( buffer, "<span variant='smallcaps'>" , "variant", PANGO_VARIANT_SMALL_CAPS, NULL );
1263 
1264 	/* stretch */
1265 	// 'ultracondensed', 'extracondensed', 'condensed', 'semicondensed', 'normal', 'semiexpanded', 'expanded', 'extraexpanded', 'ultraexpanded'
1266 	gtk_text_buffer_create_tag ( buffer, "<span stretch='ultracondensed'>" , "stretch", PANGO_STRETCH_ULTRA_CONDENSED, NULL );
1267 	gtk_text_buffer_create_tag ( buffer, "<span stretch='extracondensed'>" , "stretch", PANGO_STRETCH_EXTRA_CONDENSED, NULL );
1268 	gtk_text_buffer_create_tag ( buffer, "<span stretch='condensed'>"      , "stretch", PANGO_STRETCH_CONDENSED, NULL );
1269 	gtk_text_buffer_create_tag ( buffer, "<span stretch='normal'>"         , "stretch", PANGO_STRETCH_NORMAL, NULL );
1270 	gtk_text_buffer_create_tag ( buffer, "<span stretch='semicondensed'>"  , "stretch", PANGO_STRETCH_SEMI_CONDENSED, NULL );
1271 	gtk_text_buffer_create_tag ( buffer, "<span stretch='expanded'>"       , "stretch", PANGO_STRETCH_EXPANDED, NULL );
1272 	gtk_text_buffer_create_tag ( buffer, "<span stretch='extraexpanded'>"  , "stretch", PANGO_STRETCH_EXTRA_EXPANDED, NULL );
1273 	gtk_text_buffer_create_tag ( buffer, "<span stretch='ultraexpanded'>"  , "stretch", PANGO_STRETCH_ULTRA_EXPANDED, NULL );
1274 
1275 	/* underline */
1276 	// 'none', 'single', 'double', 'low', 'error'
1277 	gtk_text_buffer_create_tag ( buffer, "<span underline='none'>"   , "underline", PANGO_UNDERLINE_NONE, NULL );
1278 	gtk_text_buffer_create_tag ( buffer, "<span underline='single'>" , "underline", PANGO_UNDERLINE_SINGLE, NULL );
1279 	gtk_text_buffer_create_tag ( buffer, "<span underline='double'>" , "underline", PANGO_UNDERLINE_DOUBLE, NULL );
1280 	gtk_text_buffer_create_tag ( buffer, "<span underline='low'>"    , "underline", PANGO_UNDERLINE_LOW, NULL );
1281 	gtk_text_buffer_create_tag ( buffer, "<span underline='error'>"  , "underline", PANGO_UNDERLINE_ERROR, NULL );
1282 
1283 	return TCL_OK;
1284 }
1285 
1286 /**
1287 \brief
1288 **/
gnoclOptTextOnEnterLeave(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)1289 static int gnoclOptTextOnEnterLeave ( Tcl_Interp * interp, GnoclOption * opt, GObject * obj, Tcl_Obj **ret )
1290 {
1291 	GtkWidget *container;
1292 	container =  gtk_widget_get_parent ( obj );
1293 
1294 	assert ( strcmp ( opt->optName, "-onEnter" ) == 0 || strcmp ( opt->optName, "-onLeave" ) == 0 );
1295 	return gnoclConnectOptCmd ( interp, obj, opt->optName[3] == 'E' ? "enter-notify-event" : "leave-notify-event", G_CALLBACK ( doOnTextEnterLeave ), opt, NULL, ret );
1296 }
1297 
1298 /**
1299 \brief
1300 **/
getBitmapMask(gchar * filename)1301 static GdkBitmap *getBitmapMask ( gchar * filename )
1302 {
1303 	GdkPixbuf *pbuf;
1304 	GdkBitmap *ret;
1305 	GError *err = NULL;
1306 
1307 	g_return_val_if_fail ( filename != NULL, NULL );
1308 
1309 	pbuf = gdk_pixbuf_new_from_file ( filename, &err );
1310 
1311 	if ( err != NULL )
1312 	{
1313 		g_warning ( "%s", err->message );
1314 		g_error_free ( err );
1315 		return NULL;
1316 	}
1317 
1318 	/* you may want to change the threshold, depending on your image */
1319 	gdk_pixbuf_render_pixmap_and_mask ( pbuf, NULL, &ret, 1 );
1320 
1321 	//g_object_unref ( pbuf );
1322 
1323 	return ret;
1324 }
1325 
1326 
1327 /**
1328 \brief
1329 **/
doOnInsertPixbuf(GtkTextBuffer * textbuffer,GtkTextIter * location,GdkPixbuf * pixbuf,gpointer user_data)1330 static void doOnInsertPixbuf ( GtkTextBuffer * textbuffer, GtkTextIter * location, GdkPixbuf * pixbuf, gpointer user_data )
1331 {
1332 	GnoclCommandData *cs = ( GnoclCommandData * ) user_data;
1333 
1334 	GnoclPercSubst ps[] =
1335 	{
1336 		{ 'w', GNOCL_STRING },  /* widget */
1337 		{ 'r', GNOCL_INT },     /* row */
1338 		{ 'c', GNOCL_INT },     /* column */
1339 		{ 'p', GNOCL_INT },		/* pixbuf */
1340 		{ 0 }
1341 	};
1342 
1343 	ps[0].val.str = gnoclGetNameFromWidget ( textbuffer );
1344 	ps[1].val.i   = gtk_text_iter_get_line ( location );
1345 	ps[2].val.i   = gtk_text_iter_get_line_offset ( location );
1346 	ps[3].val.str = gnoclGetNameFromPixBuf ( pixbuf );
1347 
1348 	gnoclPercentSubstAndEval ( cs->interp, ps, cs->command, 1 );
1349 }
1350 
1351 
1352 /**
1353 \brief
1354 \author     William J Giddings
1355 \date       30-Apr-09
1356 **/
gnoclOptOnInsertPB(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)1357 int gnoclOptOnInsertPB ( Tcl_Interp * interp, GnoclOption * opt, GObject * obj, Tcl_Obj **ret )
1358 {
1359 
1360 	/* check the name of the signal is correct for this function */
1361 	assert ( strcmp ( opt->optName, "-onInsertPixBuf" ) == 0 );
1362 
1363 	/* connect the signal with its callback function */
1364 	return gnoclConnectOptCmd ( interp, GTK_ENTRY  ( obj ), "insert-pixbuf", G_CALLBACK ( doOnInsertPixbuf ), opt, NULL, ret );
1365 
1366 }
1367 
1368 /**
1369 \brief     Handles the "toggle-cursor-visible" signal.
1370 \author    William J Giddings
1371 \date      30/04/2010
1372 \since     0.9.95
1373 \note      Used by: gnome::text, Default Binding F7.
1374 \**/
doOnToggleCursorVisible(GtkTextView * text_view,gpointer user_data)1375 static void doOnToggleCursorVisible ( GtkTextView * text_view, gpointer user_data )
1376 {
1377 
1378 	GnoclCommandData *cs = ( GnoclCommandData * ) user_data;
1379 
1380 	GnoclPercSubst ps[] =
1381 	{
1382 		{ 'w', GNOCL_STRING },  /* widget name */
1383 		{ 'g', GNOCL_STRING },  /* glade name */
1384 		{ 'v', GNOCL_INT },  	/* visibility, boolean */
1385 		{ 0 }
1386 	};
1387 
1388 	ps[0].val.str = gnoclGetNameFromWidget ( text_view );
1389 	ps[1].val.str = gtk_widget_get_name ( GTK_WIDGET ( text_view ) );
1390 	ps[2].val.i = gtk_text_view_get_cursor_visible ( text_view );
1391 
1392 	gnoclPercentSubstAndEval ( cs->interp, ps, cs->command, 1 );
1393 }
1394 
1395 /**
1396 \brief
1397 \author		William J Giddings
1398 \date		30/04/2010
1399 \note
1400 **/
gnoclOptOnToggleCursorVisible(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)1401 int gnoclOptOnToggleCursorVisible ( Tcl_Interp * interp, GnoclOption * opt, GObject * obj, Tcl_Obj **ret )
1402 {
1403 	/* check the name of the signal is correct for this function */
1404 	assert ( strcmp ( opt->optName, "-onToggleCursorVisible" ) == 0 );
1405 
1406 	/* connect the signal with its callback function */
1407 	return gnoclConnectOptCmd ( interp, obj, "toggle-cursor-visible" , G_CALLBACK ( doOnToggleCursorVisible ), opt, NULL, ret );
1408 }
1409 
1410 /**
1411 \brief
1412     Description yet to be added.
1413 \note
1414     As long as the options for the GtkScrolledWindow are not set
1415     automatically, we don't need any special handling in gnoclSetOptions.
1416 */
1417 static const int scrollBarIdx = 0;
1418 static const int textIdx = 1;
1419 static const int bufferIdx = 2;
1420 static const int useUndoIdx = 3;
1421 static const int dataIdx = 4;
1422 static const int baseColorIdx = 5;
1423 static const int variableIdx = 6;
1424 static const int onChangedIdx = 7;
1425 static const int baseFontIdx = 8;
1426 static const int tooltipIdx = 9;
1427 
1428 static GnoclOption textOptions[] =
1429 {
1430 	/*  textView */
1431 
1432 	/*  gnocl-specific options - cget implemented */
1433 	{ "-scrollbar", GNOCL_OBJ, NULL },
1434 	{ "-text", GNOCL_STRING, NULL},
1435 	{ "-buffer", GNOCL_STRING, NULL},
1436 	{ "-useUndo", GNOCL_STRING, NULL},
1437 	{ "-data", GNOCL_OBJ, "", gnoclOptData },
1438 	{ "-baseColor", GNOCL_OBJ, "normal", gnoclOptGdkColorBase },
1439 	{ "-variable", GNOCL_STRING, NULL },
1440 	{ "-onChanged", GNOCL_STRING, NULL },
1441 	{ "-baseFont", GNOCL_OBJ, "Sans 14", gnoclOptGdkBaseFont },
1442 	{ "-tooltip", GNOCL_OBJ, "", gnoclOptTooltip },
1443 
1444 	/* GtkTextView properties
1445 	"accepts-tab"              gboolean              : Read / Write
1446 	"buffer"                   GtkTextBuffer*        : Read / Write
1447 	"cursor-visible"           gboolean              X
1448 	"editable"                 gboolean              X
1449 	"indent"                   gint                  X
1450 	"justification"            GtkJustification      X
1451 	"left-margin"              gint                  X
1452 	"overwrite"                gboolean              : Read / Write
1453 	"pixels-above-lines"       gint                  X
1454 	"pixels-below-lines"       gint                  X
1455 	"pixels-inside-wrap"       gint                  X
1456 	"right-margin"             gint                  : Read / Write
1457 	"tabs"                     PangoTabArray*        : Read / Write
1458 	"wrap-mode"                GtkWrapMode           : Read / Write
1459 	*/
1460 
1461 	{ "-markupTags", GNOCL_OBJ, "", gnoclOptMarkupTags },
1462 	{ "-acceptsTab", GNOCL_BOOL, "accepts-tab" },
1463 	{ "-cursorVisible", GNOCL_BOOL, "cursor_visible" },
1464 	{ "-editable", GNOCL_BOOL, "editable" },
1465 	{ "-indent", GNOCL_INT, "indent" },
1466 	{ "-justify", GNOCL_OBJ, "justification", gnoclOptJustification },
1467 	{ "-leftMargin", GNOCL_INT, "left_margin" },
1468 	{ "-inputMethod", GNOCL_STRING, "im-module" },
1469 	{ "-overwrite", GNOCL_BOOL, "overwrite" },
1470 	{ "-pixelsBelowLines", GNOCL_INT, "pixels_below_lines" },
1471 	{ "-pixelsAboveLines", GNOCL_INT, "pixels_above_lines" },
1472 	{ "-pixelsInsideWrap", GNOCL_INT, "pixels_inside_wrap" },
1473 	{ "-rightMargin", GNOCL_INT, "right_margin" },
1474 	{ "-tabs", GNOCL_OBJ, "tabs", gnoclOptTabs}, /* "tabs" */
1475 	{ "-wrapMode", GNOCL_OBJ, "wrap_mode", gnoclOptWrapmode },
1476 
1477 	/* GtkTextBuffer properties
1478 	"copy-target-list"         GtkTargetList*        : Read
1479 	"cursor-position"          gint                  : Read
1480 	"has-selection"            gboolean              : Read
1481 	"paste-target-list"        GtkTargetList*        : Read
1482 	"tag-table"                GtkTextTagTable*      : Read / Write / Construct Only
1483 	"text"                     gchar*                : Read / Write
1484 	*/
1485 
1486 	{ "-hasFocus", GNOCL_BOOL, "has-focus" },
1487 
1488 	{ "-onShowHelp", GNOCL_OBJ, "", gnoclOptOnShowHelp },
1489 	{ "-name", GNOCL_STRING, "name" },
1490 	{ "-visible", GNOCL_BOOL, "visible" },
1491 	{ "-sensitive", GNOCL_BOOL, "sensitive" },
1492 	{ "-baseFont", GNOCL_OBJ, "Sans 14", gnoclOptGdkBaseFont },
1493 	//{ "-baseColor", GNOCL_OBJ, "normal", gnoclOptGdkColorBase },
1494 
1495 	/* -------- GtkTextView signals --------*/
1496 
1497 	/*
1498 	  "backspace"                                      : Run Last / Action
1499 	  "copy-clipboard"                                 : Run Last / Action
1500 	  "cut-clipboard"                                  : Run Last / Action
1501 	  "delete-from-cursor"                             : Run Last / Action
1502 	  "insert-at-cursor"                               : Run Last / Action
1503 	  "move-cursor"                                    : Run Last / Action
1504 	  "move-viewport"                                  : Run Last / Action
1505 	  "page-horizontally"                              : Run Last / Action
1506 	  "paste-clipboard"                                : Run Last / Action
1507 	  "populate-popup"                                 : Run Last
1508 	  "select-all"                                     : Run Last / Action
1509 	  "set-anchor"                                     : Run Last / Action
1510 	  "set-scroll-adjustments"                         : Run Last / Action
1511 	  "toggle-cursor-visible"                          : Run Last / Action
1512 	  "toggle-overwrite"                               : Run Last / Action
1513 
1514 	*/
1515 
1516 	{ "-onBackspace", GNOCL_OBJ, "", gnoclOptOnBackspace},
1517 	{ "-onCopyClipboard", GNOCL_OBJ, "C", gnoclOptOnClipboard},
1518 	{ "-onCutClipboard", GNOCL_OBJ, "X", gnoclOptOnClipboard},
1519 	{ "-onUndo", GNOCL_OBJ, "U", gnoclOptOnUndoRedo},
1520 	{ "-onRedo", GNOCL_OBJ, "R", gnoclOptOnUndoRedo},
1521 
1522 	/* added 29/Apr/2010 */
1523 	{ "-onDeleteFromCursor", GNOCL_OBJ, "", gnoclOptOnDeleteFromCursor},
1524 	{ "-onInsertAtCursor", GNOCL_OBJ, "", gnoclOptOnInsertAtCursor},
1525 	{ "-onMoveCursor", GNOCL_OBJ, "", gnoclOptOnMoveCursor},
1526 	{ "-onMoveViewport", GNOCL_OBJ, "", gnoclOptOnMoveViewport},
1527 	{ "-onPageHorizontally", GNOCL_OBJ, "", gnoclOptOnPageHorizontally},
1528 	{ "-onPasteClipboard", GNOCL_OBJ, "P", gnoclOptOnClipboard},
1529 	{ "-onSelectAll", GNOCL_OBJ, "", gnoclOptOnSelectAll},
1530 	{ "-onPreeditChanged", GNOCL_OBJ, "", gnoclOptOnClipboard},
1531 
1532 	/* added 30/Apr/2010 */
1533 	{ "-onSetAnchor", GNOCL_OBJ, "", gnoclOptOnSetAnchor},
1534 	{ "-onSetScrollAdjustments", GNOCL_OBJ, "", gnoclOptOnScrollAdjustments},
1535 
1536 	/* check parse*.c code, for errors, or re-enter */
1537 	{ "-onToggleCursorVisible", GNOCL_OBJ, "", gnoclOptOnToggleCursorVisible },
1538 	{ "-onToggleOverWrite", GNOCL_OBJ, "", gnoclOptOnToggleOverwrite},
1539 
1540 	/* -------- end of GtkTexView signals */
1541 	{ "-onButtonPress", GNOCL_OBJ, "P", gnoclOptOnButton },
1542 	{ "-onButtonRelease", GNOCL_OBJ, "R", gnoclOptOnButton },
1543 	{ "-onKeyPress", GNOCL_OBJ, "", gnoclOptOnKeyPress },
1544 	{ "-onKeyRelease", GNOCL_OBJ, "", gnoclOptOnKeyRelease },
1545 	{ "-onMotion", GNOCL_OBJ, "", gnoclOptOnMotion },
1546 	{ "-onFocusIn", GNOCL_OBJ, "I", gnoclOptOnFocus },
1547 	{ "-onFocusOut", GNOCL_OBJ, "O", gnoclOptOnFocus },
1548 	{ "-onEnter", GNOCL_OBJ, "E", gnoclOptTextOnEnterLeave },
1549 	{ "-onLeave", GNOCL_OBJ, "L", gnoclOptTextOnEnterLeave },
1550 	{ "-onPopulatePopup", GNOCL_OBJ, "", gnoclOptOnPopulatePopup },
1551 	{ "-heightRequest", GNOCL_INT, "height-request" },
1552 	{ "-widthRequest", GNOCL_INT, "width-request" },
1553 
1554 	/* -------- GtkTextBuffer signals -------- */
1555 	{ "-onApplyTag", GNOCL_OBJ, "", gnoclOptOnApplyTag},
1556 	{ "-onBeginUserAction", GNOCL_OBJ, "", gnoclOptOnBeginUserAction},
1557 	{ "-onChanged", GNOCL_OBJ, "", gnoclOptOnChanged},
1558 	{ "-onDeleteRange", GNOCL_OBJ, "", gnoclOptOnDeleteRange},
1559 	{ "-onEndUserAction", GNOCL_OBJ, "", gnoclOptOnEndUserAction},
1560 	{ "-onInsertChildAnchor", GNOCL_OBJ, "", gnoclOptOnInsertChildAnchor},
1561 	{ "-onInsertPixBuf", GNOCL_OBJ, "", gnoclOptOnInsertPB},
1562 	{ "-onInsertText", GNOCL_OBJ, "", gnoclOptOnTextInsert},
1563 	{ "-onMarkDelete", GNOCL_OBJ, "", gnoclOptOnMarkDelete},
1564 	{ "-onMarkSet", GNOCL_OBJ, "", gnoclOptOnMarkSet},
1565 	{ "-onModified", GNOCL_OBJ, "", gnoclOptOnModified}, /* ie. modified-changed */
1566 	{ "-onPasteDone", GNOCL_OBJ, "", gnoclOptOnPasteDone}, /* since Gtk+ 2.15 */
1567 	{ "-onRemoveTag", GNOCL_OBJ, "", gnoclOptOnRemoveTag},
1568 
1569 	/*  inherited GtkWidget features */
1570 	{ "-onScroll", GNOCL_OBJ, "", gnoclOptOnScroll },
1571 	{ "-borderWidth", GNOCL_OBJ, "border-width", gnoclOptPadding },
1572 
1573 	/* drag and drop functionality taken from box.c */
1574 	{ "-dropTargets", GNOCL_LIST, "t", gnoclOptDnDTargets },
1575 	{ "-dragTargets", GNOCL_LIST, "s", gnoclOptDnDTargets },
1576 	{ "-onDropData", GNOCL_OBJ, "", gnoclOptOnDropData },
1577 	{ "-onDragBegin", GNOCL_OBJ, "", gnoclOptOnDragEnd },
1578 	{ "-onDragEnd", GNOCL_OBJ, "", gnoclOptOnDragEnd },
1579 	{ "-onDragData", GNOCL_OBJ, "", gnoclOptOnDragData },
1580 	{ "-hasTooltip", GNOCL_BOOL, "has-tooltip" },
1581 	{ "-onQueryTooltip", GNOCL_OBJ, "", gnoclOptOnQueryToolTip },
1582 	{ "-onDestroy", GNOCL_OBJ, "destroy", gnoclOptCommand },
1583 
1584 	{ NULL }
1585 };
1586 
1587 /**
1588 \brief      Convert at text index in the form of {row col} into a GtkTextBuffer iter(ator).
1589 \author     Peter G Baum
1590 \date       2001-06:
1591 \bug        (text_cursor_keyWords_test.tcl:13461): Gtk-WARNING **: Invalid text buffer iterator: either the iterator is uninitialized,
1592             or the characters/pixbufs/widgets in the buffer have been modified since the iterator was created.
1593             You must use marks, character numbers, or line numbers to preserve a position across buffer modifications.
1594             You can apply tags and insert marks without invalidating your iterators,
1595             but any mutation that affects 'indexable' buffer contents (contents that can be referred to by character offset)
1596             will invalidate all outstanding iterators
1597             Causes: moving the inter does not act on the buffer, once the iter has been moved, then it n
1598 \todo       Include new keywords
1599                 sentenceStart
1600                 sentenceEnd
1601                 paragraphStart
1602                 paragraphEnd
1603                 wordStart
1604                 wordEnd
1605                 lineEnd
1606 \history
1607     2008-06-27  Began implementation of new keywords for text position. See TODO.
1608 */
posToIter(Tcl_Interp * interp,Tcl_Obj * obj,GtkTextBuffer * buffer,GtkTextIter * iter)1609 int posToIter ( Tcl_Interp * interp, Tcl_Obj * obj, GtkTextBuffer * buffer, GtkTextIter * iter )
1610 {
1611 	char errMsg[] = "Position must be either a list of row and column "
1612 					"or a keyword plus offset";
1613 	char errEndOffset[] = "offset to \"end\" must be negative";
1614 
1615 	int len;
1616 
1617 	/*  error check the arguments passed to the function */
1618 
1619 	if ( Tcl_ListObjLength ( interp, obj, &len ) != TCL_OK || len < 1 || len > 2 )
1620 	{
1621 		Tcl_SetResult ( interp, errMsg, TCL_STATIC );
1622 		return TCL_ERROR;
1623 	}
1624 
1625 	/*  this is right */
1626 
1627 	if ( len == 2 )
1628 	{
1629 		int idx[2];
1630 		int isEnd[2] = { 0, 0 };
1631 		int k;
1632 
1633 		for ( k = 0; k < 2; ++k )
1634 		{
1635 			Tcl_Obj *tp;
1636 
1637 			if ( Tcl_ListObjIndex ( interp, obj, k, &tp ) != TCL_OK )
1638 			{
1639 				Tcl_SetResult ( interp, errMsg, TCL_STATIC );
1640 				return TCL_ERROR;
1641 			}
1642 
1643 			if ( Tcl_GetIntFromObj ( NULL, tp, idx + k ) != TCL_OK )
1644 			{
1645 				char *txt = Tcl_GetString ( tp );
1646 
1647 				if ( strncmp ( txt, "end", 3 ) == 0 )
1648 				{
1649 					if ( gnoclPosOffset ( interp, txt + 3, idx + k ) != TCL_OK )
1650 						return TCL_ERROR;
1651 
1652 					if ( idx[k] > 0 )
1653 					{
1654 						Tcl_SetResult ( interp, errEndOffset, TCL_STATIC );
1655 						return TCL_ERROR;
1656 					}
1657 
1658 					isEnd[k] = 1;
1659 				}
1660 
1661 				else
1662 				{
1663 					Tcl_AppendResult ( interp, "unknown row or column index \"", txt, "\" must be integer or end plus offset" );
1664 					return TCL_ERROR;
1665 				}
1666 
1667 			}
1668 		}
1669 
1670 		gtk_text_buffer_get_start_iter ( buffer, iter );
1671 
1672 		if ( isEnd[0] )
1673 		{
1674 			gtk_text_iter_set_line ( iter, -1 );
1675 			gtk_text_iter_backward_lines ( iter, -idx[0] );
1676 		}
1677 
1678 		else
1679 			gtk_text_iter_set_line ( iter, idx[0] );
1680 
1681 		if ( isEnd[0] )
1682 		{
1683 			gtk_text_iter_forward_to_line_end ( iter );
1684 			gtk_text_iter_backward_chars ( iter, -idx[1] );
1685 		}
1686 
1687 		else
1688 			gtk_text_iter_forward_chars ( iter, idx[1] );
1689 	}
1690 
1691 	else if ( Tcl_GetIntFromObj ( NULL, obj, &len ) == TCL_OK )
1692 	{
1693 		if ( len < 0 )
1694 		{
1695 			Tcl_SetResult ( interp, "character offset must be greater zero.", TCL_STATIC );
1696 			return TCL_ERROR;
1697 		}
1698 
1699 		gtk_text_buffer_get_iter_at_offset ( buffer, iter, len );
1700 	}
1701 
1702 	else
1703 	{
1704 		const char *txt = Tcl_GetString ( obj );
1705 		const char *last;
1706 		int offset;
1707 
1708 		/*  get a fresh iterator, it may have already been altered due to a previous call */
1709 		gtk_text_buffer_get_iter_at_mark ( buffer, iter, gtk_text_buffer_get_insert ( buffer ) );
1710 
1711 
1712 		if ( strncmp ( txt, "start", 5 ) == 0 )
1713 		{
1714 #ifdef DEBUG_TEXT
1715 			g_print ( "checking start\n" );
1716 #endif
1717 			gtk_text_buffer_get_start_iter ( buffer, iter );
1718 			last = txt + 5;
1719 		}
1720 
1721 		else if ( strncmp ( txt, "end", 3 ) == 0 )
1722 		{
1723 #ifdef DEBUG_TEXT
1724 			g_print ( "checking end\n" );
1725 #endif
1726 			gtk_text_buffer_get_end_iter ( buffer, iter );
1727 			last = txt + 3;
1728 		}
1729 
1730 		else if ( strncmp ( txt, "cursor", 6 ) == 0 )
1731 		{
1732 #ifdef DEBUG_TEXT
1733 			g_print ( "checking cursor\n" );
1734 #endif
1735 			last = txt + 6;
1736 			gtk_text_buffer_get_iter_at_mark ( buffer, iter, gtk_text_buffer_get_insert ( buffer ) );
1737 		}
1738 
1739 		else if ( strncmp ( txt, "selectionStart", 14 ) == 0 )
1740 		{
1741 #ifdef DEBUG_TEXT
1742 			g_print ( "checking selectionStart\n" );
1743 #endif
1744 			GtkTextIter end;
1745 			gtk_text_buffer_get_selection_bounds ( buffer, iter, &end );
1746 			last = txt + 14;
1747 		}
1748 
1749 		else if ( strncmp ( txt, "selectionEnd", 12 ) == 0 )
1750 		{
1751 #ifdef DEBUG_TEXT
1752 			g_print ( "checking selectionEnd\n" );
1753 #endif
1754 			GtkTextIter start;
1755 			gtk_text_buffer_get_selection_bounds ( buffer, &start, iter );
1756 			last = txt + 12;
1757 		}
1758 
1759 		else if ( strncmp ( txt, "wordStart", 9 ) == 0 )
1760 		{
1761 #ifdef DEBUG_TEXT
1762 			g_print ( "checking wordStart\n" );
1763 #endif
1764 			/*  get a fresh iterator, it may have already been altered */
1765 			//gtk_text_buffer_get_iter_at_mark( buffer, iter, gtk_text_buffer_get_insert( buffer ) );
1766 			gtk_text_iter_backward_word_start ( iter );
1767 			last = txt + 9;
1768 		}
1769 
1770 		else if ( strncmp ( txt, "wordEnd", 7 ) == 0 )
1771 		{
1772 #ifdef DEBUG_TEXT
1773 			g_print ( "checking wordEnd\n" );
1774 #endif
1775 			/*  get a fresh iterator, it may have already been altered */
1776 			//gtk_text_buffer_get_iter_at_mark( buffer, iter, gtk_text_buffer_get_insert( buffer ) );
1777 			gtk_text_iter_forward_word_end ( iter );
1778 			last = txt + 7;
1779 		}
1780 
1781 		/*  WJG CURRENTLY WORKING HERE. Nothing happening, also text insert now kaput! */
1782 
1783 		else if ( strncmp ( txt, "sentenceStart", 13 ) == 0 )
1784 		{
1785 #ifdef DEBUG_TEXT
1786 			printf ( "checking sentenceStart\n" );
1787 #endif
1788 			/*  get a fresh iterator, it may have already been altered */
1789 			//gtk_text_buffer_get_iter_at_mark( buffer, iter, gtk_text_buffer_get_insert( buffer ) );
1790 			gtk_text_iter_backward_sentence_start ( iter );
1791 			last = txt + 13;
1792 		}
1793 
1794 		else if ( strncmp ( txt, "sentenceEnd", 11 ) == 0 )
1795 		{
1796 #ifdef DEBUG_TEXT
1797 			printf ( "checking sentenceEnd\n" );
1798 #endif
1799 			/*  get a fresh iterator, it may have already been altered */
1800 			//gtk_text_buffer_get_iter_at_mark( buffer, iter, gtk_text_buffer_get_insert( buffer ) );
1801 			gtk_text_iter_forward_sentence_end ( iter );
1802 			last = txt + 11;
1803 		}
1804 
1805 		else if ( strncmp ( txt, "lineStart", 9 ) == 0 )
1806 		{
1807 #ifdef DEBUG_TEXT
1808 			printf ( "checking lineStart\n" );
1809 #endif
1810 			/*  move iterator to an offset of 0 */
1811 			/*  get a fresh iterator, it may have already been altered */
1812 			//gtk_text_buffer_get_iter_at_mark( buffer, iter, gtk_text_buffer_get_insert( buffer ) );
1813 			gtk_text_iter_backward_visible_line ( iter );
1814 			last = txt + 9;
1815 		}
1816 
1817 		else if ( strncmp ( txt, "lineEnd", 7 ) == 0 )
1818 		{
1819 #ifdef DEBUG_TEXT
1820 			g_print ( "checking lineEnd\n" );
1821 #endif
1822 			/*  move iterator to the start of the next line, then move back one offset */
1823 			/*  get a fresh iterator, it may have already been altered */
1824 			//gtk_text_buffer_get_iter_at_mark( buffer, iter, gtk_text_buffer_get_insert( buffer ) );
1825 			gtk_text_iter_forward_visible_line ( iter );
1826 			last = txt + 7;
1827 		}
1828 
1829 		else
1830 		{
1831 			Tcl_AppendResult ( interp, "unknown index \"", txt,
1832 							   "\", must be a list of row and column, "
1833 							   "an integer as character offset, "
1834 							   "or one of start, end, cursor, wordStart, wordEnd, sentenceStart, sentenceEnd, lineStart, lineEnd, selectionStart, or selectionEnd",
1835 							   NULL );
1836 			return TCL_ERROR;
1837 		}
1838 
1839 		if ( gnoclPosOffset ( interp, last, &offset ) != TCL_OK )
1840 			return TCL_ERROR;
1841 
1842 		if ( offset > 0 )
1843 			gtk_text_iter_forward_chars ( iter, offset );
1844 		else if ( offset < 0 )
1845 			gtk_text_iter_backward_chars ( iter, -offset );
1846 	}
1847 
1848 	return TCL_OK;
1849 }
1850 
1851 /**
1852 \brief      Apply a lists of tags to the a specified range of text.
1853 **/
applyTag(GtkTextBuffer * buffer,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[],int cmdNo)1854 static int applyTag ( GtkTextBuffer * buffer, Tcl_Interp * interp, int objc, Tcl_Obj *  const objv[], int cmdNo )
1855 {
1856 	/**
1857 	Or, does it appear here?
1858 	*/
1859 	/*  declare some variables */
1860 	// console error messaging
1861 	GnoclOption insertOptions[] =
1862 	{
1863 		{ "-tags", GNOCL_LIST, NULL },
1864 		{ NULL }
1865 	};
1866 	const int tagsIdx = 0;
1867 	gint      startOffset;
1868 	gint   endOffset;
1869 	int       ret = TCL_ERROR;
1870 
1871 	GtkTextIter   iter;
1872 	GtkTextIter   iter2;
1873 
1874 	/*  The arguments passed in the tcl script are in the objv array. These are:
1875 	0:  {0 0}       fromIndex
1876 	+1:     {0 end}   toIndex
1877 	+2:       -tags
1878 	+3:     bold cursor     taglist
1879 	*/
1880 
1881 	/*
1882 	printf ( "-2: {%s} \n-1: {%s} \n0: {%s} \n+1: {%s} \n+2: %s \n+3: %s \n",
1883 	 gnoclGetString ( objv[cmdNo-2] ),
1884 	 gnoclGetString ( objv[cmdNo-1] ),
1885 	 gnoclGetString ( objv[cmdNo] ),
1886 	 gnoclGetString ( objv[cmdNo+1] ),
1887 	 gnoclGetString ( objv[cmdNo+2] ),
1888 	 gnoclGetString ( objv[cmdNo+3] ) );
1889 	*/
1890 
1891 	// "position text ?-option val ...?"
1892 
1893 	if ( objc < cmdNo + 2 )
1894 	{
1895 		Tcl_WrongNumArgs ( interp, cmdNo, objv, "fromIndex toIndex -tags {tag1 tag2...}S" );
1896 		return TCL_ERROR;
1897 	}
1898 
1899 	/*  determine some value */
1900 	// get position of fromIndex within the buffer as in iterator
1901 
1902 	if ( posToIter ( interp, objv[cmdNo], buffer, &iter ) != TCL_OK )
1903 	{
1904 		return TCL_ERROR;
1905 	}
1906 
1907 	// get position of toIndex within the buffer as in iterator
1908 
1909 	if ( posToIter ( interp, objv[cmdNo+1], buffer, &iter2 ) != TCL_OK )
1910 	{
1911 		return TCL_ERROR;
1912 	}
1913 
1914 	/*  parse options, check to see if they are suitable */
1915 
1916 	if ( gnoclParseOptions ( interp, objc - cmdNo - 1, objv + cmdNo + 1, insertOptions ) != TCL_OK )
1917 	{
1918 		goto clearExit;
1919 	}
1920 
1921 	startOffset = gtk_text_iter_get_offset ( &iter );
1922 
1923 	endOffset = gtk_text_iter_get_offset ( &iter2 );
1924 
1925 	/*  add the tags, gets a list and then works through them */
1926 
1927 	if ( insertOptions[tagsIdx].status == GNOCL_STATUS_CHANGED )
1928 	{
1929 		GtkTextIter start;
1930 		GtkTextIter end;
1931 		int k, no;
1932 		Tcl_Obj *obj = insertOptions[tagsIdx].val.obj;
1933 
1934 		/*  get the offset position for the inserted text*/
1935 		gtk_text_buffer_get_iter_at_offset ( buffer, &start, startOffset );
1936 		gtk_text_buffer_get_iter_at_offset ( buffer, &end, endOffset );
1937 
1938 		if ( Tcl_ListObjLength ( interp, obj, &no ) != TCL_OK )
1939 		{
1940 			goto clearExit;
1941 		}
1942 
1943 		/*  apply each tag in turn */
1944 
1945 		for ( k = 0; k < no; ++k )
1946 		{
1947 			Tcl_Obj *tp;
1948 
1949 			if ( Tcl_ListObjIndex ( interp, obj, k, &tp ) != TCL_OK )
1950 			{
1951 				Tcl_SetResult ( interp, "Could not read tag list", TCL_STATIC );
1952 				goto clearExit;
1953 			}
1954 
1955 			gtk_text_buffer_apply_tag_by_name ( buffer, Tcl_GetString ( tp ), &start, &end );
1956 
1957 		}
1958 	}
1959 
1960 	ret = TCL_OK;
1961 
1962 clearExit:
1963 	gnoclClearOptions ( insertOptions );
1964 
1965 	return ret;
1966 }
1967 
1968 /**
1969 \brief	Remove specific tag from a tag tagtable
1970 **/
deleteTag(GtkTextTag * tag,gpointer data)1971 static void deleteTag  ( GtkTextTag * tag, gpointer data )
1972 {
1973 	gtk_text_tag_table_remove ( data, tag );
1974 }
1975 
1976 
1977 /**
1978 \brief
1979 \note
1980 **/
removeTag(GtkTextBuffer * buffer,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[],int cmdNo)1981 static int removeTag ( GtkTextBuffer * buffer, Tcl_Interp * interp, int objc, Tcl_Obj *  const objv[], int cmdNo )
1982 {
1983 	/*  declare some variables */
1984 	// console error messaging
1985 	GnoclOption insertOptions[] =
1986 	{
1987 		{ "-tags", GNOCL_LIST, NULL },
1988 		{ NULL }
1989 	};
1990 	const int tagsIdx = 0;
1991 	gint startOffset;
1992 	gint endOffset;
1993 	int ret = TCL_ERROR;
1994 
1995 	GtkTextIter   iter;
1996 	GtkTextIter   iter2;
1997 
1998 	/*  The arguments passed in the tcl script are in the objv array. These are:
1999 	0:  {0 0}       fromIndex
2000 	+1:     {0 end}   toIndex
2001 	+2:       -tags
2002 	+3:     bold cursor     taglist
2003 	*/
2004 	/*
2005 	printf ( "-2: {%s} \n-1: {%s} \n0: {%s} \n+1: {%s} \n+2: %s \n+3: %s \n",
2006 	 gnoclGetString ( objv[cmdNo-2] ),
2007 	 gnoclGetString ( objv[cmdNo-1] ),
2008 	 gnoclGetString ( objv[cmdNo] ),
2009 	 gnoclGetString ( objv[cmdNo+1] ),
2010 	 gnoclGetString ( objv[cmdNo+2] ),
2011 	 gnoclGetString ( objv[cmdNo+3] ) );
2012 	*/
2013 	// "position text ?-option val ...?"
2014 
2015 	if ( objc < cmdNo + 2 )
2016 	{
2017 		Tcl_WrongNumArgs ( interp, cmdNo, objv, "fromIndex toIndex -tags {tag1 tag2...}S" );
2018 		return TCL_ERROR;
2019 	}
2020 
2021 	/*  determine some value */
2022 	// get position of fromIndex within the buffer as in iterator
2023 
2024 	if ( posToIter ( interp, objv[cmdNo], buffer, &iter ) != TCL_OK ) return TCL_ERROR;
2025 
2026 	// get position of toIndex within the buffer as in iterator
2027 	if ( posToIter ( interp, objv[cmdNo+1], buffer, &iter2 ) != TCL_OK ) return TCL_ERROR;
2028 
2029 	/*  parse options, check to see if they are suitable */
2030 	if ( gnoclParseOptions ( interp, objc - cmdNo - 1, objv + cmdNo + 1, insertOptions ) != TCL_OK ) goto clearExit;
2031 
2032 	startOffset = gtk_text_iter_get_offset ( &iter );
2033 
2034 	endOffset = gtk_text_iter_get_offset ( &iter2 );
2035 
2036 
2037 	/* check for keyword all */
2038 
2039 
2040 	/*  add the tags, gets a list and then works through them */
2041 	if ( insertOptions[tagsIdx].status == GNOCL_STATUS_CHANGED )
2042 	{
2043 		GtkTextIter start;
2044 		GtkTextIter end;
2045 		int k, no;
2046 		Tcl_Obj *obj = insertOptions[tagsIdx].val.obj;
2047 
2048 		/*  get the offset position for the inserted text*/
2049 		gtk_text_buffer_get_iter_at_offset ( buffer, &start, startOffset );
2050 		gtk_text_buffer_get_iter_at_offset ( buffer, &end, endOffset );
2051 
2052 		if ( Tcl_ListObjLength ( interp, obj, &no ) != TCL_OK ) goto clearExit;
2053 
2054 		/*  apply each tag in turn */
2055 		for ( k = 0; k < no; ++k )
2056 		{
2057 			Tcl_Obj *tp;
2058 
2059 			if ( Tcl_ListObjIndex ( interp, obj, k, &tp ) != TCL_OK )
2060 			{
2061 				Tcl_SetResult ( interp, "Could not read tag list", TCL_STATIC );
2062 				goto clearExit;
2063 			}
2064 
2065 			gtk_text_buffer_remove_tag_by_name ( buffer, Tcl_GetString ( tp ), &start, &end );
2066 
2067 		}
2068 	}
2069 
2070 	ret = TCL_OK;
2071 
2072 clearExit:
2073 	gnoclClearOptions ( insertOptions );
2074 
2075 	return ret;
2076 }
2077 
2078 /**
2079 \brief      To implement working bindings to GtkTextMark functions.
2080 \author     William J Giddings
2081 \date       31/Jun/2008
2082 \note
2083 **/
markCmd(GtkTextBuffer * buffer,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[],int cmdNo)2084 static int markCmd ( GtkTextBuffer * buffer, Tcl_Interp * interp, int objc, Tcl_Obj *  const objv[], int cmdNo )
2085 {
2086 	const char  *cmds[] = { "create", "configure", "delete", "move", "names", "cget", "getIndex", NULL };
2087 	enum   cmdIdx { CreateIdx, ConfigureIdx, DeleteIdx, MoveIdx, NamesIdx, CgetIdx, GetIndexIdx };
2088 	int     idx, row, col;
2089 	GtkTextIter iter;
2090 	GtkTextMark *mark;
2091 	Tcl_Obj  *resList;
2092 
2093 	GnoclOption markOptions[] =
2094 	{
2095 		{ "-visible", GNOCL_BOOL, "invisible" },
2096 		{ "-gravity", GNOCL_BOOL, "left-gravity" },
2097 		{ NULL }
2098 	};
2099 
2100 	/*  check the script for errors */
2101 
2102 	if ( objc < cmdNo + 1 )
2103 	{
2104 		Tcl_WrongNumArgs ( interp, cmdNo, objv, "subcommand ?option val ...?" );
2105 		return TCL_ERROR;
2106 	}
2107 
2108 	if ( Tcl_GetIndexFromObj ( interp, objv[cmdNo], cmds, "subcommand", TCL_EXACT, &idx ) != TCL_OK )
2109 	{
2110 		return TCL_ERROR;
2111 	}
2112 
2113 
2114 	switch ( idx )
2115 	{
2116 		case CreateIdx:
2117 			{
2118 				char *str;
2119 				Tcl_Obj       *resList;
2120 #ifdef DEBUG_TEXT
2121 				printf ( "markCmd 1>  create %sIdx mark: %s position: { %s } \n",
2122 						 Tcl_GetString ( objv[cmdNo+0] ) ,
2123 						 Tcl_GetString ( objv[cmdNo+1] ) ,
2124 						 Tcl_GetString ( objv[cmdNo+2] ) );
2125 #endif
2126 
2127 				if ( objc < cmdNo + 2 )
2128 				{
2129 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "mark-name ?option val ...?" );
2130 					return TCL_ERROR;
2131 				}
2132 
2133 				/*  convert position to inter */
2134 
2135 				if ( posToIter ( interp, objv[cmdNo+2], buffer, &iter ) != TCL_OK )
2136 				{
2137 					/*  defaul to cursor position */
2138 					return TCL_ERROR;
2139 				}
2140 
2141 				gtk_text_buffer_create_mark ( buffer, Tcl_GetString ( objv[cmdNo+1] ), &iter, 0 );
2142 
2143 				/*  return the name of the mark created */
2144 				resList = Tcl_NewListObj ( 0, NULL );
2145 				str = Tcl_GetString ( objv[cmdNo+1] );
2146 				Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( str, -1 ) );
2147 				Tcl_SetObjResult ( interp, resList );
2148 
2149 				return TCL_OK ;
2150 
2151 			}
2152 
2153 		case ConfigureIdx:
2154 			{
2155 
2156 				if ( objc < cmdNo + 2 )
2157 				{
2158 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "mark-name ?option val ...?" );
2159 					return TCL_ERROR;
2160 				}
2161 
2162 #ifdef DEBUG_TEXT
2163 				printf ( "markCmd ConfigureIdx> %s %s %s %s} \n",
2164 						 Tcl_GetString ( objv[cmdNo+0] ) ,
2165 						 Tcl_GetString ( objv[cmdNo+1] ) ,
2166 						 Tcl_GetString ( objv[cmdNo+2] ) ,
2167 						 Tcl_GetString ( objv[cmdNo+3] ) );
2168 #endif
2169 
2170 				mark = gtk_text_buffer_get_mark ( buffer, Tcl_GetString ( objv[cmdNo+1] ) );
2171 
2172 				/*  check the options flag */
2173 
2174 				if  ( strcmp ( Tcl_GetString ( objv[cmdNo+2] ), "-visible" ) )
2175 				{
2176 #ifdef DEBUG_TEXT
2177 					printf ( "markCmd 3>\n" );
2178 #endif
2179 					/*  apply the setting */
2180 
2181 					if ( Tcl_GetString ( objv[cmdNo+3] ) )
2182 					{
2183 						gtk_text_mark_set_visible ( mark, 1 );
2184 					}
2185 
2186 					else
2187 					{
2188 						gtk_text_mark_set_visible ( mark, 0 );
2189 					}
2190 
2191 				}
2192 
2193 				else if  ( strcmp ( Tcl_GetString ( objv[cmdNo+2] ), "-gravity" ) )
2194 				{
2195 					/*  NOTE:
2196 					 *  There is no Gtk lib function to reset the gravity of a marker.
2197 					 *  To achieve this, the marker first needs to be deleted and then
2198 					 *  a new recreated with the same name and a complementary left-gravity
2199 					 *  setting. Right-gravity is necessary for right-to-left written scripts
2200 					 *  such as Hebrew and Arabic.
2201 					 */
2202 #ifdef DEBUG_TEXT
2203 					printf ( "markCmd 4>\n" );
2204 #endif
2205 					/*  apply the setting */
2206 
2207 					if ( strcmp ( Tcl_GetString ( objv[cmdNo+3] ), "left" ) )
2208 					{
2209 						gtk_text_mark_set_visible ( mark, 1 );
2210 					}
2211 
2212 					else
2213 						/*  reverts to default, ie left-gravity 0 */
2214 					{
2215 						gtk_text_mark_set_visible ( mark, 1 );
2216 					}
2217 
2218 				}
2219 
2220 				return TCL_OK;
2221 
2222 			}
2223 
2224 		case DeleteIdx:
2225 			{
2226 				gtk_text_buffer_delete_mark_by_name ( buffer, Tcl_GetString ( objv[cmdNo+1] ) );
2227 				return TCL_OK;
2228 			}
2229 
2230 		case MoveIdx:
2231 			{
2232 
2233 				/*  convert the new position to a GtkTextIter */
2234 				posToIter ( interp, objv[cmdNo+2] , buffer, &iter );
2235 
2236 				/*  move names mark to a new location within the buffer */
2237 				gtk_text_buffer_move_mark_by_name ( buffer, Tcl_GetString ( objv[cmdNo+1] ), &iter );
2238 
2239 				return TCL_OK;
2240 
2241 			}
2242 
2243 		case NamesIdx:
2244 			{
2245 				// return a list of all the marks associated with the textBuffer, such a query is not supported within Gtk
2246 			}
2247 
2248 		case CgetIdx:	// markCmd
2249 			{
2250 				/*  if cget implmented, then to get the position of a mark
2251 				*
2252 				*  void gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer, GtkTextIter *iter, GtkTextMark *mark);
2253 				*  gboolean gtk_text_mark_get_visible (GtkTextMark *mark);
2254 				*  gboolean gtk_text_mark_get_left_gravity (GtkTextMark *mark);
2255 				*/
2256 
2257 			}
2258 
2259 		case GetIndexIdx:
2260 			{
2261 #ifdef DEBUG_TEXT
2262 				printf ( "GetIndex\n" );
2263 #endif
2264 				/*  return the index of the named marker */
2265 				mark = gtk_text_buffer_get_mark ( buffer, Tcl_GetString ( objv[cmdNo+1] ) );
2266 				gtk_text_buffer_get_iter_at_mark ( buffer, &iter, mark );
2267 
2268 				/*  the following block is hacked from GetCursorIdx */
2269 				row = gtk_text_iter_get_line ( &iter );
2270 				col = gtk_text_iter_get_line_offset ( &iter );
2271 
2272 				resList = Tcl_NewListObj ( 0, NULL );
2273 				Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( row ) );
2274 				Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( col ) );
2275 				Tcl_SetObjResult ( interp, resList );
2276 
2277 			}
2278 
2279 		default:
2280 			{
2281 				//assert ( 0 );
2282 				//return TCL_ERROR;
2283 			}
2284 	}
2285 
2286 	return TCL_OK;
2287 
2288 }
2289 
2290 /**
2291 \brief
2292 
2293     pathName tag add tagName index1 ?index2 index1 index2 ...?
2294     pathName tag bind tagName ?sequence? ?script?
2295     pathName tag cget tagName option
2296     pathName tag configure tagName ?option? ?value? ?option value ...?
2297     pathName tag delete tagName ?tagName ...?
2298     pathName tag lower tagName ?belowThis?
2299     pathName tag names ?index?
2300     pathName tag nextrange tagName index1 ?index2?
2301     pathName tag prevrange tagName index1 ?index2?
2302     pathName tag properties tagName
2303     pathName tag raise tagName ?aboveThis?
2304     pathName tag ranges tagName
2305     pathName tag remove tagName index1 ?index2 index1 index2 ...?
2306 
2307 \todo
2308 	some Tk-compatible command synonyms
2309 		add + apply?
2310 	allow list arguments for add, remove and delete
2311 
2312 **/
tagCmd(GtkTextBuffer * buffer,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[],int cmdNo)2313 int tagCmd ( GtkTextBuffer * buffer, Tcl_Interp * interp, int objc, Tcl_Obj *  const objv[], int cmdNo )
2314 {
2315 #ifdef DEBUG_TAGS
2316 	g_print ( "%s\n", __FUNCTION__ );
2317 #endif
2318 
2319 	// widgetname tag add tagname start_index end_index
2320 	// widgetname tag remove tagname start_index end_index
2321 
2322 	// const char *cmds[] = { "create", "configure", "add", "delete", "remove", NULL };
2323 	// enum cmdIdx { CreateIdx, ConfigureIdx, AddIdx, DeleteIdx};
2324 	const char *cmds[] =
2325 	{
2326 		"cget", "create", "configure", "apply",
2327 		"delete", "remove", "get", "clear", "set",
2328 		"ranges", "names", "raise", "lower",
2329 		"copy", "properties",
2330 		NULL
2331 	};
2332 	enum cmdIdx
2333 	{
2334 		CgetIdx, CreateIdx, ConfigureIdx, ApplyIdx,
2335 		DeleteIdx, RemoveIdx, GetIdx, ClearIdx, SetIdx,
2336 		RangesIdx, NamesIdx, RaiseIdx, LowerIdx,
2337 		CopyIdx, PropertiesIdx,
2338 	};
2339 
2340 	/*  see also list.c */
2341 
2342 	GnoclOption tagOptions[] =
2343 	{
2344 
2345 		/* new options added 30/04/11, may need some revision */
2346 
2347 		{"-marginAccumulate", GNOCL_BOOL, "accumulative-margin"},
2348 		{"-backgroundFullHeight", GNOCL_BOOL, "background-full-height"},
2349 		{"-backgroundStipple", GNOCL_OBJ, gnoclOptTagBackgroundStipple},
2350 		{"-direction", GNOCL_OBJ, "direction", gnoclOptTagTextDirection},
2351 		{"-foregroundStipple", GNOCL_OBJ, "foreground-stipple", gnoclOptTextTagForegroundStipple},
2352 		{"-indent", GNOCL_INT, "indent"},
2353 		{"-language", GNOCL_OBJ, "language", gnocOptTextTagLanguage},
2354 		{"-leftMargin", GNOCL_INT, "left-margin"},
2355 		{"-name", GNOCL_STRING, "name"},
2356 		{"-pixelsInsideWrap", GNOCL_INT, "pixels-inside-wrap"},
2357 		{"-priority", GNOCL_OBJ, "", gnoclOptTextTagPriority},
2358 		{"-rightMargin", GNOCL_INT, "right-margin"},
2359 		{"-rise", GNOCL_INT, "rise"},
2360 		{"-scale", GNOCL_DOUBLE, "scale"},
2361 		{"-tabs", GNOCL_OBJ, "tabs", gnoclOptTextTagTabs},
2362 		{"-variant", GNOCL_OBJ, "variant", gnoclOptTextTagVariant},
2363 		{"-weight", GNOCL_INT, "weight"},
2364 
2365 		/*--------------- existing options ---------------*/
2366 
2367 		{ "-background", GNOCL_OBJ, "background-gdk", gnoclOptGdkColor },
2368 		{ "-editable", GNOCL_BOOL, "editable" },
2369 		{ "-foreground", GNOCL_OBJ, "foreground-gdk", gnoclOptGdkColor },
2370 		{ "-font", GNOCL_STRING, "font" },
2371 		{ "-fontFamily", GNOCL_STRING, "family" },
2372 		{ "-fontStyle", GNOCL_OBJ, "style", gnoclOptPangoStyle },
2373 		{ "-fontVariant", GNOCL_OBJ, "variant", gnoclOptPangoVariant },
2374 		{ "-fontWeight", GNOCL_OBJ, "weight", gnoclOptPangoWeight },
2375 		{ "-fontRise", GNOCL_OBJ, "rise", gnoclOptPangoScaledInt },
2376 		{ "-fontStretch", GNOCL_OBJ, "stretch", gnoclOptPangoStretch },
2377 		{ "-fontSize", GNOCL_OBJ, "size", gnoclOptPangoScaledInt },
2378 		//{ "-fontScale", GNOCL_OBJ, "scale", gnoclOptScale },
2379 		{ "-invisible", GNOCL_BOOL, "invisible" },
2380 		{ "-justification", GNOCL_OBJ, "justification", gnoclOptJustification },
2381 		{ "-paragraph", GNOCL_OBJ, "paragraph-background-gdk", gnoclOptGdkColor },
2382 		{ "-pixelsAboveLines", GNOCL_INT, "pixels-above-lines" },
2383 		{ "-pixelsBelowLines", GNOCL_INT, "pixels-below-lines" },
2384 		{ "-size", GNOCL_INT, "size" },
2385 		{ "-strikethrough", GNOCL_BOOL, "strikethrough" },
2386 		{ "-sizePoints", GNOCL_DOUBLE, "size-points" },
2387 		{ "-underline", GNOCL_OBJ, "underline", gnoclOptUnderline },
2388 		{ "-wrapMode", GNOCL_OBJ, "wrap-mode", gnoclOptWrapmode },
2389 
2390 		{ "-data", GNOCL_OBJ, "", gnoclOptData },
2391 
2392 		/* settings, what to do with these? */
2393 
2394 		/*
2395 				{"-backgroundFullHeightSet", GNOCL_BOOL, "background-full-height-set"},
2396 				{"-backgroundSet", GNOCL_BOOL, "background-set"},
2397 				{"-backgroundStippleSet", GNOCL_BOOL, "background-stipple-set"},
2398 				{"-editableSet", GNOCL_BOOL, "editable-set"},
2399 				{"-fontFamiltSet", GNOCL_BOOL, "family-set"},
2400 				{"-foregroundStippleSet", GNOCL_BOOL, "foreground-stipple-set"},
2401 				{"-indentSet", GNOCL_BOOL, "indent-set"},
2402 				{"-invisibleSet", GNOCL_BOOL, "invisible-set"},
2403 				{"-justificationSet", GNOCL_BOOL, "justification-set"},
2404 				{"-languageSet", GNOCL_BOOL, "language-set"},
2405 				{"-leftMarginSet", GNOCL_BOOL, "left-margin-set"},
2406 				{"-paragraphBackgroundSet", GNOCL_BOOL, "paragraph-background-set"},
2407 				{"-pixelsAboveLinesSet", GNOCL_BOOL, "pixels-above-lines-set"},
2408 				{"-pixelsBelowLinesSet", GNOCL_BOOL, "pixels-below-lines-set"},
2409 				{"-pixelsInsideWrapSet", GNOCL_BOOL, "pixels-inside-wrap-set"},
2410 				{"-rightMarginSet", GNOCL_BOOL, "right-margin-set"},
2411 				{"-riseSet", GNOCL_BOOL, "rise-set"},
2412 				{"-scaleSet", GNOCL_BOOL, "scale-set"},
2413 				{"-sizeSet", GNOCL_BOOL, "size-set"},
2414 				{"-tabsSet", GNOCL_BOOL, "tabs-set"},
2415 				{"-underlineSet", GNOCL_BOOL, "underline-set"},
2416 				{"-variantSet", GNOCL_BOOL, "variant-set"},
2417 				{"-weightSet", GNOCL_BOOL, "weight-set"},
2418 				{"-wrapModeSet", GNOCL_BOOL, "wrap-mode-set"},
2419 		*/
2420 
2421 		/*  GtkTextTag signal */
2422 		{ "-onEvent", GNOCL_OBJ, "", gnoclOptOnEvent },
2423 		{ NULL }
2424 	};
2425 
2426 	int idx;
2427 
2428 	if ( objc < cmdNo + 1 )
2429 	{
2430 		Tcl_WrongNumArgs ( interp, cmdNo, objv, "subcommand ?option val ...?" );
2431 		return TCL_ERROR;
2432 	}
2433 
2434 	if ( Tcl_GetIndexFromObj ( interp, objv[cmdNo], cmds, "subcommand", TCL_EXACT, &idx ) != TCL_OK )
2435 	{
2436 		return TCL_ERROR;
2437 	}
2438 
2439 	switch ( idx )
2440 	{
2441 
2442 		case NamesIdx:	// return a list of all tag names
2443 			{
2444 #ifdef DEBUG_TAGS
2445 				g_print ( "\ttag names\n" );
2446 #endif
2447 				GtkTextTagTable *tagtable = gtk_text_buffer_get_tag_table ( buffer );
2448 
2449 				gchar names[512];
2450 
2451 				Tcl_Obj *resList;
2452 				resList = Tcl_NewListObj ( 0, NULL );
2453 				/* create a tcl list */
2454 
2455 				/*  get the settings of each tag in the buffer*/
2456 				/*  note, pass the address of the pointer to the data assigned by the called function */
2457 				gtk_text_tag_table_foreach ( tagtable, getTagName , &resList );
2458 
2459 				Tcl_SetObjResult ( interp, resList );
2460 				/*  reset the outsput string by using null pointers */
2461 				//gnoclGetTagProperties ( NULL, NULL );
2462 
2463 #ifdef  DEBUG_TAGS
2464 				g_print ( "tag names\n" );
2465 #endif
2466 
2467 				return TCL_OK;
2468 			}
2469 			break;
2470 		case PropertiesIdx:
2471 			{
2472 #ifdef DEBUG_TAGS
2473 				g_print ( "\ttag properties %s\n", Tcl_GetString ( objv[3] ) );
2474 #endif
2475 
2476 				Tcl_Obj *resList;
2477 				resList = Tcl_NewListObj ( 0, NULL );
2478 
2479 				GtkTextTagTable *table = gtk_text_buffer_get_tag_table ( buffer );
2480 				GtkTextTag *tag = gtk_text_tag_table_lookup ( table, Tcl_GetString ( objv[3] ) );
2481 
2482 				gnoclGetTagProperties ( tag, resList );
2483 
2484 				Tcl_SetObjResult ( interp, resList );
2485 
2486 				return TCL_OK;
2487 
2488 			}
2489 			break;
2490 		case CopyIdx:
2491 			{
2492 #ifdef DEBUG_TAGS
2493 				g_print ( "\ttag copy\n" );
2494 #endif
2495 				listParameters ( objc, objv, __FUNCTION__ );
2496 
2497 				GtkScrolledWindow *scrolled = gnoclGetWidgetFromName ( Tcl_GetString ( objv[3] ), interp );
2498 				GtkTextView *text = GTK_TEXT_VIEW ( gtk_bin_get_child ( GTK_BIN ( scrolled ) ) );
2499 				GtkTextBuffer *buffer2 = gtk_text_view_get_buffer ( text );
2500 				GtkTextTagTable *table = gtk_text_buffer_get_tag_table ( buffer2 );
2501 
2502 				buffer->tag_table = table;
2503 
2504 				g_object_ref ( buffer->tag_table );
2505 
2506 				table->buffers = g_slist_prepend ( table->buffers, buffer );
2507 
2508 			}
2509 			break;
2510 		case RaiseIdx:
2511 			{
2512 #ifdef DEBUG_TAGS
2513 				g_print ( "\ttag raise\n" );
2514 #endif
2515 
2516 				GtkTextTagTable *table = gtk_text_buffer_get_tag_table ( buffer );
2517 
2518 				GtkTextTag *tag1;
2519 				GtkTextTag *tag2;
2520 
2521 				tag1 = gtk_text_tag_table_lookup ( table, Tcl_GetString ( objv[cmdNo+2] ) );
2522 				tag2 = gtk_text_tag_table_lookup ( table, Tcl_GetString ( objv[cmdNo+3] ) );
2523 
2524 				gint priority = gtk_text_tag_get_priority ( tag1 );
2525 				priority++;
2526 				gtk_text_tag_set_priority ( tag2, priority );
2527 
2528 			}
2529 			break;
2530 		case LowerIdx:
2531 			{
2532 #ifdef DEBUG_TEXT
2533 				g_print ( "tag lower\n" );
2534 #endif
2535 
2536 				GtkTextTagTable *table = gtk_text_buffer_get_tag_table ( buffer );
2537 
2538 				GtkTextTag *tag1;
2539 				GtkTextTag *tag2;
2540 
2541 				tag1 = gtk_text_tag_table_lookup ( table, Tcl_GetString ( objv[cmdNo+2] ) );
2542 				tag2 = gtk_text_tag_table_lookup ( table, Tcl_GetString ( objv[cmdNo+3] ) );
2543 
2544 				gint priority = gtk_text_tag_get_priority ( tag1 );
2545 
2546 				if ( priority >= 1 )
2547 				{
2548 					priority++;
2549 				}
2550 
2551 				gtk_text_tag_set_priority ( tag2, priority );
2552 			}
2553 
2554 		case RangesIdx:
2555 			{
2556 #ifdef DEBUG_TAGS
2557 				g_print ( "\ttag ranges\n" );
2558 #endif
2559 				gnoclGetTagRanges ( interp, buffer, Tcl_GetString ( objv[cmdNo+1] ) );
2560 			}
2561 			break;
2562 		case SetIdx:
2563 			{
2564 				/* control tag option application settings */
2565 			}
2566 			break;
2567 		case ClearIdx:
2568 			{
2569 				GtkTextTagTable *tagtable = gtk_text_buffer_get_tag_table ( buffer );
2570 
2571 				/*  get the settings of each tag in the buffer*/
2572 				/*  note, pass the address of the pointer to the data assigned by the called function */
2573 				gtk_text_tag_table_foreach ( tagtable, deleteTag , tagtable );
2574 
2575 			}
2576 			break;
2577 		case CgetIdx:	// tagCmd
2578 			{
2579 				//g_print ( "tag CgetIdx 1\n" );
2580 
2581 				int     idx;
2582 				Tcl_Obj *resList;
2583 
2584 				GtkTextTagTable *tagtable = gtk_text_buffer_get_tag_table ( buffer );
2585 				//g_print ( "tag CgetIdx 2\n" );
2586 				GtkTextTag *tag = gtk_text_tag_table_lookup ( tagtable, Tcl_GetString ( objv[cmdNo+1] ) );
2587 				//g_print ( "tag CgetIdx 3\n" );
2588 
2589 				switch ( gnoclTagCget ( interp, objc, objv, G_OBJECT ( tag ), tagOptions, &idx ) )
2590 				{
2591 					case GNOCL_CGET_ERROR:
2592 						{
2593 							return TCL_ERROR;
2594 						}
2595 					case GNOCL_CGET_HANDLED:
2596 						{
2597 							return TCL_OK;
2598 						}
2599 					case GNOCL_CGET_NOTHANDLED:
2600 						{
2601 							return gnoclCgetOne ( interp, objv, G_OBJECT ( tag ), tagOptions, &idx );
2602 						}
2603 				}
2604 
2605 				break;
2606 			}
2607 
2608 			/*  return a list of tags applied to current iter */
2609 		case GetIdx:
2610 			{
2611 				//int ret;
2612 				GSList *p, *tagList;
2613 				GtkTextIter iter;
2614 
2615 				Tcl_Obj *resList;
2616 
2617 				Tcl_Obj *err;
2618 				Tcl_Obj *ret;
2619 
2620 				ret = 0;
2621 
2622 				static char *tagOpt[] =
2623 				{
2624 					"-on", "-off", "-all", NULL
2625 				};
2626 
2627 				static enum  tagOptIdx
2628 				{
2629 					OnIdx, OffIdx, AllIdx
2630 				};
2631 
2632 				gint idx;
2633 
2634 				/*  check the number of arguments */
2635 				if ( objc < 4 || objc > 5 )
2636 				{
2637 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "position opts" );
2638 					return TCL_ERROR;
2639 				}
2640 
2641 				/*  convert the position to a pointer */
2642 				if ( posToIter ( interp, objv[3], buffer, &iter ) != TCL_OK )
2643 				{
2644 					return -1;
2645 				}
2646 
2647 
2648 				if ( objc == 5 )
2649 				{
2650 
2651 					getIdx ( tagOpt, Tcl_GetString ( objv[4] ), &idx );
2652 
2653 //g_print ("here I am... idx = %d\n", idx);
2654 
2655 					switch ( idx )
2656 					{
2657 						case OnIdx:
2658 							{
2659 								/* build a list of tagOn changes */
2660 								//g_print ("get onTags\n");
2661 								tagList = gtk_text_iter_get_toggled_tags ( &iter, TRUE );
2662 							}
2663 							break;
2664 						case OffIdx:
2665 							{
2666 								/* build a list of tagOff changes */
2667 								//g_print ("get offTags\n");
2668 								tagList = gtk_text_iter_get_toggled_tags ( &iter, FALSE );
2669 							}
2670 							break;
2671 						default:
2672 							{
2673 								//g_print ( "got everything!\n" );
2674 								tagList = gtk_text_iter_get_tags ( &iter );
2675 							}
2676 					}
2677 
2678 				}
2679 
2680 				else
2681 				{
2682 					/* get a list of all applicable tags */
2683 					tagList = gtk_text_iter_get_tags ( &iter );
2684 				}
2685 
2686 				/*  initialise list for return to the inpreter */
2687 				resList = Tcl_NewListObj ( 0, NULL );
2688 
2689 				/*  build up a list of names */
2690 				for ( p = tagList; p != NULL; p = p->next )
2691 				{
2692 					gchar *name = ( GTK_TEXT_TAG ( p->data )->name );
2693 
2694 					Tcl_ListObjAppendElement ( interp, resList, Tcl_NewStringObj ( name, -1 ) );
2695 				}
2696 
2697 				/*  tidy up and return the answer */
2698 				g_slist_free ( tagList );
2699 				Tcl_SetObjResult ( interp, resList );
2700 			}
2701 			break ;
2702 		case CreateIdx:
2703 			{
2704 				int ret;
2705 				GtkTextTag *tag;
2706 				/*  win tag create name */
2707 
2708 				if ( objc < cmdNo + 2 )
2709 				{
2710 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "tag-name ?option val ...?" );
2711 					return TCL_ERROR;
2712 				}
2713 
2714 				/*  tag = gtk_text_tag_new( Tcl_GetString( objv[3] ) ); */
2715 				tag = gtk_text_buffer_create_tag ( buffer, Tcl_GetString ( objv[cmdNo+1] ), NULL );
2716 
2717 				ret = gnoclParseAndSetOptions ( interp, objc - cmdNo - 1, objv + cmdNo + 1, tagOptions, G_OBJECT ( tag ) );
2718 
2719 				gnoclClearOptions ( tagOptions );
2720 
2721 				return ret;
2722 			}
2723 
2724 		case ConfigureIdx:
2725 			{
2726 				int        ret;
2727 				GtkTextTag *tag;
2728 
2729 				/*  win tag create name */
2730 
2731 				if ( objc < cmdNo + 2 )
2732 				{
2733 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "tag-name ?option val ...?" );
2734 					return TCL_ERROR;
2735 				}
2736 
2737 				/*  TODO? first reset options */
2738 				tag = gtk_text_tag_table_lookup ( gtk_text_buffer_get_tag_table ( buffer ), Tcl_GetString ( objv[cmdNo+1] ) );
2739 
2740 				if ( tag == NULL )
2741 				{
2742 					Tcl_AppendResult ( interp, "Unknown tag \"", Tcl_GetString ( objv[cmdNo+1] ), "\"", NULL );
2743 					return TCL_ERROR;
2744 				}
2745 
2746 				ret = gnoclParseAndSetOptions ( interp, objc - cmdNo - 1, objv + cmdNo + 1, tagOptions, G_OBJECT ( tag ) );
2747 
2748 				gnoclClearOptions ( tagOptions );
2749 
2750 				return ret;
2751 			}
2752 
2753 		case ApplyIdx:
2754 			{
2755 				if ( applyTag ( buffer, interp, objc, objv, cmdNo + 1 ) != TCL_OK ) return -1;
2756 
2757 				break;
2758 			}
2759 
2760 		case RemoveIdx:
2761 			{
2762 				if ( removeTag ( buffer, interp, objc, objv, cmdNo + 1 ) != TCL_OK ) return -1;
2763 
2764 				break;
2765 			}
2766 
2767 		case DeleteIdx:
2768 			{
2769 				/*! WJG Added 28/03/08 */
2770 				GtkTextTagTable *tagtable = gtk_text_buffer_get_tag_table ( buffer );
2771 				GtkTextTag *tag = gtk_text_tag_table_lookup ( tagtable, Tcl_GetString ( objv[cmdNo+1] ) );
2772 
2773 				if ( tag != NULL )
2774 				{
2775 
2776 					gtk_text_tag_table_remove ( tagtable, tag );
2777 				}
2778 
2779 				break;
2780 			}
2781 
2782 		default:
2783 			{
2784 				assert ( 0 );
2785 				return TCL_ERROR;
2786 			}
2787 	}
2788 
2789 	return TCL_OK;
2790 }
2791 
2792 /**
2793 **/
scrollToMark(GtkTextView * view,GtkTextBuffer * buffer,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])2794 static int scrollToMark (
2795 	GtkTextView * view,
2796 	GtkTextBuffer * buffer,
2797 	Tcl_Interp * interp,
2798 	int objc,
2799 	Tcl_Obj *  const objv[] )
2800 {
2801 #ifdef DEBUG_TEXT
2802 	printf ( "scrollToMark 1>  %s \n", Tcl_GetString ( objv[2] ) );
2803 #endif
2804 
2805 	GtkTextMark *mark;
2806 
2807 	if ( objc < 3 )
2808 	{
2809 		Tcl_WrongNumArgs ( interp, 2, objv, "index ?-option val ...?" );
2810 		return TCL_ERROR;
2811 	}
2812 
2813 	/*  check to see that the mark exists */
2814 	mark = gtk_text_buffer_get_mark ( buffer, Tcl_GetString ( objv[2] ) );
2815 
2816 	/*  reposition */
2817 	if ( mark == NULL )
2818 	{
2819 		Tcl_SetResult ( interp, "This mark does not exist.", TCL_STATIC );
2820 		return TCL_ERROR;
2821 	}
2822 
2823 	gtk_text_view_scroll_mark_onscreen  ( view, mark );
2824 
2825 	return TCL_OK;
2826 
2827 }
2828 
2829 /**
2830 \brief
2831 \author
2832 \date
2833 \note
2834 **/
scrollToPos(GtkTextView * view,GtkTextBuffer * buffer,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])2835 static int scrollToPos (
2836 	GtkTextView * view,
2837 	GtkTextBuffer * buffer,
2838 	Tcl_Interp * interp,
2839 	int objc,
2840 	Tcl_Obj *  const objv[] )
2841 {
2842 
2843 #ifdef DEBUG_TEXT
2844 	printf ( "scrollToPos 1>  %s \n",  Tcl_GetString ( objv[2] ) );
2845 #endif
2846 
2847 	GnoclOption options[] =
2848 
2849 	{
2850 		{ "-margin", GNOCL_DOUBLE, NULL },    /*  0 */
2851 		{ "-align", GNOCL_OBJ, NULL },        /*  1 */
2852 		{ NULL }
2853 	};
2854 	const int marginIdx = 0;
2855 	const int alignIdx  = 1;
2856 
2857 	int   ret = TCL_ERROR;
2858 
2859 	double      margin = .0;
2860 	int         useAlign = 0;
2861 	gfloat      xAlign = 0.5, yAlign = 0.5;
2862 	GtkTextIter iter;
2863 	GtkTextMark *mark;
2864 
2865 	if ( objc < 3 )
2866 	{
2867 		Tcl_WrongNumArgs ( interp, 2, objv, "index ?-option val ...?" );
2868 		return TCL_ERROR;
2869 	}
2870 
2871 	if ( posToIter ( interp, objv[2], buffer, &iter ) != TCL_OK )
2872 	{
2873 		return TCL_ERROR;
2874 	}
2875 
2876 	if ( gnoclParseOptions ( interp, objc - 2, objv + 2, options ) != TCL_OK )
2877 	{
2878 		goto clearExit;
2879 	}
2880 
2881 	if ( options[alignIdx].status == GNOCL_STATUS_CHANGED )
2882 	{
2883 		if ( gnoclGetBothAlign ( interp, options[alignIdx].val.obj, &xAlign, &yAlign ) != TCL_OK )
2884 		{
2885 			goto clearExit;
2886 		}
2887 
2888 		useAlign = 1;
2889 	}
2890 
2891 	if ( options[marginIdx].status == GNOCL_STATUS_CHANGED )
2892 	{
2893 		margin = options[marginIdx].val.d;
2894 
2895 		if ( margin < 0.0 || margin >= 0.5 )
2896 		{
2897 			Tcl_SetResult ( interp, "-margin must be between 0 and 0.5", TCL_STATIC );
2898 			goto clearExit;
2899 		}
2900 	}
2901 
2902 
2903 	mark = gtk_text_buffer_create_mark ( buffer, "__gnoclScrollMark__", &iter, 0 );
2904 
2905 
2906 	gtk_text_view_scroll_to_mark ( view, mark, margin, useAlign, xAlign, yAlign );
2907 
2908 	gtk_text_buffer_delete_mark ( buffer, mark );
2909 
2910 	ret = TCL_OK;
2911 
2912 clearExit:
2913 	gnoclClearOptions ( options );
2914 	return ret;
2915 }
2916 
2917 /**
2918 \brief      Insert formatted string into specified text widget at a given location.
2919 \author     PGB
2920 \date       2001-06:
2921 \bugs       Recent changes to posToIter causing this function to crash.
2922             But, applyTag, which is hack of this function does not cause a crash!
2923 \history    2008-06-27  Began implementation of new keywords for text position. See TODO.
2924 **/
textInsert(GtkTextBuffer * buffer,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[],int cmdNo)2925 static int textInsert ( GtkTextBuffer * buffer, Tcl_Interp * interp, int objc, Tcl_Obj *  const objv[], int cmdNo )
2926 {
2927 	GnoclOption insertOptions[] =
2928 	{
2929 		{ "-tags", GNOCL_LIST, NULL },
2930 		{ NULL }
2931 	};
2932 	const int tagsIdx = 0;
2933 	gint      startOffset;
2934 	int       ret = TCL_ERROR;
2935 
2936 	GtkTextIter   iter;
2937 
2938 	if ( objc < cmdNo + 2 )
2939 	{
2940 		Tcl_WrongNumArgs ( interp, cmdNo, objv, "position text ?-option val ...?" );
2941 		return TCL_ERROR;
2942 	}
2943 
2944 	if ( posToIter ( interp, objv[cmdNo], buffer, &iter ) != TCL_OK )
2945 	{
2946 		return TCL_ERROR;
2947 	}
2948 
2949 	if ( gnoclParseOptions ( interp, objc - cmdNo - 1, objv + cmdNo + 1, insertOptions ) != TCL_OK )
2950 	{
2951 		goto clearExit;
2952 	}
2953 
2954 	startOffset = gtk_text_iter_get_offset ( &iter );
2955 
2956 
2957 	/* handle pango strings first */
2958 	gint type = gnoclGetStringType ( objv[cmdNo+1] );
2959 
2960 	if ( type == 48 )
2961 	{
2962 
2963 		gnoclInsertMarkup ( buffer, &iter, gnoclGetString ( objv[cmdNo+1] ) );
2964 
2965 		//gtk_text_buffer_insert_markup ( buffer, &iter, gnoclGetString ( objv[cmdNo+1] ) );
2966 		//gnoclMarkupInsertTest ( buffer, &iter );
2967 
2968 	}
2969 
2970 	else
2971 	{
2972 		gtk_text_buffer_insert ( buffer, &iter, gnoclGetString ( objv[cmdNo+1] ), -1 );
2973 	}
2974 
2975 	if ( insertOptions[tagsIdx].status == GNOCL_STATUS_CHANGED )
2976 	{
2977 		GtkTextIter start;
2978 		int k, no;
2979 		Tcl_Obj *obj = insertOptions[tagsIdx].val.obj;
2980 
2981 		gtk_text_buffer_get_iter_at_offset ( buffer, &start, startOffset );
2982 
2983 		if ( Tcl_ListObjLength ( interp, obj, &no ) != TCL_OK )
2984 		{
2985 			goto clearExit;
2986 		}
2987 
2988 		for ( k = 0; k < no; ++k )
2989 		{
2990 			Tcl_Obj *tp;
2991 
2992 			if ( Tcl_ListObjIndex ( interp, obj, k, &tp ) != TCL_OK )
2993 			{
2994 				Tcl_SetResult ( interp, "Could not read tag list", TCL_STATIC );
2995 				goto clearExit;
2996 			}
2997 
2998 			gtk_text_buffer_apply_tag_by_name ( buffer, Tcl_GetString ( tp ), &start, &iter );
2999 		}
3000 	}
3001 
3002 	ret = TCL_OK;
3003 
3004 clearExit:
3005 	gnoclClearOptions ( insertOptions );
3006 
3007 	return ret;
3008 }
3009 
3010 /**
3011 \brief	** USING ** TEXTPARAMS
3012 **/
configure(Tcl_Interp * interp,TextParams * para,GnoclOption options[])3013 static int configure ( Tcl_Interp *interp, TextParams *para, GnoclOption options[] )
3014 {
3015 
3016 	GtkScrolledWindow *scrolled = para->scrolled;
3017 	GtkTextView *text = GTK_TEXT_VIEW ( gtk_bin_get_child ( GTK_BIN ( scrolled ) ) );
3018 	GtkTextBuffer *buffer = gtk_text_view_get_buffer ( text );
3019 
3020 
3021 	/****************************/
3022 
3023 	gnoclAttachOptCmdAndVar (
3024 		&options[onChangedIdx], &para->onChanged,
3025 		&options[variableIdx], &para->textVariable,
3026 		"changed", G_OBJECT ( buffer ),
3027 		G_CALLBACK ( changedFunc ), interp, traceFunc, para );
3028 
3029 	if ( options[variableIdx].status == GNOCL_STATUS_CHANGED && para->textVariable != NULL )
3030 	{
3031 		// if variable does not exist -> set it, else set widget state
3032 		const char *val = Tcl_GetVar ( interp, para->textVariable, TCL_GLOBAL_ONLY );
3033 
3034 		if ( val == NULL )
3035 		{
3036 
3037 			GtkTextIter *start, *end;
3038 
3039 			gtk_text_buffer_get_bounds ( buffer, start, end );
3040 
3041 			val = gtk_text_buffer_get_text ( buffer, start, end, 0 );
3042 
3043 			setTextVariable ( para, val );
3044 		}
3045 
3046 		else
3047 		{
3048 			//setVal ( para->label, val );
3049 		}
3050 	}
3051 
3052 	/*****************************/
3053 
3054 
3055 	if ( options[textIdx].status == GNOCL_STATUS_CHANGED )
3056 	{
3057 		//printf ( "INSERT SOME TEXT-b\n" );
3058 
3059 		char *str = options[textIdx].val.str;
3060 		gtk_text_buffer_set_text ( buffer, str, -1 );
3061 	}
3062 
3063 	if ( options[scrollBarIdx].status == GNOCL_STATUS_CHANGED )
3064 	{
3065 		GtkPolicyType hor, vert;
3066 
3067 		if ( gnoclGetScrollbarPolicy ( interp, options[scrollBarIdx].val.obj, &hor, &vert ) != TCL_OK )
3068 		{
3069 			return TCL_ERROR;
3070 		}
3071 
3072 		gtk_scrolled_window_set_policy ( scrolled, hor, vert );
3073 	}
3074 
3075 	if ( options[bufferIdx].status == GNOCL_STATUS_CHANGED )
3076 	{
3077 		printf ( "APPLY NEW BUFFER-%s\n", options[bufferIdx].val.str );
3078 
3079 		GtkTextBuffer *buffer;
3080 
3081 		buffer = gnoclGetWidgetFromName ( options[bufferIdx].val.str, interp );
3082 
3083 		gtk_text_view_set_buffer ( text, buffer );
3084 
3085 	}
3086 
3087 
3088 	return TCL_OK;
3089 }
3090 
3091 
3092 /**
3093 \brief	** USING ** TEXTPARAMS
3094 **/
configure_textView(Tcl_Interp * interp,GtkTextView * text,GnoclOption options[])3095 static int configure_textView ( Tcl_Interp *interp, GtkTextView *text, GnoclOption options[] )
3096 {
3097 
3098 	//GtkScrolledWindow *scrolled = para->scrolled;
3099 	//GtkTextView *text = GTK_TEXT_VIEW ( gtk_bin_get_child ( GTK_BIN ( scrolled ) ) );
3100 	GtkTextBuffer *buffer = gtk_text_view_get_buffer ( text );
3101 
3102 
3103 	/****************************/
3104 
3105 	/*
3106 		gnoclAttachOptCmdAndVar (
3107 			&options[onChangedIdx], &para->onChanged,
3108 			&options[variableIdx], &para->textVariable,
3109 			"changed", G_OBJECT ( buffer ),
3110 			G_CALLBACK ( changedFunc ), interp, traceFunc, para );
3111 
3112 		if ( options[variableIdx].status == GNOCL_STATUS_CHANGED && para->textVariable != NULL )
3113 		{
3114 			// if variable does not exist -> set it, else set widget state
3115 			const char *val = Tcl_GetVar ( interp, para->textVariable, TCL_GLOBAL_ONLY );
3116 
3117 			if ( val == NULL )
3118 			{
3119 
3120 				GtkTextIter *start, *end;
3121 
3122 				gtk_text_buffer_get_bounds ( buffer, start, end );
3123 
3124 				val = gtk_text_buffer_get_text ( buffer, start, end, 0 );
3125 
3126 				setTextVariable ( para, val );
3127 			}
3128 
3129 			else
3130 			{
3131 				//setVal ( para->label, val );
3132 			}
3133 		}
3134 	*/
3135 	/*****************************/
3136 
3137 
3138 	if ( options[textIdx].status == GNOCL_STATUS_CHANGED )
3139 	{
3140 		//printf ( "INSERT SOME TEXT-b\n" );
3141 
3142 		char *str = options[textIdx].val.str;
3143 		gtk_text_buffer_set_text ( buffer, str, -1 );
3144 	}
3145 
3146 	/*
3147 		if ( options[scrollBarIdx].status == GNOCL_STATUS_CHANGED )
3148 		{
3149 			GtkPolicyType hor, vert;
3150 
3151 			if ( gnoclGetScrollbarPolicy ( interp, options[scrollBarIdx].val.obj, &hor, &vert ) != TCL_OK )
3152 			{
3153 				return TCL_ERROR;
3154 			}
3155 
3156 			gtk_scrolled_window_set_policy ( scrolled, hor, vert );
3157 		}
3158 	*/
3159 	if ( options[bufferIdx].status == GNOCL_STATUS_CHANGED )
3160 	{
3161 		printf ( "APPLY NEW BUFFER-%s\n", options[bufferIdx].val.str );
3162 
3163 		GtkTextBuffer *buffer;
3164 
3165 		buffer = gnoclGetWidgetFromName ( options[bufferIdx].val.str, interp );
3166 
3167 		gtk_text_view_set_buffer ( text, buffer );
3168 
3169 	}
3170 
3171 
3172 	return TCL_OK;
3173 }
3174 
3175 /**
3176 \brief
3177 **/
cget(Tcl_Interp * interp,GtkTextView * text,GnoclOption options[],int idx)3178 static int cget ( Tcl_Interp * interp, GtkTextView * text, GnoclOption options[], int idx )
3179 {
3180 	/* get the option from the array? */
3181 	Tcl_Obj *obj = NULL;
3182 
3183 
3184 	if ( idx == tooltipIdx )
3185 	{
3186 		obj = Tcl_NewStringObj ( gtk_widget_get_tooltip_markup ( GTK_WIDGET ( text ) ), -1 );
3187 	}
3188 
3189 	if ( idx == baseFontIdx )
3190 	{
3191 		//g_print ( "basefont\n" );
3192 		PangoContext *context = gtk_widget_get_pango_context ( GTK_WIDGET ( text ) );
3193 		PangoFontDescription *desc = pango_context_get_font_description ( context );
3194 		char *font = pango_font_description_to_string  ( desc );
3195 
3196 		obj = Tcl_NewStringObj ( font, -1 );
3197 
3198 
3199 	}
3200 
3201 	if ( idx == dataIdx )
3202 	{
3203 		obj = Tcl_NewStringObj ( g_object_get_data ( text, "gnocl::data" ), -1 );
3204 	}
3205 
3206 	if ( idx == baseColorIdx )
3207 	{
3208 		//g_print ( "basecolor\n" );
3209 
3210 		Tcl_Obj *ret = Tcl_NewListObj ( 0, interp );
3211 		GdkColor color;
3212 
3213 		//modifyWidgetGdkColor ( interp, opts, G_OBJECT(text), gtk_widget_modify_base, G_STRUCT_OFFSET ( GtkStyle, base ), resList );
3214 
3215 		GtkStyle *style = gtk_rc_get_style ( GTK_WIDGET ( text ) );
3216 		GdkColor *cp = ( GdkColor * ) G_STRUCT_MEMBER_P ( style, G_STRUCT_OFFSET ( GtkStyle, base ) );
3217 		//GdkColor color = cp[type];
3218 
3219 		Tcl_ListObjAppendElement ( interp, ret, Tcl_NewIntObj ( color.red ) );
3220 		Tcl_ListObjAppendElement ( interp, ret, Tcl_NewIntObj ( color.green ) );
3221 		Tcl_ListObjAppendElement ( interp, ret, Tcl_NewIntObj ( color.blue ) );
3222 
3223 		Tcl_SetObjResult ( interp, obj );
3224 
3225 		return TCL_OK;
3226 	}
3227 
3228 
3229 	if ( obj != NULL )
3230 	{
3231 		Tcl_SetObjResult ( interp, obj );
3232 		return TCL_OK;
3233 	}
3234 
3235 
3236 	return gnoclCgetNotImplemented ( interp, options + idx );
3237 }
3238 
3239 /**
3240 \brief	Return a list of all occuranances of a named tag within a buffer
3241 **/
gnoclGetTagRanges(Tcl_Interp * interp,GtkTextBuffer * buffer,gchar * tagName)3242 static void gnoclGetTagRanges ( Tcl_Interp *interp, GtkTextBuffer *buffer, gchar *tagName )
3243 {
3244 #if 0
3245 	g_print ( "func = %s  tagname = %s\n", __FUNCTION__, tagName );
3246 #endif
3247 
3248 	GtkTextIter iter;
3249 	GtkTextTag *tag;
3250 	GtkTextTagTable *table;
3251 	gint row;
3252 	gint col;
3253 
3254 	Tcl_Obj *res;
3255 	res = Tcl_NewStringObj ( "", 0 );
3256 
3257 	static char s1[300];
3258 	static char s2[10];
3259 
3260 
3261 	gtk_text_buffer_get_start_iter ( buffer, &iter );
3262 
3263 	table = gtk_text_buffer_get_tag_table ( buffer );
3264 
3265 	tag = gtk_text_tag_table_lookup ( table, tagName );
3266 
3267 	if ( tag == NULL )
3268 	{
3269 
3270 		return;
3271 	}
3272 
3273 
3274 
3275 	/* check to see if tag applied at start of text */
3276 	if ( gtk_text_iter_begins_tag ( &iter, tag ) == TRUE )
3277 	{
3278 
3279 		row = gtk_text_iter_get_line ( &iter );
3280 		col = gtk_text_iter_get_line_offset ( &iter );
3281 
3282 		sprintf ( s2, "%d %d ", row, col );
3283 		strcat ( s1, s2 );
3284 	}
3285 
3286 	while ( ( gtk_text_iter_forward_to_tag_toggle ( &iter, tag ) ) == TRUE )
3287 	{
3288 
3289 		row = gtk_text_iter_get_line ( &iter );
3290 		col = gtk_text_iter_get_line_offset ( &iter );
3291 
3292 		sprintf ( s2, "%d %d ", row, col );
3293 		strcat ( s1, s2 );
3294 
3295 	}
3296 
3297 	Tcl_AppendStringsToObj ( res, trim ( s1 ), ( char * ) NULL );
3298 	Tcl_SetObjResult ( interp, res );
3299 
3300 	sprintf ( s1, "" );
3301 	sprintf ( s2, "" );
3302 }
3303 
3304 
3305 /**
3306 \brief	Add tagname to a Tcl list.
3307 **/
getTagName(GtkTextTag * tag,gpointer data)3308 static void getTagName ( GtkTextTag * tag, gpointer data )
3309 {
3310 #ifdef DEBUG_TAGS
3311 	g_print ( "%s %s\n", __FUNCTION__, tag->name );
3312 #endif
3313 
3314 	Tcl_Obj **resList = data;
3315 
3316 	Tcl_ListObjAppendElement ( NULL, *resList, Tcl_NewStringObj ( tag->name, -1 ) );
3317 
3318 }
3319 
3320 /**
3321      ->   0: Ok
3322         1: delete chosen
3323         2: configure chosen
3324         3: scrollToPosition chosen
3325       < 0: ERROR
3326 */
3327 
3328 /**
3329 \brief      Return list of tag properties and their values.
3330 \note       Only returns those attribute which have been set away from their default values.
3331 
3332             Getting a handle on the various tag parameters has been a process of trial and error.
3333 
3334             An alternative way of getting the colour values but this time in hex is:
3335             GdkColor *bg_color2  = &tag_appearance->bg_color;
3336             char *clr = gdk_color_to_string ( bg_color2 );
3337             sprintf ( tmp2, "clr = %s ",clr);
3338 \arguments	TAG POINTER, ptr to Tcl list
3339 \returns	TCL_LIST
3340 **/
gnoclGetTagProperties(GtkTextTag * tag,Tcl_Obj * resList)3341 static void gnoclGetTagProperties ( GtkTextTag *tag, Tcl_Obj *resList )
3342 {
3343 #ifdef DEBUG_TAGS
3344 	g_print ( "%s start\n", __FUNCTION__ );
3345 #endif
3346 
3347 	if ( tag == NULL )
3348 	{
3349 		return;
3350 	}
3351 
3352 	/*  modify the memory allocation here to use malloc and free to release it */
3353 
3354 	static char tmp[300];
3355 
3356 	GtkTextAppearance *tag_appearance; // use tag->values->appearance.underline etc.
3357 
3358 	/*  Individual chunks of this can be set/unset as a group */
3359 	PangoFontDescription *font;
3360 	GtkTextDirection direction;
3361 	guint realized;
3362 
3363 	/*    -----------------------------------------------
3364 	 *  get a handle on the tag appearance structure
3365 	 *  it might be fair to say that these are 'options'
3366 	 *  and take default values.
3367 	 *  When values are returned following a dump tags call,
3368 	 *  only return these values if they have been changed from
3369 	 *  system defaults.
3370 	 *    -----------------------------------------------*/
3371 	tag_appearance = tag->values;
3372 
3373 	gchar **fontName;
3374 	gchar **fontFamily;
3375 	gchar **fontDesc;
3376 
3377 #ifdef DEBUG_TAGS
3378 	g_print ( "%s 1\n", __FUNCTION__ );
3379 #endif
3380 
3381 	/* priority */
3382 	Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-priority", -1 ) );
3383 	//sprintf ( tmp, "%d", tag->priority );
3384 	//Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( tmp, -1 ) );
3385 	Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewIntObj ( tag->priority ) );
3386 
3387 #ifdef DEBUG_TAGS
3388 	g_print ( "%s priority\n", __FUNCTION__ );
3389 #endif
3390 
3391 	/* font */
3392 
3393 #ifdef DEBUG_TAGS
3394 	g_print ( "%s font start\n", __FUNCTION__ );
3395 #endif
3396 
3397 	/* these need to be concatenated into a meaningfull string */
3398 	g_object_get ( G_OBJECT ( tag ), "font", &fontName, NULL );
3399 	g_object_get ( G_OBJECT ( tag ), "family", &fontFamily, NULL );
3400 	g_object_get ( G_OBJECT ( tag ), "font-desc", &fontDesc, NULL );
3401 
3402 #ifdef DEBUG_TAGS
3403 	g_print ( "%s font middle\n", __FUNCTION__ );
3404 
3405 	g_print ( "family = %s\n", fontFamily );
3406 	g_print ( "desc   = %s\n", fontDesc );
3407 
3408 #endif
3409 
3410 	if ( fontName != NULL )
3411 	{
3412 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-font", -1 ) );
3413 
3414 	}
3415 
3416 	sprintf ( tmp, "%s", fontName  );
3417 	Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( tmp, -1 ) );
3418 
3419 	/*
3420 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-fontFamily", -1 ) );
3421 		sprintf ( tmp, "%s", fontFamily );
3422 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( tmp,  -1 ) );
3423 	*/
3424 
3425 #ifdef DEBUG_TAGS
3426 	g_print ( "%s font end\n", __FUNCTION__ );
3427 #endif
3428 
3429 	/*  background stipple */
3430 	if ( tag->bg_stipple_set )
3431 	{
3432 		GdkBitmap *bg_stipple  = tag_appearance->bg_stipple;
3433 	}
3434 
3435 #ifdef DEBUG_TAGS
3436 	g_print ( "%s stipple\n", __FUNCTION__ );
3437 #endif
3438 
3439 
3440 	/*  background colour */
3441 	if ( tag->pg_bg_color_set )
3442 	{
3443 		GdkColor bg_color  = tag_appearance->bg_color;
3444 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-background", -1 ) );
3445 		sprintf ( tmp, "%d %d %d", bg_color.red, bg_color.green, bg_color.blue );
3446 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( tmp,  -1 ) );
3447 	}
3448 
3449 #ifdef DEBUG_TAGS
3450 	g_print ( "%s backgroun\n", __FUNCTION__ );
3451 #endif
3452 
3453 	/*  foreground colour */
3454 	if ( tag->fg_color_set )
3455 	{
3456 		GdkColor fg_color  = tag_appearance->fg_color;
3457 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-foreground", -1 ) );
3458 		sprintf ( tmp, "%d %d %d", fg_color.red, fg_color.green, fg_color.blue );
3459 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( tmp, -1 ) );
3460 	}
3461 
3462 #ifdef DEBUG_TAGS
3463 	g_print ( "%s foreground\n", __FUNCTION__ );
3464 #endif
3465 
3466 	/*  font scaling */
3467 	if ( tag->scale_set )
3468 	{
3469 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-scale", -1 ) );
3470 		sprintf ( tmp, "%f", tag->values->font_scale );
3471 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( tmp, -1 ) );
3472 	}
3473 
3474 	/*  foreground stipple */
3475 	if ( tag->fg_stipple_set )
3476 	{
3477 		GdkBitmap *fg_stipple = tag_appearance->fg_stipple;
3478 	}
3479 
3480 	/*  text justfification */
3481 	if ( tag->justification_set )
3482 	{
3483 
3484 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-justification", -1 ) );
3485 
3486 		// GTK_JUSTIFY_LEFT | GTK_JUSTIFY_RIGHT | GTK_JUSTIFY_CENTER | GTK_JUSTIFY_FILL
3487 		switch ( tag->values->justification )
3488 		{
3489 			case GTK_JUSTIFY_LEFT:
3490 				{
3491 					sprintf ( tmp, "left" );
3492 				}
3493 				break;
3494 			case GTK_JUSTIFY_RIGHT:
3495 				{
3496 					sprintf ( tmp, "right" );
3497 				}
3498 				break;
3499 			case GTK_JUSTIFY_CENTER:
3500 				{
3501 					sprintf ( tmp, "center" );
3502 				}
3503 				break;
3504 			case GTK_JUSTIFY_FILL:
3505 				{
3506 					sprintf ( tmp, "fill" );
3507 				}
3508 				break;
3509 			default: {}
3510 		}
3511 
3512 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( tmp, -1 ) );
3513 	}
3514 
3515 	/*  default indent */
3516 	if ( tag->indent_set )
3517 	{
3518 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-indent", -1 ) );
3519 		sprintf ( tmp, "%d", tag->values->indent );
3520 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewIntObj ( tag->values->indent ) );
3521 	}
3522 
3523 	/*  text rise, i.e. for superscript */
3524 	if ( tag->rise_set )
3525 	{
3526 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-rise", -1 ) );
3527 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewIntObj (  tag_appearance->rise ) );
3528 	}
3529 
3530 	/*  strikethrough or, overstrike */
3531 	if ( tag->strikethrough_set )
3532 	{
3533 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-strikethrough", -1 ) );
3534 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewIntObj ( tag->values->appearance.strikethrough ) );
3535 	}
3536 
3537 	/* right margin */
3538 	if ( tag->right_margin_set )
3539 	{
3540 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-rightMargin", -1 ) );
3541 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewIntObj (  tag->values->right_margin ) );
3542 	}
3543 
3544 	/* pixels above lines */
3545 	if ( tag->pixels_above_lines_set )
3546 	{
3547 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-pixelsAboveLines", -1 ) );
3548 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewIntObj (  tag->values->pixels_above_lines ) );
3549 	}
3550 
3551 	/* pixels below lines */
3552 	if ( tag->pixels_below_lines_set )
3553 	{
3554 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-pixelsBelowLines", -1 ) );
3555 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewIntObj (  tag->values->pixels_below_lines ) );
3556 	}
3557 
3558 	/* wrapmode? */
3559 	/*
3560 		if ( tag->pixels_inside_wrap_set )
3561 		{
3562 			Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-wrapMode", -1 ) );
3563 			Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewIntObj( tag->values->pixels_inside_wrap ) );
3564 		}
3565 	*/
3566 	if ( tag->tabs_set )
3567 	{
3568 		PangoTabArray *tabs = tag->values->tabs;
3569 	}
3570 
3571 	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
3572 	/* underline */
3573 	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
3574 	if ( tag->underline_set )
3575 	{
3576 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-underline", -1 ) );
3577 
3578 		//switch ( tag_appearance->underline )
3579 		switch ( tag->values->appearance.underline )
3580 		{
3581 			case PANGO_UNDERLINE_NONE:
3582 				{
3583 					Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "none", -1 ) );
3584 				} break;
3585 			case PANGO_UNDERLINE_SINGLE:
3586 				{
3587 					Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "single", -1 ) );
3588 				} break;
3589 			case PANGO_UNDERLINE_DOUBLE:
3590 				{
3591 					Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "double", -1 ) );
3592 				} break;
3593 			case PANGO_UNDERLINE_LOW:
3594 				{
3595 					Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "low", -1 ) );
3596 				} break;
3597 			case PANGO_UNDERLINE_ERROR:
3598 				{
3599 					Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "error", -1 ) );
3600 				} break;
3601 			default:
3602 				{
3603 					Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "single", -1 ) );
3604 				}
3605 		}
3606 
3607 	}
3608 
3609 	/* wrapmode */
3610 	if ( tag->wrap_mode_set )
3611 	{
3612 
3613 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-wrapMode", -1 ) );
3614 
3615 		switch ( tag->values->wrap_mode )
3616 		{
3617 			case GTK_WRAP_CHAR:
3618 				{
3619 					Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "char", -1 ) );
3620 				} break;
3621 			case GTK_WRAP_NONE:
3622 				{
3623 					Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "none", -1 ) );
3624 				} break;
3625 			case GTK_WRAP_WORD:
3626 				{
3627 					Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "word", -1 ) );
3628 				}
3629 			case GTK_WRAP_WORD_CHAR:
3630 				{
3631 					Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "word", -1 ) );
3632 				}
3633 				break;
3634 			default: {}
3635 		}
3636 
3637 
3638 	}
3639 
3640 	if ( tag->bg_full_height_set )
3641 	{
3642 		/*  Background is fit to full line height rather than
3643 		 *  baseline +/- ascent/descent (font height)
3644 		*/
3645 		guint bg_full_height;
3646 
3647 		//sprintf ( tmp, "bg_full_height %d", tag->values->pixels_inside_wrap );
3648 		//Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( tmp, -1 ) );
3649 	}
3650 
3651 	/* invisible */
3652 	if ( tag->invisible_set )
3653 	{
3654 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-invisible", -1 ) );
3655 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewIntObj (  tag->values->invisible ) );
3656 
3657 	}
3658 
3659 	/* editable */
3660 	if ( tag->editable_set )
3661 	{
3662 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewStringObj ( "-editable", -1 ) );
3663 		Tcl_ListObjAppendElement ( NULL, resList, Tcl_NewIntObj (  tag->values->editable ) );
3664 	}
3665 
3666 	if ( tag->language_set )
3667 	{
3668 		PangoLanguage *language;
3669 	}
3670 
3671 	/*  Whether to use background-related values; this is irrelevant for
3672 	 *  the values struct when in a tag, but is used for the composite
3673 	 *  values struct; it's true if any of the tags being composited
3674 	 *  had background stuff set.
3675 	 */
3676 	guint draw_bg = tag_appearance->draw_bg;
3677 
3678 	/*  These are only used when we are actually laying out and rendering
3679 	 *  a paragraph; not when a GtkTextAppearance is part of a
3680 	 *  GtkTextAttributes.
3681 	 */
3682 	guint inside_selection = tag_appearance->inside_selection;
3683 
3684 	guint is_text = tag_appearance->is_text;
3685 
3686 #ifdef DEBUG_TAGS
3687 	g_print ( "%s end\n", __FUNCTION__ );
3688 #endif
3689 }
3690 
3691 
3692 /**
3693 \brief      Return list of tag name
3694 **/
gnoclGetTagNames(GtkTextTag * tag,gpointer data)3695 static void gnoclGetTagNames ( GtkTextTag * tag, gpointer data )
3696 {
3697 #ifdef DEBUG_TEXT
3698 	//g_print ( "%s 1 \n", __FUNCTION__ );
3699 #endif
3700 
3701 	if ( tag == NULL )
3702 	{
3703 		return;
3704 	}
3705 
3706 	char **str = data;
3707 
3708 	/*  modify the memory allocation here to use malloc and free to release it */
3709 
3710 	static char tmp[300];
3711 
3712 	sprintf ( tmp, "%s", tag->name );
3713 
3714 	*str = tmp;
3715 
3716 }
3717 
3718 
3719 /**
3720 \brief
3721 **/
signalEmit(Tcl_Interp * interp,Tcl_Obj * obj,int cmdNo,GtkTextBuffer * buffer)3722 static int signalEmit ( Tcl_Interp * interp, Tcl_Obj * obj, int cmdNo, GtkTextBuffer * buffer )
3723 {
3724 
3725 	const char *signal = Tcl_GetString ( obj );
3726 
3727 #ifdef DEBUG_TEXT
3728 	printf ( ">> emitSignal %s\n", signal );
3729 #endif
3730 
3731 	/*  the problem now, is how to get the right object */
3732 	gtk_signal_emit_by_name ( GTK_OBJECT ( GTK_WIDGET ( buffer ) ), signal, NULL );
3733 
3734 	return TCL_OK;
3735 }
3736 
3737 static	const char *cmds[] =
3738 {
3739 	"getMarkup", "getAttributes", "insertMarkup",
3740 
3741 	"delete", "configure", "scrollToPosition", "scrollToMark",
3742 	"parent",
3743 	"getIndex", "getCoords", "getRect",
3744 	"undo", "redo", "grabFocus", "resetUndo", "getPos",
3745 
3746 	"set", "erase", "select", "get", "cut", "copy", "paste", "pasteRichText_",
3747 	"cget", "getLineCount", "getWordLength", "getLength",
3748 	"getLineLength", "setCursor", "getCursor", "insert", "tag",
3749 	"dump", "signalEmit", "mark", "gotoWordStart",
3750 	"gotoWordEnd", "search", "class", "spawn", "replace",
3751 	"serialize", "deSerialize", "save", "load", "print", "lorem",
3752 	"clear", "popup", "getSelectionBounds",
3753 	"hasGlobalFocus", "isToplevelFocus",
3754 
3755 	NULL
3756 };
3757 
3758 /**
3759 \brief
3760 **/
gnoclTextCommand(GtkTextView * textView,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[],int cmdNo,int isTextWidget)3761 int gnoclTextCommand ( GtkTextView *textView, Tcl_Interp * interp, int objc, Tcl_Obj *  const objv[], int cmdNo, int isTextWidget )
3762 {
3763 #ifdef DEBUG_TEXT
3764 	g_print ( "gnoclTextCommand %s %s\n", Tcl_GetString ( objv[cmdNo] ), Tcl_GetString ( objv[cmdNo+1] ) );
3765 #endif
3766 
3767 	GtkTextBuffer  *buffer = gtk_text_view_get_buffer ( textView );
3768 
3769 
3770 
3771 	enum cmdIdx
3772 	{
3773 		GetMarkupIdx, GetAttributesIdx, InsertMarkupIdx,
3774 
3775 		DeleteIdx, ConfigureIdx, ScrollToPosIdx, ScrollToMarkIdx,
3776 		ParentIdx,
3777 		GetIndexIdx, GetCoordsIdx, GetRectIdx,
3778 		UndoIdx, RedoIdx, GrabFocusIdx, ResetUndoIdx, GetPosIdx,
3779 
3780 		SetIdx, EraseIdx, SelectIdx, GetIdx, CutIdx, CopyIdx, PasteIdx, PasteRichTextIdx,
3781 		CgetIdx, GetLineCountIdx, GetWordLengthIdx, GetLengthIdx,
3782 		GetLineLengthIdx, SetCursorIdx, GetCursorIdx, InsertIdx, TagIdx,
3783 		DumpIdx, SignalEmitIdx, MarkIdx, GotoWordStartIdx,
3784 		GotoWordEndIdx, SearchIdx, ClassIdx, SpawnIdx, ReplaceIdx,
3785 		SerializeIdx, DeSerializeIdx, SaveIdx, LoadIdx, PrintIdx, LoremIdx,
3786 		ClearIdx, PopupIdx, GetSelectionBounds,
3787 		HasGlobalFocusIdx, IsToplevelFocusIdx
3788 	};
3789 
3790 
3791 	int   idx;
3792 	GtkTextMark *mark;
3793 
3794 	/*  WJG STUFF */
3795 	char s[10];
3796 
3797 	if ( objc < cmdNo + 1 )
3798 	{
3799 		Tcl_WrongNumArgs ( interp, cmdNo, objv, "command" );
3800 		return -1;
3801 	}
3802 
3803 	if ( Tcl_GetIndexFromObj ( interp, objv[cmdNo], isTextWidget ? cmds : cmds + 3, "command", TCL_EXACT, &idx ) != TCL_OK )
3804 	{
3805 		return -1;
3806 	}
3807 
3808 	if ( !isTextWidget )
3809 	{
3810 		idx += 3;
3811 	}
3812 
3813 //	g_print ( "1\n" );
3814 
3815 	switch ( idx )
3816 	{
3817 			/* item 1...n are GtkTextView operations, pass args onto textFunc*/
3818 		case DeleteIdx:         return 1;
3819 		case ConfigureIdx:      return 2;
3820 		case ScrollToPosIdx:    return 3;
3821 		case ScrollToMarkIdx:   return 4;
3822 		case ParentIdx:         return 5;
3823 		case GetIndexIdx:       return 6;
3824 		case GetCoordsIdx:      return 7;
3825 		case GetRectIdx:        return 8;
3826 		case UndoIdx:  			return 9;
3827 		case RedoIdx:  			return 10;
3828 		case GrabFocusIdx:  	return 11;
3829 		case ResetUndoIdx:  	return 12;
3830 		case GetPosIdx: 		return 13;
3831 		case HasGlobalFocusIdx:	return 14;
3832 		case IsToplevelFocusIdx:	return 15;
3833 
3834 			/*
3835 			guint8 * gtk_clipboard_wait_for_rich_text (GtkClipboard *clipboard, GtkTextBuffer *buffer, GdkAtom *format, gsize *length);
3836 			gtk_clipboard_request_rich_text (GtkClipboard *clipboard, GtkTextBuffer *buffer, GtkClipboardRichTextReceivedFunc callback, gpointer user_data);
3837 			*/
3838 #if 0
3839 		case PasteRichTextIdx:
3840 			{
3841 #if 0
3842 				GtkClipboard *clipboard;
3843 				GdkAtom	 format;
3844 				gsize length;
3845 				guint8 *data;
3846 
3847 				g_print ( "1\n" );
3848 				clipboard = gtk_clipboard_get ( GDK_NONE );
3849 				g_print ( "2\n" );
3850 				//format = gtk_text_buffer_register_deserialize_tagset ( buffer, "default" );
3851 				g_print ( "3\n" );
3852 				//gtk_clipboard_request_rich_text (clipboard, buffer, NULL, NULL);
3853 				data = gtk_clipboard_wait_for_rich_text  ( clipboard, buffer, format, &length );
3854 				gtk_text_buffer_deserialize ( buffer, buffer, format, &iter, data, length, NULL ); //??
3855 				g_print ( "4\n" );
3856 				g_free ( data );
3857 #endif
3858 				GtkClipboard *clipboard;
3859 				GdkAtom *targets;
3860 				clipboard = gtk_clipboard_get (  GDK_SELECTION_PRIMARY );
3861 				gint n_targets;
3862 //gboolean gtk_clipboard_wait_for_targets  (GtkClipboard *clipboard, GdkAtom **targets, gint *n_targets);
3863 				gtk_clipboard_wait_for_targets  ( clipboard, &targets, &n_targets );
3864 				g_print ( "n_targets = %d\n", n_targets );
3865 				g_print ( "targets  %s\n", gdk_atom_name ( targets ) );
3866 
3867 
3868 //GtkSelectionData *  gtk_clipboard_wait_for_contents     (clipboard, targets);
3869 
3870 			}
3871 			break;
3872 #endif
3873 			/* these are GtkTextBuffer operations */
3874 		case InsertMarkupIdx:
3875 			{
3876 				GtkTextIter iter;
3877 				g_print ( "InsertMarkupIdx %s\n", Tcl_GetString ( objv[cmdNo+2] ) );
3878 
3879 				if ( posToIter ( interp, objv[cmdNo+1], buffer, &iter ) != TCL_OK )
3880 				{
3881 					return TCL_ERROR;
3882 				}
3883 
3884 				gnoclInsertMarkup ( buffer, &iter, Tcl_GetString ( objv[cmdNo+2]  ) );
3885 			}
3886 			break;
3887 
3888 		case GetAttributesIdx:
3889 			{
3890 				if ( strcmp ( Tcl_GetString ( objv[cmdNo+1] ), "attributes" ) == 0 )
3891 				{
3892 
3893 					GtkTextIter iter;
3894 					GtkTextAttributes values;
3895 
3896 					if ( posToIter ( interp, objv[cmdNo+2], buffer, &iter ) != TCL_OK )
3897 					{
3898 						return TCL_ERROR;
3899 					}
3900 
3901 					if ( gtk_text_iter_get_attributes ( &iter, &values ) )
3902 					{
3903 #ifdef DEBUG_TEXT
3904 						g_print ( "attributes at %s\n", Tcl_GetString ( objv[cmdNo+2] ) );
3905 #endif
3906 						/*
3907 						GtkJustification justification;
3908 						GtkTextDirection direction;
3909 						PangoFontDescription *font;
3910 						gdouble font_scale;
3911 						gint left_margin;
3912 						gint indent;
3913 						gint right_margin;
3914 						gint pixels_above_lines;
3915 						gint pixels_below_lines;
3916 						gint pixels_inside_wrap;
3917 						PangoTabArray *tabs;
3918 						GtkWrapMode wrap_mode;
3919 						PangoLanguage *language;
3920 						guint invisible : 1;
3921 						guint bg_full_height : 1;
3922 						guint editable : 1;
3923 						guint realized : 1;
3924 						*/
3925 
3926 						getAttributes ( interp, &values );
3927 
3928 					}
3929 
3930 					return TCL_OK;
3931 
3932 				}
3933 			}
3934 			break;
3935 
3936 		case GetMarkupIdx:
3937 			{
3938 				g_print ( "%s getMarkup\n", __FUNCTION__ );
3939 
3940 				GtkTextIter startIter, endIter;
3941 
3942 				posToIter ( interp, objv[cmdNo+1], buffer, &startIter );
3943 				posToIter ( interp, objv[cmdNo+2], buffer, &endIter );
3944 				//g_print ( "getMarkup 1\n" );
3945 				Tcl_Obj *res = getMarkUpString ( interp, buffer, &startIter, &endIter );
3946 				//g_print ( "getMarkup 2\n" );
3947 				//char *txt = gtk_text_buffer_get_text ( buffer, &startIter, &endIter, 1 );
3948 				Tcl_SetObjResult ( interp, res );
3949 				//g_print ( "getMarkup 3\n" );
3950 			}
3951 			break;
3952 
3953 		case PrintIdx:
3954 			{
3955 #ifdef DEBUG_TEXT
3956 				g_print ( "print\n" );
3957 #endif
3958 				/* reset parameters for this command and then call */
3959 				gnoclPrintCmd ( buffer, interp, objc, objv );
3960 
3961 			}
3962 
3963 			break;
3964 		case ClearIdx:
3965 			{
3966 				gtk_text_buffer_set_text ( buffer, "", 0 );
3967 			}
3968 			break;
3969 		case LoremIdx:
3970 			{
3971 
3972 				gchar lorem[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sed eleifend sem. Aenean at convallis ante. Etiam venenatis massa vitae nisl pretium sed pretium velit vehicula. Morbi vitae magna justo. Nullam ultricies rutrum felis rutrum tristique. Quisque orci mauris, cursus at dapibus quis, faucibus et nibh. Etiam posuere scelerisque libero eu rutrum. Nulla vel metus ut purus tempus adipiscing. Aenean lacus nunc, luctus sed tempor ac, semper vitae massa. Nunc et augue vitae ligula facilisis pulvinar a vestibulum magna. Quisque convallis rutrum vehicula. Morbi pulvinar nunc quis dui pharetra faucibus. Fusce sapien metus, varius eget fringilla quis, tristique vitae augue. Duis accumsan aliquet diam sed pretium. Nunc ipsum neque, auctor et convallis eget, molestie vitae libero. Integer eget velit at leo aliquam lobortis vel eu erat. Suspendisse sed orci neque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut lobortis arcu gravida sapien vestibulum venenatis. In quis diam tellus.";
3973 
3974 				gtk_text_buffer_insert_at_cursor ( buffer, lorem, strlen ( lorem ) );
3975 
3976 			}
3977 			break;
3978 		case PopupIdx:
3979 			{
3980 				// 0   1     2       3       4
3981 				// $id popup item    <path>
3982 				// $id popup subMenu <path1> <path2>
3983 #ifdef DEBUG_TEXT
3984 				g_print ( "PopupIdx %s\n", Tcl_GetString ( objv[cmdNo] ) );
3985 				g_print ( "PopupIdx %s\n", Tcl_GetString ( objv[cmdNo +1] ) );
3986 				g_print ( "PopupIdx %s\n", Tcl_GetString ( objv[cmdNo +2] ) );
3987 #endif
3988 
3989 				static char *popupOptions[] =
3990 				{
3991 					"item", "subMenu", "separator",
3992 					NULL
3993 				};
3994 
3995 				static enum  popupOptionsIdx
3996 				{
3997 					ItemIdx, SubMenuIdx, SeparatorIdx
3998 				};
3999 
4000 				gint idx;
4001 
4002 				getIdx ( popupOptions,  Tcl_GetString ( objv[cmdNo +1] ), &idx );
4003 
4004 				switch ( idx )
4005 				{
4006 					case SeparatorIdx:
4007 						{
4008 							gnoclPopupMenuAddSeparator ( interp );
4009 						}
4010 						break;
4011 					case ItemIdx:
4012 						{
4013 							gnoclPopupMenuAddItem ( interp, Tcl_GetString ( objv[cmdNo+2] ) );
4014 						} break;
4015 					case SubMenuIdx:
4016 						{
4017 							gnoclPopupMenuAddSubMenu ( interp, Tcl_GetString ( objv[cmdNo+2] ),  Tcl_GetString ( objv[cmdNo+3] ) );
4018 						} break;
4019 					default: {}
4020 				}
4021 
4022 
4023 			}
4024 
4025 			break;
4026 		case SaveIdx:
4027 		case SerializeIdx:  /* WJG 29/04/09 */
4028 			{
4029 
4030 				FILE        *output;
4031 				guint8		*data;
4032 				gsize		length;
4033 				GtkTextIter	start, end;
4034 				GdkAtom		se_format;
4035 
4036 				se_format = gtk_text_buffer_register_serialize_tagset ( buffer, NULL );
4037 
4038 				gtk_text_buffer_get_bounds ( buffer, &start, &end );
4039 				data = gtk_text_buffer_serialize ( buffer, buffer, se_format, &start, &end, &length );
4040 
4041 #ifdef DEBUG_TEXT
4042 				g_print ( "%s\n", data );
4043 #endif
4044 
4045 
4046 				output = fopen ( Tcl_GetString ( objv[cmdNo+1] ), "w" );
4047 
4048 				fwrite ( &length, sizeof ( gsize ), 1, output );
4049 				fwrite ( data, sizeof ( guint8 ), length, output );
4050 				fclose ( output );
4051 
4052 #if 0 // attempt to serialize returning a text string
4053 				GString *buf;
4054 				buf = g_string_sized_new ( length );
4055 
4056 				int i;
4057 
4058 				output = fopen ( "serialize.xml", "w" );
4059 
4060 				/* ignore the first 32 characters */
4061 				for ( i = 31; i < length ; i++ )
4062 				{
4063 					/* show the content of the data array */
4064 					g_string_append_unichar ( buf, data[i] ); /* <--- problems here, but why? */
4065 				}
4066 
4067 				fclose ( output );
4068 
4069 				Tcl_SetObjResult ( interp, Tcl_NewStringObj ( buf->str, -1 ) );
4070 
4071 				g_string_free ( buf, 1 );
4072 
4073 #endif
4074 
4075 				return TCL_OK;
4076 
4077 			}
4078 
4079 			break;
4080 		case LoadIdx:
4081 		case DeSerializeIdx:  /* WJG 29/04/09 */
4082 			{
4083 
4084 				FILE *input;
4085 				guint8 *data;
4086 				gsize length;
4087 				GtkTextIter iter;
4088 				GdkAtom de_format;
4089 
4090 #if 0 	// binary file
4091 				input = fopen ( Tcl_GetString ( objv[cmdNo+1] ), "r" );
4092 
4093 				// Return with error message if the file is not found.
4094 
4095 				if ( input == NULL )
4096 				{
4097 					char str[128];
4098 					sprintf ( str, "File %s not found.\n", Tcl_GetString ( objv[cmdNo+1] ) );
4099 					Tcl_SetObjResult ( interp, Tcl_NewStringObj ( str, -1 ) );
4100 					return TCL_OK;
4101 				}
4102 
4103 				// read data
4104 				fread ( &length, sizeof ( gsize ), 1, input );
4105 				data = malloc ( sizeof ( guint8 ) * length );
4106 				fread ( data, sizeof ( guint8 ), length, input );
4107 				fclose ( input );
4108 
4109 				de_format = gtk_text_buffer_register_deserialize_tagset ( buffer, "default" );
4110 				gtk_text_buffer_get_iter_at_offset ( buffer, &iter, 0 );
4111 				gtk_text_buffer_deserialize ( buffer, buffer, de_format, &iter, data, length, NULL );
4112 
4113 				g_free ( data );
4114 
4115 #else  	// text file
4116 				de_format = gtk_text_buffer_register_deserialize_tagset ( buffer, "default" );
4117 				gtk_text_buffer_get_iter_at_offset ( buffer, &iter, 0 );
4118 				gtk_text_buffer_deserialize ( buffer, buffer, de_format, &iter, Tcl_GetString ( objv[cmdNo+1] ), strlen ( Tcl_GetString ( objv[cmdNo+1] ) ), NULL );
4119 #endif
4120 
4121 				return TCL_OK;
4122 			}
4123 
4124 			break;
4125 		case ReplaceIdx:    /*  WJG 21/02/09 -Pretty much the same code as SearchIdx */
4126 			{
4127 				gint row1, col1, row2, col2;
4128 				GtkTextIter start;
4129 				GtkTextIter begin, end;
4130 				GtkTextMark *replace;
4131 				Tcl_Obj *resList;
4132 				gint applyTags;
4133 				gchar *  pch;
4134 				gchar *  tagList;
4135 				gint i;
4136 
4137 				replace = NULL;
4138 
4139 				if ( objc < cmdNo + 2 )
4140 				{
4141 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "<search-phrase> <swap-phrase>" );
4142 					return -1;
4143 				}
4144 
4145 				resList = Tcl_NewListObj ( 0, NULL );
4146 
4147 				/*  default with the start of the buffer */
4148 				gtk_text_buffer_get_start_iter ( buffer, &start );
4149 
4150 				i = 0;
4151 
4152 				while ( gtk_text_iter_forward_search ( &start, Tcl_GetString ( objv[cmdNo+1] ), 0, &begin, &end, NULL ) != NULL )
4153 				{
4154 
4155 					if ( replace == NULL )
4156 					{
4157 						replace = gtk_text_buffer_create_mark ( buffer, "REPLACE_MARK", &begin, 1 );
4158 					}
4159 
4160 					else
4161 					{
4162 						gtk_text_buffer_move_mark  ( buffer, replace, &begin );
4163 					}
4164 
4165 					gtk_text_buffer_delete ( buffer, &begin, &end );
4166 
4167 					gtk_text_buffer_get_iter_at_mark ( buffer, &end, replace );
4168 					gtk_text_buffer_insert ( buffer, &end,  Tcl_GetString ( objv[cmdNo+2] ),  strlen (  Tcl_GetString ( objv[cmdNo+2] ) ) );
4169 
4170 					start = end;
4171 					i++;
4172 
4173 				}
4174 
4175 				gtk_text_buffer_delete_mark ( buffer, replace );
4176 
4177 				Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( i ) );
4178 
4179 				Tcl_SetObjResult ( interp, resList );
4180 
4181 				return TCL_OK;
4182 			}
4183 
4184 			break;
4185 		case SpawnIdx: /*  WJG began 06/12/08 */
4186 			{
4187 				/*  code taken from gnoclTextCmd */
4188 				GtkTextView *spawn;
4189 				GtkScrolledWindow *scrolled;
4190 				GtkTextBuffer *spawnBuffer;
4191 				spawnBuffer = buffer;
4192 #ifdef DEBUG_TEXT
4193 				g_print ( "spawn -1\n" );
4194 #endif
4195 				/*  create a new text view with buffer GtkTextBuffer *buffer*/
4196 				//g_object_ref (G_OBJECT(buffer));
4197 				spawn = GTK_TEXT_VIEW ( gtk_text_view_new_with_buffer ( GTK_TEXT_BUFFER ( spawnBuffer ) ) );
4198 				//spawn = GTK_TEXT_VIEW ( gtk_text_view_new_with_buffer ( NULL ) );
4199 				//gtk_text_view_set_buffer (spawn, buffer);
4200 #ifdef DEBUG_TEXT
4201 				g_print ( "spawn -2\n" );
4202 #endif
4203 				/*  add some extra signals to the default setting */
4204 				gtk_widget_add_events ( spawn, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK );
4205 				g_print ( "spawn -3\n" );
4206 				scrolled =  gtk_scrolled_window_new ( NULL, NULL );
4207 				gtk_scrolled_window_set_policy ( scrolled, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
4208 				gtk_container_add ( scrolled, GTK_WIDGET ( spawn ) );
4209 				gtk_widget_show_all ( GTK_WIDGET ( scrolled ) );
4210 #ifdef DEBUG_TEXT
4211 				g_print ( "spawn -4\n" );
4212 #endif
4213 
4214 				if ( 0 )
4215 				{
4216 					/*  get properties of the parent widget */
4217 					gint intval;
4218 					gchar *strval;
4219 					GObject *objval;
4220 
4221 					g_object_get ( spawn,
4222 								   "int-property", &intval,
4223 								   "str-property", &strval,
4224 								   "obj-property", &objval,
4225 								   NULL );
4226 
4227 					// Do something with intval, strval, objval
4228 					g_free ( strval );
4229 					g_object_unref ( objval );
4230 				}
4231 
4232 				/*  need to get options from the existing view */
4233 				return gnoclRegisterWidget ( interp, GTK_WIDGET ( scrolled ), textFunc );
4234 
4235 			}
4236 
4237 			break;
4238 
4239 		case SearchIdx: /*  WJG began 13/09/08 */
4240 			{
4241 
4242 				int row1, col1, row2, col2;
4243 				GtkTextIter start;
4244 				GtkTextIter begin, end;
4245 				Tcl_Obj *resList;
4246 				gint applyTags;
4247 				char *  pch;
4248 				char *  tagList;
4249 				GtkTextTagTable *table;
4250 
4251 				if ( objc < cmdNo + 1 )
4252 				{
4253 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "<search-phrase> -tags {taglist}" );
4254 					return -1;
4255 				}
4256 
4257 				applyTags = 0;
4258 
4259 				if ( objc == cmdNo + 4 )
4260 				{
4261 					if ( strcmp ( Tcl_GetString ( objv[cmdNo+2] ), "-tags" ) == 0 )
4262 					{
4263 						pch = strtok ( Tcl_GetString ( objv[cmdNo+3] ), " " );
4264 
4265 						table = gtk_text_buffer_get_tag_table ( buffer );
4266 
4267 						if ( gtk_text_tag_table_lookup ( table, pch ) == NULL )
4268 						{
4269 
4270 							Tcl_SetObjResult ( interp, Tcl_NewStringObj ( "GNOCL ERROR! Specified tag not found.", -1 ) );
4271 
4272 							return TCL_ERROR;
4273 						}
4274 
4275 						applyTags = 1;
4276 					}
4277 
4278 					else
4279 					{
4280 						Tcl_SetObjResult ( interp, Tcl_NewStringObj ( "GNOCL ERROR! Invalid option given, it must be -tags <taglist>.", -1 ) );
4281 
4282 						return TCL_ERROR;
4283 					}
4284 				}
4285 
4286 
4287 				resList = Tcl_NewListObj ( 0, NULL );
4288 
4289 				/*  default with the start of the buffer */
4290 				gtk_text_buffer_get_start_iter ( buffer, &start );
4291 
4292 				while ( gtk_text_iter_forward_search ( &start, Tcl_GetString ( objv[cmdNo+1] ), 0, &begin, &end, NULL ) != NULL )
4293 				{
4294 					/*  return the index of the found location */
4295 					row1 = gtk_text_iter_get_line ( &begin );
4296 					col1 = gtk_text_iter_get_line_offset ( &begin );
4297 					row2 = gtk_text_iter_get_line ( &end );
4298 					col2 = gtk_text_iter_get_line_offset ( &end );
4299 
4300 					/*  check if there is a taglist to apply */
4301 					if ( applyTags == 1 )
4302 					{
4303 						/* currently supporting only one tag */
4304 						gtk_text_buffer_apply_tag_by_name ( buffer, pch, &begin, &end );
4305 
4306 					}
4307 
4308 					Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( row1 ) );
4309 					Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( col1 ) );
4310 					Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( row2 ) );
4311 					Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( col2 ) );
4312 
4313 					start = end;
4314 
4315 				}
4316 
4317 				Tcl_SetObjResult ( interp, resList );
4318 
4319 				return TCL_OK;
4320 			}
4321 
4322 			break;
4323 		case SignalEmitIdx:
4324 			{
4325 				/*  error check the command */
4326 				if ( objc != cmdNo + 2 )
4327 				{
4328 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "<signal-name>" );
4329 
4330 					return -1;
4331 				}
4332 
4333 				/*  DEBUG_TEXTging test line */
4334 #ifdef DEBUG_TEXT
4335 				printf ( "signalEmit %s\n", objv[cmdNo+1] );
4336 #endif
4337 
4338 				/*  attempt to emit the signal */
4339 				if ( signalEmit ( interp, objv[cmdNo+1] , cmdNo, buffer ) != TCL_OK )
4340 				{
4341 					return -1;
4342 				}
4343 			}
4344 
4345 			break;
4346 		case ClassIdx:
4347 			{
4348 				Tcl_SetObjResult ( interp, Tcl_NewStringObj ( "text", -1 ) );
4349 			}
4350 			break;
4351 		case EraseIdx:
4352 		case SelectIdx:
4353 		case GetIdx:
4354 			{
4355 				GtkTextIter startIter, endIter;
4356 
4357 
4358 				if ( objc < cmdNo + 3 )
4359 				{
4360 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "startIndex ?endIndex?" );
4361 					return TCL_ERROR;
4362 				}
4363 
4364 #ifdef DEBUG_TEXT
4365 				g_print ( "7\n" );
4366 #endif
4367 
4368 				if ( posToIter ( interp, objv[cmdNo+1], buffer, &startIter ) != TCL_OK )
4369 				{
4370 					return TCL_ERROR;
4371 				}
4372 
4373 #ifdef DEBUG_TEXT
4374 				g_print ( "8\n" );
4375 #endif
4376 
4377 				if ( objc >= 4 )
4378 				{
4379 					if ( posToIter ( interp, objv[cmdNo+2], buffer, &endIter ) != TCL_OK )
4380 					{
4381 						return TCL_ERROR;
4382 					}
4383 				}
4384 
4385 				else
4386 				{
4387 					endIter = startIter;
4388 					gtk_text_iter_backward_char ( &endIter );
4389 				}
4390 
4391 #ifdef DEBUG_TEXT
4392 				g_print ( "9\n" );
4393 #endif
4394 
4395 				switch ( idx )
4396 				{
4397 					case EraseIdx:
4398 						{
4399 							gtk_text_buffer_delete ( buffer, &startIter, &endIter );
4400 						}
4401 						break;
4402 					case SelectIdx:
4403 						{
4404 							gtk_text_buffer_place_cursor ( buffer, &startIter );
4405 							gtk_text_buffer_move_mark_by_name ( buffer, "selection_bound", &endIter );
4406 						}
4407 						break;
4408 					case GetIdx:
4409 						{
4410 							/*  TODO: include_hidden_chars */
4411 #ifdef DEBUG_TEXT
4412 							g_print ( "10 ----\n" );
4413 #endif
4414 
4415 							char *txt = gtk_text_buffer_get_text ( buffer, &startIter, &endIter, 1 );
4416 							Tcl_SetObjResult ( interp, Tcl_NewStringObj ( txt, -1 ) );
4417 
4418 						}
4419 						break;
4420 				}
4421 			}
4422 #ifdef DEBUG_TEXT
4423 			g_print ( "11\n" );
4424 #endif
4425 			break;
4426 		case CutIdx:
4427 		case CopyIdx:
4428 		case PasteIdx:
4429 			{
4430 				/*  TODO: option which clipboard */
4431 				GtkClipboard *clipboard = gtk_clipboard_get ( GDK_NONE );
4432 
4433 				if ( objc != cmdNo + 1 )
4434 				{
4435 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, NULL );
4436 					return TCL_ERROR;
4437 				}
4438 
4439 				switch ( idx )
4440 				{
4441 					case CutIdx:
4442 						{
4443 							gtk_text_buffer_cut_clipboard ( buffer, clipboard, 1 );
4444 						}
4445 						break;
4446 					case CopyIdx:
4447 						{
4448 							gtk_text_buffer_copy_clipboard ( buffer, clipboard );
4449 						}
4450 						break;
4451 					case PasteIdx:
4452 						{
4453 							gtk_text_buffer_paste_clipboard ( buffer, clipboard, NULL, 1 );
4454 						}
4455 						break;
4456 				}
4457 			}
4458 
4459 			break;
4460 		case CgetIdx:	// gnoclTextCommand
4461 			{
4462 #ifdef DEBUG_TEXT
4463 				g_print ( "%s CgetIdx\n", __FUNCTION__ );
4464 #endif
4465 
4466 
4467 				int     idx;
4468 
4469 				switch ( gnoclCget ( interp, objc, objv, G_OBJECT ( textView ), textOptions, &idx ) )
4470 				{
4471 					case GNOCL_CGET_ERROR:
4472 						{
4473 							return TCL_ERROR;
4474 						}
4475 					case GNOCL_CGET_HANDLED:
4476 						{
4477 							return TCL_OK;
4478 						}
4479 					case GNOCL_CGET_NOTHANDLED:
4480 						{
4481 							return cget ( interp, textView, textOptions, idx );
4482 						}
4483 				}
4484 
4485 			}
4486 
4487 			break;
4488 		case GetLineCountIdx: /*  WJG Added 24/04/08 */
4489 			{
4490 				/*  editable getLength */
4491 				if ( objc != cmdNo + 1 )
4492 				{
4493 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, NULL );
4494 					return -1;
4495 				}
4496 
4497 				Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gtk_text_buffer_get_line_count ( buffer ) ) );
4498 			}
4499 
4500 			break;
4501 		case GetLengthIdx: /*  TODO getByteCount */
4502 			{
4503 				/*  editable getLength */
4504 				if ( objc != cmdNo + 1 )
4505 				{
4506 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, NULL );
4507 					return -1;
4508 				}
4509 
4510 				Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gtk_text_buffer_get_char_count ( buffer ) ) );
4511 			}
4512 
4513 			break;
4514 		case GetLineLengthIdx: /*  Added WJG 17/05/08 */
4515 			{
4516 				GtkTextIter iter;
4517 
4518 				if ( objc != cmdNo + 2 )
4519 				{
4520 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "index" );
4521 					return -1;
4522 				}
4523 
4524 				if ( posToIter ( interp, objv[cmdNo+1], buffer, &iter ) != TCL_OK )
4525 				{
4526 					return -1;
4527 				}
4528 
4529 				Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gtk_text_iter_get_chars_in_line ( &iter ) ) );
4530 			}
4531 
4532 			break;
4533 		case GetWordLengthIdx: /*  Added WJG 12/09/08 */
4534 			{
4535 				GtkTextIter iter, iter_a;
4536 				int row_a, col_a, row_b, col_b, wordLength;
4537 
4538 				/*  get the iter at the specified position */
4539 				posToIter ( interp, objv[cmdNo+1], buffer, &iter );
4540 
4541 				/*  move the iter to the start of the word */
4542 				gtk_text_iter_backward_word_start ( &iter );
4543 
4544 				/*  get row-offset values for the iter */
4545 				row_a = gtk_text_iter_get_line ( &iter );
4546 				col_a = gtk_text_iter_get_line_offset ( &iter );
4547 
4548 				/*  move the iter to the end of the word */
4549 				gtk_text_iter_forward_word_end ( &iter );
4550 
4551 				/*  get the position... */
4552 				row_b = gtk_text_iter_get_line ( &iter );
4553 				col_b = gtk_text_iter_get_line_offset ( &iter );
4554 
4555 				/*  subtract the larger from the smaller */
4556 				wordLength = col_b - col_a;
4557 
4558 				/*  return the value */
4559 				Tcl_SetObjResult ( interp, Tcl_NewIntObj ( wordLength ) );
4560 			}
4561 
4562 			break;
4563 		case GotoWordStartIdx: /*  Added WJG 12/09/08 */
4564 			{
4565 				GtkTextIter iter;
4566 
4567 				/*  text setCursor index */
4568 
4569 				if ( objc != cmdNo + 2 )
4570 				{
4571 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "index" );
4572 					return -1;
4573 				}
4574 
4575 				gtk_text_buffer_get_iter_at_mark ( buffer, &iter, gtk_text_buffer_get_insert ( buffer ) );
4576 
4577 				gtk_text_iter_backward_word_start ( &iter );
4578 
4579 				gtk_text_buffer_place_cursor ( buffer, &iter );
4580 			}
4581 
4582 			break;
4583 		case GotoWordEndIdx: /*  Added WJG 12/09/08 */
4584 			{
4585 				GtkTextIter iter;
4586 
4587 				/*  text setCursor index */
4588 
4589 				if ( objc != cmdNo + 2 )
4590 				{
4591 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "index" );
4592 					return -1;
4593 				}
4594 
4595 				gtk_text_buffer_get_iter_at_mark ( buffer, &iter, gtk_text_buffer_get_insert ( buffer ) );
4596 
4597 				gtk_text_iter_forward_word_end ( &iter );
4598 
4599 				gtk_text_buffer_place_cursor ( buffer, &iter );
4600 			}
4601 
4602 			break;
4603 		case SetIdx:
4604 			{
4605 				gtk_text_buffer_set_text ( buffer, gnoclGetString ( objv[cmdNo+1] ), -1 );
4606 			}
4607 
4608 			break;
4609 		case SetCursorIdx:
4610 			{
4611 				GtkTextIter iter;
4612 
4613 				/*  text setCursor index */
4614 
4615 				if ( objc != cmdNo + 2 )
4616 				{
4617 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "index" );
4618 					return -1;
4619 				}
4620 
4621 				if ( posToIter ( interp, objv[cmdNo+1], buffer, &iter ) != TCL_OK )
4622 				{
4623 					return -1;
4624 				}
4625 
4626 				gtk_text_buffer_place_cursor ( buffer, &iter );
4627 			}
4628 
4629 			break;
4630 		case GetCursorIdx:
4631 			{
4632 				GtkTextIter   iter;
4633 				int           row, col;
4634 				Tcl_Obj       *resList;
4635 
4636 				/*  text getCursor */
4637 				if ( objc != cmdNo + 1 )
4638 				{
4639 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, NULL );
4640 					return -1;
4641 				}
4642 
4643 				gtk_text_buffer_get_iter_at_mark ( buffer, &iter, gtk_text_buffer_get_insert ( buffer ) );
4644 
4645 				row = gtk_text_iter_get_line ( &iter );
4646 				col = gtk_text_iter_get_line_offset ( &iter );
4647 
4648 				resList = Tcl_NewListObj ( 0, NULL );
4649 				Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( row ) );
4650 				Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( col ) );
4651 				Tcl_SetObjResult ( interp, resList );
4652 			}
4653 
4654 			break;
4655 
4656 		case GetSelectionBounds:
4657 			{
4658 				GtkTextIter startIter, endIter;
4659 
4660 				int           row, col;
4661 				Tcl_Obj       *resList;
4662 
4663 				if ( gtk_text_buffer_get_selection_bounds ( buffer, &startIter, &endIter ) )
4664 				{
4665 
4666 					resList = Tcl_NewListObj ( 0, NULL );
4667 
4668 					row = gtk_text_iter_get_line ( &startIter );
4669 					col = gtk_text_iter_get_line_offset ( &startIter );
4670 
4671 					Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( row ) );
4672 					Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( col ) );
4673 
4674 					row = gtk_text_iter_get_line ( &endIter );
4675 					col = gtk_text_iter_get_line_offset ( &endIter );
4676 
4677 					Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( row ) );
4678 					Tcl_ListObjAppendElement ( interp, resList, Tcl_NewIntObj ( col ) );
4679 
4680 					Tcl_SetObjResult ( interp, resList );
4681 					return TCL_OK;
4682 
4683 				}
4684 
4685 				/* return null string if there is no selection */
4686 				Tcl_SetObjResult ( interp, Tcl_NewStringObj ( "", -1  ) );
4687 				return TCL_OK;
4688 
4689 
4690 			}
4691 			break;
4692 
4693 
4694 		case InsertIdx:
4695 			{
4696 
4697 				if ( textInsert ( buffer, interp, objc, objv, cmdNo + 1 ) != TCL_OK )
4698 				{
4699 					return -1;
4700 				}
4701 			}
4702 			/*  this action needs to emit an insert text signal */
4703 
4704 			break;
4705 
4706 		case MarkIdx:
4707 			{
4708 				if ( markCmd ( buffer, interp, objc, objv, cmdNo + 1 ) != TCL_OK )
4709 				{
4710 					return -1;
4711 				}
4712 			}
4713 			break;
4714 
4715 		case TagIdx:
4716 			{
4717 				if ( tagCmd ( buffer, interp, objc, objv, cmdNo + 1 ) != TCL_OK )
4718 				{
4719 					return -1;
4720 				}
4721 			}
4722 			break;
4723 
4724 			/*  the widget dump has the format;
4725 			 *  widgetId dump option startIndex endIndx
4726 			 */
4727 		case DumpIdx:
4728 			{
4729 				/*  some DEBUG_TEXTging feedback */
4730 
4731 #ifdef DEBUG_TAGS
4732 				g_print ( "\tdump: %d %d: %s %s %s %s\n",
4733 						  objc, cmdNo + 4,
4734 						  Tcl_GetString ( objv[cmdNo] ),
4735 						  Tcl_GetString ( objv[cmdNo+1] ),
4736 						  Tcl_GetString ( objv[cmdNo+2] ),
4737 						  Tcl_GetString ( objv[cmdNo+3] ) ) ;
4738 #endif
4739 
4740 
4741 
4742 				GtkTextIter startIter, endIter;
4743 
4744 				GtkTextTagTable *tagtable;
4745 				char *txt;
4746 				int idx;
4747 
4748 				static const char *cmds[] =
4749 				{
4750 					"all", "tags", "text",
4751 					"window", "images", "marks",
4752 					NULL
4753 				};
4754 
4755 				enum opts
4756 				{
4757 					AllIdx, TagsIdx, TextIdx,
4758 					WindowsIdx, ImagesIdx, MarksIdx
4759 				};
4760 
4761 				/*  do some error checking */
4762 
4763 				if ( objc < cmdNo + 4 )
4764 				{
4765 					Tcl_WrongNumArgs ( interp, cmdNo + 1, objv, "?all|text|tags|window|images|marks? startIndex ?endIndex?" );
4766 					return TCL_ERROR;
4767 				}
4768 
4769 				/*  get iters for the required range */
4770 
4771 				if ( posToIter ( interp, objv[cmdNo+2], buffer, &startIter ) != TCL_OK )
4772 				{
4773 					return TCL_ERROR;
4774 				}
4775 
4776 				if ( posToIter ( interp, objv[cmdNo+3], buffer, &endIter ) != TCL_OK )
4777 				{
4778 					return TCL_ERROR;
4779 				}
4780 
4781 				/*  get the sub-command, one of all, tags, text, images, marks */
4782 
4783 
4784 				if ( Tcl_GetIndexFromObj ( interp, objv[cmdNo+1], cmds, "subcommand", TCL_EXACT, &idx ) != TCL_OK )
4785 				{
4786 					return TCL_ERROR;
4787 				}
4788 
4789 #if 0
4790 				g_print ( "-----HERE\n" );
4791 #endif
4792 
4793 //getIdx ( cmds, objv[cmdNo+1], &idx );
4794 
4795 
4796 				/*
4797 				 *  Respond to the second keyword..
4798 				 */
4799 
4800 				switch ( idx )
4801 				{
4802 					case AllIdx:
4803 						{
4804 #if 0
4805 							g_print ( "-----AllIdx\n" );
4806 #endif
4807 
4808 							Tcl_Obj *res;
4809 							res = dumpAll ( interp,  buffer, &startIter, &endIter ) ;
4810 							Tcl_SetObjResult ( interp, res );
4811 							return TCL_OK;
4812 						}
4813 
4814 						break;
4815 					case TagsIdx:	/* include tagOn/Off changes in the text */
4816 						{
4817 #ifdef DEBUG_TEXT
4818 							g_print ( "dump text+tags start\n" );
4819 #endif
4820 							GtkTextTagTable *tagtable = gtk_text_buffer_get_tag_table ( buffer );
4821 
4822 							/*  get the settings of each tag in the buffer*/
4823 							/*  note, pass the address of the pointer to the data assigned by the called function */
4824 
4825 							gtk_text_tag_table_foreach ( tagtable, gnoclGetTagProperties, &txt ); //
4826 
4827 #ifdef DEBUG_TEXT
4828 							g_print ( "dump text+tags end\n" );
4829 #endif
4830 
4831 							//Tcl_SetObjResult ( interp, Tcl_NewStringObj ( txt, -1 ) );
4832 							/*  reset the outsput string by using null pointers */
4833 							//gnoclGetTagProperties ( NULL, NULL );
4834 							return TCL_OK;
4835 						}
4836 
4837 						break;
4838 					case TextIdx:
4839 						{
4840 							/*  TODO: include_hidden_chars */
4841 							txt = gtk_text_buffer_get_text ( buffer, &startIter, &endIter, 1 );
4842 							Tcl_SetObjResult ( interp, Tcl_NewStringObj ( txt, -1 ) );
4843 							return TCL_OK;
4844 						}
4845 
4846 						break;
4847 					case WindowsIdx:
4848 						{
4849 							txt = "dump windows... Feature not yet implmented\n";
4850 							Tcl_SetObjResult ( interp, Tcl_NewStringObj ( txt, -1 ) );
4851 							return TCL_OK;
4852 						}
4853 
4854 						break;
4855 					case ImagesIdx:
4856 						{
4857 							txt = "dump images... Feature not yet implmented\n";
4858 							Tcl_SetObjResult ( interp, Tcl_NewStringObj ( txt, -1 ) );
4859 							return TCL_OK;
4860 						}
4861 
4862 						break;
4863 					case MarksIdx:
4864 						{
4865 							txt = "dump marks... Feature not yet implmented\n";
4866 							Tcl_SetObjResult ( interp, Tcl_NewStringObj ( txt, -1 ) );
4867 							return TCL_OK;
4868 						}
4869 
4870 						break;
4871 					default:
4872 						{
4873 							assert ( 0 );
4874 						}
4875 				}
4876 
4877 				return TCL_OK;
4878 
4879 			}
4880 
4881 			break;
4882 
4883 		default:
4884 			assert ( 0 );
4885 			return -1;
4886 	}
4887 
4888 	return 0;
4889 }
4890 
4891 
4892 
4893 /**
4894 \brief      ** USING ** TEXTPARAMS
4895 			Handler for gnocl created instances that take into account the scrolled window
4896 \note       Unlike gnocl, Builder/Glade  not provide text objects within scrolled windows.
4897             Two handle functions are necessary, one for gnocl built widgets, and one for builder/glade widgets.
4898 **/
4899 
textFunc(ClientData data,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])4900 static int textFunc ( ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *  const objv[] )
4901 {
4902 	TextParams *para = ( TextParams * ) data;
4903 
4904 	GtkScrolledWindow   *scrolled = para->scrolled;
4905 	GtkTextView     *text = GTK_TEXT_VIEW ( gtk_bin_get_child ( GTK_BIN ( scrolled ) ) );
4906 	GtkTextBuffer  *buffer = gtk_text_view_get_buffer ( text );
4907 
4908 #ifdef DEBUG_TEXT_TEXT
4909 	g_printf ( "textFunc\n" );
4910 	gint _i;
4911 
4912 	for ( _i = 0; _i < objc; _i++ )
4913 	{
4914 		g_print ( "\targ %d = %s\n", _i,  Tcl_GetString ( objv[_i] ) );
4915 	}
4916 
4917 #endif
4918 
4919 
4920 	if ( objc < 2 )
4921 	{
4922 		Tcl_WrongNumArgs ( interp, 1, objv, "command" );
4923 		return TCL_ERROR;
4924 	}
4925 
4926 	/*
4927 		case DeleteIdx:         return 1;
4928 		case ConfigureIdx:      return 2;
4929 		case ScrollToPosIdx:    return 3;
4930 		case ScrollToMarkIdx:   return 4;
4931 		case ParentIdx:         return 5;
4932 		case GetIndexIdx:       return 6;
4933 		case GetCoordsIdx:      return 7;
4934 		case GetRectIdx:        return 8;
4935 		case UndoIdx:  			return 9;
4936 		case RedoIdx:  			return 10;
4937 		case GrabFocusIdx:  	return 11;
4938 		case ResetUndoIdx:  	return 12;
4939 		case GetPosIdx: 		return 13;
4940 		case HasFocus			return 14;
4941 	*/
4942 
4943 	switch ( gnoclTextCommand ( text, interp, objc, objv, 1, 1 ) )
4944 	{
4945 			/*  these are command which work upon the GtkTextView rather than the GtkTextBuffer */
4946 		case 0: /*  return TCL_OK */
4947 			{
4948 				break;
4949 			}
4950 		case 1:  /*  delete */
4951 			{
4952 				return gnoclDelete ( interp, GTK_WIDGET ( scrolled ), objc, objv );
4953 			}
4954 		case 2:     /*  configure */
4955 			{
4956 				int ret = TCL_ERROR;
4957 
4958 				if ( gnoclParseAndSetOptions ( interp, objc - 1, objv + 1, textOptions, G_OBJECT ( text ) ) == TCL_OK )
4959 				{
4960 					//ret = configure ( interp, scrolled, text, para, textOptions );
4961 					ret = configure ( interp, para, textOptions );
4962 				}
4963 
4964 				gnoclClearOptions ( textOptions );
4965 
4966 				return ret;
4967 			}
4968 
4969 			break;
4970 		case 3: /*  scrollToPosition */
4971 			{
4972 				return scrollToPos ( text, buffer, interp, objc, objv );
4973 			}
4974 		case 4: /*  scrollToMark */
4975 			{
4976 				return scrollToMark ( text, buffer, interp, objc, objv );
4977 			}
4978 		case 5: /*  get parent, WJG added 06/12/08 */
4979 			{
4980 				GtkWidget *  parent;
4981 				Tcl_Obj *obj = NULL;
4982 				parent = gtk_widget_get_parent ( GTK_WIDGET ( data ) );
4983 				obj = Tcl_NewStringObj ( gnoclGetNameFromWidget ( parent ), -1 );
4984 				Tcl_SetObjResult ( interp, obj );
4985 
4986 				/*  this function not working too well! */
4987 				/*  return gnoclGetParent ( interp, data ); */
4988 				return TCL_OK;
4989 			}
4990 
4991 			break;
4992 			// getIndex
4993 		case 6: /* get line/row from root window coordinates, ie passed from an event */
4994 			{
4995 
4996 				//g_print ( "tag getIndex\n" );
4997 
4998 				GtkTextIter iter;
4999 				gint y, line_no;
5000 				gint x, row_no;
5001 
5002 				gint wx, wy; /* window coordinates */
5003 				gint bx, by; /* buffer coordinates */
5004 				gint line, row;
5005 
5006 				//sscanf ( Tcl_GetString ( objv[2] ), "%d %d", &wx, &wy );
5007 
5008 				Tcl_GetIntFromObj ( NULL, objv[2], &wx ) ;
5009 				Tcl_GetIntFromObj ( NULL, objv[3], &wy ) ;
5010 
5011 				//g_print ( "1\n" );
5012 
5013 				//gdk_window_get_pointer (TxT->window, &wx, &wy, NULL);
5014 				gtk_text_view_window_to_buffer_coords ( text, GTK_TEXT_WINDOW_WIDGET, wx, wy, &bx, &by );
5015 				gtk_text_view_get_iter_at_location ( text, &iter, bx, by );
5016 
5017 				//gtk_text_layout_get_iter_at_pixel (text->layout, &iter, x, y);
5018 
5019 				//g_print ( "2\n" );
5020 
5021 
5022 				line = gtk_text_iter_get_line ( &iter );
5023 				row = gtk_text_iter_get_line_offset ( &iter );
5024 
5025 				//g_print ( "3\n" );
5026 
5027 				gchar str[16];
5028 				sprintf ( str, "%d %d", line, row );
5029 
5030 				//g_print ( "4\n" );
5031 
5032 				Tcl_SetObjResult ( interp, Tcl_NewStringObj ( str, -1 ) );
5033 
5034 			}
5035 			break;
5036 
5037 			/* past line col position, return window location */
5038 		case 7: /* window x/y coords from iter */
5039 			{
5040 
5041 				gint wx;
5042 				gint wy;
5043 
5044 				GtkTextIter iter;
5045 				GdkRectangle rect;
5046 
5047 				if ( posToIter ( interp, objv[2], buffer, &iter ) != TCL_OK )
5048 				{
5049 					return TCL_ERROR;
5050 				}
5051 
5052 				gtk_text_view_get_iter_location  ( text, &iter, &rect );
5053 
5054 				// this line returns the buffer coordinates as window cooordinates!
5055 				gtk_text_view_buffer_to_window_coords ( text, GTK_TEXT_WINDOW_WIDGET, rect.x, rect.y, &wx, &wy );
5056 
5057 				gchar str[24];
5058 				sprintf ( str, "%d %d %d %d\n", wx, wy, rect.width, rect.height );
5059 				Tcl_SetObjResult ( interp, Tcl_NewStringObj ( str, -1 ) );
5060 
5061 			}
5062 			break;
5063 		case 8: /* get visible rect */
5064 			{
5065 				GdkRectangle rect;
5066 
5067 				gtk_text_view_get_visible_rect ( text, &rect );
5068 
5069 				gchar str[24];
5070 				sprintf ( str, "%d %d %d %d\n", rect.x, rect.y, rect.width, rect.height );
5071 				Tcl_SetObjResult ( interp, Tcl_NewStringObj ( str, -1 ) );
5072 
5073 			}
5074 			break;
5075 		case 9: /* undo action */
5076 			{
5077 				gtk_undo_view_undo ( text );
5078 			}
5079 			break;
5080 		case 10: /* redo action */
5081 			{
5082 				gtk_undo_view_redo  ( text );
5083 			}
5084 		case 11: /* grab keyboard input */
5085 			{
5086 				gtk_widget_grab_focus ( text );
5087 				return TCL_OK;
5088 			}
5089 		case 12: /* reset Undo/Redo buffer */
5090 			{
5091 
5092 				gtk_undo_view_reset ( text );
5093 
5094 				return TCL_OK;
5095 			}
5096 
5097 		case 13: /* get iter at pixel */
5098 			{
5099 
5100 				//GtkTextIter iter;
5101 				//gtk_text_layout_get_iter_at_pixel (text->layout, &iter, x, y);
5102 				return TCL_OK;
5103 			}
5104 
5105 		case 14: /* does the widget have focus */
5106 			{
5107 
5108 				//GtkTextIter iter;
5109 				//gtk_text_layout_get_iter_at_pixel (text->layout, &iter, x, y);
5110 				Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gtk_widget_has_focus ( text ) ) );
5111 				return TCL_OK;
5112 			}
5113 
5114 		case 15: /* does the widget have focus */
5115 			{
5116 
5117 				//GtkTextIter iter;
5118 				//gtk_text_layout_get_iter_at_pixel (text->layout, &iter, x, y);
5119 				Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gtk_widget_is_focus ( text ) ) );
5120 				return TCL_OK;
5121 			}
5122 
5123 
5124 		default:
5125 			{
5126 				return TCL_ERROR;
5127 			}
5128 	}
5129 
5130 	return TCL_OK;
5131 }
5132 
5133 
5134 /**
5135 \brief      Handler for glade created instances that have no scrolled window.
5136 **/
textViewFunc(ClientData data,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])5137 int textViewFunc ( ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *  const objv[] )
5138 {
5139 
5140 	GtkTextView    *text = GTK_TEXT_VIEW ( data );
5141 	GtkTextBuffer  *buffer = gtk_text_view_get_buffer ( text );
5142 
5143 	if ( objc < 2 )
5144 	{
5145 		Tcl_WrongNumArgs ( interp, 1, objv, "command" );
5146 		return TCL_ERROR;
5147 	}
5148 
5149 	switch ( gnoclTextCommand ( text, interp, objc, objv, 1, 1 ) )
5150 	{
5151 			/*  these are command which work upon the GtkTextView rather than the GtkTextBuffer */
5152 		case 0:
5153 			break;  /*  return TCL_OK */
5154 		case 1:     /*  delete */
5155 			//return gnoclDelete ( interp, GTK_WIDGET ( scrolled ), objc, objv );
5156 		case 2:     /*  configure */
5157 			{
5158 				int ret = TCL_ERROR;
5159 
5160 				if ( gnoclParseAndSetOptions ( interp, objc - 1, objv + 1, textOptions, G_OBJECT ( text ) ) == TCL_OK )
5161 				{
5162 					//ret = configure ( interp, scrolled, text, para, textOptions );
5163 					//ret = configure ( interp, scrolled, text, textOptions );
5164 				}
5165 
5166 				gnoclClearOptions ( textOptions );
5167 
5168 				return ret;
5169 			}
5170 
5171 			break;
5172 		case 3: /*  scrollToPosition */
5173 			return scrollToPos ( text, buffer, interp, objc, objv );
5174 		case 4: /*  scrollToMark */
5175 			return scrollToMark ( text, buffer, interp, objc, objv );
5176 		case 5: /*  get parent, WJG added 06/12/08 */
5177 			{
5178 				GtkWidget *  parent;
5179 				Tcl_Obj *obj = NULL;
5180 				parent = gtk_widget_get_parent ( GTK_WIDGET ( data ) );
5181 				obj = Tcl_NewStringObj ( gnoclGetNameFromWidget ( parent ), -1 );
5182 				Tcl_SetObjResult ( interp, obj );
5183 
5184 				/*  this function not working too well! */
5185 				/*  return gnoclGetParent ( interp, data ); */
5186 				return TCL_OK;
5187 			}
5188 
5189 			break;
5190 		case 6: /* grab keyboard input */
5191 			{
5192 				gtk_widget_grab_focus ( text );
5193 				return TCL_OK;
5194 			}
5195 			break;
5196 		default:
5197 			{
5198 				return TCL_ERROR;
5199 			}
5200 	}
5201 
5202 	return TCL_OK;
5203 }
5204 
5205 
5206 /**
5207 \brief	Create a fully developed text megawidget.
5208 \note	** USING ** TEXTPARAMS
5209 **/
gnoclTextCmd(ClientData data,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])5210 int gnoclTextCmd ( ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *  const objv[] )
5211 {
5212 	if ( gnoclGetCmdsAndOpts ( interp, cmds, textOptions, objv, objc ) == TCL_OK )
5213 	{
5214 		return TCL_OK;
5215 	}
5216 
5217 	TextParams *para;
5218 
5219 	int               ret, k;
5220 	GtkTextView       *textView;
5221 	GtkTextView       *textBuffer;
5222 	GtkScrolledWindow *scrolled;
5223 
5224 	para = g_new ( TextParams, 1 );
5225 
5226 	para->interp = interp;
5227 	para->textVariable = NULL;
5228 	para->onChanged = NULL;
5229 	para->inSetVar = 0;
5230 	para->useMarkup = FALSE;
5231 
5232 
5233 	if ( gnoclParseOptions ( interp, objc, objv, textOptions ) != TCL_OK )
5234 	{
5235 		gnoclClearOptions ( textOptions );
5236 		return TCL_ERROR;
5237 	}
5238 
5239 	//textView = GTK_TEXT_VIEW ( gtk_text_view_new( ) );
5240 
5241 	// implement new undo/redo buffer
5242 	textView = gtk_undo_view_new ( gtk_text_buffer_new  ( NULL ) );
5243 
5244 	para->scrolled =  GTK_SCROLLED_WINDOW ( gtk_scrolled_window_new ( NULL, NULL ) );
5245 
5246 	gtk_scrolled_window_set_policy ( para->scrolled, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
5247 
5248 	gtk_container_add ( GTK_CONTAINER ( para->scrolled ), GTK_WIDGET ( textView ) );
5249 
5250 	gtk_widget_show_all ( GTK_WIDGET ( para->scrolled ) );
5251 
5252 	//add some extra signals to the default setting -these have no effect!!!
5253 	gtk_widget_add_events ( textView, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK );
5254 
5255 	ret = gnoclSetOptions ( interp, textOptions, G_OBJECT ( textView ), -1 );
5256 
5257 
5258 	if ( ret == TCL_OK )
5259 	{
5260 		ret = configure ( interp, para, textOptions );
5261 	}
5262 
5263 	gnoclClearOptions ( textOptions );
5264 
5265 	if ( ret != TCL_OK )
5266 	{
5267 		gtk_widget_destroy ( GTK_WIDGET ( para->scrolled ) );
5268 		return TCL_ERROR;
5269 	}
5270 
5271 	para->name = gnoclGetAutoWidgetId();
5272 
5273 	g_signal_connect ( G_OBJECT ( para->scrolled ), "destroy", G_CALLBACK ( destroyFunc ), para );
5274 
5275 	gnoclMemNameAndWidget ( para->name, GTK_WIDGET ( para->scrolled ) );
5276 
5277 	Tcl_CreateObjCommand ( interp, para->name, textFunc, para, NULL );
5278 
5279 	Tcl_SetObjResult ( interp, Tcl_NewStringObj ( para->name, -1 ) );
5280 
5281 	return TCL_OK;
5282 
5283 }
5284 
5285 
5286 /**
5287 \brief	Create a plain vanilla GtkTextView widget
5288 \todo	Create modified version of the configure command
5289 **/
gnoclTextViewCmd(ClientData data,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])5290 int gnoclTextViewCmd ( ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *  const objv[] )
5291 {
5292 
5293 	TextParams *para;
5294 
5295 	int               ret, k;
5296 	GtkTextView       *textView;
5297 	GtkTextView       *textBuffer;
5298 
5299 
5300 	if ( gnoclParseOptions ( interp, objc, objv, textOptions ) != TCL_OK )
5301 	{
5302 		gnoclClearOptions ( textOptions );
5303 		return TCL_ERROR;
5304 	}
5305 
5306 	// implement new undo/redo buffer
5307 	textView = gtk_undo_view_new ( gtk_text_buffer_new  ( NULL ) );
5308 
5309 
5310 	gtk_widget_show_all ( GTK_WIDGET ( textView ) );
5311 
5312 	//add some extra signals to the default setting -these have no effect!!!
5313 	gtk_widget_add_events ( textView, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK );
5314 
5315 	ret = gnoclSetOptions ( interp, textOptions, G_OBJECT ( textView ), -1 );
5316 
5317 
5318 	if ( ret == TCL_OK )
5319 	{
5320 		ret = configure_textView ( interp, textView, textOptions );
5321 	}
5322 
5323 	gnoclClearOptions ( textOptions );
5324 
5325 	if ( ret != TCL_OK )
5326 	{
5327 		gtk_widget_destroy ( GTK_WIDGET ( textView ) );
5328 		return TCL_ERROR;
5329 	}
5330 
5331 	return gnoclRegisterWidget ( interp, textView, textViewFunc );
5332 
5333 }
5334