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 (window);
79 active_window_stack = g_slist_prepend (active_window_stack, window);
83 pop_active_window (void)
85 g_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 = (FileselOKFunc)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 g_signal_connect (GTK_FILE_SELECTION (filesel)->ok_button,
148 G_CALLBACK (filesel_ok_cb), filesel);
149 g_signal_connect_swapped (GTK_FILE_SELECTION (filesel)->cancel_button,
151 G_CALLBACK (gtk_widget_destroy), filesel);
153 g_signal_connect (filesel, "destroy",
154 G_CALLBACK (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 g_signal_stop_emission_by_name (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 g_signal_connect (dialog, "destroy",
230 G_CALLBACK (gtk_main_quit), NULL);
232 /* Catch Escape key presses and have them destroy the dialog
234 g_signal_connect (dialog, "key_press_event",
235 G_CALLBACK (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 g_signal_connect (button, "clicked",
268 G_CALLBACK (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 g_signal_connect (button, "clicked",
284 G_CALLBACK (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 g_signal_connect_swapped (button, "clicked",
299 G_CALLBACK (gtk_object_destroy), 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 */
313 * Example buffer filling code
316 blink_timeout (gpointer data)
319 static gboolean flip = FALSE;
321 tag = GTK_TEXT_TAG (data);
323 g_object_set (G_OBJECT (tag),
324 "foreground", flip ? "blue" : "purple",
334 tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
335 const GtkTextIter *iter, gpointer user_data)
339 char_index = gtk_text_iter_get_offset (iter);
343 case GDK_MOTION_NOTIFY:
344 printf ("Motion event at char %d tag `%s'\n",
345 char_index, tag->name);
348 case GDK_BUTTON_PRESS:
349 printf ("Button press at char %d tag `%s'\n",
350 char_index, tag->name);
353 case GDK_2BUTTON_PRESS:
354 printf ("Double click at char %d tag `%s'\n",
355 char_index, tag->name);
358 case GDK_3BUTTON_PRESS:
359 printf ("Triple click at char %d tag `%s'\n",
360 char_index, tag->name);
363 case GDK_BUTTON_RELEASE:
364 printf ("Button release at char %d tag `%s'\n",
365 char_index, tag->name);
369 case GDK_KEY_RELEASE:
370 printf ("Key event at char %d tag `%s'\n",
371 char_index, tag->name);
374 case GDK_ENTER_NOTIFY:
375 case GDK_LEAVE_NOTIFY:
376 case GDK_PROPERTY_NOTIFY:
377 case GDK_SELECTION_CLEAR:
378 case GDK_SELECTION_REQUEST:
379 case GDK_SELECTION_NOTIFY:
380 case GDK_PROXIMITY_IN:
381 case GDK_PROXIMITY_OUT:
384 case GDK_DRAG_MOTION:
385 case GDK_DRAG_STATUS:
387 case GDK_DROP_FINISHED:
396 setup_tag (GtkTextTag *tag)
398 g_signal_connect (tag,
400 G_CALLBACK (tag_event_handler),
404 static const char *book_closed_xpm[] = {
430 fill_example_buffer (GtkTextBuffer *buffer)
432 GtkTextIter iter, iter2;
434 GtkTextChildAnchor *anchor;
441 /* FIXME this is broken if called twice on a buffer, since
442 * we try to create tags a second time.
445 tag = gtk_text_buffer_create_tag (buffer, "fg_blue", NULL);
448 gtk_timeout_add (1000, blink_timeout, tag);
453 color.red = color.green = 0;
458 g_object_set (G_OBJECT (tag),
459 "foreground_gdk", &color,
460 "background_gdk", &color2,
464 tag = gtk_text_buffer_create_tag (buffer, "fg_red", NULL);
468 color.blue = color.green = 0;
470 g_object_set (G_OBJECT (tag),
471 "rise", -4 * PANGO_SCALE,
472 "foreground_gdk", &color,
475 tag = gtk_text_buffer_create_tag (buffer, "bg_green", NULL);
479 color.blue = color.red = 0;
480 color.green = 0xffff;
481 g_object_set (G_OBJECT (tag),
482 "background_gdk", &color,
486 tag = gtk_text_buffer_create_tag (buffer, "strikethrough", NULL);
490 g_object_set (G_OBJECT (tag),
491 "strikethrough", TRUE,
495 tag = gtk_text_buffer_create_tag (buffer, "underline", NULL);
499 g_object_set (G_OBJECT (tag),
500 "underline", PANGO_UNDERLINE_SINGLE,
505 g_object_set (G_OBJECT (tag),
506 "underline", PANGO_UNDERLINE_SINGLE,
509 tag = gtk_text_buffer_create_tag (buffer, "centered", NULL);
511 g_object_set (G_OBJECT (tag),
512 "justification", GTK_JUSTIFY_CENTER,
515 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote", NULL);
517 g_object_set (G_OBJECT (tag),
518 "wrap_mode", GTK_WRAP_WORD,
519 "direction", GTK_TEXT_DIR_RTL,
526 tag = gtk_text_buffer_create_tag (buffer, "negative_indent", NULL);
528 g_object_set (G_OBJECT (tag),
532 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
534 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
536 g_object_ref (anchor);
538 g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
539 (GDestroyNotify) g_object_unref);
541 pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
546 GtkTextMark * temp_mark;
548 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
550 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
552 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",
555 gtk_text_buffer_insert (buffer, &iter, str, -1);
559 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
561 gtk_text_buffer_insert (buffer, &iter,
562 "(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"
563 /* This is UTF8 stuff, Emacs doesn't
564 really know how to display it */
565 "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);
568 gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
571 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
572 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
574 gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
576 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
577 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
579 gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
581 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
582 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
584 gtk_text_buffer_apply_tag_by_name (buffer, "strikethrough", &iter, &iter2);
586 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
587 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
589 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
591 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
592 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
594 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
596 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
597 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
599 gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
602 gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
603 gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
605 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
606 gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
608 gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
609 gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
610 gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1);
611 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
612 gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
614 gtk_text_buffer_insert_with_tags (buffer, &iter,
615 "Paragraph with negative indentation. blah blah blah blah blah. The quick brown fox jumped over the lazy dog.\n",
617 gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (buffer),
624 g_object_unref (pixbuf);
626 printf ("%d lines %d chars\n",
627 gtk_text_buffer_get_line_count (buffer),
628 gtk_text_buffer_get_char_count (buffer));
630 /* Move cursor to start */
631 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
632 gtk_text_buffer_place_cursor (buffer, &iter);
634 gtk_text_buffer_set_modified (buffer, FALSE);
638 fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
643 GtkTextIter iter, end;
645 f = fopen (filename, "r");
649 gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
650 filename, g_strerror (errno));
651 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
656 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
660 const char *leftover;
661 int to_read = 2047 - remaining;
663 count = fread (buf + remaining, 1, to_read, f);
664 buf[count + remaining] = '\0';
666 g_utf8_validate (buf, count + remaining, &leftover);
668 g_assert (g_utf8_validate (buf, leftover - buf, NULL));
669 gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
671 remaining = (buf + remaining + count) - leftover;
672 g_memmove (buf, leftover, remaining);
674 if (remaining > 6 || count < to_read)
680 gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
681 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
685 /* We had a newline in the buffer to begin with. (The buffer always contains
686 * a newline, so we delete to the end of the buffer to clean up.
688 gtk_text_buffer_get_end_iter (buffer, &end);
689 gtk_text_buffer_delete (buffer, &iter, &end);
691 gtk_text_buffer_set_modified (buffer, FALSE);
697 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
699 View *view = view_from_widget (window);
701 push_active_window (GTK_WINDOW (window));
702 check_close_view (view);
703 pop_active_window ();
713 get_empty_view (View *view)
715 if (!view->buffer->filename &&
716 !gtk_text_buffer_get_modified (view->buffer->buffer))
719 return create_view (create_buffer ());
723 view_from_widget (GtkWidget *widget)
725 if (GTK_IS_MENU_ITEM (widget))
727 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
728 return g_object_get_data (G_OBJECT (item_factory), "view");
732 GtkWidget *app = gtk_widget_get_toplevel (widget);
733 return g_object_get_data (G_OBJECT (app), "view");
738 do_new (gpointer callback_data,
739 guint callback_action,
742 create_view (create_buffer ());
746 do_new_view (gpointer callback_data,
747 guint callback_action,
750 View *view = view_from_widget (widget);
752 create_view (view->buffer);
756 open_ok_func (const char *filename, gpointer data)
759 View *new_view = get_empty_view (view);
761 if (!fill_file_buffer (new_view->buffer->buffer, filename))
763 if (new_view != view)
764 close_view (new_view);
769 g_free (new_view->buffer->filename);
770 new_view->buffer->filename = g_strdup (filename);
771 buffer_filename_set (new_view->buffer);
778 do_open (gpointer callback_data,
779 guint callback_action,
782 View *view = view_from_widget (widget);
784 push_active_window (GTK_WINDOW (view->window));
785 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
786 pop_active_window ();
790 do_save_as (gpointer callback_data,
791 guint callback_action,
794 View *view = view_from_widget (widget);
796 push_active_window (GTK_WINDOW (view->window));
797 save_as_buffer (view->buffer);
798 pop_active_window ();
802 do_save (gpointer callback_data,
803 guint callback_action,
806 View *view = view_from_widget (widget);
808 push_active_window (GTK_WINDOW (view->window));
809 if (!view->buffer->filename)
810 do_save_as (callback_data, callback_action, widget);
812 save_buffer (view->buffer);
813 pop_active_window ();
817 do_close (gpointer callback_data,
818 guint callback_action,
821 View *view = view_from_widget (widget);
823 push_active_window (GTK_WINDOW (view->window));
824 check_close_view (view);
825 pop_active_window ();
829 do_exit (gpointer callback_data,
830 guint callback_action,
833 View *view = view_from_widget (widget);
835 GSList *tmp_list = buffers;
837 push_active_window (GTK_WINDOW (view->window));
840 if (!check_buffer_saved (tmp_list->data))
843 tmp_list = tmp_list->next;
847 pop_active_window ();
851 do_example (gpointer callback_data,
852 guint callback_action,
855 View *view = view_from_widget (widget);
858 new_view = get_empty_view (view);
860 fill_example_buffer (new_view->buffer->buffer);
862 view_add_example_widgets (new_view);
867 do_insert_and_scroll (gpointer callback_data,
868 guint callback_action,
871 View *view = view_from_widget (widget);
872 GtkTextBuffer *buffer;
873 GtkTextIter start, end;
876 buffer = view->buffer->buffer;
878 gtk_text_buffer_get_bounds (buffer, &start, &end);
879 mark = gtk_text_buffer_create_mark (buffer, NULL, &end, /* right grav */ FALSE);
881 gtk_text_buffer_insert (buffer, &end,
882 "Hello this is multiple lines of text\n"
883 "Line 1\n" "Line 2\n"
884 "Line 3\n" "Line 4\n"
888 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view->text_view), mark,
890 gtk_text_buffer_delete_mark (buffer, mark);
894 do_wrap_changed (gpointer callback_data,
895 guint callback_action,
898 View *view = view_from_widget (widget);
900 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
904 do_direction_changed (gpointer callback_data,
905 guint callback_action,
908 View *view = view_from_widget (widget);
910 gtk_widget_set_direction (view->text_view, callback_action);
911 gtk_widget_queue_resize (view->text_view);
916 do_spacing_changed (gpointer callback_data,
917 guint callback_action,
920 View *view = view_from_widget (widget);
924 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
926 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
928 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
933 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
935 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
937 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
943 do_editable_changed (gpointer callback_data,
944 guint callback_action,
947 View *view = view_from_widget (widget);
949 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
953 do_cursor_visible_changed (gpointer callback_data,
954 guint callback_action,
957 View *view = view_from_widget (widget);
959 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
963 do_color_cycle_changed (gpointer callback_data,
964 guint callback_action,
967 View *view = view_from_widget (widget);
969 buffer_set_colors (view->buffer, callback_action);
973 do_apply_editable (gpointer callback_data,
974 guint callback_action,
977 View *view = view_from_widget (widget);
981 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
986 gtk_text_buffer_remove_tag (view->buffer->buffer,
987 view->buffer->not_editable_tag,
992 gtk_text_buffer_apply_tag (view->buffer->buffer,
993 view->buffer->not_editable_tag,
1000 do_apply_invisible (gpointer callback_data,
1001 guint callback_action,
1004 View *view = view_from_widget (widget);
1008 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1011 if (callback_action)
1013 gtk_text_buffer_remove_tag (view->buffer->buffer,
1014 view->buffer->invisible_tag,
1019 gtk_text_buffer_apply_tag (view->buffer->buffer,
1020 view->buffer->invisible_tag,
1027 do_apply_tabs (gpointer callback_data,
1028 guint callback_action,
1031 View *view = view_from_widget (widget);
1035 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1038 if (callback_action)
1040 gtk_text_buffer_remove_tag (view->buffer->buffer,
1041 view->buffer->custom_tabs_tag,
1046 gtk_text_buffer_apply_tag (view->buffer->buffer,
1047 view->buffer->custom_tabs_tag,
1054 do_apply_colors (gpointer callback_data,
1055 guint callback_action,
1058 View *view = view_from_widget (widget);
1059 Buffer *buffer = view->buffer;
1063 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1066 if (!callback_action)
1070 tmp = buffer->color_tags;
1073 gtk_text_buffer_remove_tag (view->buffer->buffer,
1076 tmp = g_slist_next (tmp);
1083 tmp = buffer->color_tags;
1087 gboolean done = FALSE;
1090 gtk_text_iter_forward_char (&next);
1091 gtk_text_iter_forward_char (&next);
1093 if (gtk_text_iter_compare (&next, &end) >= 0)
1099 gtk_text_buffer_apply_tag (view->buffer->buffer,
1108 tmp = g_slist_next (tmp);
1110 tmp = buffer->color_tags;
1117 do_remove_tags (gpointer callback_data,
1118 guint callback_action,
1121 View *view = view_from_widget (widget);
1125 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1128 gtk_text_buffer_remove_all_tags (view->buffer->buffer,
1134 do_properties (gpointer callback_data,
1135 guint callback_action,
1138 View *view = view_from_widget (widget);
1140 create_prop_editor (G_OBJECT (view->text_view), 0);
1150 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1152 GtkTextBuffer *buffer;
1154 GtkTextIter start, end;
1155 gchar *search_string;
1157 if (response_id != RESPONSE_FORWARD &&
1158 response_id != RESPONSE_BACKWARD)
1160 gtk_widget_destroy (dialog);
1164 buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
1166 gtk_text_buffer_get_bounds (buffer, &start, &end);
1168 search_string = gtk_text_iter_get_text (&start, &end);
1170 g_print ("Searching for `%s'\n", search_string);
1172 if (response_id == RESPONSE_FORWARD)
1173 buffer_search_forward (view->buffer, search_string, view);
1174 else if (response_id == RESPONSE_BACKWARD)
1175 buffer_search_backward (view->buffer, search_string, view);
1177 g_free (search_string);
1179 gtk_widget_destroy (dialog);
1183 do_search (gpointer callback_data,
1184 guint callback_action,
1187 View *view = view_from_widget (widget);
1189 GtkWidget *search_text;
1190 GtkTextBuffer *buffer;
1192 dialog = gtk_dialog_new_with_buttons ("Search",
1193 GTK_WINDOW (view->window),
1194 GTK_DIALOG_DESTROY_WITH_PARENT,
1195 "Forward", RESPONSE_FORWARD,
1196 "Backward", RESPONSE_BACKWARD,
1198 GTK_RESPONSE_NONE, NULL);
1201 buffer = gtk_text_buffer_new (NULL);
1203 search_text = gtk_text_view_new_with_buffer (buffer);
1205 g_object_unref (buffer);
1207 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1211 g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
1213 g_signal_connect (dialog,
1215 G_CALLBACK (dialog_response_callback),
1218 gtk_widget_show (search_text);
1220 gtk_widget_grab_focus (search_text);
1222 gtk_widget_show_all (dialog);
1227 /* position is in coordinate system of text_view_move_child */
1236 movable_child_callback (GtkWidget *child,
1240 ChildMoveInfo *info;
1241 GtkTextView *text_view;
1243 text_view = GTK_TEXT_VIEW (data);
1245 g_return_val_if_fail (GTK_IS_EVENT_BOX (child), FALSE);
1246 g_return_val_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (text_view), FALSE);
1248 info = g_object_get_data (G_OBJECT (child),
1249 "testtext-move-info");
1253 info = g_new (ChildMoveInfo, 1);
1257 g_object_set_data_full (G_OBJECT (child),
1258 "testtext-move-info",
1263 switch (event->type)
1265 case GDK_BUTTON_PRESS:
1266 if (info->button < 0)
1268 if (gdk_pointer_grab (event->button.window,
1270 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1271 GDK_BUTTON_RELEASE_MASK,
1274 event->button.time) != GDK_GRAB_SUCCESS)
1277 info->button = event->button.button;
1279 info->start_x = child->allocation.x;
1280 info->start_y = child->allocation.y;
1281 info->click_x = child->allocation.x + event->button.x;
1282 info->click_y = child->allocation.y + event->button.y;
1286 case GDK_BUTTON_RELEASE:
1287 if (info->button < 0)
1290 if (info->button == event->button.button)
1294 gdk_pointer_ungrab (event->button.time);
1297 /* convert to window coords from event box coords */
1298 x = info->start_x + (event->button.x + child->allocation.x - info->click_x);
1299 y = info->start_y + (event->button.y + child->allocation.y - info->click_y);
1301 gtk_text_view_move_child (text_view,
1307 case GDK_MOTION_NOTIFY:
1311 if (info->button < 0)
1314 gdk_window_get_pointer (child->window, &x, &y, NULL); /* ensure more events */
1316 /* to window coords from event box coords */
1317 x += child->allocation.x;
1318 y += child->allocation.y;
1320 x = info->start_x + (x - info->click_x);
1321 y = info->start_y + (y - info->click_y);
1323 gtk_text_view_move_child (text_view,
1337 add_movable_child (GtkTextView *text_view,
1338 GtkTextWindowType window)
1340 GtkWidget *event_box;
1344 label = gtk_label_new ("Drag me around");
1346 event_box = gtk_event_box_new ();
1347 gtk_widget_add_events (event_box,
1348 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1349 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
1352 color.green = color.blue = 0;
1353 gtk_widget_modify_bg (event_box, GTK_STATE_NORMAL, &color);
1355 gtk_container_add (GTK_CONTAINER (event_box), label);
1357 gtk_widget_show_all (event_box);
1359 g_signal_connect (event_box, "event",
1360 G_CALLBACK (movable_child_callback),
1363 gtk_text_view_add_child_in_window (text_view,
1370 do_add_children (gpointer callback_data,
1371 guint callback_action,
1374 View *view = view_from_widget (widget);
1376 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1377 GTK_TEXT_WINDOW_WIDGET);
1378 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1379 GTK_TEXT_WINDOW_LEFT);
1380 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1381 GTK_TEXT_WINDOW_RIGHT);
1385 do_add_focus_children (gpointer callback_data,
1386 guint callback_action,
1389 View *view = view_from_widget (widget);
1391 GtkTextChildAnchor *anchor;
1393 GtkTextView *text_view;
1395 text_view = GTK_TEXT_VIEW (view->text_view);
1397 child = gtk_button_new_with_mnemonic ("Button _A in widget->window");
1399 gtk_text_view_add_child_in_window (text_view,
1401 GTK_TEXT_WINDOW_WIDGET,
1404 child = gtk_button_new_with_mnemonic ("Button _B in widget->window");
1406 gtk_text_view_add_child_in_window (text_view,
1408 GTK_TEXT_WINDOW_WIDGET,
1411 child = gtk_button_new_with_mnemonic ("Button _C in left window");
1413 gtk_text_view_add_child_in_window (text_view,
1415 GTK_TEXT_WINDOW_LEFT,
1418 child = gtk_button_new_with_mnemonic ("Button _D in right window");
1420 gtk_text_view_add_child_in_window (text_view,
1422 GTK_TEXT_WINDOW_RIGHT,
1425 gtk_text_buffer_get_start_iter (view->buffer->buffer, &iter);
1427 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1429 child = gtk_button_new_with_mnemonic ("Button _E in buffer");
1431 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1433 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1435 child = gtk_button_new_with_mnemonic ("Button _F in buffer");
1437 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1439 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1441 child = gtk_button_new_with_mnemonic ("Button _G in buffer");
1443 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1445 /* show all the buttons */
1446 gtk_widget_show_all (view->text_view);
1450 view_init_menus (View *view)
1452 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1453 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1454 GtkWidget *menu_item = NULL;
1458 case GTK_TEXT_DIR_LTR:
1459 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1461 case GTK_TEXT_DIR_RTL:
1462 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1469 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1474 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1477 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1480 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
1487 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1490 static GtkItemFactoryEntry menu_items[] =
1492 { "/_File", NULL, 0, 0, "<Branch>" },
1493 { "/File/_New", "<control>N", do_new, 0, NULL },
1494 { "/File/New _View", NULL, do_new_view, 0, NULL },
1495 { "/File/_Open", "<control>O", do_open, 0, NULL },
1496 { "/File/_Save", "<control>S", do_save, 0, NULL },
1497 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1498 { "/File/sep1", NULL, 0, 0, "<Separator>" },
1499 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1500 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1502 { "/_Edit", NULL, 0, 0, "<Branch>" },
1503 { "/Edit/Find...", NULL, do_search, 0, NULL },
1505 { "/_Settings", NULL, 0, 0, "<Branch>" },
1506 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAP_NONE, "<RadioItem>" },
1507 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAP_WORD, "/Settings/Wrap Off" },
1508 { "/Settings/Wrap _Chars", NULL, do_wrap_changed, GTK_WRAP_CHAR, "/Settings/Wrap Off" },
1509 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1510 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1511 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1512 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1514 { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "<RadioItem>" },
1515 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" },
1516 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1518 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1519 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1521 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1522 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1523 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1524 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1525 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1526 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1527 { "/_Attributes", NULL, 0, 0, "<Branch>" },
1528 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1529 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1530 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1531 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1532 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1533 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1534 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1535 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
1536 { "/Attributes/Remove all tags", NULL, do_remove_tags, 0, NULL },
1537 { "/Attributes/Properties", NULL, do_properties, 0, NULL },
1538 { "/_Test", NULL, 0, 0, "<Branch>" },
1539 { "/Test/_Example", NULL, do_example, 0, NULL },
1540 { "/Test/_Insert and scroll", NULL, do_insert_and_scroll, 0, NULL },
1541 { "/Test/_Add fixed children", NULL, do_add_children, 0, NULL },
1542 { "/Test/A_dd focusable children", NULL, do_add_focus_children, 0, NULL },
1546 save_buffer (Buffer *buffer)
1548 GtkTextIter start, end;
1550 gboolean result = FALSE;
1551 gboolean have_backup = FALSE;
1552 gchar *bak_filename;
1555 g_return_val_if_fail (buffer->filename != NULL, FALSE);
1557 bak_filename = g_strconcat (buffer->filename, "~", NULL);
1559 if (rename (buffer->filename, bak_filename) != 0)
1561 if (errno != ENOENT)
1563 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1564 buffer->filename, bak_filename, g_strerror (errno));
1565 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1573 file = fopen (buffer->filename, "w");
1576 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1577 buffer->filename, bak_filename, g_strerror (errno));
1578 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1582 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1583 gtk_text_buffer_get_end_iter (buffer->buffer, &end);
1585 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1587 if (fputs (chars, file) == EOF ||
1588 fclose (file) == EOF)
1590 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1591 buffer->filename, g_strerror (errno));
1592 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1600 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
1606 if (!result && have_backup)
1608 if (rename (bak_filename, buffer->filename) != 0)
1610 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1611 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1612 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1617 g_free (bak_filename);
1623 save_as_ok_func (const char *filename, gpointer data)
1625 Buffer *buffer = data;
1626 char *old_filename = buffer->filename;
1628 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1630 struct stat statbuf;
1632 if (stat (filename, &statbuf) == 0)
1634 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1635 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1643 buffer->filename = g_strdup (filename);
1645 if (save_buffer (buffer))
1647 g_free (old_filename);
1648 buffer_filename_set (buffer);
1653 g_free (buffer->filename);
1654 buffer->filename = old_filename;
1660 save_as_buffer (Buffer *buffer)
1662 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1666 check_buffer_saved (Buffer *buffer)
1668 if (gtk_text_buffer_get_modified (buffer->buffer))
1670 char *pretty_name = buffer_pretty_name (buffer);
1671 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1674 g_free (pretty_name);
1676 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1680 return save_as_buffer (buffer);
1681 else if (result == 1)
1693 create_buffer (void)
1696 PangoTabArray *tabs;
1699 buffer = g_new (Buffer, 1);
1701 buffer->buffer = gtk_text_buffer_new (NULL);
1703 buffer->refcount = 1;
1704 buffer->filename = NULL;
1705 buffer->untitled_serial = -1;
1707 buffer->color_tags = NULL;
1708 buffer->color_cycle_timeout = 0;
1709 buffer->start_hue = 0.0;
1712 while (i < N_COLORS)
1716 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL, NULL);
1718 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1724 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1725 "invisible", TRUE, NULL);
1728 buffer->not_editable_tag =
1729 gtk_text_buffer_create_tag (buffer->buffer, NULL,
1731 "foreground", "purple", NULL);
1733 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1734 "foreground", "red", NULL);
1736 tabs = pango_tab_array_new_with_positions (4,
1741 PANGO_TAB_LEFT, 120);
1743 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1745 "foreground", "green", NULL);
1747 pango_tab_array_free (tabs);
1749 buffers = g_slist_prepend (buffers, buffer);
1755 buffer_pretty_name (Buffer *buffer)
1757 if (buffer->filename)
1760 char *result = g_path_get_basename (buffer->filename);
1761 p = strchr (result, '/');
1769 if (buffer->untitled_serial == -1)
1770 buffer->untitled_serial = untitled_serial++;
1772 if (buffer->untitled_serial == 1)
1773 return g_strdup ("Untitled");
1775 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1780 buffer_filename_set (Buffer *buffer)
1782 GSList *tmp_list = views;
1786 View *view = tmp_list->data;
1788 if (view->buffer == buffer)
1789 view_set_title (view);
1791 tmp_list = tmp_list->next;
1796 buffer_search (Buffer *buffer,
1802 GtkTextIter start, end;
1806 /* remove tag from whole buffer */
1807 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1808 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1811 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1812 gtk_text_buffer_get_mark (buffer->buffer,
1818 GtkTextIter match_start, match_end;
1822 while (gtk_text_iter_forward_search (&iter, str,
1823 GTK_TEXT_SEARCH_VISIBLE_ONLY |
1824 GTK_TEXT_SEARCH_TEXT_ONLY,
1825 &match_start, &match_end,
1829 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1830 &match_start, &match_end);
1837 while (gtk_text_iter_backward_search (&iter, str,
1838 GTK_TEXT_SEARCH_VISIBLE_ONLY |
1839 GTK_TEXT_SEARCH_TEXT_ONLY,
1840 &match_start, &match_end,
1844 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1845 &match_start, &match_end);
1852 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1853 GTK_DIALOG_DESTROY_WITH_PARENT,
1856 "%d strings found and marked in red",
1859 g_signal_connect_swapped (dialog,
1861 G_CALLBACK (gtk_widget_destroy), dialog);
1863 gtk_widget_show (dialog);
1867 buffer_search_forward (Buffer *buffer, const char *str,
1870 buffer_search (buffer, str, view, TRUE);
1874 buffer_search_backward (Buffer *buffer, const char *str,
1877 buffer_search (buffer, str, view, FALSE);
1881 buffer_ref (Buffer *buffer)
1887 buffer_unref (Buffer *buffer)
1890 if (buffer->refcount == 0)
1892 buffer_set_colors (buffer, FALSE);
1893 buffers = g_slist_remove (buffers, buffer);
1894 g_object_unref (buffer->buffer);
1895 g_free (buffer->filename);
1901 hsv_to_rgb (gdouble *h,
1905 gdouble hue, saturation, value;
1923 f = hue - (int) hue;
1924 p = value * (1.0 - saturation);
1925 q = value * (1.0 - saturation * f);
1926 t = value * (1.0 - saturation * (1.0 - f));
1967 g_assert_not_reached ();
1973 hue_to_color (gdouble hue,
1982 g_return_if_fail (hue <= 1.0);
1984 hsv_to_rgb (&h, &s, &v);
1986 color->red = h * 65535;
1987 color->green = s * 65535;
1988 color->blue = v * 65535;
1993 color_cycle_timeout (gpointer data)
1995 Buffer *buffer = data;
1997 buffer_cycle_colors (buffer);
2003 buffer_set_colors (Buffer *buffer,
2009 if (enabled && buffer->color_cycle_timeout == 0)
2010 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
2011 else if (!enabled && buffer->color_cycle_timeout != 0)
2013 gtk_timeout_remove (buffer->color_cycle_timeout);
2014 buffer->color_cycle_timeout = 0;
2017 tmp = buffer->color_tags;
2024 hue_to_color (hue, &color);
2026 g_object_set (G_OBJECT (tmp->data),
2027 "foreground_gdk", &color,
2031 g_object_set (G_OBJECT (tmp->data),
2032 "foreground_set", FALSE,
2035 hue += 1.0 / N_COLORS;
2037 tmp = g_slist_next (tmp);
2042 buffer_cycle_colors (Buffer *buffer)
2045 gdouble hue = buffer->start_hue;
2047 tmp = buffer->color_tags;
2052 hue_to_color (hue, &color);
2054 g_object_set (G_OBJECT (tmp->data),
2055 "foreground_gdk", &color,
2058 hue += 1.0 / N_COLORS;
2062 tmp = g_slist_next (tmp);
2065 buffer->start_hue += 1.0 / N_COLORS;
2066 if (buffer->start_hue > 1.0)
2067 buffer->start_hue = 0.0;
2071 close_view (View *view)
2073 views = g_slist_remove (views, view);
2074 buffer_unref (view->buffer);
2075 gtk_widget_destroy (view->window);
2076 g_object_unref (view->item_factory);
2085 check_close_view (View *view)
2087 if (view->buffer->refcount > 1 ||
2088 check_buffer_saved (view->buffer))
2093 view_set_title (View *view)
2095 char *pretty_name = buffer_pretty_name (view->buffer);
2096 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
2098 gtk_window_set_title (GTK_WINDOW (view->window), title);
2100 g_free (pretty_name);
2105 cursor_set_callback (GtkTextBuffer *buffer,
2106 const GtkTextIter *location,
2110 GtkTextView *text_view;
2112 /* Redraw tab windows if the cursor moves
2113 * on the mapped widget (windows may not exist before realization...
2116 text_view = GTK_TEXT_VIEW (user_data);
2118 if (GTK_WIDGET_MAPPED (text_view) &&
2119 mark == gtk_text_buffer_get_insert (buffer))
2121 GdkWindow *tab_window;
2123 tab_window = gtk_text_view_get_window (text_view,
2124 GTK_TEXT_WINDOW_TOP);
2126 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
2128 tab_window = gtk_text_view_get_window (text_view,
2129 GTK_TEXT_WINDOW_BOTTOM);
2131 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
2136 tab_stops_expose (GtkWidget *widget,
2137 GdkEventExpose *event,
2144 GdkWindow *bottom_win;
2145 GtkTextView *text_view;
2146 GtkTextWindowType type;
2147 GdkDrawable *target;
2148 gint *positions = NULL;
2150 GtkTextAttributes *attrs;
2152 GtkTextBuffer *buffer;
2155 text_view = GTK_TEXT_VIEW (widget);
2157 /* See if this expose is on the tab stop window */
2158 top_win = gtk_text_view_get_window (text_view,
2159 GTK_TEXT_WINDOW_TOP);
2161 bottom_win = gtk_text_view_get_window (text_view,
2162 GTK_TEXT_WINDOW_BOTTOM);
2164 if (event->window == top_win)
2166 type = GTK_TEXT_WINDOW_TOP;
2169 else if (event->window == bottom_win)
2171 type = GTK_TEXT_WINDOW_BOTTOM;
2172 target = bottom_win;
2177 first_x = event->area.x;
2178 last_x = first_x + event->area.width;
2180 gtk_text_view_window_to_buffer_coords (text_view,
2187 gtk_text_view_window_to_buffer_coords (text_view,
2194 buffer = gtk_text_view_get_buffer (text_view);
2196 gtk_text_buffer_get_iter_at_mark (buffer,
2198 gtk_text_buffer_get_mark (buffer,
2201 attrs = gtk_text_attributes_new ();
2203 gtk_text_iter_get_attributes (&insert, attrs);
2207 size = pango_tab_array_get_size (attrs->tabs);
2209 pango_tab_array_get_tabs (attrs->tabs,
2213 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
2221 gtk_text_attributes_unref (attrs);
2229 positions[i] = PANGO_PIXELS (positions[i]);
2231 gtk_text_view_buffer_to_window_coords (text_view,
2238 gdk_draw_line (target,
2239 widget->style->fg_gc [widget->state],
2252 get_lines (GtkTextView *text_view,
2255 GArray *buffer_coords,
2263 g_array_set_size (buffer_coords, 0);
2264 g_array_set_size (numbers, 0);
2266 /* Get iter at first y */
2267 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
2269 /* For each iter, get its location and add it to the arrays.
2270 * Stop when we pass last_y
2275 while (!gtk_text_iter_is_end (&iter))
2280 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2282 g_array_append_val (buffer_coords, y);
2283 line_num = gtk_text_iter_get_line (&iter);
2284 g_array_append_val (numbers, line_num);
2288 if ((y + height) >= last_y)
2291 gtk_text_iter_forward_line (&iter);
2298 line_numbers_expose (GtkWidget *widget,
2299 GdkEventExpose *event,
2308 GdkWindow *left_win;
2309 GdkWindow *right_win;
2310 PangoLayout *layout;
2311 GtkTextView *text_view;
2312 GtkTextWindowType type;
2313 GdkDrawable *target;
2315 text_view = GTK_TEXT_VIEW (widget);
2317 /* See if this expose is on the line numbers window */
2318 left_win = gtk_text_view_get_window (text_view,
2319 GTK_TEXT_WINDOW_LEFT);
2321 right_win = gtk_text_view_get_window (text_view,
2322 GTK_TEXT_WINDOW_RIGHT);
2324 if (event->window == left_win)
2326 type = GTK_TEXT_WINDOW_LEFT;
2329 else if (event->window == right_win)
2331 type = GTK_TEXT_WINDOW_RIGHT;
2337 first_y = event->area.y;
2338 last_y = first_y + event->area.height;
2340 gtk_text_view_window_to_buffer_coords (text_view,
2347 gtk_text_view_window_to_buffer_coords (text_view,
2354 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2355 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2357 get_lines (text_view,
2364 /* Draw fully internationalized numbers! */
2366 layout = gtk_widget_create_pango_layout (widget, "");
2374 gtk_text_view_buffer_to_window_coords (text_view,
2377 g_array_index (pixels, gint, i),
2381 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2383 pango_layout_set_text (layout, str, -1);
2385 gtk_paint_layout (widget->style,
2387 GTK_WIDGET_STATE (widget),
2400 g_array_free (pixels, TRUE);
2401 g_array_free (numbers, TRUE);
2403 g_object_unref (layout);
2405 /* don't stop emission, need to draw children */
2410 create_view (Buffer *buffer)
2417 view = g_new0 (View, 1);
2418 views = g_slist_prepend (views, view);
2420 view->buffer = buffer;
2421 buffer_ref (buffer);
2423 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2424 g_object_set_data (G_OBJECT (view->window), "view", view);
2426 g_signal_connect (view->window, "delete_event",
2427 G_CALLBACK (delete_event_cb), NULL);
2429 view->accel_group = gtk_accel_group_new ();
2430 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2431 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2433 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2435 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2437 vbox = gtk_vbox_new (FALSE, 0);
2438 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2440 gtk_box_pack_start (GTK_BOX (vbox),
2441 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2444 sw = gtk_scrolled_window_new (NULL, NULL);
2445 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2446 GTK_POLICY_AUTOMATIC,
2447 GTK_POLICY_AUTOMATIC);
2449 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2450 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2453 /* Make sure border width works, no real reason to do this other than testing */
2454 gtk_container_set_border_width (GTK_CONTAINER (view->text_view),
2457 /* Draw tab stops in the top and bottom windows. */
2459 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2460 GTK_TEXT_WINDOW_TOP,
2463 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2464 GTK_TEXT_WINDOW_BOTTOM,
2467 g_signal_connect (view->text_view,
2469 G_CALLBACK (tab_stops_expose),
2472 g_signal_connect (view->buffer->buffer,
2474 G_CALLBACK (cursor_set_callback),
2477 /* Draw line numbers in the side windows; we should really be
2478 * more scientific about what width we set them to.
2480 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2481 GTK_TEXT_WINDOW_RIGHT,
2484 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2485 GTK_TEXT_WINDOW_LEFT,
2488 g_signal_connect (view->text_view,
2490 G_CALLBACK (line_numbers_expose),
2493 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2494 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2496 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2498 gtk_widget_grab_focus (view->text_view);
2500 view_set_title (view);
2501 view_init_menus (view);
2503 view_add_example_widgets (view);
2505 gtk_widget_show_all (view->window);
2510 view_add_example_widgets (View *view)
2512 GtkTextChildAnchor *anchor;
2515 buffer = view->buffer;
2517 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2520 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2524 widget = gtk_button_new_with_label ("Foo");
2526 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2530 gtk_widget_show (widget);
2537 if (g_file_test ("../gdk-pixbuf/libpixbufloader-pnm.la",
2538 G_FILE_TEST_EXISTS))
2540 putenv ("GDK_PIXBUF_MODULE_FILE=../gdk-pixbuf/gdk-pixbuf.loaders");
2541 putenv ("GTK_IM_MODULE_FILE=../modules/input/gtk.immodules");
2546 main (int argc, char** argv)
2553 gtk_init (&argc, &argv);
2555 buffer = create_buffer ();
2556 view = create_view (buffer);
2557 buffer_unref (buffer);
2559 push_active_window (GTK_WINDOW (view->window));
2560 for (i=1; i < argc; i++)
2564 /* Quick and dirty canonicalization - better should be in GLib
2567 if (!g_path_is_absolute (argv[i]))
2569 char *cwd = g_get_current_dir ();
2570 filename = g_strconcat (cwd, "/", argv[i], NULL);
2576 open_ok_func (filename, view);
2578 if (filename != argv[i])
2581 pop_active_window ();