11 static GtkTextBuffer *info_buffer;
12 static GtkTextBuffer *source_buffer;
14 static gchar *current_file = NULL;
24 typedef struct _CallbackData CallbackData;
32 window_closed_cb (GtkWidget *window, gpointer data)
34 CallbackData *cbdata = data;
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,
43 gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter,
44 ITALIC_COLUMN, !italic,
47 gtk_tree_path_free (cbdata->path);
52 read_line (FILE *stream, GString *str)
58 g_string_truncate (str, 0);
64 c = getc_unlocked (stream);
76 int next_c = getc_unlocked (stream);
78 if (!(next_c == EOF ||
79 (c == '\r' && next_c == '\n') ||
80 (c == '\n' && next_c == '\r')))
81 ungetc (next_c, stream);
86 g_string_append_c (str, c);
98 /* Stupid syntax highlighting.
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.
104 /* This code should not be used elsewhere, except perhaps as an example of how
105 * to iterate through a text buffer.
112 static gchar *tokens[] =
119 static gchar *types[] =
153 "GtkColorSelection ",
167 static gchar *control[] =
181 parse_chars (gchar *text,
190 /* Handle comments first */
191 if (*state == STATE_IN_COMMENT)
193 *end_ptr = strstr (text, "*/");
197 *state = STATE_NORMAL;
206 /* check for comment */
207 if (!strncmp (text, "/*", 2))
209 *end_ptr = strstr (text, "*/");
213 *state = STATE_IN_COMMENT;
218 /* check for preprocessor defines */
219 if (*text == '#' && start)
222 *tag = "preprocessor";
227 if (start && * text != '\t' && *text != ' ' && *text != '{' && *text != '}')
229 if (strstr (text, "("))
231 *end_ptr = strstr (text, "(");
236 /* check for types */
237 for (i = 0; types[i] != NULL; i++)
238 if (!strncmp (text, types[i], strlen (types[i])))
240 *end_ptr = text + strlen (types[i]);
245 /* check for control */
246 for (i = 0; control[i] != NULL; i++)
247 if (!strncmp (text, control[i], strlen (control[i])))
249 *end_ptr = text + strlen (control[i]);
254 /* check for string */
257 gint maybe_escape = FALSE;
261 while (**end_ptr != '\000')
263 if (**end_ptr == '\"' && !maybe_escape)
268 if (**end_ptr == '\\')
271 maybe_escape = FALSE;
277 /* not at the start of a tag. Find the next one. */
278 for (i = 0; tokens[i] != NULL; i++)
280 next_token = strstr (text, tokens[i]);
284 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
286 *end_ptr = next_token;
290 for (i = 0; types[i] != NULL; i++)
292 next_token = strstr (text, types[i]);
296 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
298 *end_ptr = next_token;
302 for (i = 0; control[i] != NULL; i++)
304 next_token = strstr (text, control[i]);
308 *end_ptr = (*end_ptr<next_token)?*end_ptr:next_token;
310 *end_ptr = next_token;
315 /* While not as cool as c-mode, this will do as a quick attempt at highlighting */
319 GtkTextIter start_iter, next_iter, tmp_iter;
322 gchar *start_ptr, *end_ptr;
325 state = STATE_NORMAL;
327 gtk_text_buffer_get_iter_at_offset (source_buffer, &start_iter, 0);
329 next_iter = start_iter;
330 while (gtk_text_iter_forward_line (&next_iter))
332 gboolean start = TRUE;
333 start_ptr = text = gtk_text_iter_get_text (&start_iter, &next_iter);
337 parse_chars (start_ptr, &end_ptr, &state, &tag, start);
342 tmp_iter = start_iter;
343 gtk_text_iter_forward_chars (&tmp_iter, end_ptr - start_ptr);
347 tmp_iter = next_iter;
350 gtk_text_buffer_apply_tag_by_name (source_buffer, tag, &start_iter, &tmp_iter);
352 start_iter = tmp_iter;
358 start_iter = next_iter;
363 load_file (const gchar *filename)
366 GtkTextIter start, end;
367 GString *buffer = g_string_new (NULL);
369 gboolean in_para = 0;
371 if (current_file && !strcmp (current_file, filename))
373 g_string_free (buffer, TRUE);
377 g_free (current_file);
378 current_file = g_strdup (filename);
380 gtk_text_buffer_get_bounds (info_buffer, &start, &end);
381 gtk_text_buffer_delete (info_buffer, &start, &end);
383 gtk_text_buffer_get_bounds (source_buffer, &start, &end);
384 gtk_text_buffer_delete (source_buffer, &start, &end);
386 file = fopen (filename, "r");
390 char *installed = g_strconcat (DEMOCODEDIR,
395 file = fopen (installed, "r");
402 g_warning ("Cannot open %s: %s\n", filename, g_strerror (errno));
406 gtk_text_buffer_get_iter_at_offset (info_buffer, &start, 0);
407 while (read_line (file, buffer))
409 gchar *p = buffer->str;
416 while (*p == '/' || *p == '*' || isspace (*p))
419 while (q > p && isspace (*(q - 1)))
424 int len_chars = g_utf8_pointer_to_offset (p, q);
428 g_assert (strlen (p) >= q - p);
429 gtk_text_buffer_insert (info_buffer, &end, p, q - p);
432 gtk_text_iter_backward_chars (&start, len_chars);
433 gtk_text_buffer_apply_tag_by_name (info_buffer, "title", &start, &end);
442 /* Reading body of info section */
445 if (*p == '*' && *(p + 1) == '/')
447 gtk_text_buffer_get_iter_at_offset (source_buffer, &start, 0);
454 while (*p == '*' || isspace (*p))
458 while (isspace (*(p + len - 1)))
464 gtk_text_buffer_insert (info_buffer, &start, " ", 1);
466 g_assert (strlen (p) >= len);
467 gtk_text_buffer_insert (info_buffer, &start, p, len);
472 gtk_text_buffer_insert (info_buffer, &start, "\n", 1);
479 /* Skipping blank lines */
492 /* Reading program body */
493 gtk_text_buffer_insert (source_buffer, &start, p, -1);
494 gtk_text_buffer_insert (source_buffer, &start, "\n", 1);
501 g_string_free (buffer, TRUE);
505 button_press_event_cb (GtkTreeView *tree_view,
506 GdkEventButton *event,
509 if (event->type == GDK_2BUTTON_PRESS)
511 GtkTreePath *path = NULL;
513 gtk_tree_view_get_path_at_pos (tree_view,
529 gtk_tree_model_get_iter (model, &iter, path);
530 gtk_tree_model_get (GTK_TREE_MODEL (model),
533 ITALIC_COLUMN, &italic,
535 gtk_tree_store_set (GTK_TREE_STORE (model),
537 ITALIC_COLUMN, !italic,
542 CallbackData *cbdata;
544 cbdata = g_new (CallbackData, 1);
545 cbdata->model = model;
548 gtk_signal_connect (GTK_OBJECT (window),
550 GTK_SIGNAL_FUNC (window_closed_cb),
555 gtk_tree_path_free (path);
559 gtk_signal_emit_stop_by_name (GTK_OBJECT (tree_view),
560 "button_press_event");
568 row_activated_cb (GtkTreeView *tree_view,
570 GtkTreeViewColumn *column)
578 model = gtk_tree_view_get_model (tree_view);
580 gtk_tree_model_get_iter (model, &iter, path);
581 gtk_tree_model_get (GTK_TREE_MODEL (model),
584 ITALIC_COLUMN, &italic,
586 gtk_tree_store_set (GTK_TREE_STORE (model),
588 ITALIC_COLUMN, !italic,
594 CallbackData *cbdata;
596 cbdata = g_new (CallbackData, 1);
597 cbdata->model = model;
598 cbdata->path = gtk_tree_path_copy (path);
600 gtk_signal_connect (GTK_OBJECT (window),
602 GTK_SIGNAL_FUNC (window_closed_cb),
608 selection_cb (GtkTreeSelection *selection,
612 GValue value = {0, };
614 if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
617 gtk_tree_model_get_value (model, &iter,
620 load_file (g_value_get_string (&value));
621 g_value_unset (&value);
625 create_text (GtkTextBuffer **buffer,
628 GtkWidget *scrolled_window;
629 GtkWidget *text_view;
630 PangoFontDescription *font_desc;
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),
639 text_view = gtk_text_view_new ();
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);
646 gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
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);
654 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
659 /* Make it a bit nicer for text. */
660 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
662 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view),
664 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view),
668 return scrolled_window;
671 /* Technically a list, but if we do go to 80 demos, we may want to move to a tree */
675 GtkTreeSelection *selection;
676 GtkCellRenderer *cell;
677 GtkWidget *tree_view;
678 GtkTreeViewColumn *column;
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));
687 gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
688 GTK_SELECTION_BROWSE);
689 gtk_widget_set_size_request (tree_view, 200, -1);
691 for (i=0; i < G_N_ELEMENTS (testgtk_demos); i++)
693 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
695 gtk_tree_store_set (GTK_TREE_STORE (model),
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,
704 cell = gtk_cell_renderer_text_new ();
706 g_object_set (G_OBJECT (cell),
707 "style", PANGO_STYLE_ITALIC,
710 column = gtk_tree_view_column_new_with_attributes ("Widget (double click for demo)",
712 "text", TITLE_COLUMN,
713 "style_set", ITALIC_COLUMN,
716 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
717 GTK_TREE_VIEW_COLUMN (column));
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);
726 setup_default_icon (void)
730 /* Try in current directory, in case we haven't yet been installed
731 * (would be wrong in a real app)
733 pixbuf = gdk_pixbuf_new_from_file ("./gtk-logo-rgb.gif", NULL);
740 pixbuf = gdk_pixbuf_new_from_file (DEMOCODEDIR"/gtk-logo-rgb.gif",
743 /* Ignoring this error (passing NULL instead of &err above)
744 * would probably be reasonable for most apps. We're just
751 dialog = gtk_message_dialog_new (NULL, 0,
754 "Failed to read icon file "DEMOCODEDIR"/gtk-logo-rgb.gif: %s",
758 gtk_signal_connect (GTK_OBJECT (dialog),
760 GTK_SIGNAL_FUNC (gtk_widget_destroy),
770 list = g_list_append (list, pixbuf);
771 gtk_window_set_default_icon_list (list);
773 g_object_unref (G_OBJECT (pixbuf));
778 main (int argc, char **argv)
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.
790 if (g_file_test ("../../gdk-pixbuf/.libs/libpixbufloader-pnm.so",
793 putenv ("GDK_PIXBUF_MODULEDIR=../../gdk-pixbuf/.libs");
794 putenv ("GTK_IM_MODULE_FILE=../../modules/input/gtk.immodules");
796 /* -- End of hack -- */
798 gtk_init (&argc, &argv);
800 setup_default_icon ();
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);
807 hbox = gtk_hbox_new (FALSE, 0);
808 gtk_container_add (GTK_CONTAINER (window), hbox);
810 tree = create_tree ();
811 gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
813 notebook = gtk_notebook_new ();
814 gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
816 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
817 create_text (&info_buffer, FALSE),
818 gtk_label_new_with_mnemonic ("_Info"));
820 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
821 create_text (&source_buffer, TRUE),
822 gtk_label_new_with_mnemonic ("_Source"));
824 tag = gtk_text_buffer_create_tag (info_buffer, "title",
828 tag = gtk_text_buffer_create_tag (source_buffer, "comment",
831 tag = gtk_text_buffer_create_tag (source_buffer, "type",
832 "foreground", "ForestGreen",
834 tag = gtk_text_buffer_create_tag (source_buffer, "string",
835 "foreground", "RosyBrown",
836 "weight", PANGO_WEIGHT_BOLD,
838 tag = gtk_text_buffer_create_tag (source_buffer, "control",
839 "foreground", "purple",
841 tag = gtk_text_buffer_create_tag (source_buffer, "preprocessor",
842 "style", PANGO_STYLE_OBLIQUE,
843 "foreground", "burlywood4",
845 tag = gtk_text_buffer_create_tag (source_buffer, "function",
846 "weight", PANGO_WEIGHT_BOLD,
847 "foreground", "DarkGoldenrod4",
850 gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
851 gtk_widget_show_all (window);
854 load_file (testgtk_demos[0].filename);