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, TRUE, FALSE,
1582 &match_start, &match_end,
1586 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1587 &match_start, &match_end);
1594 while (gtk_text_iter_backward_search (&iter, str, TRUE, FALSE,
1595 &match_start, &match_end,
1599 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1600 &match_start, &match_end);
1607 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1610 GTK_DIALOG_DESTROY_WITH_PARENT,
1611 "%d strings found and marked in red",
1614 gtk_signal_connect_object (GTK_OBJECT (dialog),
1616 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1617 GTK_OBJECT (dialog));
1619 gtk_widget_show (dialog);
1623 buffer_search_forward (Buffer *buffer, const char *str,
1626 buffer_search (buffer, str, view, TRUE);
1630 buffer_search_backward (Buffer *buffer, const char *str,
1633 buffer_search (buffer, str, view, FALSE);
1637 buffer_ref (Buffer *buffer)
1643 buffer_unref (Buffer *buffer)
1646 if (buffer->refcount == 0)
1648 buffer_set_colors (buffer, FALSE);
1649 buffers = g_slist_remove (buffers, buffer);
1650 g_object_unref (G_OBJECT (buffer->buffer));
1651 g_free (buffer->filename);
1657 hsv_to_rgb (gdouble *h,
1661 gdouble hue, saturation, value;
1679 f = hue - (int) hue;
1680 p = value * (1.0 - saturation);
1681 q = value * (1.0 - saturation * f);
1682 t = value * (1.0 - saturation * (1.0 - f));
1723 g_assert_not_reached ();
1729 hue_to_color (gdouble hue,
1738 g_return_if_fail (hue <= 1.0);
1740 hsv_to_rgb (&h, &s, &v);
1742 color->red = h * 65535;
1743 color->green = s * 65535;
1744 color->blue = v * 65535;
1749 color_cycle_timeout (gpointer data)
1751 Buffer *buffer = data;
1753 buffer_cycle_colors (buffer);
1759 buffer_set_colors (Buffer *buffer,
1765 if (enabled && buffer->color_cycle_timeout == 0)
1766 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
1767 else if (!enabled && buffer->color_cycle_timeout != 0)
1769 gtk_timeout_remove (buffer->color_cycle_timeout);
1770 buffer->color_cycle_timeout = 0;
1773 tmp = buffer->color_tags;
1780 hue_to_color (hue, &color);
1782 g_object_set (G_OBJECT (tmp->data),
1783 "foreground_gdk", &color,
1787 g_object_set (G_OBJECT (tmp->data),
1788 "foreground_set", FALSE,
1791 hue += 1.0 / N_COLORS;
1793 tmp = g_slist_next (tmp);
1798 buffer_cycle_colors (Buffer *buffer)
1801 gdouble hue = buffer->start_hue;
1803 tmp = buffer->color_tags;
1808 hue_to_color (hue, &color);
1810 g_object_set (G_OBJECT (tmp->data),
1811 "foreground_gdk", &color,
1814 hue += 1.0 / N_COLORS;
1818 tmp = g_slist_next (tmp);
1821 buffer->start_hue += 1.0 / N_COLORS;
1822 if (buffer->start_hue > 1.0)
1823 buffer->start_hue = 0.0;
1827 close_view (View *view)
1829 views = g_slist_remove (views, view);
1830 buffer_unref (view->buffer);
1831 gtk_widget_destroy (view->window);
1832 g_object_unref (G_OBJECT (view->item_factory));
1841 check_close_view (View *view)
1843 if (view->buffer->refcount > 1 ||
1844 check_buffer_saved (view->buffer))
1849 view_set_title (View *view)
1851 char *pretty_name = buffer_pretty_name (view->buffer);
1852 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
1854 gtk_window_set_title (GTK_WINDOW (view->window), title);
1856 g_free (pretty_name);
1861 cursor_set_callback (GtkTextBuffer *buffer,
1862 const GtkTextIter *location,
1866 GtkTextView *text_view;
1868 /* Redraw tab windows if the cursor moves
1869 * on the mapped widget (windows may not exist before realization...
1872 text_view = GTK_TEXT_VIEW (user_data);
1874 if (GTK_WIDGET_MAPPED (text_view) &&
1875 mark == gtk_text_buffer_get_insert (buffer))
1877 GdkWindow *tab_window;
1879 tab_window = gtk_text_view_get_window (text_view,
1880 GTK_TEXT_WINDOW_TOP);
1882 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1884 tab_window = gtk_text_view_get_window (text_view,
1885 GTK_TEXT_WINDOW_BOTTOM);
1887 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1892 tab_stops_expose (GtkWidget *widget,
1893 GdkEventExpose *event,
1900 GdkWindow *bottom_win;
1901 GtkTextView *text_view;
1902 GtkTextWindowType type;
1903 GdkDrawable *target;
1904 gint *positions = NULL;
1906 GtkTextAttributes *attrs;
1908 GtkTextBuffer *buffer;
1911 text_view = GTK_TEXT_VIEW (widget);
1913 /* See if this expose is on the tab stop window */
1914 top_win = gtk_text_view_get_window (text_view,
1915 GTK_TEXT_WINDOW_TOP);
1917 bottom_win = gtk_text_view_get_window (text_view,
1918 GTK_TEXT_WINDOW_BOTTOM);
1920 if (event->window == top_win)
1922 type = GTK_TEXT_WINDOW_TOP;
1925 else if (event->window == bottom_win)
1927 type = GTK_TEXT_WINDOW_BOTTOM;
1928 target = bottom_win;
1933 first_x = event->area.x;
1934 last_x = first_x + event->area.width;
1936 gtk_text_view_window_to_buffer_coords (text_view,
1943 gtk_text_view_window_to_buffer_coords (text_view,
1950 buffer = gtk_text_view_get_buffer (text_view);
1952 gtk_text_buffer_get_iter_at_mark (buffer,
1954 gtk_text_buffer_get_mark (buffer,
1957 attrs = gtk_text_attributes_new ();
1959 gtk_text_iter_get_attributes (&insert, attrs);
1963 size = pango_tab_array_get_size (attrs->tabs);
1965 pango_tab_array_get_tabs (attrs->tabs,
1969 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
1977 gtk_text_attributes_unref (attrs);
1985 positions[i] = PANGO_PIXELS (positions[i]);
1987 gtk_text_view_buffer_to_window_coords (text_view,
1994 gdk_draw_line (target,
1995 widget->style->fg_gc [widget->state],
2008 get_lines (GtkTextView *text_view,
2011 GArray *buffer_coords,
2019 g_array_set_size (buffer_coords, 0);
2020 g_array_set_size (numbers, 0);
2022 /* Get iter at first y */
2023 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
2025 /* For each iter, get its location and add it to the arrays.
2026 * Stop when we pass last_y
2031 while (!gtk_text_iter_is_end (&iter))
2036 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2038 g_array_append_val (buffer_coords, y);
2039 line_num = gtk_text_iter_get_line (&iter);
2040 g_array_append_val (numbers, line_num);
2044 if ((y + height) >= last_y)
2047 gtk_text_iter_forward_line (&iter);
2054 line_numbers_expose (GtkWidget *widget,
2055 GdkEventExpose *event,
2064 GdkWindow *left_win;
2065 GdkWindow *right_win;
2066 PangoLayout *layout;
2067 GtkTextView *text_view;
2068 GtkTextWindowType type;
2069 GdkDrawable *target;
2071 text_view = GTK_TEXT_VIEW (widget);
2073 /* See if this expose is on the line numbers window */
2074 left_win = gtk_text_view_get_window (text_view,
2075 GTK_TEXT_WINDOW_LEFT);
2077 right_win = gtk_text_view_get_window (text_view,
2078 GTK_TEXT_WINDOW_RIGHT);
2080 if (event->window == left_win)
2082 type = GTK_TEXT_WINDOW_LEFT;
2085 else if (event->window == right_win)
2087 type = GTK_TEXT_WINDOW_RIGHT;
2093 first_y = event->area.y;
2094 last_y = first_y + event->area.height;
2096 gtk_text_view_window_to_buffer_coords (text_view,
2103 gtk_text_view_window_to_buffer_coords (text_view,
2110 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2111 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2113 get_lines (text_view,
2120 /* Draw fully internationalized numbers! */
2122 layout = gtk_widget_create_pango_layout (widget, "");
2130 gtk_text_view_buffer_to_window_coords (text_view,
2133 g_array_index (pixels, gint, i),
2137 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2139 pango_layout_set_text (layout, str, -1);
2141 gtk_paint_layout (widget->style,
2143 GTK_WIDGET_STATE (widget),
2156 g_array_free (pixels, TRUE);
2157 g_array_free (numbers, TRUE);
2159 g_object_unref (G_OBJECT (layout));
2165 create_view (Buffer *buffer)
2172 view = g_new0 (View, 1);
2173 views = g_slist_prepend (views, view);
2175 view->buffer = buffer;
2176 buffer_ref (buffer);
2178 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2179 g_object_set_data (G_OBJECT (view->window), "view", view);
2181 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2182 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2184 view->accel_group = gtk_accel_group_new ();
2185 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2186 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2188 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2190 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2192 vbox = gtk_vbox_new (FALSE, 0);
2193 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2195 gtk_box_pack_start (GTK_BOX (vbox),
2196 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2199 sw = gtk_scrolled_window_new (NULL, NULL);
2200 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2201 GTK_POLICY_AUTOMATIC,
2202 GTK_POLICY_AUTOMATIC);
2204 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2205 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2208 /* Draw tab stops in the top and bottom windows. */
2210 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2211 GTK_TEXT_WINDOW_TOP,
2214 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2215 GTK_TEXT_WINDOW_BOTTOM,
2218 gtk_signal_connect (GTK_OBJECT (view->text_view),
2220 GTK_SIGNAL_FUNC (tab_stops_expose),
2223 g_signal_connect (G_OBJECT (view->buffer->buffer),
2225 GTK_SIGNAL_FUNC (cursor_set_callback),
2228 /* Draw line numbers in the side windows; we should really be
2229 * more scientific about what width we set them to.
2231 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2232 GTK_TEXT_WINDOW_RIGHT,
2235 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2236 GTK_TEXT_WINDOW_LEFT,
2239 gtk_signal_connect (GTK_OBJECT (view->text_view),
2241 GTK_SIGNAL_FUNC (line_numbers_expose),
2244 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2245 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2247 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2249 gtk_widget_grab_focus (view->text_view);
2251 view_set_title (view);
2252 view_init_menus (view);
2254 view_add_example_widgets (view);
2256 gtk_widget_show_all (view->window);
2261 view_add_example_widgets (View *view)
2263 GtkTextChildAnchor *anchor;
2266 buffer = view->buffer;
2268 /* REMOVE to test widgets */
2271 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2274 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2278 widget = gtk_button_new_with_label ("Foo");
2280 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2284 gtk_widget_show (widget);
2289 file_exists (const char *filename)
2291 struct stat statbuf;
2293 return stat (filename, &statbuf) == 0;
2298 if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
2300 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2301 putenv ("GTK_IM_MODULE_FILE=../modules/input/gtk.immodules");
2306 main (int argc, char** argv)
2314 gtk_init (&argc, &argv);
2316 buffer = create_buffer ();
2317 view = create_view (buffer);
2318 buffer_unref (buffer);
2320 push_active_window (GTK_WINDOW (view->window));
2321 for (i=1; i < argc; i++)
2325 /* Quick and dirty canonicalization - better should be in GLib
2328 if (!g_path_is_absolute (argv[i]))
2330 char *cwd = g_get_current_dir ();
2331 filename = g_strconcat (cwd, "/", argv[i], NULL);
2337 open_ok_func (filename, view);
2339 if (filename != argv[i])
2342 pop_active_window ();