8 #include <glib/gstdio.h>
12 static GtkWidget *info_view;
13 static GtkWidget *source_view;
15 static gchar *current_file = NULL;
17 static GtkWidget *notebook;
28 typedef struct _CallbackData CallbackData;
36 window_closed_cb (GtkWidget *window, gpointer data)
38 CallbackData *cbdata = data;
42 gtk_tree_model_get_iter (cbdata->model, &iter, cbdata->path);
43 gtk_tree_model_get (GTK_TREE_MODEL (cbdata->model), &iter,
46 if (style == PANGO_STYLE_ITALIC)
47 gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter,
48 STYLE_COLUMN, PANGO_STYLE_NORMAL,
51 gtk_tree_path_free (cbdata->path);
55 /* Stupid syntax highlighting.
57 * No regex was used in the making of this highlighting.
58 * It should only work for simple cases. This is good, as
59 * that's all we should have in the demos.
61 /* This code should not be used elsewhere, except perhaps as an example of how
62 * to iterate through a text buffer.
69 static gchar *tokens[] =
76 static gchar *types[] =
110 "GtkColorSelection ",
124 "GtkRadioActionEntry ",
132 "GdkEventWindowState ",
137 "GtkToggleActionEntry ",
149 "GtkTreeViewColumn ",
150 "GdkDisplayManager ",
165 "GtkEditableInterface ",
167 "GdkEventConfigure ",
170 "GtkEntryCompletion ",
174 "GtkCellRendererText ",
178 "GtkPrintOperation ",
182 "PangoFontDescription ",
196 "GdkEventVisibility ",
198 "GtkTextChildAnchor ",
201 "GtkCellRendererToggle ",
205 static gchar *control[] =
219 parse_chars (gchar *text,
228 /* Handle comments first */
229 if (*state == STATE_IN_COMMENT)
231 *end_ptr = strstr (text, "*/");
235 *state = STATE_NORMAL;
244 /* check for comment */
245 if (!strncmp (text, "/*", 2))
247 *end_ptr = strstr (text, "*/");
251 *state = STATE_IN_COMMENT;
256 /* check for preprocessor defines */
257 if (*text == '#' && start)
260 *tag = "preprocessor";
265 if (start && * text != '\t' && *text != ' ' && *text != '{' && *text != '}')
267 if (strstr (text, "("))
269 *end_ptr = strstr (text, "(");
274 /* check for types */
275 for (i = 0; types[i] != NULL; i++)
276 if (!strncmp (text, types[i], strlen (types[i])) ||
277 (start && types[i][0] == ' ' && !strncmp (text, types[i] + 1, strlen (types[i]) - 1)))
279 *end_ptr = text + strlen (types[i]);
284 /* check for control */
285 for (i = 0; control[i] != NULL; i++)
286 if (!strncmp (text, control[i], strlen (control[i])))
288 *end_ptr = text + strlen (control[i]);
293 /* check for string */
296 gint maybe_escape = FALSE;
300 while (**end_ptr != '\000')
302 if (**end_ptr == '\"' && !maybe_escape)
307 if (**end_ptr == '\\')
310 maybe_escape = FALSE;
316 /* not at the start of a tag. Find the next one. */
317 for (i = 0; tokens[i] != NULL; i++)
319 next_token = strstr (text, tokens[i]);
323 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
325 *end_ptr = next_token;
329 for (i = 0; types[i] != NULL; i++)
331 next_token = strstr (text, types[i]);
335 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
337 *end_ptr = next_token;
341 for (i = 0; control[i] != NULL; i++)
343 next_token = strstr (text, control[i]);
347 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
349 *end_ptr = next_token;
354 /* While not as cool as c-mode, this will do as a quick attempt at highlighting */
356 fontify (GtkTextBuffer *source_buffer)
358 GtkTextIter start_iter, next_iter, tmp_iter;
361 gchar *start_ptr, *end_ptr;
364 state = STATE_NORMAL;
366 gtk_text_buffer_get_iter_at_offset (source_buffer, &start_iter, 0);
368 next_iter = start_iter;
369 while (gtk_text_iter_forward_line (&next_iter))
371 gboolean start = TRUE;
372 start_ptr = text = gtk_text_iter_get_text (&start_iter, &next_iter);
376 parse_chars (start_ptr, &end_ptr, &state, &tag, start);
381 tmp_iter = start_iter;
382 gtk_text_iter_forward_chars (&tmp_iter, end_ptr - start_ptr);
386 tmp_iter = next_iter;
389 gtk_text_buffer_apply_tag_by_name (source_buffer, tag, &start_iter, &tmp_iter);
391 start_iter = tmp_iter;
397 start_iter = next_iter;
401 static GtkWidget *create_text (GtkWidget **text_view, gboolean is_source);
404 add_data_tab (const gchar *demoname)
406 gchar *resource_dir, *resource_name, *content_type;
409 GtkWidget *widget, *label;
412 resource_dir = g_strconcat ("/", demoname, NULL);
413 resources = g_resources_enumerate_children (resource_dir, 0, NULL);
414 if (resources == NULL)
416 g_free (resource_dir);
420 for (i = 0; resources[i]; i++)
422 resource_name = g_strconcat (resource_dir, "/", resources[i], NULL);
423 bytes = g_resources_lookup_data (resource_name, 0, NULL);
426 content_type = g_content_type_guess (resource_name,
427 g_bytes_get_data (bytes, NULL),
428 g_bytes_get_size (bytes),
431 /* In theory we should look at all the mime types gdk-pixbuf supports
432 * and go from there, but we know what file types we've added.
434 if (g_content_type_is_a (content_type, "image/png") ||
435 g_content_type_is_a (content_type, "image/gif") ||
436 g_content_type_is_a (content_type, "image/jpeg"))
438 widget = gtk_image_new_from_resource (resource_name);
440 else if (g_content_type_is_a (content_type, "text/plain"))
442 GtkTextBuffer *buffer;
445 widget = create_text (&textview, FALSE);
446 buffer = gtk_text_buffer_new (NULL);
447 gtk_text_buffer_set_text (buffer, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
448 gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer);
452 g_warning ("Don't know how to display resource '%s' of type '%s'\n", resource_name, content_type);
456 gtk_widget_show_all (widget);
457 label = gtk_label_new (resources[i]);
458 gtk_widget_show (label);
459 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), widget, label);
461 g_free (content_type);
462 g_free (resource_name);
463 g_bytes_unref (bytes);
466 g_strfreev (resources);
467 g_free (resource_dir);
471 remove_data_tabs (void)
475 for (i = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)) - 1; i > 1; i--)
476 gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), i);
480 load_file (const gchar *demoname,
481 const gchar *filename)
483 GtkTextBuffer *info_buffer, *source_buffer;
484 GtkTextIter start, end;
485 char *resource_filename;
488 gboolean in_para = 0;
493 if (!g_strcmp0 (current_file, filename))
498 add_data_tab (demoname);
500 g_free (current_file);
501 current_file = g_strdup (filename);
503 info_buffer = gtk_text_buffer_new (NULL);
504 gtk_text_buffer_create_tag (info_buffer, "title",
506 "pixels-below-lines", 10,
509 source_buffer = gtk_text_buffer_new (NULL);
510 gtk_text_buffer_create_tag (source_buffer, "comment",
511 "foreground", "DodgerBlue",
513 gtk_text_buffer_create_tag (source_buffer, "type",
514 "foreground", "ForestGreen",
516 gtk_text_buffer_create_tag (source_buffer, "string",
517 "foreground", "RosyBrown",
518 "weight", PANGO_WEIGHT_BOLD,
520 gtk_text_buffer_create_tag (source_buffer, "control",
521 "foreground", "purple",
523 gtk_text_buffer_create_tag (source_buffer, "preprocessor",
524 "style", PANGO_STYLE_OBLIQUE,
525 "foreground", "burlywood4",
527 gtk_text_buffer_create_tag (source_buffer, "function",
528 "weight", PANGO_WEIGHT_BOLD,
529 "foreground", "DarkGoldenrod4",
532 resource_filename = g_strconcat ("/sources/", filename, NULL);
533 bytes = g_resources_lookup_data (resource_filename, 0, &err);
534 g_free (resource_filename);
538 g_warning ("Cannot open source for %s: %s\n", filename, err->message);
543 lines = g_strsplit (g_bytes_get_data (bytes, NULL), "\n", -1);
544 g_bytes_unref (bytes);
546 gtk_text_buffer_get_iter_at_offset (info_buffer, &start, 0);
547 for (i = 0; lines[i] != NULL; i++)
553 /* Make sure \r is stripped at the end for the poor windows people */
554 lines[i] = g_strchomp (lines[i]);
561 while (*p == '/' || *p == '*' || g_ascii_isspace (*p))
566 while (*r != '/' && *r != ':' && *r != '\0')
573 if (r[0] == ':' && r[1] == ':')
577 while (q > p && g_ascii_isspace (*(q - 1)))
583 int len_chars = g_utf8_pointer_to_offset (p, q);
587 g_assert (strlen (p) >= q - p);
588 gtk_text_buffer_insert (info_buffer, &end, p, q - p);
591 gtk_text_iter_backward_chars (&start, len_chars);
592 gtk_text_buffer_apply_tag_by_name (info_buffer, "title", &start, &end);
596 while (*p && *p != '\n') p++;
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);
660 fontify (source_buffer);
664 gtk_text_view_set_buffer (GTK_TEXT_VIEW (info_view), info_buffer);
665 g_object_unref (info_buffer);
666 gtk_text_view_set_buffer (GTK_TEXT_VIEW (source_view), source_buffer);
667 g_object_unref (source_buffer);
671 row_activated_cb (GtkTreeView *tree_view,
673 GtkTreeViewColumn *column)
681 model = gtk_tree_view_get_model (tree_view);
683 gtk_tree_model_get_iter (model, &iter, path);
684 gtk_tree_model_get (GTK_TREE_MODEL (model),
687 STYLE_COLUMN, &style,
692 gtk_tree_store_set (GTK_TREE_STORE (model),
694 STYLE_COLUMN, (style == PANGO_STYLE_ITALIC ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC),
696 window = (func) (gtk_widget_get_toplevel (GTK_WIDGET (tree_view)));
700 CallbackData *cbdata;
702 cbdata = g_new (CallbackData, 1);
703 cbdata->model = model;
704 cbdata->path = gtk_tree_path_copy (path);
706 g_signal_connect (window, "destroy",
707 G_CALLBACK (window_closed_cb), cbdata);
713 selection_cb (GtkTreeSelection *selection,
717 char *name, *filename;
719 if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
722 gtk_tree_model_get (model, &iter,
724 FILENAME_COLUMN, &filename,
728 load_file (name, filename);
735 create_text (GtkWidget **view,
738 GtkWidget *scrolled_window;
739 GtkWidget *text_view;
740 PangoFontDescription *font_desc;
742 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
743 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
744 GTK_POLICY_AUTOMATIC,
745 GTK_POLICY_AUTOMATIC);
746 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
749 *view = text_view = gtk_text_view_new ();
750 g_object_set (text_view, "margin", 20, NULL);
752 gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
753 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
755 gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
759 font_desc = pango_font_description_from_string ("monospace");
760 gtk_widget_override_font (text_view, font_desc);
761 pango_font_description_free (font_desc);
763 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
768 /* Make it a bit nicer for text. */
769 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
771 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view),
773 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view),
777 return scrolled_window;
783 GtkTreeSelection *selection;
784 GtkCellRenderer *cell;
785 GtkWidget *tree_view;
786 GtkTreeViewColumn *column;
789 GtkWidget *box, *label, *scrolled_window;
793 model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
794 tree_view = gtk_tree_view_new ();
795 gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
796 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
798 gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
799 GTK_SELECTION_BROWSE);
800 gtk_widget_set_size_request (tree_view, 200, -1);
802 /* this code only supports 1 level of children. If we
803 * want more we probably have to use a recursing function.
807 Demo *children = d->children;
809 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
811 gtk_tree_store_set (GTK_TREE_STORE (model),
813 NAME_COLUMN, d->name,
814 TITLE_COLUMN, d->title,
815 FILENAME_COLUMN, d->filename,
816 FUNC_COLUMN, d->func,
817 STYLE_COLUMN, PANGO_STYLE_NORMAL,
825 while (children->title)
827 GtkTreeIter child_iter;
829 gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &iter);
831 gtk_tree_store_set (GTK_TREE_STORE (model),
833 NAME_COLUMN, children->name,
834 TITLE_COLUMN, children->title,
835 FILENAME_COLUMN, children->filename,
836 FUNC_COLUMN, children->func,
837 STYLE_COLUMN, PANGO_STYLE_NORMAL,
844 cell = gtk_cell_renderer_text_new ();
846 column = gtk_tree_view_column_new_with_attributes ("Widget (double click for demo)",
848 "text", TITLE_COLUMN,
849 "style", STYLE_COLUMN,
852 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
853 GTK_TREE_VIEW_COLUMN (column));
855 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
856 gtk_tree_selection_select_iter (GTK_TREE_SELECTION (selection), &iter);
858 g_signal_connect (selection, "changed", G_CALLBACK (selection_cb), model);
859 g_signal_connect (tree_view, "row_activated", G_CALLBACK (row_activated_cb), model);
861 gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
862 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
864 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
865 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
867 GTK_POLICY_AUTOMATIC);
868 gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
870 label = gtk_label_new ("Widget (double click for demo)");
872 box = gtk_notebook_new ();
873 gtk_notebook_append_page (GTK_NOTEBOOK (box), scrolled_window, label);
875 gtk_widget_grab_focus (tree_view);
877 g_object_unref (model);
883 setup_default_icon (void)
887 pixbuf = gdk_pixbuf_new_from_resource ("/gtk-logo-old.png", NULL);
888 /* We load a resource, so we can guarantee that loading it is successful */
891 gtk_window_set_default_icon (pixbuf);
893 g_object_unref (pixbuf);
897 main (int argc, char **argv)
903 /* Most code in gtk-demo is intended to be exemplary, but not
904 * these few lines, which are just a hack so gtk-demo will work
905 * in the GTK tree without installing it.
907 if (g_file_test ("../../modules/input/immodules.cache", G_FILE_TEST_EXISTS))
909 g_setenv ("GTK_IM_MODULE_FILE", "../../modules/input/immodules.cache", TRUE);
911 /* -- End of hack -- */
913 gtk_init (&argc, &argv);
915 setup_default_icon ();
917 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
918 gtk_window_set_title (GTK_WINDOW (window), "GTK+ Code Demos");
919 g_signal_connect_after (window, "destroy",
920 G_CALLBACK (gtk_main_quit), NULL);
922 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
923 gtk_container_add (GTK_CONTAINER (window), hbox);
925 tree = create_tree ();
926 gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
928 notebook = gtk_notebook_new ();
929 gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
930 gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
932 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
933 create_text (&info_view, FALSE),
934 gtk_label_new_with_mnemonic ("_Info"));
936 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
937 create_text (&source_view, TRUE),
938 gtk_label_new_with_mnemonic ("_Source"));
940 gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
941 gtk_widget_show_all (window);
943 load_file (gtk_demos[0].name, gtk_demos[0].filename);