8 #include <gdk/gdkkeysyms.h>
10 #include "prop-editor.h"
12 typedef struct _Buffer Buffer;
13 typedef struct _View View;
15 static gint untitled_serial = 1;
17 GSList *active_window_stack = NULL;
22 GtkTextBuffer *buffer;
25 GtkTextTag *invisible_tag;
26 GtkTextTag *not_editable_tag;
27 GtkTextTag *found_text_tag;
28 GtkTextTag *custom_tabs_tag;
30 guint color_cycle_timeout;
38 GtkAccelGroup *accel_group;
39 GtkItemFactory *item_factory;
43 static void push_active_window (GtkWindow *window);
44 static void pop_active_window (void);
45 static GtkWindow *get_active_window (void);
47 static Buffer * create_buffer (void);
48 static gboolean check_buffer_saved (Buffer *buffer);
49 static gboolean save_buffer (Buffer *buffer);
50 static gboolean save_as_buffer (Buffer *buffer);
51 static char * buffer_pretty_name (Buffer *buffer);
52 static void buffer_filename_set (Buffer *buffer);
53 static void buffer_search_forward (Buffer *buffer,
56 static void buffer_search_backward (Buffer *buffer,
59 static void buffer_set_colors (Buffer *buffer,
61 static void buffer_cycle_colors (Buffer *buffer);
63 static View *view_from_widget (GtkWidget *widget);
65 static View *create_view (Buffer *buffer);
66 static void check_close_view (View *view);
67 static void close_view (View *view);
68 static void view_set_title (View *view);
69 static void view_init_menus (View *view);
70 static void view_add_example_widgets (View *view);
72 GSList *buffers = NULL;
76 push_active_window (GtkWindow *window)
78 g_object_ref (G_OBJECT (window));
79 active_window_stack = g_slist_prepend (active_window_stack, window);
83 pop_active_window (void)
85 gtk_object_unref (active_window_stack->data);
86 active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack);
90 get_active_window (void)
92 if (active_window_stack)
93 return active_window_stack->data;
99 * Filesel utility function
102 typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data);
105 filesel_ok_cb (GtkWidget *button, GtkWidget *filesel)
107 FileselOKFunc ok_func = g_object_get_data (G_OBJECT (filesel), "ok-func");
108 gpointer data = g_object_get_data (G_OBJECT (filesel), "ok-data");
109 gint *result = g_object_get_data (G_OBJECT (filesel), "ok-result");
111 gtk_widget_hide (filesel);
113 if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data))
115 gtk_widget_destroy (filesel);
119 gtk_widget_show (filesel);
123 filesel_run (GtkWindow *parent,
125 const char *start_file,
129 GtkWidget *filesel = gtk_file_selection_new (title);
130 gboolean result = FALSE;
133 parent = get_active_window ();
136 gtk_window_set_transient_for (GTK_WINDOW (filesel), parent);
139 gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file);
142 g_object_set_data (G_OBJECT (filesel), "ok-func", func);
143 g_object_set_data (G_OBJECT (filesel), "ok-data", data);
144 g_object_set_data (G_OBJECT (filesel), "ok-result", &result);
146 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
148 GTK_SIGNAL_FUNC (filesel_ok_cb), filesel);
149 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
151 GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (filesel));
153 gtk_signal_connect (GTK_OBJECT (filesel), "destroy",
154 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
155 gtk_window_set_modal (GTK_WINDOW (filesel), TRUE);
157 gtk_widget_show (filesel);
164 * MsgBox utility functions
168 msgbox_yes_cb (GtkWidget *widget, gboolean *result)
171 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
175 msgbox_no_cb (GtkWidget *widget, gboolean *result)
178 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
182 msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
184 if (event->keyval == GDK_Escape)
186 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
187 gtk_object_destroy (GTK_OBJECT (widget));
194 /* Don't copy this example, it's all crack-smoking - you can just use
195 * GtkMessageDialog now
198 msgbox_run (GtkWindow *parent,
200 const char *yes_button,
201 const char *no_button,
202 const char *cancel_button,
205 gboolean result = -1;
210 GtkWidget *button_box;
211 GtkWidget *separator;
213 g_return_val_if_fail (message != NULL, FALSE);
214 g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE);
217 parent = get_active_window ();
221 dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
222 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
224 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
225 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
227 /* Quit our recursive main loop when the dialog is destroyed.
229 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
230 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
232 /* Catch Escape key presses and have them destroy the dialog
234 gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event",
235 GTK_SIGNAL_FUNC (msgbox_key_press_cb), NULL);
237 /* Fill in the contents of the widget
239 vbox = gtk_vbox_new (FALSE, 0);
240 gtk_container_add (GTK_CONTAINER (dialog), vbox);
242 label = gtk_label_new (message);
243 gtk_misc_set_padding (GTK_MISC (label), 12, 12);
244 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
245 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
247 separator = gtk_hseparator_new ();
248 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
250 button_box = gtk_hbutton_box_new ();
251 gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
252 gtk_container_set_border_width (GTK_CONTAINER (button_box), 8);
255 /* When Yes is clicked, call the msgbox_yes_cb
256 * This sets the result variable and destroys the dialog
260 button = gtk_button_new_with_label (yes_button);
261 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
262 gtk_container_add (GTK_CONTAINER (button_box), button);
264 if (default_index == 0)
265 gtk_widget_grab_default (button);
267 gtk_signal_connect (GTK_OBJECT (button), "clicked",
268 GTK_SIGNAL_FUNC (msgbox_yes_cb), &result);
271 /* When No is clicked, call the msgbox_no_cb
272 * This sets the result variable and destroys the dialog
276 button = gtk_button_new_with_label (no_button);
277 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
278 gtk_container_add (GTK_CONTAINER (button_box), button);
280 if (default_index == 0)
281 gtk_widget_grab_default (button);
283 gtk_signal_connect (GTK_OBJECT (button), "clicked",
284 GTK_SIGNAL_FUNC (msgbox_no_cb), &result);
287 /* When Cancel is clicked, destroy the dialog
291 button = gtk_button_new_with_label (cancel_button);
292 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
293 gtk_container_add (GTK_CONTAINER (button_box), button);
295 if (default_index == 1)
296 gtk_widget_grab_default (button);
298 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
299 GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (dialog));
302 gtk_widget_show_all (dialog);
304 /* Run a recursive main loop until a button is clicked
305 * or the user destroys the dialog through the window mananger */
312 * Example buffer filling code
315 blink_timeout (gpointer data)
318 static gboolean flip = FALSE;
320 tag = GTK_TEXT_TAG (data);
322 g_object_set (G_OBJECT (tag),
323 "foreground", flip ? "blue" : "purple",
332 tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
333 const GtkTextIter *iter, gpointer user_data)
337 char_index = gtk_text_iter_get_offset (iter);
341 case GDK_MOTION_NOTIFY:
342 printf ("Motion event at char %d tag `%s'\n",
343 char_index, tag->name);
346 case GDK_BUTTON_PRESS:
347 printf ("Button press at char %d tag `%s'\n",
348 char_index, tag->name);
351 case GDK_2BUTTON_PRESS:
352 printf ("Double click at char %d tag `%s'\n",
353 char_index, tag->name);
356 case GDK_3BUTTON_PRESS:
357 printf ("Triple click at char %d tag `%s'\n",
358 char_index, tag->name);
361 case GDK_BUTTON_RELEASE:
362 printf ("Button release at char %d tag `%s'\n",
363 char_index, tag->name);
367 case GDK_KEY_RELEASE:
368 printf ("Key event at char %d tag `%s'\n",
369 char_index, tag->name);
372 case GDK_ENTER_NOTIFY:
373 case GDK_LEAVE_NOTIFY:
374 case GDK_PROPERTY_NOTIFY:
375 case GDK_SELECTION_CLEAR:
376 case GDK_SELECTION_REQUEST:
377 case GDK_SELECTION_NOTIFY:
378 case GDK_PROXIMITY_IN:
379 case GDK_PROXIMITY_OUT:
382 case GDK_DRAG_MOTION:
383 case GDK_DRAG_STATUS:
385 case GDK_DROP_FINISHED:
394 setup_tag (GtkTextTag *tag)
396 g_signal_connect (G_OBJECT (tag),
398 G_CALLBACK (tag_event_handler),
402 static const char *book_closed_xpm[] = {
428 fill_example_buffer (GtkTextBuffer *buffer)
430 GtkTextIter iter, iter2;
432 GtkTextChildAnchor *anchor;
439 /* FIXME this is broken if called twice on a buffer, since
440 * we try to create tags a second time.
443 tag = gtk_text_buffer_create_tag (buffer, "fg_blue", NULL);
445 /* gtk_timeout_add (1000, blink_timeout, tag); */
449 color.red = color.green = 0;
454 g_object_set (G_OBJECT (tag),
455 "foreground_gdk", &color,
456 "background_gdk", &color2,
460 tag = gtk_text_buffer_create_tag (buffer, "fg_red", NULL);
464 color.blue = color.green = 0;
466 g_object_set (G_OBJECT (tag),
467 "rise", -4 * PANGO_SCALE,
468 "foreground_gdk", &color,
471 tag = gtk_text_buffer_create_tag (buffer, "bg_green", NULL);
475 color.blue = color.red = 0;
476 color.green = 0xffff;
477 g_object_set (G_OBJECT (tag),
478 "background_gdk", &color,
482 tag = gtk_text_buffer_create_tag (buffer, "strikethrough", NULL);
486 g_object_set (G_OBJECT (tag),
487 "strikethrough", TRUE,
491 tag = gtk_text_buffer_create_tag (buffer, "underline", NULL);
495 g_object_set (G_OBJECT (tag),
496 "underline", PANGO_UNDERLINE_SINGLE,
501 g_object_set (G_OBJECT (tag),
502 "underline", PANGO_UNDERLINE_SINGLE,
505 tag = gtk_text_buffer_create_tag (buffer, "centered", NULL);
507 g_object_set (G_OBJECT (tag),
508 "justification", GTK_JUSTIFY_CENTER,
511 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote", NULL);
513 g_object_set (G_OBJECT (tag),
514 "wrap_mode", GTK_WRAP_WORD,
515 "direction", GTK_TEXT_DIR_RTL,
522 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
524 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
526 g_object_ref (G_OBJECT (anchor));
528 g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
529 (GDestroyNotify) g_object_unref);
531 pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
536 GtkTextMark * temp_mark;
538 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
540 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
542 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",
545 gtk_text_buffer_insert (buffer, &iter, str, -1);
549 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
551 gtk_text_buffer_insert (buffer, &iter,
552 "(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"
553 /* This is UTF8 stuff, Emacs doesn't
554 really know how to display it */
555 "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew(שלום) Hebrew punctuation(\xd6\xbfש\xd6\xbb\xd6\xbc\xd6\xbb\xd6\xbfל\xd6\xbcו\xd6\xbc\xd6\xbb\xd6\xbb\xd6\xbfם\xd6\xbc\xd6\xbb\xd6\xbf) Japanese (日本語) Thai (สวัสดีครับ) Thai wrong spelling (คำต่อไปนื่สะกดผิด พัั้ัั่งโกะ)\n", -1);
558 gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
561 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
562 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
564 gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
566 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
567 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
569 gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
571 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
572 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
574 gtk_text_buffer_apply_tag_by_name (buffer, "strikethrough", &iter, &iter2);
576 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
577 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
579 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
581 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
582 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
584 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
586 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
587 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
589 gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
592 gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
593 gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
595 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
596 gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
598 gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
599 gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
600 gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1);
601 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
602 gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
607 g_object_unref (G_OBJECT (pixbuf));
609 printf ("%d lines %d chars\n",
610 gtk_text_buffer_get_line_count (buffer),
611 gtk_text_buffer_get_char_count (buffer));
613 /* Move cursor to start */
614 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
615 gtk_text_buffer_place_cursor (buffer, &iter);
617 gtk_text_buffer_set_modified (buffer, FALSE);
621 fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
626 GtkTextIter iter, end;
628 f = fopen (filename, "r");
632 gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
633 filename, g_strerror (errno));
634 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
639 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
643 const char *leftover;
644 int to_read = 2047 - remaining;
646 count = fread (buf + remaining, 1, to_read, f);
647 buf[count + remaining] = '\0';
649 g_utf8_validate (buf, count + remaining, &leftover);
651 g_assert (g_utf8_validate (buf, leftover - buf, NULL));
652 gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
654 remaining = (buf + remaining + count) - leftover;
655 g_memmove (buf, leftover, remaining);
657 if (remaining > 6 || count < to_read)
663 gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
664 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
668 /* We had a newline in the buffer to begin with. (The buffer always contains
669 * a newline, so we delete to the end of the buffer to clean up.
671 gtk_text_buffer_get_end_iter (buffer, &end);
672 gtk_text_buffer_delete (buffer, &iter, &end);
674 gtk_text_buffer_set_modified (buffer, FALSE);
680 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
682 View *view = view_from_widget (window);
684 push_active_window (GTK_WINDOW (window));
685 check_close_view (view);
686 pop_active_window ();
696 get_empty_view (View *view)
698 if (!view->buffer->filename &&
699 !gtk_text_buffer_get_modified (view->buffer->buffer))
702 return create_view (create_buffer ());
706 view_from_widget (GtkWidget *widget)
708 if (GTK_IS_MENU_ITEM (widget))
710 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
711 return g_object_get_data (G_OBJECT (item_factory), "view");
715 GtkWidget *app = gtk_widget_get_toplevel (widget);
716 return g_object_get_data (G_OBJECT (app), "view");
721 do_new (gpointer callback_data,
722 guint callback_action,
725 create_view (create_buffer ());
729 do_new_view (gpointer callback_data,
730 guint callback_action,
733 View *view = view_from_widget (widget);
735 create_view (view->buffer);
739 open_ok_func (const char *filename, gpointer data)
742 View *new_view = get_empty_view (view);
744 if (!fill_file_buffer (new_view->buffer->buffer, filename))
746 if (new_view != view)
747 close_view (new_view);
752 g_free (new_view->buffer->filename);
753 new_view->buffer->filename = g_strdup (filename);
754 buffer_filename_set (new_view->buffer);
761 do_open (gpointer callback_data,
762 guint callback_action,
765 View *view = view_from_widget (widget);
767 push_active_window (GTK_WINDOW (view->window));
768 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
769 pop_active_window ();
773 do_save_as (gpointer callback_data,
774 guint callback_action,
777 View *view = view_from_widget (widget);
779 push_active_window (GTK_WINDOW (view->window));
780 save_as_buffer (view->buffer);
781 pop_active_window ();
785 do_save (gpointer callback_data,
786 guint callback_action,
789 View *view = view_from_widget (widget);
791 push_active_window (GTK_WINDOW (view->window));
792 if (!view->buffer->filename)
793 do_save_as (callback_data, callback_action, widget);
795 save_buffer (view->buffer);
796 pop_active_window ();
800 do_close (gpointer callback_data,
801 guint callback_action,
804 View *view = view_from_widget (widget);
806 push_active_window (GTK_WINDOW (view->window));
807 check_close_view (view);
808 pop_active_window ();
812 do_exit (gpointer callback_data,
813 guint callback_action,
816 View *view = view_from_widget (widget);
818 GSList *tmp_list = buffers;
820 push_active_window (GTK_WINDOW (view->window));
823 if (!check_buffer_saved (tmp_list->data))
826 tmp_list = tmp_list->next;
830 pop_active_window ();
834 do_example (gpointer callback_data,
835 guint callback_action,
838 View *view = view_from_widget (widget);
841 new_view = get_empty_view (view);
843 fill_example_buffer (new_view->buffer->buffer);
845 view_add_example_widgets (new_view);
850 do_insert_and_scroll (gpointer callback_data,
851 guint callback_action,
854 View *view = view_from_widget (widget);
855 GtkTextBuffer *buffer;
856 GtkTextIter start, end;
859 buffer = view->buffer->buffer;
861 gtk_text_buffer_get_bounds (buffer, &start, &end);
862 mark = gtk_text_buffer_create_mark (buffer, NULL, &end, /* right grav */ FALSE);
864 gtk_text_iter_backward_char (&end);
865 gtk_text_buffer_insert (buffer, &end,
866 "Hello this is multiple lines of text\n"
867 "Line 1\n" "Line 2\n"
868 "Line 3\n" "Line 4\n"
872 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view->text_view), mark,
874 gtk_text_buffer_delete_mark (buffer, mark);
878 do_wrap_changed (gpointer callback_data,
879 guint callback_action,
882 View *view = view_from_widget (widget);
884 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
888 do_direction_changed (gpointer callback_data,
889 guint callback_action,
892 View *view = view_from_widget (widget);
894 gtk_widget_set_direction (view->text_view, callback_action);
895 gtk_widget_queue_resize (view->text_view);
900 do_spacing_changed (gpointer callback_data,
901 guint callback_action,
904 View *view = view_from_widget (widget);
908 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
910 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
912 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
917 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
919 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
921 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
927 do_editable_changed (gpointer callback_data,
928 guint callback_action,
931 View *view = view_from_widget (widget);
933 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
937 do_cursor_visible_changed (gpointer callback_data,
938 guint callback_action,
941 View *view = view_from_widget (widget);
943 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
947 do_color_cycle_changed (gpointer callback_data,
948 guint callback_action,
951 View *view = view_from_widget (widget);
953 buffer_set_colors (view->buffer, callback_action);
957 do_apply_editable (gpointer callback_data,
958 guint callback_action,
961 View *view = view_from_widget (widget);
965 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
970 gtk_text_buffer_remove_tag (view->buffer->buffer,
971 view->buffer->not_editable_tag,
976 gtk_text_buffer_apply_tag (view->buffer->buffer,
977 view->buffer->not_editable_tag,
984 do_apply_invisible (gpointer callback_data,
985 guint callback_action,
988 View *view = view_from_widget (widget);
992 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
997 gtk_text_buffer_remove_tag (view->buffer->buffer,
998 view->buffer->invisible_tag,
1003 gtk_text_buffer_apply_tag (view->buffer->buffer,
1004 view->buffer->invisible_tag,
1011 do_apply_tabs (gpointer callback_data,
1012 guint callback_action,
1015 View *view = view_from_widget (widget);
1019 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1022 if (callback_action)
1024 gtk_text_buffer_remove_tag (view->buffer->buffer,
1025 view->buffer->custom_tabs_tag,
1030 gtk_text_buffer_apply_tag (view->buffer->buffer,
1031 view->buffer->custom_tabs_tag,
1038 do_apply_colors (gpointer callback_data,
1039 guint callback_action,
1042 View *view = view_from_widget (widget);
1043 Buffer *buffer = view->buffer;
1047 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1050 if (!callback_action)
1054 tmp = buffer->color_tags;
1057 gtk_text_buffer_remove_tag (view->buffer->buffer,
1060 tmp = g_slist_next (tmp);
1067 tmp = buffer->color_tags;
1071 gboolean done = FALSE;
1074 gtk_text_iter_forward_char (&next);
1075 gtk_text_iter_forward_char (&next);
1077 if (gtk_text_iter_compare (&next, &end) > 0)
1083 gtk_text_buffer_apply_tag (view->buffer->buffer,
1092 tmp = g_slist_next (tmp);
1094 tmp = buffer->color_tags;
1101 do_remove_tags (gpointer callback_data,
1102 guint callback_action,
1105 View *view = view_from_widget (widget);
1109 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1112 gtk_text_buffer_remove_all_tags (view->buffer->buffer,
1118 do_properties (gpointer callback_data,
1119 guint callback_action,
1122 View *view = view_from_widget (widget);
1124 create_prop_editor (G_OBJECT (view->text_view), 0);
1134 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1136 GtkTextBuffer *buffer;
1138 GtkTextIter start, end;
1139 gchar *search_string;
1141 if (response_id != RESPONSE_FORWARD &&
1142 response_id != RESPONSE_BACKWARD)
1144 gtk_widget_destroy (dialog);
1148 buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
1150 gtk_text_buffer_get_bounds (buffer, &start, &end);
1152 /* Remove trailing newline */
1153 gtk_text_iter_backward_char (&end);
1155 search_string = gtk_text_iter_get_text (&start, &end);
1157 printf ("Searching for `%s'\n", search_string);
1159 if (response_id == RESPONSE_FORWARD)
1160 buffer_search_forward (view->buffer, search_string, view);
1161 else if (response_id == RESPONSE_BACKWARD)
1162 buffer_search_backward (view->buffer, search_string, view);
1164 g_free (search_string);
1166 gtk_widget_destroy (dialog);
1170 do_search (gpointer callback_data,
1171 guint callback_action,
1174 View *view = view_from_widget (widget);
1176 GtkWidget *search_text;
1177 GtkTextBuffer *buffer;
1179 dialog = gtk_dialog_new_with_buttons ("Search",
1180 GTK_WINDOW (view->window),
1181 GTK_DIALOG_DESTROY_WITH_PARENT,
1182 "Forward", RESPONSE_FORWARD,
1183 "Backward", RESPONSE_BACKWARD,
1185 GTK_RESPONSE_NONE, NULL);
1188 buffer = gtk_text_buffer_new (NULL);
1190 search_text = gtk_text_view_new_with_buffer (buffer);
1192 g_object_unref (G_OBJECT (buffer));
1194 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1198 g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
1200 gtk_signal_connect (GTK_OBJECT (dialog),
1202 GTK_SIGNAL_FUNC (dialog_response_callback),
1205 gtk_widget_show (search_text);
1207 gtk_widget_grab_focus (search_text);
1209 gtk_widget_show_all (dialog);
1213 view_init_menus (View *view)
1215 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1216 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1217 GtkWidget *menu_item = NULL;
1221 case GTK_TEXT_DIR_LTR:
1222 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1224 case GTK_TEXT_DIR_RTL:
1225 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1232 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1237 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1240 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1243 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
1250 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1253 static GtkItemFactoryEntry menu_items[] =
1255 { "/_File", NULL, 0, 0, "<Branch>" },
1256 { "/File/_New", "<control>N", do_new, 0, NULL },
1257 { "/File/New _View", NULL, do_new_view, 0, NULL },
1258 { "/File/_Open", "<control>O", do_open, 0, NULL },
1259 { "/File/_Save", "<control>S", do_save, 0, NULL },
1260 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1261 { "/File/sep1", NULL, 0, 0, "<Separator>" },
1262 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1263 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1265 { "/_Edit", NULL, 0, 0, "<Branch>" },
1266 { "/Edit/Find...", NULL, do_search, 0, NULL },
1268 { "/_Settings", NULL, 0, 0, "<Branch>" },
1269 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAP_NONE, "<RadioItem>" },
1270 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAP_WORD, "/Settings/Wrap Off" },
1271 { "/Settings/Wrap _Chars", NULL, do_wrap_changed, GTK_WRAP_CHAR, "/Settings/Wrap Off" },
1272 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1273 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1274 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1275 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1277 { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "<RadioItem>" },
1278 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" },
1279 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1281 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1282 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1284 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1285 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1286 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1287 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1288 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1289 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1290 { "/_Attributes", NULL, 0, 0, "<Branch>" },
1291 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1292 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1293 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1294 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1295 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1296 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1297 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1298 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
1299 { "/Attributes/Remove all tags", NULL, do_remove_tags, 0, NULL },
1300 { "/Attributes/Properties", NULL, do_properties, 0, NULL },
1301 { "/_Test", NULL, 0, 0, "<Branch>" },
1302 { "/Test/_Example", NULL, do_example, 0, NULL },
1303 { "/Test/_Insert and scroll", NULL, do_insert_and_scroll, 0, NULL },
1307 save_buffer (Buffer *buffer)
1309 GtkTextIter start, end;
1311 gboolean result = FALSE;
1312 gboolean have_backup = FALSE;
1313 gchar *bak_filename;
1316 g_return_val_if_fail (buffer->filename != NULL, FALSE);
1318 bak_filename = g_strconcat (buffer->filename, "~", NULL);
1320 if (rename (buffer->filename, bak_filename) != 0)
1322 if (errno != ENOENT)
1324 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1325 buffer->filename, bak_filename, g_strerror (errno));
1326 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1334 file = fopen (buffer->filename, "w");
1337 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1338 buffer->filename, bak_filename, g_strerror (errno));
1339 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1343 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1344 gtk_text_buffer_get_end_iter (buffer->buffer, &end);
1346 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1348 if (fputs (chars, file) == EOF ||
1349 fclose (file) == EOF)
1351 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1352 buffer->filename, g_strerror (errno));
1353 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1361 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
1367 if (!result && have_backup)
1369 if (rename (bak_filename, buffer->filename) != 0)
1371 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1372 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1373 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1378 g_free (bak_filename);
1384 save_as_ok_func (const char *filename, gpointer data)
1386 Buffer *buffer = data;
1387 char *old_filename = buffer->filename;
1389 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1391 struct stat statbuf;
1393 if (stat (filename, &statbuf) == 0)
1395 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1396 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1404 buffer->filename = g_strdup (filename);
1406 if (save_buffer (buffer))
1408 g_free (old_filename);
1409 buffer_filename_set (buffer);
1414 g_free (buffer->filename);
1415 buffer->filename = old_filename;
1421 save_as_buffer (Buffer *buffer)
1423 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1427 check_buffer_saved (Buffer *buffer)
1429 if (gtk_text_buffer_get_modified (buffer->buffer))
1431 char *pretty_name = buffer_pretty_name (buffer);
1432 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1435 g_free (pretty_name);
1437 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1441 return save_as_buffer (buffer);
1442 else if (result == 1)
1454 create_buffer (void)
1457 PangoTabArray *tabs;
1460 buffer = g_new (Buffer, 1);
1462 buffer->buffer = gtk_text_buffer_new (NULL);
1464 buffer->refcount = 1;
1465 buffer->filename = NULL;
1466 buffer->untitled_serial = -1;
1468 buffer->color_tags = NULL;
1469 buffer->color_cycle_timeout = 0;
1470 buffer->start_hue = 0.0;
1473 while (i < N_COLORS)
1477 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL, NULL);
1479 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1484 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1485 "invisible", TRUE, NULL);
1487 buffer->not_editable_tag =
1488 gtk_text_buffer_create_tag (buffer->buffer, NULL,
1490 "foreground", "purple", NULL);
1492 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1493 "foreground", "red", NULL);
1495 tabs = pango_tab_array_new_with_positions (4,
1500 PANGO_TAB_LEFT, 120);
1502 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1504 "foreground", "green", NULL);
1506 pango_tab_array_free (tabs);
1508 buffers = g_slist_prepend (buffers, buffer);
1514 buffer_pretty_name (Buffer *buffer)
1516 if (buffer->filename)
1519 char *result = g_path_get_basename (buffer->filename);
1520 p = strchr (result, '/');
1528 if (buffer->untitled_serial == -1)
1529 buffer->untitled_serial = untitled_serial++;
1531 if (buffer->untitled_serial == 1)
1532 return g_strdup ("Untitled");
1534 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1539 buffer_filename_set (Buffer *buffer)
1541 GSList *tmp_list = views;
1545 View *view = tmp_list->data;
1547 if (view->buffer == buffer)
1548 view_set_title (view);
1550 tmp_list = tmp_list->next;
1555 buffer_search (Buffer *buffer,
1561 GtkTextIter start, end;
1565 /* remove tag from whole buffer */
1566 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1567 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1570 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1571 gtk_text_buffer_get_mark (buffer->buffer,
1577 GtkTextIter match_start, match_end;
1581 while (gtk_text_iter_forward_search (&iter, str,
1582 GTK_TEXT_SEARCH_VISIBLE_ONLY |
1583 GTK_TEXT_SEARCH_TEXT_ONLY,
1584 &match_start, &match_end,
1588 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1589 &match_start, &match_end);
1596 while (gtk_text_iter_backward_search (&iter, str,
1597 GTK_TEXT_SEARCH_VISIBLE_ONLY |
1598 GTK_TEXT_SEARCH_TEXT_ONLY,
1599 &match_start, &match_end,
1603 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1604 &match_start, &match_end);
1611 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1614 GTK_DIALOG_DESTROY_WITH_PARENT,
1615 "%d strings found and marked in red",
1618 gtk_signal_connect_object (GTK_OBJECT (dialog),
1620 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1621 GTK_OBJECT (dialog));
1623 gtk_widget_show (dialog);
1627 buffer_search_forward (Buffer *buffer, const char *str,
1630 buffer_search (buffer, str, view, TRUE);
1634 buffer_search_backward (Buffer *buffer, const char *str,
1637 buffer_search (buffer, str, view, FALSE);
1641 buffer_ref (Buffer *buffer)
1647 buffer_unref (Buffer *buffer)
1650 if (buffer->refcount == 0)
1652 buffer_set_colors (buffer, FALSE);
1653 buffers = g_slist_remove (buffers, buffer);
1654 g_object_unref (G_OBJECT (buffer->buffer));
1655 g_free (buffer->filename);
1661 hsv_to_rgb (gdouble *h,
1665 gdouble hue, saturation, value;
1683 f = hue - (int) hue;
1684 p = value * (1.0 - saturation);
1685 q = value * (1.0 - saturation * f);
1686 t = value * (1.0 - saturation * (1.0 - f));
1727 g_assert_not_reached ();
1733 hue_to_color (gdouble hue,
1742 g_return_if_fail (hue <= 1.0);
1744 hsv_to_rgb (&h, &s, &v);
1746 color->red = h * 65535;
1747 color->green = s * 65535;
1748 color->blue = v * 65535;
1753 color_cycle_timeout (gpointer data)
1755 Buffer *buffer = data;
1757 buffer_cycle_colors (buffer);
1763 buffer_set_colors (Buffer *buffer,
1769 if (enabled && buffer->color_cycle_timeout == 0)
1770 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
1771 else if (!enabled && buffer->color_cycle_timeout != 0)
1773 gtk_timeout_remove (buffer->color_cycle_timeout);
1774 buffer->color_cycle_timeout = 0;
1777 tmp = buffer->color_tags;
1784 hue_to_color (hue, &color);
1786 g_object_set (G_OBJECT (tmp->data),
1787 "foreground_gdk", &color,
1791 g_object_set (G_OBJECT (tmp->data),
1792 "foreground_set", FALSE,
1795 hue += 1.0 / N_COLORS;
1797 tmp = g_slist_next (tmp);
1802 buffer_cycle_colors (Buffer *buffer)
1805 gdouble hue = buffer->start_hue;
1807 tmp = buffer->color_tags;
1812 hue_to_color (hue, &color);
1814 g_object_set (G_OBJECT (tmp->data),
1815 "foreground_gdk", &color,
1818 hue += 1.0 / N_COLORS;
1822 tmp = g_slist_next (tmp);
1825 buffer->start_hue += 1.0 / N_COLORS;
1826 if (buffer->start_hue > 1.0)
1827 buffer->start_hue = 0.0;
1831 close_view (View *view)
1833 views = g_slist_remove (views, view);
1834 buffer_unref (view->buffer);
1835 gtk_widget_destroy (view->window);
1836 g_object_unref (G_OBJECT (view->item_factory));
1845 check_close_view (View *view)
1847 if (view->buffer->refcount > 1 ||
1848 check_buffer_saved (view->buffer))
1853 view_set_title (View *view)
1855 char *pretty_name = buffer_pretty_name (view->buffer);
1856 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
1858 gtk_window_set_title (GTK_WINDOW (view->window), title);
1860 g_free (pretty_name);
1865 cursor_set_callback (GtkTextBuffer *buffer,
1866 const GtkTextIter *location,
1870 GtkTextView *text_view;
1872 /* Redraw tab windows if the cursor moves
1873 * on the mapped widget (windows may not exist before realization...
1876 text_view = GTK_TEXT_VIEW (user_data);
1878 if (GTK_WIDGET_MAPPED (text_view) &&
1879 mark == gtk_text_buffer_get_insert (buffer))
1881 GdkWindow *tab_window;
1883 tab_window = gtk_text_view_get_window (text_view,
1884 GTK_TEXT_WINDOW_TOP);
1886 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1888 tab_window = gtk_text_view_get_window (text_view,
1889 GTK_TEXT_WINDOW_BOTTOM);
1891 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1896 tab_stops_expose (GtkWidget *widget,
1897 GdkEventExpose *event,
1904 GdkWindow *bottom_win;
1905 GtkTextView *text_view;
1906 GtkTextWindowType type;
1907 GdkDrawable *target;
1908 gint *positions = NULL;
1910 GtkTextAttributes *attrs;
1912 GtkTextBuffer *buffer;
1915 text_view = GTK_TEXT_VIEW (widget);
1917 /* See if this expose is on the tab stop window */
1918 top_win = gtk_text_view_get_window (text_view,
1919 GTK_TEXT_WINDOW_TOP);
1921 bottom_win = gtk_text_view_get_window (text_view,
1922 GTK_TEXT_WINDOW_BOTTOM);
1924 if (event->window == top_win)
1926 type = GTK_TEXT_WINDOW_TOP;
1929 else if (event->window == bottom_win)
1931 type = GTK_TEXT_WINDOW_BOTTOM;
1932 target = bottom_win;
1937 first_x = event->area.x;
1938 last_x = first_x + event->area.width;
1940 gtk_text_view_window_to_buffer_coords (text_view,
1947 gtk_text_view_window_to_buffer_coords (text_view,
1954 buffer = gtk_text_view_get_buffer (text_view);
1956 gtk_text_buffer_get_iter_at_mark (buffer,
1958 gtk_text_buffer_get_mark (buffer,
1961 attrs = gtk_text_attributes_new ();
1963 gtk_text_iter_get_attributes (&insert, attrs);
1967 size = pango_tab_array_get_size (attrs->tabs);
1969 pango_tab_array_get_tabs (attrs->tabs,
1973 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
1981 gtk_text_attributes_unref (attrs);
1989 positions[i] = PANGO_PIXELS (positions[i]);
1991 gtk_text_view_buffer_to_window_coords (text_view,
1998 gdk_draw_line (target,
1999 widget->style->fg_gc [widget->state],
2012 get_lines (GtkTextView *text_view,
2015 GArray *buffer_coords,
2023 g_array_set_size (buffer_coords, 0);
2024 g_array_set_size (numbers, 0);
2026 /* Get iter at first y */
2027 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
2029 /* For each iter, get its location and add it to the arrays.
2030 * Stop when we pass last_y
2035 while (!gtk_text_iter_is_end (&iter))
2040 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2042 g_array_append_val (buffer_coords, y);
2043 line_num = gtk_text_iter_get_line (&iter);
2044 g_array_append_val (numbers, line_num);
2048 if ((y + height) >= last_y)
2051 gtk_text_iter_forward_line (&iter);
2058 line_numbers_expose (GtkWidget *widget,
2059 GdkEventExpose *event,
2068 GdkWindow *left_win;
2069 GdkWindow *right_win;
2070 PangoLayout *layout;
2071 GtkTextView *text_view;
2072 GtkTextWindowType type;
2073 GdkDrawable *target;
2075 text_view = GTK_TEXT_VIEW (widget);
2077 /* See if this expose is on the line numbers window */
2078 left_win = gtk_text_view_get_window (text_view,
2079 GTK_TEXT_WINDOW_LEFT);
2081 right_win = gtk_text_view_get_window (text_view,
2082 GTK_TEXT_WINDOW_RIGHT);
2084 if (event->window == left_win)
2086 type = GTK_TEXT_WINDOW_LEFT;
2089 else if (event->window == right_win)
2091 type = GTK_TEXT_WINDOW_RIGHT;
2097 first_y = event->area.y;
2098 last_y = first_y + event->area.height;
2100 gtk_text_view_window_to_buffer_coords (text_view,
2107 gtk_text_view_window_to_buffer_coords (text_view,
2114 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2115 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2117 get_lines (text_view,
2124 /* Draw fully internationalized numbers! */
2126 layout = gtk_widget_create_pango_layout (widget, "");
2134 gtk_text_view_buffer_to_window_coords (text_view,
2137 g_array_index (pixels, gint, i),
2141 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2143 pango_layout_set_text (layout, str, -1);
2145 gtk_paint_layout (widget->style,
2147 GTK_WIDGET_STATE (widget),
2160 g_array_free (pixels, TRUE);
2161 g_array_free (numbers, TRUE);
2163 g_object_unref (G_OBJECT (layout));
2169 create_view (Buffer *buffer)
2176 view = g_new0 (View, 1);
2177 views = g_slist_prepend (views, view);
2179 view->buffer = buffer;
2180 buffer_ref (buffer);
2182 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2183 g_object_set_data (G_OBJECT (view->window), "view", view);
2185 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2186 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2188 view->accel_group = gtk_accel_group_new ();
2189 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2190 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2192 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2194 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2196 vbox = gtk_vbox_new (FALSE, 0);
2197 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2199 gtk_box_pack_start (GTK_BOX (vbox),
2200 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2203 sw = gtk_scrolled_window_new (NULL, NULL);
2204 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2205 GTK_POLICY_AUTOMATIC,
2206 GTK_POLICY_AUTOMATIC);
2208 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2209 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2212 /* Draw tab stops in the top and bottom windows. */
2214 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2215 GTK_TEXT_WINDOW_TOP,
2218 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2219 GTK_TEXT_WINDOW_BOTTOM,
2222 gtk_signal_connect (GTK_OBJECT (view->text_view),
2224 GTK_SIGNAL_FUNC (tab_stops_expose),
2227 g_signal_connect (G_OBJECT (view->buffer->buffer),
2229 GTK_SIGNAL_FUNC (cursor_set_callback),
2232 /* Draw line numbers in the side windows; we should really be
2233 * more scientific about what width we set them to.
2235 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2236 GTK_TEXT_WINDOW_RIGHT,
2239 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2240 GTK_TEXT_WINDOW_LEFT,
2243 gtk_signal_connect (GTK_OBJECT (view->text_view),
2245 GTK_SIGNAL_FUNC (line_numbers_expose),
2248 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2249 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2251 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2253 gtk_widget_grab_focus (view->text_view);
2255 view_set_title (view);
2256 view_init_menus (view);
2258 view_add_example_widgets (view);
2260 gtk_widget_show_all (view->window);
2265 view_add_example_widgets (View *view)
2267 GtkTextChildAnchor *anchor;
2270 buffer = view->buffer;
2272 /* REMOVE to test widgets */
2275 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2278 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2282 widget = gtk_button_new_with_label ("Foo");
2284 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2288 gtk_widget_show (widget);
2293 file_exists (const char *filename)
2295 struct stat statbuf;
2297 return stat (filename, &statbuf) == 0;
2302 if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
2304 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2305 putenv ("GTK_IM_MODULE_FILE=../modules/input/gtk.immodules");
2310 main (int argc, char** argv)
2317 gtk_init (&argc, &argv);
2319 buffer = create_buffer ();
2320 view = create_view (buffer);
2321 buffer_unref (buffer);
2323 push_active_window (GTK_WINDOW (view->window));
2324 for (i=1; i < argc; i++)
2328 /* Quick and dirty canonicalization - better should be in GLib
2331 if (!g_path_is_absolute (argv[i]))
2333 char *cwd = g_get_current_dir ();
2334 filename = g_strconcat (cwd, "/", argv[i], NULL);
2340 open_ok_func (filename, view);
2342 if (filename != argv[i])
2345 pop_active_window ();