]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/main.c
gtk: remove "gboolean homogeneous" from gtk_box_new()
[~andy/gtk] / demos / gtk-demo / main.c
1 #include "config.h"
2 #include <errno.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include <gtk/gtk.h>
8 #include <glib/gstdio.h>
9
10 #include "demos.h"
11
12 static GtkTextBuffer *info_buffer;
13 static GtkTextBuffer *source_buffer;
14
15 static gchar *current_file = NULL;
16
17
18 enum {
19   TITLE_COLUMN,
20   FILENAME_COLUMN,
21   FUNC_COLUMN,
22   STYLE_COLUMN,
23   NUM_COLUMNS
24 };
25
26 typedef struct _CallbackData CallbackData;
27 struct _CallbackData
28 {
29   GtkTreeModel *model;
30   GtkTreePath *path;
31 };
32
33 #ifdef G_OS_WIN32
34
35 #undef DEMOCODEDIR
36
37 static char *
38 get_democodedir (void)
39 {
40   static char *result = NULL;
41
42   if (result == NULL)
43     {
44       result = g_win32_get_package_installation_directory_of_module (NULL);
45       if (result == NULL)
46         result = "unknown-location";
47
48       result = g_strconcat (result, "\\share\\gtk-2.0\\demo", NULL);
49     }
50
51   return result;
52 }
53
54 #define DEMOCODEDIR get_democodedir ()
55
56 #endif
57
58 /**
59  * demo_find_file:
60  * @base: base filename
61  * @err:  location to store error, or %NULL.
62  * 
63  * Looks for @base first in the current directory, then in the
64  * location GTK+ where it will be installed on make install,
65  * returns the first file found.
66  * 
67  * Return value: the filename, if found or %NULL
68  **/
69 gchar *
70 demo_find_file (const char *base,
71                 GError    **err)
72 {
73   g_return_val_if_fail (err == NULL || *err == NULL, NULL);
74   
75   if (g_file_test ("gtk-logo-rgb.gif", G_FILE_TEST_EXISTS) &&
76       g_file_test (base, G_FILE_TEST_EXISTS))
77     return g_strdup (base);
78   else
79     {
80       char *filename = g_build_filename (DEMOCODEDIR, base, NULL);
81       if (!g_file_test (filename, G_FILE_TEST_EXISTS))
82         {
83           g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_NOENT,
84                        "Cannot find demo data file \"%s\"", base);
85           g_free (filename);
86           return NULL;
87         }
88       return filename;
89     }
90 }
91
92 static void
93 window_closed_cb (GtkWidget *window, gpointer data)
94 {
95   CallbackData *cbdata = data;
96   GtkTreeIter iter;
97   PangoStyle style;
98
99   gtk_tree_model_get_iter (cbdata->model, &iter, cbdata->path);
100   gtk_tree_model_get (GTK_TREE_MODEL (cbdata->model), &iter,
101                       STYLE_COLUMN, &style,
102                       -1);
103   if (style == PANGO_STYLE_ITALIC)
104     gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter,
105                         STYLE_COLUMN, PANGO_STYLE_NORMAL,
106                         -1);
107
108   gtk_tree_path_free (cbdata->path);
109   g_free (cbdata);
110 }
111
112 gboolean
113 read_line (FILE *stream, GString *str)
114 {
115   int n_read = 0;
116   
117 #ifdef HAVE_FLOCKFILE
118   flockfile (stream);
119 #endif
120
121   g_string_truncate (str, 0);
122   
123   while (1)
124     {
125       int c;
126       
127 #ifdef HAVE_FLOCKFILE
128       c = getc_unlocked (stream);
129 #else
130       c = getc (stream);
131 #endif
132
133       if (c == EOF)
134         goto done;
135       else
136         n_read++;
137
138       switch (c)
139         {
140         case '\r':
141         case '\n':
142           {
143 #ifdef HAVE_FLOCKFILE
144             int next_c = getc_unlocked (stream);
145 #else
146             int next_c = getc (stream);
147 #endif
148             
149             if (!(next_c == EOF ||
150                   (c == '\r' && next_c == '\n') ||
151                   (c == '\n' && next_c == '\r')))
152               ungetc (next_c, stream);
153             
154             goto done;
155           }
156         default:
157           g_string_append_c (str, c);
158         }
159     }
160
161  done:
162
163 #ifdef HAVE_FLOCKFILE
164   funlockfile (stream);
165 #endif
166
167   return n_read > 0;
168 }
169
170
171 /* Stupid syntax highlighting.
172  *
173  * No regex was used in the making of this highlighting.
174  * It should only work for simple cases.  This is good, as
175  * that's all we should have in the demos.
176  */
177 /* This code should not be used elsewhere, except perhaps as an example of how
178  * to iterate through a text buffer.
179  */
180 enum {
181   STATE_NORMAL,
182   STATE_IN_COMMENT
183 };
184
185 static gchar *tokens[] =
186 {
187   "/*",
188   "\"",
189   NULL
190 };
191
192 static gchar *types[] =
193 {
194   "static",
195   "const ",
196   "void",
197   "gint",
198   " int ",
199   " char ",
200   "gchar ",
201   "gfloat",
202   "float",
203   "double",
204   "gint8",
205   "gint16",
206   "gint32",
207   "guint",
208   "guint8",
209   "guint16",
210   "guint32",
211   "guchar",
212   "glong",
213   "gboolean" ,
214   "gshort",
215   "gushort",
216   "gulong",
217   "gdouble",
218   "gldouble",
219   "gpointer",
220   "NULL",
221   "GList",
222   "GSList",
223   "FALSE",
224   "TRUE",
225   "FILE ",
226   "GtkColorSelection ",
227   "GtkWidget ",
228   "GtkButton ",
229   "GdkColor ",
230   "GdkRectangle ",
231   "GdkEventExpose ",
232   "GdkGC ",
233   "GdkPixbufLoader ",
234   "GdkPixbuf ",
235   "GError",
236   "size_t",
237   "GtkAboutDialog ",
238   "GtkAction ",
239   "GtkActionEntry ",
240   "GtkRadioActionEntry ",
241   "GtkIconFactory ",
242   "GtkStockItem ",
243   "GtkIconSet ",
244   "GtkTextBuffer ",
245   "GtkStatusbar ",
246   "GtkTextIter ",
247   "GtkTextMark ",
248   "GdkEventWindowState ",
249   "GtkActionGroup ",
250   "GtkUIManager ",
251   "GtkRadioAction ",
252   "GtkActionClass ",
253   "GtkToggleActionEntry ",
254   "GtkAssistant ",
255   "GtkBuilder ",
256   "GtkSizeGroup ",
257   "GtkTreeModel ",
258   "GtkTreeSelection ",
259   "GdkDisplay ",
260   "GdkScreen ",
261   "GdkWindow ",
262   "GdkEventButton ",
263   "GdkCursor ",
264   "GtkTreeIter ",
265   "GtkTreeViewColumn ",
266   "GdkDisplayManager ",
267   "GtkClipboard ",
268   "GtkIconSize ",
269   "GtkImage ",
270   "GdkDragContext ",
271   "GtkSelectionData ",
272   "GtkDialog ",
273   "GtkMenuItem ",
274   "GtkListStore ",
275   "GtkCellLayout ",
276   "GtkCellRenderer ",
277   "GtkTreePath ",
278   "GtkTreeStore ",
279   "GtkEntry ",
280   "GtkEditable ",
281   "GtkEditableInterface ",
282   "GdkPixmap ",
283   "GdkEventConfigure ",
284   "GdkEventMotion ",
285   "GdkModifierType ",
286   "GtkEntryCompletion ",
287   "GtkToolItem ",
288   "GDir ",
289   "GtkIconView ",
290   "GtkCellRendererText ",
291   "GtkContainer ",
292   "GtkAccelGroup ",
293   "GtkPaned ",
294   "GtkPrintOperation ",
295   "GtkPrintContext ",
296   "cairo_t ",
297   "PangoLayout "
298   "PangoFontDescription ",
299   "PangoRenderer ",
300   "PangoMatrix ",
301   "PangoContext ",
302   "PangoLayout ",
303   "GtkTable ",
304   "GtkToggleButton ",
305   "GString ",
306   "GtkIconSize ",
307   "GtkTreeView ",
308   "GtkTextTag ",
309   "GdkEvent ",
310   "GdkEventKey ",
311   "GtkTextView ",
312   "GdkEventVisibility ",
313   "GdkBitmap ",
314   "GtkTextChildAnchor ",
315   "GArray ",
316   "GtkCellEditable ",
317   "GtkCellRendererToggle ",
318   NULL
319 };
320
321 static gchar *control[] =
322 {
323   " if ",
324   " while ",
325   " else",
326   " do ",
327   " for ",
328   "?",
329   ":",
330   "return ",
331   "goto ",
332   NULL
333 };
334 void
335 parse_chars (gchar     *text,
336              gchar    **end_ptr,
337              gint      *state,
338              gchar    **tag,
339              gboolean   start)
340 {
341   gint i;
342   gchar *next_token;
343
344   /* Handle comments first */
345   if (*state == STATE_IN_COMMENT)
346     {
347       *end_ptr = strstr (text, "*/");
348       if (*end_ptr)
349         {
350           *end_ptr += 2;
351           *state = STATE_NORMAL;
352           *tag = "comment";
353         }
354       return;
355     }
356
357   *tag = NULL;
358   *end_ptr = NULL;
359
360   /* check for comment */
361   if (!strncmp (text, "/*", 2))
362     {
363       *end_ptr = strstr (text, "*/");
364       if (*end_ptr)
365         *end_ptr += 2;
366       else
367         *state = STATE_IN_COMMENT;
368       *tag = "comment";
369       return;
370     }
371
372   /* check for preprocessor defines */
373   if (*text == '#' && start)
374     {
375       *end_ptr = NULL;
376       *tag = "preprocessor";
377       return;
378     }
379
380   /* functions */
381   if (start && * text != '\t' && *text != ' ' && *text != '{' && *text != '}')
382     {
383       if (strstr (text, "("))
384         {
385           *end_ptr = strstr (text, "(");
386           *tag = "function";
387           return;
388         }
389     }
390   /* check for types */
391   for (i = 0; types[i] != NULL; i++)
392     if (!strncmp (text, types[i], strlen (types[i])) ||
393         (start && types[i][0] == ' ' && !strncmp (text, types[i] + 1, strlen (types[i]) - 1)))
394       {
395         *end_ptr = text + strlen (types[i]);
396         *tag = "type";
397         return;
398       }
399
400   /* check for control */
401   for (i = 0; control[i] != NULL; i++)
402     if (!strncmp (text, control[i], strlen (control[i])))
403       {
404         *end_ptr = text + strlen (control[i]);
405         *tag = "control";
406         return;
407       }
408
409   /* check for string */
410   if (text[0] == '"')
411     {
412       gint maybe_escape = FALSE;
413
414       *end_ptr = text + 1;
415       *tag = "string";
416       while (**end_ptr != '\000')
417         {
418           if (**end_ptr == '\"' && !maybe_escape)
419             {
420               *end_ptr += 1;
421               return;
422             }
423           if (**end_ptr == '\\')
424             maybe_escape = TRUE;
425           else
426             maybe_escape = FALSE;
427           *end_ptr += 1;
428         }
429       return;
430     }
431
432   /* not at the start of a tag.  Find the next one. */
433   for (i = 0; tokens[i] != NULL; i++)
434     {
435       next_token = strstr (text, tokens[i]);
436       if (next_token)
437         {
438           if (*end_ptr)
439             *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
440           else
441             *end_ptr = next_token;
442         }
443     }
444
445   for (i = 0; types[i] != NULL; i++)
446     {
447       next_token = strstr (text, types[i]);
448       if (next_token)
449         {
450           if (*end_ptr)
451             *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
452           else
453             *end_ptr = next_token;
454         }
455     }
456
457   for (i = 0; control[i] != NULL; i++)
458     {
459       next_token = strstr (text, control[i]);
460       if (next_token)
461         {
462           if (*end_ptr)
463             *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
464           else
465             *end_ptr = next_token;
466         }
467     }
468 }
469
470 /* While not as cool as c-mode, this will do as a quick attempt at highlighting */
471 static void
472 fontify (void)
473 {
474   GtkTextIter start_iter, next_iter, tmp_iter;
475   gint state;
476   gchar *text;
477   gchar *start_ptr, *end_ptr;
478   gchar *tag;
479
480   state = STATE_NORMAL;
481
482   gtk_text_buffer_get_iter_at_offset (source_buffer, &start_iter, 0);
483
484   next_iter = start_iter;
485   while (gtk_text_iter_forward_line (&next_iter))
486     {
487       gboolean start = TRUE;
488       start_ptr = text = gtk_text_iter_get_text (&start_iter, &next_iter);
489
490       do
491         {
492           parse_chars (start_ptr, &end_ptr, &state, &tag, start);
493
494           start = FALSE;
495           if (end_ptr)
496             {
497               tmp_iter = start_iter;
498               gtk_text_iter_forward_chars (&tmp_iter, end_ptr - start_ptr);
499             }
500           else
501             {
502               tmp_iter = next_iter;
503             }
504           if (tag)
505             gtk_text_buffer_apply_tag_by_name (source_buffer, tag, &start_iter, &tmp_iter);
506
507           start_iter = tmp_iter;
508           start_ptr = end_ptr;
509         }
510       while (end_ptr);
511
512       g_free (text);
513       start_iter = next_iter;
514     }
515 }
516
517 void
518 load_file (const gchar *filename)
519 {
520   FILE *file;
521   GtkTextIter start, end;
522   char *full_filename;
523   GError *err = NULL;
524   GString *buffer = g_string_new (NULL);
525   int state = 0;
526   gboolean in_para = 0;
527
528   if (current_file && !strcmp (current_file, filename))
529     {
530       g_string_free (buffer, TRUE);
531       return;
532     }
533
534   g_free (current_file);
535   current_file = g_strdup (filename);
536   
537   gtk_text_buffer_get_bounds (info_buffer, &start, &end);
538   gtk_text_buffer_delete (info_buffer, &start, &end);
539
540   gtk_text_buffer_get_bounds (source_buffer, &start, &end);
541   gtk_text_buffer_delete (source_buffer, &start, &end);
542
543   full_filename = demo_find_file (filename, &err);
544   if (!full_filename)
545     {
546       g_warning ("%s", err->message);
547       g_error_free (err);
548       return;
549     }
550
551   file = g_fopen (full_filename, "r");
552
553   if (!file)
554     g_warning ("Cannot open %s: %s\n", full_filename, g_strerror (errno));
555
556   g_free (full_filename);
557
558   if (!file)
559     return;
560
561   gtk_text_buffer_get_iter_at_offset (info_buffer, &start, 0);
562   while (read_line (file, buffer))
563     {
564       gchar *p = buffer->str;
565       gchar *q;
566       gchar *r;
567       
568       switch (state)
569         {
570         case 0:
571           /* Reading title */
572           while (*p == '/' || *p == '*' || g_ascii_isspace (*p))
573             p++;
574           r = p;
575           while (*r != '/' && strlen (r))
576             r++;
577           if (strlen (r) > 0)
578             p = r + 1;
579           q = p + strlen (p);
580           while (q > p && g_ascii_isspace (*(q - 1)))
581             q--;
582
583           if (q > p)
584             {
585               int len_chars = g_utf8_pointer_to_offset (p, q);
586
587               end = start;
588
589               g_assert (strlen (p) >= q - p);
590               gtk_text_buffer_insert (info_buffer, &end, p, q - p);
591               start = end;
592
593               gtk_text_iter_backward_chars (&start, len_chars);
594               gtk_text_buffer_apply_tag_by_name (info_buffer, "title", &start, &end);
595
596               start = end;
597               
598               state++;
599             }
600           break;
601             
602         case 1:
603           /* Reading body of info section */
604           while (g_ascii_isspace (*p))
605             p++;
606           if (*p == '*' && *(p + 1) == '/')
607             {
608               gtk_text_buffer_get_iter_at_offset (source_buffer, &start, 0);
609               state++;
610             }
611           else
612             {
613               int len;
614               
615               while (*p == '*' || g_ascii_isspace (*p))
616                 p++;
617
618               len = strlen (p);
619               while (g_ascii_isspace (*(p + len - 1)))
620                 len--;
621               
622               if (len > 0)
623                 {
624                   if (in_para)
625                     gtk_text_buffer_insert (info_buffer, &start, " ", 1);
626
627                   g_assert (strlen (p) >= len);
628                   gtk_text_buffer_insert (info_buffer, &start, p, len);
629                   in_para = 1;
630                 }
631               else
632                 {
633                   gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
634                   in_para = 0;
635                 }
636             }
637           break;
638
639         case 2:
640           /* Skipping blank lines */
641           while (g_ascii_isspace (*p))
642             p++;
643           if (*p)
644             {
645               p = buffer->str;
646               state++;
647               /* Fall through */
648             }
649           else
650             break;
651           
652         case 3:
653           /* Reading program body */
654           gtk_text_buffer_insert (source_buffer, &start, p, -1);
655           gtk_text_buffer_insert (source_buffer, &start, "\n", 1);
656           break;
657         }
658     }
659
660   fclose (file);
661   
662   fontify ();
663
664   g_string_free (buffer, TRUE);
665 }
666
667 void
668 row_activated_cb (GtkTreeView       *tree_view,
669                   GtkTreePath       *path,
670                   GtkTreeViewColumn *column)
671 {
672   GtkTreeIter iter;
673   PangoStyle style;
674   GDoDemoFunc func;
675   GtkWidget *window;
676   GtkTreeModel *model;
677
678   model = gtk_tree_view_get_model (tree_view);
679   
680   gtk_tree_model_get_iter (model, &iter, path);
681   gtk_tree_model_get (GTK_TREE_MODEL (model),
682                       &iter,
683                       FUNC_COLUMN, &func,
684                       STYLE_COLUMN, &style,
685                       -1);
686
687   if (func)
688     {
689       gtk_tree_store_set (GTK_TREE_STORE (model),
690                           &iter,
691                           STYLE_COLUMN, (style == PANGO_STYLE_ITALIC ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC),
692                           -1);
693       window = (func) (gtk_widget_get_toplevel (GTK_WIDGET (tree_view)));
694       
695       if (window != NULL)
696         {
697           CallbackData *cbdata;
698           
699           cbdata = g_new (CallbackData, 1);
700           cbdata->model = model;
701           cbdata->path = gtk_tree_path_copy (path);
702           
703           g_signal_connect (window, "destroy",
704                             G_CALLBACK (window_closed_cb), cbdata);
705         }
706     }
707 }
708
709 static void
710 selection_cb (GtkTreeSelection *selection,
711               GtkTreeModel     *model)
712 {
713   GtkTreeIter iter;
714   GValue value = {0, };
715
716   if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
717     return;
718
719   gtk_tree_model_get_value (model, &iter,
720                             FILENAME_COLUMN,
721                             &value);
722   if (g_value_get_string (&value))
723     load_file (g_value_get_string (&value));
724   g_value_unset (&value);
725 }
726
727 static GtkWidget *
728 create_text (GtkTextBuffer **buffer,
729              gboolean        is_source)
730 {
731   GtkWidget *scrolled_window;
732   GtkWidget *text_view;
733   PangoFontDescription *font_desc;
734
735   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
736   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
737                                   GTK_POLICY_AUTOMATIC,
738                                   GTK_POLICY_AUTOMATIC);
739   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
740                                        GTK_SHADOW_IN);
741   
742   text_view = gtk_text_view_new ();
743   
744   *buffer = gtk_text_buffer_new (NULL);
745   gtk_text_view_set_buffer (GTK_TEXT_VIEW (text_view), *buffer);
746   gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
747   gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
748
749   gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
750   
751   if (is_source)
752     {
753       font_desc = pango_font_description_from_string ("monospace");
754       gtk_widget_modify_font (text_view, font_desc);
755       pango_font_description_free (font_desc);
756
757       gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
758                                    GTK_WRAP_NONE);
759     }
760   else
761     {
762       /* Make it a bit nicer for text. */
763       gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
764                                    GTK_WRAP_WORD);
765       gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view),
766                                             2);
767       gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view),
768                                             2);
769     }
770   
771   return scrolled_window;
772 }
773
774 static GtkWidget *
775 create_tree (void)
776 {
777   GtkTreeSelection *selection;
778   GtkCellRenderer *cell;
779   GtkWidget *tree_view;
780   GtkTreeViewColumn *column;
781   GtkTreeStore *model;
782   GtkTreeIter iter;
783   GtkWidget *box, *label, *scrolled_window;
784
785   Demo *d = testgtk_demos;
786
787   model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
788   tree_view = gtk_tree_view_new ();
789   gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
790   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
791
792   gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
793                                GTK_SELECTION_BROWSE);
794   gtk_widget_set_size_request (tree_view, 200, -1);
795
796   /* this code only supports 1 level of children. If we
797    * want more we probably have to use a recursing function.
798    */
799   while (d->title)
800     {
801       Demo *children = d->children;
802
803       gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
804
805       gtk_tree_store_set (GTK_TREE_STORE (model),
806                           &iter,
807                           TITLE_COLUMN, d->title,
808                           FILENAME_COLUMN, d->filename,
809                           FUNC_COLUMN, d->func,
810                           STYLE_COLUMN, PANGO_STYLE_NORMAL,
811                           -1);
812
813       d++;
814
815       if (!children)
816         continue;
817       
818       while (children->title)
819         {
820           GtkTreeIter child_iter;
821
822           gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &iter);
823           
824           gtk_tree_store_set (GTK_TREE_STORE (model),
825                               &child_iter,
826                               TITLE_COLUMN, children->title,
827                               FILENAME_COLUMN, children->filename,
828                               FUNC_COLUMN, children->func,
829                               STYLE_COLUMN, PANGO_STYLE_NORMAL,
830                               -1);
831           
832           children++;
833         }
834     }
835
836   cell = gtk_cell_renderer_text_new ();
837
838   column = gtk_tree_view_column_new_with_attributes ("Widget (double click for demo)",
839                                                      cell,
840                                                      "text", TITLE_COLUMN,
841                                                      "style", STYLE_COLUMN,
842                                                      NULL);
843   
844   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
845                                GTK_TREE_VIEW_COLUMN (column));
846
847   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
848   gtk_tree_selection_select_iter (GTK_TREE_SELECTION (selection), &iter);
849
850   g_signal_connect (selection, "changed", G_CALLBACK (selection_cb), model);
851   g_signal_connect (tree_view, "row_activated", G_CALLBACK (row_activated_cb), model);
852
853   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
854   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
855                                     
856   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
857   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
858                                   GTK_POLICY_NEVER,
859                                   GTK_POLICY_AUTOMATIC);
860   gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
861
862   label = gtk_label_new ("Widget (double click for demo)");
863
864   box = gtk_notebook_new ();
865   gtk_notebook_append_page (GTK_NOTEBOOK (box), scrolled_window, label);
866
867   gtk_widget_grab_focus (tree_view);
868
869    g_object_unref (model);
870
871   return box;
872 }
873
874 static void
875 setup_default_icon (void)
876 {
877   GdkPixbuf *pixbuf;
878   char *filename;
879   GError *err;
880
881   err = NULL;
882
883   pixbuf = NULL;
884   filename = demo_find_file ("gtk-logo-rgb.gif", &err);
885   if (filename)
886     {
887       pixbuf = gdk_pixbuf_new_from_file (filename, &err);
888       g_free (filename);
889     }
890
891   /* Ignoring this error (passing NULL instead of &err above)
892    * would probably be reasonable for most apps.  We're just
893    * showing off.
894    */
895   if (err)
896     {
897       GtkWidget *dialog;
898       
899       dialog = gtk_message_dialog_new (NULL, 0,
900                                        GTK_MESSAGE_ERROR,
901                                        GTK_BUTTONS_CLOSE,
902                                        "Failed to read icon file: %s",
903                                        err->message);
904       g_error_free (err);
905
906       g_signal_connect (dialog, "response",
907                         G_CALLBACK (gtk_widget_destroy), NULL);
908     }
909
910   if (pixbuf)
911     {
912       GList *list;      
913       GdkPixbuf *transparent;
914
915       /* The gtk-logo-rgb icon has a white background, make it transparent */
916       transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
917
918       list = NULL;
919       list = g_list_append (list, transparent);
920       gtk_window_set_default_icon_list (list);
921       g_list_free (list);
922       g_object_unref (pixbuf);
923       g_object_unref (transparent);
924     }
925 }
926
927 int
928 main (int argc, char **argv)
929 {
930   GtkWidget *window;
931   GtkWidget *notebook;
932   GtkWidget *hbox;
933   GtkWidget *tree;
934   GtkTextTag *tag;
935
936   /* Most code in gtk-demo is intended to be exemplary, but not
937    * these few lines, which are just a hack so gtk-demo will work
938    * in the GTK tree without installing it.
939    */
940   if (g_file_test ("../../gdk-pixbuf/libpixbufloader-pnm.la",
941                    G_FILE_TEST_EXISTS))
942     {
943       g_setenv ("GDK_PIXBUF_MODULE_FILE", "../../gdk-pixbuf/loaders.cache", TRUE);
944       g_setenv ("GTK_IM_MODULE_FILE", "../../modules/input/immodules.cache", TRUE);
945     }
946   /* -- End of hack -- */
947   
948   gtk_init (&argc, &argv);
949
950   setup_default_icon ();
951   
952   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
953   gtk_window_set_title (GTK_WINDOW (window), "GTK+ Code Demos");
954   g_signal_connect_after (window, "destroy",
955                     G_CALLBACK (gtk_main_quit), NULL);
956
957   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
958   gtk_container_add (GTK_CONTAINER (window), hbox);
959
960   tree = create_tree ();
961   gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
962
963   notebook = gtk_notebook_new ();
964   gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
965
966   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
967                             create_text (&info_buffer, FALSE),
968                             gtk_label_new_with_mnemonic ("_Info"));
969
970   tag = gtk_text_buffer_create_tag (info_buffer, "title",
971                                     "font", "Sans 18",
972                                     NULL);
973    g_object_unref (info_buffer);
974
975   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
976                             create_text (&source_buffer, TRUE),
977                             gtk_label_new_with_mnemonic ("_Source"));
978
979
980   tag = gtk_text_buffer_create_tag (source_buffer, "comment",
981                                     "foreground", "DodgerBlue",
982                                     NULL);
983   tag = gtk_text_buffer_create_tag (source_buffer, "type",
984                                     "foreground", "ForestGreen",
985                                     NULL);
986   tag = gtk_text_buffer_create_tag (source_buffer, "string",
987                                     "foreground", "RosyBrown",
988                                     "weight", PANGO_WEIGHT_BOLD,
989                                     NULL);
990   tag = gtk_text_buffer_create_tag (source_buffer, "control",
991                                     "foreground", "purple",
992                                     NULL);
993   tag = gtk_text_buffer_create_tag (source_buffer, "preprocessor",
994                                     "style", PANGO_STYLE_OBLIQUE,
995                                     "foreground", "burlywood4",
996                                     NULL);
997   tag = gtk_text_buffer_create_tag (source_buffer, "function",
998                                     "weight", PANGO_WEIGHT_BOLD,
999                                     "foreground", "DarkGoldenrod4",
1000                                     NULL);
1001    g_object_unref (source_buffer);
1002   
1003   gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
1004   gtk_widget_show_all (window);
1005   
1006
1007   load_file (testgtk_demos[0].filename);
1008   
1009   gtk_main ();
1010
1011   return 0;
1012 }