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 (info_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 (info_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 ();
640 gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
642 *buffer = gtk_text_buffer_new (NULL);
643 gtk_text_view_set_buffer (GTK_TEXT_VIEW (text_view), *buffer);
644 gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
645 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
649 font_desc = pango_font_description_from_string ("Courier 12");
650 gtk_widget_modify_font (text_view, font_desc);
651 pango_font_description_free (font_desc);
653 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
658 /* Make it a bit nicer for text. */
659 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
661 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view),
663 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view),
667 return scrolled_window;
670 /* Technically a list, but if we do go to 80 demos, we may want to move to a tree */
674 GtkTreeSelection *selection;
675 GtkCellRenderer *cell;
676 GtkWidget *tree_view;
677 GtkTreeViewColumn *column;
682 model = gtk_tree_store_new_with_types (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
683 tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
684 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
686 gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
687 GTK_TREE_SELECTION_SINGLE);
688 gtk_widget_set_usize (tree_view, 200, -1);
690 for (i=0; i < G_N_ELEMENTS (testgtk_demos); i++)
692 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
694 gtk_tree_store_set (GTK_TREE_STORE (model),
696 TITLE_COLUMN, testgtk_demos[i].title,
697 FILENAME_COLUMN, testgtk_demos[i].filename,
698 FUNC_COLUMN, testgtk_demos[i].func,
699 ITALIC_COLUMN, FALSE,
703 cell = gtk_cell_renderer_text_new ();
705 g_object_set (G_OBJECT (cell),
706 "style", PANGO_STYLE_ITALIC,
709 column = gtk_tree_view_column_new_with_attributes ("Widget (double click for demo)",
711 "text", TITLE_COLUMN,
712 "style_set", ITALIC_COLUMN,
715 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
716 GTK_TREE_VIEW_COLUMN (column));
718 gtk_signal_connect (GTK_OBJECT (selection), "selection_changed", GTK_SIGNAL_FUNC (selection_cb), model);
719 gtk_signal_connect (GTK_OBJECT (tree_view), "row_activated", GTK_SIGNAL_FUNC (row_activated_cb), model);
725 main (int argc, char **argv)
733 /* Most code in gtk-demo is intended to be exemplary, but not
734 * these few lines, which are just a hack so gtk-demo will work
735 * in the GTK tree without installing it.
737 if (g_file_test ("../../gdk-pixbuf/.libs/libpixbufloader-pnm.so",
740 putenv ("GDK_PIXBUF_MODULEDIR=../../gdk-pixbuf/.libs");
741 putenv ("GTK_IM_MODULE_FILE=../../modules/input/gtk.immodules");
743 /* -- End of hack -- */
745 gtk_init (&argc, &argv);
747 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
748 gtk_window_set_title (GTK_WINDOW (window), "GTK+ Code Demos");
749 gtk_signal_connect (GTK_OBJECT (window), "destroy",
750 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
752 hbox = gtk_hbox_new (FALSE, 0);
753 gtk_container_add (GTK_CONTAINER (window), hbox);
755 tree = create_tree ();
756 gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
758 notebook = gtk_notebook_new ();
759 gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
761 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
762 create_text (&info_buffer, FALSE),
763 gtk_label_new_with_mnemonic ("_Info"));
765 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
766 create_text (&source_buffer, TRUE),
767 gtk_label_new_with_mnemonic ("_Source"));
769 tag = gtk_text_buffer_create_tag (info_buffer, "title",
773 tag = gtk_text_buffer_create_tag (info_buffer, "comment",
774 "foreground", "blue",
776 tag = gtk_text_buffer_create_tag (info_buffer, "type",
779 tag = gtk_text_buffer_create_tag (info_buffer, "string",
780 "foreground", "SpringGreen3",
781 "weight", PANGO_WEIGHT_BOLD,
783 tag = gtk_text_buffer_create_tag (info_buffer, "control",
784 "foreground", "purple",
786 tag = gtk_text_buffer_create_tag (info_buffer, "preprocessor",
787 "style", PANGO_STYLE_OBLIQUE,
788 "foreground", "burlywood4",
790 tag = gtk_text_buffer_create_tag (info_buffer, "function",
791 "weight", PANGO_WEIGHT_BOLD,
792 "foreground", "DarkGoldenrod4",
795 gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
796 gtk_widget_show_all (window);
799 load_file (testgtk_demos[0].filename);