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