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 = (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", (gpointer)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 tag = gtk_text_buffer_create_tag (buffer, "negative_indent", NULL);
524 g_object_set (G_OBJECT (tag),
528 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
530 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
532 g_object_ref (G_OBJECT (anchor));
534 g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
535 (GDestroyNotify) g_object_unref);
537 pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
542 GtkTextMark * temp_mark;
544 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
546 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
548 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",
551 gtk_text_buffer_insert (buffer, &iter, str, -1);
555 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
557 gtk_text_buffer_insert (buffer, &iter,
558 "(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"
559 /* This is UTF8 stuff, Emacs doesn't
560 really know how to display it */
561 "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);
564 gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
567 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
568 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
570 gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
572 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
573 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
575 gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
577 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
578 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
580 gtk_text_buffer_apply_tag_by_name (buffer, "strikethrough", &iter, &iter2);
582 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
583 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
585 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
587 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
588 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
590 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
592 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
593 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
595 gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
598 gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
599 gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
601 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
602 gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
604 gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
605 gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
606 gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1);
607 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
608 gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
610 gtk_text_buffer_insert_with_tags (buffer, &iter,
611 "Paragraph with negative indentation. blah blah blah blah blah. The quick brown fox jumped over the lazy dog.\n",
613 gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (buffer),
620 g_object_unref (G_OBJECT (pixbuf));
622 printf ("%d lines %d chars\n",
623 gtk_text_buffer_get_line_count (buffer),
624 gtk_text_buffer_get_char_count (buffer));
626 /* Move cursor to start */
627 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
628 gtk_text_buffer_place_cursor (buffer, &iter);
630 gtk_text_buffer_set_modified (buffer, FALSE);
634 fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
639 GtkTextIter iter, end;
641 f = fopen (filename, "r");
645 gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
646 filename, g_strerror (errno));
647 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
652 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
656 const char *leftover;
657 int to_read = 2047 - remaining;
659 count = fread (buf + remaining, 1, to_read, f);
660 buf[count + remaining] = '\0';
662 g_utf8_validate (buf, count + remaining, &leftover);
664 g_assert (g_utf8_validate (buf, leftover - buf, NULL));
665 gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
667 remaining = (buf + remaining + count) - leftover;
668 g_memmove (buf, leftover, remaining);
670 if (remaining > 6 || count < to_read)
676 gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
677 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
681 /* We had a newline in the buffer to begin with. (The buffer always contains
682 * a newline, so we delete to the end of the buffer to clean up.
684 gtk_text_buffer_get_end_iter (buffer, &end);
685 gtk_text_buffer_delete (buffer, &iter, &end);
687 gtk_text_buffer_set_modified (buffer, FALSE);
693 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
695 View *view = view_from_widget (window);
697 push_active_window (GTK_WINDOW (window));
698 check_close_view (view);
699 pop_active_window ();
709 get_empty_view (View *view)
711 if (!view->buffer->filename &&
712 !gtk_text_buffer_get_modified (view->buffer->buffer))
715 return create_view (create_buffer ());
719 view_from_widget (GtkWidget *widget)
721 if (GTK_IS_MENU_ITEM (widget))
723 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
724 return g_object_get_data (G_OBJECT (item_factory), "view");
728 GtkWidget *app = gtk_widget_get_toplevel (widget);
729 return g_object_get_data (G_OBJECT (app), "view");
734 do_new (gpointer callback_data,
735 guint callback_action,
738 create_view (create_buffer ());
742 do_new_view (gpointer callback_data,
743 guint callback_action,
746 View *view = view_from_widget (widget);
748 create_view (view->buffer);
752 open_ok_func (const char *filename, gpointer data)
755 View *new_view = get_empty_view (view);
757 if (!fill_file_buffer (new_view->buffer->buffer, filename))
759 if (new_view != view)
760 close_view (new_view);
765 g_free (new_view->buffer->filename);
766 new_view->buffer->filename = g_strdup (filename);
767 buffer_filename_set (new_view->buffer);
774 do_open (gpointer callback_data,
775 guint callback_action,
778 View *view = view_from_widget (widget);
780 push_active_window (GTK_WINDOW (view->window));
781 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
782 pop_active_window ();
786 do_save_as (gpointer callback_data,
787 guint callback_action,
790 View *view = view_from_widget (widget);
792 push_active_window (GTK_WINDOW (view->window));
793 save_as_buffer (view->buffer);
794 pop_active_window ();
798 do_save (gpointer callback_data,
799 guint callback_action,
802 View *view = view_from_widget (widget);
804 push_active_window (GTK_WINDOW (view->window));
805 if (!view->buffer->filename)
806 do_save_as (callback_data, callback_action, widget);
808 save_buffer (view->buffer);
809 pop_active_window ();
813 do_close (gpointer callback_data,
814 guint callback_action,
817 View *view = view_from_widget (widget);
819 push_active_window (GTK_WINDOW (view->window));
820 check_close_view (view);
821 pop_active_window ();
825 do_exit (gpointer callback_data,
826 guint callback_action,
829 View *view = view_from_widget (widget);
831 GSList *tmp_list = buffers;
833 push_active_window (GTK_WINDOW (view->window));
836 if (!check_buffer_saved (tmp_list->data))
839 tmp_list = tmp_list->next;
843 pop_active_window ();
847 do_example (gpointer callback_data,
848 guint callback_action,
851 View *view = view_from_widget (widget);
854 new_view = get_empty_view (view);
856 fill_example_buffer (new_view->buffer->buffer);
858 view_add_example_widgets (new_view);
863 do_insert_and_scroll (gpointer callback_data,
864 guint callback_action,
867 View *view = view_from_widget (widget);
868 GtkTextBuffer *buffer;
869 GtkTextIter start, end;
872 buffer = view->buffer->buffer;
874 gtk_text_buffer_get_bounds (buffer, &start, &end);
875 mark = gtk_text_buffer_create_mark (buffer, NULL, &end, /* right grav */ FALSE);
877 gtk_text_buffer_insert (buffer, &end,
878 "Hello this is multiple lines of text\n"
879 "Line 1\n" "Line 2\n"
880 "Line 3\n" "Line 4\n"
884 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view->text_view), mark,
886 gtk_text_buffer_delete_mark (buffer, mark);
890 do_wrap_changed (gpointer callback_data,
891 guint callback_action,
894 View *view = view_from_widget (widget);
896 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
900 do_direction_changed (gpointer callback_data,
901 guint callback_action,
904 View *view = view_from_widget (widget);
906 gtk_widget_set_direction (view->text_view, callback_action);
907 gtk_widget_queue_resize (view->text_view);
912 do_spacing_changed (gpointer callback_data,
913 guint callback_action,
916 View *view = view_from_widget (widget);
920 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
922 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
924 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
929 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
931 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
933 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
939 do_editable_changed (gpointer callback_data,
940 guint callback_action,
943 View *view = view_from_widget (widget);
945 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
949 do_cursor_visible_changed (gpointer callback_data,
950 guint callback_action,
953 View *view = view_from_widget (widget);
955 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
959 do_color_cycle_changed (gpointer callback_data,
960 guint callback_action,
963 View *view = view_from_widget (widget);
965 buffer_set_colors (view->buffer, callback_action);
969 do_apply_editable (gpointer callback_data,
970 guint callback_action,
973 View *view = view_from_widget (widget);
977 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
982 gtk_text_buffer_remove_tag (view->buffer->buffer,
983 view->buffer->not_editable_tag,
988 gtk_text_buffer_apply_tag (view->buffer->buffer,
989 view->buffer->not_editable_tag,
996 do_apply_invisible (gpointer callback_data,
997 guint callback_action,
1000 View *view = view_from_widget (widget);
1004 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1007 if (callback_action)
1009 gtk_text_buffer_remove_tag (view->buffer->buffer,
1010 view->buffer->invisible_tag,
1015 gtk_text_buffer_apply_tag (view->buffer->buffer,
1016 view->buffer->invisible_tag,
1023 do_apply_tabs (gpointer callback_data,
1024 guint callback_action,
1027 View *view = view_from_widget (widget);
1031 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1034 if (callback_action)
1036 gtk_text_buffer_remove_tag (view->buffer->buffer,
1037 view->buffer->custom_tabs_tag,
1042 gtk_text_buffer_apply_tag (view->buffer->buffer,
1043 view->buffer->custom_tabs_tag,
1050 do_apply_colors (gpointer callback_data,
1051 guint callback_action,
1054 View *view = view_from_widget (widget);
1055 Buffer *buffer = view->buffer;
1059 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1062 if (!callback_action)
1066 tmp = buffer->color_tags;
1069 gtk_text_buffer_remove_tag (view->buffer->buffer,
1072 tmp = g_slist_next (tmp);
1079 tmp = buffer->color_tags;
1083 gboolean done = FALSE;
1086 gtk_text_iter_forward_char (&next);
1087 gtk_text_iter_forward_char (&next);
1089 if (gtk_text_iter_compare (&next, &end) >= 0)
1095 gtk_text_buffer_apply_tag (view->buffer->buffer,
1104 tmp = g_slist_next (tmp);
1106 tmp = buffer->color_tags;
1113 do_remove_tags (gpointer callback_data,
1114 guint callback_action,
1117 View *view = view_from_widget (widget);
1121 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1124 gtk_text_buffer_remove_all_tags (view->buffer->buffer,
1130 do_properties (gpointer callback_data,
1131 guint callback_action,
1134 View *view = view_from_widget (widget);
1136 create_prop_editor (G_OBJECT (view->text_view), 0);
1146 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1148 GtkTextBuffer *buffer;
1150 GtkTextIter start, end;
1151 gchar *search_string;
1153 if (response_id != RESPONSE_FORWARD &&
1154 response_id != RESPONSE_BACKWARD)
1156 gtk_widget_destroy (dialog);
1160 buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
1162 gtk_text_buffer_get_bounds (buffer, &start, &end);
1164 search_string = gtk_text_iter_get_text (&start, &end);
1166 g_print ("Searching for `%s'\n", search_string);
1168 if (response_id == RESPONSE_FORWARD)
1169 buffer_search_forward (view->buffer, search_string, view);
1170 else if (response_id == RESPONSE_BACKWARD)
1171 buffer_search_backward (view->buffer, search_string, view);
1173 g_free (search_string);
1175 gtk_widget_destroy (dialog);
1179 do_search (gpointer callback_data,
1180 guint callback_action,
1183 View *view = view_from_widget (widget);
1185 GtkWidget *search_text;
1186 GtkTextBuffer *buffer;
1188 dialog = gtk_dialog_new_with_buttons ("Search",
1189 GTK_WINDOW (view->window),
1190 GTK_DIALOG_DESTROY_WITH_PARENT,
1191 "Forward", RESPONSE_FORWARD,
1192 "Backward", RESPONSE_BACKWARD,
1194 GTK_RESPONSE_NONE, NULL);
1197 buffer = gtk_text_buffer_new (NULL);
1199 search_text = gtk_text_view_new_with_buffer (buffer);
1201 g_object_unref (G_OBJECT (buffer));
1203 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1207 g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
1209 gtk_signal_connect (GTK_OBJECT (dialog),
1211 GTK_SIGNAL_FUNC (dialog_response_callback),
1214 gtk_widget_show (search_text);
1216 gtk_widget_grab_focus (search_text);
1218 gtk_widget_show_all (dialog);
1223 /* position is in coordinate system of text_view_move_child */
1232 movable_child_callback (GtkWidget *child,
1236 ChildMoveInfo *info;
1237 GtkTextView *text_view;
1239 text_view = GTK_TEXT_VIEW (data);
1241 g_return_val_if_fail (GTK_IS_EVENT_BOX (child), FALSE);
1242 g_return_val_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (text_view), FALSE);
1244 info = g_object_get_data (G_OBJECT (child),
1245 "testtext-move-info");
1249 info = g_new (ChildMoveInfo, 1);
1253 g_object_set_data_full (G_OBJECT (child),
1254 "testtext-move-info",
1259 switch (event->type)
1261 case GDK_BUTTON_PRESS:
1262 if (info->button < 0)
1264 if (gdk_pointer_grab (event->button.window,
1266 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1267 GDK_BUTTON_RELEASE_MASK,
1270 event->button.time) != GDK_GRAB_SUCCESS)
1273 info->button = event->button.button;
1275 info->start_x = child->allocation.x;
1276 info->start_y = child->allocation.y;
1277 info->click_x = child->allocation.x + event->button.x;
1278 info->click_y = child->allocation.y + event->button.y;
1282 case GDK_BUTTON_RELEASE:
1283 if (info->button < 0)
1286 if (info->button == event->button.button)
1290 gdk_pointer_ungrab (event->button.time);
1293 /* convert to window coords from event box coords */
1294 x = info->start_x + (event->button.x + child->allocation.x - info->click_x);
1295 y = info->start_y + (event->button.y + child->allocation.y - info->click_y);
1297 gtk_text_view_move_child (text_view,
1303 case GDK_MOTION_NOTIFY:
1307 if (info->button < 0)
1310 gdk_window_get_pointer (child->window, &x, &y, NULL); /* ensure more events */
1312 /* to window coords from event box coords */
1313 x += child->allocation.x;
1314 y += child->allocation.y;
1316 x = info->start_x + (x - info->click_x);
1317 y = info->start_y + (y - info->click_y);
1319 gtk_text_view_move_child (text_view,
1333 add_movable_child (GtkTextView *text_view,
1334 GtkTextWindowType window)
1336 GtkWidget *event_box;
1340 label = gtk_label_new ("Drag me around");
1342 event_box = gtk_event_box_new ();
1343 gtk_widget_add_events (event_box,
1344 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1345 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
1348 color.green = color.blue = 0;
1349 gtk_widget_modify_bg (event_box, GTK_STATE_NORMAL, &color);
1351 gtk_container_add (GTK_CONTAINER (event_box), label);
1353 gtk_widget_show_all (event_box);
1355 g_signal_connect (G_OBJECT (event_box), "event",
1356 G_CALLBACK (movable_child_callback),
1359 gtk_text_view_add_child_in_window (text_view,
1366 do_add_children (gpointer callback_data,
1367 guint callback_action,
1370 View *view = view_from_widget (widget);
1372 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1373 GTK_TEXT_WINDOW_WIDGET);
1374 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1375 GTK_TEXT_WINDOW_LEFT);
1376 add_movable_child (GTK_TEXT_VIEW (view->text_view),
1377 GTK_TEXT_WINDOW_RIGHT);
1381 do_add_focus_children (gpointer callback_data,
1382 guint callback_action,
1385 View *view = view_from_widget (widget);
1387 GtkTextChildAnchor *anchor;
1389 GtkTextView *text_view;
1391 text_view = GTK_TEXT_VIEW (view->text_view);
1393 child = gtk_button_new_with_mnemonic ("Button _A in widget->window");
1395 gtk_text_view_add_child_in_window (text_view,
1397 GTK_TEXT_WINDOW_WIDGET,
1400 child = gtk_button_new_with_mnemonic ("Button _B in widget->window");
1402 gtk_text_view_add_child_in_window (text_view,
1404 GTK_TEXT_WINDOW_WIDGET,
1407 child = gtk_button_new_with_mnemonic ("Button _C in left window");
1409 gtk_text_view_add_child_in_window (text_view,
1411 GTK_TEXT_WINDOW_LEFT,
1414 child = gtk_button_new_with_mnemonic ("Button _D in right window");
1416 gtk_text_view_add_child_in_window (text_view,
1418 GTK_TEXT_WINDOW_RIGHT,
1421 gtk_text_buffer_get_start_iter (view->buffer->buffer, &iter);
1423 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1425 child = gtk_button_new_with_mnemonic ("Button _E in buffer");
1427 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1429 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1431 child = gtk_button_new_with_mnemonic ("Button _F in buffer");
1433 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1435 anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
1437 child = gtk_button_new_with_mnemonic ("Button _G in buffer");
1439 gtk_text_view_add_child_at_anchor (text_view, child, anchor);
1441 /* show all the buttons */
1442 gtk_widget_show_all (view->text_view);
1446 view_init_menus (View *view)
1448 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1449 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1450 GtkWidget *menu_item = NULL;
1454 case GTK_TEXT_DIR_LTR:
1455 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1457 case GTK_TEXT_DIR_RTL:
1458 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1465 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1470 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1473 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1476 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
1483 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1486 static GtkItemFactoryEntry menu_items[] =
1488 { "/_File", NULL, 0, 0, "<Branch>" },
1489 { "/File/_New", "<control>N", do_new, 0, NULL },
1490 { "/File/New _View", NULL, do_new_view, 0, NULL },
1491 { "/File/_Open", "<control>O", do_open, 0, NULL },
1492 { "/File/_Save", "<control>S", do_save, 0, NULL },
1493 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1494 { "/File/sep1", NULL, 0, 0, "<Separator>" },
1495 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1496 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1498 { "/_Edit", NULL, 0, 0, "<Branch>" },
1499 { "/Edit/Find...", NULL, do_search, 0, NULL },
1501 { "/_Settings", NULL, 0, 0, "<Branch>" },
1502 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAP_NONE, "<RadioItem>" },
1503 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAP_WORD, "/Settings/Wrap Off" },
1504 { "/Settings/Wrap _Chars", NULL, do_wrap_changed, GTK_WRAP_CHAR, "/Settings/Wrap Off" },
1505 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1506 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1507 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1508 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1510 { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "<RadioItem>" },
1511 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" },
1512 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1514 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1515 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1517 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1518 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1519 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1520 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1521 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1522 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1523 { "/_Attributes", NULL, 0, 0, "<Branch>" },
1524 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1525 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1526 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1527 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1528 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1529 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1530 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1531 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
1532 { "/Attributes/Remove all tags", NULL, do_remove_tags, 0, NULL },
1533 { "/Attributes/Properties", NULL, do_properties, 0, NULL },
1534 { "/_Test", NULL, 0, 0, "<Branch>" },
1535 { "/Test/_Example", NULL, do_example, 0, NULL },
1536 { "/Test/_Insert and scroll", NULL, do_insert_and_scroll, 0, NULL },
1537 { "/Test/_Add fixed children", NULL, do_add_children, 0, NULL },
1538 { "/Test/A_dd focusable children", NULL, do_add_focus_children, 0, NULL },
1542 save_buffer (Buffer *buffer)
1544 GtkTextIter start, end;
1546 gboolean result = FALSE;
1547 gboolean have_backup = FALSE;
1548 gchar *bak_filename;
1551 g_return_val_if_fail (buffer->filename != NULL, FALSE);
1553 bak_filename = g_strconcat (buffer->filename, "~", NULL);
1555 if (rename (buffer->filename, bak_filename) != 0)
1557 if (errno != ENOENT)
1559 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1560 buffer->filename, bak_filename, g_strerror (errno));
1561 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1569 file = fopen (buffer->filename, "w");
1572 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1573 buffer->filename, bak_filename, g_strerror (errno));
1574 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1578 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1579 gtk_text_buffer_get_end_iter (buffer->buffer, &end);
1581 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1583 if (fputs (chars, file) == EOF ||
1584 fclose (file) == EOF)
1586 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1587 buffer->filename, g_strerror (errno));
1588 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1596 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
1602 if (!result && have_backup)
1604 if (rename (bak_filename, buffer->filename) != 0)
1606 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1607 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1608 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1613 g_free (bak_filename);
1619 save_as_ok_func (const char *filename, gpointer data)
1621 Buffer *buffer = data;
1622 char *old_filename = buffer->filename;
1624 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1626 struct stat statbuf;
1628 if (stat (filename, &statbuf) == 0)
1630 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1631 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1639 buffer->filename = g_strdup (filename);
1641 if (save_buffer (buffer))
1643 g_free (old_filename);
1644 buffer_filename_set (buffer);
1649 g_free (buffer->filename);
1650 buffer->filename = old_filename;
1656 save_as_buffer (Buffer *buffer)
1658 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1662 check_buffer_saved (Buffer *buffer)
1664 if (gtk_text_buffer_get_modified (buffer->buffer))
1666 char *pretty_name = buffer_pretty_name (buffer);
1667 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1670 g_free (pretty_name);
1672 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1676 return save_as_buffer (buffer);
1677 else if (result == 1)
1689 create_buffer (void)
1692 PangoTabArray *tabs;
1695 buffer = g_new (Buffer, 1);
1697 buffer->buffer = gtk_text_buffer_new (NULL);
1699 buffer->refcount = 1;
1700 buffer->filename = NULL;
1701 buffer->untitled_serial = -1;
1703 buffer->color_tags = NULL;
1704 buffer->color_cycle_timeout = 0;
1705 buffer->start_hue = 0.0;
1708 while (i < N_COLORS)
1712 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL, NULL);
1714 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1720 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1721 "invisible", TRUE, NULL);
1724 buffer->not_editable_tag =
1725 gtk_text_buffer_create_tag (buffer->buffer, NULL,
1727 "foreground", "purple", NULL);
1729 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1730 "foreground", "red", NULL);
1732 tabs = pango_tab_array_new_with_positions (4,
1737 PANGO_TAB_LEFT, 120);
1739 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1741 "foreground", "green", NULL);
1743 pango_tab_array_free (tabs);
1745 buffers = g_slist_prepend (buffers, buffer);
1751 buffer_pretty_name (Buffer *buffer)
1753 if (buffer->filename)
1756 char *result = g_path_get_basename (buffer->filename);
1757 p = strchr (result, '/');
1765 if (buffer->untitled_serial == -1)
1766 buffer->untitled_serial = untitled_serial++;
1768 if (buffer->untitled_serial == 1)
1769 return g_strdup ("Untitled");
1771 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1776 buffer_filename_set (Buffer *buffer)
1778 GSList *tmp_list = views;
1782 View *view = tmp_list->data;
1784 if (view->buffer == buffer)
1785 view_set_title (view);
1787 tmp_list = tmp_list->next;
1792 buffer_search (Buffer *buffer,
1798 GtkTextIter start, end;
1802 /* remove tag from whole buffer */
1803 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1804 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1807 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1808 gtk_text_buffer_get_mark (buffer->buffer,
1814 GtkTextIter match_start, match_end;
1818 while (gtk_text_iter_forward_search (&iter, str,
1819 GTK_TEXT_SEARCH_VISIBLE_ONLY |
1820 GTK_TEXT_SEARCH_TEXT_ONLY,
1821 &match_start, &match_end,
1825 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1826 &match_start, &match_end);
1833 while (gtk_text_iter_backward_search (&iter, str,
1834 GTK_TEXT_SEARCH_VISIBLE_ONLY |
1835 GTK_TEXT_SEARCH_TEXT_ONLY,
1836 &match_start, &match_end,
1840 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1841 &match_start, &match_end);
1848 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1849 GTK_DIALOG_DESTROY_WITH_PARENT,
1852 "%d strings found and marked in red",
1855 gtk_signal_connect_object (GTK_OBJECT (dialog),
1857 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1858 GTK_OBJECT (dialog));
1860 gtk_widget_show (dialog);
1864 buffer_search_forward (Buffer *buffer, const char *str,
1867 buffer_search (buffer, str, view, TRUE);
1871 buffer_search_backward (Buffer *buffer, const char *str,
1874 buffer_search (buffer, str, view, FALSE);
1878 buffer_ref (Buffer *buffer)
1884 buffer_unref (Buffer *buffer)
1887 if (buffer->refcount == 0)
1889 buffer_set_colors (buffer, FALSE);
1890 buffers = g_slist_remove (buffers, buffer);
1891 g_object_unref (G_OBJECT (buffer->buffer));
1892 g_free (buffer->filename);
1898 hsv_to_rgb (gdouble *h,
1902 gdouble hue, saturation, value;
1920 f = hue - (int) hue;
1921 p = value * (1.0 - saturation);
1922 q = value * (1.0 - saturation * f);
1923 t = value * (1.0 - saturation * (1.0 - f));
1964 g_assert_not_reached ();
1970 hue_to_color (gdouble hue,
1979 g_return_if_fail (hue <= 1.0);
1981 hsv_to_rgb (&h, &s, &v);
1983 color->red = h * 65535;
1984 color->green = s * 65535;
1985 color->blue = v * 65535;
1990 color_cycle_timeout (gpointer data)
1992 Buffer *buffer = data;
1994 buffer_cycle_colors (buffer);
2000 buffer_set_colors (Buffer *buffer,
2006 if (enabled && buffer->color_cycle_timeout == 0)
2007 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
2008 else if (!enabled && buffer->color_cycle_timeout != 0)
2010 gtk_timeout_remove (buffer->color_cycle_timeout);
2011 buffer->color_cycle_timeout = 0;
2014 tmp = buffer->color_tags;
2021 hue_to_color (hue, &color);
2023 g_object_set (G_OBJECT (tmp->data),
2024 "foreground_gdk", &color,
2028 g_object_set (G_OBJECT (tmp->data),
2029 "foreground_set", FALSE,
2032 hue += 1.0 / N_COLORS;
2034 tmp = g_slist_next (tmp);
2039 buffer_cycle_colors (Buffer *buffer)
2042 gdouble hue = buffer->start_hue;
2044 tmp = buffer->color_tags;
2049 hue_to_color (hue, &color);
2051 g_object_set (G_OBJECT (tmp->data),
2052 "foreground_gdk", &color,
2055 hue += 1.0 / N_COLORS;
2059 tmp = g_slist_next (tmp);
2062 buffer->start_hue += 1.0 / N_COLORS;
2063 if (buffer->start_hue > 1.0)
2064 buffer->start_hue = 0.0;
2068 close_view (View *view)
2070 views = g_slist_remove (views, view);
2071 buffer_unref (view->buffer);
2072 gtk_widget_destroy (view->window);
2073 g_object_unref (G_OBJECT (view->item_factory));
2082 check_close_view (View *view)
2084 if (view->buffer->refcount > 1 ||
2085 check_buffer_saved (view->buffer))
2090 view_set_title (View *view)
2092 char *pretty_name = buffer_pretty_name (view->buffer);
2093 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
2095 gtk_window_set_title (GTK_WINDOW (view->window), title);
2097 g_free (pretty_name);
2102 cursor_set_callback (GtkTextBuffer *buffer,
2103 const GtkTextIter *location,
2107 GtkTextView *text_view;
2109 /* Redraw tab windows if the cursor moves
2110 * on the mapped widget (windows may not exist before realization...
2113 text_view = GTK_TEXT_VIEW (user_data);
2115 if (GTK_WIDGET_MAPPED (text_view) &&
2116 mark == gtk_text_buffer_get_insert (buffer))
2118 GdkWindow *tab_window;
2120 tab_window = gtk_text_view_get_window (text_view,
2121 GTK_TEXT_WINDOW_TOP);
2123 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
2125 tab_window = gtk_text_view_get_window (text_view,
2126 GTK_TEXT_WINDOW_BOTTOM);
2128 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
2133 tab_stops_expose (GtkWidget *widget,
2134 GdkEventExpose *event,
2141 GdkWindow *bottom_win;
2142 GtkTextView *text_view;
2143 GtkTextWindowType type;
2144 GdkDrawable *target;
2145 gint *positions = NULL;
2147 GtkTextAttributes *attrs;
2149 GtkTextBuffer *buffer;
2152 text_view = GTK_TEXT_VIEW (widget);
2154 /* See if this expose is on the tab stop window */
2155 top_win = gtk_text_view_get_window (text_view,
2156 GTK_TEXT_WINDOW_TOP);
2158 bottom_win = gtk_text_view_get_window (text_view,
2159 GTK_TEXT_WINDOW_BOTTOM);
2161 if (event->window == top_win)
2163 type = GTK_TEXT_WINDOW_TOP;
2166 else if (event->window == bottom_win)
2168 type = GTK_TEXT_WINDOW_BOTTOM;
2169 target = bottom_win;
2174 first_x = event->area.x;
2175 last_x = first_x + event->area.width;
2177 gtk_text_view_window_to_buffer_coords (text_view,
2184 gtk_text_view_window_to_buffer_coords (text_view,
2191 buffer = gtk_text_view_get_buffer (text_view);
2193 gtk_text_buffer_get_iter_at_mark (buffer,
2195 gtk_text_buffer_get_mark (buffer,
2198 attrs = gtk_text_attributes_new ();
2200 gtk_text_iter_get_attributes (&insert, attrs);
2204 size = pango_tab_array_get_size (attrs->tabs);
2206 pango_tab_array_get_tabs (attrs->tabs,
2210 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
2218 gtk_text_attributes_unref (attrs);
2226 positions[i] = PANGO_PIXELS (positions[i]);
2228 gtk_text_view_buffer_to_window_coords (text_view,
2235 gdk_draw_line (target,
2236 widget->style->fg_gc [widget->state],
2249 get_lines (GtkTextView *text_view,
2252 GArray *buffer_coords,
2260 g_array_set_size (buffer_coords, 0);
2261 g_array_set_size (numbers, 0);
2263 /* Get iter at first y */
2264 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
2266 /* For each iter, get its location and add it to the arrays.
2267 * Stop when we pass last_y
2272 while (!gtk_text_iter_is_end (&iter))
2277 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2279 g_array_append_val (buffer_coords, y);
2280 line_num = gtk_text_iter_get_line (&iter);
2281 g_array_append_val (numbers, line_num);
2285 if ((y + height) >= last_y)
2288 gtk_text_iter_forward_line (&iter);
2295 line_numbers_expose (GtkWidget *widget,
2296 GdkEventExpose *event,
2305 GdkWindow *left_win;
2306 GdkWindow *right_win;
2307 PangoLayout *layout;
2308 GtkTextView *text_view;
2309 GtkTextWindowType type;
2310 GdkDrawable *target;
2312 text_view = GTK_TEXT_VIEW (widget);
2314 /* See if this expose is on the line numbers window */
2315 left_win = gtk_text_view_get_window (text_view,
2316 GTK_TEXT_WINDOW_LEFT);
2318 right_win = gtk_text_view_get_window (text_view,
2319 GTK_TEXT_WINDOW_RIGHT);
2321 if (event->window == left_win)
2323 type = GTK_TEXT_WINDOW_LEFT;
2326 else if (event->window == right_win)
2328 type = GTK_TEXT_WINDOW_RIGHT;
2334 first_y = event->area.y;
2335 last_y = first_y + event->area.height;
2337 gtk_text_view_window_to_buffer_coords (text_view,
2344 gtk_text_view_window_to_buffer_coords (text_view,
2351 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2352 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2354 get_lines (text_view,
2361 /* Draw fully internationalized numbers! */
2363 layout = gtk_widget_create_pango_layout (widget, "");
2371 gtk_text_view_buffer_to_window_coords (text_view,
2374 g_array_index (pixels, gint, i),
2378 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2380 pango_layout_set_text (layout, str, -1);
2382 gtk_paint_layout (widget->style,
2384 GTK_WIDGET_STATE (widget),
2397 g_array_free (pixels, TRUE);
2398 g_array_free (numbers, TRUE);
2400 g_object_unref (G_OBJECT (layout));
2402 /* don't stop emission, need to draw children */
2407 create_view (Buffer *buffer)
2414 view = g_new0 (View, 1);
2415 views = g_slist_prepend (views, view);
2417 view->buffer = buffer;
2418 buffer_ref (buffer);
2420 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2421 g_object_set_data (G_OBJECT (view->window), "view", view);
2423 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2424 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2426 view->accel_group = gtk_accel_group_new ();
2427 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2428 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2430 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2432 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2434 vbox = gtk_vbox_new (FALSE, 0);
2435 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2437 gtk_box_pack_start (GTK_BOX (vbox),
2438 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2441 sw = gtk_scrolled_window_new (NULL, NULL);
2442 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2443 GTK_POLICY_AUTOMATIC,
2444 GTK_POLICY_AUTOMATIC);
2446 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2447 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2450 /* Make sure border width works, no real reason to do this other than testing */
2451 gtk_container_set_border_width (GTK_CONTAINER (view->text_view),
2454 /* Draw tab stops in the top and bottom windows. */
2456 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2457 GTK_TEXT_WINDOW_TOP,
2460 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2461 GTK_TEXT_WINDOW_BOTTOM,
2464 gtk_signal_connect (GTK_OBJECT (view->text_view),
2466 GTK_SIGNAL_FUNC (tab_stops_expose),
2469 g_signal_connect (G_OBJECT (view->buffer->buffer),
2471 GTK_SIGNAL_FUNC (cursor_set_callback),
2474 /* Draw line numbers in the side windows; we should really be
2475 * more scientific about what width we set them to.
2477 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2478 GTK_TEXT_WINDOW_RIGHT,
2481 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2482 GTK_TEXT_WINDOW_LEFT,
2485 gtk_signal_connect (GTK_OBJECT (view->text_view),
2487 GTK_SIGNAL_FUNC (line_numbers_expose),
2490 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2491 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2493 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2495 gtk_widget_grab_focus (view->text_view);
2497 view_set_title (view);
2498 view_init_menus (view);
2500 view_add_example_widgets (view);
2502 gtk_widget_show_all (view->window);
2507 view_add_example_widgets (View *view)
2509 GtkTextChildAnchor *anchor;
2512 buffer = view->buffer;
2514 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2517 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2521 widget = gtk_button_new_with_label ("Foo");
2523 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2527 gtk_widget_show (widget);
2532 file_exists (const char *filename)
2534 struct stat statbuf;
2536 return stat (filename, &statbuf) == 0;
2541 if (file_exists ("../gdk-pixbuf/libpixbufloader-pnm.la"))
2543 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2544 putenv ("GTK_IM_MODULE_FILE=../modules/input/gtk.immodules");
2549 main (int argc, char** argv)
2556 gtk_init (&argc, &argv);
2558 buffer = create_buffer ();
2559 view = create_view (buffer);
2560 buffer_unref (buffer);
2562 push_active_window (GTK_WINDOW (view->window));
2563 for (i=1; i < argc; i++)
2567 /* Quick and dirty canonicalization - better should be in GLib
2570 if (!g_path_is_absolute (argv[i]))
2572 char *cwd = g_get_current_dir ();
2573 filename = g_strconcat (cwd, "/", argv[i], NULL);
2579 open_ok_func (filename, view);
2581 if (filename != argv[i])
2584 pop_active_window ();