8 #include <gdk/gdkkeysyms.h>
10 #include "prop-editor.h"
12 typedef struct _Buffer Buffer;
13 typedef struct _View View;
15 static gint untitled_serial = 1;
17 GSList *active_window_stack = NULL;
22 GtkTextBuffer *buffer;
25 GtkTextTag *invisible_tag;
26 GtkTextTag *not_editable_tag;
27 GtkTextTag *found_text_tag;
28 GtkTextTag *custom_tabs_tag;
30 guint color_cycle_timeout;
38 GtkAccelGroup *accel_group;
39 GtkItemFactory *item_factory;
43 static void push_active_window (GtkWindow *window);
44 static void pop_active_window (void);
45 static GtkWindow *get_active_window (void);
47 static Buffer * create_buffer (void);
48 static gboolean check_buffer_saved (Buffer *buffer);
49 static gboolean save_buffer (Buffer *buffer);
50 static gboolean save_as_buffer (Buffer *buffer);
51 static char * buffer_pretty_name (Buffer *buffer);
52 static void buffer_filename_set (Buffer *buffer);
53 static void buffer_search_forward (Buffer *buffer,
56 static void buffer_search_backward (Buffer *buffer,
59 static void buffer_set_colors (Buffer *buffer,
61 static void buffer_cycle_colors (Buffer *buffer);
63 static View *view_from_widget (GtkWidget *widget);
65 static View *create_view (Buffer *buffer);
66 static void check_close_view (View *view);
67 static void close_view (View *view);
68 static void view_set_title (View *view);
69 static void view_init_menus (View *view);
70 static void view_add_example_widgets (View *view);
72 GSList *buffers = NULL;
76 push_active_window (GtkWindow *window)
78 g_object_ref (G_OBJECT (window));
79 active_window_stack = g_slist_prepend (active_window_stack, window);
83 pop_active_window (void)
85 gtk_object_unref (active_window_stack->data);
86 active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack);
90 get_active_window (void)
92 if (active_window_stack)
93 return active_window_stack->data;
99 * Filesel utility function
102 typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data);
105 filesel_ok_cb (GtkWidget *button, GtkWidget *filesel)
107 FileselOKFunc ok_func = g_object_get_data (G_OBJECT (filesel), "ok-func");
108 gpointer data = g_object_get_data (G_OBJECT (filesel), "ok-data");
109 gint *result = g_object_get_data (G_OBJECT (filesel), "ok-result");
111 gtk_widget_hide (filesel);
113 if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data))
115 gtk_widget_destroy (filesel);
119 gtk_widget_show (filesel);
123 filesel_run (GtkWindow *parent,
125 const char *start_file,
129 GtkWidget *filesel = gtk_file_selection_new (title);
130 gboolean result = FALSE;
133 parent = get_active_window ();
136 gtk_window_set_transient_for (GTK_WINDOW (filesel), parent);
139 gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file);
142 g_object_set_data (G_OBJECT (filesel), "ok-func", func);
143 g_object_set_data (G_OBJECT (filesel), "ok-data", data);
144 g_object_set_data (G_OBJECT (filesel), "ok-result", &result);
146 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
148 GTK_SIGNAL_FUNC (filesel_ok_cb), filesel);
149 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
151 GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (filesel));
153 gtk_signal_connect (GTK_OBJECT (filesel), "destroy",
154 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
155 gtk_window_set_modal (GTK_WINDOW (filesel), TRUE);
157 gtk_widget_show (filesel);
164 * MsgBox utility functions
168 msgbox_yes_cb (GtkWidget *widget, gboolean *result)
171 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
175 msgbox_no_cb (GtkWidget *widget, gboolean *result)
178 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
182 msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
184 if (event->keyval == GDK_Escape)
186 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
187 gtk_object_destroy (GTK_OBJECT (widget));
194 /* Don't copy this example, it's all crack-smoking - you can just use
195 * GtkMessageDialog now
198 msgbox_run (GtkWindow *parent,
200 const char *yes_button,
201 const char *no_button,
202 const char *cancel_button,
205 gboolean result = -1;
210 GtkWidget *button_box;
211 GtkWidget *separator;
213 g_return_val_if_fail (message != NULL, FALSE);
214 g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE);
217 parent = get_active_window ();
221 dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
222 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
224 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
225 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
227 /* Quit our recursive main loop when the dialog is destroyed.
229 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
230 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
232 /* Catch Escape key presses and have them destroy the dialog
234 gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event",
235 GTK_SIGNAL_FUNC (msgbox_key_press_cb), NULL);
237 /* Fill in the contents of the widget
239 vbox = gtk_vbox_new (FALSE, 0);
240 gtk_container_add (GTK_CONTAINER (dialog), vbox);
242 label = gtk_label_new (message);
243 gtk_misc_set_padding (GTK_MISC (label), 12, 12);
244 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
245 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
247 separator = gtk_hseparator_new ();
248 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
250 button_box = gtk_hbutton_box_new ();
251 gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
252 gtk_container_set_border_width (GTK_CONTAINER (button_box), 8);
255 /* When Yes is clicked, call the msgbox_yes_cb
256 * This sets the result variable and destroys the dialog
260 button = gtk_button_new_with_label (yes_button);
261 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
262 gtk_container_add (GTK_CONTAINER (button_box), button);
264 if (default_index == 0)
265 gtk_widget_grab_default (button);
267 gtk_signal_connect (GTK_OBJECT (button), "clicked",
268 GTK_SIGNAL_FUNC (msgbox_yes_cb), &result);
271 /* When No is clicked, call the msgbox_no_cb
272 * This sets the result variable and destroys the dialog
276 button = gtk_button_new_with_label (no_button);
277 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
278 gtk_container_add (GTK_CONTAINER (button_box), button);
280 if (default_index == 0)
281 gtk_widget_grab_default (button);
283 gtk_signal_connect (GTK_OBJECT (button), "clicked",
284 GTK_SIGNAL_FUNC (msgbox_no_cb), &result);
287 /* When Cancel is clicked, destroy the dialog
291 button = gtk_button_new_with_label (cancel_button);
292 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
293 gtk_container_add (GTK_CONTAINER (button_box), button);
295 if (default_index == 1)
296 gtk_widget_grab_default (button);
298 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
299 GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (dialog));
302 gtk_widget_show_all (dialog);
304 /* Run a recursive main loop until a button is clicked
305 * or the user destroys the dialog through the window mananger */
312 * Example buffer filling code
315 blink_timeout (gpointer data)
318 static gboolean flip = FALSE;
320 tag = GTK_TEXT_TAG (data);
322 g_object_set (G_OBJECT (tag),
323 "foreground", flip ? "blue" : "purple",
332 tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
333 const GtkTextIter *iter, gpointer user_data)
337 char_index = gtk_text_iter_get_offset (iter);
341 case GDK_MOTION_NOTIFY:
342 printf ("Motion event at char %d tag `%s'\n",
343 char_index, tag->name);
346 case GDK_BUTTON_PRESS:
347 printf ("Button press at char %d tag `%s'\n",
348 char_index, tag->name);
351 case GDK_2BUTTON_PRESS:
352 printf ("Double click at char %d tag `%s'\n",
353 char_index, tag->name);
356 case GDK_3BUTTON_PRESS:
357 printf ("Triple click at char %d tag `%s'\n",
358 char_index, tag->name);
361 case GDK_BUTTON_RELEASE:
362 printf ("Button release at char %d tag `%s'\n",
363 char_index, tag->name);
367 case GDK_KEY_RELEASE:
368 printf ("Key event at char %d tag `%s'\n",
369 char_index, tag->name);
372 case GDK_ENTER_NOTIFY:
373 case GDK_LEAVE_NOTIFY:
374 case GDK_PROPERTY_NOTIFY:
375 case GDK_SELECTION_CLEAR:
376 case GDK_SELECTION_REQUEST:
377 case GDK_SELECTION_NOTIFY:
378 case GDK_PROXIMITY_IN:
379 case GDK_PROXIMITY_OUT:
382 case GDK_DRAG_MOTION:
383 case GDK_DRAG_STATUS:
385 case GDK_DROP_FINISHED:
394 setup_tag (GtkTextTag *tag)
396 g_signal_connect (G_OBJECT (tag),
398 G_CALLBACK (tag_event_handler),
402 static const char *book_closed_xpm[] = {
428 fill_example_buffer (GtkTextBuffer *buffer)
430 GtkTextIter iter, iter2;
432 GtkTextChildAnchor *anchor;
439 /* FIXME this is broken if called twice on a buffer, since
440 * we try to create tags a second time.
443 tag = gtk_text_buffer_create_tag (buffer, "fg_blue", NULL);
445 /* gtk_timeout_add (1000, blink_timeout, tag); */
449 color.red = color.green = 0;
454 g_object_set (G_OBJECT (tag),
455 "foreground_gdk", &color,
456 "background_gdk", &color2,
460 tag = gtk_text_buffer_create_tag (buffer, "fg_red", NULL);
464 color.blue = color.green = 0;
466 g_object_set (G_OBJECT (tag),
467 "rise", -4 * PANGO_SCALE,
468 "foreground_gdk", &color,
471 tag = gtk_text_buffer_create_tag (buffer, "bg_green", NULL);
475 color.blue = color.red = 0;
476 color.green = 0xffff;
477 g_object_set (G_OBJECT (tag),
478 "background_gdk", &color,
482 tag = gtk_text_buffer_create_tag (buffer, "strikethrough", NULL);
486 g_object_set (G_OBJECT (tag),
487 "strikethrough", TRUE,
491 tag = gtk_text_buffer_create_tag (buffer, "underline", NULL);
495 g_object_set (G_OBJECT (tag),
496 "underline", PANGO_UNDERLINE_SINGLE,
501 g_object_set (G_OBJECT (tag),
502 "underline", PANGO_UNDERLINE_SINGLE,
505 tag = gtk_text_buffer_create_tag (buffer, "centered", NULL);
507 g_object_set (G_OBJECT (tag),
508 "justification", GTK_JUSTIFY_CENTER,
511 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote", NULL);
513 g_object_set (G_OBJECT (tag),
514 "wrap_mode", GTK_WRAP_WORD,
515 "direction", GTK_TEXT_DIR_RTL,
522 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);
1719 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1720 "invisible", TRUE, NULL);
1722 buffer->not_editable_tag =
1723 gtk_text_buffer_create_tag (buffer->buffer, NULL,
1725 "foreground", "purple", NULL);
1727 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1728 "foreground", "red", NULL);
1730 tabs = pango_tab_array_new_with_positions (4,
1735 PANGO_TAB_LEFT, 120);
1737 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1739 "foreground", "green", NULL);
1741 pango_tab_array_free (tabs);
1743 buffers = g_slist_prepend (buffers, buffer);
1749 buffer_pretty_name (Buffer *buffer)
1751 if (buffer->filename)
1754 char *result = g_path_get_basename (buffer->filename);
1755 p = strchr (result, '/');
1763 if (buffer->untitled_serial == -1)
1764 buffer->untitled_serial = untitled_serial++;
1766 if (buffer->untitled_serial == 1)
1767 return g_strdup ("Untitled");
1769 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1774 buffer_filename_set (Buffer *buffer)
1776 GSList *tmp_list = views;
1780 View *view = tmp_list->data;
1782 if (view->buffer == buffer)
1783 view_set_title (view);
1785 tmp_list = tmp_list->next;
1790 buffer_search (Buffer *buffer,
1796 GtkTextIter start, end;
1800 /* remove tag from whole buffer */
1801 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1802 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1805 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1806 gtk_text_buffer_get_mark (buffer->buffer,
1812 GtkTextIter match_start, match_end;
1816 while (gtk_text_iter_forward_search (&iter, str,
1817 GTK_TEXT_SEARCH_VISIBLE_ONLY |
1818 GTK_TEXT_SEARCH_TEXT_ONLY,
1819 &match_start, &match_end,
1823 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1824 &match_start, &match_end);
1831 while (gtk_text_iter_backward_search (&iter, str,
1832 GTK_TEXT_SEARCH_VISIBLE_ONLY |
1833 GTK_TEXT_SEARCH_TEXT_ONLY,
1834 &match_start, &match_end,
1838 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1839 &match_start, &match_end);
1846 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1849 GTK_DIALOG_DESTROY_WITH_PARENT,
1850 "%d strings found and marked in red",
1853 gtk_signal_connect_object (GTK_OBJECT (dialog),
1855 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1856 GTK_OBJECT (dialog));
1858 gtk_widget_show (dialog);
1862 buffer_search_forward (Buffer *buffer, const char *str,
1865 buffer_search (buffer, str, view, TRUE);
1869 buffer_search_backward (Buffer *buffer, const char *str,
1872 buffer_search (buffer, str, view, FALSE);
1876 buffer_ref (Buffer *buffer)
1882 buffer_unref (Buffer *buffer)
1885 if (buffer->refcount == 0)
1887 buffer_set_colors (buffer, FALSE);
1888 buffers = g_slist_remove (buffers, buffer);
1889 g_object_unref (G_OBJECT (buffer->buffer));
1890 g_free (buffer->filename);
1896 hsv_to_rgb (gdouble *h,
1900 gdouble hue, saturation, value;
1918 f = hue - (int) hue;
1919 p = value * (1.0 - saturation);
1920 q = value * (1.0 - saturation * f);
1921 t = value * (1.0 - saturation * (1.0 - f));
1962 g_assert_not_reached ();
1968 hue_to_color (gdouble hue,
1977 g_return_if_fail (hue <= 1.0);
1979 hsv_to_rgb (&h, &s, &v);
1981 color->red = h * 65535;
1982 color->green = s * 65535;
1983 color->blue = v * 65535;
1988 color_cycle_timeout (gpointer data)
1990 Buffer *buffer = data;
1992 buffer_cycle_colors (buffer);
1998 buffer_set_colors (Buffer *buffer,
2004 if (enabled && buffer->color_cycle_timeout == 0)
2005 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
2006 else if (!enabled && buffer->color_cycle_timeout != 0)
2008 gtk_timeout_remove (buffer->color_cycle_timeout);
2009 buffer->color_cycle_timeout = 0;
2012 tmp = buffer->color_tags;
2019 hue_to_color (hue, &color);
2021 g_object_set (G_OBJECT (tmp->data),
2022 "foreground_gdk", &color,
2026 g_object_set (G_OBJECT (tmp->data),
2027 "foreground_set", FALSE,
2030 hue += 1.0 / N_COLORS;
2032 tmp = g_slist_next (tmp);
2037 buffer_cycle_colors (Buffer *buffer)
2040 gdouble hue = buffer->start_hue;
2042 tmp = buffer->color_tags;
2047 hue_to_color (hue, &color);
2049 g_object_set (G_OBJECT (tmp->data),
2050 "foreground_gdk", &color,
2053 hue += 1.0 / N_COLORS;
2057 tmp = g_slist_next (tmp);
2060 buffer->start_hue += 1.0 / N_COLORS;
2061 if (buffer->start_hue > 1.0)
2062 buffer->start_hue = 0.0;
2066 close_view (View *view)
2068 views = g_slist_remove (views, view);
2069 buffer_unref (view->buffer);
2070 gtk_widget_destroy (view->window);
2071 g_object_unref (G_OBJECT (view->item_factory));
2080 check_close_view (View *view)
2082 if (view->buffer->refcount > 1 ||
2083 check_buffer_saved (view->buffer))
2088 view_set_title (View *view)
2090 char *pretty_name = buffer_pretty_name (view->buffer);
2091 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
2093 gtk_window_set_title (GTK_WINDOW (view->window), title);
2095 g_free (pretty_name);
2100 cursor_set_callback (GtkTextBuffer *buffer,
2101 const GtkTextIter *location,
2105 GtkTextView *text_view;
2107 /* Redraw tab windows if the cursor moves
2108 * on the mapped widget (windows may not exist before realization...
2111 text_view = GTK_TEXT_VIEW (user_data);
2113 if (GTK_WIDGET_MAPPED (text_view) &&
2114 mark == gtk_text_buffer_get_insert (buffer))
2116 GdkWindow *tab_window;
2118 tab_window = gtk_text_view_get_window (text_view,
2119 GTK_TEXT_WINDOW_TOP);
2121 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
2123 tab_window = gtk_text_view_get_window (text_view,
2124 GTK_TEXT_WINDOW_BOTTOM);
2126 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
2131 tab_stops_expose (GtkWidget *widget,
2132 GdkEventExpose *event,
2139 GdkWindow *bottom_win;
2140 GtkTextView *text_view;
2141 GtkTextWindowType type;
2142 GdkDrawable *target;
2143 gint *positions = NULL;
2145 GtkTextAttributes *attrs;
2147 GtkTextBuffer *buffer;
2150 text_view = GTK_TEXT_VIEW (widget);
2152 /* See if this expose is on the tab stop window */
2153 top_win = gtk_text_view_get_window (text_view,
2154 GTK_TEXT_WINDOW_TOP);
2156 bottom_win = gtk_text_view_get_window (text_view,
2157 GTK_TEXT_WINDOW_BOTTOM);
2159 if (event->window == top_win)
2161 type = GTK_TEXT_WINDOW_TOP;
2164 else if (event->window == bottom_win)
2166 type = GTK_TEXT_WINDOW_BOTTOM;
2167 target = bottom_win;
2172 first_x = event->area.x;
2173 last_x = first_x + event->area.width;
2175 gtk_text_view_window_to_buffer_coords (text_view,
2182 gtk_text_view_window_to_buffer_coords (text_view,
2189 buffer = gtk_text_view_get_buffer (text_view);
2191 gtk_text_buffer_get_iter_at_mark (buffer,
2193 gtk_text_buffer_get_mark (buffer,
2196 attrs = gtk_text_attributes_new ();
2198 gtk_text_iter_get_attributes (&insert, attrs);
2202 size = pango_tab_array_get_size (attrs->tabs);
2204 pango_tab_array_get_tabs (attrs->tabs,
2208 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
2216 gtk_text_attributes_unref (attrs);
2224 positions[i] = PANGO_PIXELS (positions[i]);
2226 gtk_text_view_buffer_to_window_coords (text_view,
2233 gdk_draw_line (target,
2234 widget->style->fg_gc [widget->state],
2247 get_lines (GtkTextView *text_view,
2250 GArray *buffer_coords,
2258 g_array_set_size (buffer_coords, 0);
2259 g_array_set_size (numbers, 0);
2261 /* Get iter at first y */
2262 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
2264 /* For each iter, get its location and add it to the arrays.
2265 * Stop when we pass last_y
2270 while (!gtk_text_iter_is_end (&iter))
2275 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2277 g_array_append_val (buffer_coords, y);
2278 line_num = gtk_text_iter_get_line (&iter);
2279 g_array_append_val (numbers, line_num);
2283 if ((y + height) >= last_y)
2286 gtk_text_iter_forward_line (&iter);
2293 line_numbers_expose (GtkWidget *widget,
2294 GdkEventExpose *event,
2303 GdkWindow *left_win;
2304 GdkWindow *right_win;
2305 PangoLayout *layout;
2306 GtkTextView *text_view;
2307 GtkTextWindowType type;
2308 GdkDrawable *target;
2310 text_view = GTK_TEXT_VIEW (widget);
2312 /* See if this expose is on the line numbers window */
2313 left_win = gtk_text_view_get_window (text_view,
2314 GTK_TEXT_WINDOW_LEFT);
2316 right_win = gtk_text_view_get_window (text_view,
2317 GTK_TEXT_WINDOW_RIGHT);
2319 if (event->window == left_win)
2321 type = GTK_TEXT_WINDOW_LEFT;
2324 else if (event->window == right_win)
2326 type = GTK_TEXT_WINDOW_RIGHT;
2332 first_y = event->area.y;
2333 last_y = first_y + event->area.height;
2335 gtk_text_view_window_to_buffer_coords (text_view,
2342 gtk_text_view_window_to_buffer_coords (text_view,
2349 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2350 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2352 get_lines (text_view,
2359 /* Draw fully internationalized numbers! */
2361 layout = gtk_widget_create_pango_layout (widget, "");
2369 gtk_text_view_buffer_to_window_coords (text_view,
2372 g_array_index (pixels, gint, i),
2376 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2378 pango_layout_set_text (layout, str, -1);
2380 gtk_paint_layout (widget->style,
2382 GTK_WIDGET_STATE (widget),
2395 g_array_free (pixels, TRUE);
2396 g_array_free (numbers, TRUE);
2398 g_object_unref (G_OBJECT (layout));
2400 /* don't stop emission, need to draw children */
2405 create_view (Buffer *buffer)
2412 view = g_new0 (View, 1);
2413 views = g_slist_prepend (views, view);
2415 view->buffer = buffer;
2416 buffer_ref (buffer);
2418 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2419 g_object_set_data (G_OBJECT (view->window), "view", view);
2421 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2422 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2424 view->accel_group = gtk_accel_group_new ();
2425 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2426 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2428 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2430 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2432 vbox = gtk_vbox_new (FALSE, 0);
2433 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2435 gtk_box_pack_start (GTK_BOX (vbox),
2436 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2439 sw = gtk_scrolled_window_new (NULL, NULL);
2440 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2441 GTK_POLICY_AUTOMATIC,
2442 GTK_POLICY_AUTOMATIC);
2444 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2445 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2448 /* Make sure border width works, no real reason to do this other than testing */
2449 gtk_container_set_border_width (GTK_CONTAINER (view->text_view),
2452 /* Draw tab stops in the top and bottom windows. */
2454 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2455 GTK_TEXT_WINDOW_TOP,
2458 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2459 GTK_TEXT_WINDOW_BOTTOM,
2462 gtk_signal_connect (GTK_OBJECT (view->text_view),
2464 GTK_SIGNAL_FUNC (tab_stops_expose),
2467 g_signal_connect (G_OBJECT (view->buffer->buffer),
2469 GTK_SIGNAL_FUNC (cursor_set_callback),
2472 /* Draw line numbers in the side windows; we should really be
2473 * more scientific about what width we set them to.
2475 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2476 GTK_TEXT_WINDOW_RIGHT,
2479 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2480 GTK_TEXT_WINDOW_LEFT,
2483 gtk_signal_connect (GTK_OBJECT (view->text_view),
2485 GTK_SIGNAL_FUNC (line_numbers_expose),
2488 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2489 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2491 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2493 gtk_widget_grab_focus (view->text_view);
2495 view_set_title (view);
2496 view_init_menus (view);
2498 view_add_example_widgets (view);
2500 gtk_widget_show_all (view->window);
2505 view_add_example_widgets (View *view)
2507 GtkTextChildAnchor *anchor;
2510 buffer = view->buffer;
2512 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2515 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2519 widget = gtk_button_new_with_label ("Foo");
2521 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2525 gtk_widget_show (widget);
2530 file_exists (const char *filename)
2532 struct stat statbuf;
2534 return stat (filename, &statbuf) == 0;
2539 if (file_exists ("../gdk-pixbuf/libpixbufloader-pnm.la"))
2541 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2542 putenv ("GTK_IM_MODULE_FILE=../modules/input/gtk.immodules");
2547 main (int argc, char** argv)
2554 gtk_init (&argc, &argv);
2556 buffer = create_buffer ();
2557 view = create_view (buffer);
2558 buffer_unref (buffer);
2560 push_active_window (GTK_WINDOW (view->window));
2561 for (i=1; i < argc; i++)
2565 /* Quick and dirty canonicalization - better should be in GLib
2568 if (!g_path_is_absolute (argv[i]))
2570 char *cwd = g_get_current_dir ();
2571 filename = g_strconcat (cwd, "/", argv[i], NULL);
2577 open_ok_func (filename, view);
2579 if (filename != argv[i])
2582 pop_active_window ();