8 #include <gdk/gdkkeysyms.h>
10 typedef struct _Buffer Buffer;
11 typedef struct _View View;
13 static gint untitled_serial = 1;
15 GSList *active_window_stack = NULL;
20 GtkTextBuffer *buffer;
23 GtkTextTag *invisible_tag;
24 GtkTextTag *not_editable_tag;
25 GtkTextTag *found_text_tag;
26 GtkTextTag *custom_tabs_tag;
28 guint color_cycle_timeout;
36 GtkAccelGroup *accel_group;
37 GtkItemFactory *item_factory;
41 static void push_active_window (GtkWindow *window);
42 static void pop_active_window (void);
43 static GtkWindow *get_active_window (void);
45 static Buffer * create_buffer (void);
46 static gboolean check_buffer_saved (Buffer *buffer);
47 static gboolean save_buffer (Buffer *buffer);
48 static gboolean save_as_buffer (Buffer *buffer);
49 static char * buffer_pretty_name (Buffer *buffer);
50 static void buffer_filename_set (Buffer *buffer);
51 static void buffer_search_forward (Buffer *buffer,
54 static void buffer_search_backward (Buffer *buffer,
57 static void buffer_set_colors (Buffer *buffer,
59 static void buffer_cycle_colors (Buffer *buffer);
61 static View *view_from_widget (GtkWidget *widget);
63 static View *create_view (Buffer *buffer);
64 static void check_close_view (View *view);
65 static void close_view (View *view);
66 static void view_set_title (View *view);
67 static void view_init_menus (View *view);
68 static void view_add_example_widgets (View *view);
70 GSList *buffers = NULL;
74 push_active_window (GtkWindow *window)
76 g_object_ref (G_OBJECT (window));
77 active_window_stack = g_slist_prepend (active_window_stack, window);
81 pop_active_window (void)
83 gtk_object_unref (active_window_stack->data);
84 active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack);
88 get_active_window (void)
90 if (active_window_stack)
91 return active_window_stack->data;
97 * Filesel utility function
100 typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data);
103 filesel_ok_cb (GtkWidget *button, GtkWidget *filesel)
105 FileselOKFunc ok_func = g_object_get_data (G_OBJECT (filesel), "ok-func");
106 gpointer data = g_object_get_data (G_OBJECT (filesel), "ok-data");
107 gint *result = g_object_get_data (G_OBJECT (filesel), "ok-result");
109 gtk_widget_hide (filesel);
111 if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data))
113 gtk_widget_destroy (filesel);
117 gtk_widget_show (filesel);
121 filesel_run (GtkWindow *parent,
123 const char *start_file,
127 GtkWidget *filesel = gtk_file_selection_new (title);
128 gboolean result = FALSE;
131 parent = get_active_window ();
134 gtk_window_set_transient_for (GTK_WINDOW (filesel), parent);
137 gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file);
140 g_object_set_data (G_OBJECT (filesel), "ok-func", func);
141 g_object_set_data (G_OBJECT (filesel), "ok-data", data);
142 g_object_set_data (G_OBJECT (filesel), "ok-result", &result);
144 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
146 GTK_SIGNAL_FUNC (filesel_ok_cb), filesel);
147 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
149 GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (filesel));
151 gtk_signal_connect (GTK_OBJECT (filesel), "destroy",
152 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
153 gtk_window_set_modal (GTK_WINDOW (filesel), TRUE);
155 gtk_widget_show (filesel);
162 * MsgBox utility functions
166 msgbox_yes_cb (GtkWidget *widget, gboolean *result)
169 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
173 msgbox_no_cb (GtkWidget *widget, gboolean *result)
176 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
180 msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
182 if (event->keyval == GDK_Escape)
184 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
185 gtk_object_destroy (GTK_OBJECT (widget));
193 msgbox_run (GtkWindow *parent,
195 const char *yes_button,
196 const char *no_button,
197 const char *cancel_button,
200 gboolean result = -1;
205 GtkWidget *button_box;
206 GtkWidget *separator;
208 g_return_val_if_fail (message != NULL, FALSE);
209 g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE);
212 parent = get_active_window ();
216 dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
217 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
219 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
220 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
222 /* Quit our recursive main loop when the dialog is destroyed.
224 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
225 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
227 /* Catch Escape key presses and have them destroy the dialog
229 gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event",
230 GTK_SIGNAL_FUNC (msgbox_key_press_cb), NULL);
232 /* Fill in the contents of the widget
234 vbox = gtk_vbox_new (FALSE, 0);
235 gtk_container_add (GTK_CONTAINER (dialog), vbox);
237 label = gtk_label_new (message);
238 gtk_misc_set_padding (GTK_MISC (label), 12, 12);
239 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
240 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
242 separator = gtk_hseparator_new ();
243 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
245 button_box = gtk_hbutton_box_new ();
246 gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
247 gtk_container_set_border_width (GTK_CONTAINER (button_box), 8);
250 /* When Yes is clicked, call the msgbox_yes_cb
251 * This sets the result variable and destroys the dialog
255 button = gtk_button_new_with_label (yes_button);
256 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
257 gtk_container_add (GTK_CONTAINER (button_box), button);
259 if (default_index == 0)
260 gtk_widget_grab_default (button);
262 gtk_signal_connect (GTK_OBJECT (button), "clicked",
263 GTK_SIGNAL_FUNC (msgbox_yes_cb), &result);
266 /* When No is clicked, call the msgbox_no_cb
267 * This sets the result variable and destroys the dialog
271 button = gtk_button_new_with_label (no_button);
272 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
273 gtk_container_add (GTK_CONTAINER (button_box), button);
275 if (default_index == 0)
276 gtk_widget_grab_default (button);
278 gtk_signal_connect (GTK_OBJECT (button), "clicked",
279 GTK_SIGNAL_FUNC (msgbox_no_cb), &result);
282 /* When Cancel is clicked, destroy the dialog
286 button = gtk_button_new_with_label (cancel_button);
287 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
288 gtk_container_add (GTK_CONTAINER (button_box), button);
290 if (default_index == 1)
291 gtk_widget_grab_default (button);
293 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
294 GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (dialog));
297 gtk_widget_show_all (dialog);
299 /* Run a recursive main loop until a button is clicked
300 * or the user destroys the dialog through the window mananger */
307 * Example buffer filling code
310 blink_timeout (gpointer data)
313 static gboolean flip = FALSE;
315 tag = GTK_TEXT_TAG (data);
317 g_object_set (G_OBJECT (tag),
318 "foreground", flip ? "blue" : "purple",
327 tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
328 const GtkTextIter *iter, gpointer user_data)
332 char_index = gtk_text_iter_get_offset (iter);
336 case GDK_MOTION_NOTIFY:
337 printf ("Motion event at char %d tag `%s'\n",
338 char_index, tag->name);
341 case GDK_BUTTON_PRESS:
342 printf ("Button press at char %d tag `%s'\n",
343 char_index, tag->name);
346 case GDK_2BUTTON_PRESS:
347 printf ("Double click at char %d tag `%s'\n",
348 char_index, tag->name);
351 case GDK_3BUTTON_PRESS:
352 printf ("Triple click at char %d tag `%s'\n",
353 char_index, tag->name);
356 case GDK_BUTTON_RELEASE:
357 printf ("Button release at char %d tag `%s'\n",
358 char_index, tag->name);
362 case GDK_KEY_RELEASE:
363 printf ("Key event at char %d tag `%s'\n",
364 char_index, tag->name);
367 case GDK_ENTER_NOTIFY:
368 case GDK_LEAVE_NOTIFY:
369 case GDK_PROPERTY_NOTIFY:
370 case GDK_SELECTION_CLEAR:
371 case GDK_SELECTION_REQUEST:
372 case GDK_SELECTION_NOTIFY:
373 case GDK_PROXIMITY_IN:
374 case GDK_PROXIMITY_OUT:
377 case GDK_DRAG_MOTION:
378 case GDK_DRAG_STATUS:
380 case GDK_DROP_FINISHED:
389 setup_tag (GtkTextTag *tag)
391 g_signal_connect_data (G_OBJECT (tag),
394 NULL, NULL, FALSE, FALSE);
397 static char *book_closed_xpm[] = {
423 fill_example_buffer (GtkTextBuffer *buffer)
425 GtkTextIter iter, iter2;
433 /* FIXME this is broken if called twice on a buffer, since
434 * we try to create tags a second time.
437 tag = gtk_text_buffer_create_tag (buffer, "fg_blue");
439 /* gtk_timeout_add (1000, blink_timeout, tag); */
443 color.red = color.green = 0;
448 g_object_set (G_OBJECT (tag),
449 "foreground_gdk", &color,
450 "background_gdk", &color2,
454 tag = gtk_text_buffer_create_tag (buffer, "fg_red");
458 color.blue = color.green = 0;
460 g_object_set (G_OBJECT (tag),
461 "rise", -4 * PANGO_SCALE,
462 "foreground_gdk", &color,
465 tag = gtk_text_buffer_create_tag (buffer, "bg_green");
469 color.blue = color.red = 0;
470 color.green = 0xffff;
471 g_object_set (G_OBJECT (tag),
472 "background_gdk", &color,
476 tag = gtk_text_buffer_create_tag (buffer, "strikethrough");
480 g_object_set (G_OBJECT (tag),
481 "strikethrough", TRUE,
485 tag = gtk_text_buffer_create_tag (buffer, "underline");
489 g_object_set (G_OBJECT (tag),
490 "underline", PANGO_UNDERLINE_SINGLE,
495 g_object_set (G_OBJECT (tag),
496 "underline", PANGO_UNDERLINE_SINGLE,
499 tag = gtk_text_buffer_create_tag (buffer, "centered");
501 g_object_set (G_OBJECT (tag),
502 "justification", GTK_JUSTIFY_CENTER,
505 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote");
507 g_object_set (G_OBJECT (tag),
508 "wrap_mode", GTK_WRAP_WORD,
509 "direction", GTK_TEXT_DIR_RTL,
517 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
519 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
521 g_object_ref (G_OBJECT (anchor));
523 g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
524 (GDestroyNotify) g_object_unref);
527 pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
532 GtkTextMark * temp_mark;
534 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
536 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
538 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",
541 gtk_text_buffer_insert (buffer, &iter, str, -1);
545 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
547 gtk_text_buffer_insert (buffer, &iter,
548 "(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"
549 /* This is UTF8 stuff, Emacs doesn't
550 really know how to display it */
551 "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew שלום Japanese (日本語)\n", -1);
554 gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
557 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
558 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
560 gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
562 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
563 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
565 gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
567 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
568 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
570 gtk_text_buffer_apply_tag_by_name (buffer, "strikethrough", &iter, &iter2);
572 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
573 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
575 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
577 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
578 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
580 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
582 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
583 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
585 gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
588 gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
589 gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
591 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
592 gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
594 gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
595 gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
596 gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1);
597 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
598 gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
603 g_object_unref (G_OBJECT (pixbuf));
605 printf ("%d lines %d chars\n",
606 gtk_text_buffer_get_line_count (buffer),
607 gtk_text_buffer_get_char_count (buffer));
609 /* Move cursor to start */
610 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
611 gtk_text_buffer_place_cursor (buffer, &iter);
613 gtk_text_buffer_set_modified (buffer, FALSE);
617 fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
622 GtkTextIter iter, end;
624 f = fopen (filename, "r");
628 gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
629 filename, g_strerror (errno));
630 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
635 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
639 const char *leftover;
640 int to_read = 2047 - remaining;
642 count = fread (buf + remaining, 1, to_read, f);
643 buf[count + remaining] = '\0';
645 g_utf8_validate (buf, count + remaining, &leftover);
647 g_assert (g_utf8_validate (buf, leftover - buf, NULL));
648 gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
650 remaining = (buf + remaining + count) - leftover;
651 g_memmove (buf, leftover, remaining);
653 if (remaining > 6 || count < to_read)
659 gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
660 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
664 /* We had a newline in the buffer to begin with. (The buffer always contains
665 * a newline, so we delete to the end of the buffer to clean up.
667 gtk_text_buffer_get_end_iter (buffer, &end);
668 gtk_text_buffer_delete (buffer, &iter, &end);
670 gtk_text_buffer_set_modified (buffer, FALSE);
676 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
678 View *view = view_from_widget (window);
680 push_active_window (GTK_WINDOW (window));
681 check_close_view (view);
682 pop_active_window ();
692 get_empty_view (View *view)
694 if (!view->buffer->filename &&
695 !gtk_text_buffer_get_modified (view->buffer->buffer))
698 return create_view (create_buffer ());
702 view_from_widget (GtkWidget *widget)
706 if (GTK_IS_MENU_ITEM (widget))
708 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
709 return g_object_get_data (G_OBJECT (item_factory), "view");
713 GtkWidget *app = gtk_widget_get_toplevel (widget);
714 return g_object_get_data (G_OBJECT (app), "view");
719 do_new (gpointer callback_data,
720 guint callback_action,
723 create_view (create_buffer ());
727 do_new_view (gpointer callback_data,
728 guint callback_action,
731 View *view = view_from_widget (widget);
733 create_view (view->buffer);
737 open_ok_func (const char *filename, gpointer data)
740 View *new_view = get_empty_view (view);
742 if (!fill_file_buffer (new_view->buffer->buffer, filename))
744 if (new_view != view)
745 close_view (new_view);
750 g_free (new_view->buffer->filename);
751 new_view->buffer->filename = g_strdup (filename);
752 buffer_filename_set (new_view->buffer);
759 do_open (gpointer callback_data,
760 guint callback_action,
763 View *view = view_from_widget (widget);
765 push_active_window (GTK_WINDOW (view->window));
766 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
767 pop_active_window ();
771 do_save_as (gpointer callback_data,
772 guint callback_action,
775 View *view = view_from_widget (widget);
777 push_active_window (GTK_WINDOW (view->window));
778 save_as_buffer (view->buffer);
779 pop_active_window ();
783 do_save (gpointer callback_data,
784 guint callback_action,
787 View *view = view_from_widget (widget);
789 push_active_window (GTK_WINDOW (view->window));
790 if (!view->buffer->filename)
791 do_save_as (callback_data, callback_action, widget);
793 save_buffer (view->buffer);
794 pop_active_window ();
798 do_close (gpointer callback_data,
799 guint callback_action,
802 View *view = view_from_widget (widget);
804 push_active_window (GTK_WINDOW (view->window));
805 check_close_view (view);
806 pop_active_window ();
810 do_exit (gpointer callback_data,
811 guint callback_action,
814 View *view = view_from_widget (widget);
816 GSList *tmp_list = buffers;
818 push_active_window (GTK_WINDOW (view->window));
821 if (!check_buffer_saved (tmp_list->data))
824 tmp_list = tmp_list->next;
828 pop_active_window ();
832 do_example (gpointer callback_data,
833 guint callback_action,
836 View *view = view_from_widget (widget);
839 new_view = get_empty_view (view);
841 fill_example_buffer (new_view->buffer->buffer);
843 view_add_example_widgets (new_view);
847 do_wrap_changed (gpointer callback_data,
848 guint callback_action,
851 View *view = view_from_widget (widget);
853 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
857 do_direction_changed (gpointer callback_data,
858 guint callback_action,
861 View *view = view_from_widget (widget);
863 gtk_widget_set_direction (view->text_view, callback_action);
864 gtk_widget_queue_resize (view->text_view);
869 do_spacing_changed (gpointer callback_data,
870 guint callback_action,
873 View *view = view_from_widget (widget);
877 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
879 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
881 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
886 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
888 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
890 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
896 do_editable_changed (gpointer callback_data,
897 guint callback_action,
900 View *view = view_from_widget (widget);
902 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
906 do_cursor_visible_changed (gpointer callback_data,
907 guint callback_action,
910 View *view = view_from_widget (widget);
912 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
916 do_color_cycle_changed (gpointer callback_data,
917 guint callback_action,
920 View *view = view_from_widget (widget);
922 buffer_set_colors (view->buffer, callback_action);
926 do_apply_editable (gpointer callback_data,
927 guint callback_action,
930 View *view = view_from_widget (widget);
934 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
939 gtk_text_buffer_remove_tag (view->buffer->buffer,
940 view->buffer->not_editable_tag,
945 gtk_text_buffer_apply_tag (view->buffer->buffer,
946 view->buffer->not_editable_tag,
953 do_apply_invisible (gpointer callback_data,
954 guint callback_action,
957 View *view = view_from_widget (widget);
961 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
966 gtk_text_buffer_remove_tag (view->buffer->buffer,
967 view->buffer->invisible_tag,
972 gtk_text_buffer_apply_tag (view->buffer->buffer,
973 view->buffer->invisible_tag,
980 do_apply_tabs (gpointer callback_data,
981 guint callback_action,
984 View *view = view_from_widget (widget);
988 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
993 gtk_text_buffer_remove_tag (view->buffer->buffer,
994 view->buffer->custom_tabs_tag,
999 gtk_text_buffer_apply_tag (view->buffer->buffer,
1000 view->buffer->custom_tabs_tag,
1007 do_apply_colors (gpointer callback_data,
1008 guint callback_action,
1011 View *view = view_from_widget (widget);
1012 Buffer *buffer = view->buffer;
1016 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1019 if (!callback_action)
1023 tmp = buffer->color_tags;
1026 gtk_text_buffer_remove_tag (view->buffer->buffer,
1029 tmp = g_slist_next (tmp);
1036 tmp = buffer->color_tags;
1040 gboolean done = FALSE;
1043 gtk_text_iter_forward_char (&next);
1044 gtk_text_iter_forward_char (&next);
1046 if (gtk_text_iter_compare (&next, &end) > 0)
1052 gtk_text_buffer_apply_tag (view->buffer->buffer,
1061 tmp = g_slist_next (tmp);
1063 tmp = buffer->color_tags;
1076 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1078 GtkTextBuffer *buffer;
1080 GtkTextIter start, end;
1081 gchar *search_string;
1083 if (response_id != RESPONSE_FORWARD &&
1084 response_id != RESPONSE_BACKWARD)
1086 gtk_widget_destroy (dialog);
1090 buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
1092 gtk_text_buffer_get_bounds (buffer, &start, &end);
1094 /* Remove trailing newline */
1095 gtk_text_iter_backward_char (&end);
1097 search_string = gtk_text_iter_get_text (&start, &end);
1099 printf ("Searching for `%s'\n", search_string);
1101 if (response_id == RESPONSE_FORWARD)
1102 buffer_search_forward (view->buffer, search_string, view);
1103 else if (response_id == RESPONSE_BACKWARD)
1104 buffer_search_backward (view->buffer, search_string, view);
1106 g_free (search_string);
1108 gtk_widget_destroy (dialog);
1112 do_search (gpointer callback_data,
1113 guint callback_action,
1116 View *view = view_from_widget (widget);
1118 GtkWidget *search_text;
1119 GtkTextBuffer *buffer;
1121 dialog = gtk_dialog_new_with_buttons ("Search",
1122 GTK_WINDOW (view->window),
1123 GTK_DIALOG_DESTROY_WITH_PARENT,
1124 "Forward", RESPONSE_FORWARD,
1125 "Backward", RESPONSE_BACKWARD,
1126 GTK_STOCK_BUTTON_CANCEL,
1127 GTK_RESPONSE_NONE, NULL);
1130 buffer = gtk_text_buffer_new (NULL);
1132 search_text = gtk_text_view_new_with_buffer (buffer);
1134 g_object_unref (G_OBJECT (buffer));
1136 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1140 g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
1142 gtk_signal_connect (GTK_OBJECT (dialog),
1144 GTK_SIGNAL_FUNC (dialog_response_callback),
1147 gtk_widget_show (search_text);
1149 gtk_widget_grab_focus (search_text);
1151 gtk_widget_show_all (dialog);
1155 view_init_menus (View *view)
1157 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1158 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1159 GtkWidget *menu_item = NULL;
1163 case GTK_TEXT_DIR_LTR:
1164 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1166 case GTK_TEXT_DIR_RTL:
1167 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1174 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1179 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1182 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1185 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
1192 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1195 static GtkItemFactoryEntry menu_items[] =
1197 { "/_File", NULL, 0, 0, "<Branch>" },
1198 { "/File/_New", "<control>N", do_new, 0, NULL },
1199 { "/File/New _View", NULL, do_new_view, 0, NULL },
1200 { "/File/_Open", "<control>O", do_open, 0, NULL },
1201 { "/File/_Save", "<control>S", do_save, 0, NULL },
1202 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1203 { "/File/sep1", NULL, 0, 0, "<Separator>" },
1204 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1205 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1207 { "/_Edit", NULL, 0, 0, "<Branch>" },
1208 { "/Edit/Find...", NULL, do_search, 0, NULL },
1210 { "/_Settings", NULL, 0, 0, "<Branch>" },
1211 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAP_NONE, "<RadioItem>" },
1212 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAP_WORD, "/Settings/Wrap Off" },
1213 { "/Settings/Wrap _Chars", NULL, do_wrap_changed, GTK_WRAP_CHAR, "/Settings/Wrap Off" },
1214 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1215 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1216 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1217 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1219 { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "<RadioItem>" },
1220 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" },
1221 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1223 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1224 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1226 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1227 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1228 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1229 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1230 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1231 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1232 { "/_Attributes", NULL, 0, 0, "<Branch>" },
1233 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1234 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1235 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1236 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1237 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1238 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1239 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1240 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
1241 { "/_Test", NULL, 0, 0, "<Branch>" },
1242 { "/Test/_Example", NULL, do_example, 0, NULL },
1246 save_buffer (Buffer *buffer)
1248 GtkTextIter start, end;
1250 gboolean result = FALSE;
1251 gboolean have_backup = FALSE;
1252 gchar *bak_filename;
1255 g_return_val_if_fail (buffer->filename != NULL, FALSE);
1257 bak_filename = g_strconcat (buffer->filename, "~", NULL);
1259 if (rename (buffer->filename, bak_filename) != 0)
1261 if (errno != ENOENT)
1263 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1264 buffer->filename, bak_filename, g_strerror (errno));
1265 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1273 file = fopen (buffer->filename, "w");
1276 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1277 buffer->filename, bak_filename, g_strerror (errno));
1278 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1282 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1283 gtk_text_buffer_get_end_iter (buffer->buffer, &end);
1285 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1287 if (fputs (chars, file) == EOF ||
1288 fclose (file) == EOF)
1290 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1291 buffer->filename, g_strerror (errno));
1292 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1300 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
1306 if (!result && have_backup)
1308 if (rename (bak_filename, buffer->filename) != 0)
1310 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1311 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1312 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1317 g_free (bak_filename);
1323 save_as_ok_func (const char *filename, gpointer data)
1325 Buffer *buffer = data;
1326 char *old_filename = buffer->filename;
1328 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1330 struct stat statbuf;
1332 if (stat (filename, &statbuf) == 0)
1334 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1335 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1343 buffer->filename = g_strdup (filename);
1345 if (save_buffer (buffer))
1347 g_free (old_filename);
1348 buffer_filename_set (buffer);
1353 g_free (buffer->filename);
1354 buffer->filename = old_filename;
1360 save_as_buffer (Buffer *buffer)
1362 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1366 check_buffer_saved (Buffer *buffer)
1368 if (gtk_text_buffer_get_modified (buffer->buffer))
1370 char *pretty_name = buffer_pretty_name (buffer);
1371 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1374 g_free (pretty_name);
1376 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1380 return save_as_buffer (buffer);
1381 else if (result == 1)
1393 create_buffer (void)
1396 PangoTabArray *tabs;
1399 buffer = g_new (Buffer, 1);
1401 buffer->buffer = gtk_text_buffer_new (NULL);
1403 buffer->refcount = 1;
1404 buffer->filename = NULL;
1405 buffer->untitled_serial = -1;
1407 buffer->color_tags = NULL;
1408 buffer->color_cycle_timeout = 0;
1409 buffer->start_hue = 0.0;
1412 while (i < N_COLORS)
1416 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1418 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1423 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1424 g_object_set (G_OBJECT (buffer->invisible_tag),
1428 buffer->not_editable_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1429 g_object_set (G_OBJECT (buffer->not_editable_tag),
1431 "foreground", "purple", NULL);
1433 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1434 g_object_set (G_OBJECT (buffer->found_text_tag),
1435 "foreground", "red", NULL);
1437 tabs = pango_tab_array_new_with_positions (4,
1442 PANGO_TAB_LEFT, 120);
1444 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1445 g_object_set (G_OBJECT (buffer->custom_tabs_tag),
1447 "foreground", "green", NULL);
1449 pango_tab_array_free (tabs);
1451 buffers = g_slist_prepend (buffers, buffer);
1457 buffer_pretty_name (Buffer *buffer)
1459 if (buffer->filename)
1462 char *result = g_path_get_basename (buffer->filename);
1463 p = strchr (result, '/');
1471 if (buffer->untitled_serial == -1)
1472 buffer->untitled_serial = untitled_serial++;
1474 if (buffer->untitled_serial == 1)
1475 return g_strdup ("Untitled");
1477 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1482 buffer_filename_set (Buffer *buffer)
1484 GSList *tmp_list = views;
1488 View *view = tmp_list->data;
1490 if (view->buffer == buffer)
1491 view_set_title (view);
1493 tmp_list = tmp_list->next;
1498 buffer_search (Buffer *buffer,
1504 GtkTextIter start, end;
1508 /* remove tag from whole buffer */
1509 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1510 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1513 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1514 gtk_text_buffer_get_mark (buffer->buffer,
1520 GtkTextIter match_start, match_end;
1524 while (gtk_text_iter_forward_search (&iter, str, TRUE, FALSE,
1525 &match_start, &match_end,
1529 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1530 &match_start, &match_end);
1537 while (gtk_text_iter_backward_search (&iter, str, TRUE, FALSE,
1538 &match_start, &match_end,
1542 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1543 &match_start, &match_end);
1550 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1553 GTK_DIALOG_DESTROY_WITH_PARENT,
1554 "%d strings found and marked in red",
1557 gtk_signal_connect_object (GTK_OBJECT (dialog),
1559 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1560 GTK_OBJECT (dialog));
1562 gtk_widget_show (dialog);
1566 buffer_search_forward (Buffer *buffer, const char *str,
1569 buffer_search (buffer, str, view, TRUE);
1573 buffer_search_backward (Buffer *buffer, const char *str,
1576 buffer_search (buffer, str, view, FALSE);
1580 buffer_ref (Buffer *buffer)
1586 buffer_unref (Buffer *buffer)
1589 if (buffer->refcount == 0)
1591 buffer_set_colors (buffer, FALSE);
1592 buffers = g_slist_remove (buffers, buffer);
1593 g_object_unref (G_OBJECT (buffer->buffer));
1594 g_free (buffer->filename);
1600 hsv_to_rgb (gdouble *h,
1604 gdouble hue, saturation, value;
1622 f = hue - (int) hue;
1623 p = value * (1.0 - saturation);
1624 q = value * (1.0 - saturation * f);
1625 t = value * (1.0 - saturation * (1.0 - f));
1666 g_assert_not_reached ();
1672 hue_to_color (gdouble hue,
1681 g_return_if_fail (hue <= 1.0);
1683 hsv_to_rgb (&h, &s, &v);
1685 color->red = h * 65535;
1686 color->green = s * 65535;
1687 color->blue = v * 65535;
1692 color_cycle_timeout (gpointer data)
1694 Buffer *buffer = data;
1696 buffer_cycle_colors (buffer);
1702 buffer_set_colors (Buffer *buffer,
1708 if (enabled && buffer->color_cycle_timeout == 0)
1709 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
1710 else if (!enabled && buffer->color_cycle_timeout != 0)
1712 gtk_timeout_remove (buffer->color_cycle_timeout);
1713 buffer->color_cycle_timeout = 0;
1716 tmp = buffer->color_tags;
1723 hue_to_color (hue, &color);
1725 g_object_set (G_OBJECT (tmp->data),
1726 "foreground_gdk", &color,
1730 g_object_set (G_OBJECT (tmp->data),
1731 "foreground_set", FALSE,
1734 hue += 1.0 / N_COLORS;
1736 tmp = g_slist_next (tmp);
1741 buffer_cycle_colors (Buffer *buffer)
1744 gdouble hue = buffer->start_hue;
1746 tmp = buffer->color_tags;
1751 hue_to_color (hue, &color);
1753 g_object_set (G_OBJECT (tmp->data),
1754 "foreground_gdk", &color,
1757 hue += 1.0 / N_COLORS;
1761 tmp = g_slist_next (tmp);
1764 buffer->start_hue += 1.0 / N_COLORS;
1765 if (buffer->start_hue > 1.0)
1766 buffer->start_hue = 0.0;
1770 close_view (View *view)
1772 views = g_slist_remove (views, view);
1773 buffer_unref (view->buffer);
1774 gtk_widget_destroy (view->window);
1775 g_object_unref (G_OBJECT (view->item_factory));
1784 check_close_view (View *view)
1786 if (view->buffer->refcount > 1 ||
1787 check_buffer_saved (view->buffer))
1792 view_set_title (View *view)
1794 char *pretty_name = buffer_pretty_name (view->buffer);
1795 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
1797 gtk_window_set_title (GTK_WINDOW (view->window), title);
1799 g_free (pretty_name);
1804 cursor_set_callback (GtkTextBuffer *buffer,
1805 const GtkTextIter *location,
1809 GtkTextView *text_view;
1811 /* Redraw tab windows if the cursor moves
1812 * on the mapped widget (windows may not exist before realization...
1815 text_view = GTK_TEXT_VIEW (user_data);
1817 if (GTK_WIDGET_MAPPED (text_view) &&
1818 mark == gtk_text_buffer_get_insert (buffer))
1820 GdkWindow *tab_window;
1822 tab_window = gtk_text_view_get_window (text_view,
1823 GTK_TEXT_WINDOW_TOP);
1825 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1827 tab_window = gtk_text_view_get_window (text_view,
1828 GTK_TEXT_WINDOW_BOTTOM);
1830 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1835 tab_stops_expose (GtkWidget *widget,
1836 GdkEventExpose *event,
1843 GdkWindow *bottom_win;
1844 GtkTextView *text_view;
1845 GtkTextWindowType type;
1846 GdkDrawable *target;
1847 gint *positions = NULL;
1849 GtkTextAttributes *attrs;
1851 GtkTextBuffer *buffer;
1854 text_view = GTK_TEXT_VIEW (widget);
1856 /* See if this expose is on the tab stop window */
1857 top_win = gtk_text_view_get_window (text_view,
1858 GTK_TEXT_WINDOW_TOP);
1860 bottom_win = gtk_text_view_get_window (text_view,
1861 GTK_TEXT_WINDOW_BOTTOM);
1863 if (event->window == top_win)
1865 type = GTK_TEXT_WINDOW_TOP;
1868 else if (event->window == bottom_win)
1870 type = GTK_TEXT_WINDOW_BOTTOM;
1871 target = bottom_win;
1876 first_x = event->area.x;
1877 last_x = first_x + event->area.width;
1879 gtk_text_view_window_to_buffer_coords (text_view,
1886 gtk_text_view_window_to_buffer_coords (text_view,
1893 buffer = gtk_text_view_get_buffer (text_view);
1895 gtk_text_buffer_get_iter_at_mark (buffer,
1897 gtk_text_buffer_get_mark (buffer,
1900 attrs = gtk_text_attributes_new ();
1902 gtk_text_iter_get_attributes (&insert, attrs);
1906 size = pango_tab_array_get_size (attrs->tabs);
1908 pango_tab_array_get_tabs (attrs->tabs,
1912 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
1920 gtk_text_attributes_unref (attrs);
1928 positions[i] = PANGO_PIXELS (positions[i]);
1930 gtk_text_view_buffer_to_window_coords (text_view,
1937 gdk_draw_line (target,
1938 widget->style->fg_gc [widget->state],
1951 get_lines (GtkTextView *text_view,
1954 GArray *buffer_coords,
1962 g_array_set_size (buffer_coords, 0);
1963 g_array_set_size (numbers, 0);
1965 /* Get iter at first y */
1966 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
1968 /* For each iter, get its location and add it to the arrays.
1969 * Stop when we pass last_y
1974 while (!gtk_text_iter_is_end (&iter))
1979 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
1981 g_array_append_val (buffer_coords, y);
1982 line_num = gtk_text_iter_get_line (&iter);
1983 g_array_append_val (numbers, line_num);
1987 if ((y + height) >= last_y)
1990 gtk_text_iter_forward_line (&iter);
1997 line_numbers_expose (GtkWidget *widget,
1998 GdkEventExpose *event,
2007 GdkWindow *left_win;
2008 GdkWindow *right_win;
2009 PangoLayout *layout;
2010 GtkTextView *text_view;
2011 GtkTextWindowType type;
2012 GdkDrawable *target;
2014 text_view = GTK_TEXT_VIEW (widget);
2016 /* See if this expose is on the line numbers window */
2017 left_win = gtk_text_view_get_window (text_view,
2018 GTK_TEXT_WINDOW_LEFT);
2020 right_win = gtk_text_view_get_window (text_view,
2021 GTK_TEXT_WINDOW_RIGHT);
2023 if (event->window == left_win)
2025 type = GTK_TEXT_WINDOW_LEFT;
2028 else if (event->window == right_win)
2030 type = GTK_TEXT_WINDOW_RIGHT;
2036 first_y = event->area.y;
2037 last_y = first_y + event->area.height;
2039 gtk_text_view_window_to_buffer_coords (text_view,
2046 gtk_text_view_window_to_buffer_coords (text_view,
2053 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2054 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2056 get_lines (text_view,
2063 /* Draw fully internationalized numbers! */
2065 layout = gtk_widget_create_pango_layout (widget, "");
2073 gtk_text_view_buffer_to_window_coords (text_view,
2076 g_array_index (pixels, gint, i),
2080 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2082 pango_layout_set_text (layout, str, -1);
2084 gtk_paint_layout (widget->style,
2086 GTK_WIDGET_STATE (widget),
2098 g_array_free (pixels, TRUE);
2099 g_array_free (numbers, TRUE);
2101 g_object_unref (G_OBJECT (layout));
2107 create_view (Buffer *buffer)
2114 view = g_new0 (View, 1);
2115 views = g_slist_prepend (views, view);
2117 view->buffer = buffer;
2118 buffer_ref (buffer);
2120 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2121 g_object_set_data (G_OBJECT (view->window), "view", view);
2123 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2124 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2126 view->accel_group = gtk_accel_group_new ();
2127 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2128 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2130 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2132 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2134 vbox = gtk_vbox_new (FALSE, 0);
2135 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2137 gtk_box_pack_start (GTK_BOX (vbox),
2138 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2141 sw = gtk_scrolled_window_new (NULL, NULL);
2142 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2143 GTK_POLICY_AUTOMATIC,
2144 GTK_POLICY_AUTOMATIC);
2146 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2147 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2150 /* Draw tab stops in the top and bottom windows. */
2152 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2153 GTK_TEXT_WINDOW_TOP,
2156 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2157 GTK_TEXT_WINDOW_BOTTOM,
2160 gtk_signal_connect (GTK_OBJECT (view->text_view),
2162 GTK_SIGNAL_FUNC (tab_stops_expose),
2165 g_signal_connect_data (G_OBJECT (view->buffer->buffer),
2167 GTK_SIGNAL_FUNC (cursor_set_callback),
2168 view->text_view, NULL, FALSE, FALSE);
2170 /* Draw line numbers in the side windows; we should really be
2171 * more scientific about what width we set them to.
2173 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2174 GTK_TEXT_WINDOW_RIGHT,
2177 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2178 GTK_TEXT_WINDOW_LEFT,
2181 gtk_signal_connect (GTK_OBJECT (view->text_view),
2183 GTK_SIGNAL_FUNC (line_numbers_expose),
2186 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2187 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2189 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2191 gtk_widget_grab_focus (view->text_view);
2193 view_set_title (view);
2194 view_init_menus (view);
2196 view_add_example_widgets (view);
2198 gtk_widget_show_all (view->window);
2203 view_add_example_widgets (View *view)
2205 GtkTextChildAnchor *anchor;
2210 buffer = view->buffer;
2212 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2215 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2219 widget = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
2220 GTK_ICON_SIZE_DIALOG);
2222 widget = gtk_button_new_with_label ("Foo");
2224 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2228 gtk_widget_show (widget);
2233 file_exists (const char *filename)
2235 struct stat statbuf;
2237 return stat (filename, &statbuf) == 0;
2242 if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
2244 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2245 putenv ("GTK_IM_MODULE_FILE=./gtk.immodules");
2250 main (int argc, char** argv)
2258 gtk_init (&argc, &argv);
2260 buffer = create_buffer ();
2261 view = create_view (buffer);
2262 buffer_unref (buffer);
2264 push_active_window (GTK_WINDOW (view->window));
2265 for (i=1; i < argc; i++)
2269 /* Quick and dirty canonicalization - better should be in GLib
2272 if (!g_path_is_absolute (argv[i]))
2274 char *cwd = g_get_current_dir ();
2275 filename = g_strconcat (cwd, "/", argv[i], NULL);
2281 open_ok_func (filename, view);
2283 if (filename != argv[i])
2286 pop_active_window ();