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.
28 #undef GTK_DISABLE_DEPRECATED
31 #include <gdk/gdkkeysyms.h>
33 #include "prop-editor.h"
35 typedef struct _Buffer Buffer
;
36 typedef struct _View View
;
38 static gint untitled_serial
= 1;
40 GSList
*active_window_stack
= NULL
;
45 GtkTextBuffer
*buffer
;
48 GtkTextTag
*invisible_tag
;
49 GtkTextTag
*not_editable_tag
;
50 GtkTextTag
*found_text_tag
;
52 GtkTextTag
*large_tag
;
53 GtkTextTag
*indent_tag
;
54 GtkTextTag
*margin_tag
;
55 GtkTextTag
*custom_tabs_tag
;
57 guint color_cycle_timeout
;
65 GtkAccelGroup
*accel_group
;
66 GtkItemFactory
*item_factory
;
70 static void push_active_window (GtkWindow
*window
);
71 static void pop_active_window (void);
72 static GtkWindow
*get_active_window (void);
74 static Buffer
* create_buffer (void);
75 static gboolean
check_buffer_saved (Buffer
*buffer
);
76 static gboolean
save_buffer (Buffer
*buffer
);
77 static gboolean
save_as_buffer (Buffer
*buffer
);
78 static char * buffer_pretty_name (Buffer
*buffer
);
79 static void buffer_filename_set (Buffer
*buffer
);
80 static void buffer_search_forward (Buffer
*buffer
,
83 static void buffer_search_backward (Buffer
*buffer
,
86 static void buffer_set_colors (Buffer
*buffer
,
88 static void buffer_cycle_colors (Buffer
*buffer
);
90 static View
*view_from_widget (GtkWidget
*widget
);
92 static View
*create_view (Buffer
*buffer
);
93 static void check_close_view (View
*view
);
94 static void close_view (View
*view
);
95 static void view_set_title (View
*view
);
96 static void view_init_menus (View
*view
);
97 static void view_add_example_widgets (View
*view
);
99 GSList
*buffers
= NULL
;
100 GSList
*views
= NULL
;
103 push_active_window (GtkWindow
*window
)
105 g_object_ref (window
);
106 active_window_stack
= g_slist_prepend (active_window_stack
, window
);
110 pop_active_window (void)
112 g_object_unref (active_window_stack
->data
);
113 active_window_stack
= g_slist_delete_link (active_window_stack
, active_window_stack
);
117 get_active_window (void)
119 if (active_window_stack
)
120 return active_window_stack
->data
;
126 * Filesel utility function
129 typedef gboolean (*FileselOKFunc
) (const char *filename
, gpointer data
);
132 filesel_ok_cb (GtkWidget
*button
, GtkWidget
*filesel
)
134 FileselOKFunc ok_func
= (FileselOKFunc
)g_object_get_data (G_OBJECT (filesel
), "ok-func");
135 gpointer data
= g_object_get_data (G_OBJECT (filesel
), "ok-data");
136 gint
*result
= g_object_get_data (G_OBJECT (filesel
), "ok-result");
138 gtk_widget_hide (filesel
);
140 if ((*ok_func
) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel
)), data
))
142 gtk_widget_destroy (filesel
);
146 gtk_widget_show (filesel
);
150 filesel_run (GtkWindow
*parent
,
152 const char *start_file
,
156 GtkWidget
*filesel
= gtk_file_selection_new (title
);
157 gboolean result
= FALSE
;
160 parent
= get_active_window ();
163 gtk_window_set_transient_for (GTK_WINDOW (filesel
), parent
);
166 gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel
), start_file
);
169 g_object_set_data (G_OBJECT (filesel
), "ok-func", func
);
170 g_object_set_data (G_OBJECT (filesel
), "ok-data", data
);
171 g_object_set_data (G_OBJECT (filesel
), "ok-result", &result
);
173 g_signal_connect (GTK_FILE_SELECTION (filesel
)->ok_button
,
175 G_CALLBACK (filesel_ok_cb
), filesel
);
176 g_signal_connect_swapped (GTK_FILE_SELECTION (filesel
)->cancel_button
,
178 G_CALLBACK (gtk_widget_destroy
), filesel
);
180 g_signal_connect (filesel
, "destroy",
181 G_CALLBACK (gtk_main_quit
), NULL
);
182 gtk_window_set_modal (GTK_WINDOW (filesel
), TRUE
);
184 gtk_widget_show (filesel
);
191 * MsgBox utility functions
195 msgbox_yes_cb (GtkWidget
*widget
, gboolean
*result
)
198 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget
)));
202 msgbox_no_cb (GtkWidget
*widget
, gboolean
*result
)
205 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget
)));
209 msgbox_key_press_cb (GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
211 if (event
->keyval
== GDK_Escape
)
213 g_signal_stop_emission_by_name (widget
, "key_press_event");
214 gtk_object_destroy (GTK_OBJECT (widget
));
221 /* Don't copy this example, it's all crack-smoking - you can just use
222 * GtkMessageDialog now
225 msgbox_run (GtkWindow
*parent
,
227 const char *yes_button
,
228 const char *no_button
,
229 const char *cancel_button
,
232 gboolean result
= -1;
237 GtkWidget
*button_box
;
238 GtkWidget
*separator
;
240 g_return_val_if_fail (message
!= NULL
, FALSE
);
241 g_return_val_if_fail (default_index
>= 0 && default_index
<= 1, FALSE
);
244 parent
= get_active_window ();
248 dialog
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
249 gtk_window_set_modal (GTK_WINDOW (dialog
), TRUE
);
251 gtk_window_set_transient_for (GTK_WINDOW (dialog
), parent
);
252 gtk_window_set_position (GTK_WINDOW (dialog
), GTK_WIN_POS_MOUSE
);
254 /* Quit our recursive main loop when the dialog is destroyed.
256 g_signal_connect (dialog
, "destroy",
257 G_CALLBACK (gtk_main_quit
), NULL
);
259 /* Catch Escape key presses and have them destroy the dialog
261 g_signal_connect (dialog
, "key_press_event",
262 G_CALLBACK (msgbox_key_press_cb
), NULL
);
264 /* Fill in the contents of the widget
266 vbox
= gtk_vbox_new (FALSE
, 0);
267 gtk_container_add (GTK_CONTAINER (dialog
), vbox
);
269 label
= gtk_label_new (message
);
270 gtk_misc_set_padding (GTK_MISC (label
), 12, 12);
271 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
272 gtk_box_pack_start (GTK_BOX (vbox
), label
, TRUE
, TRUE
, 0);
274 separator
= gtk_hseparator_new ();
275 gtk_box_pack_start (GTK_BOX (vbox
), separator
, FALSE
, FALSE
, 0);
277 button_box
= gtk_hbutton_box_new ();
278 gtk_box_pack_start (GTK_BOX (vbox
), button_box
, FALSE
, FALSE
, 0);
279 gtk_container_set_border_width (GTK_CONTAINER (button_box
), 8);
282 /* When Yes is clicked, call the msgbox_yes_cb
283 * This sets the result variable and destroys the dialog
287 button
= gtk_button_new_with_label (yes_button
);
288 GTK_WIDGET_SET_FLAGS (button
, GTK_CAN_DEFAULT
);
289 gtk_container_add (GTK_CONTAINER (button_box
), button
);
291 if (default_index
== 0)
292 gtk_widget_grab_default (button
);
294 g_signal_connect (button
, "clicked",
295 G_CALLBACK (msgbox_yes_cb
), &result
);
298 /* When No is clicked, call the msgbox_no_cb
299 * This sets the result variable and destroys the dialog
303 button
= gtk_button_new_with_label (no_button
);
304 GTK_WIDGET_SET_FLAGS (button
, GTK_CAN_DEFAULT
);
305 gtk_container_add (GTK_CONTAINER (button_box
), button
);
307 if (default_index
== 0)
308 gtk_widget_grab_default (button
);
310 g_signal_connect (button
, "clicked",
311 G_CALLBACK (msgbox_no_cb
), &result
);
314 /* When Cancel is clicked, destroy the dialog
318 button
= gtk_button_new_with_label (cancel_button
);
319 GTK_WIDGET_SET_FLAGS (button
, GTK_CAN_DEFAULT
);
320 gtk_container_add (GTK_CONTAINER (button_box
), button
);
322 if (default_index
== 1)
323 gtk_widget_grab_default (button
);
325 g_signal_connect_swapped (button
, "clicked",
326 G_CALLBACK (gtk_object_destroy
), dialog
);
329 gtk_widget_show_all (dialog
);
331 /* Run a recursive main loop until a button is clicked
332 * or the user destroys the dialog through the window mananger */
340 * Example buffer filling code
343 blink_timeout (gpointer data
)
346 static gboolean flip
= FALSE
;
348 tag
= GTK_TEXT_TAG (data
);
351 "foreground", flip
? "blue" : "purple",
361 tag_event_handler (GtkTextTag
*tag
, GtkWidget
*widget
, GdkEvent
*event
,
362 const GtkTextIter
*iter
, gpointer user_data
)
366 char_index
= gtk_text_iter_get_offset (iter
);
370 case GDK_MOTION_NOTIFY
:
371 printf ("Motion event at char %d tag `%s'\n",
372 char_index
, tag
->name
);
375 case GDK_BUTTON_PRESS
:
376 printf ("Button press at char %d tag `%s'\n",
377 char_index
, tag
->name
);
380 case GDK_2BUTTON_PRESS
:
381 printf ("Double click at char %d tag `%s'\n",
382 char_index
, tag
->name
);
385 case GDK_3BUTTON_PRESS
:
386 printf ("Triple click at char %d tag `%s'\n",
387 char_index
, tag
->name
);
390 case GDK_BUTTON_RELEASE
:
391 printf ("Button release at char %d tag `%s'\n",
392 char_index
, tag
->name
);
396 case GDK_KEY_RELEASE
:
397 printf ("Key event at char %d tag `%s'\n",
398 char_index
, tag
->name
);
401 case GDK_ENTER_NOTIFY
:
402 case GDK_LEAVE_NOTIFY
:
403 case GDK_PROPERTY_NOTIFY
:
404 case GDK_SELECTION_CLEAR
:
405 case GDK_SELECTION_REQUEST
:
406 case GDK_SELECTION_NOTIFY
:
407 case GDK_PROXIMITY_IN
:
408 case GDK_PROXIMITY_OUT
:
411 case GDK_DRAG_MOTION
:
412 case GDK_DRAG_STATUS
:
414 case GDK_DROP_FINISHED
:
423 setup_tag (GtkTextTag
*tag
)
425 g_signal_connect (tag
,
427 G_CALLBACK (tag_event_handler
),
431 static const char *book_closed_xpm
[] = {
457 fill_example_buffer (GtkTextBuffer
*buffer
)
459 GtkTextIter iter
, iter2
;
461 GtkTextChildAnchor
*anchor
;
468 /* FIXME this is broken if called twice on a buffer, since
469 * we try to create tags a second time.
472 tag
= gtk_text_buffer_create_tag (buffer
, "fg_blue", NULL
);
475 gtk_timeout_add (1000, blink_timeout
, tag
);
480 color
.red
= color
.green
= 0;
486 "foreground_gdk", &color
,
487 "background_gdk", &color2
,
491 tag
= gtk_text_buffer_create_tag (buffer
, "fg_red", NULL
);
495 color
.blue
= color
.green
= 0;
498 "rise", -4 * PANGO_SCALE
,
499 "foreground_gdk", &color
,
502 tag
= gtk_text_buffer_create_tag (buffer
, "bg_green", NULL
);
506 color
.blue
= color
.red
= 0;
507 color
.green
= 0xffff;
509 "background_gdk", &color
,
513 tag
= gtk_text_buffer_create_tag (buffer
, "strikethrough", NULL
);
518 "strikethrough", TRUE
,
522 tag
= gtk_text_buffer_create_tag (buffer
, "underline", NULL
);
527 "underline", PANGO_UNDERLINE_SINGLE
,
530 tag
= gtk_text_buffer_create_tag (buffer
, "underline_error", NULL
);
535 "underline", PANGO_UNDERLINE_ERROR
,
538 tag
= gtk_text_buffer_create_tag (buffer
, "centered", NULL
);
541 "justification", GTK_JUSTIFY_CENTER
,
544 tag
= gtk_text_buffer_create_tag (buffer
, "rtl_quote", NULL
);
547 "wrap_mode", GTK_WRAP_WORD
,
548 "direction", GTK_TEXT_DIR_RTL
,
555 tag
= gtk_text_buffer_create_tag (buffer
, "negative_indent", NULL
);
561 gtk_text_buffer_get_iter_at_offset (buffer
, &iter
, 0);
563 anchor
= gtk_text_buffer_create_child_anchor (buffer
, &iter
);
565 g_object_ref (anchor
);
567 g_object_set_data_full (G_OBJECT (buffer
), "anchor", anchor
,
568 (GDestroyNotify
) g_object_unref
);
570 pixbuf
= gdk_pixbuf_new_from_xpm_data (book_closed_xpm
);
575 GtkTextMark
* temp_mark
;
577 gtk_text_buffer_get_iter_at_offset (buffer
, &iter
, 0);
579 gtk_text_buffer_insert_pixbuf (buffer
, &iter
, pixbuf
);
581 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",
584 gtk_text_buffer_insert (buffer
, &iter
, str
, -1);
588 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter
, 0, 5);
590 gtk_text_buffer_insert (buffer
, &iter
,
591 "(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"
592 /* This is UTF8 stuff, Emacs doesn't
593 really know how to display it */
594 "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);
597 gtk_text_buffer_create_mark (buffer
, "tmp_mark", &iter
, TRUE
);
600 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter
, 0, 6);
601 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter2
, 0, 13);
603 gtk_text_buffer_apply_tag_by_name (buffer
, "fg_blue", &iter
, &iter2
);
605 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter
, 1, 10);
606 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter2
, 1, 16);
608 gtk_text_buffer_apply_tag_by_name (buffer
, "underline", &iter
, &iter2
);
610 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter
, 1, 4);
611 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter2
, 1, 7);
613 gtk_text_buffer_apply_tag_by_name (buffer
, "underline_error", &iter
, &iter2
);
615 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter
, 1, 14);
616 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter2
, 1, 24);
618 gtk_text_buffer_apply_tag_by_name (buffer
, "strikethrough", &iter
, &iter2
);
620 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter
, 0, 9);
621 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter2
, 0, 16);
623 gtk_text_buffer_apply_tag_by_name (buffer
, "bg_green", &iter
, &iter2
);
625 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter
, 4, 2);
626 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter2
, 4, 10);
628 gtk_text_buffer_apply_tag_by_name (buffer
, "bg_green", &iter
, &iter2
);
630 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter
, 4, 8);
631 gtk_text_buffer_get_iter_at_line_offset (buffer
, &iter2
, 4, 15);
633 gtk_text_buffer_apply_tag_by_name (buffer
, "fg_red", &iter
, &iter2
);
636 gtk_text_buffer_get_iter_at_mark (buffer
, &iter
, temp_mark
);
637 gtk_text_buffer_insert (buffer
, &iter
, "Centered text!\n", -1);
639 gtk_text_buffer_get_iter_at_mark (buffer
, &iter2
, temp_mark
);
640 gtk_text_buffer_apply_tag_by_name (buffer
, "centered", &iter2
, &iter
);
642 gtk_text_buffer_move_mark (buffer
, temp_mark
, &iter
);
643 gtk_text_buffer_insert (buffer
, &iter
, "Word wrapped, Right-to-left Quote\n", -1);
644 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);
645 gtk_text_buffer_get_iter_at_mark (buffer
, &iter2
, temp_mark
);
646 gtk_text_buffer_apply_tag_by_name (buffer
, "rtl_quote", &iter2
, &iter
);
648 gtk_text_buffer_insert_with_tags (buffer
, &iter
,
649 "Paragraph with negative indentation. blah blah blah blah blah. The quick brown fox jumped over the lazy dog.\n",
651 gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (buffer
),
658 g_object_unref (pixbuf
);
660 printf ("%d lines %d chars\n",
661 gtk_text_buffer_get_line_count (buffer
),
662 gtk_text_buffer_get_char_count (buffer
));
664 /* Move cursor to start */
665 gtk_text_buffer_get_iter_at_offset (buffer
, &iter
, 0);
666 gtk_text_buffer_place_cursor (buffer
, &iter
);
668 gtk_text_buffer_set_modified (buffer
, FALSE
);
672 fill_file_buffer (GtkTextBuffer
*buffer
, const char *filename
)
677 GtkTextIter iter
, end
;
679 f
= fopen (filename
, "r");
683 gchar
*err
= g_strdup_printf ("Cannot open file '%s': %s",
684 filename
, g_strerror (errno
));
685 msgbox_run (NULL
, err
, "OK", NULL
, NULL
, 0);
690 gtk_text_buffer_get_iter_at_offset (buffer
, &iter
, 0);
694 const char *leftover
;
695 int to_read
= 2047 - remaining
;
697 count
= fread (buf
+ remaining
, 1, to_read
, f
);
698 buf
[count
+ remaining
] = '\0';
700 g_utf8_validate (buf
, count
+ remaining
, &leftover
);
702 g_assert (g_utf8_validate (buf
, leftover
- buf
, NULL
));
703 gtk_text_buffer_insert (buffer
, &iter
, buf
, leftover
- buf
);
705 remaining
= (buf
+ remaining
+ count
) - leftover
;
706 g_memmove (buf
, leftover
, remaining
);
708 if (remaining
> 6 || count
< to_read
)
714 gchar
*err
= g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename
);
715 msgbox_run (NULL
, err
, "OK", NULL
, NULL
, 0);
719 /* We had a newline in the buffer to begin with. (The buffer always contains
720 * a newline, so we delete to the end of the buffer to clean up.
722 gtk_text_buffer_get_end_iter (buffer
, &end
);
723 gtk_text_buffer_delete (buffer
, &iter
, &end
);
725 gtk_text_buffer_set_modified (buffer
, FALSE
);
731 delete_event_cb (GtkWidget
*window
, GdkEventAny
*event
, gpointer data
)
733 View
*view
= view_from_widget (window
);
735 push_active_window (GTK_WINDOW (window
));
736 check_close_view (view
);
737 pop_active_window ();
747 get_empty_view (View
*view
)
749 if (!view
->buffer
->filename
&&
750 !gtk_text_buffer_get_modified (view
->buffer
->buffer
))
753 return create_view (create_buffer ());
757 view_from_widget (GtkWidget
*widget
)
759 if (GTK_IS_MENU_ITEM (widget
))
761 GtkItemFactory
*item_factory
= gtk_item_factory_from_widget (widget
);
762 return g_object_get_data (G_OBJECT (item_factory
), "view");
766 GtkWidget
*app
= gtk_widget_get_toplevel (widget
);
767 return g_object_get_data (G_OBJECT (app
), "view");
772 do_new (gpointer callback_data
,
773 guint callback_action
,
776 create_view (create_buffer ());
780 do_new_view (gpointer callback_data
,
781 guint callback_action
,
784 View
*view
= view_from_widget (widget
);
786 create_view (view
->buffer
);
790 open_ok_func (const char *filename
, gpointer data
)
793 View
*new_view
= get_empty_view (view
);
795 if (!fill_file_buffer (new_view
->buffer
->buffer
, filename
))
797 if (new_view
!= view
)
798 close_view (new_view
);
803 g_free (new_view
->buffer
->filename
);
804 new_view
->buffer
->filename
= g_strdup (filename
);
805 buffer_filename_set (new_view
->buffer
);
812 do_open (gpointer callback_data
,
813 guint callback_action
,
816 View
*view
= view_from_widget (widget
);
818 push_active_window (GTK_WINDOW (view
->window
));
819 filesel_run (NULL
, "Open File", NULL
, open_ok_func
, view
);
820 pop_active_window ();
824 do_save_as (gpointer callback_data
,
825 guint callback_action
,
828 View
*view
= view_from_widget (widget
);
830 push_active_window (GTK_WINDOW (view
->window
));
831 save_as_buffer (view
->buffer
);
832 pop_active_window ();
836 do_save (gpointer callback_data
,
837 guint callback_action
,
840 View
*view
= view_from_widget (widget
);
842 push_active_window (GTK_WINDOW (view
->window
));
843 if (!view
->buffer
->filename
)
844 do_save_as (callback_data
, callback_action
, widget
);
846 save_buffer (view
->buffer
);
847 pop_active_window ();
851 do_close (gpointer callback_data
,
852 guint callback_action
,
855 View
*view
= view_from_widget (widget
);
857 push_active_window (GTK_WINDOW (view
->window
));
858 check_close_view (view
);
859 pop_active_window ();
863 do_exit (gpointer callback_data
,
864 guint callback_action
,
867 View
*view
= view_from_widget (widget
);
869 GSList
*tmp_list
= buffers
;
871 push_active_window (GTK_WINDOW (view
->window
));
874 if (!check_buffer_saved (tmp_list
->data
))
877 tmp_list
= tmp_list
->next
;
881 pop_active_window ();
885 do_example (gpointer callback_data
,
886 guint callback_action
,
889 View
*view
= view_from_widget (widget
);
892 new_view
= get_empty_view (view
);
894 fill_example_buffer (new_view
->buffer
->buffer
);
896 view_add_example_widgets (new_view
);
901 do_insert_and_scroll (gpointer callback_data
,
902 guint callback_action
,
905 View
*view
= view_from_widget (widget
);
906 GtkTextBuffer
*buffer
;
907 GtkTextIter start
, end
;
910 buffer
= view
->buffer
->buffer
;
912 gtk_text_buffer_get_bounds (buffer
, &start
, &end
);
913 mark
= gtk_text_buffer_create_mark (buffer
, NULL
, &end
, /* right grav */ FALSE
);
915 gtk_text_buffer_insert (buffer
, &end
,
916 "Hello this is multiple lines of text\n"
917 "Line 1\n" "Line 2\n"
918 "Line 3\n" "Line 4\n"
922 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view
->text_view
), mark
,
924 gtk_text_buffer_delete_mark (buffer
, mark
);
928 do_wrap_changed (gpointer callback_data
,
929 guint callback_action
,
932 View
*view
= view_from_widget (widget
);
934 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view
->text_view
), callback_action
);
938 do_direction_changed (gpointer callback_data
,
939 guint callback_action
,
942 View
*view
= view_from_widget (widget
);
944 gtk_widget_set_direction (view
->text_view
, callback_action
);
945 gtk_widget_queue_resize (view
->text_view
);
950 do_spacing_changed (gpointer callback_data
,
951 guint callback_action
,
954 View
*view
= view_from_widget (widget
);
958 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view
->text_view
),
960 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view
->text_view
),
962 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view
->text_view
),
967 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view
->text_view
),
969 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view
->text_view
),
971 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view
->text_view
),
977 do_editable_changed (gpointer callback_data
,
978 guint callback_action
,
981 View
*view
= view_from_widget (widget
);
983 gtk_text_view_set_editable (GTK_TEXT_VIEW (view
->text_view
), callback_action
);
987 change_cursor_color (GtkWidget
*widget
,
992 GdkColor red
= {0, 65535, 0, 0};
993 gtk_widget_modify_cursor (widget
, &red
, &red
);
996 gtk_widget_modify_cursor (widget
, NULL
, NULL
);
1000 do_cursor_visible_changed (gpointer callback_data
,
1001 guint callback_action
,
1004 View
*view
= view_from_widget (widget
);
1006 switch (callback_action
)
1009 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view
->text_view
), FALSE
);
1012 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view
->text_view
), TRUE
);
1013 change_cursor_color (view
->text_view
, FALSE
);
1016 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view
->text_view
), TRUE
);
1017 change_cursor_color (view
->text_view
, TRUE
);
1023 do_color_cycle_changed (gpointer callback_data
,
1024 guint callback_action
,
1027 View
*view
= view_from_widget (widget
);
1029 buffer_set_colors (view
->buffer
, callback_action
);
1033 do_apply_editable (gpointer callback_data
,
1034 guint callback_action
,
1037 View
*view
= view_from_widget (widget
);
1041 if (gtk_text_buffer_get_selection_bounds (view
->buffer
->buffer
,
1044 if (callback_action
)
1046 gtk_text_buffer_remove_tag (view
->buffer
->buffer
,
1047 view
->buffer
->not_editable_tag
,
1052 gtk_text_buffer_apply_tag (view
->buffer
->buffer
,
1053 view
->buffer
->not_editable_tag
,
1060 do_apply_invisible (gpointer callback_data
,
1061 guint callback_action
,
1064 View
*view
= view_from_widget (widget
);
1068 if (gtk_text_buffer_get_selection_bounds (view
->buffer
->buffer
,
1071 if (callback_action
)
1073 gtk_text_buffer_remove_tag (view
->buffer
->buffer
,
1074 view
->buffer
->invisible_tag
,
1079 gtk_text_buffer_apply_tag (view
->buffer
->buffer
,
1080 view
->buffer
->invisible_tag
,
1087 do_apply_rise (gpointer callback_data
,
1088 guint callback_action
,
1091 View
*view
= view_from_widget (widget
);
1095 if (gtk_text_buffer_get_selection_bounds (view
->buffer
->buffer
,
1098 if (callback_action
)
1100 gtk_text_buffer_remove_tag (view
->buffer
->buffer
,
1101 view
->buffer
->rise_tag
,
1106 gtk_text_buffer_apply_tag (view
->buffer
->buffer
,
1107 view
->buffer
->rise_tag
,
1114 do_apply_large (gpointer callback_data
,
1115 guint callback_action
,
1118 View
*view
= view_from_widget (widget
);
1122 if (gtk_text_buffer_get_selection_bounds (view
->buffer
->buffer
,
1125 if (callback_action
)
1127 gtk_text_buffer_remove_tag (view
->buffer
->buffer
,
1128 view
->buffer
->large_tag
,
1133 gtk_text_buffer_apply_tag (view
->buffer
->buffer
,
1134 view
->buffer
->large_tag
,
1141 do_apply_indent (gpointer callback_data
,
1142 guint callback_action
,
1145 View
*view
= view_from_widget (widget
);
1149 if (gtk_text_buffer_get_selection_bounds (view
->buffer
->buffer
,
1152 if (callback_action
)
1154 gtk_text_buffer_remove_tag (view
->buffer
->buffer
,
1155 view
->buffer
->indent_tag
,
1160 gtk_text_buffer_apply_tag (view
->buffer
->buffer
,
1161 view
->buffer
->indent_tag
,
1168 do_apply_margin (gpointer callback_data
,
1169 guint callback_action
,
1172 View
*view
= view_from_widget (widget
);
1176 if (gtk_text_buffer_get_selection_bounds (view
->buffer
->buffer
,
1179 if (callback_action
)
1181 gtk_text_buffer_remove_tag (view
->buffer
->buffer
,
1182 view
->buffer
->margin_tag
,
1187 gtk_text_buffer_apply_tag (view
->buffer
->buffer
,
1188 view
->buffer
->margin_tag
,
1195 do_apply_tabs (gpointer callback_data
,
1196 guint callback_action
,
1199 View
*view
= view_from_widget (widget
);
1203 if (gtk_text_buffer_get_selection_bounds (view
->buffer
->buffer
,
1206 if (callback_action
)
1208 gtk_text_buffer_remove_tag (view
->buffer
->buffer
,
1209 view
->buffer
->custom_tabs_tag
,
1214 gtk_text_buffer_apply_tag (view
->buffer
->buffer
,
1215 view
->buffer
->custom_tabs_tag
,
1222 do_apply_colors (gpointer callback_data
,
1223 guint callback_action
,
1226 View
*view
= view_from_widget (widget
);
1227 Buffer
*buffer
= view
->buffer
;
1231 if (gtk_text_buffer_get_selection_bounds (view
->buffer
->buffer
,
1234 if (!callback_action
)
1238 tmp
= buffer
->color_tags
;
1241 gtk_text_buffer_remove_tag (view
->buffer
->buffer
,
1244 tmp
= g_slist_next (tmp
);
1251 tmp
= buffer
->color_tags
;
1255 gboolean done
= FALSE
;
1258 gtk_text_iter_forward_char (&next
);
1259 gtk_text_iter_forward_char (&next
);
1261 if (gtk_text_iter_compare (&next
, &end
) >= 0)
1267 gtk_text_buffer_apply_tag (view
->buffer
->buffer
,
1276 tmp
= g_slist_next (tmp
);
1278 tmp
= buffer
->color_tags
;
1285 do_remove_tags (gpointer callback_data
,
1286 guint callback_action
,
1289 View
*view
= view_from_widget (widget
);
1293 if (gtk_text_buffer_get_selection_bounds (view
->buffer
->buffer
,
1296 gtk_text_buffer_remove_all_tags (view
->buffer
->buffer
,
1302 do_properties (gpointer callback_data
,
1303 guint callback_action
,
1306 View
*view
= view_from_widget (widget
);
1308 create_prop_editor (G_OBJECT (view
->text_view
), 0);
1312 rich_text_store_populate (GtkListStore
*store
,
1313 GtkTextBuffer
*buffer
,
1314 gboolean deserialize
)
1320 gtk_list_store_clear (store
);
1323 formats
= gtk_text_buffer_get_deserialize_formats (buffer
, &n_formats
);
1325 formats
= gtk_text_buffer_get_serialize_formats (buffer
, &n_formats
);
1327 for (i
= 0; i
< n_formats
; i
++)
1331 gboolean can_create_tags
= FALSE
;
1333 mime_type
= gdk_atom_name (formats
[i
]);
1337 gtk_text_buffer_deserialize_get_can_create_tags (buffer
, formats
[i
]);
1339 gtk_list_store_append (store
, &iter
);
1340 gtk_list_store_set (store
, &iter
,
1353 rich_text_paste_target_list_notify (GtkTextBuffer
*buffer
,
1354 const GParamSpec
*pspec
,
1355 GtkListStore
*store
)
1357 rich_text_store_populate (store
, buffer
, TRUE
);
1361 rich_text_copy_target_list_notify (GtkTextBuffer
*buffer
,
1362 const GParamSpec
*pspec
,
1363 GtkListStore
*store
)
1365 rich_text_store_populate (store
, buffer
, FALSE
);
1369 rich_text_can_create_tags_toggled (GtkCellRendererToggle
*toggle
,
1371 GtkTreeModel
*model
)
1375 if (gtk_tree_model_get_iter_from_string (model
, &iter
, path
))
1377 GtkTextBuffer
*buffer
;
1379 gboolean can_create_tags
;
1381 buffer
= g_object_get_data (G_OBJECT (model
), "buffer");
1383 gtk_tree_model_get (model
, &iter
,
1385 2, &can_create_tags
,
1388 gtk_text_buffer_deserialize_set_can_create_tags (buffer
, format
,
1391 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
1392 2, !can_create_tags
,
1398 rich_text_unregister_clicked (GtkWidget
*button
,
1401 GtkTreeSelection
*sel
= gtk_tree_view_get_selection (tv
);
1402 GtkTreeModel
*model
;
1405 if (gtk_tree_selection_get_selected (sel
, &model
, &iter
))
1407 GtkTextBuffer
*buffer
;
1408 gboolean deserialize
;
1411 buffer
= g_object_get_data (G_OBJECT (model
), "buffer");
1412 deserialize
= GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model
),
1415 gtk_tree_model_get (model
, &iter
,
1420 gtk_text_buffer_unregister_deserialize_format (buffer
, format
);
1422 gtk_text_buffer_unregister_serialize_format (buffer
, format
);
1427 rich_text_register_clicked (GtkWidget
*button
,
1434 dialog
= gtk_dialog_new_with_buttons ("Register new Tagset",
1435 GTK_WINDOW (gtk_widget_get_toplevel (button
)),
1436 GTK_DIALOG_DESTROY_WITH_PARENT
,
1437 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
1438 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
1440 label
= gtk_label_new ("Enter tagset name or leave blank for "
1441 "unrestricted internal format:");
1442 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog
)->vbox
), label
,
1445 entry
= gtk_entry_new ();
1446 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog
)->vbox
), entry
,
1449 gtk_widget_show_all (dialog
);
1451 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_OK
)
1453 GtkTreeModel
*model
= gtk_tree_view_get_model (tv
);
1454 GtkTextBuffer
*buffer
= g_object_get_data (G_OBJECT (model
), "buffer");
1455 const gchar
*tagset
= gtk_entry_get_text (GTK_ENTRY (entry
));
1456 gboolean deserialize
;
1458 deserialize
= GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model
),
1461 if (tagset
&& ! strlen (tagset
))
1465 gtk_text_buffer_register_deserialize_tagset (buffer
, tagset
);
1467 gtk_text_buffer_register_serialize_tagset (buffer
, tagset
);
1470 gtk_widget_destroy (dialog
);
1474 do_rich_text (gpointer callback_data
,
1478 View
*view
= view_from_widget (widget
);
1479 GtkTextBuffer
*buffer
;
1485 GtkListStore
*store
;
1487 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (view
->text_view
));
1489 dialog
= gtk_dialog_new_with_buttons (deserialize
?
1490 "Rich Text Paste & Drop" :
1491 "Rich Text Copy & Drag",
1492 GTK_WINDOW (view
->window
),
1493 GTK_DIALOG_DESTROY_WITH_PARENT
,
1496 g_signal_connect (dialog
, "response",
1497 G_CALLBACK (gtk_widget_destroy
),
1500 store
= gtk_list_store_new (3,
1505 g_object_set_data (G_OBJECT (store
), "buffer", buffer
);
1506 g_object_set_data (G_OBJECT (store
), "deserialize",
1507 GUINT_TO_POINTER (deserialize
));
1509 tv
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (store
));
1510 g_object_unref (store
);
1512 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv
),
1513 0, "Rich Text Format",
1514 gtk_cell_renderer_text_new (),
1520 GtkCellRenderer
*renderer
= gtk_cell_renderer_toggle_new ();
1522 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv
),
1523 1, "Can Create Tags",
1528 g_signal_connect (renderer
, "toggled",
1529 G_CALLBACK (rich_text_can_create_tags_toggled
),
1533 sw
= gtk_scrolled_window_new (NULL
, NULL
);
1534 gtk_widget_set_size_request (sw
, 300, 100);
1535 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog
)->vbox
), sw
);
1537 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw
), tv
);
1539 hbox
= gtk_hbox_new (FALSE
, 6);
1540 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog
)->vbox
), hbox
,
1543 button
= gtk_button_new_with_label ("Unregister Selected Format");
1544 gtk_box_pack_start (GTK_BOX (hbox
), button
, FALSE
, FALSE
, 0);
1546 g_signal_connect (button
, "clicked",
1547 G_CALLBACK (rich_text_unregister_clicked
),
1550 button
= gtk_button_new_with_label ("Register New Tagset\n"
1551 "for the Internal Format");
1552 gtk_box_pack_start (GTK_BOX (hbox
), button
, FALSE
, FALSE
, 0);
1554 g_signal_connect (button
, "clicked",
1555 G_CALLBACK (rich_text_register_clicked
),
1559 g_signal_connect_object (buffer
, "notify::paste-target-list",
1560 G_CALLBACK (rich_text_paste_target_list_notify
),
1561 G_OBJECT (store
), 0);
1563 g_signal_connect_object (buffer
, "notify::copy-target-list",
1564 G_CALLBACK (rich_text_copy_target_list_notify
),
1565 G_OBJECT (store
), 0);
1567 rich_text_store_populate (store
, buffer
, deserialize
);
1569 gtk_widget_show_all (dialog
);
1579 dialog_response_callback (GtkWidget
*dialog
, gint response_id
, gpointer data
)
1581 GtkTextBuffer
*buffer
;
1583 GtkTextIter start
, end
;
1584 gchar
*search_string
;
1586 if (response_id
!= RESPONSE_FORWARD
&&
1587 response_id
!= RESPONSE_BACKWARD
)
1589 gtk_widget_destroy (dialog
);
1593 buffer
= g_object_get_data (G_OBJECT (dialog
), "buffer");
1595 gtk_text_buffer_get_bounds (buffer
, &start
, &end
);
1597 search_string
= gtk_text_iter_get_text (&start
, &end
);
1599 g_print ("Searching for `%s'\n", search_string
);
1601 if (response_id
== RESPONSE_FORWARD
)
1602 buffer_search_forward (view
->buffer
, search_string
, view
);
1603 else if (response_id
== RESPONSE_BACKWARD
)
1604 buffer_search_backward (view
->buffer
, search_string
, view
);
1606 g_free (search_string
);
1608 gtk_widget_destroy (dialog
);
1612 do_copy (gpointer callback_data
,
1613 guint callback_action
,
1616 View
*view
= view_from_widget (widget
);
1617 GtkTextBuffer
*buffer
;
1619 buffer
= view
->buffer
->buffer
;
1621 gtk_text_buffer_copy_clipboard (buffer
,
1622 gtk_clipboard_get (GDK_NONE
));
1626 do_search (gpointer callback_data
,
1627 guint callback_action
,
1630 View
*view
= view_from_widget (widget
);
1632 GtkWidget
*search_text
;
1633 GtkTextBuffer
*buffer
;
1635 dialog
= gtk_dialog_new_with_buttons ("Search",
1636 GTK_WINDOW (view
->window
),
1637 GTK_DIALOG_DESTROY_WITH_PARENT
,
1638 "Forward", RESPONSE_FORWARD
,
1639 "Backward", RESPONSE_BACKWARD
,
1641 GTK_RESPONSE_NONE
, NULL
);
1644 buffer
= gtk_text_buffer_new (NULL
);
1646 search_text
= gtk_text_view_new_with_buffer (buffer
);
1648 g_object_unref (buffer
);
1650 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog
)->vbox
),
1654 g_object_set_data (G_OBJECT (dialog
), "buffer", buffer
);
1656 g_signal_connect (dialog
,
1658 G_CALLBACK (dialog_response_callback
),
1661 gtk_widget_show (search_text
);
1663 gtk_widget_grab_focus (search_text
);
1665 gtk_widget_show_all (dialog
);
1669 do_select_all (gpointer callback_data
,
1670 guint callback_action
,
1673 View
*view
= view_from_widget (widget
);
1674 GtkTextBuffer
*buffer
;
1675 GtkTextIter start
, end
;
1677 buffer
= view
->buffer
->buffer
;
1679 gtk_text_buffer_get_bounds (buffer
, &start
, &end
);
1680 gtk_text_buffer_select_range (buffer
, &start
, &end
);
1685 /* position is in coordinate system of text_view_move_child */
1694 movable_child_callback (GtkWidget
*child
,
1698 ChildMoveInfo
*info
;
1699 GtkTextView
*text_view
;
1701 text_view
= GTK_TEXT_VIEW (data
);
1703 g_return_val_if_fail (GTK_IS_EVENT_BOX (child
), FALSE
);
1704 g_return_val_if_fail (gtk_widget_get_parent (child
) == GTK_WIDGET (text_view
), FALSE
);
1706 info
= g_object_get_data (G_OBJECT (child
),
1707 "testtext-move-info");
1711 info
= g_new (ChildMoveInfo
, 1);
1715 g_object_set_data_full (G_OBJECT (child
),
1716 "testtext-move-info",
1721 switch (event
->type
)
1723 case GDK_BUTTON_PRESS
:
1724 if (info
->button
< 0)
1726 if (gdk_pointer_grab (event
->button
.window
,
1728 GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
|
1729 GDK_BUTTON_RELEASE_MASK
,
1732 event
->button
.time
) != GDK_GRAB_SUCCESS
)
1735 info
->button
= event
->button
.button
;
1737 info
->start_x
= child
->allocation
.x
;
1738 info
->start_y
= child
->allocation
.y
;
1739 info
->click_x
= child
->allocation
.x
+ event
->button
.x
;
1740 info
->click_y
= child
->allocation
.y
+ event
->button
.y
;
1744 case GDK_BUTTON_RELEASE
:
1745 if (info
->button
< 0)
1748 if (info
->button
== event
->button
.button
)
1752 gdk_pointer_ungrab (event
->button
.time
);
1755 /* convert to window coords from event box coords */
1756 x
= info
->start_x
+ (event
->button
.x
+ child
->allocation
.x
- info
->click_x
);
1757 y
= info
->start_y
+ (event
->button
.y
+ child
->allocation
.y
- info
->click_y
);
1759 gtk_text_view_move_child (text_view
,
1765 case GDK_MOTION_NOTIFY
:
1769 if (info
->button
< 0)
1772 gdk_window_get_pointer (child
->window
, &x
, &y
, NULL
); /* ensure more events */
1774 /* to window coords from event box coords */
1775 x
+= child
->allocation
.x
;
1776 y
+= child
->allocation
.y
;
1778 x
= info
->start_x
+ (x
- info
->click_x
);
1779 y
= info
->start_y
+ (y
- info
->click_y
);
1781 gtk_text_view_move_child (text_view
,
1795 add_movable_child (GtkTextView
*text_view
,
1796 GtkTextWindowType window
)
1798 GtkWidget
*event_box
;
1802 label
= gtk_label_new ("Drag me around");
1804 event_box
= gtk_event_box_new ();
1805 gtk_widget_add_events (event_box
,
1806 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
1807 GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
);
1810 color
.green
= color
.blue
= 0;
1811 gtk_widget_modify_bg (event_box
, GTK_STATE_NORMAL
, &color
);
1813 gtk_container_add (GTK_CONTAINER (event_box
), label
);
1815 gtk_widget_show_all (event_box
);
1817 g_signal_connect (event_box
, "event",
1818 G_CALLBACK (movable_child_callback
),
1821 gtk_text_view_add_child_in_window (text_view
,
1828 do_add_children (gpointer callback_data
,
1829 guint callback_action
,
1832 View
*view
= view_from_widget (widget
);
1834 add_movable_child (GTK_TEXT_VIEW (view
->text_view
),
1835 GTK_TEXT_WINDOW_WIDGET
);
1836 add_movable_child (GTK_TEXT_VIEW (view
->text_view
),
1837 GTK_TEXT_WINDOW_LEFT
);
1838 add_movable_child (GTK_TEXT_VIEW (view
->text_view
),
1839 GTK_TEXT_WINDOW_RIGHT
);
1843 do_add_focus_children (gpointer callback_data
,
1844 guint callback_action
,
1847 View
*view
= view_from_widget (widget
);
1849 GtkTextChildAnchor
*anchor
;
1851 GtkTextView
*text_view
;
1853 text_view
= GTK_TEXT_VIEW (view
->text_view
);
1855 child
= gtk_button_new_with_mnemonic ("Button _A in widget->window");
1857 gtk_text_view_add_child_in_window (text_view
,
1859 GTK_TEXT_WINDOW_WIDGET
,
1862 child
= gtk_button_new_with_mnemonic ("Button _B in widget->window");
1864 gtk_text_view_add_child_in_window (text_view
,
1866 GTK_TEXT_WINDOW_WIDGET
,
1869 child
= gtk_button_new_with_mnemonic ("Button _C in left window");
1871 gtk_text_view_add_child_in_window (text_view
,
1873 GTK_TEXT_WINDOW_LEFT
,
1876 child
= gtk_button_new_with_mnemonic ("Button _D in right window");
1878 gtk_text_view_add_child_in_window (text_view
,
1880 GTK_TEXT_WINDOW_RIGHT
,
1883 gtk_text_buffer_get_start_iter (view
->buffer
->buffer
, &iter
);
1885 anchor
= gtk_text_buffer_create_child_anchor (view
->buffer
->buffer
, &iter
);
1887 child
= gtk_button_new_with_mnemonic ("Button _E in buffer");
1889 gtk_text_view_add_child_at_anchor (text_view
, child
, anchor
);
1891 anchor
= gtk_text_buffer_create_child_anchor (view
->buffer
->buffer
, &iter
);
1893 child
= gtk_button_new_with_mnemonic ("Button _F in buffer");
1895 gtk_text_view_add_child_at_anchor (text_view
, child
, anchor
);
1897 anchor
= gtk_text_buffer_create_child_anchor (view
->buffer
->buffer
, &iter
);
1899 child
= gtk_button_new_with_mnemonic ("Button _G in buffer");
1901 gtk_text_view_add_child_at_anchor (text_view
, child
, anchor
);
1903 /* show all the buttons */
1904 gtk_widget_show_all (view
->text_view
);
1908 view_init_menus (View
*view
)
1910 GtkTextDirection direction
= gtk_widget_get_direction (view
->text_view
);
1911 GtkWrapMode wrap_mode
= gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view
->text_view
));
1912 GtkWidget
*menu_item
= NULL
;
1916 case GTK_TEXT_DIR_LTR
:
1917 menu_item
= gtk_item_factory_get_widget (view
->item_factory
, "/Settings/Left-to-Right");
1919 case GTK_TEXT_DIR_RTL
:
1920 menu_item
= gtk_item_factory_get_widget (view
->item_factory
, "/Settings/Right-to-Left");
1927 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item
));
1932 menu_item
= gtk_item_factory_get_widget (view
->item_factory
, "/Settings/Wrap Off");
1935 menu_item
= gtk_item_factory_get_widget (view
->item_factory
, "/Settings/Wrap Words");
1938 menu_item
= gtk_item_factory_get_widget (view
->item_factory
, "/Settings/Wrap Chars");
1945 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item
));
1948 static GtkItemFactoryEntry menu_items
[] =
1950 { "/_File", NULL
, NULL
, 0, "<Branch>" },
1951 { "/File/_New", "<control>N", do_new
, 0, NULL
},
1952 { "/File/New _View", NULL
, do_new_view
, 0, NULL
},
1953 { "/File/_Open", "<control>O", do_open
, 0, NULL
},
1954 { "/File/_Save", "<control>S", do_save
, 0, NULL
},
1955 { "/File/Save _As...", NULL
, do_save_as
, 0, NULL
},
1956 { "/File/sep1", NULL
, NULL
, 0, "<Separator>" },
1957 { "/File/_Close", "<control>W" , do_close
, 0, NULL
},
1958 { "/File/E_xit", "<control>Q" , do_exit
, 0, NULL
},
1960 { "/_Edit", NULL
, 0, 0, "<Branch>" },
1961 { "/Edit/Copy", NULL
, do_copy
, 0, NULL
},
1962 { "/Edit/sep1", NULL
, NULL
, 0, "<Separator>" },
1963 { "/Edit/Find...", NULL
, do_search
, 0, NULL
},
1964 { "/Edit/Select All", "<control>A", do_select_all
, 0, NULL
},
1966 { "/_Settings", NULL
, NULL
, 0, "<Branch>" },
1967 { "/Settings/Wrap _Off", NULL
, do_wrap_changed
, GTK_WRAP_NONE
, "<RadioItem>" },
1968 { "/Settings/Wrap _Words", NULL
, do_wrap_changed
, GTK_WRAP_WORD
, "/Settings/Wrap Off" },
1969 { "/Settings/Wrap _Chars", NULL
, do_wrap_changed
, GTK_WRAP_CHAR
, "/Settings/Wrap Off" },
1970 { "/Settings/sep1", NULL
, NULL
, 0, "<Separator>" },
1971 { "/Settings/Editable", NULL
, do_editable_changed
, TRUE
, "<RadioItem>" },
1972 { "/Settings/Not editable", NULL
, do_editable_changed
, FALSE
, "/Settings/Editable" },
1973 { "/Settings/sep1", NULL
, NULL
, 0, "<Separator>" },
1975 { "/Settings/Cursor normal", NULL
, do_cursor_visible_changed
, 1, "<RadioItem>" },
1976 { "/Settings/Cursor not visible", NULL
, do_cursor_visible_changed
, 0, "/Settings/Cursor normal" },
1977 { "/Settings/Cursor colored", NULL
, do_cursor_visible_changed
, 2, "/Settings/Cursor normal" },
1978 { "/Settings/sep1", NULL
, NULL
, 0, "<Separator>" },
1980 { "/Settings/Left-to-Right", NULL
, do_direction_changed
, GTK_TEXT_DIR_LTR
, "<RadioItem>" },
1981 { "/Settings/Right-to-Left", NULL
, do_direction_changed
, GTK_TEXT_DIR_RTL
, "/Settings/Left-to-Right" },
1983 { "/Settings/sep1", NULL
, NULL
, 0, "<Separator>" },
1984 { "/Settings/Sane spacing", NULL
, do_spacing_changed
, FALSE
, "<RadioItem>" },
1985 { "/Settings/Funky spacing", NULL
, do_spacing_changed
, TRUE
, "/Settings/Sane spacing" },
1986 { "/Settings/sep1", NULL
, NULL
, 0, "<Separator>" },
1987 { "/Settings/Don't cycle color tags", NULL
, do_color_cycle_changed
, FALSE
, "<RadioItem>" },
1988 { "/Settings/Cycle colors", NULL
, do_color_cycle_changed
, TRUE
, "/Settings/Don't cycle color tags" },
1989 { "/_Attributes", NULL
, NULL
, 0, "<Branch>" },
1990 { "/Attributes/Editable", NULL
, do_apply_editable
, TRUE
, NULL
},
1991 { "/Attributes/Not editable", NULL
, do_apply_editable
, FALSE
, NULL
},
1992 { "/Attributes/Invisible", NULL
, do_apply_invisible
, FALSE
, NULL
},
1993 { "/Attributes/Visible", NULL
, do_apply_invisible
, TRUE
, NULL
},
1994 { "/Attributes/Rise", NULL
, do_apply_rise
, FALSE
, NULL
},
1995 { "/Attributes/Large", NULL
, do_apply_large
, FALSE
, NULL
},
1996 { "/Attributes/Indent", NULL
, do_apply_indent
, FALSE
, NULL
},
1997 { "/Attributes/Margins", NULL
, do_apply_margin
, FALSE
, NULL
},
1998 { "/Attributes/Custom tabs", NULL
, do_apply_tabs
, FALSE
, NULL
},
1999 { "/Attributes/Default tabs", NULL
, do_apply_tabs
, TRUE
, NULL
},
2000 { "/Attributes/Color cycles", NULL
, do_apply_colors
, TRUE
, NULL
},
2001 { "/Attributes/No colors", NULL
, do_apply_colors
, FALSE
, NULL
},
2002 { "/Attributes/Remove all tags", NULL
, do_remove_tags
, 0, NULL
},
2003 { "/Attributes/Properties", NULL
, do_properties
, 0, NULL
},
2004 { "/Attributes/Rich Text copy & drag", NULL
, do_rich_text
, 0, NULL
},
2005 { "/Attributes/Rich Text paste & drop", NULL
, do_rich_text
, 1, NULL
},
2006 { "/_Test", NULL
, NULL
, 0, "<Branch>" },
2007 { "/Test/_Example", NULL
, do_example
, 0, NULL
},
2008 { "/Test/_Insert and scroll", NULL
, do_insert_and_scroll
, 0, NULL
},
2009 { "/Test/_Add fixed children", NULL
, do_add_children
, 0, NULL
},
2010 { "/Test/A_dd focusable children", NULL
, do_add_focus_children
, 0, NULL
},
2014 save_buffer (Buffer
*buffer
)
2016 GtkTextIter start
, end
;
2018 gboolean result
= FALSE
;
2019 gboolean have_backup
= FALSE
;
2020 gchar
*bak_filename
;
2023 g_return_val_if_fail (buffer
->filename
!= NULL
, FALSE
);
2025 bak_filename
= g_strconcat (buffer
->filename
, "~", NULL
);
2027 if (rename (buffer
->filename
, bak_filename
) != 0)
2029 if (errno
!= ENOENT
)
2031 gchar
*err
= g_strdup_printf ("Cannot back up '%s' to '%s': %s",
2032 buffer
->filename
, bak_filename
, g_strerror (errno
));
2033 msgbox_run (NULL
, err
, "OK", NULL
, NULL
, 0);
2041 file
= fopen (buffer
->filename
, "w");
2044 gchar
*err
= g_strdup_printf ("Cannot back up '%s' to '%s': %s",
2045 buffer
->filename
, bak_filename
, g_strerror (errno
));
2046 msgbox_run (NULL
, err
, "OK", NULL
, NULL
, 0);
2050 gtk_text_buffer_get_iter_at_offset (buffer
->buffer
, &start
, 0);
2051 gtk_text_buffer_get_end_iter (buffer
->buffer
, &end
);
2053 chars
= gtk_text_buffer_get_slice (buffer
->buffer
, &start
, &end
, FALSE
);
2055 if (fputs (chars
, file
) == EOF
||
2056 fclose (file
) == EOF
)
2058 gchar
*err
= g_strdup_printf ("Error writing to '%s': %s",
2059 buffer
->filename
, g_strerror (errno
));
2060 msgbox_run (NULL
, err
, "OK", NULL
, NULL
, 0);
2068 gtk_text_buffer_set_modified (buffer
->buffer
, FALSE
);
2074 if (!result
&& have_backup
)
2076 if (rename (bak_filename
, buffer
->filename
) != 0)
2078 gchar
*err
= g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
2079 buffer
->filename
, bak_filename
, g_strerror (errno
), bak_filename
);
2080 msgbox_run (NULL
, err
, "OK", NULL
, NULL
, 0);
2085 g_free (bak_filename
);
2091 save_as_ok_func (const char *filename
, gpointer data
)
2093 Buffer
*buffer
= data
;
2094 char *old_filename
= buffer
->filename
;
2096 if (!buffer
->filename
|| strcmp (filename
, buffer
->filename
) != 0)
2098 struct stat statbuf
;
2100 if (stat (filename
, &statbuf
) == 0)
2102 gchar
*err
= g_strdup_printf ("Ovewrite existing file '%s'?", filename
);
2103 gint result
= msgbox_run (NULL
, err
, "Yes", "No", NULL
, 1);
2111 buffer
->filename
= g_strdup (filename
);
2113 if (save_buffer (buffer
))
2115 g_free (old_filename
);
2116 buffer_filename_set (buffer
);
2121 g_free (buffer
->filename
);
2122 buffer
->filename
= old_filename
;
2128 save_as_buffer (Buffer
*buffer
)
2130 return filesel_run (NULL
, "Save File", NULL
, save_as_ok_func
, buffer
);
2134 check_buffer_saved (Buffer
*buffer
)
2136 if (gtk_text_buffer_get_modified (buffer
->buffer
))
2138 char *pretty_name
= buffer_pretty_name (buffer
);
2139 char *msg
= g_strdup_printf ("Save changes to '%s'?", pretty_name
);
2142 g_free (pretty_name
);
2144 result
= msgbox_run (NULL
, msg
, "Yes", "No", "Cancel", 0);
2148 return save_as_buffer (buffer
);
2149 else if (result
== 1)
2161 create_buffer (void)
2164 PangoTabArray
*tabs
;
2167 buffer
= g_new (Buffer
, 1);
2169 buffer
->buffer
= gtk_text_buffer_new (NULL
);
2171 buffer
->refcount
= 1;
2172 buffer
->filename
= NULL
;
2173 buffer
->untitled_serial
= -1;
2175 buffer
->color_tags
= NULL
;
2176 buffer
->color_cycle_timeout
= 0;
2177 buffer
->start_hue
= 0.0;
2180 while (i
< N_COLORS
)
2184 tag
= gtk_text_buffer_create_tag (buffer
->buffer
, NULL
, NULL
);
2186 buffer
->color_tags
= g_slist_prepend (buffer
->color_tags
, tag
);
2192 buffer
->invisible_tag
= gtk_text_buffer_create_tag (buffer
->buffer
, NULL
,
2193 "invisible", TRUE
, NULL
);
2196 buffer
->not_editable_tag
=
2197 gtk_text_buffer_create_tag (buffer
->buffer
, NULL
,
2199 "foreground", "purple", NULL
);
2201 buffer
->found_text_tag
= gtk_text_buffer_create_tag (buffer
->buffer
, NULL
,
2202 "foreground", "red", NULL
);
2204 buffer
->rise_tag
= gtk_text_buffer_create_tag (buffer
->buffer
, NULL
,
2205 "rise", 10 * PANGO_SCALE
, NULL
);
2207 buffer
->large_tag
= gtk_text_buffer_create_tag (buffer
->buffer
, NULL
,
2208 "scale", PANGO_SCALE_X_LARGE
, NULL
);
2210 buffer
->indent_tag
= gtk_text_buffer_create_tag (buffer
->buffer
, NULL
,
2211 "indent", 20, NULL
);
2213 buffer
->margin_tag
= gtk_text_buffer_create_tag (buffer
->buffer
, NULL
,
2214 "left_margin", 20, "right_margin", 20, NULL
);
2216 tabs
= pango_tab_array_new_with_positions (4,
2221 PANGO_TAB_LEFT
, 120);
2223 buffer
->custom_tabs_tag
= gtk_text_buffer_create_tag (buffer
->buffer
, NULL
,
2225 "foreground", "green", NULL
);
2227 pango_tab_array_free (tabs
);
2229 buffers
= g_slist_prepend (buffers
, buffer
);
2235 buffer_pretty_name (Buffer
*buffer
)
2237 if (buffer
->filename
)
2240 char *result
= g_path_get_basename (buffer
->filename
);
2241 p
= strchr (result
, '/');
2249 if (buffer
->untitled_serial
== -1)
2250 buffer
->untitled_serial
= untitled_serial
++;
2252 if (buffer
->untitled_serial
== 1)
2253 return g_strdup ("Untitled");
2255 return g_strdup_printf ("Untitled #%d", buffer
->untitled_serial
);
2260 buffer_filename_set (Buffer
*buffer
)
2262 GSList
*tmp_list
= views
;
2266 View
*view
= tmp_list
->data
;
2268 if (view
->buffer
== buffer
)
2269 view_set_title (view
);
2271 tmp_list
= tmp_list
->next
;
2276 buffer_search (Buffer
*buffer
,
2282 GtkTextIter start
, end
;
2286 /* remove tag from whole buffer */
2287 gtk_text_buffer_get_bounds (buffer
->buffer
, &start
, &end
);
2288 gtk_text_buffer_remove_tag (buffer
->buffer
, buffer
->found_text_tag
,
2291 gtk_text_buffer_get_iter_at_mark (buffer
->buffer
, &iter
,
2292 gtk_text_buffer_get_mark (buffer
->buffer
,
2298 GtkTextIter match_start
, match_end
;
2302 while (gtk_text_iter_forward_search (&iter
, str
,
2303 GTK_TEXT_SEARCH_VISIBLE_ONLY
|
2304 GTK_TEXT_SEARCH_TEXT_ONLY
,
2305 &match_start
, &match_end
,
2309 gtk_text_buffer_apply_tag (buffer
->buffer
, buffer
->found_text_tag
,
2310 &match_start
, &match_end
);
2317 while (gtk_text_iter_backward_search (&iter
, str
,
2318 GTK_TEXT_SEARCH_VISIBLE_ONLY
|
2319 GTK_TEXT_SEARCH_TEXT_ONLY
,
2320 &match_start
, &match_end
,
2324 gtk_text_buffer_apply_tag (buffer
->buffer
, buffer
->found_text_tag
,
2325 &match_start
, &match_end
);
2332 dialog
= gtk_message_dialog_new (GTK_WINDOW (view
->window
),
2333 GTK_DIALOG_DESTROY_WITH_PARENT
,
2336 "%d strings found and marked in red",
2339 g_signal_connect_swapped (dialog
,
2341 G_CALLBACK (gtk_widget_destroy
), dialog
);
2343 gtk_widget_show (dialog
);
2347 buffer_search_forward (Buffer
*buffer
, const char *str
,
2350 buffer_search (buffer
, str
, view
, TRUE
);
2354 buffer_search_backward (Buffer
*buffer
, const char *str
,
2357 buffer_search (buffer
, str
, view
, FALSE
);
2361 buffer_ref (Buffer
*buffer
)
2367 buffer_unref (Buffer
*buffer
)
2370 if (buffer
->refcount
== 0)
2372 buffer_set_colors (buffer
, FALSE
);
2373 buffers
= g_slist_remove (buffers
, buffer
);
2374 g_object_unref (buffer
->buffer
);
2375 g_free (buffer
->filename
);
2381 hsv_to_rgb (gdouble
*h
,
2385 gdouble hue
, saturation
, value
;
2403 f
= hue
- (int) hue
;
2404 p
= value
* (1.0 - saturation
);
2405 q
= value
* (1.0 - saturation
* f
);
2406 t
= value
* (1.0 - saturation
* (1.0 - f
));
2447 g_assert_not_reached ();
2453 hue_to_color (gdouble hue
,
2462 g_return_if_fail (hue
<= 1.0);
2464 hsv_to_rgb (&h
, &s
, &v
);
2466 color
->red
= h
* 65535;
2467 color
->green
= s
* 65535;
2468 color
->blue
= v
* 65535;
2473 color_cycle_timeout (gpointer data
)
2475 Buffer
*buffer
= data
;
2477 buffer_cycle_colors (buffer
);
2483 buffer_set_colors (Buffer
*buffer
,
2489 if (enabled
&& buffer
->color_cycle_timeout
== 0)
2490 buffer
->color_cycle_timeout
= gdk_threads_add_timeout (200, color_cycle_timeout
, buffer
);
2491 else if (!enabled
&& buffer
->color_cycle_timeout
!= 0)
2493 g_source_remove (buffer
->color_cycle_timeout
);
2494 buffer
->color_cycle_timeout
= 0;
2497 tmp
= buffer
->color_tags
;
2504 hue_to_color (hue
, &color
);
2506 g_object_set (tmp
->data
,
2507 "foreground_gdk", &color
,
2511 g_object_set (tmp
->data
,
2512 "foreground_set", FALSE
,
2515 hue
+= 1.0 / N_COLORS
;
2517 tmp
= g_slist_next (tmp
);
2522 buffer_cycle_colors (Buffer
*buffer
)
2525 gdouble hue
= buffer
->start_hue
;
2527 tmp
= buffer
->color_tags
;
2532 hue_to_color (hue
, &color
);
2534 g_object_set (tmp
->data
,
2535 "foreground_gdk", &color
,
2538 hue
+= 1.0 / N_COLORS
;
2542 tmp
= g_slist_next (tmp
);
2545 buffer
->start_hue
+= 1.0 / N_COLORS
;
2546 if (buffer
->start_hue
> 1.0)
2547 buffer
->start_hue
= 0.0;
2551 close_view (View
*view
)
2553 views
= g_slist_remove (views
, view
);
2554 buffer_unref (view
->buffer
);
2555 gtk_widget_destroy (view
->window
);
2556 g_object_unref (view
->item_factory
);
2565 check_close_view (View
*view
)
2567 if (view
->buffer
->refcount
> 1 ||
2568 check_buffer_saved (view
->buffer
))
2573 view_set_title (View
*view
)
2575 char *pretty_name
= buffer_pretty_name (view
->buffer
);
2576 char *title
= g_strconcat ("testtext - ", pretty_name
, NULL
);
2578 gtk_window_set_title (GTK_WINDOW (view
->window
), title
);
2580 g_free (pretty_name
);
2585 cursor_set_callback (GtkTextBuffer
*buffer
,
2586 const GtkTextIter
*location
,
2590 GtkTextView
*text_view
;
2592 /* Redraw tab windows if the cursor moves
2593 * on the mapped widget (windows may not exist before realization...
2596 text_view
= GTK_TEXT_VIEW (user_data
);
2598 if (GTK_WIDGET_MAPPED (text_view
) &&
2599 mark
== gtk_text_buffer_get_insert (buffer
))
2601 GdkWindow
*tab_window
;
2603 tab_window
= gtk_text_view_get_window (text_view
,
2604 GTK_TEXT_WINDOW_TOP
);
2606 gdk_window_invalidate_rect (tab_window
, NULL
, FALSE
);
2608 tab_window
= gtk_text_view_get_window (text_view
,
2609 GTK_TEXT_WINDOW_BOTTOM
);
2611 gdk_window_invalidate_rect (tab_window
, NULL
, FALSE
);
2616 tab_stops_expose (GtkWidget
*widget
,
2617 GdkEventExpose
*event
,
2624 GdkWindow
*bottom_win
;
2625 GtkTextView
*text_view
;
2626 GtkTextWindowType type
;
2627 GdkDrawable
*target
;
2628 gint
*positions
= NULL
;
2630 GtkTextAttributes
*attrs
;
2632 GtkTextBuffer
*buffer
;
2635 text_view
= GTK_TEXT_VIEW (widget
);
2637 /* See if this expose is on the tab stop window */
2638 top_win
= gtk_text_view_get_window (text_view
,
2639 GTK_TEXT_WINDOW_TOP
);
2641 bottom_win
= gtk_text_view_get_window (text_view
,
2642 GTK_TEXT_WINDOW_BOTTOM
);
2644 if (event
->window
== top_win
)
2646 type
= GTK_TEXT_WINDOW_TOP
;
2649 else if (event
->window
== bottom_win
)
2651 type
= GTK_TEXT_WINDOW_BOTTOM
;
2652 target
= bottom_win
;
2657 first_x
= event
->area
.x
;
2658 last_x
= first_x
+ event
->area
.width
;
2660 gtk_text_view_window_to_buffer_coords (text_view
,
2667 gtk_text_view_window_to_buffer_coords (text_view
,
2674 buffer
= gtk_text_view_get_buffer (text_view
);
2676 gtk_text_buffer_get_iter_at_mark (buffer
,
2678 gtk_text_buffer_get_mark (buffer
,
2681 attrs
= gtk_text_attributes_new ();
2683 gtk_text_iter_get_attributes (&insert
, attrs
);
2687 size
= pango_tab_array_get_size (attrs
->tabs
);
2689 pango_tab_array_get_tabs (attrs
->tabs
,
2693 in_pixels
= pango_tab_array_get_positions_in_pixels (attrs
->tabs
);
2701 gtk_text_attributes_unref (attrs
);
2709 positions
[i
] = PANGO_PIXELS (positions
[i
]);
2711 gtk_text_view_buffer_to_window_coords (text_view
,
2718 gdk_draw_line (target
,
2719 widget
->style
->fg_gc
[widget
->state
],
2732 get_lines (GtkTextView
*text_view
,
2735 GArray
*buffer_coords
,
2743 g_array_set_size (buffer_coords
, 0);
2744 g_array_set_size (numbers
, 0);
2746 /* Get iter at first y */
2747 gtk_text_view_get_line_at_y (text_view
, &iter
, first_y
, NULL
);
2749 /* For each iter, get its location and add it to the arrays.
2750 * Stop when we pass last_y
2755 while (!gtk_text_iter_is_end (&iter
))
2760 gtk_text_view_get_line_yrange (text_view
, &iter
, &y
, &height
);
2762 g_array_append_val (buffer_coords
, y
);
2763 line_num
= gtk_text_iter_get_line (&iter
);
2764 g_array_append_val (numbers
, line_num
);
2768 if ((y
+ height
) >= last_y
)
2771 gtk_text_iter_forward_line (&iter
);
2778 line_numbers_expose (GtkWidget
*widget
,
2779 GdkEventExpose
*event
,
2788 GdkWindow
*left_win
;
2789 GdkWindow
*right_win
;
2790 PangoLayout
*layout
;
2791 GtkTextView
*text_view
;
2792 GtkTextWindowType type
;
2793 GdkDrawable
*target
;
2795 text_view
= GTK_TEXT_VIEW (widget
);
2797 /* See if this expose is on the line numbers window */
2798 left_win
= gtk_text_view_get_window (text_view
,
2799 GTK_TEXT_WINDOW_LEFT
);
2801 right_win
= gtk_text_view_get_window (text_view
,
2802 GTK_TEXT_WINDOW_RIGHT
);
2804 if (event
->window
== left_win
)
2806 type
= GTK_TEXT_WINDOW_LEFT
;
2809 else if (event
->window
== right_win
)
2811 type
= GTK_TEXT_WINDOW_RIGHT
;
2817 first_y
= event
->area
.y
;
2818 last_y
= first_y
+ event
->area
.height
;
2820 gtk_text_view_window_to_buffer_coords (text_view
,
2827 gtk_text_view_window_to_buffer_coords (text_view
,
2834 numbers
= g_array_new (FALSE
, FALSE
, sizeof (gint
));
2835 pixels
= g_array_new (FALSE
, FALSE
, sizeof (gint
));
2837 get_lines (text_view
,
2844 /* Draw fully internationalized numbers! */
2846 layout
= gtk_widget_create_pango_layout (widget
, "");
2854 gtk_text_view_buffer_to_window_coords (text_view
,
2857 g_array_index (pixels
, gint
, i
),
2861 str
= g_strdup_printf ("%d", g_array_index (numbers
, gint
, i
));
2863 pango_layout_set_text (layout
, str
, -1);
2865 gtk_paint_layout (widget
->style
,
2867 GTK_WIDGET_STATE (widget
),
2880 g_array_free (pixels
, TRUE
);
2881 g_array_free (numbers
, TRUE
);
2883 g_object_unref (layout
);
2885 /* don't stop emission, need to draw children */
2890 selection_changed (GtkTextBuffer
*buffer
,
2892 GtkWidget
*copy_menu
)
2894 gtk_widget_set_sensitive (copy_menu
, gtk_text_buffer_get_has_selection (buffer
));
2898 create_view (Buffer
*buffer
)
2901 GtkWidget
*copy_menu
;
2905 view
= g_new0 (View
, 1);
2906 views
= g_slist_prepend (views
, view
);
2908 view
->buffer
= buffer
;
2909 buffer_ref (buffer
);
2911 view
->window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
2912 g_object_set_data (G_OBJECT (view
->window
), "view", view
);
2914 g_signal_connect (view
->window
, "delete_event",
2915 G_CALLBACK (delete_event_cb
), NULL
);
2917 view
->accel_group
= gtk_accel_group_new ();
2918 view
->item_factory
= gtk_item_factory_new (GTK_TYPE_MENU_BAR
, "<main>", view
->accel_group
);
2919 g_object_set_data (G_OBJECT (view
->item_factory
), "view", view
);
2921 gtk_item_factory_create_items (view
->item_factory
, G_N_ELEMENTS (menu_items
), menu_items
, view
);
2923 /* make the Copy menu item sensitivity update according to the selection */
2924 copy_menu
= gtk_item_factory_get_item (view
->item_factory
, "<main>/Edit/Copy");
2925 gtk_widget_set_sensitive (copy_menu
, gtk_text_buffer_get_has_selection (view
->buffer
->buffer
));
2926 g_signal_connect (view
->buffer
->buffer
,
2927 "notify::has-selection",
2928 G_CALLBACK (selection_changed
),
2931 gtk_window_add_accel_group (GTK_WINDOW (view
->window
), view
->accel_group
);
2933 vbox
= gtk_vbox_new (FALSE
, 0);
2934 gtk_container_add (GTK_CONTAINER (view
->window
), vbox
);
2936 gtk_box_pack_start (GTK_BOX (vbox
),
2937 gtk_item_factory_get_widget (view
->item_factory
, "<main>"),
2940 sw
= gtk_scrolled_window_new (NULL
, NULL
);
2941 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
),
2942 GTK_POLICY_AUTOMATIC
,
2943 GTK_POLICY_AUTOMATIC
);
2945 view
->text_view
= gtk_text_view_new_with_buffer (buffer
->buffer
);
2946 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view
->text_view
),
2949 /* Make sure border width works, no real reason to do this other than testing */
2950 gtk_container_set_border_width (GTK_CONTAINER (view
->text_view
),
2953 /* Draw tab stops in the top and bottom windows. */
2955 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view
->text_view
),
2956 GTK_TEXT_WINDOW_TOP
,
2959 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view
->text_view
),
2960 GTK_TEXT_WINDOW_BOTTOM
,
2963 g_signal_connect (view
->text_view
,
2965 G_CALLBACK (tab_stops_expose
),
2968 g_signal_connect (view
->buffer
->buffer
,
2970 G_CALLBACK (cursor_set_callback
),
2973 /* Draw line numbers in the side windows; we should really be
2974 * more scientific about what width we set them to.
2976 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view
->text_view
),
2977 GTK_TEXT_WINDOW_RIGHT
,
2980 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view
->text_view
),
2981 GTK_TEXT_WINDOW_LEFT
,
2984 g_signal_connect (view
->text_view
,
2986 G_CALLBACK (line_numbers_expose
),
2989 gtk_box_pack_start (GTK_BOX (vbox
), sw
, TRUE
, TRUE
, 0);
2990 gtk_container_add (GTK_CONTAINER (sw
), view
->text_view
);
2992 gtk_window_set_default_size (GTK_WINDOW (view
->window
), 500, 500);
2994 gtk_widget_grab_focus (view
->text_view
);
2996 view_set_title (view
);
2997 view_init_menus (view
);
2999 view_add_example_widgets (view
);
3001 gtk_widget_show_all (view
->window
);
3006 view_add_example_widgets (View
*view
)
3008 GtkTextChildAnchor
*anchor
;
3011 buffer
= view
->buffer
;
3013 anchor
= g_object_get_data (G_OBJECT (buffer
->buffer
),
3016 if (anchor
&& !gtk_text_child_anchor_get_deleted (anchor
))
3020 widget
= gtk_button_new_with_label ("Foo");
3022 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view
->text_view
),
3026 gtk_widget_show (widget
);
3033 if (g_file_test ("../gdk-pixbuf/libpixbufloader-pnm.la",
3034 G_FILE_TEST_EXISTS
))
3036 g_setenv ("GDK_PIXBUF_MODULE_FILE", "../gdk-pixbuf/gdk-pixbuf.loaders", TRUE
);
3037 g_setenv ("GTK_IM_MODULE_FILE", "../modules/input/gtk.immodules", TRUE
);
3042 main (int argc
, char** argv
)
3049 gtk_init (&argc
, &argv
);
3051 buffer
= create_buffer ();
3052 view
= create_view (buffer
);
3053 buffer_unref (buffer
);
3055 push_active_window (GTK_WINDOW (view
->window
));
3056 for (i
=1; i
< argc
; i
++)
3060 /* Quick and dirty canonicalization - better should be in GLib
3063 if (!g_path_is_absolute (argv
[i
]))
3065 char *cwd
= g_get_current_dir ();
3066 filename
= g_strconcat (cwd
, "/", argv
[i
], NULL
);
3072 open_ok_func (filename
, view
);
3074 if (filename
!= argv
[i
])
3077 pop_active_window ();