]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/main.c
add default icon
[~andy/gtk] / demos / gtk-demo / main.c
1 #include <errno.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <ctype.h>
6
7 #include <gtk/gtk.h>
8
9 #include <demos.h>
10
11 static GtkTextBuffer *info_buffer;
12 static GtkTextBuffer *source_buffer;
13
14 static gchar *current_file = NULL;
15
16 enum {
17   TITLE_COLUMN,
18   FILENAME_COLUMN,
19   FUNC_COLUMN,
20   ITALIC_COLUMN,
21   NUM_COLUMNS
22 };
23
24 typedef struct _CallbackData CallbackData;
25 struct _CallbackData
26 {
27   GtkTreeModel *model;
28   GtkTreePath *path;
29 };
30
31 static void
32 window_closed_cb (GtkWidget *window, gpointer data)
33 {
34   CallbackData *cbdata = data;
35   GtkTreeIter iter;
36   gboolean italic;
37
38   gtk_tree_model_get_iter (cbdata->model, &iter, cbdata->path);
39   gtk_tree_model_get (GTK_TREE_MODEL (cbdata->model), &iter,
40                       ITALIC_COLUMN, &italic,
41                       -1);
42   if (italic)
43     gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter,
44                         ITALIC_COLUMN, !italic,
45                         -1);
46
47   gtk_tree_path_free (cbdata->path);
48   g_free (cbdata);
49 }
50
51 gboolean
52 read_line (FILE *stream, GString *str)
53 {
54   int n_read = 0;
55   
56   flockfile (stream);
57
58   g_string_truncate (str, 0);
59   
60   while (1)
61     {
62       int c;
63       
64       c = getc_unlocked (stream);
65
66       if (c == EOF)
67         goto done;
68       else
69         n_read++;
70
71       switch (c)
72         {
73         case '\r':
74         case '\n':
75           {
76             int next_c = getc_unlocked (stream);
77             
78             if (!(next_c == EOF ||
79                   (c == '\r' && next_c == '\n') ||
80                   (c == '\n' && next_c == '\r')))
81               ungetc (next_c, stream);
82             
83             goto done;
84           }
85         default:
86           g_string_append_c (str, c);
87         }
88     }
89
90  done:
91
92   funlockfile (stream);
93
94   return n_read > 0;
95 }
96
97
98 /* Stupid syntax highlighting.
99  *
100  * No regex was used in the making of this highlighting.
101  * It should only work for simple cases.  This is good, as
102  * that's all we should have in the demos.
103  */
104 /* This code should not be used elsewhere, except perhaps as an example of how
105  * to iterate through a text buffer.
106  */
107 enum {
108   STATE_NORMAL,
109   STATE_IN_COMMENT,
110 };
111
112 static gchar *tokens[] =
113 {
114   "/*",
115   "\"",
116   NULL
117 };
118
119 static gchar *types[] =
120 {
121   "static",
122   "const ",
123   "void",
124   "gint",
125   "int ",
126   "char ",
127   "gchar ",
128   "gfloat",
129   "float",
130   "gint8",
131   "gint16",
132   "gint32",
133   "guint",
134   "guint8",
135   "guint16",
136   "guint32",
137   "guchar",
138   "glong",
139   "gboolean" ,
140   "gshort",
141   "gushort",
142   "gulong",
143   "gdouble",
144   "gldouble",
145   "gpointer",
146   "NULL",
147   "GList",
148   "GSList",
149   "FALSE",
150   "TRUE",
151   "FILE ",
152   "GtkObject ",
153   "GtkColorSelection ",
154   "GtkWidget ",
155   "GtkButton ",
156   "GdkColor ",
157   "GdkRectangle ",
158   "GdkEventExpose ",
159   "GdkGC ",
160   "GdkPixbufLoader ",
161   "GdkPixbuf ",
162   "GError",
163   "size_t",
164   NULL
165 };
166
167 static gchar *control[] =
168 {
169   " if ",
170   " while ",
171   " else",
172   " do ",
173   " for ",
174   "?",
175   ":",
176   "return ",
177   "goto ",
178   NULL
179 };
180 void
181 parse_chars (gchar     *text,
182              gchar    **end_ptr,
183              gint      *state,
184              gchar    **tag,
185              gboolean   start)
186 {
187   gint i;
188   gchar *next_token;
189
190   /* Handle comments first */
191   if (*state == STATE_IN_COMMENT)
192     {
193       *end_ptr = strstr (text, "*/");
194       if (*end_ptr)
195         {
196           *end_ptr += 2;
197           *state = STATE_NORMAL;
198           *tag = "comment";
199         }
200       return;
201     }
202
203   *tag = NULL;
204   *end_ptr = NULL;
205
206   /* check for comment */
207   if (!strncmp (text, "/*", 2))
208     {
209       *end_ptr = strstr (text, "*/");
210       if (*end_ptr)
211         *end_ptr += 2;
212       else
213         *state = STATE_IN_COMMENT;
214       *tag = "comment";
215       return;
216     }
217
218   /* check for preprocessor defines */
219   if (*text == '#' && start)
220     {
221       *end_ptr = NULL;
222       *tag = "preprocessor";
223       return;
224     }
225
226   /* functions */
227   if (start && * text != '\t' && *text != ' ' && *text != '{' && *text != '}')
228     {
229       if (strstr (text, "("))
230         {
231           *end_ptr = strstr (text, "(");
232           *tag = "function";
233           return;
234         }
235     }
236   /* check for types */
237   for (i = 0; types[i] != NULL; i++)
238     if (!strncmp (text, types[i], strlen (types[i])))
239       {
240         *end_ptr = text + strlen (types[i]);
241         *tag = "type";
242         return;
243       }
244
245   /* check for control */
246   for (i = 0; control[i] != NULL; i++)
247     if (!strncmp (text, control[i], strlen (control[i])))
248       {
249         *end_ptr = text + strlen (control[i]);
250         *tag = "control";
251         return;
252       }
253
254   /* check for string */
255   if (text[0] == '"')
256     {
257       gint maybe_escape = FALSE;
258
259       *end_ptr = text + 1;
260       *tag = "string";
261       while (**end_ptr != '\000')
262         {
263           if (**end_ptr == '\"' && !maybe_escape)
264             {
265               *end_ptr += 1;
266               return;
267             }
268           if (**end_ptr == '\\')
269             maybe_escape = TRUE;
270           else
271             maybe_escape = FALSE;
272           *end_ptr += 1;
273         }
274       return;
275     }
276
277   /* not at the start of a tag.  Find the next one. */
278   for (i = 0; tokens[i] != NULL; i++)
279     {
280       next_token = strstr (text, tokens[i]);
281       if (next_token)
282         {
283           if (*end_ptr)
284             *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
285           else
286             *end_ptr = next_token;
287         }
288     }
289
290   for (i = 0; types[i] != NULL; i++)
291     {
292       next_token = strstr (text, types[i]);
293       if (next_token)
294         {
295           if (*end_ptr)
296             *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
297           else
298             *end_ptr = next_token;
299         }
300     }
301
302   for (i = 0; control[i] != NULL; i++)
303     {
304       next_token = strstr (text, control[i]);
305       if (next_token)
306         {
307           if (*end_ptr)
308             *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
309           else
310             *end_ptr = next_token;
311         }
312     }
313 }
314
315 /* While not as cool as c-mode, this will do as a quick attempt at highlighting */
316 static void
317 fontify ()
318 {
319   GtkTextIter start_iter, next_iter, tmp_iter;
320   gint state;
321   gchar *text;
322   gchar *start_ptr, *end_ptr;
323   gchar *tag;
324
325   state = STATE_NORMAL;
326
327   gtk_text_buffer_get_iter_at_offset (source_buffer, &start_iter, 0);
328
329   next_iter = start_iter;
330   while (gtk_text_iter_forward_line (&next_iter))
331     {
332       gboolean start = TRUE;
333       start_ptr = text = gtk_text_iter_get_text (&start_iter, &next_iter);
334
335       do
336         {
337           parse_chars (start_ptr, &end_ptr, &state, &tag, start);
338
339           start = FALSE;
340           if (end_ptr)
341             {
342               tmp_iter = start_iter;
343               gtk_text_iter_forward_chars (&tmp_iter, end_ptr - start_ptr);
344             }
345           else
346             {
347               tmp_iter = next_iter;
348             }
349           if (tag)
350             gtk_text_buffer_apply_tag_by_name (source_buffer, tag, &start_iter, &tmp_iter);
351
352           start_iter = tmp_iter;
353           start_ptr = end_ptr;
354         }
355       while (end_ptr);
356
357       g_free (text);
358       start_iter = next_iter;
359     }
360 }
361
362 void
363 load_file (const gchar *filename)
364 {
365   FILE *file;
366   GtkTextIter start, end;
367   GString *buffer = g_string_new (NULL);
368   int state = 0;
369   gboolean in_para = 0;
370
371   if (current_file && !strcmp (current_file, filename))
372     {
373       g_string_free (buffer, TRUE);
374       return;
375     }
376
377   g_free (current_file);
378   current_file = g_strdup (filename);
379   
380   gtk_text_buffer_get_bounds (info_buffer, &start, &end);
381   gtk_text_buffer_delete (info_buffer, &start, &end);
382
383   gtk_text_buffer_get_bounds (source_buffer, &start, &end);
384   gtk_text_buffer_delete (source_buffer, &start, &end);
385
386   file = fopen (filename, "r");
387
388   if (!file)
389     {
390       char *installed = g_strconcat (DEMOCODEDIR,
391                                      G_DIR_SEPARATOR_S,
392                                      filename,
393                                      NULL);
394
395       file = fopen (installed, "r");
396
397       g_free (installed);
398     }
399   
400   if (!file)
401     {
402       g_warning ("Cannot open %s: %s\n", filename, g_strerror (errno));
403       return;
404     }
405
406   gtk_text_buffer_get_iter_at_offset (info_buffer, &start, 0);
407   while (read_line (file, buffer))
408     {
409       gchar *p = buffer->str;
410       gchar *q;
411       
412       switch (state)
413         {
414         case 0:
415           /* Reading title */
416           while (*p == '/' || *p == '*' || isspace (*p))
417             p++;
418           q = p + strlen (p);
419           while (q > p && isspace (*(q - 1)))
420             q--;
421
422           if (q > p)
423             {
424               int len_chars = g_utf8_pointer_to_offset (p, q);
425
426               end = start;
427
428               g_assert (strlen (p) >= q - p);
429               gtk_text_buffer_insert (info_buffer, &end, p, q - p);
430               start = end;
431
432               gtk_text_iter_backward_chars (&start, len_chars);
433               gtk_text_buffer_apply_tag_by_name (info_buffer, "title", &start, &end);
434
435               start = end;
436               
437               state++;
438             }
439           break;
440             
441         case 1:
442           /* Reading body of info section */
443           while (isspace (*p))
444             p++;
445           if (*p == '*' && *(p + 1) == '/')
446             {
447               gtk_text_buffer_get_iter_at_offset (source_buffer, &start, 0);
448               state++;
449             }
450           else
451             {
452               int len;
453               
454               while (*p == '*' || isspace (*p))
455                 p++;
456
457               len = strlen (p);
458               while (isspace (*(p + len - 1)))
459                 len--;
460               
461               if (len > 0)
462                 {
463                   if (in_para)
464                     gtk_text_buffer_insert (info_buffer, &start, " ", 1);
465
466                   g_assert (strlen (p) >= len);
467                   gtk_text_buffer_insert (info_buffer, &start, p, len);
468                   in_para = 1;
469                 }
470               else
471                 {
472                   gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
473                   in_para = 0;
474                 }
475             }
476           break;
477
478         case 2:
479           /* Skipping blank lines */
480           while (isspace (*p))
481             p++;
482           if (*p)
483             {
484               p = buffer->str;
485               state++;
486               /* Fall through */
487             }
488           else
489             break;
490           
491         case 3:
492           /* Reading program body */
493           gtk_text_buffer_insert (source_buffer, &start, p, -1);
494           gtk_text_buffer_insert (source_buffer, &start, "\n", 1);
495           break;
496         }
497     }
498
499   fontify ();
500
501   g_string_free (buffer, TRUE);
502 }
503
504 gboolean
505 button_press_event_cb (GtkTreeView    *tree_view,
506                        GdkEventButton *event,
507                        GtkTreeModel   *model)
508 {
509   if (event->type == GDK_2BUTTON_PRESS)
510     {
511       GtkTreePath *path = NULL;
512
513       gtk_tree_view_get_path_at_pos (tree_view,
514                                      event->window,
515                                      event->x,
516                                      event->y,
517                                      &path,
518                                      NULL,
519                                      NULL,
520                                      NULL);
521
522       if (path)
523         {
524           GtkTreeIter iter;
525           gboolean italic;
526           GDoDemoFunc func;
527           GtkWidget *window;
528
529           gtk_tree_model_get_iter (model, &iter, path);
530           gtk_tree_model_get (GTK_TREE_MODEL (model),
531                               &iter,
532                               FUNC_COLUMN, &func,
533                               ITALIC_COLUMN, &italic,
534                               -1);
535           gtk_tree_store_set (GTK_TREE_STORE (model),
536                               &iter,
537                               ITALIC_COLUMN, !italic,
538                               -1);
539           window = (func) ();
540           if (window != NULL)
541             {
542               CallbackData *cbdata;
543
544               cbdata = g_new (CallbackData, 1);
545               cbdata->model = model;
546               cbdata->path = path;
547
548               gtk_signal_connect (GTK_OBJECT (window),
549                                   "destroy",
550                                   GTK_SIGNAL_FUNC (window_closed_cb),
551                                   cbdata);
552             }
553           else
554             {
555               gtk_tree_path_free (path);
556             }
557         }
558
559       gtk_signal_emit_stop_by_name (GTK_OBJECT (tree_view),
560                                     "button_press_event");
561       return TRUE;
562     }
563   
564   return FALSE;
565 }
566
567 void
568 row_activated_cb (GtkTreeView       *tree_view,
569                   GtkTreePath       *path,
570                   GtkTreeViewColumn *column)
571 {
572   GtkTreeIter iter;
573   gboolean italic;
574   GDoDemoFunc func;
575   GtkWidget *window;
576   GtkTreeModel *model;
577
578   model = gtk_tree_view_get_model (tree_view);
579   
580   gtk_tree_model_get_iter (model, &iter, path);
581   gtk_tree_model_get (GTK_TREE_MODEL (model),
582                       &iter,
583                       FUNC_COLUMN, &func,
584                       ITALIC_COLUMN, &italic,
585                       -1);
586   gtk_tree_store_set (GTK_TREE_STORE (model),
587                       &iter,
588                       ITALIC_COLUMN, !italic,
589                       -1);
590   window = (func) ();
591
592   if (window != NULL)
593     {
594       CallbackData *cbdata;
595       
596       cbdata = g_new (CallbackData, 1);
597       cbdata->model = model;
598       cbdata->path = gtk_tree_path_copy (path);
599       
600       gtk_signal_connect (GTK_OBJECT (window),
601                           "destroy",
602                           GTK_SIGNAL_FUNC (window_closed_cb),
603                           cbdata);
604     }
605 }
606
607 static void
608 selection_cb (GtkTreeSelection *selection,
609               GtkTreeModel     *model)
610 {
611   GtkTreeIter iter;
612   GValue value = {0, };
613
614   if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
615     return;
616
617   gtk_tree_model_get_value (model, &iter,
618                             FILENAME_COLUMN,
619                             &value);
620   load_file (g_value_get_string (&value));
621   g_value_unset (&value);
622 }
623
624 static GtkWidget *
625 create_text (GtkTextBuffer **buffer,
626              gboolean        is_source)
627 {
628   GtkWidget *scrolled_window;
629   GtkWidget *text_view;
630   PangoFontDescription *font_desc;
631
632   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
633   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
634                                   GTK_POLICY_AUTOMATIC,
635                                   GTK_POLICY_AUTOMATIC);
636   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
637                                        GTK_SHADOW_IN);
638   
639   text_view = gtk_text_view_new ();
640   
641   *buffer = gtk_text_buffer_new (NULL);
642   gtk_text_view_set_buffer (GTK_TEXT_VIEW (text_view), *buffer);
643   gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
644   gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
645
646   gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
647   
648   if (is_source)
649     {
650       font_desc = pango_font_description_from_string ("Courier 12");
651       gtk_widget_modify_font (text_view, font_desc);
652       pango_font_description_free (font_desc);
653
654       gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
655                                    GTK_WRAP_NONE);
656     }
657   else
658     {
659       /* Make it a bit nicer for text. */
660       gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
661                                    GTK_WRAP_WORD);
662       gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view),
663                                             2);
664       gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view),
665                                             2);
666     }
667   
668   return scrolled_window;
669 }
670
671 /* Technically a list, but if we do go to 80 demos, we may want to move to a tree */
672 static GtkWidget *
673 create_tree (void)
674 {
675   GtkTreeSelection *selection;
676   GtkCellRenderer *cell;
677   GtkWidget *tree_view;
678   GtkTreeViewColumn *column;
679   GtkTreeStore *model;
680   GtkTreeIter iter;
681   gint i;
682
683   model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
684   tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
685   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
686
687   gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
688                                GTK_SELECTION_BROWSE);
689   gtk_widget_set_size_request (tree_view, 200, -1);
690
691   for (i=0; i < G_N_ELEMENTS (testgtk_demos); i++)
692     {
693       gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
694
695       gtk_tree_store_set (GTK_TREE_STORE (model),
696                           &iter,
697                           TITLE_COLUMN, testgtk_demos[i].title,
698                           FILENAME_COLUMN, testgtk_demos[i].filename,
699                           FUNC_COLUMN, testgtk_demos[i].func,
700                           ITALIC_COLUMN, FALSE,
701                           -1);
702     }
703
704   cell = gtk_cell_renderer_text_new ();
705
706   g_object_set (G_OBJECT (cell),
707                 "style", PANGO_STYLE_ITALIC,
708                 NULL);
709   
710   column = gtk_tree_view_column_new_with_attributes ("Widget (double click for demo)",
711                                                      cell,
712                                                      "text", TITLE_COLUMN,
713                                                      "style_set", ITALIC_COLUMN,
714                                                      NULL);
715   
716   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
717                                GTK_TREE_VIEW_COLUMN (column));
718
719   g_signal_connect (G_OBJECT (selection), "changed", GTK_SIGNAL_FUNC (selection_cb), model);
720   g_signal_connect (G_OBJECT (tree_view), "row_activated", GTK_SIGNAL_FUNC (row_activated_cb), model);
721
722   return tree_view;
723 }
724
725 static void
726 setup_default_icon (void)
727 {
728   GdkPixbuf *pixbuf;
729   
730   /* Try in current directory, in case we haven't yet been installed
731    * (would be wrong in a real app)
732    */
733   pixbuf = gdk_pixbuf_new_from_file ("./gtk-logo-rgb.gif", NULL);
734
735   if (pixbuf == NULL)
736     {
737       GError *err;
738
739       err = NULL;
740       pixbuf = gdk_pixbuf_new_from_file (DEMOCODEDIR"/gtk-logo-rgb.gif",
741                                          &err);
742
743       /* Ignoring this error (passing NULL instead of &err above)
744        * would probably be reasonable for most apps.  We're just
745        * showing off.
746        */
747       if (err)
748         {
749           GtkWidget *dialog;
750           
751           dialog = gtk_message_dialog_new (NULL, 0,
752                                            GTK_MESSAGE_ERROR,
753                                            GTK_BUTTONS_CLOSE,
754                                            "Failed to read icon file "DEMOCODEDIR"/gtk-logo-rgb.gif: %s",
755                                            err->message);
756           g_error_free (err);
757
758           gtk_signal_connect (GTK_OBJECT (dialog),
759                               "response",
760                               GTK_SIGNAL_FUNC (gtk_widget_destroy),
761                               NULL);
762         }
763     }
764
765   if (pixbuf)
766     {
767       GList *list;      
768
769       list = NULL;
770       list = g_list_append (list, pixbuf);
771       gtk_window_set_default_icon_list (list);
772       g_list_free (list);
773       g_object_unref (G_OBJECT (pixbuf));
774     }
775 }
776
777 int
778 main (int argc, char **argv)
779 {
780   GtkWidget *window;
781   GtkWidget *notebook;
782   GtkWidget *hbox;
783   GtkWidget *tree;
784   GtkTextTag *tag;
785
786   /* Most code in gtk-demo is intended to be exemplary, but not
787    * these few lines, which are just a hack so gtk-demo will work
788    * in the GTK tree without installing it.
789    */
790   if (g_file_test ("../../gdk-pixbuf/.libs/libpixbufloader-pnm.so",
791                    G_FILE_TEST_EXISTS))
792     {
793       putenv ("GDK_PIXBUF_MODULEDIR=../../gdk-pixbuf/.libs");
794       putenv ("GTK_IM_MODULE_FILE=../../modules/input/gtk.immodules");
795     }
796   /* -- End of hack -- */
797   
798   gtk_init (&argc, &argv);
799
800   setup_default_icon ();
801   
802   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
803   gtk_window_set_title (GTK_WINDOW (window), "GTK+ Code Demos");
804   gtk_signal_connect (GTK_OBJECT (window), "destroy",
805                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
806
807   hbox = gtk_hbox_new (FALSE, 0);
808   gtk_container_add (GTK_CONTAINER (window), hbox);
809
810   tree = create_tree ();
811   gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
812
813   notebook = gtk_notebook_new ();
814   gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
815
816   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
817                             create_text (&info_buffer, FALSE),
818                             gtk_label_new_with_mnemonic ("_Info"));
819
820   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
821                             create_text (&source_buffer, TRUE),
822                             gtk_label_new_with_mnemonic ("_Source"));
823
824   tag = gtk_text_buffer_create_tag (info_buffer, "title",
825                                     "font", "Sans 18",
826                                     NULL);
827
828   tag = gtk_text_buffer_create_tag (source_buffer, "comment",
829                                     "foreground", "red",
830                                     NULL);
831   tag = gtk_text_buffer_create_tag (source_buffer, "type",
832                                     "foreground", "ForestGreen",
833                                     NULL);
834   tag = gtk_text_buffer_create_tag (source_buffer, "string",
835                                     "foreground", "RosyBrown",
836                                     "weight", PANGO_WEIGHT_BOLD,
837                                     NULL);
838   tag = gtk_text_buffer_create_tag (source_buffer, "control",
839                                     "foreground", "purple",
840                                     NULL);
841   tag = gtk_text_buffer_create_tag (source_buffer, "preprocessor",
842                                     "style", PANGO_STYLE_OBLIQUE,
843                                     "foreground", "burlywood4",
844                                     NULL);
845   tag = gtk_text_buffer_create_tag (source_buffer, "function",
846                                     "weight", PANGO_WEIGHT_BOLD,
847                                     "foreground", "DarkGoldenrod4",
848                                     NULL);
849   
850   gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
851   gtk_widget_show_all (window);
852   
853
854   load_file (testgtk_demos[0].filename);
855   
856   gtk_main ();
857
858   return 0;
859 }