8 #include <glib/gstdio.h>
12 static GtkTextBuffer *info_buffer;
13 static GtkTextBuffer *source_buffer;
15 static gchar *current_file = NULL;
26 typedef struct _CallbackData CallbackData;
38 get_democodedir (void)
40 static char *result = NULL;
44 result = g_win32_get_package_installation_directory_of_module (NULL);
46 result = "unknown-location";
48 result = g_strconcat (result, "\\share\\gtk-2.0\\demo", NULL);
54 #define DEMOCODEDIR get_democodedir ()
60 * @base: base filename
61 * @err: location to store error, or %NULL.
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.
67 * Return value: the filename, if found or %NULL
70 demo_find_file (const char *base,
73 g_return_val_if_fail (err == NULL || *err == NULL, NULL);
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);
80 char *filename = g_build_filename (DEMOCODEDIR, base, NULL);
81 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
83 g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_NOENT,
84 "Cannot find demo data file \"%s\"", base);
93 window_closed_cb (GtkWidget *window, gpointer data)
95 CallbackData *cbdata = data;
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,
103 if (style == PANGO_STYLE_ITALIC)
104 gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter,
105 STYLE_COLUMN, PANGO_STYLE_NORMAL,
108 gtk_tree_path_free (cbdata->path);
113 read_line (FILE *stream, GString *str)
117 #ifdef HAVE_FLOCKFILE
121 g_string_truncate (str, 0);
127 #ifdef HAVE_FLOCKFILE
128 c = getc_unlocked (stream);
143 #ifdef HAVE_FLOCKFILE
144 int next_c = getc_unlocked (stream);
146 int next_c = getc (stream);
149 if (!(next_c == EOF ||
150 (c == '\r' && next_c == '\n') ||
151 (c == '\n' && next_c == '\r')))
152 ungetc (next_c, stream);
157 g_string_append_c (str, c);
163 #ifdef HAVE_FLOCKFILE
164 funlockfile (stream);
171 /* Stupid syntax highlighting.
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.
177 /* This code should not be used elsewhere, except perhaps as an example of how
178 * to iterate through a text buffer.
185 static gchar *tokens[] =
192 static gchar *types[] =
226 "GtkColorSelection ",
240 "GtkRadioActionEntry ",
248 "GdkEventWindowState ",
253 "GtkToggleActionEntry ",
265 "GtkTreeViewColumn ",
266 "GdkDisplayManager ",
281 "GtkEditableInterface ",
283 "GdkEventConfigure ",
286 "GtkEntryCompletion ",
290 "GtkCellRendererText ",
294 "GtkPrintOperation ",
298 "PangoFontDescription ",
312 "GdkEventVisibility ",
314 "GtkTextChildAnchor ",
317 "GtkCellRendererToggle ",
321 static gchar *control[] =
335 parse_chars (gchar *text,
344 /* Handle comments first */
345 if (*state == STATE_IN_COMMENT)
347 *end_ptr = strstr (text, "*/");
351 *state = STATE_NORMAL;
360 /* check for comment */
361 if (!strncmp (text, "/*", 2))
363 *end_ptr = strstr (text, "*/");
367 *state = STATE_IN_COMMENT;
372 /* check for preprocessor defines */
373 if (*text == '#' && start)
376 *tag = "preprocessor";
381 if (start && * text != '\t' && *text != ' ' && *text != '{' && *text != '}')
383 if (strstr (text, "("))
385 *end_ptr = strstr (text, "(");
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)))
395 *end_ptr = text + strlen (types[i]);
400 /* check for control */
401 for (i = 0; control[i] != NULL; i++)
402 if (!strncmp (text, control[i], strlen (control[i])))
404 *end_ptr = text + strlen (control[i]);
409 /* check for string */
412 gint maybe_escape = FALSE;
416 while (**end_ptr != '\000')
418 if (**end_ptr == '\"' && !maybe_escape)
423 if (**end_ptr == '\\')
426 maybe_escape = FALSE;
432 /* not at the start of a tag. Find the next one. */
433 for (i = 0; tokens[i] != NULL; i++)
435 next_token = strstr (text, tokens[i]);
439 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
441 *end_ptr = next_token;
445 for (i = 0; types[i] != NULL; i++)
447 next_token = strstr (text, types[i]);
451 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
453 *end_ptr = next_token;
457 for (i = 0; control[i] != NULL; i++)
459 next_token = strstr (text, control[i]);
463 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
465 *end_ptr = next_token;
470 /* While not as cool as c-mode, this will do as a quick attempt at highlighting */
474 GtkTextIter start_iter, next_iter, tmp_iter;
477 gchar *start_ptr, *end_ptr;
480 state = STATE_NORMAL;
482 gtk_text_buffer_get_iter_at_offset (source_buffer, &start_iter, 0);
484 next_iter = start_iter;
485 while (gtk_text_iter_forward_line (&next_iter))
487 gboolean start = TRUE;
488 start_ptr = text = gtk_text_iter_get_text (&start_iter, &next_iter);
492 parse_chars (start_ptr, &end_ptr, &state, &tag, start);
497 tmp_iter = start_iter;
498 gtk_text_iter_forward_chars (&tmp_iter, end_ptr - start_ptr);
502 tmp_iter = next_iter;
505 gtk_text_buffer_apply_tag_by_name (source_buffer, tag, &start_iter, &tmp_iter);
507 start_iter = tmp_iter;
513 start_iter = next_iter;
518 load_file (const gchar *filename)
521 GtkTextIter start, end;
524 GString *buffer = g_string_new (NULL);
526 gboolean in_para = 0;
528 if (current_file && !strcmp (current_file, filename))
530 g_string_free (buffer, TRUE);
534 g_free (current_file);
535 current_file = g_strdup (filename);
537 gtk_text_buffer_get_bounds (info_buffer, &start, &end);
538 gtk_text_buffer_delete (info_buffer, &start, &end);
540 gtk_text_buffer_get_bounds (source_buffer, &start, &end);
541 gtk_text_buffer_delete (source_buffer, &start, &end);
543 full_filename = demo_find_file (filename, &err);
546 g_warning ("%s", err->message);
551 file = g_fopen (full_filename, "r");
554 g_warning ("Cannot open %s: %s\n", full_filename, g_strerror (errno));
556 g_free (full_filename);
561 gtk_text_buffer_get_iter_at_offset (info_buffer, &start, 0);
562 while (read_line (file, buffer))
564 gchar *p = buffer->str;
572 while (*p == '/' || *p == '*' || g_ascii_isspace (*p))
575 while (*r != '/' && strlen (r))
580 while (q > p && g_ascii_isspace (*(q - 1)))
585 int len_chars = g_utf8_pointer_to_offset (p, q);
589 g_assert (strlen (p) >= q - p);
590 gtk_text_buffer_insert (info_buffer, &end, p, q - p);
593 gtk_text_iter_backward_chars (&start, len_chars);
594 gtk_text_buffer_apply_tag_by_name (info_buffer, "title", &start, &end);
603 /* Reading body of info section */
604 while (g_ascii_isspace (*p))
606 if (*p == '*' && *(p + 1) == '/')
608 gtk_text_buffer_get_iter_at_offset (source_buffer, &start, 0);
615 while (*p == '*' || g_ascii_isspace (*p))
619 while (g_ascii_isspace (*(p + len - 1)))
625 gtk_text_buffer_insert (info_buffer, &start, " ", 1);
627 g_assert (strlen (p) >= len);
628 gtk_text_buffer_insert (info_buffer, &start, p, len);
633 gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
640 /* Skipping blank lines */
641 while (g_ascii_isspace (*p))
653 /* Reading program body */
654 gtk_text_buffer_insert (source_buffer, &start, p, -1);
655 gtk_text_buffer_insert (source_buffer, &start, "\n", 1);
664 g_string_free (buffer, TRUE);
668 row_activated_cb (GtkTreeView *tree_view,
670 GtkTreeViewColumn *column)
678 model = gtk_tree_view_get_model (tree_view);
680 gtk_tree_model_get_iter (model, &iter, path);
681 gtk_tree_model_get (GTK_TREE_MODEL (model),
684 STYLE_COLUMN, &style,
689 gtk_tree_store_set (GTK_TREE_STORE (model),
691 STYLE_COLUMN, (style == PANGO_STYLE_ITALIC ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC),
693 window = (func) (gtk_widget_get_toplevel (GTK_WIDGET (tree_view)));
697 CallbackData *cbdata;
699 cbdata = g_new (CallbackData, 1);
700 cbdata->model = model;
701 cbdata->path = gtk_tree_path_copy (path);
703 g_signal_connect (window, "destroy",
704 G_CALLBACK (window_closed_cb), cbdata);
710 selection_cb (GtkTreeSelection *selection,
714 GValue value = {0, };
716 if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
719 gtk_tree_model_get_value (model, &iter,
722 if (g_value_get_string (&value))
723 load_file (g_value_get_string (&value));
724 g_value_unset (&value);
728 create_text (GtkTextBuffer **buffer,
731 GtkWidget *scrolled_window;
732 GtkWidget *text_view;
733 PangoFontDescription *font_desc;
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),
742 text_view = gtk_text_view_new ();
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);
749 gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
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);
757 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
762 /* Make it a bit nicer for text. */
763 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
765 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view),
767 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view),
771 return scrolled_window;
777 GtkTreeSelection *selection;
778 GtkCellRenderer *cell;
779 GtkWidget *tree_view;
780 GtkTreeViewColumn *column;
783 GtkWidget *box, *label, *scrolled_window;
785 Demo *d = testgtk_demos;
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));
792 gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
793 GTK_SELECTION_BROWSE);
794 gtk_widget_set_size_request (tree_view, 200, -1);
796 /* this code only supports 1 level of children. If we
797 * want more we probably have to use a recursing function.
801 Demo *children = d->children;
803 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
805 gtk_tree_store_set (GTK_TREE_STORE (model),
807 TITLE_COLUMN, d->title,
808 FILENAME_COLUMN, d->filename,
809 FUNC_COLUMN, d->func,
810 STYLE_COLUMN, PANGO_STYLE_NORMAL,
818 while (children->title)
820 GtkTreeIter child_iter;
822 gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &iter);
824 gtk_tree_store_set (GTK_TREE_STORE (model),
826 TITLE_COLUMN, children->title,
827 FILENAME_COLUMN, children->filename,
828 FUNC_COLUMN, children->func,
829 STYLE_COLUMN, PANGO_STYLE_NORMAL,
836 cell = gtk_cell_renderer_text_new ();
838 column = gtk_tree_view_column_new_with_attributes ("Widget (double click for demo)",
840 "text", TITLE_COLUMN,
841 "style", STYLE_COLUMN,
844 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
845 GTK_TREE_VIEW_COLUMN (column));
847 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
848 gtk_tree_selection_select_iter (GTK_TREE_SELECTION (selection), &iter);
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);
853 gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
854 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
856 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
857 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
859 GTK_POLICY_AUTOMATIC);
860 gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
862 label = gtk_label_new ("Widget (double click for demo)");
864 box = gtk_notebook_new ();
865 gtk_notebook_append_page (GTK_NOTEBOOK (box), scrolled_window, label);
867 gtk_widget_grab_focus (tree_view);
869 g_object_unref (model);
875 setup_default_icon (void)
884 filename = demo_find_file ("gtk-logo-rgb.gif", &err);
887 pixbuf = gdk_pixbuf_new_from_file (filename, &err);
891 /* Ignoring this error (passing NULL instead of &err above)
892 * would probably be reasonable for most apps. We're just
899 dialog = gtk_message_dialog_new (NULL, 0,
902 "Failed to read icon file: %s",
906 g_signal_connect (dialog, "response",
907 G_CALLBACK (gtk_widget_destroy), NULL);
913 GdkPixbuf *transparent;
915 /* The gtk-logo-rgb icon has a white background, make it transparent */
916 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
919 list = g_list_append (list, transparent);
920 gtk_window_set_default_icon_list (list);
922 g_object_unref (pixbuf);
923 g_object_unref (transparent);
928 main (int argc, char **argv)
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.
940 if (g_file_test ("../../gdk-pixbuf/libpixbufloader-pnm.la",
943 g_setenv ("GDK_PIXBUF_MODULE_FILE", "../../gdk-pixbuf/loaders.cache", TRUE);
944 g_setenv ("GTK_IM_MODULE_FILE", "../../modules/input/immodules.cache", TRUE);
946 /* -- End of hack -- */
948 gtk_init (&argc, &argv);
950 setup_default_icon ();
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);
957 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
958 gtk_container_add (GTK_CONTAINER (window), hbox);
960 tree = create_tree ();
961 gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
963 notebook = gtk_notebook_new ();
964 gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
966 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
967 create_text (&info_buffer, FALSE),
968 gtk_label_new_with_mnemonic ("_Info"));
970 tag = gtk_text_buffer_create_tag (info_buffer, "title",
973 g_object_unref (info_buffer);
975 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
976 create_text (&source_buffer, TRUE),
977 gtk_label_new_with_mnemonic ("_Source"));
980 tag = gtk_text_buffer_create_tag (source_buffer, "comment",
981 "foreground", "DodgerBlue",
983 tag = gtk_text_buffer_create_tag (source_buffer, "type",
984 "foreground", "ForestGreen",
986 tag = gtk_text_buffer_create_tag (source_buffer, "string",
987 "foreground", "RosyBrown",
988 "weight", PANGO_WEIGHT_BOLD,
990 tag = gtk_text_buffer_create_tag (source_buffer, "control",
991 "foreground", "purple",
993 tag = gtk_text_buffer_create_tag (source_buffer, "preprocessor",
994 "style", PANGO_STYLE_OBLIQUE,
995 "foreground", "burlywood4",
997 tag = gtk_text_buffer_create_tag (source_buffer, "function",
998 "weight", PANGO_WEIGHT_BOLD,
999 "foreground", "DarkGoldenrod4",
1001 g_object_unref (source_buffer);
1003 gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
1004 gtk_widget_show_all (window);
1007 load_file (testgtk_demos[0].filename);