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-3.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 = G_VALUE_INIT;
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_override_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)
935 /* Most code in gtk-demo is intended to be exemplary, but not
936 * these few lines, which are just a hack so gtk-demo will work
937 * in the GTK tree without installing it.
939 if (g_file_test ("../../gdk-pixbuf/libpixbufloader-pnm.la",
942 g_setenv ("GDK_PIXBUF_MODULE_FILE", "../../gdk-pixbuf/loaders.cache", TRUE);
943 g_setenv ("GTK_IM_MODULE_FILE", "../../modules/input/immodules.cache", TRUE);
945 /* -- End of hack -- */
947 gtk_init (&argc, &argv);
949 setup_default_icon ();
951 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
952 gtk_window_set_title (GTK_WINDOW (window), "GTK+ Code Demos");
953 g_signal_connect_after (window, "destroy",
954 G_CALLBACK (gtk_main_quit), NULL);
956 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
957 gtk_container_add (GTK_CONTAINER (window), hbox);
959 tree = create_tree ();
960 gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
962 notebook = gtk_notebook_new ();
963 gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
965 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
966 create_text (&info_buffer, FALSE),
967 gtk_label_new_with_mnemonic ("_Info"));
969 gtk_text_buffer_create_tag (info_buffer, "title",
972 g_object_unref (info_buffer);
974 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
975 create_text (&source_buffer, TRUE),
976 gtk_label_new_with_mnemonic ("_Source"));
979 gtk_text_buffer_create_tag (source_buffer, "comment",
980 "foreground", "DodgerBlue",
982 gtk_text_buffer_create_tag (source_buffer, "type",
983 "foreground", "ForestGreen",
985 gtk_text_buffer_create_tag (source_buffer, "string",
986 "foreground", "RosyBrown",
987 "weight", PANGO_WEIGHT_BOLD,
989 gtk_text_buffer_create_tag (source_buffer, "control",
990 "foreground", "purple",
992 gtk_text_buffer_create_tag (source_buffer, "preprocessor",
993 "style", PANGO_STYLE_OBLIQUE,
994 "foreground", "burlywood4",
996 gtk_text_buffer_create_tag (source_buffer, "function",
997 "weight", PANGO_WEIGHT_BOLD,
998 "foreground", "DarkGoldenrod4",
1000 g_object_unref (source_buffer);
1002 gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
1003 gtk_widget_show_all (window);
1005 load_file (testgtk_demos[0].filename);