]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/textview.c
2870bb11fa8327d7e1f43a075691016fdad85b57
[~andy/gtk] / demos / gtk-demo / textview.c
1 /* Text Widget
2  *
3  * The GtkTextView widget displays a GtkTextBuffer. One GtkTextBuffer
4  * can be displayed by multiple GtkTextViews. This demo has two views
5  * displaying a single buffer, and shows off the widget's text
6  * formatting features.
7  *
8  */
9
10 #include <gtk/gtk.h>
11 #include <stdlib.h> /* for exit() */
12
13 #include "demo-common.h"
14
15 static void easter_egg_callback (GtkWidget *button, gpointer data);
16
17 #define gray50_width 2
18 #define gray50_height 2
19 static char gray50_bits[] = {
20   0x02, 0x01
21 };
22
23 static void
24 create_tags (GtkTextBuffer *buffer)
25 {
26   GdkBitmap *stipple;
27
28   /* Create a bunch of tags. Note that it's also possible to
29    * create tags with gtk_text_tag_new() then add them to the
30    * tag table for the buffer, gtk_text_buffer_create_tag() is
31    * just a convenience function. Also note that you don't have
32    * to give tags a name; pass NULL for the name to create an
33    * anonymous tag.
34    *
35    * In any real app, another useful optimization would be to create
36    * a GtkTextTagTable in advance, and reuse the same tag table for
37    * all the buffers with the same tag set, instead of creating
38    * new copies of the same tags for every buffer.
39    *
40    * Tags are assigned default priorities in order of addition to the
41    * tag table.  That is, tags created later that affect the same text
42    * property affected by an earlier tag will override the earlier
43    * tag.  You can modify tag priorities with
44    * gtk_text_tag_set_priority().
45    */
46
47   gtk_text_buffer_create_tag (buffer, "heading",
48                               "weight", PANGO_WEIGHT_BOLD,
49                               "size", 15 * PANGO_SCALE,
50                               NULL);
51   
52   gtk_text_buffer_create_tag (buffer, "italic",
53                               "style", PANGO_STYLE_ITALIC, NULL);
54
55   gtk_text_buffer_create_tag (buffer, "bold",
56                               "weight", PANGO_WEIGHT_BOLD, NULL);  
57   
58   gtk_text_buffer_create_tag (buffer, "big",
59                               /* points times the PANGO_SCALE factor */
60                               "size", 20 * PANGO_SCALE, NULL);
61
62   gtk_text_buffer_create_tag (buffer, "xx-small",
63                               "scale", PANGO_SCALE_XX_SMALL, NULL);
64
65   gtk_text_buffer_create_tag (buffer, "x-large",
66                               "scale", PANGO_SCALE_X_LARGE, NULL);
67   
68   gtk_text_buffer_create_tag (buffer, "monospace",
69                               "family", "monospace", NULL);
70   
71   gtk_text_buffer_create_tag (buffer, "blue_foreground",
72                               "foreground", "blue", NULL);  
73
74   gtk_text_buffer_create_tag (buffer, "red_background",
75                               "background", "red", NULL);
76
77   stipple = gdk_bitmap_create_from_data (NULL,
78                                          gray50_bits, gray50_width,
79                                          gray50_height);
80   
81   gtk_text_buffer_create_tag (buffer, "background_stipple",
82                               "background_stipple", stipple, NULL);
83
84   gtk_text_buffer_create_tag (buffer, "foreground_stipple",
85                               "foreground_stipple", stipple, NULL);
86
87   g_object_unref (stipple);
88
89   gtk_text_buffer_create_tag (buffer, "big_gap_before_line",
90                               "pixels_above_lines", 30, NULL);
91
92   gtk_text_buffer_create_tag (buffer, "big_gap_after_line",
93                               "pixels_below_lines", 30, NULL);
94
95   gtk_text_buffer_create_tag (buffer, "double_spaced_line",
96                               "pixels_inside_wrap", 10, NULL);
97
98   gtk_text_buffer_create_tag (buffer, "not_editable",
99                               "editable", FALSE, NULL);
100   
101   gtk_text_buffer_create_tag (buffer, "word_wrap",
102                               "wrap_mode", GTK_WRAP_WORD, NULL);
103
104   gtk_text_buffer_create_tag (buffer, "char_wrap",
105                               "wrap_mode", GTK_WRAP_CHAR, NULL);
106
107   gtk_text_buffer_create_tag (buffer, "no_wrap",
108                               "wrap_mode", GTK_WRAP_NONE, NULL);
109   
110   gtk_text_buffer_create_tag (buffer, "center",
111                               "justification", GTK_JUSTIFY_CENTER, NULL);
112
113   gtk_text_buffer_create_tag (buffer, "right_justify",
114                               "justification", GTK_JUSTIFY_RIGHT, NULL);
115
116   gtk_text_buffer_create_tag (buffer, "wide_margins",
117                               "left_margin", 50, "right_margin", 50,
118                               NULL);
119   
120   gtk_text_buffer_create_tag (buffer, "strikethrough",
121                               "strikethrough", TRUE, NULL);
122   
123   gtk_text_buffer_create_tag (buffer, "underline",
124                               "underline", PANGO_UNDERLINE_SINGLE, NULL);
125
126   gtk_text_buffer_create_tag (buffer, "double_underline",
127                               "underline", PANGO_UNDERLINE_DOUBLE, NULL);
128
129   gtk_text_buffer_create_tag (buffer, "superscript",
130                               "rise", 10 * PANGO_SCALE,   /* 10 pixels */
131                               "size", 8 * PANGO_SCALE,    /* 8 points */
132                               NULL);
133   
134   gtk_text_buffer_create_tag (buffer, "subscript",
135                               "rise", -10 * PANGO_SCALE,   /* 10 pixels */
136                               "size", 8 * PANGO_SCALE,     /* 8 points */
137                               NULL);
138
139   gtk_text_buffer_create_tag (buffer, "rtl_quote",
140                               "wrap_mode", GTK_WRAP_WORD,
141                               "direction", GTK_TEXT_DIR_RTL,
142                               "indent", 30,
143                               "left_margin", 20,
144                               "right_margin", 20,
145                               NULL);
146 }
147
148 static void
149 insert_text (GtkTextBuffer *buffer)
150 {
151   GtkTextIter iter;
152   GtkTextIter start, end;
153   GdkPixbuf *pixbuf;
154   GdkPixbuf *scaled;
155   GtkTextChildAnchor *anchor;
156   char *filename;
157
158   /* demo_find_file() looks in the the current directory first,
159    * so you can run gtk-demo without installing GTK, then looks
160    * in the location where the file is installed.
161    */
162   pixbuf = NULL;
163   filename = demo_find_file ("gtk-logo-rgb.gif", NULL);
164   if (filename)
165     {
166       pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
167       g_free (filename);
168     }
169
170   if (pixbuf == NULL)
171     {
172       g_printerr ("Failed to load image file gtk-logo-rgb.gif\n");
173       exit (1);
174     }
175
176   scaled = gdk_pixbuf_scale_simple (pixbuf, 32, 32, GDK_INTERP_BILINEAR);
177   g_object_unref (pixbuf);
178   pixbuf = scaled;
179   
180   /* get start of buffer; each insertion will revalidate the
181    * iterator to point to just after the inserted text.
182    */
183   gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
184
185   gtk_text_buffer_insert (buffer, &iter, "The text widget can display text with all kinds of nifty attributes. It also supports multiple views of the same buffer; this demo is showing the same buffer in two places.\n\n", -1);
186
187   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Font styles. ", -1,
188                                             "heading", NULL);
189   
190   gtk_text_buffer_insert (buffer, &iter, "For example, you can have ", -1);
191   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
192                                             "italic", -1,
193                                             "italic", NULL);
194   gtk_text_buffer_insert (buffer, &iter, ", ", -1);  
195   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
196                                             "bold", -1,
197                                             "bold", NULL);
198   gtk_text_buffer_insert (buffer, &iter, ", or ", -1);
199   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
200                                             "monospace (typewriter)", -1,
201                                             "monospace", NULL);
202   gtk_text_buffer_insert (buffer, &iter, ", or ", -1);
203   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
204                                             "big", -1,
205                                             "big", NULL);
206   gtk_text_buffer_insert (buffer, &iter, " text. ", -1);
207   gtk_text_buffer_insert (buffer, &iter, "It's best not to hardcode specific text sizes; you can use relative sizes as with CSS, such as ", -1);
208   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
209                                             "xx-small", -1,
210                                             "xx-small", NULL);
211   gtk_text_buffer_insert (buffer, &iter, " or ", -1);
212   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
213                                             "x-large", -1,
214                                             "x-large", NULL);
215   gtk_text_buffer_insert (buffer, &iter, " to ensure that your program properly adapts if the user changes the default font size.\n\n", -1);
216   
217   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Colors. ", -1,
218                                             "heading", NULL);
219   
220   gtk_text_buffer_insert (buffer, &iter, "Colors such as ", -1);  
221   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
222                                             "a blue foreground", -1,
223                                             "blue_foreground", NULL);
224   gtk_text_buffer_insert (buffer, &iter, " or ", -1);  
225   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
226                                             "a red background", -1,
227                                             "red_background", NULL);
228   gtk_text_buffer_insert (buffer, &iter, " or even ", -1);  
229   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
230                                             "a stippled red background", -1,
231                                             "red_background",
232                                             "background_stipple",
233                                             NULL);
234
235   gtk_text_buffer_insert (buffer, &iter, " or ", -1);  
236   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
237                                             "a stippled blue foreground on solid red background", -1,
238                                             "blue_foreground",
239                                             "red_background",
240                                             "foreground_stipple",
241                                             NULL);
242   gtk_text_buffer_insert (buffer, &iter, " (select that to read it) can be used.\n\n", -1);  
243
244   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Underline, strikethrough, and rise. ", -1,
245                                             "heading", NULL);
246   
247   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
248                                             "Strikethrough", -1,
249                                             "strikethrough", NULL);
250   gtk_text_buffer_insert (buffer, &iter, ", ", -1);
251   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
252                                             "underline", -1,
253                                             "underline", NULL);
254   gtk_text_buffer_insert (buffer, &iter, ", ", -1);
255   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
256                                             "double underline", -1, 
257                                             "double_underline", NULL);
258   gtk_text_buffer_insert (buffer, &iter, ", ", -1);
259   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
260                                             "superscript", -1,
261                                             "superscript", NULL);
262   gtk_text_buffer_insert (buffer, &iter, ", and ", -1);
263   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
264                                             "subscript", -1,
265                                             "subscript", NULL);
266   gtk_text_buffer_insert (buffer, &iter, " are all supported.\n\n", -1);
267
268   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Images. ", -1,
269                                             "heading", NULL);
270   
271   gtk_text_buffer_insert (buffer, &iter, "The buffer can have images in it: ", -1);
272   gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
273   gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
274   gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
275   gtk_text_buffer_insert (buffer, &iter, " for example.\n\n", -1);
276
277   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Spacing. ", -1,
278                                             "heading", NULL);
279
280   gtk_text_buffer_insert (buffer, &iter, "You can adjust the amount of space before each line.\n", -1);
281   
282   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
283                                             "This line has a whole lot of space before it.\n", -1,
284                                             "big_gap_before_line", "wide_margins", NULL);
285   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
286                                             "You can also adjust the amount of space after each line; this line has a whole lot of space after it.\n", -1,
287                                             "big_gap_after_line", "wide_margins", NULL);
288   
289   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
290                                             "You can also adjust the amount of space between wrapped lines; this line has extra space between each wrapped line in the same paragraph. To show off wrapping, some filler text: the quick brown fox jumped over the lazy dog. Blah blah blah blah blah blah blah blah blah.\n", -1,
291                                             "double_spaced_line", "wide_margins", NULL);
292
293   gtk_text_buffer_insert (buffer, &iter, "Also note that those lines have extra-wide margins.\n\n", -1);
294
295   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Editability. ", -1,
296                                             "heading", NULL);
297   
298   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
299                                             "This line is 'locked down' and can't be edited by the user - just try it! You can't delete this line.\n\n", -1,
300                                             "not_editable", NULL);
301
302   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Wrapping. ", -1,
303                                             "heading", NULL);
304
305   gtk_text_buffer_insert (buffer, &iter,
306                           "This line (and most of the others in this buffer) is word-wrapped, using the proper Unicode algorithm. Word wrap should work in all scripts and languages that GTK+ supports. Let's make this a long paragraph to demonstrate: blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah\n\n", -1);  
307   
308   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
309                                             "This line has character-based wrapping, and can wrap between any two character glyphs. Let's make this a long paragraph to demonstrate: blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah\n\n", -1,
310                                             "char_wrap", NULL);
311   
312   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
313                                             "This line has all wrapping turned off, so it makes the horizontal scrollbar appear.\n\n\n", -1,
314                                             "no_wrap", NULL);
315
316   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Justification. ", -1,
317                                             "heading", NULL);  
318   
319   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
320                                             "\nThis line has center justification.\n", -1,
321                                             "center", NULL);
322
323   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
324                                             "This line has right justification.\n", -1,
325                                             "right_justify", NULL);
326
327   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
328                                             "\nThis line has big wide margins. Text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text.\n", -1,
329                                             "wide_margins", NULL);  
330
331   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Internationalization. ", -1,
332                                             "heading", NULL);
333           
334   gtk_text_buffer_insert (buffer, &iter,
335                           "You can put all sorts of Unicode text in the buffer.\n\nGerman (Deutsch Süd) Grüß Gott\nGreek (Ελληνικά) Γειά σας\nHebrew  שלום\nJapanese (日本語)\n\nThe widget properly handles bidirectional text, word wrapping, DOS/UNIX/Unicode paragraph separators, grapheme boundaries, and so on using the Pango internationalization framework.\n", -1);  
336
337   gtk_text_buffer_insert (buffer, &iter, "Here's a word-wrapped quote in a right-to-left language:\n", -1);
338   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n\n", -1,
339                                                 "rtl_quote", NULL);
340       
341   gtk_text_buffer_insert (buffer, &iter, "You can put widgets in the buffer: Here's a button: ", -1);
342   anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
343   gtk_text_buffer_insert (buffer, &iter, " and a menu: ", -1);
344   anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
345   gtk_text_buffer_insert (buffer, &iter, " and a scale: ", -1);
346   anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
347   gtk_text_buffer_insert (buffer, &iter, " and an animation: ", -1);
348   anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
349   gtk_text_buffer_insert (buffer, &iter, " finally a text entry: ", -1);
350   anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
351   gtk_text_buffer_insert (buffer, &iter, ".\n", -1);
352   
353   gtk_text_buffer_insert (buffer, &iter, "\n\nThis demo doesn't demonstrate all the GtkTextBuffer features; it leaves out, for example: invisible/hidden text (doesn't work in GTK 2, but planned), tab stops, application-drawn areas on the sides of the widget for displaying breakpoints and such...", -1);
354
355   /* Apply word_wrap tag to whole buffer */
356   gtk_text_buffer_get_bounds (buffer, &start, &end);
357   gtk_text_buffer_apply_tag_by_name (buffer, "word_wrap", &start, &end);
358
359   g_object_unref (pixbuf);
360 }
361
362 static gboolean
363 find_anchor (GtkTextIter *iter)
364 {
365   while (gtk_text_iter_forward_char (iter))
366     {
367       if (gtk_text_iter_get_child_anchor (iter))
368         return TRUE;
369     }
370   return FALSE;
371 }
372
373 static void
374 attach_widgets (GtkTextView *text_view)
375 {
376   GtkTextIter iter;
377   GtkTextBuffer *buffer;
378   int i;
379   
380   buffer = gtk_text_view_get_buffer (text_view);
381
382   gtk_text_buffer_get_start_iter (buffer, &iter);
383
384   i = 0;
385   while (find_anchor (&iter))
386     {
387       GtkTextChildAnchor *anchor;
388       GtkWidget *widget;
389       
390       anchor = gtk_text_iter_get_child_anchor (&iter);
391
392       if (i == 0)
393         {
394           widget = gtk_button_new_with_label ("Click Me");
395
396           g_signal_connect (widget, "clicked",
397                             G_CALLBACK (easter_egg_callback),
398                             NULL);
399         }
400       else if (i == 1)
401         {
402           GtkWidget *menu_item;
403           GtkWidget *menu;
404
405           menu = gtk_menu_new ();
406           
407           widget = gtk_option_menu_new ();
408
409           menu_item = gtk_menu_item_new_with_label ("Option 1");
410           gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
411           menu_item = gtk_menu_item_new_with_label ("Option 2");
412           gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
413           menu_item = gtk_menu_item_new_with_label ("Option 3");
414           gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
415
416           gtk_option_menu_set_menu (GTK_OPTION_MENU (widget), menu);
417         }
418       else if (i == 2)
419         {
420           widget = gtk_hscale_new (NULL);
421           gtk_range_set_range (GTK_RANGE (widget), 0, 100);
422           gtk_widget_set_size_request (widget, 70, -1);
423         }
424       else if (i == 3)
425         {
426           gchar *filename = demo_find_file ("floppybuddy.gif", NULL);
427           widget = gtk_image_new_from_file (filename);
428           g_free (filename);
429         }
430       else if (i == 4)
431         {
432           widget = gtk_entry_new ();
433         }
434       else
435         {
436           widget = NULL; /* avoids a compiler warning */
437           g_assert_not_reached ();
438         }
439
440       gtk_text_view_add_child_at_anchor (text_view,
441                                          widget,
442                                          anchor);
443
444       gtk_widget_show_all (widget);
445
446       ++i;
447     }
448 }
449
450 GtkWidget *
451 do_textview (void)
452 {
453   static GtkWidget *window = NULL;
454
455   if (!window)
456     {
457       GtkWidget *vpaned;
458       GtkWidget *view1;
459       GtkWidget *view2;
460       GtkWidget *sw;
461       GtkTextBuffer *buffer;
462       
463       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
464       gtk_window_set_default_size (GTK_WINDOW (window),
465                                    450, 450);
466       
467       g_signal_connect (window, "destroy",
468                         G_CALLBACK (gtk_widget_destroyed), &window);
469
470       gtk_window_set_title (GTK_WINDOW (window), "TextView");
471       gtk_container_set_border_width (GTK_CONTAINER (window), 0);
472
473       vpaned = gtk_vpaned_new ();
474       gtk_container_set_border_width (GTK_CONTAINER(vpaned), 5);
475       gtk_container_add (GTK_CONTAINER (window), vpaned);
476
477       /* For convenience, we just use the autocreated buffer from
478        * the first text view; you could also create the buffer
479        * by itself with gtk_text_buffer_new(), then later create
480        * a view widget.
481        */
482       view1 = gtk_text_view_new ();
483       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view1));
484       view2 = gtk_text_view_new_with_buffer (buffer);
485       
486       sw = gtk_scrolled_window_new (NULL, NULL);
487       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
488                                       GTK_POLICY_AUTOMATIC,
489                                       GTK_POLICY_AUTOMATIC);
490       gtk_paned_add1 (GTK_PANED (vpaned), sw);
491
492       gtk_container_add (GTK_CONTAINER (sw), view1);
493
494       sw = gtk_scrolled_window_new (NULL, NULL);
495       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
496                                       GTK_POLICY_AUTOMATIC,
497                                       GTK_POLICY_AUTOMATIC);
498       gtk_paned_add2 (GTK_PANED (vpaned), sw);
499
500       gtk_container_add (GTK_CONTAINER (sw), view2);
501
502       create_tags (buffer);
503       insert_text (buffer);
504
505       attach_widgets (GTK_TEXT_VIEW (view1));
506       attach_widgets (GTK_TEXT_VIEW (view2));
507       
508       gtk_widget_show_all (vpaned);
509     }
510
511   if (!GTK_WIDGET_VISIBLE (window))
512     {
513       gtk_widget_show (window);
514     }
515   else
516     {
517       gtk_widget_destroy (window);
518       window = NULL;
519     }
520
521   return window;
522 }
523
524 static void
525 recursive_attach_view (int                 depth,
526                        GtkTextView        *view,
527                        GtkTextChildAnchor *anchor)
528 {
529   GtkWidget *child_view;
530   GtkWidget *event_box;
531   GdkColor color;
532   GtkWidget *align;
533   
534   if (depth > 4)
535     return;
536   
537   child_view = gtk_text_view_new_with_buffer (gtk_text_view_get_buffer (view));
538
539   /* Event box is to add a black border around each child view */
540   event_box = gtk_event_box_new ();
541   gdk_color_parse ("black", &color);
542   gtk_widget_modify_bg (event_box, GTK_STATE_NORMAL, &color);
543
544   align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
545   gtk_container_set_border_width (GTK_CONTAINER (align), 1);
546   
547   gtk_container_add (GTK_CONTAINER (event_box), align);
548   gtk_container_add (GTK_CONTAINER (align), child_view);
549   
550   gtk_text_view_add_child_at_anchor (view, event_box, anchor);
551
552   recursive_attach_view (depth + 1, GTK_TEXT_VIEW (child_view), anchor);
553 }
554
555 static void
556 easter_egg_callback (GtkWidget *button,
557                      gpointer   data)
558 {
559   static GtkWidget *window = NULL;
560   GtkTextBuffer *buffer;
561   GtkWidget     *view;
562   GtkTextIter    iter;
563   GtkTextChildAnchor *anchor;
564   GtkWidget *sw;
565
566   if (window)
567     {
568       gtk_window_present (GTK_WINDOW (window));
569       return;
570     }
571   
572   buffer = gtk_text_buffer_new (NULL);
573
574   gtk_text_buffer_get_start_iter (buffer, &iter);
575
576   gtk_text_buffer_insert (buffer, &iter,
577                           "This buffer is shared by a set of nested text views.\n Nested view:\n", -1);
578   anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
579   gtk_text_buffer_insert (buffer, &iter,
580                           "\nDon't do this in real applications, please.\n", -1);
581
582   view = gtk_text_view_new_with_buffer (buffer);
583   
584   recursive_attach_view (0, GTK_TEXT_VIEW (view), anchor);
585   
586   g_object_unref (buffer);
587
588   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
589   sw = gtk_scrolled_window_new (NULL, NULL);
590   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
591                                   GTK_POLICY_AUTOMATIC,
592                                   GTK_POLICY_AUTOMATIC);
593
594   gtk_container_add (GTK_CONTAINER (window), sw);
595   gtk_container_add (GTK_CONTAINER (sw), view);
596
597   g_object_add_weak_pointer (G_OBJECT (window),
598                              (gpointer *) &window);
599
600   gtk_window_set_default_size (GTK_WINDOW (window), 300, 400);
601   
602   gtk_widget_show_all (window);
603 }
604