2 * Copyright (C) 2000 Red Hat, Inc
3 * Author: Havoc Pennington
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
29 #include <gdk/gdkkeysyms.h>
31 #include "prop-editor.h"
33 typedef struct _Buffer Buffer;
34 typedef struct _View View;
36 static gint untitled_serial = 1;
38 GSList *active_window_stack = NULL;
43 GtkTextBuffer *buffer;
46 GtkTextTag *invisible_tag;
47 GtkTextTag *not_editable_tag;
48 GtkTextTag *found_text_tag;
50 GtkTextTag *large_tag;
51 GtkTextTag *indent_tag;
52 GtkTextTag *margin_tag;
53 GtkTextTag *custom_tabs_tag;
55 guint color_cycle_timeout;
63 GtkAccelGroup *accel_group;
64 GtkItemFactory *item_factory;
68 static void push_active_window (GtkWindow *window);
69 static void pop_active_window (void);
70 static GtkWindow *get_active_window (void);
72 static Buffer * create_buffer (void);
73 static gboolean check_buffer_saved (Buffer *buffer);
74 static gboolean save_buffer (Buffer *buffer);
75 static gboolean save_as_buffer (Buffer *buffer);
76 static char * buffer_pretty_name (Buffer *buffer);
77 static void buffer_filename_set (Buffer *buffer);
78 static void buffer_search_forward (Buffer *buffer,
81 static void buffer_search_backward (Buffer *buffer,
84 static void buffer_set_colors (Buffer *buffer,
86 static void buffer_cycle_colors (Buffer *buffer);
88 static View *view_from_widget (GtkWidget *widget);
90 static View *create_view (Buffer *buffer);
91 static void check_close_view (View *view);
92 static void close_view (View *view);
93 static void view_set_title (View *view);
94 static void view_init_menus (View *view);
95 static void view_add_example_widgets (View *view);
97 GSList *buffers = NULL;
101 push_active_window (GtkWindow *window)
103 g_object_ref (window);
104 active_window_stack = g_slist_prepend (active_window_stack, window);
108 pop_active_window (void)
110 g_object_unref (active_window_stack->data);
111 active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack);
115 get_active_window (void)
117 if (active_window_stack)
118 return active_window_stack->data;
124 * Filesel utility function
127 typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data);
130 filesel_ok_cb (GtkWidget *button, GtkWidget *filesel)
132 FileselOKFunc ok_func = (FileselOKFunc)g_object_get_data (G_OBJECT (filesel), "ok-func");
133 gpointer data = g_object_get_data (G_OBJECT (filesel), "ok-data");
134 gint *result = g_object_get_data (G_OBJECT (filesel), "ok-result");
136 gtk_widget_hide (filesel);
138 if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data))
140 gtk_widget_destroy (filesel);
144 gtk_widget_show (filesel);
148 filesel_run (GtkWindow *parent,
150 const char *start_file,
154 GtkWidget *filesel = gtk_file_selection_new (title);
155 gboolean result = FALSE;
158 parent = get_active_window ();
161 gtk_window_set_transient_for (GTK_WINDOW (filesel), parent);
164 gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file);
167 g_object_set_data (G_OBJECT (filesel), "ok-func", func);
168 g_object_set_data (G_OBJECT (filesel), "ok-data", data);
169 g_object_set_data (G_OBJECT (filesel), "ok-result", &result);
171 g_signal_connect (GTK_FILE_SELECTION (filesel)->ok_button,
173 G_CALLBACK (filesel_ok_cb), filesel);
174 g_signal_connect_swapped (GTK_FILE_SELECTION (filesel)->cancel_button,
176 G_CALLBACK (gtk_widget_destroy), filesel);
178 g_signal_connect (filesel, "destroy",
179 G_CALLBACK (gtk_main_quit), NULL);
180 gtk_window_set_modal (GTK_WINDOW (filesel), TRUE);
182 gtk_widget_show (filesel);
189 * MsgBox utility functions
193 msgbox_yes_cb (GtkWidget *widget, gboolean *result)
196 gtk_widget_destroy (gtk_widget_get_toplevel (widget));
200 msgbox_no_cb (GtkWidget *widget, gboolean *result)
203 gtk_widget_destroy (gtk_widget_get_toplevel (widget));
207 msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
209 if (event->keyval == GDK_Escape)
211 g_signal_stop_emission_by_name (widget, "key_press_event");
212 gtk_widget_destroy (widget);
219 /* Don't copy this example, it's all crack-smoking - you can just use
220 * GtkMessageDialog now
223 msgbox_run (GtkWindow *parent,
225 const char *yes_button,
226 const char *no_button,
227 const char *cancel_button,
230 gboolean result = -1;
235 GtkWidget *button_box;
236 GtkWidget *separator;
238 g_return_val_if_fail (message != NULL, FALSE);
239 g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE);
242 parent = get_active_window ();
246 dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
247 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
249 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
250 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
252 /* Quit our recursive main loop when the dialog is destroyed.
254 g_signal_connect (dialog, "destroy",
255 G_CALLBACK (gtk_main_quit), NULL);
257 /* Catch Escape key presses and have them destroy the dialog
259 g_signal_connect (dialog, "key_press_event",
260 G_CALLBACK (msgbox_key_press_cb), NULL);
262 /* Fill in the contents of the widget
264 vbox = gtk_vbox_new (FALSE, 0);
265 gtk_container_add (GTK_CONTAINER (dialog), vbox);
267 label = gtk_label_new (message);
268 gtk_misc_set_padding (GTK_MISC (label), 12, 12);
269 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
270 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
272 separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
273 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
275 button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
276 gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
277 gtk_container_set_border_width (GTK_CONTAINER (button_box), 8);
280 /* When Yes is clicked, call the msgbox_yes_cb
281 * This sets the result variable and destroys the dialog
285 button = gtk_button_new_with_label (yes_button);
286 gtk_widget_set_can_default (button, TRUE);
287 gtk_container_add (GTK_CONTAINER (button_box), button);
289 if (default_index == 0)
290 gtk_widget_grab_default (button);
292 g_signal_connect (button, "clicked",
293 G_CALLBACK (msgbox_yes_cb), &result);
296 /* When No is clicked, call the msgbox_no_cb
297 * This sets the result variable and destroys the dialog
301 button = gtk_button_new_with_label (no_button);
302 gtk_widget_set_can_default (button, TRUE);
303 gtk_container_add (GTK_CONTAINER (button_box), button);
305 if (default_index == 0)
306 gtk_widget_grab_default (button);
308 g_signal_connect (button, "clicked",
309 G_CALLBACK (msgbox_no_cb), &result);
312 /* When Cancel is clicked, destroy the dialog
316 button = gtk_button_new_with_label (cancel_button);
317 gtk_widget_set_can_default (button, TRUE);
318 gtk_container_add (GTK_CONTAINER (button_box), button);
320 if (default_index == 1)
321 gtk_widget_grab_default (button);
323 g_signal_connect_swapped (button, "clicked",
324 G_CALLBACK (gtk_object_destroy), dialog);
327 gtk_widget_show_all (dialog);
329 /* Run a recursive main loop until a button is clicked
330 * or the user destroys the dialog through the window mananger */
338 * Example buffer filling code
341 blink_timeout (gpointer data)
344 static gboolean flip = FALSE;
346 tag = GTK_TEXT_TAG (data);
349 "foreground", flip ? "blue" : "purple",
359 tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
360 const GtkTextIter *iter, gpointer user_data)
364 char_index = gtk_text_iter_get_offset (iter);
368 case GDK_MOTION_NOTIFY:
369 printf ("Motion event at char %d tag `%s'\n",
370 char_index, tag->name);
373 case GDK_BUTTON_PRESS:
374 printf ("Button press at char %d tag `%s'\n",
375 char_index, tag->name);
378 case GDK_2BUTTON_PRESS:
379 printf ("Double click at char %d tag `%s'\n",
380 char_index, tag->name);
383 case GDK_3BUTTON_PRESS:
384 printf ("Triple click at char %d tag `%s'\n",
385 char_index, tag->name);
388 case GDK_BUTTON_RELEASE:
389 printf ("Button release at char %d tag `%s'\n",
390 char_index, tag->name);
394 case GDK_KEY_RELEASE:
395 printf ("Key event at char %d tag `%s'\n",
396 char_index, tag->name);
399 case GDK_ENTER_NOTIFY:
400 case GDK_LEAVE_NOTIFY:
401 case GDK_PROPERTY_NOTIFY:
402 case GDK_SELECTION_CLEAR:
403 case GDK_SELECTION_REQUEST:
404 case GDK_SELECTION_NOTIFY:
405 case GDK_PROXIMITY_IN:
406 case GDK_PROXIMITY_OUT:
409 case GDK_DRAG_MOTION:
410 case GDK_DRAG_STATUS:
412 case GDK_DROP_FINISHED:
421 setup_tag (GtkTextTag *tag)
423 g_signal_connect (tag,
425 G_CALLBACK (tag_event_handler),
429 static const char *book_closed_xpm[] = {
455 fill_example_buffer (GtkTextBuffer *buffer)
457 GtkTextIter iter, iter2;
459 GtkTextChildAnchor *anchor;
466 /* FIXME this is broken if called twice on a buffer, since
467 * we try to create tags a second time.
470 tag = gtk_text_buffer_create_tag (buffer, "fg_blue", NULL);
473 g_timeout_add (1000, (GSourceFunc)blink_timeout, tag);
478 color.red = color.green = 0;
484 "foreground_gdk", &color,
485 "background_gdk", &color2,
489 tag = gtk_text_buffer_create_tag (buffer, "fg_red", NULL);
493 color.blue = color.green = 0;
496 "rise", -4 * PANGO_SCALE,
497 "foreground_gdk", &color,
500 tag = gtk_text_buffer_create_tag (buffer, "bg_green", NULL);
504 color.blue = color.red = 0;
505 color.green = 0xffff;
507 "background_gdk", &color,
511 tag = gtk_text_buffer_create_tag (buffer, "strikethrough", NULL);
516 "strikethrough", TRUE,
520 tag = gtk_text_buffer_create_tag (buffer, "underline", NULL);
525 "underline", PANGO_UNDERLINE_SINGLE,
528 tag = gtk_text_buffer_create_tag (buffer, "underline_error", NULL);
533 "underline", PANGO_UNDERLINE_ERROR,
536 tag = gtk_text_buffer_create_tag (buffer, "centered", NULL);
539 "justification", GTK_JUSTIFY_CENTER,
542 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote", NULL);
545 "wrap_mode", GTK_WRAP_WORD,
546 "direction", GTK_TEXT_DIR_RTL,
553 tag = gtk_text_buffer_create_tag (buffer, "negative_indent", NULL);
559 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
561 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
563 g_object_ref (anchor);
565 g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
566 (GDestroyNotify) g_object_unref);
568 pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
573 GtkTextMark * temp_mark;
575 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
577 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
579 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",
582 gtk_text_buffer_insert (buffer, &iter, str, -1);
586 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
588 gtk_text_buffer_insert (buffer, &iter,
589 "(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"
590 /* This is UTF8 stuff, Emacs doesn't
591 really know how to display it */
592 "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);
595 gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
598 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
599 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
601 gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
603 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
604 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
606 gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
608 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 4);
609 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 7);
611 gtk_text_buffer_apply_tag_by_name (buffer, "underline_error", &iter, &iter2);
613 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
614 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
616 gtk_text_buffer_apply_tag_by_name (buffer, "strikethrough", &iter, &iter2);
618 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
619 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
621 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
623 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
624 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
626 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
628 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
629 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
631 gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
634 gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
635 gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
637 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
638 gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
640 gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
641 gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
642 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);
643 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
644 gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
646 gtk_text_buffer_insert_with_tags (buffer, &iter,
647 "Paragraph with negative indentation. blah blah blah blah blah. The quick brown fox jumped over the lazy dog.\n",
649 gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (buffer),
656 g_object_unref (pixbuf);
658 printf ("%d lines %d chars\n",
659 gtk_text_buffer_get_line_count (buffer),
660 gtk_text_buffer_get_char_count (buffer));
662 /* Move cursor to start */
663 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
664 gtk_text_buffer_place_cursor (buffer, &iter);
666 gtk_text_buffer_set_modified (buffer, FALSE);
670 fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
675 GtkTextIter iter, end;
677 f = fopen (filename, "r");
681 gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
682 filename, g_strerror (errno));
683 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
688 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
692 const char *leftover;
693 int to_read = 2047 - remaining;
695 count = fread (buf + remaining, 1, to_read, f);
696 buf[count + remaining] = '\0';
698 g_utf8_validate (buf, count + remaining, &leftover);
700 g_assert (g_utf8_validate (buf, leftover - buf, NULL));
701 gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
703 remaining = (buf + remaining + count) - leftover;
704 g_memmove (buf, leftover, remaining);
706 if (remaining > 6 || count < to_read)
712 gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
713 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
717 /* We had a newline in the buffer to begin with. (The buffer always contains
718 * a newline, so we delete to the end of the buffer to clean up.
720 gtk_text_buffer_get_end_iter (buffer, &end);
721 gtk_text_buffer_delete (buffer, &iter, &end);
723 gtk_text_buffer_set_modified (buffer, FALSE);
729 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
731 View *view = view_from_widget (window);
733 push_active_window (GTK_WINDOW (window));
734 check_close_view (view);
735 pop_active_window ();
745 get_empty_view (View *view)
747 if (!view->buffer->filename &&
748 !gtk_text_buffer_get_modified (view->buffer->buffer))
751 return create_view (create_buffer ());
755 view_from_widget (GtkWidget *widget)
757 if (GTK_IS_MENU_ITEM (widget))
759 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
760 return g_object_get_data (G_OBJECT (item_factory), "view");
764 GtkWidget *app = gtk_widget_get_toplevel (widget);
765 return g_object_get_data (G_OBJECT (app), "view");
770 do_new (gpointer callback_data,
771 guint callback_action,
774 create_view (create_buffer ());
778 do_new_view (gpointer callback_data,
779 guint callback_action,
782 View *view = view_from_widget (widget);
784 create_view (view->buffer);
788 open_ok_func (const char *filename, gpointer data)
791 View *new_view = get_empty_view (view);
793 if (!fill_file_buffer (new_view->buffer->buffer, filename))
795 if (new_view != view)
796 close_view (new_view);
801 g_free (new_view->buffer->filename);
802 new_view->buffer->filename = g_strdup (filename);
803 buffer_filename_set (new_view->buffer);
810 do_open (gpointer callback_data,
811 guint callback_action,
814 View *view = view_from_widget (widget);
816 push_active_window (GTK_WINDOW (view->window));
817 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
818 pop_active_window ();
822 do_save_as (gpointer callback_data,
823 guint callback_action,
826 View *view = view_from_widget (widget);
828 push_active_window (GTK_WINDOW (view->window));
829 save_as_buffer (view->buffer);
830 pop_active_window ();
834 do_save (gpointer callback_data,
835 guint callback_action,
838 View *view = view_from_widget (widget);
840 push_active_window (GTK_WINDOW (view->window));
841 if (!view->buffer->filename)
842 do_save_as (callback_data, callback_action, widget);
844 save_buffer (view->buffer);
845 pop_active_window ();
849 do_close (gpointer callback_data,
850 guint callback_action,
853 View *view = view_from_widget (widget);
855 push_active_window (GTK_WINDOW (view->window));
856 check_close_view (view);
857 pop_active_window ();
861 do_exit (gpointer callback_data,
862 guint callback_action,
865 View *view = view_from_widget (widget);
867 GSList *tmp_list = buffers;
869 push_active_window (GTK_WINDOW (view->window));
872 if (!check_buffer_saved (tmp_list->data))
875 tmp_list = tmp_list->next;
879 pop_active_window ();
883 do_example (gpointer callback_data,
884 guint callback_action,
887 View *view = view_from_widget (widget);
890 new_view = get_empty_view (view);
892 fill_example_buffer (new_view->buffer->buffer);
894 view_add_example_widgets (new_view);
899 do_insert_and_scroll (gpointer callback_data,
900 guint callback_action,
903 View *view = view_from_widget (widget);
904 GtkTextBuffer *buffer;
905 GtkTextIter start, end;
908 buffer = view->buffer->buffer;
910 gtk_text_buffer_get_bounds (buffer, &start, &end);
911 mark = gtk_text_buffer_create_mark (buffer, NULL, &end, /* right grav */ FALSE);
913 gtk_text_buffer_insert (buffer, &end,
914 "Hello this is multiple lines of text\n"
915 "Line 1\n" "Line 2\n"
916 "Line 3\n" "Line 4\n"
920 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view->text_view), mark,
922 gtk_text_buffer_delete_mark (buffer, mark);
926 do_wrap_changed (gpointer callback_data,
927 guint callback_action,
930 View *view = view_from_widget (widget);
932 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
936 do_direction_changed (gpointer callback_data,
937 guint callback_action,
940 View *view = view_from_widget (widget);
942 gtk_widget_set_direction (view->text_view, callback_action);
943 gtk_widget_queue_resize (view->text_view);
948 do_spacing_changed (gpointer callback_data,
949 guint callback_action,
952 View *view = view_from_widget (widget);
956 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
958 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
960 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
965 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
967 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
969 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
975 do_editable_changed (gpointer callback_data,
976 guint callback_action,
979 View *view = view_from_widget (widget);
981 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
985 change_cursor_color (GtkWidget *widget,
990 GdkColor red = {0, 65535, 0, 0};
991 gtk_widget_modify_cursor (widget, &red, &red);
994 gtk_widget_modify_cursor (widget, NULL, NULL);
998 do_cursor_visible_changed (gpointer callback_data,
999 guint callback_action,
1002 View *view = view_from_widget (widget);
1004 switch (callback_action)
1007 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), FALSE);
1010 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), TRUE);
1011 change_cursor_color (view->text_view, FALSE);
1014 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), TRUE);
1015 change_cursor_color (view->text_view, TRUE);
1021 do_color_cycle_changed (gpointer callback_data,
1022 guint callback_action,
1025 View *view = view_from_widget (widget);
1027 buffer_set_colors (view->buffer, callback_action);
1031 do_apply_editable (gpointer callback_data,
1032 guint callback_action,
1035 View *view = view_from_widget (widget);
1039 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1042 if (callback_action)
1044 gtk_text_buffer_remove_tag (view->buffer->buffer,
1045 view->buffer->not_editable_tag,
1050 gtk_text_buffer_apply_tag (view->buffer->buffer,
1051 view->buffer->not_editable_tag,
1058 do_apply_invisible (gpointer callback_data,
1059 guint callback_action,
1062 View *view = view_from_widget (widget);
1066 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1069 if (callback_action)
1071 gtk_text_buffer_remove_tag (view->buffer->buffer,
1072 view->buffer->invisible_tag,
1077 gtk_text_buffer_apply_tag (view->buffer->buffer,
1078 view->buffer->invisible_tag,
1085 do_apply_rise (gpointer callback_data,
1086 guint callback_action,
1089 View *view = view_from_widget (widget);
1093 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1096 if (callback_action)
1098 gtk_text_buffer_remove_tag (view->buffer->buffer,
1099 view->buffer->rise_tag,
1104 gtk_text_buffer_apply_tag (view->buffer->buffer,
1105 view->buffer->rise_tag,
1112 do_apply_large (gpointer callback_data,
1113 guint callback_action,
1116 View *view = view_from_widget (widget);
1120 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1123 if (callback_action)
1125 gtk_text_buffer_remove_tag (view->buffer->buffer,
1126 view->buffer->large_tag,
1131 gtk_text_buffer_apply_tag (view->buffer->buffer,
1132 view->buffer->large_tag,
1139 do_apply_indent (gpointer callback_data,
1140 guint callback_action,
1143 View *view = view_from_widget (widget);
1147 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1150 if (callback_action)
1152 gtk_text_buffer_remove_tag (view->buffer->buffer,
1153 view->buffer->indent_tag,
1158 gtk_text_buffer_apply_tag (view->buffer->buffer,
1159 view->buffer->indent_tag,
1166 do_apply_margin (gpointer callback_data,
1167 guint callback_action,
1170 View *view = view_from_widget (widget);
1174 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1177 if (callback_action)
1179 gtk_text_buffer_remove_tag (view->buffer->buffer,
1180 view->buffer->margin_tag,
1185 gtk_text_buffer_apply_tag (view->buffer->buffer,
1186 view->buffer->margin_tag,
1193 do_apply_tabs (gpointer callback_data,
1194 guint callback_action,
1197 View *view = view_from_widget (widget);
1201 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1204 if (callback_action)
1206 gtk_text_buffer_remove_tag (view->buffer->buffer,
1207 view->buffer->custom_tabs_tag,
1212 gtk_text_buffer_apply_tag (view->buffer->buffer,
1213 view->buffer->custom_tabs_tag,
1220 do_apply_colors (gpointer callback_data,
1221 guint callback_action,
1224 View *view = view_from_widget (widget);
1225 Buffer *buffer = view->buffer;
1229 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1232 if (!callback_action)
1236 tmp = buffer->color_tags;
1239 gtk_text_buffer_remove_tag (view->buffer->buffer,
1242 tmp = g_slist_next (tmp);
1249 tmp = buffer->color_tags;
1253 gboolean done = FALSE;
1256 gtk_text_iter_forward_char (&next);
1257 gtk_text_iter_forward_char (&next);
1259 if (gtk_text_iter_compare (&next, &end) >= 0)
1265 gtk_text_buffer_apply_tag (view->buffer->buffer,
1274 tmp = g_slist_next (tmp);
1276 tmp = buffer->color_tags;
1283 do_remove_tags (gpointer callback_data,
1284 guint callback_action,
1287 View *view = view_from_widget (widget);
1291 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1294 gtk_text_buffer_remove_all_tags (view->buffer->buffer,
1300 do_properties (gpointer callback_data,
1301 guint callback_action,
1304 View *view = view_from_widget (widget);
1306 create_prop_editor (G_OBJECT (view->text_view), 0);
1310 rich_text_store_populate (GtkListStore *store,
1311 GtkTextBuffer *buffer,
1312 gboolean deserialize)
1318 gtk_list_store_clear (store);
1321 formats = gtk_text_buffer_get_deserialize_formats (buffer, &n_formats);
1323 formats = gtk_text_buffer_get_serialize_formats (buffer, &n_formats);
1325 for (i = 0; i < n_formats; i++)
1329 gboolean can_create_tags = FALSE;
1331 mime_type = gdk_atom_name (formats[i]);
1335 gtk_text_buffer_deserialize_get_can_create_tags (buffer, formats[i]);
1337 gtk_list_store_append (store, &iter);
1338 gtk_list_store_set (store, &iter,
1351 rich_text_paste_target_list_notify (GtkTextBuffer *buffer,
1352 const GParamSpec *pspec,
1353 GtkListStore *store)
1355 rich_text_store_populate (store, buffer, TRUE);
1359 rich_text_copy_target_list_notify (GtkTextBuffer *buffer,
1360 const GParamSpec *pspec,
1361 GtkListStore *store)
1363 rich_text_store_populate (store, buffer, FALSE);
1367 rich_text_can_create_tags_toggled (GtkCellRendererToggle *toggle,
1369 GtkTreeModel *model)
1373 if (gtk_tree_model_get_iter_from_string (model, &iter, path))
1375 GtkTextBuffer *buffer;
1377 gboolean can_create_tags;
1379 buffer = g_object_get_data (G_OBJECT (model), "buffer");
1381 gtk_tree_model_get (model, &iter,
1383 2, &can_create_tags,
1386 gtk_text_buffer_deserialize_set_can_create_tags (buffer, format,
1389 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1390 2, !can_create_tags,
1396 rich_text_unregister_clicked (GtkWidget *button,
1399 GtkTreeSelection *sel = gtk_tree_view_get_selection (tv);
1400 GtkTreeModel *model;
1403 if (gtk_tree_selection_get_selected (sel, &model, &iter))
1405 GtkTextBuffer *buffer;
1406 gboolean deserialize;
1409 buffer = g_object_get_data (G_OBJECT (model), "buffer");
1410 deserialize = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model),
1413 gtk_tree_model_get (model, &iter,
1418 gtk_text_buffer_unregister_deserialize_format (buffer, format);
1420 gtk_text_buffer_unregister_serialize_format (buffer, format);
1425 rich_text_register_clicked (GtkWidget *button,
1432 dialog = gtk_dialog_new_with_buttons ("Register new Tagset",
1433 GTK_WINDOW (gtk_widget_get_toplevel (button)),
1434 GTK_DIALOG_DESTROY_WITH_PARENT,
1435 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1436 GTK_STOCK_OK, GTK_RESPONSE_OK,
1438 label = gtk_label_new ("Enter tagset name or leave blank for "
1439 "unrestricted internal format:");
1440 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), label,
1443 entry = gtk_entry_new ();
1444 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), entry,
1447 gtk_widget_show_all (dialog);
1449 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
1451 GtkTreeModel *model = gtk_tree_view_get_model (tv);
1452 GtkTextBuffer *buffer = g_object_get_data (G_OBJECT (model), "buffer");
1453 const gchar *tagset = gtk_entry_get_text (GTK_ENTRY (entry));
1454 gboolean deserialize;
1456 deserialize = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model),
1459 if (tagset && ! strlen (tagset))
1463 gtk_text_buffer_register_deserialize_tagset (buffer, tagset);
1465 gtk_text_buffer_register_serialize_tagset (buffer, tagset);
1468 gtk_widget_destroy (dialog);
1472 do_rich_text (gpointer callback_data,
1476 View *view = view_from_widget (widget);
1477 GtkTextBuffer *buffer;
1483 GtkListStore *store;
1485 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->text_view));
1487 dialog = gtk_dialog_new_with_buttons (deserialize ?
1488 "Rich Text Paste & Drop" :
1489 "Rich Text Copy & Drag",
1490 GTK_WINDOW (view->window),
1491 GTK_DIALOG_DESTROY_WITH_PARENT,
1494 g_signal_connect (dialog, "response",
1495 G_CALLBACK (gtk_widget_destroy),
1498 store = gtk_list_store_new (3,
1503 g_object_set_data (G_OBJECT (store), "buffer", buffer);
1504 g_object_set_data (G_OBJECT (store), "deserialize",
1505 GUINT_TO_POINTER (deserialize));
1507 tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1508 g_object_unref (store);
1510 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv),
1511 0, "Rich Text Format",
1512 gtk_cell_renderer_text_new (),
1518 GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new ();
1520 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv),
1521 1, "Can Create Tags",
1526 g_signal_connect (renderer, "toggled",
1527 G_CALLBACK (rich_text_can_create_tags_toggled),
1531 sw = gtk_scrolled_window_new (NULL, NULL);
1532 gtk_widget_set_size_request (sw, 300, 100);
1533 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), sw);
1535 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), tv);
1537 hbox = gtk_hbox_new (FALSE, 6);
1538 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
1541 button = gtk_button_new_with_label ("Unregister Selected Format");
1542 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1544 g_signal_connect (button, "clicked",
1545 G_CALLBACK (rich_text_unregister_clicked),
1548 button = gtk_button_new_with_label ("Register New Tagset\n"
1549 "for the Internal Format");
1550 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1552 g_signal_connect (button, "clicked",
1553 G_CALLBACK (rich_text_register_clicked),
1557 g_signal_connect_object (buffer, "notify::paste-target-list",
1558 G_CALLBACK (rich_text_paste_target_list_notify),
1559 G_OBJECT (store), 0);
1561 g_signal_connect_object (buffer, "notify::copy-target-list",
1562 G_CALLBACK (rich_text_copy_target_list_notify),
1563 G_OBJECT (store), 0);
1565 rich_text_store_populate (store, buffer, deserialize);
1567 gtk_widget_show_all (dialog);
1577 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1579 GtkTextBuffer *buffer;
1581 GtkTextIter start, end;
1582 gchar *search_string;
1584 if (response_id != RESPONSE_FORWARD &&
1585 response_id != RESPONSE_BACKWARD)
1587 gtk_widget_destroy (dialog);
1591 buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
1593 gtk_text_buffer_get_bounds (buffer, &start, &end);
1595 search_string = gtk_text_iter_get_text (&start, &end);
1597 g_print ("Searching for `%s'\n", search_string);
1599 if (response_id == RESPONSE_FORWARD)
1600 buffer_search_forward (view->buffer, search_string, view);
1601 else if (response_id == RESPONSE_BACKWARD)
1602 buffer_search_backward (view->buffer, search_string, view);
1604 g_free (search_string);
1606 gtk_widget_destroy (dialog);
1610 do_copy (gpointer callback_data,
1611 guint callback_action,
1614 View *view = view_from_widget (widget);
1615 GtkTextBuffer *buffer;
1617 buffer = view->buffer->buffer;
1619 gtk_text_buffer_copy_clipboard (buffer,
1620 gtk_clipboard_get (GDK_NONE));
1624 do_search (gpointer callback_data,
1625 guint callback_action,
1628 View *view = view_from_widget (widget);
1630 GtkWidget *search_text;
1631 GtkTextBuffer *buffer;
1633 dialog = gtk_dialog_new_with_buttons ("Search",
1634 GTK_WINDOW (view->window),
1635 GTK_DIALOG_DESTROY_WITH_PARENT,
1636 "Forward", RESPONSE_FORWARD,
1637 "Backward", RESPONSE_BACKWARD,
1639 GTK_RESPONSE_NONE, NULL);
1642 buffer = gtk_text_buffer_new (NULL);
1644 search_text = gtk_text_view_new_with_buffer (buffer);
1646 g_object_unref (buffer);
1648 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1652 g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
1654 g_signal_connect (dialog,
1656 G_CALLBACK (dialog_response_callback),
1659 gtk_widget_show (search_text);
1661 gtk_widget_grab_focus (search_text);
1663 gtk_widget_show_all (dialog);
1667 do_select_all (gpointer callback_data,
1668 guint callback_action,
1671 View *view = view_from_widget (widget);
1672 GtkTextBuffer *buffer;
1673 GtkTextIter start, end;
1675 buffer = view->buffer->buffer;
1677 gtk_text_buffer_get_bounds (buffer, &start, &end);
1678 gtk_text_buffer_select_range (buffer, &start, &end);
1683 /* position is in coordinate system of text_view_move_child */
1692 movable_child_callback (GtkWidget *child,
1696 ChildMoveInfo *info;
1697 GtkTextView *text_view;
1699 text_view = GTK_TEXT_VIEW (data);
1701 g_return_val_if_fail (GTK_IS_EVENT_BOX (child), FALSE);
1702 g_return_val_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (text_view), FALSE);
1704 info = g_object_get_data (G_OBJECT (child),
1705 "testtext-move-info");
1709 info = g_new (ChildMoveInfo, 1);
1713 g_object_set_data_full (G_OBJECT (child),
1714 "testtext-move-info",
1719 switch (event->type)
1721 case GDK_BUTTON_PRESS:
1722 if (info->button < 0)
1724 if (gdk_pointer_grab (event->button.window,
1726 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1727 GDK_BUTTON_RELEASE_MASK,
1730 event->button.time) != GDK_GRAB_SUCCESS)
1733 info->button = event->button.button;
1735 info->start_x = child->allocation.x;
1736 info->start_y = child->allocation.y;
1737 info->click_x = child->allocation.x + event->button.x;
1738 info->click_y = child->allocation.y + event->button.y;
1742 case GDK_BUTTON_RELEASE:
1743 if (info->button < 0)
1746 if (info->button == event->button.button)
1750 gdk_pointer_ungrab (event->button.time);
1753 /* convert to window coords from event box coords */
1754 x = info->start_x + (event->button.x + child->allocation.x - info->click_x);
1755 y = info->start_y + (event->button.y + child->allocation.y - info->click_y);
1757 gtk_text_view_move_child (text_view,
1763 case GDK_MOTION_NOTIFY:
1767 if (info->button < 0)
1770 gdk_window_get_pointer (child->window, &x, &y, NULL); /* ensure more events */
1772 /* to window coords from event box coords */
1773 x += child->allocation.x;
1774 y += child->allocation.y;
1776 x = info->start_x + (x - info->click_x);
1777 y = info->start_y + (y - info->click_y);
1779 gtk_text_view_move_child (text_view,
1793 add_movable_child (GtkTextView *text_view,
1794 GtkTextWindowType window)
1796 GtkWidget *event_box;
1800 label = gtk_label_new ("Drag me around");
1802 event_box = gtk_event_box_new ();
1803 gtk_widget_add_events (event_box,
1804 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1805 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
1808 color.green = color.blue = 0;
1809 gtk_widget_modify_bg (event_box, GTK_STATE_NORMAL, &color);
1811 gtk_container_add (GTK_CONTAINER (event_box), label);
1813 gtk_widget_show_all (event_box);
1815 g_signal_connect (event_box, "event",
1816 G_CALLBACK (movable_child_callback),
1819 gtk_text_view_add_child_in_window (text_view,
1826 do_add_children (gpointer callback_data,
1827 guint callback_action,
1830 View *view = view_from_widget (widget);
1832 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1833 GTK_TEXT_WINDOW_WIDGET);
1834 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1835 GTK_TEXT_WINDOW_LEFT);
1836 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1837 GTK_TEXT_WINDOW_RIGHT);
1841 do_add_focus_children (gpointer callback_data,
1842 guint callback_action,
1845 View *view = view_from_widget (widget);
1847 GtkTextChildAnchor *anchor;
1849 GtkTextView *text_view;
1851 text_view = GTK_TEXT_VIEW (view->text_view);
1853 child = gtk_button_new_with_mnemonic ("Button _A in widget->window");
1855 gtk_text_view_add_child_in_window (text_view,
1857 GTK_TEXT_WINDOW_WIDGET,
1860 child = gtk_button_new_with_mnemonic ("Button _B in widget->window");
1862 gtk_text_view_add_child_in_window (text_view,
1864 GTK_TEXT_WINDOW_WIDGET,
1867 child = gtk_button_new_with_mnemonic ("Button _C in left window");
1869 gtk_text_view_add_child_in_window (text_view,
1871 GTK_TEXT_WINDOW_LEFT,
1874 child = gtk_button_new_with_mnemonic ("Button _D in right window");
1876 gtk_text_view_add_child_in_window (text_view,
1878 GTK_TEXT_WINDOW_RIGHT,
1881 gtk_text_buffer_get_start_iter (view->buffer->buffer, &iter);
1883 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1885 child = gtk_button_new_with_mnemonic ("Button _E in buffer");
1887 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1889 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1891 child = gtk_button_new_with_mnemonic ("Button _F in buffer");
1893 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1895 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1897 child = gtk_button_new_with_mnemonic ("Button _G in buffer");
1899 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1901 /* show all the buttons */
1902 gtk_widget_show_all (view->text_view);
1906 view_init_menus (View *view)
1908 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1909 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1910 GtkWidget *menu_item = NULL;
1914 case GTK_TEXT_DIR_LTR:
1915 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1917 case GTK_TEXT_DIR_RTL:
1918 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1925 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1930 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1933 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1936 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
1943 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1946 static GtkItemFactoryEntry menu_items[] =
1948 { "/_File", NULL, NULL, 0, "<Branch>" },
1949 { "/File/_New", "<control>N", do_new, 0, NULL },
1950 { "/File/New _View", NULL, do_new_view, 0, NULL },
1951 { "/File/_Open", "<control>O", do_open, 0, NULL },
1952 { "/File/_Save", "<control>S", do_save, 0, NULL },
1953 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1954 { "/File/sep1", NULL, NULL, 0, "<Separator>" },
1955 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1956 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1958 { "/_Edit", NULL, 0, 0, "<Branch>" },
1959 { "/Edit/Copy", NULL, do_copy, 0, NULL },
1960 { "/Edit/sep1", NULL, NULL, 0, "<Separator>" },
1961 { "/Edit/Find...", NULL, do_search, 0, NULL },
1962 { "/Edit/Select All", "<control>A", do_select_all, 0, NULL },
1964 { "/_Settings", NULL, NULL, 0, "<Branch>" },
1965 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAP_NONE, "<RadioItem>" },
1966 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAP_WORD, "/Settings/Wrap Off" },
1967 { "/Settings/Wrap _Chars", NULL, do_wrap_changed, GTK_WRAP_CHAR, "/Settings/Wrap Off" },
1968 { "/Settings/sep1", NULL, NULL, 0, "<Separator>" },
1969 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1970 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1971 { "/Settings/sep1", NULL, NULL, 0, "<Separator>" },
1973 { "/Settings/Cursor normal", NULL, do_cursor_visible_changed, 1, "<RadioItem>" },
1974 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, 0, "/Settings/Cursor normal" },
1975 { "/Settings/Cursor colored", NULL, do_cursor_visible_changed, 2, "/Settings/Cursor normal" },
1976 { "/Settings/sep1", NULL, NULL, 0, "<Separator>" },
1978 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1979 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1981 { "/Settings/sep1", NULL, NULL, 0, "<Separator>" },
1982 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1983 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1984 { "/Settings/sep1", NULL, NULL, 0, "<Separator>" },
1985 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1986 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1987 { "/_Attributes", NULL, NULL, 0, "<Branch>" },
1988 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1989 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1990 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1991 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1992 { "/Attributes/Rise", NULL, do_apply_rise, FALSE, NULL },
1993 { "/Attributes/Large", NULL, do_apply_large, FALSE, NULL },
1994 { "/Attributes/Indent", NULL, do_apply_indent, FALSE, NULL },
1995 { "/Attributes/Margins", NULL, do_apply_margin, FALSE, NULL },
1996 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1997 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1998 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1999 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
2000 { "/Attributes/Remove all tags", NULL, do_remove_tags, 0, NULL },
2001 { "/Attributes/Properties", NULL, do_properties, 0, NULL },
2002 { "/Attributes/Rich Text copy & drag", NULL, do_rich_text, 0, NULL },
2003 { "/Attributes/Rich Text paste & drop", NULL, do_rich_text, 1, NULL },
2004 { "/_Test", NULL, NULL, 0, "<Branch>" },
2005 { "/Test/_Example", NULL, do_example, 0, NULL },
2006 { "/Test/_Insert and scroll", NULL, do_insert_and_scroll, 0, NULL },
2007 { "/Test/_Add fixed children", NULL, do_add_children, 0, NULL },
2008 { "/Test/A_dd focusable children", NULL, do_add_focus_children, 0, NULL },
2012 save_buffer (Buffer *buffer)
2014 GtkTextIter start, end;
2016 gboolean result = FALSE;
2017 gboolean have_backup = FALSE;
2018 gchar *bak_filename;
2021 g_return_val_if_fail (buffer->filename != NULL, FALSE);
2023 bak_filename = g_strconcat (buffer->filename, "~", NULL);
2025 if (rename (buffer->filename, bak_filename) != 0)
2027 if (errno != ENOENT)
2029 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
2030 buffer->filename, bak_filename, g_strerror (errno));
2031 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
2039 file = fopen (buffer->filename, "w");
2042 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
2043 buffer->filename, bak_filename, g_strerror (errno));
2044 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
2048 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
2049 gtk_text_buffer_get_end_iter (buffer->buffer, &end);
2051 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
2053 if (fputs (chars, file) == EOF ||
2054 fclose (file) == EOF)
2056 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
2057 buffer->filename, g_strerror (errno));
2058 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
2066 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
2072 if (!result && have_backup)
2074 if (rename (bak_filename, buffer->filename) != 0)
2076 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
2077 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
2078 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
2083 g_free (bak_filename);
2089 save_as_ok_func (const char *filename, gpointer data)
2091 Buffer *buffer = data;
2092 char *old_filename = buffer->filename;
2094 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
2096 struct stat statbuf;
2098 if (stat (filename, &statbuf) == 0)
2100 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
2101 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
2109 buffer->filename = g_strdup (filename);
2111 if (save_buffer (buffer))
2113 g_free (old_filename);
2114 buffer_filename_set (buffer);
2119 g_free (buffer->filename);
2120 buffer->filename = old_filename;
2126 save_as_buffer (Buffer *buffer)
2128 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
2132 check_buffer_saved (Buffer *buffer)
2134 if (gtk_text_buffer_get_modified (buffer->buffer))
2136 char *pretty_name = buffer_pretty_name (buffer);
2137 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
2140 g_free (pretty_name);
2142 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
2146 return save_as_buffer (buffer);
2147 else if (result == 1)
2159 create_buffer (void)
2162 PangoTabArray *tabs;
2165 buffer = g_new (Buffer, 1);
2167 buffer->buffer = gtk_text_buffer_new (NULL);
2169 buffer->refcount = 1;
2170 buffer->filename = NULL;
2171 buffer->untitled_serial = -1;
2173 buffer->color_tags = NULL;
2174 buffer->color_cycle_timeout = 0;
2175 buffer->start_hue = 0.0;
2178 while (i < N_COLORS)
2182 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL, NULL);
2184 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
2190 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
2191 "invisible", TRUE, NULL);
2194 buffer->not_editable_tag =
2195 gtk_text_buffer_create_tag (buffer->buffer, NULL,
2197 "foreground", "purple", NULL);
2199 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
2200 "foreground", "red", NULL);
2202 buffer->rise_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
2203 "rise", 10 * PANGO_SCALE, NULL);
2205 buffer->large_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
2206 "scale", PANGO_SCALE_X_LARGE, NULL);
2208 buffer->indent_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
2209 "indent", 20, NULL);
2211 buffer->margin_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
2212 "left_margin", 20, "right_margin", 20, NULL);
2214 tabs = pango_tab_array_new_with_positions (4,
2219 PANGO_TAB_LEFT, 120);
2221 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
2223 "foreground", "green", NULL);
2225 pango_tab_array_free (tabs);
2227 buffers = g_slist_prepend (buffers, buffer);
2233 buffer_pretty_name (Buffer *buffer)
2235 if (buffer->filename)
2238 char *result = g_path_get_basename (buffer->filename);
2239 p = strchr (result, '/');
2247 if (buffer->untitled_serial == -1)
2248 buffer->untitled_serial = untitled_serial++;
2250 if (buffer->untitled_serial == 1)
2251 return g_strdup ("Untitled");
2253 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
2258 buffer_filename_set (Buffer *buffer)
2260 GSList *tmp_list = views;
2264 View *view = tmp_list->data;
2266 if (view->buffer == buffer)
2267 view_set_title (view);
2269 tmp_list = tmp_list->next;
2274 buffer_search (Buffer *buffer,
2280 GtkTextIter start, end;
2284 /* remove tag from whole buffer */
2285 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
2286 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
2289 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
2290 gtk_text_buffer_get_mark (buffer->buffer,
2296 GtkTextIter match_start, match_end;
2300 while (gtk_text_iter_forward_search (&iter, str,
2301 GTK_TEXT_SEARCH_VISIBLE_ONLY |
2302 GTK_TEXT_SEARCH_TEXT_ONLY,
2303 &match_start, &match_end,
2307 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
2308 &match_start, &match_end);
2315 while (gtk_text_iter_backward_search (&iter, str,
2316 GTK_TEXT_SEARCH_VISIBLE_ONLY |
2317 GTK_TEXT_SEARCH_TEXT_ONLY,
2318 &match_start, &match_end,
2322 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
2323 &match_start, &match_end);
2330 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
2331 GTK_DIALOG_DESTROY_WITH_PARENT,
2334 "%d strings found and marked in red",
2337 g_signal_connect_swapped (dialog,
2339 G_CALLBACK (gtk_widget_destroy), dialog);
2341 gtk_widget_show (dialog);
2345 buffer_search_forward (Buffer *buffer, const char *str,
2348 buffer_search (buffer, str, view, TRUE);
2352 buffer_search_backward (Buffer *buffer, const char *str,
2355 buffer_search (buffer, str, view, FALSE);
2359 buffer_ref (Buffer *buffer)
2365 buffer_unref (Buffer *buffer)
2368 if (buffer->refcount == 0)
2370 buffer_set_colors (buffer, FALSE);
2371 buffers = g_slist_remove (buffers, buffer);
2372 g_object_unref (buffer->buffer);
2373 g_free (buffer->filename);
2379 hsv_to_rgb (gdouble *h,
2383 gdouble hue, saturation, value;
2401 f = hue - (int) hue;
2402 p = value * (1.0 - saturation);
2403 q = value * (1.0 - saturation * f);
2404 t = value * (1.0 - saturation * (1.0 - f));
2445 g_assert_not_reached ();
2451 hue_to_color (gdouble hue,
2460 g_return_if_fail (hue <= 1.0);
2462 hsv_to_rgb (&h, &s, &v);
2464 color->red = h * 65535;
2465 color->green = s * 65535;
2466 color->blue = v * 65535;
2471 color_cycle_timeout (gpointer data)
2473 Buffer *buffer = data;
2475 buffer_cycle_colors (buffer);
2481 buffer_set_colors (Buffer *buffer,
2487 if (enabled && buffer->color_cycle_timeout == 0)
2488 buffer->color_cycle_timeout = gdk_threads_add_timeout (200, color_cycle_timeout, buffer);
2489 else if (!enabled && buffer->color_cycle_timeout != 0)
2491 g_source_remove (buffer->color_cycle_timeout);
2492 buffer->color_cycle_timeout = 0;
2495 tmp = buffer->color_tags;
2502 hue_to_color (hue, &color);
2504 g_object_set (tmp->data,
2505 "foreground_gdk", &color,
2509 g_object_set (tmp->data,
2510 "foreground_set", FALSE,
2513 hue += 1.0 / N_COLORS;
2515 tmp = g_slist_next (tmp);
2520 buffer_cycle_colors (Buffer *buffer)
2523 gdouble hue = buffer->start_hue;
2525 tmp = buffer->color_tags;
2530 hue_to_color (hue, &color);
2532 g_object_set (tmp->data,
2533 "foreground_gdk", &color,
2536 hue += 1.0 / N_COLORS;
2540 tmp = g_slist_next (tmp);
2543 buffer->start_hue += 1.0 / N_COLORS;
2544 if (buffer->start_hue > 1.0)
2545 buffer->start_hue = 0.0;
2549 close_view (View *view)
2551 views = g_slist_remove (views, view);
2552 buffer_unref (view->buffer);
2553 gtk_widget_destroy (view->window);
2554 g_object_unref (view->item_factory);
2563 check_close_view (View *view)
2565 if (view->buffer->refcount > 1 ||
2566 check_buffer_saved (view->buffer))
2571 view_set_title (View *view)
2573 char *pretty_name = buffer_pretty_name (view->buffer);
2574 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
2576 gtk_window_set_title (GTK_WINDOW (view->window), title);
2578 g_free (pretty_name);
2583 cursor_set_callback (GtkTextBuffer *buffer,
2584 const GtkTextIter *location,
2588 GtkTextView *text_view;
2590 /* Redraw tab windows if the cursor moves
2591 * on the mapped widget (windows may not exist before realization...
2594 text_view = GTK_TEXT_VIEW (user_data);
2596 if (gtk_widget_get_mapped (GTK_WIDGET (text_view)) &&
2597 mark == gtk_text_buffer_get_insert (buffer))
2599 GdkWindow *tab_window;
2601 tab_window = gtk_text_view_get_window (text_view,
2602 GTK_TEXT_WINDOW_TOP);
2604 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
2606 tab_window = gtk_text_view_get_window (text_view,
2607 GTK_TEXT_WINDOW_BOTTOM);
2609 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
2614 tab_stops_expose (GtkWidget *widget,
2615 GdkEventExpose *event,
2622 GdkWindow *bottom_win;
2623 GtkTextView *text_view;
2624 GtkTextWindowType type;
2625 GdkDrawable *target;
2626 gint *positions = NULL;
2628 GtkTextAttributes *attrs;
2630 GtkTextBuffer *buffer;
2633 text_view = GTK_TEXT_VIEW (widget);
2635 /* See if this expose is on the tab stop window */
2636 top_win = gtk_text_view_get_window (text_view,
2637 GTK_TEXT_WINDOW_TOP);
2639 bottom_win = gtk_text_view_get_window (text_view,
2640 GTK_TEXT_WINDOW_BOTTOM);
2642 if (event->window == top_win)
2644 type = GTK_TEXT_WINDOW_TOP;
2647 else if (event->window == bottom_win)
2649 type = GTK_TEXT_WINDOW_BOTTOM;
2650 target = bottom_win;
2655 first_x = event->area.x;
2656 last_x = first_x + event->area.width;
2658 gtk_text_view_window_to_buffer_coords (text_view,
2665 gtk_text_view_window_to_buffer_coords (text_view,
2672 buffer = gtk_text_view_get_buffer (text_view);
2674 gtk_text_buffer_get_iter_at_mark (buffer,
2676 gtk_text_buffer_get_mark (buffer,
2679 attrs = gtk_text_attributes_new ();
2681 gtk_text_iter_get_attributes (&insert, attrs);
2685 size = pango_tab_array_get_size (attrs->tabs);
2687 pango_tab_array_get_tabs (attrs->tabs,
2691 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
2699 gtk_text_attributes_unref (attrs);
2707 positions[i] = PANGO_PIXELS (positions[i]);
2709 gtk_text_view_buffer_to_window_coords (text_view,
2716 gdk_draw_line (target,
2717 widget->style->fg_gc [widget->state],
2730 get_lines (GtkTextView *text_view,
2733 GArray *buffer_coords,
2741 g_array_set_size (buffer_coords, 0);
2742 g_array_set_size (numbers, 0);
2744 /* Get iter at first y */
2745 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
2747 /* For each iter, get its location and add it to the arrays.
2748 * Stop when we pass last_y
2753 while (!gtk_text_iter_is_end (&iter))
2758 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2760 g_array_append_val (buffer_coords, y);
2761 line_num = gtk_text_iter_get_line (&iter);
2762 g_array_append_val (numbers, line_num);
2766 if ((y + height) >= last_y)
2769 gtk_text_iter_forward_line (&iter);
2776 line_numbers_expose (GtkWidget *widget,
2777 GdkEventExpose *event,
2786 GdkWindow *left_win;
2787 GdkWindow *right_win;
2788 PangoLayout *layout;
2789 GtkTextView *text_view;
2790 GtkTextWindowType type;
2791 GdkDrawable *target;
2793 text_view = GTK_TEXT_VIEW (widget);
2795 /* See if this expose is on the line numbers window */
2796 left_win = gtk_text_view_get_window (text_view,
2797 GTK_TEXT_WINDOW_LEFT);
2799 right_win = gtk_text_view_get_window (text_view,
2800 GTK_TEXT_WINDOW_RIGHT);
2802 if (event->window == left_win)
2804 type = GTK_TEXT_WINDOW_LEFT;
2807 else if (event->window == right_win)
2809 type = GTK_TEXT_WINDOW_RIGHT;
2815 first_y = event->area.y;
2816 last_y = first_y + event->area.height;
2818 gtk_text_view_window_to_buffer_coords (text_view,
2825 gtk_text_view_window_to_buffer_coords (text_view,
2832 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2833 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2835 get_lines (text_view,
2842 /* Draw fully internationalized numbers! */
2844 layout = gtk_widget_create_pango_layout (widget, "");
2852 gtk_text_view_buffer_to_window_coords (text_view,
2855 g_array_index (pixels, gint, i),
2859 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2861 pango_layout_set_text (layout, str, -1);
2863 gtk_paint_layout (widget->style,
2865 gtk_widget_get_state (widget),
2878 g_array_free (pixels, TRUE);
2879 g_array_free (numbers, TRUE);
2881 g_object_unref (layout);
2883 /* don't stop emission, need to draw children */
2888 selection_changed (GtkTextBuffer *buffer,
2890 GtkWidget *copy_menu)
2892 gtk_widget_set_sensitive (copy_menu, gtk_text_buffer_get_has_selection (buffer));
2896 create_view (Buffer *buffer)
2899 GtkWidget *copy_menu;
2903 view = g_new0 (View, 1);
2904 views = g_slist_prepend (views, view);
2906 view->buffer = buffer;
2907 buffer_ref (buffer);
2909 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2910 g_object_set_data (G_OBJECT (view->window), "view", view);
2912 g_signal_connect (view->window, "delete_event",
2913 G_CALLBACK (delete_event_cb), NULL);
2915 view->accel_group = gtk_accel_group_new ();
2916 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2917 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2919 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2921 /* make the Copy menu item sensitivity update according to the selection */
2922 copy_menu = gtk_item_factory_get_item (view->item_factory, "<main>/Edit/Copy");
2923 gtk_widget_set_sensitive (copy_menu, gtk_text_buffer_get_has_selection (view->buffer->buffer));
2924 g_signal_connect (view->buffer->buffer,
2925 "notify::has-selection",
2926 G_CALLBACK (selection_changed),
2929 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2931 vbox = gtk_vbox_new (FALSE, 0);
2932 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2934 gtk_box_pack_start (GTK_BOX (vbox),
2935 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2938 sw = gtk_scrolled_window_new (NULL, NULL);
2939 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2940 GTK_POLICY_AUTOMATIC,
2941 GTK_POLICY_AUTOMATIC);
2943 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2944 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2947 /* Make sure border width works, no real reason to do this other than testing */
2948 gtk_container_set_border_width (GTK_CONTAINER (view->text_view),
2951 /* Draw tab stops in the top and bottom windows. */
2953 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2954 GTK_TEXT_WINDOW_TOP,
2957 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2958 GTK_TEXT_WINDOW_BOTTOM,
2961 g_signal_connect (view->text_view,
2963 G_CALLBACK (tab_stops_expose),
2966 g_signal_connect (view->buffer->buffer,
2968 G_CALLBACK (cursor_set_callback),
2971 /* Draw line numbers in the side windows; we should really be
2972 * more scientific about what width we set them to.
2974 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2975 GTK_TEXT_WINDOW_RIGHT,
2978 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2979 GTK_TEXT_WINDOW_LEFT,
2982 g_signal_connect (view->text_view,
2984 G_CALLBACK (line_numbers_expose),
2987 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2988 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2990 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2992 gtk_widget_grab_focus (view->text_view);
2994 view_set_title (view);
2995 view_init_menus (view);
2997 view_add_example_widgets (view);
2999 gtk_widget_show_all (view->window);
3004 view_add_example_widgets (View *view)
3006 GtkTextChildAnchor *anchor;
3009 buffer = view->buffer;
3011 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
3014 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
3018 widget = gtk_button_new_with_label ("Foo");
3020 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
3024 gtk_widget_show (widget);
3031 if (g_file_test ("../gdk-pixbuf/libpixbufloader-pnm.la",
3032 G_FILE_TEST_EXISTS))
3034 g_setenv ("GDK_PIXBUF_MODULE_FILE", "../gdk-pixbuf/loaders.cache", TRUE);
3035 g_setenv ("GTK_IM_MODULE_FILE", "../modules/input/immodules.cache", TRUE);
3040 main (int argc, char** argv)
3047 gtk_init (&argc, &argv);
3049 buffer = create_buffer ();
3050 view = create_view (buffer);
3051 buffer_unref (buffer);
3053 push_active_window (GTK_WINDOW (view->window));
3054 for (i=1; i < argc; i++)
3058 /* Quick and dirty canonicalization - better should be in GLib
3061 if (!g_path_is_absolute (argv[i]))
3063 char *cwd = g_get_current_dir ();
3064 filename = g_strconcat (cwd, "/", argv[i], NULL);
3070 open_ok_func (filename, view);
3072 if (filename != argv[i])
3075 pop_active_window ();