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[] =
227 "GtkColorSelection ",
241 "GtkRadioActionEntry ",
249 "GdkEventWindowState ",
254 "GtkToggleActionEntry ",
266 "GtkTreeViewColumn ",
267 "GdkDisplayManager ",
284 "GdkEventConfigure ",
287 "GtkEntryCompletion ",
291 "GtkCellRendererText ",
295 "GtkPrintOperation ",
299 "PangoFontDescription ",
313 "GdkEventVisibility ",
315 "GtkTextChildAnchor ",
318 "GtkCellRendererToggle ",
322 static gchar *control[] =
336 parse_chars (gchar *text,
345 /* Handle comments first */
346 if (*state == STATE_IN_COMMENT)
348 *end_ptr = strstr (text, "*/");
352 *state = STATE_NORMAL;
361 /* check for comment */
362 if (!strncmp (text, "/*", 2))
364 *end_ptr = strstr (text, "*/");
368 *state = STATE_IN_COMMENT;
373 /* check for preprocessor defines */
374 if (*text == '#' && start)
377 *tag = "preprocessor";
382 if (start && * text != '\t' && *text != ' ' && *text != '{' && *text != '}')
384 if (strstr (text, "("))
386 *end_ptr = strstr (text, "(");
391 /* check for types */
392 for (i = 0; types[i] != NULL; i++)
393 if (!strncmp (text, types[i], strlen (types[i])) ||
394 (start && types[i][0] == ' ' && !strncmp (text, types[i] + 1, strlen (types[i]) - 1)))
396 *end_ptr = text + strlen (types[i]);
401 /* check for control */
402 for (i = 0; control[i] != NULL; i++)
403 if (!strncmp (text, control[i], strlen (control[i])))
405 *end_ptr = text + strlen (control[i]);
410 /* check for string */
413 gint maybe_escape = FALSE;
417 while (**end_ptr != '\000')
419 if (**end_ptr == '\"' && !maybe_escape)
424 if (**end_ptr == '\\')
427 maybe_escape = FALSE;
433 /* not at the start of a tag. Find the next one. */
434 for (i = 0; tokens[i] != NULL; i++)
436 next_token = strstr (text, tokens[i]);
440 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
442 *end_ptr = next_token;
446 for (i = 0; types[i] != NULL; i++)
448 next_token = strstr (text, types[i]);
452 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
454 *end_ptr = next_token;
458 for (i = 0; control[i] != NULL; i++)
460 next_token = strstr (text, control[i]);
464 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
466 *end_ptr = next_token;
471 /* While not as cool as c-mode, this will do as a quick attempt at highlighting */
475 GtkTextIter start_iter, next_iter, tmp_iter;
478 gchar *start_ptr, *end_ptr;
481 state = STATE_NORMAL;
483 gtk_text_buffer_get_iter_at_offset (source_buffer, &start_iter, 0);
485 next_iter = start_iter;
486 while (gtk_text_iter_forward_line (&next_iter))
488 gboolean start = TRUE;
489 start_ptr = text = gtk_text_iter_get_text (&start_iter, &next_iter);
493 parse_chars (start_ptr, &end_ptr, &state, &tag, start);
498 tmp_iter = start_iter;
499 gtk_text_iter_forward_chars (&tmp_iter, end_ptr - start_ptr);
503 tmp_iter = next_iter;
506 gtk_text_buffer_apply_tag_by_name (source_buffer, tag, &start_iter, &tmp_iter);
508 start_iter = tmp_iter;
514 start_iter = next_iter;
519 load_file (const gchar *filename)
522 GtkTextIter start, end;
525 GString *buffer = g_string_new (NULL);
527 gboolean in_para = 0;
529 if (current_file && !strcmp (current_file, filename))
531 g_string_free (buffer, TRUE);
535 g_free (current_file);
536 current_file = g_strdup (filename);
538 gtk_text_buffer_get_bounds (info_buffer, &start, &end);
539 gtk_text_buffer_delete (info_buffer, &start, &end);
541 gtk_text_buffer_get_bounds (source_buffer, &start, &end);
542 gtk_text_buffer_delete (source_buffer, &start, &end);
544 full_filename = demo_find_file (filename, &err);
547 g_warning ("%s", err->message);
552 file = g_fopen (full_filename, "r");
555 g_warning ("Cannot open %s: %s\n", full_filename, g_strerror (errno));
557 g_free (full_filename);
562 gtk_text_buffer_get_iter_at_offset (info_buffer, &start, 0);
563 while (read_line (file, buffer))
565 gchar *p = buffer->str;
573 while (*p == '/' || *p == '*' || g_ascii_isspace (*p))
576 while (*r != '/' && strlen (r))
581 while (q > p && g_ascii_isspace (*(q - 1)))
586 int len_chars = g_utf8_pointer_to_offset (p, q);
590 g_assert (strlen (p) >= q - p);
591 gtk_text_buffer_insert (info_buffer, &end, p, q - p);
594 gtk_text_iter_backward_chars (&start, len_chars);
595 gtk_text_buffer_apply_tag_by_name (info_buffer, "title", &start, &end);
604 /* Reading body of info section */
605 while (g_ascii_isspace (*p))
607 if (*p == '*' && *(p + 1) == '/')
609 gtk_text_buffer_get_iter_at_offset (source_buffer, &start, 0);
616 while (*p == '*' || g_ascii_isspace (*p))
620 while (g_ascii_isspace (*(p + len - 1)))
626 gtk_text_buffer_insert (info_buffer, &start, " ", 1);
628 g_assert (strlen (p) >= len);
629 gtk_text_buffer_insert (info_buffer, &start, p, len);
634 gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
641 /* Skipping blank lines */
642 while (g_ascii_isspace (*p))
654 /* Reading program body */
655 gtk_text_buffer_insert (source_buffer, &start, p, -1);
656 gtk_text_buffer_insert (source_buffer, &start, "\n", 1);
665 g_string_free (buffer, TRUE);
669 row_activated_cb (GtkTreeView *tree_view,
671 GtkTreeViewColumn *column)
679 model = gtk_tree_view_get_model (tree_view);
681 gtk_tree_model_get_iter (model, &iter, path);
682 gtk_tree_model_get (GTK_TREE_MODEL (model),
685 STYLE_COLUMN, &style,
690 gtk_tree_store_set (GTK_TREE_STORE (model),
692 STYLE_COLUMN, (style == PANGO_STYLE_ITALIC ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC),
694 window = (func) (gtk_widget_get_toplevel (GTK_WIDGET (tree_view)));
698 CallbackData *cbdata;
700 cbdata = g_new (CallbackData, 1);
701 cbdata->model = model;
702 cbdata->path = gtk_tree_path_copy (path);
704 g_signal_connect (window, "destroy",
705 G_CALLBACK (window_closed_cb), cbdata);
711 selection_cb (GtkTreeSelection *selection,
715 GValue value = {0, };
717 if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
720 gtk_tree_model_get_value (model, &iter,
723 if (g_value_get_string (&value))
724 load_file (g_value_get_string (&value));
725 g_value_unset (&value);
729 create_text (GtkTextBuffer **buffer,
732 GtkWidget *scrolled_window;
733 GtkWidget *text_view;
734 PangoFontDescription *font_desc;
736 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
737 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
738 GTK_POLICY_AUTOMATIC,
739 GTK_POLICY_AUTOMATIC);
740 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
743 text_view = gtk_text_view_new ();
745 *buffer = gtk_text_buffer_new (NULL);
746 gtk_text_view_set_buffer (GTK_TEXT_VIEW (text_view), *buffer);
747 gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
748 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
750 gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
754 font_desc = pango_font_description_from_string ("monospace");
755 gtk_widget_modify_font (text_view, font_desc);
756 pango_font_description_free (font_desc);
758 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
763 /* Make it a bit nicer for text. */
764 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
766 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view),
768 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view),
772 return scrolled_window;
778 GtkTreeSelection *selection;
779 GtkCellRenderer *cell;
780 GtkWidget *tree_view;
781 GtkTreeViewColumn *column;
784 GtkWidget *box, *label, *scrolled_window;
786 Demo *d = testgtk_demos;
788 model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
789 tree_view = gtk_tree_view_new ();
790 gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
791 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
793 gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
794 GTK_SELECTION_BROWSE);
795 gtk_widget_set_size_request (tree_view, 200, -1);
797 /* this code only supports 1 level of children. If we
798 * want more we probably have to use a recursing function.
802 Demo *children = d->children;
804 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
806 gtk_tree_store_set (GTK_TREE_STORE (model),
808 TITLE_COLUMN, d->title,
809 FILENAME_COLUMN, d->filename,
810 FUNC_COLUMN, d->func,
811 STYLE_COLUMN, PANGO_STYLE_NORMAL,
819 while (children->title)
821 GtkTreeIter child_iter;
823 gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &iter);
825 gtk_tree_store_set (GTK_TREE_STORE (model),
827 TITLE_COLUMN, children->title,
828 FILENAME_COLUMN, children->filename,
829 FUNC_COLUMN, children->func,
830 STYLE_COLUMN, PANGO_STYLE_NORMAL,
837 cell = gtk_cell_renderer_text_new ();
839 column = gtk_tree_view_column_new_with_attributes ("Widget (double click for demo)",
841 "text", TITLE_COLUMN,
842 "style", STYLE_COLUMN,
845 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
846 GTK_TREE_VIEW_COLUMN (column));
848 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
849 gtk_tree_selection_select_iter (GTK_TREE_SELECTION (selection), &iter);
851 g_signal_connect (selection, "changed", G_CALLBACK (selection_cb), model);
852 g_signal_connect (tree_view, "row_activated", G_CALLBACK (row_activated_cb), model);
854 gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
855 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
857 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
858 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
860 GTK_POLICY_AUTOMATIC);
861 gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
863 label = gtk_label_new ("Widget (double click for demo)");
865 box = gtk_notebook_new ();
866 gtk_notebook_append_page (GTK_NOTEBOOK (box), scrolled_window, label);
868 gtk_widget_grab_focus (tree_view);
870 g_object_unref (model);
876 setup_default_icon (void)
885 filename = demo_find_file ("gtk-logo-rgb.gif", &err);
888 pixbuf = gdk_pixbuf_new_from_file (filename, &err);
892 /* Ignoring this error (passing NULL instead of &err above)
893 * would probably be reasonable for most apps. We're just
900 dialog = gtk_message_dialog_new (NULL, 0,
903 "Failed to read icon file: %s",
907 g_signal_connect (dialog, "response",
908 G_CALLBACK (gtk_widget_destroy), NULL);
914 GdkPixbuf *transparent;
916 /* The gtk-logo-rgb icon has a white background, make it transparent */
917 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
920 list = g_list_append (list, transparent);
921 gtk_window_set_default_icon_list (list);
923 g_object_unref (pixbuf);
924 g_object_unref (transparent);
929 main (int argc, char **argv)
937 /* Most code in gtk-demo is intended to be exemplary, but not
938 * these few lines, which are just a hack so gtk-demo will work
939 * in the GTK tree without installing it.
941 if (g_file_test ("../../gdk-pixbuf/libpixbufloader-pnm.la",
944 g_setenv ("GDK_PIXBUF_MODULE_FILE", "../../gdk-pixbuf/gdk-pixbuf.loaders", TRUE);
945 g_setenv ("GTK_IM_MODULE_FILE", "../../modules/input/gtk.immodules", TRUE);
947 /* -- End of hack -- */
949 gtk_init (&argc, &argv);
951 setup_default_icon ();
953 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
954 gtk_window_set_title (GTK_WINDOW (window), "GTK+ Code Demos");
955 g_signal_connect_after (window, "destroy",
956 G_CALLBACK (gtk_main_quit), NULL);
958 hbox = gtk_hbox_new (FALSE, 0);
959 gtk_container_add (GTK_CONTAINER (window), hbox);
961 tree = create_tree ();
962 gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
964 notebook = gtk_notebook_new ();
965 gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
967 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
968 create_text (&info_buffer, FALSE),
969 gtk_label_new_with_mnemonic ("_Info"));
971 tag = gtk_text_buffer_create_tag (info_buffer, "title",
974 g_object_unref (info_buffer);
976 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
977 create_text (&source_buffer, TRUE),
978 gtk_label_new_with_mnemonic ("_Source"));
981 tag = gtk_text_buffer_create_tag (source_buffer, "comment",
982 "foreground", "DodgerBlue",
984 tag = gtk_text_buffer_create_tag (source_buffer, "type",
985 "foreground", "ForestGreen",
987 tag = gtk_text_buffer_create_tag (source_buffer, "string",
988 "foreground", "RosyBrown",
989 "weight", PANGO_WEIGHT_BOLD,
991 tag = gtk_text_buffer_create_tag (source_buffer, "control",
992 "foreground", "purple",
994 tag = gtk_text_buffer_create_tag (source_buffer, "preprocessor",
995 "style", PANGO_STYLE_OBLIQUE,
996 "foreground", "burlywood4",
998 tag = gtk_text_buffer_create_tag (source_buffer, "function",
999 "weight", PANGO_WEIGHT_BOLD,
1000 "foreground", "DarkGoldenrod4",
1002 g_object_unref (source_buffer);
1004 gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
1005 gtk_widget_show_all (window);
1008 load_file (testgtk_demos[0].filename);