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