]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/main.c
Include "config.h" instead of <config.h> Command used: find -name
[~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 (NULL, 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   "gint8",
204   "gint16",
205   "gint32",
206   "guint",
207   "guint8",
208   "guint16",
209   "guint32",
210   "guchar",
211   "glong",
212   "gboolean" ,
213   "gshort",
214   "gushort",
215   "gulong",
216   "gdouble",
217   "gldouble",
218   "gpointer",
219   "NULL",
220   "GList",
221   "GSList",
222   "FALSE",
223   "TRUE",
224   "FILE ",
225   "GtkObject ",
226   "GtkColorSelection ",
227   "GtkWidget ",
228   "GtkButton ",
229   "GdkColor ",
230   "GdkRectangle ",
231   "GdkEventExpose ",
232   "GdkGC ",
233   "GdkPixbufLoader ",
234   "GdkPixbuf ",
235   "GError",
236   "size_t",
237   NULL
238 };
239
240 static gchar *control[] =
241 {
242   " if ",
243   " while ",
244   " else",
245   " do ",
246   " for ",
247   "?",
248   ":",
249   "return ",
250   "goto ",
251   NULL
252 };
253 void
254 parse_chars (gchar     *text,
255              gchar    **end_ptr,
256              gint      *state,
257              gchar    **tag,
258              gboolean   start)
259 {
260   gint i;
261   gchar *next_token;
262
263   /* Handle comments first */
264   if (*state == STATE_IN_COMMENT)
265     {
266       *end_ptr = strstr (text, "*/");
267       if (*end_ptr)
268         {
269           *end_ptr += 2;
270           *state = STATE_NORMAL;
271           *tag = "comment";
272         }
273       return;
274     }
275
276   *tag = NULL;
277   *end_ptr = NULL;
278
279   /* check for comment */
280   if (!strncmp (text, "/*", 2))
281     {
282       *end_ptr = strstr (text, "*/");
283       if (*end_ptr)
284         *end_ptr += 2;
285       else
286         *state = STATE_IN_COMMENT;
287       *tag = "comment";
288       return;
289     }
290
291   /* check for preprocessor defines */
292   if (*text == '#' && start)
293     {
294       *end_ptr = NULL;
295       *tag = "preprocessor";
296       return;
297     }
298
299   /* functions */
300   if (start && * text != '\t' && *text != ' ' && *text != '{' && *text != '}')
301     {
302       if (strstr (text, "("))
303         {
304           *end_ptr = strstr (text, "(");
305           *tag = "function";
306           return;
307         }
308     }
309   /* check for types */
310   for (i = 0; types[i] != NULL; i++)
311     if (!strncmp (text, types[i], strlen (types[i])))
312       {
313         *end_ptr = text + strlen (types[i]);
314         *tag = "type";
315         return;
316       }
317
318   /* check for control */
319   for (i = 0; control[i] != NULL; i++)
320     if (!strncmp (text, control[i], strlen (control[i])))
321       {
322         *end_ptr = text + strlen (control[i]);
323         *tag = "control";
324         return;
325       }
326
327   /* check for string */
328   if (text[0] == '"')
329     {
330       gint maybe_escape = FALSE;
331
332       *end_ptr = text + 1;
333       *tag = "string";
334       while (**end_ptr != '\000')
335         {
336           if (**end_ptr == '\"' && !maybe_escape)
337             {
338               *end_ptr += 1;
339               return;
340             }
341           if (**end_ptr == '\\')
342             maybe_escape = TRUE;
343           else
344             maybe_escape = FALSE;
345           *end_ptr += 1;
346         }
347       return;
348     }
349
350   /* not at the start of a tag.  Find the next one. */
351   for (i = 0; tokens[i] != NULL; i++)
352     {
353       next_token = strstr (text, tokens[i]);
354       if (next_token)
355         {
356           if (*end_ptr)
357             *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
358           else
359             *end_ptr = next_token;
360         }
361     }
362
363   for (i = 0; types[i] != NULL; i++)
364     {
365       next_token = strstr (text, types[i]);
366       if (next_token)
367         {
368           if (*end_ptr)
369             *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
370           else
371             *end_ptr = next_token;
372         }
373     }
374
375   for (i = 0; control[i] != NULL; i++)
376     {
377       next_token = strstr (text, control[i]);
378       if (next_token)
379         {
380           if (*end_ptr)
381             *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
382           else
383             *end_ptr = next_token;
384         }
385     }
386 }
387
388 /* While not as cool as c-mode, this will do as a quick attempt at highlighting */
389 static void
390 fontify (void)
391 {
392   GtkTextIter start_iter, next_iter, tmp_iter;
393   gint state;
394   gchar *text;
395   gchar *start_ptr, *end_ptr;
396   gchar *tag;
397
398   state = STATE_NORMAL;
399
400   gtk_text_buffer_get_iter_at_offset (source_buffer, &start_iter, 0);
401
402   next_iter = start_iter;
403   while (gtk_text_iter_forward_line (&next_iter))
404     {
405       gboolean start = TRUE;
406       start_ptr = text = gtk_text_iter_get_text (&start_iter, &next_iter);
407
408       do
409         {
410           parse_chars (start_ptr, &end_ptr, &state, &tag, start);
411
412           start = FALSE;
413           if (end_ptr)
414             {
415               tmp_iter = start_iter;
416               gtk_text_iter_forward_chars (&tmp_iter, end_ptr - start_ptr);
417             }
418           else
419             {
420               tmp_iter = next_iter;
421             }
422           if (tag)
423             gtk_text_buffer_apply_tag_by_name (source_buffer, tag, &start_iter, &tmp_iter);
424
425           start_iter = tmp_iter;
426           start_ptr = end_ptr;
427         }
428       while (end_ptr);
429
430       g_free (text);
431       start_iter = next_iter;
432     }
433 }
434
435 void
436 load_file (const gchar *filename)
437 {
438   FILE *file;
439   GtkTextIter start, end;
440   char *full_filename;
441   GError *err = NULL;
442   GString *buffer = g_string_new (NULL);
443   int state = 0;
444   gboolean in_para = 0;
445
446   if (current_file && !strcmp (current_file, filename))
447     {
448       g_string_free (buffer, TRUE);
449       return;
450     }
451
452   g_free (current_file);
453   current_file = g_strdup (filename);
454   
455   gtk_text_buffer_get_bounds (info_buffer, &start, &end);
456   gtk_text_buffer_delete (info_buffer, &start, &end);
457
458   gtk_text_buffer_get_bounds (source_buffer, &start, &end);
459   gtk_text_buffer_delete (source_buffer, &start, &end);
460
461   full_filename = demo_find_file (filename, &err);
462   if (!full_filename)
463     {
464       g_warning ("%s", err->message);
465       g_error_free (err);
466       return;
467     }
468
469   file = g_fopen (full_filename, "r");
470
471   if (!file)
472     g_warning ("Cannot open %s: %s\n", full_filename, g_strerror (errno));
473
474   g_free (full_filename);
475
476   if (!file)
477     return;
478
479   gtk_text_buffer_get_iter_at_offset (info_buffer, &start, 0);
480   while (read_line (file, buffer))
481     {
482       gchar *p = buffer->str;
483       gchar *q;
484       gchar *r;
485       
486       switch (state)
487         {
488         case 0:
489           /* Reading title */
490           while (*p == '/' || *p == '*' || g_ascii_isspace (*p))
491             p++;
492           r = p;
493           while (*r != '/' && strlen (r))
494             r++;
495           if (strlen (r) > 0)
496             p = r + 1;
497           q = p + strlen (p);
498           while (q > p && g_ascii_isspace (*(q - 1)))
499             q--;
500
501           if (q > p)
502             {
503               int len_chars = g_utf8_pointer_to_offset (p, q);
504
505               end = start;
506
507               g_assert (strlen (p) >= q - p);
508               gtk_text_buffer_insert (info_buffer, &end, p, q - p);
509               start = end;
510
511               gtk_text_iter_backward_chars (&start, len_chars);
512               gtk_text_buffer_apply_tag_by_name (info_buffer, "title", &start, &end);
513
514               start = end;
515               
516               state++;
517             }
518           break;
519             
520         case 1:
521           /* Reading body of info section */
522           while (g_ascii_isspace (*p))
523             p++;
524           if (*p == '*' && *(p + 1) == '/')
525             {
526               gtk_text_buffer_get_iter_at_offset (source_buffer, &start, 0);
527               state++;
528             }
529           else
530             {
531               int len;
532               
533               while (*p == '*' || g_ascii_isspace (*p))
534                 p++;
535
536               len = strlen (p);
537               while (g_ascii_isspace (*(p + len - 1)))
538                 len--;
539               
540               if (len > 0)
541                 {
542                   if (in_para)
543                     gtk_text_buffer_insert (info_buffer, &start, " ", 1);
544
545                   g_assert (strlen (p) >= len);
546                   gtk_text_buffer_insert (info_buffer, &start, p, len);
547                   in_para = 1;
548                 }
549               else
550                 {
551                   gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
552                   in_para = 0;
553                 }
554             }
555           break;
556
557         case 2:
558           /* Skipping blank lines */
559           while (g_ascii_isspace (*p))
560             p++;
561           if (*p)
562             {
563               p = buffer->str;
564               state++;
565               /* Fall through */
566             }
567           else
568             break;
569           
570         case 3:
571           /* Reading program body */
572           gtk_text_buffer_insert (source_buffer, &start, p, -1);
573           gtk_text_buffer_insert (source_buffer, &start, "\n", 1);
574           break;
575         }
576     }
577
578   fclose (file);
579   
580   fontify ();
581
582   g_string_free (buffer, TRUE);
583 }
584
585 void
586 row_activated_cb (GtkTreeView       *tree_view,
587                   GtkTreePath       *path,
588                   GtkTreeViewColumn *column)
589 {
590   GtkTreeIter iter;
591   PangoStyle style;
592   GDoDemoFunc func;
593   GtkWidget *window;
594   GtkTreeModel *model;
595
596   model = gtk_tree_view_get_model (tree_view);
597   
598   gtk_tree_model_get_iter (model, &iter, path);
599   gtk_tree_model_get (GTK_TREE_MODEL (model),
600                       &iter,
601                       FUNC_COLUMN, &func,
602                       STYLE_COLUMN, &style,
603                       -1);
604
605   if (func)
606     {
607       gtk_tree_store_set (GTK_TREE_STORE (model),
608                           &iter,
609                           STYLE_COLUMN, (style == PANGO_STYLE_ITALIC ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC),
610                           -1);
611       window = (func) (gtk_widget_get_toplevel (GTK_WIDGET (tree_view)));
612       
613       if (window != NULL)
614         {
615           CallbackData *cbdata;
616           
617           cbdata = g_new (CallbackData, 1);
618           cbdata->model = model;
619           cbdata->path = gtk_tree_path_copy (path);
620           
621           g_signal_connect (window, "destroy",
622                             G_CALLBACK (window_closed_cb), cbdata);
623         }
624     }
625 }
626
627 static void
628 selection_cb (GtkTreeSelection *selection,
629               GtkTreeModel     *model)
630 {
631   GtkTreeIter iter;
632   GValue value = {0, };
633
634   if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
635     return;
636
637   gtk_tree_model_get_value (model, &iter,
638                             FILENAME_COLUMN,
639                             &value);
640   if (g_value_get_string (&value))
641     load_file (g_value_get_string (&value));
642   g_value_unset (&value);
643 }
644
645 static GtkWidget *
646 create_text (GtkTextBuffer **buffer,
647              gboolean        is_source)
648 {
649   GtkWidget *scrolled_window;
650   GtkWidget *text_view;
651   PangoFontDescription *font_desc;
652
653   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
654   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
655                                   GTK_POLICY_AUTOMATIC,
656                                   GTK_POLICY_AUTOMATIC);
657   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
658                                        GTK_SHADOW_IN);
659   
660   text_view = gtk_text_view_new ();
661   
662   *buffer = gtk_text_buffer_new (NULL);
663   gtk_text_view_set_buffer (GTK_TEXT_VIEW (text_view), *buffer);
664   gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
665   gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
666
667   gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
668   
669   if (is_source)
670     {
671       font_desc = pango_font_description_from_string ("monospace");
672       gtk_widget_modify_font (text_view, font_desc);
673       pango_font_description_free (font_desc);
674
675       gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
676                                    GTK_WRAP_NONE);
677     }
678   else
679     {
680       /* Make it a bit nicer for text. */
681       gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
682                                    GTK_WRAP_WORD);
683       gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view),
684                                             2);
685       gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view),
686                                             2);
687     }
688   
689   return scrolled_window;
690 }
691
692 static GtkWidget *
693 create_tree (void)
694 {
695   GtkTreeSelection *selection;
696   GtkCellRenderer *cell;
697   GtkWidget *tree_view;
698   GtkTreeViewColumn *column;
699   GtkTreeStore *model;
700   GtkTreeIter iter;
701   GtkWidget *box, *label, *scrolled_window;
702
703   Demo *d = testgtk_demos;
704
705   model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
706   tree_view = gtk_tree_view_new ();
707   gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
708   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
709
710   gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
711                                GTK_SELECTION_BROWSE);
712   gtk_widget_set_size_request (tree_view, 200, -1);
713
714   /* this code only supports 1 level of children. If we
715    * want more we probably have to use a recursing function.
716    */
717   while (d->title)
718     {
719       Demo *children = d->children;
720
721       gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
722
723       gtk_tree_store_set (GTK_TREE_STORE (model),
724                           &iter,
725                           TITLE_COLUMN, d->title,
726                           FILENAME_COLUMN, d->filename,
727                           FUNC_COLUMN, d->func,
728                           STYLE_COLUMN, PANGO_STYLE_NORMAL,
729                           -1);
730
731       d++;
732
733       if (!children)
734         continue;
735       
736       while (children->title)
737         {
738           GtkTreeIter child_iter;
739
740           gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &iter);
741           
742           gtk_tree_store_set (GTK_TREE_STORE (model),
743                               &child_iter,
744                               TITLE_COLUMN, children->title,
745                               FILENAME_COLUMN, children->filename,
746                               FUNC_COLUMN, children->func,
747                               STYLE_COLUMN, PANGO_STYLE_NORMAL,
748                               -1);
749           
750           children++;
751         }
752     }
753
754   cell = gtk_cell_renderer_text_new ();
755
756   column = gtk_tree_view_column_new_with_attributes ("Widget (double click for demo)",
757                                                      cell,
758                                                      "text", TITLE_COLUMN,
759                                                      "style", STYLE_COLUMN,
760                                                      NULL);
761   
762   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
763                                GTK_TREE_VIEW_COLUMN (column));
764
765   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
766   gtk_tree_selection_select_iter (GTK_TREE_SELECTION (selection), &iter);
767
768   g_signal_connect (selection, "changed", G_CALLBACK (selection_cb), model);
769   g_signal_connect (tree_view, "row_activated", G_CALLBACK (row_activated_cb), model);
770
771   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
772   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
773                                     
774   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
775   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
776                                   GTK_POLICY_NEVER,
777                                   GTK_POLICY_AUTOMATIC);
778   gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
779
780   label = gtk_label_new ("Widget (double click for demo)");
781
782   box = gtk_notebook_new ();
783   gtk_notebook_append_page (GTK_NOTEBOOK (box), scrolled_window, label);
784
785   gtk_widget_grab_focus (tree_view);
786
787    g_object_unref (model);
788
789   return box;
790 }
791
792 static void
793 setup_default_icon (void)
794 {
795   GdkPixbuf *pixbuf;
796   char *filename;
797   GError *err;
798
799   err = NULL;
800
801   pixbuf = NULL;
802   filename = demo_find_file ("gtk-logo-rgb.gif", &err);
803   if (filename)
804     {
805       pixbuf = gdk_pixbuf_new_from_file (filename, &err);
806       g_free (filename);
807     }
808
809   /* Ignoring this error (passing NULL instead of &err above)
810    * would probably be reasonable for most apps.  We're just
811    * showing off.
812    */
813   if (err)
814     {
815       GtkWidget *dialog;
816       
817       dialog = gtk_message_dialog_new (NULL, 0,
818                                        GTK_MESSAGE_ERROR,
819                                        GTK_BUTTONS_CLOSE,
820                                        "Failed to read icon file: %s",
821                                        err->message);
822       g_error_free (err);
823
824       g_signal_connect (dialog, "response",
825                         G_CALLBACK (gtk_widget_destroy), NULL);
826     }
827
828   if (pixbuf)
829     {
830       GList *list;      
831       GdkPixbuf *transparent;
832
833       /* The gtk-logo-rgb icon has a white background, make it transparent */
834       transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
835
836       list = NULL;
837       list = g_list_append (list, transparent);
838       gtk_window_set_default_icon_list (list);
839       g_list_free (list);
840       g_object_unref (pixbuf);
841       g_object_unref (transparent);
842     }
843 }
844
845 int
846 main (int argc, char **argv)
847 {
848   GtkWidget *window;
849   GtkWidget *notebook;
850   GtkWidget *hbox;
851   GtkWidget *tree;
852   GtkTextTag *tag;
853
854   /* Most code in gtk-demo is intended to be exemplary, but not
855    * these few lines, which are just a hack so gtk-demo will work
856    * in the GTK tree without installing it.
857    */
858   if (g_file_test ("../../gdk-pixbuf/libpixbufloader-pnm.la",
859                    G_FILE_TEST_EXISTS))
860     {
861       g_setenv ("GDK_PIXBUF_MODULE_FILE", "../../gdk-pixbuf/gdk-pixbuf.loaders", TRUE);
862       g_setenv ("GTK_IM_MODULE_FILE", "../../modules/input/gtk.immodules", TRUE);
863     }
864   /* -- End of hack -- */
865   
866   gtk_init (&argc, &argv);
867
868   setup_default_icon ();
869   
870   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
871   gtk_window_set_title (GTK_WINDOW (window), "GTK+ Code Demos");
872   g_signal_connect_after (window, "destroy",
873                     G_CALLBACK (gtk_main_quit), NULL);
874
875   hbox = gtk_hbox_new (FALSE, 0);
876   gtk_container_add (GTK_CONTAINER (window), hbox);
877
878   tree = create_tree ();
879   gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
880
881   notebook = gtk_notebook_new ();
882   gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
883
884   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
885                             create_text (&info_buffer, FALSE),
886                             gtk_label_new_with_mnemonic ("_Info"));
887
888   tag = gtk_text_buffer_create_tag (info_buffer, "title",
889                                     "font", "Sans 18",
890                                     NULL);
891    g_object_unref (info_buffer);
892
893   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
894                             create_text (&source_buffer, TRUE),
895                             gtk_label_new_with_mnemonic ("_Source"));
896
897
898   tag = gtk_text_buffer_create_tag (source_buffer, "comment",
899                                     "foreground", "DodgerBlue",
900                                     NULL);
901   tag = gtk_text_buffer_create_tag (source_buffer, "type",
902                                     "foreground", "ForestGreen",
903                                     NULL);
904   tag = gtk_text_buffer_create_tag (source_buffer, "string",
905                                     "foreground", "RosyBrown",
906                                     "weight", PANGO_WEIGHT_BOLD,
907                                     NULL);
908   tag = gtk_text_buffer_create_tag (source_buffer, "control",
909                                     "foreground", "purple",
910                                     NULL);
911   tag = gtk_text_buffer_create_tag (source_buffer, "preprocessor",
912                                     "style", PANGO_STYLE_OBLIQUE,
913                                     "foreground", "burlywood4",
914                                     NULL);
915   tag = gtk_text_buffer_create_tag (source_buffer, "function",
916                                     "weight", PANGO_WEIGHT_BOLD,
917                                     "foreground", "DarkGoldenrod4",
918                                     NULL);
919    g_object_unref (source_buffer);
920   
921   gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
922   gtk_widget_show_all (window);
923   
924
925   load_file (testgtk_demos[0].filename);
926   
927   gtk_main ();
928
929   return 0;
930 }