8 #undef GTK_DISABLE_DEPRECATED
11 #include <gdk/gdkkeysyms.h>
13 #include "prop-editor.h"
15 typedef struct _Buffer Buffer;
16 typedef struct _View View;
18 static gint untitled_serial = 1;
20 GSList *active_window_stack = NULL;
25 GtkTextBuffer *buffer;
28 GtkTextTag *invisible_tag;
29 GtkTextTag *not_editable_tag;
30 GtkTextTag *found_text_tag;
31 GtkTextTag *custom_tabs_tag;
33 guint color_cycle_timeout;
41 GtkAccelGroup *accel_group;
42 GtkItemFactory *item_factory;
46 static void push_active_window (GtkWindow *window);
47 static void pop_active_window (void);
48 static GtkWindow *get_active_window (void);
50 static Buffer * create_buffer (void);
51 static gboolean check_buffer_saved (Buffer *buffer);
52 static gboolean save_buffer (Buffer *buffer);
53 static gboolean save_as_buffer (Buffer *buffer);
54 static char * buffer_pretty_name (Buffer *buffer);
55 static void buffer_filename_set (Buffer *buffer);
56 static void buffer_search_forward (Buffer *buffer,
59 static void buffer_search_backward (Buffer *buffer,
62 static void buffer_set_colors (Buffer *buffer,
64 static void buffer_cycle_colors (Buffer *buffer);
66 static View *view_from_widget (GtkWidget *widget);
68 static View *create_view (Buffer *buffer);
69 static void check_close_view (View *view);
70 static void close_view (View *view);
71 static void view_set_title (View *view);
72 static void view_init_menus (View *view);
73 static void view_add_example_widgets (View *view);
75 GSList *buffers = NULL;
79 push_active_window (GtkWindow *window)
81 g_object_ref (window);
82 active_window_stack = g_slist_prepend (active_window_stack, window);
86 pop_active_window (void)
88 g_object_unref (active_window_stack->data);
89 active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack);
93 get_active_window (void)
95 if (active_window_stack)
96 return active_window_stack->data;
102 * Filesel utility function
105 typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data);
108 filesel_ok_cb (GtkWidget *button, GtkWidget *filesel)
110 FileselOKFunc ok_func = (FileselOKFunc)g_object_get_data (G_OBJECT (filesel), "ok-func");
111 gpointer data = g_object_get_data (G_OBJECT (filesel), "ok-data");
112 gint *result = g_object_get_data (G_OBJECT (filesel), "ok-result");
114 gtk_widget_hide (filesel);
116 if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data))
118 gtk_widget_destroy (filesel);
122 gtk_widget_show (filesel);
126 filesel_run (GtkWindow *parent,
128 const char *start_file,
132 GtkWidget *filesel = gtk_file_selection_new (title);
133 gboolean result = FALSE;
136 parent = get_active_window ();
139 gtk_window_set_transient_for (GTK_WINDOW (filesel), parent);
142 gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file);
145 g_object_set_data (G_OBJECT (filesel), "ok-func", func);
146 g_object_set_data (G_OBJECT (filesel), "ok-data", data);
147 g_object_set_data (G_OBJECT (filesel), "ok-result", &result);
149 g_signal_connect (GTK_FILE_SELECTION (filesel)->ok_button,
151 G_CALLBACK (filesel_ok_cb), filesel);
152 g_signal_connect_swapped (GTK_FILE_SELECTION (filesel)->cancel_button,
154 G_CALLBACK (gtk_widget_destroy), filesel);
156 g_signal_connect (filesel, "destroy",
157 G_CALLBACK (gtk_main_quit), NULL);
158 gtk_window_set_modal (GTK_WINDOW (filesel), TRUE);
160 gtk_widget_show (filesel);
167 * MsgBox utility functions
171 msgbox_yes_cb (GtkWidget *widget, gboolean *result)
174 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
178 msgbox_no_cb (GtkWidget *widget, gboolean *result)
181 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
185 msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
187 if (event->keyval == GDK_Escape)
189 g_signal_stop_emission_by_name (widget, "key_press_event");
190 gtk_object_destroy (GTK_OBJECT (widget));
197 /* Don't copy this example, it's all crack-smoking - you can just use
198 * GtkMessageDialog now
201 msgbox_run (GtkWindow *parent,
203 const char *yes_button,
204 const char *no_button,
205 const char *cancel_button,
208 gboolean result = -1;
213 GtkWidget *button_box;
214 GtkWidget *separator;
216 g_return_val_if_fail (message != NULL, FALSE);
217 g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE);
220 parent = get_active_window ();
224 dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
225 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
227 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
228 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
230 /* Quit our recursive main loop when the dialog is destroyed.
232 g_signal_connect (dialog, "destroy",
233 G_CALLBACK (gtk_main_quit), NULL);
235 /* Catch Escape key presses and have them destroy the dialog
237 g_signal_connect (dialog, "key_press_event",
238 G_CALLBACK (msgbox_key_press_cb), NULL);
240 /* Fill in the contents of the widget
242 vbox = gtk_vbox_new (FALSE, 0);
243 gtk_container_add (GTK_CONTAINER (dialog), vbox);
245 label = gtk_label_new (message);
246 gtk_misc_set_padding (GTK_MISC (label), 12, 12);
247 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
248 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
250 separator = gtk_hseparator_new ();
251 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
253 button_box = gtk_hbutton_box_new ();
254 gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
255 gtk_container_set_border_width (GTK_CONTAINER (button_box), 8);
258 /* When Yes is clicked, call the msgbox_yes_cb
259 * This sets the result variable and destroys the dialog
263 button = gtk_button_new_with_label (yes_button);
264 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
265 gtk_container_add (GTK_CONTAINER (button_box), button);
267 if (default_index == 0)
268 gtk_widget_grab_default (button);
270 g_signal_connect (button, "clicked",
271 G_CALLBACK (msgbox_yes_cb), &result);
274 /* When No is clicked, call the msgbox_no_cb
275 * This sets the result variable and destroys the dialog
279 button = gtk_button_new_with_label (no_button);
280 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
281 gtk_container_add (GTK_CONTAINER (button_box), button);
283 if (default_index == 0)
284 gtk_widget_grab_default (button);
286 g_signal_connect (button, "clicked",
287 G_CALLBACK (msgbox_no_cb), &result);
290 /* When Cancel is clicked, destroy the dialog
294 button = gtk_button_new_with_label (cancel_button);
295 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
296 gtk_container_add (GTK_CONTAINER (button_box), button);
298 if (default_index == 1)
299 gtk_widget_grab_default (button);
301 g_signal_connect_swapped (button, "clicked",
302 G_CALLBACK (gtk_object_destroy), dialog);
305 gtk_widget_show_all (dialog);
307 /* Run a recursive main loop until a button is clicked
308 * or the user destroys the dialog through the window mananger */
316 * Example buffer filling code
319 blink_timeout (gpointer data)
322 static gboolean flip = FALSE;
324 tag = GTK_TEXT_TAG (data);
327 "foreground", flip ? "blue" : "purple",
337 tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
338 const GtkTextIter *iter, gpointer user_data)
342 char_index = gtk_text_iter_get_offset (iter);
346 case GDK_MOTION_NOTIFY:
347 printf ("Motion event at char %d tag `%s'\n",
348 char_index, tag->name);
351 case GDK_BUTTON_PRESS:
352 printf ("Button press at char %d tag `%s'\n",
353 char_index, tag->name);
356 case GDK_2BUTTON_PRESS:
357 printf ("Double click at char %d tag `%s'\n",
358 char_index, tag->name);
361 case GDK_3BUTTON_PRESS:
362 printf ("Triple click at char %d tag `%s'\n",
363 char_index, tag->name);
366 case GDK_BUTTON_RELEASE:
367 printf ("Button release at char %d tag `%s'\n",
368 char_index, tag->name);
372 case GDK_KEY_RELEASE:
373 printf ("Key event at char %d tag `%s'\n",
374 char_index, tag->name);
377 case GDK_ENTER_NOTIFY:
378 case GDK_LEAVE_NOTIFY:
379 case GDK_PROPERTY_NOTIFY:
380 case GDK_SELECTION_CLEAR:
381 case GDK_SELECTION_REQUEST:
382 case GDK_SELECTION_NOTIFY:
383 case GDK_PROXIMITY_IN:
384 case GDK_PROXIMITY_OUT:
387 case GDK_DRAG_MOTION:
388 case GDK_DRAG_STATUS:
390 case GDK_DROP_FINISHED:
399 setup_tag (GtkTextTag *tag)
401 g_signal_connect (tag,
403 G_CALLBACK (tag_event_handler),
407 static const char *book_closed_xpm[] = {
433 fill_example_buffer (GtkTextBuffer *buffer)
435 GtkTextIter iter, iter2;
437 GtkTextChildAnchor *anchor;
444 /* FIXME this is broken if called twice on a buffer, since
445 * we try to create tags a second time.
448 tag = gtk_text_buffer_create_tag (buffer, "fg_blue", NULL);
451 gtk_timeout_add (1000, blink_timeout, tag);
456 color.red = color.green = 0;
462 "foreground_gdk", &color,
463 "background_gdk", &color2,
467 tag = gtk_text_buffer_create_tag (buffer, "fg_red", NULL);
471 color.blue = color.green = 0;
474 "rise", -4 * PANGO_SCALE,
475 "foreground_gdk", &color,
478 tag = gtk_text_buffer_create_tag (buffer, "bg_green", NULL);
482 color.blue = color.red = 0;
483 color.green = 0xffff;
485 "background_gdk", &color,
489 tag = gtk_text_buffer_create_tag (buffer, "strikethrough", NULL);
494 "strikethrough", TRUE,
498 tag = gtk_text_buffer_create_tag (buffer, "underline", NULL);
503 "underline", PANGO_UNDERLINE_SINGLE,
506 tag = gtk_text_buffer_create_tag (buffer, "underline_error", NULL);
511 "underline", PANGO_UNDERLINE_ERROR,
514 tag = gtk_text_buffer_create_tag (buffer, "centered", NULL);
517 "justification", GTK_JUSTIFY_CENTER,
520 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote", NULL);
523 "wrap_mode", GTK_WRAP_WORD,
524 "direction", GTK_TEXT_DIR_RTL,
531 tag = gtk_text_buffer_create_tag (buffer, "negative_indent", NULL);
537 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
539 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
541 g_object_ref (anchor);
543 g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
544 (GDestroyNotify) g_object_unref);
546 pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
551 GtkTextMark * temp_mark;
553 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
555 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
557 str = g_strdup_printf ("%d Hello World! blah blah blah blah blah blah blah blah blah blah blah blah\nwoo woo woo woo woo woo woo woo woo woo woo woo woo woo woo\n",
560 gtk_text_buffer_insert (buffer, &iter, str, -1);
564 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
566 gtk_text_buffer_insert (buffer, &iter,
567 "(Hello World!)\nfoo foo Hello this is some text we are using to text word wrap. It has punctuation! gee; blah - hmm, great.\nnew line with a significant quantity of text on it. This line really does contain some text. More text! More text! More text!\n"
568 /* This is UTF8 stuff, Emacs doesn't
569 really know how to display it */
570 "German (Deutsch S\303\274d) Gr\303\274\303\237 Gott Greek (\316\225\316\273\316\273\316\267\316\275\316\271\316\272\316\254) \316\223\316\265\316\271\316\254 \317\203\316\261\317\202 Hebrew(\327\251\327\234\327\225\327\235) Hebrew punctuation(\xd6\xbf\327\251\xd6\xbb\xd6\xbc\xd6\xbb\xd6\xbf\327\234\xd6\xbc\327\225\xd6\xbc\xd6\xbb\xd6\xbb\xd6\xbf\327\235\xd6\xbc\xd6\xbb\xd6\xbf) Japanese (\346\227\245\346\234\254\350\252\236) Thai (\340\270\252\340\270\247\340\270\261\340\270\252\340\270\224\340\270\265\340\270\204\340\270\243\340\270\261\340\270\232) Thai wrong spelling (\340\270\204\340\270\263\340\270\225\340\271\210\340\270\255\340\271\204\340\270\233\340\270\231\340\270\267\340\271\210\340\270\252\340\270\260\340\270\201\340\270\224\340\270\234\340\270\264\340\270\224 \340\270\236\340\270\261\340\270\261\340\271\211\340\270\261\340\270\261\340\271\210\340\270\207\340\271\202\340\270\201\340\270\260)\n", -1);
573 gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
576 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
577 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
579 gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
581 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
582 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
584 gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
586 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 4);
587 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 7);
589 gtk_text_buffer_apply_tag_by_name (buffer, "underline_error", &iter, &iter2);
591 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
592 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
594 gtk_text_buffer_apply_tag_by_name (buffer, "strikethrough", &iter, &iter2);
596 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
597 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
599 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
601 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
602 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
604 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
606 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
607 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
609 gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
612 gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
613 gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
615 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
616 gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
618 gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
619 gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
620 gtk_text_buffer_insert (buffer, &iter, "\331\210\331\202\330\257 \330\250\330\257\330\243 \330\253\331\204\330\247\330\253 \331\205\331\206 \330\243\331\203\330\253\330\261 \330\247\331\204\331\205\330\244\330\263\330\263\330\247\330\252 \330\252\331\202\330\257\331\205\330\247 \331\201\331\212 \330\264\330\250\331\203\330\251 \330\247\331\203\330\263\331\212\331\210\331\206 \330\250\330\261\330\247\331\205\330\254\331\207\330\247 \331\203\331\205\331\206\330\270\331\205\330\247\330\252 \331\204\330\247 \330\252\330\263\330\271\331\211 \331\204\331\204\330\261\330\250\330\255\330\214 \330\253\331\205 \330\252\330\255\331\210\331\204\330\252 \331\201\331\212 \330\247\331\204\330\263\331\206\331\210\330\247\330\252 \330\247\331\204\330\256\331\205\330\263 \330\247\331\204\331\205\330\247\330\266\331\212\330\251 \330\245\331\204\331\211 \331\205\330\244\330\263\330\263\330\247\330\252 \331\205\330\247\331\204\331\212\330\251 \331\205\331\206\330\270\331\205\330\251\330\214 \331\210\330\250\330\247\330\252\330\252 \330\254\330\262\330\241\330\247 \331\205\331\206 \330\247\331\204\331\206\330\270\330\247\331\205 \330\247\331\204\331\205\330\247\331\204\331\212 \331\201\331\212 \330\250\331\204\330\257\330\247\331\206\331\207\330\247\330\214 \331\210\331\204\331\203\331\206\331\207\330\247 \330\252\330\252\330\256\330\265\330\265 \331\201\331\212 \330\256\330\257\331\205\330\251 \331\202\330\267\330\247\330\271 \330\247\331\204\331\205\330\264\330\261\331\210\330\271\330\247\330\252 \330\247\331\204\330\265\330\272\331\212\330\261\330\251. \331\210\330\243\330\255\330\257 \330\243\331\203\330\253\330\261 \331\207\330\260\331\207 \330\247\331\204\331\205\330\244\330\263\330\263\330\247\330\252 \331\206\330\254\330\247\330\255\330\247 \331\207\331\210 \302\273\330\250\330\247\331\206\331\203\331\210\330\263\331\210\331\204\302\253 \331\201\331\212 \330\250\331\210\331\204\331\212\331\201\331\212\330\247.\n", -1);
621 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
622 gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
624 gtk_text_buffer_insert_with_tags (buffer, &iter,
625 "Paragraph with negative indentation. blah blah blah blah blah. The quick brown fox jumped over the lazy dog.\n",
627 gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (buffer),
634 g_object_unref (pixbuf);
636 printf ("%d lines %d chars\n",
637 gtk_text_buffer_get_line_count (buffer),
638 gtk_text_buffer_get_char_count (buffer));
640 /* Move cursor to start */
641 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
642 gtk_text_buffer_place_cursor (buffer, &iter);
644 gtk_text_buffer_set_modified (buffer, FALSE);
648 fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
653 GtkTextIter iter, end;
655 f = fopen (filename, "r");
659 gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
660 filename, g_strerror (errno));
661 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
666 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
670 const char *leftover;
671 int to_read = 2047 - remaining;
673 count = fread (buf + remaining, 1, to_read, f);
674 buf[count + remaining] = '\0';
676 g_utf8_validate (buf, count + remaining, &leftover);
678 g_assert (g_utf8_validate (buf, leftover - buf, NULL));
679 gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
681 remaining = (buf + remaining + count) - leftover;
682 g_memmove (buf, leftover, remaining);
684 if (remaining > 6 || count < to_read)
690 gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
691 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
695 /* We had a newline in the buffer to begin with. (The buffer always contains
696 * a newline, so we delete to the end of the buffer to clean up.
698 gtk_text_buffer_get_end_iter (buffer, &end);
699 gtk_text_buffer_delete (buffer, &iter, &end);
701 gtk_text_buffer_set_modified (buffer, FALSE);
707 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
709 View *view = view_from_widget (window);
711 push_active_window (GTK_WINDOW (window));
712 check_close_view (view);
713 pop_active_window ();
723 get_empty_view (View *view)
725 if (!view->buffer->filename &&
726 !gtk_text_buffer_get_modified (view->buffer->buffer))
729 return create_view (create_buffer ());
733 view_from_widget (GtkWidget *widget)
735 if (GTK_IS_MENU_ITEM (widget))
737 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
738 return g_object_get_data (G_OBJECT (item_factory), "view");
742 GtkWidget *app = gtk_widget_get_toplevel (widget);
743 return g_object_get_data (G_OBJECT (app), "view");
748 do_new (gpointer callback_data,
749 guint callback_action,
752 create_view (create_buffer ());
756 do_new_view (gpointer callback_data,
757 guint callback_action,
760 View *view = view_from_widget (widget);
762 create_view (view->buffer);
766 open_ok_func (const char *filename, gpointer data)
769 View *new_view = get_empty_view (view);
771 if (!fill_file_buffer (new_view->buffer->buffer, filename))
773 if (new_view != view)
774 close_view (new_view);
779 g_free (new_view->buffer->filename);
780 new_view->buffer->filename = g_strdup (filename);
781 buffer_filename_set (new_view->buffer);
788 do_open (gpointer callback_data,
789 guint callback_action,
792 View *view = view_from_widget (widget);
794 push_active_window (GTK_WINDOW (view->window));
795 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
796 pop_active_window ();
800 do_save_as (gpointer callback_data,
801 guint callback_action,
804 View *view = view_from_widget (widget);
806 push_active_window (GTK_WINDOW (view->window));
807 save_as_buffer (view->buffer);
808 pop_active_window ();
812 do_save (gpointer callback_data,
813 guint callback_action,
816 View *view = view_from_widget (widget);
818 push_active_window (GTK_WINDOW (view->window));
819 if (!view->buffer->filename)
820 do_save_as (callback_data, callback_action, widget);
822 save_buffer (view->buffer);
823 pop_active_window ();
827 do_close (gpointer callback_data,
828 guint callback_action,
831 View *view = view_from_widget (widget);
833 push_active_window (GTK_WINDOW (view->window));
834 check_close_view (view);
835 pop_active_window ();
839 do_exit (gpointer callback_data,
840 guint callback_action,
843 View *view = view_from_widget (widget);
845 GSList *tmp_list = buffers;
847 push_active_window (GTK_WINDOW (view->window));
850 if (!check_buffer_saved (tmp_list->data))
853 tmp_list = tmp_list->next;
857 pop_active_window ();
861 do_example (gpointer callback_data,
862 guint callback_action,
865 View *view = view_from_widget (widget);
868 new_view = get_empty_view (view);
870 fill_example_buffer (new_view->buffer->buffer);
872 view_add_example_widgets (new_view);
877 do_insert_and_scroll (gpointer callback_data,
878 guint callback_action,
881 View *view = view_from_widget (widget);
882 GtkTextBuffer *buffer;
883 GtkTextIter start, end;
886 buffer = view->buffer->buffer;
888 gtk_text_buffer_get_bounds (buffer, &start, &end);
889 mark = gtk_text_buffer_create_mark (buffer, NULL, &end, /* right grav */ FALSE);
891 gtk_text_buffer_insert (buffer, &end,
892 "Hello this is multiple lines of text\n"
893 "Line 1\n" "Line 2\n"
894 "Line 3\n" "Line 4\n"
898 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view->text_view), mark,
900 gtk_text_buffer_delete_mark (buffer, mark);
904 do_wrap_changed (gpointer callback_data,
905 guint callback_action,
908 View *view = view_from_widget (widget);
910 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
914 do_direction_changed (gpointer callback_data,
915 guint callback_action,
918 View *view = view_from_widget (widget);
920 gtk_widget_set_direction (view->text_view, callback_action);
921 gtk_widget_queue_resize (view->text_view);
926 do_spacing_changed (gpointer callback_data,
927 guint callback_action,
930 View *view = view_from_widget (widget);
934 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
936 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
938 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
943 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
945 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
947 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
953 do_editable_changed (gpointer callback_data,
954 guint callback_action,
957 View *view = view_from_widget (widget);
959 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
963 do_cursor_visible_changed (gpointer callback_data,
964 guint callback_action,
967 View *view = view_from_widget (widget);
969 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
973 do_color_cycle_changed (gpointer callback_data,
974 guint callback_action,
977 View *view = view_from_widget (widget);
979 buffer_set_colors (view->buffer, callback_action);
983 do_apply_editable (gpointer callback_data,
984 guint callback_action,
987 View *view = view_from_widget (widget);
991 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
996 gtk_text_buffer_remove_tag (view->buffer->buffer,
997 view->buffer->not_editable_tag,
1002 gtk_text_buffer_apply_tag (view->buffer->buffer,
1003 view->buffer->not_editable_tag,
1010 do_apply_invisible (gpointer callback_data,
1011 guint callback_action,
1014 View *view = view_from_widget (widget);
1018 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1021 if (callback_action)
1023 gtk_text_buffer_remove_tag (view->buffer->buffer,
1024 view->buffer->invisible_tag,
1029 gtk_text_buffer_apply_tag (view->buffer->buffer,
1030 view->buffer->invisible_tag,
1037 do_apply_tabs (gpointer callback_data,
1038 guint callback_action,
1041 View *view = view_from_widget (widget);
1045 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1048 if (callback_action)
1050 gtk_text_buffer_remove_tag (view->buffer->buffer,
1051 view->buffer->custom_tabs_tag,
1056 gtk_text_buffer_apply_tag (view->buffer->buffer,
1057 view->buffer->custom_tabs_tag,
1064 do_apply_colors (gpointer callback_data,
1065 guint callback_action,
1068 View *view = view_from_widget (widget);
1069 Buffer *buffer = view->buffer;
1073 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1076 if (!callback_action)
1080 tmp = buffer->color_tags;
1083 gtk_text_buffer_remove_tag (view->buffer->buffer,
1086 tmp = g_slist_next (tmp);
1093 tmp = buffer->color_tags;
1097 gboolean done = FALSE;
1100 gtk_text_iter_forward_char (&next);
1101 gtk_text_iter_forward_char (&next);
1103 if (gtk_text_iter_compare (&next, &end) >= 0)
1109 gtk_text_buffer_apply_tag (view->buffer->buffer,
1118 tmp = g_slist_next (tmp);
1120 tmp = buffer->color_tags;
1127 do_remove_tags (gpointer callback_data,
1128 guint callback_action,
1131 View *view = view_from_widget (widget);
1135 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1138 gtk_text_buffer_remove_all_tags (view->buffer->buffer,
1144 do_properties (gpointer callback_data,
1145 guint callback_action,
1148 View *view = view_from_widget (widget);
1150 create_prop_editor (G_OBJECT (view->text_view), 0);
1160 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1162 GtkTextBuffer *buffer;
1164 GtkTextIter start, end;
1165 gchar *search_string;
1167 if (response_id != RESPONSE_FORWARD &&
1168 response_id != RESPONSE_BACKWARD)
1170 gtk_widget_destroy (dialog);
1174 buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
1176 gtk_text_buffer_get_bounds (buffer, &start, &end);
1178 search_string = gtk_text_iter_get_text (&start, &end);
1180 g_print ("Searching for `%s'\n", search_string);
1182 if (response_id == RESPONSE_FORWARD)
1183 buffer_search_forward (view->buffer, search_string, view);
1184 else if (response_id == RESPONSE_BACKWARD)
1185 buffer_search_backward (view->buffer, search_string, view);
1187 g_free (search_string);
1189 gtk_widget_destroy (dialog);
1193 do_search (gpointer callback_data,
1194 guint callback_action,
1197 View *view = view_from_widget (widget);
1199 GtkWidget *search_text;
1200 GtkTextBuffer *buffer;
1202 dialog = gtk_dialog_new_with_buttons ("Search",
1203 GTK_WINDOW (view->window),
1204 GTK_DIALOG_DESTROY_WITH_PARENT,
1205 "Forward", RESPONSE_FORWARD,
1206 "Backward", RESPONSE_BACKWARD,
1208 GTK_RESPONSE_NONE, NULL);
1211 buffer = gtk_text_buffer_new (NULL);
1213 search_text = gtk_text_view_new_with_buffer (buffer);
1215 g_object_unref (buffer);
1217 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1221 g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
1223 g_signal_connect (dialog,
1225 G_CALLBACK (dialog_response_callback),
1228 gtk_widget_show (search_text);
1230 gtk_widget_grab_focus (search_text);
1232 gtk_widget_show_all (dialog);
1237 /* position is in coordinate system of text_view_move_child */
1246 movable_child_callback (GtkWidget *child,
1250 ChildMoveInfo *info;
1251 GtkTextView *text_view;
1253 text_view = GTK_TEXT_VIEW (data);
1255 g_return_val_if_fail (GTK_IS_EVENT_BOX (child), FALSE);
1256 g_return_val_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (text_view), FALSE);
1258 info = g_object_get_data (G_OBJECT (child),
1259 "testtext-move-info");
1263 info = g_new (ChildMoveInfo, 1);
1267 g_object_set_data_full (G_OBJECT (child),
1268 "testtext-move-info",
1273 switch (event->type)
1275 case GDK_BUTTON_PRESS:
1276 if (info->button < 0)
1278 if (gdk_pointer_grab (event->button.window,
1280 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1281 GDK_BUTTON_RELEASE_MASK,
1284 event->button.time) != GDK_GRAB_SUCCESS)
1287 info->button = event->button.button;
1289 info->start_x = child->allocation.x;
1290 info->start_y = child->allocation.y;
1291 info->click_x = child->allocation.x + event->button.x;
1292 info->click_y = child->allocation.y + event->button.y;
1296 case GDK_BUTTON_RELEASE:
1297 if (info->button < 0)
1300 if (info->button == event->button.button)
1304 gdk_pointer_ungrab (event->button.time);
1307 /* convert to window coords from event box coords */
1308 x = info->start_x + (event->button.x + child->allocation.x - info->click_x);
1309 y = info->start_y + (event->button.y + child->allocation.y - info->click_y);
1311 gtk_text_view_move_child (text_view,
1317 case GDK_MOTION_NOTIFY:
1321 if (info->button < 0)
1324 gdk_window_get_pointer (child->window, &x, &y, NULL); /* ensure more events */
1326 /* to window coords from event box coords */
1327 x += child->allocation.x;
1328 y += child->allocation.y;
1330 x = info->start_x + (x - info->click_x);
1331 y = info->start_y + (y - info->click_y);
1333 gtk_text_view_move_child (text_view,
1347 add_movable_child (GtkTextView *text_view,
1348 GtkTextWindowType window)
1350 GtkWidget *event_box;
1354 label = gtk_label_new ("Drag me around");
1356 event_box = gtk_event_box_new ();
1357 gtk_widget_add_events (event_box,
1358 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1359 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
1362 color.green = color.blue = 0;
1363 gtk_widget_modify_bg (event_box, GTK_STATE_NORMAL, &color);
1365 gtk_container_add (GTK_CONTAINER (event_box), label);
1367 gtk_widget_show_all (event_box);
1369 g_signal_connect (event_box, "event",
1370 G_CALLBACK (movable_child_callback),
1373 gtk_text_view_add_child_in_window (text_view,
1380 do_add_children (gpointer callback_data,
1381 guint callback_action,
1384 View *view = view_from_widget (widget);
1386 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1387 GTK_TEXT_WINDOW_WIDGET);
1388 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1389 GTK_TEXT_WINDOW_LEFT);
1390 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1391 GTK_TEXT_WINDOW_RIGHT);
1395 do_add_focus_children (gpointer callback_data,
1396 guint callback_action,
1399 View *view = view_from_widget (widget);
1401 GtkTextChildAnchor *anchor;
1403 GtkTextView *text_view;
1405 text_view = GTK_TEXT_VIEW (view->text_view);
1407 child = gtk_button_new_with_mnemonic ("Button _A in widget->window");
1409 gtk_text_view_add_child_in_window (text_view,
1411 GTK_TEXT_WINDOW_WIDGET,
1414 child = gtk_button_new_with_mnemonic ("Button _B in widget->window");
1416 gtk_text_view_add_child_in_window (text_view,
1418 GTK_TEXT_WINDOW_WIDGET,
1421 child = gtk_button_new_with_mnemonic ("Button _C in left window");
1423 gtk_text_view_add_child_in_window (text_view,
1425 GTK_TEXT_WINDOW_LEFT,
1428 child = gtk_button_new_with_mnemonic ("Button _D in right window");
1430 gtk_text_view_add_child_in_window (text_view,
1432 GTK_TEXT_WINDOW_RIGHT,
1435 gtk_text_buffer_get_start_iter (view->buffer->buffer, &iter);
1437 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1439 child = gtk_button_new_with_mnemonic ("Button _E in buffer");
1441 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1443 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1445 child = gtk_button_new_with_mnemonic ("Button _F in buffer");
1447 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1449 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1451 child = gtk_button_new_with_mnemonic ("Button _G in buffer");
1453 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1455 /* show all the buttons */
1456 gtk_widget_show_all (view->text_view);
1460 view_init_menus (View *view)
1462 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1463 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1464 GtkWidget *menu_item = NULL;
1468 case GTK_TEXT_DIR_LTR:
1469 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1471 case GTK_TEXT_DIR_RTL:
1472 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1479 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1484 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1487 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1490 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
1497 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1500 static GtkItemFactoryEntry menu_items[] =
1502 { "/_File", NULL, NULL, 0, "<Branch>" },
1503 { "/File/_New", "<control>N", do_new, 0, NULL },
1504 { "/File/New _View", NULL, do_new_view, 0, NULL },
1505 { "/File/_Open", "<control>O", do_open, 0, NULL },
1506 { "/File/_Save", "<control>S", do_save, 0, NULL },
1507 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1508 { "/File/sep1", NULL, NULL, 0, "<Separator>" },
1509 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1510 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1512 { "/_Edit", NULL, 0, 0, "<Branch>" },
1513 { "/Edit/Find...", NULL, do_search, 0, NULL },
1515 { "/_Settings", NULL, NULL, 0, "<Branch>" },
1516 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAP_NONE, "<RadioItem>" },
1517 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAP_WORD, "/Settings/Wrap Off" },
1518 { "/Settings/Wrap _Chars", NULL, do_wrap_changed, GTK_WRAP_CHAR, "/Settings/Wrap Off" },
1519 { "/Settings/sep1", NULL, NULL, 0, "<Separator>" },
1520 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1521 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1522 { "/Settings/sep1", NULL, NULL, 0, "<Separator>" },
1524 { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "<RadioItem>" },
1525 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" },
1526 { "/Settings/sep1", NULL, NULL, 0, "<Separator>" },
1528 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1529 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1531 { "/Settings/sep1", NULL, NULL, 0, "<Separator>" },
1532 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1533 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1534 { "/Settings/sep1", NULL, NULL, 0, "<Separator>" },
1535 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1536 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1537 { "/_Attributes", NULL, NULL, 0, "<Branch>" },
1538 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1539 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1540 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1541 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1542 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1543 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1544 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1545 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
1546 { "/Attributes/Remove all tags", NULL, do_remove_tags, 0, NULL },
1547 { "/Attributes/Properties", NULL, do_properties, 0, NULL },
1548 { "/_Test", NULL, NULL, 0, "<Branch>" },
1549 { "/Test/_Example", NULL, do_example, 0, NULL },
1550 { "/Test/_Insert and scroll", NULL, do_insert_and_scroll, 0, NULL },
1551 { "/Test/_Add fixed children", NULL, do_add_children, 0, NULL },
1552 { "/Test/A_dd focusable children", NULL, do_add_focus_children, 0, NULL },
1556 save_buffer (Buffer *buffer)
1558 GtkTextIter start, end;
1560 gboolean result = FALSE;
1561 gboolean have_backup = FALSE;
1562 gchar *bak_filename;
1565 g_return_val_if_fail (buffer->filename != NULL, FALSE);
1567 bak_filename = g_strconcat (buffer->filename, "~", NULL);
1569 if (rename (buffer->filename, bak_filename) != 0)
1571 if (errno != ENOENT)
1573 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1574 buffer->filename, bak_filename, g_strerror (errno));
1575 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1583 file = fopen (buffer->filename, "w");
1586 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1587 buffer->filename, bak_filename, g_strerror (errno));
1588 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1592 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1593 gtk_text_buffer_get_end_iter (buffer->buffer, &end);
1595 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1597 if (fputs (chars, file) == EOF ||
1598 fclose (file) == EOF)
1600 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1601 buffer->filename, g_strerror (errno));
1602 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1610 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
1616 if (!result && have_backup)
1618 if (rename (bak_filename, buffer->filename) != 0)
1620 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1621 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1622 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1627 g_free (bak_filename);
1633 save_as_ok_func (const char *filename, gpointer data)
1635 Buffer *buffer = data;
1636 char *old_filename = buffer->filename;
1638 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1640 struct stat statbuf;
1642 if (stat (filename, &statbuf) == 0)
1644 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1645 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1653 buffer->filename = g_strdup (filename);
1655 if (save_buffer (buffer))
1657 g_free (old_filename);
1658 buffer_filename_set (buffer);
1663 g_free (buffer->filename);
1664 buffer->filename = old_filename;
1670 save_as_buffer (Buffer *buffer)
1672 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1676 check_buffer_saved (Buffer *buffer)
1678 if (gtk_text_buffer_get_modified (buffer->buffer))
1680 char *pretty_name = buffer_pretty_name (buffer);
1681 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1684 g_free (pretty_name);
1686 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1690 return save_as_buffer (buffer);
1691 else if (result == 1)
1703 create_buffer (void)
1706 PangoTabArray *tabs;
1709 buffer = g_new (Buffer, 1);
1711 buffer->buffer = gtk_text_buffer_new (NULL);
1713 buffer->refcount = 1;
1714 buffer->filename = NULL;
1715 buffer->untitled_serial = -1;
1717 buffer->color_tags = NULL;
1718 buffer->color_cycle_timeout = 0;
1719 buffer->start_hue = 0.0;
1722 while (i < N_COLORS)
1726 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL, NULL);
1728 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1734 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1735 "invisible", TRUE, NULL);
1738 buffer->not_editable_tag =
1739 gtk_text_buffer_create_tag (buffer->buffer, NULL,
1741 "foreground", "purple", NULL);
1743 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1744 "foreground", "red", NULL);
1746 tabs = pango_tab_array_new_with_positions (4,
1751 PANGO_TAB_LEFT, 120);
1753 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1755 "foreground", "green", NULL);
1757 pango_tab_array_free (tabs);
1759 buffers = g_slist_prepend (buffers, buffer);
1765 buffer_pretty_name (Buffer *buffer)
1767 if (buffer->filename)
1770 char *result = g_path_get_basename (buffer->filename);
1771 p = strchr (result, '/');
1779 if (buffer->untitled_serial == -1)
1780 buffer->untitled_serial = untitled_serial++;
1782 if (buffer->untitled_serial == 1)
1783 return g_strdup ("Untitled");
1785 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1790 buffer_filename_set (Buffer *buffer)
1792 GSList *tmp_list = views;
1796 View *view = tmp_list->data;
1798 if (view->buffer == buffer)
1799 view_set_title (view);
1801 tmp_list = tmp_list->next;
1806 buffer_search (Buffer *buffer,
1812 GtkTextIter start, end;
1816 /* remove tag from whole buffer */
1817 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1818 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1821 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1822 gtk_text_buffer_get_mark (buffer->buffer,
1828 GtkTextIter match_start, match_end;
1832 while (gtk_text_iter_forward_search (&iter, str,
1833 GTK_TEXT_SEARCH_VISIBLE_ONLY |
1834 GTK_TEXT_SEARCH_TEXT_ONLY,
1835 &match_start, &match_end,
1839 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1840 &match_start, &match_end);
1847 while (gtk_text_iter_backward_search (&iter, str,
1848 GTK_TEXT_SEARCH_VISIBLE_ONLY |
1849 GTK_TEXT_SEARCH_TEXT_ONLY,
1850 &match_start, &match_end,
1854 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1855 &match_start, &match_end);
1862 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1863 GTK_DIALOG_DESTROY_WITH_PARENT,
1866 "%d strings found and marked in red",
1869 g_signal_connect_swapped (dialog,
1871 G_CALLBACK (gtk_widget_destroy), dialog);
1873 gtk_widget_show (dialog);
1877 buffer_search_forward (Buffer *buffer, const char *str,
1880 buffer_search (buffer, str, view, TRUE);
1884 buffer_search_backward (Buffer *buffer, const char *str,
1887 buffer_search (buffer, str, view, FALSE);
1891 buffer_ref (Buffer *buffer)
1897 buffer_unref (Buffer *buffer)
1900 if (buffer->refcount == 0)
1902 buffer_set_colors (buffer, FALSE);
1903 buffers = g_slist_remove (buffers, buffer);
1904 g_object_unref (buffer->buffer);
1905 g_free (buffer->filename);
1911 hsv_to_rgb (gdouble *h,
1915 gdouble hue, saturation, value;
1933 f = hue - (int) hue;
1934 p = value * (1.0 - saturation);
1935 q = value * (1.0 - saturation * f);
1936 t = value * (1.0 - saturation * (1.0 - f));
1977 g_assert_not_reached ();
1983 hue_to_color (gdouble hue,
1992 g_return_if_fail (hue <= 1.0);
1994 hsv_to_rgb (&h, &s, &v);
1996 color->red = h * 65535;
1997 color->green = s * 65535;
1998 color->blue = v * 65535;
2003 color_cycle_timeout (gpointer data)
2005 Buffer *buffer = data;
2007 buffer_cycle_colors (buffer);
2013 buffer_set_colors (Buffer *buffer,
2019 if (enabled && buffer->color_cycle_timeout == 0)
2020 buffer->color_cycle_timeout = g_timeout_add (200, color_cycle_timeout, buffer);
2021 else if (!enabled && buffer->color_cycle_timeout != 0)
2023 g_source_remove (buffer->color_cycle_timeout);
2024 buffer->color_cycle_timeout = 0;
2027 tmp = buffer->color_tags;
2034 hue_to_color (hue, &color);
2036 g_object_set (tmp->data,
2037 "foreground_gdk", &color,
2041 g_object_set (tmp->data,
2042 "foreground_set", FALSE,
2045 hue += 1.0 / N_COLORS;
2047 tmp = g_slist_next (tmp);
2052 buffer_cycle_colors (Buffer *buffer)
2055 gdouble hue = buffer->start_hue;
2057 tmp = buffer->color_tags;
2062 hue_to_color (hue, &color);
2064 g_object_set (tmp->data,
2065 "foreground_gdk", &color,
2068 hue += 1.0 / N_COLORS;
2072 tmp = g_slist_next (tmp);
2075 buffer->start_hue += 1.0 / N_COLORS;
2076 if (buffer->start_hue > 1.0)
2077 buffer->start_hue = 0.0;
2081 close_view (View *view)
2083 views = g_slist_remove (views, view);
2084 buffer_unref (view->buffer);
2085 gtk_widget_destroy (view->window);
2086 g_object_unref (view->item_factory);
2095 check_close_view (View *view)
2097 if (view->buffer->refcount > 1 ||
2098 check_buffer_saved (view->buffer))
2103 view_set_title (View *view)
2105 char *pretty_name = buffer_pretty_name (view->buffer);
2106 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
2108 gtk_window_set_title (GTK_WINDOW (view->window), title);
2110 g_free (pretty_name);
2115 cursor_set_callback (GtkTextBuffer *buffer,
2116 const GtkTextIter *location,
2120 GtkTextView *text_view;
2122 /* Redraw tab windows if the cursor moves
2123 * on the mapped widget (windows may not exist before realization...
2126 text_view = GTK_TEXT_VIEW (user_data);
2128 if (GTK_WIDGET_MAPPED (text_view) &&
2129 mark == gtk_text_buffer_get_insert (buffer))
2131 GdkWindow *tab_window;
2133 tab_window = gtk_text_view_get_window (text_view,
2134 GTK_TEXT_WINDOW_TOP);
2136 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
2138 tab_window = gtk_text_view_get_window (text_view,
2139 GTK_TEXT_WINDOW_BOTTOM);
2141 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
2146 tab_stops_expose (GtkWidget *widget,
2147 GdkEventExpose *event,
2154 GdkWindow *bottom_win;
2155 GtkTextView *text_view;
2156 GtkTextWindowType type;
2157 GdkDrawable *target;
2158 gint *positions = NULL;
2160 GtkTextAttributes *attrs;
2162 GtkTextBuffer *buffer;
2165 text_view = GTK_TEXT_VIEW (widget);
2167 /* See if this expose is on the tab stop window */
2168 top_win = gtk_text_view_get_window (text_view,
2169 GTK_TEXT_WINDOW_TOP);
2171 bottom_win = gtk_text_view_get_window (text_view,
2172 GTK_TEXT_WINDOW_BOTTOM);
2174 if (event->window == top_win)
2176 type = GTK_TEXT_WINDOW_TOP;
2179 else if (event->window == bottom_win)
2181 type = GTK_TEXT_WINDOW_BOTTOM;
2182 target = bottom_win;
2187 first_x = event->area.x;
2188 last_x = first_x + event->area.width;
2190 gtk_text_view_window_to_buffer_coords (text_view,
2197 gtk_text_view_window_to_buffer_coords (text_view,
2204 buffer = gtk_text_view_get_buffer (text_view);
2206 gtk_text_buffer_get_iter_at_mark (buffer,
2208 gtk_text_buffer_get_mark (buffer,
2211 attrs = gtk_text_attributes_new ();
2213 gtk_text_iter_get_attributes (&insert, attrs);
2217 size = pango_tab_array_get_size (attrs->tabs);
2219 pango_tab_array_get_tabs (attrs->tabs,
2223 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
2231 gtk_text_attributes_unref (attrs);
2239 positions[i] = PANGO_PIXELS (positions[i]);
2241 gtk_text_view_buffer_to_window_coords (text_view,
2248 gdk_draw_line (target,
2249 widget->style->fg_gc [widget->state],
2262 get_lines (GtkTextView *text_view,
2265 GArray *buffer_coords,
2273 g_array_set_size (buffer_coords, 0);
2274 g_array_set_size (numbers, 0);
2276 /* Get iter at first y */
2277 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
2279 /* For each iter, get its location and add it to the arrays.
2280 * Stop when we pass last_y
2285 while (!gtk_text_iter_is_end (&iter))
2290 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2292 g_array_append_val (buffer_coords, y);
2293 line_num = gtk_text_iter_get_line (&iter);
2294 g_array_append_val (numbers, line_num);
2298 if ((y + height) >= last_y)
2301 gtk_text_iter_forward_line (&iter);
2308 line_numbers_expose (GtkWidget *widget,
2309 GdkEventExpose *event,
2318 GdkWindow *left_win;
2319 GdkWindow *right_win;
2320 PangoLayout *layout;
2321 GtkTextView *text_view;
2322 GtkTextWindowType type;
2323 GdkDrawable *target;
2325 text_view = GTK_TEXT_VIEW (widget);
2327 /* See if this expose is on the line numbers window */
2328 left_win = gtk_text_view_get_window (text_view,
2329 GTK_TEXT_WINDOW_LEFT);
2331 right_win = gtk_text_view_get_window (text_view,
2332 GTK_TEXT_WINDOW_RIGHT);
2334 if (event->window == left_win)
2336 type = GTK_TEXT_WINDOW_LEFT;
2339 else if (event->window == right_win)
2341 type = GTK_TEXT_WINDOW_RIGHT;
2347 first_y = event->area.y;
2348 last_y = first_y + event->area.height;
2350 gtk_text_view_window_to_buffer_coords (text_view,
2357 gtk_text_view_window_to_buffer_coords (text_view,
2364 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2365 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2367 get_lines (text_view,
2374 /* Draw fully internationalized numbers! */
2376 layout = gtk_widget_create_pango_layout (widget, "");
2384 gtk_text_view_buffer_to_window_coords (text_view,
2387 g_array_index (pixels, gint, i),
2391 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2393 pango_layout_set_text (layout, str, -1);
2395 gtk_paint_layout (widget->style,
2397 GTK_WIDGET_STATE (widget),
2410 g_array_free (pixels, TRUE);
2411 g_array_free (numbers, TRUE);
2413 g_object_unref (layout);
2415 /* don't stop emission, need to draw children */
2420 create_view (Buffer *buffer)
2427 view = g_new0 (View, 1);
2428 views = g_slist_prepend (views, view);
2430 view->buffer = buffer;
2431 buffer_ref (buffer);
2433 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2434 g_object_set_data (G_OBJECT (view->window), "view", view);
2436 g_signal_connect (view->window, "delete_event",
2437 G_CALLBACK (delete_event_cb), NULL);
2439 view->accel_group = gtk_accel_group_new ();
2440 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2441 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2443 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2445 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2447 vbox = gtk_vbox_new (FALSE, 0);
2448 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2450 gtk_box_pack_start (GTK_BOX (vbox),
2451 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2454 sw = gtk_scrolled_window_new (NULL, NULL);
2455 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2456 GTK_POLICY_AUTOMATIC,
2457 GTK_POLICY_AUTOMATIC);
2459 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2460 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2463 /* Make sure border width works, no real reason to do this other than testing */
2464 gtk_container_set_border_width (GTK_CONTAINER (view->text_view),
2467 /* Draw tab stops in the top and bottom windows. */
2469 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2470 GTK_TEXT_WINDOW_TOP,
2473 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2474 GTK_TEXT_WINDOW_BOTTOM,
2477 g_signal_connect (view->text_view,
2479 G_CALLBACK (tab_stops_expose),
2482 g_signal_connect (view->buffer->buffer,
2484 G_CALLBACK (cursor_set_callback),
2487 /* Draw line numbers in the side windows; we should really be
2488 * more scientific about what width we set them to.
2490 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2491 GTK_TEXT_WINDOW_RIGHT,
2494 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2495 GTK_TEXT_WINDOW_LEFT,
2498 g_signal_connect (view->text_view,
2500 G_CALLBACK (line_numbers_expose),
2503 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2504 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2506 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2508 gtk_widget_grab_focus (view->text_view);
2510 view_set_title (view);
2511 view_init_menus (view);
2513 view_add_example_widgets (view);
2515 gtk_widget_show_all (view->window);
2520 view_add_example_widgets (View *view)
2522 GtkTextChildAnchor *anchor;
2525 buffer = view->buffer;
2527 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2530 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2534 widget = gtk_button_new_with_label ("Foo");
2536 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2540 gtk_widget_show (widget);
2547 if (g_file_test ("../gdk-pixbuf/libpixbufloader-pnm.la",
2548 G_FILE_TEST_EXISTS))
2550 g_setenv ("GDK_PIXBUF_MODULE_FILE", "../gdk-pixbuf/gdk-pixbuf.loaders", TRUE);
2551 g_setenv ("GTK_IM_MODULE_FILE", "../modules/input/gtk.immodules", TRUE);
2556 main (int argc, char** argv)
2563 gtk_init (&argc, &argv);
2565 buffer = create_buffer ();
2566 view = create_view (buffer);
2567 buffer_unref (buffer);
2569 push_active_window (GTK_WINDOW (view->window));
2570 for (i=1; i < argc; i++)
2574 /* Quick and dirty canonicalization - better should be in GLib
2577 if (!g_path_is_absolute (argv[i]))
2579 char *cwd = g_get_current_dir ();
2580 filename = g_strconcat (cwd, "/", argv[i], NULL);
2586 open_ok_func (filename, view);
2588 if (filename != argv[i])
2591 pop_active_window ();