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),
393 G_CALLBACK (tag_event_handler),
394 NULL, NULL, FALSE, FALSE);
397 static const 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", NULL);
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", NULL);
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", NULL);
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", NULL);
480 g_object_set (G_OBJECT (tag),
481 "strikethrough", TRUE,
485 tag = gtk_text_buffer_create_tag (buffer, "underline", NULL);
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", NULL);
501 g_object_set (G_OBJECT (tag),
502 "justification", GTK_JUSTIFY_CENTER,
505 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote", NULL);
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)
704 if (GTK_IS_MENU_ITEM (widget))
706 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
707 return g_object_get_data (G_OBJECT (item_factory), "view");
711 GtkWidget *app = gtk_widget_get_toplevel (widget);
712 return g_object_get_data (G_OBJECT (app), "view");
717 do_new (gpointer callback_data,
718 guint callback_action,
721 create_view (create_buffer ());
725 do_new_view (gpointer callback_data,
726 guint callback_action,
729 View *view = view_from_widget (widget);
731 create_view (view->buffer);
735 open_ok_func (const char *filename, gpointer data)
738 View *new_view = get_empty_view (view);
740 if (!fill_file_buffer (new_view->buffer->buffer, filename))
742 if (new_view != view)
743 close_view (new_view);
748 g_free (new_view->buffer->filename);
749 new_view->buffer->filename = g_strdup (filename);
750 buffer_filename_set (new_view->buffer);
757 do_open (gpointer callback_data,
758 guint callback_action,
761 View *view = view_from_widget (widget);
763 push_active_window (GTK_WINDOW (view->window));
764 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
765 pop_active_window ();
769 do_save_as (gpointer callback_data,
770 guint callback_action,
773 View *view = view_from_widget (widget);
775 push_active_window (GTK_WINDOW (view->window));
776 save_as_buffer (view->buffer);
777 pop_active_window ();
781 do_save (gpointer callback_data,
782 guint callback_action,
785 View *view = view_from_widget (widget);
787 push_active_window (GTK_WINDOW (view->window));
788 if (!view->buffer->filename)
789 do_save_as (callback_data, callback_action, widget);
791 save_buffer (view->buffer);
792 pop_active_window ();
796 do_close (gpointer callback_data,
797 guint callback_action,
800 View *view = view_from_widget (widget);
802 push_active_window (GTK_WINDOW (view->window));
803 check_close_view (view);
804 pop_active_window ();
808 do_exit (gpointer callback_data,
809 guint callback_action,
812 View *view = view_from_widget (widget);
814 GSList *tmp_list = buffers;
816 push_active_window (GTK_WINDOW (view->window));
819 if (!check_buffer_saved (tmp_list->data))
822 tmp_list = tmp_list->next;
826 pop_active_window ();
830 do_example (gpointer callback_data,
831 guint callback_action,
834 View *view = view_from_widget (widget);
837 new_view = get_empty_view (view);
839 fill_example_buffer (new_view->buffer->buffer);
841 view_add_example_widgets (new_view);
845 do_wrap_changed (gpointer callback_data,
846 guint callback_action,
849 View *view = view_from_widget (widget);
851 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
855 do_direction_changed (gpointer callback_data,
856 guint callback_action,
859 View *view = view_from_widget (widget);
861 gtk_widget_set_direction (view->text_view, callback_action);
862 gtk_widget_queue_resize (view->text_view);
867 do_spacing_changed (gpointer callback_data,
868 guint callback_action,
871 View *view = view_from_widget (widget);
875 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
877 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
879 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
884 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
886 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
888 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
894 do_editable_changed (gpointer callback_data,
895 guint callback_action,
898 View *view = view_from_widget (widget);
900 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
904 do_cursor_visible_changed (gpointer callback_data,
905 guint callback_action,
908 View *view = view_from_widget (widget);
910 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
914 do_color_cycle_changed (gpointer callback_data,
915 guint callback_action,
918 View *view = view_from_widget (widget);
920 buffer_set_colors (view->buffer, callback_action);
924 do_apply_editable (gpointer callback_data,
925 guint callback_action,
928 View *view = view_from_widget (widget);
932 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
937 gtk_text_buffer_remove_tag (view->buffer->buffer,
938 view->buffer->not_editable_tag,
943 gtk_text_buffer_apply_tag (view->buffer->buffer,
944 view->buffer->not_editable_tag,
951 do_apply_invisible (gpointer callback_data,
952 guint callback_action,
955 View *view = view_from_widget (widget);
959 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
964 gtk_text_buffer_remove_tag (view->buffer->buffer,
965 view->buffer->invisible_tag,
970 gtk_text_buffer_apply_tag (view->buffer->buffer,
971 view->buffer->invisible_tag,
978 do_apply_tabs (gpointer callback_data,
979 guint callback_action,
982 View *view = view_from_widget (widget);
986 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
991 gtk_text_buffer_remove_tag (view->buffer->buffer,
992 view->buffer->custom_tabs_tag,
997 gtk_text_buffer_apply_tag (view->buffer->buffer,
998 view->buffer->custom_tabs_tag,
1005 do_apply_colors (gpointer callback_data,
1006 guint callback_action,
1009 View *view = view_from_widget (widget);
1010 Buffer *buffer = view->buffer;
1014 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1017 if (!callback_action)
1021 tmp = buffer->color_tags;
1024 gtk_text_buffer_remove_tag (view->buffer->buffer,
1027 tmp = g_slist_next (tmp);
1034 tmp = buffer->color_tags;
1038 gboolean done = FALSE;
1041 gtk_text_iter_forward_char (&next);
1042 gtk_text_iter_forward_char (&next);
1044 if (gtk_text_iter_compare (&next, &end) > 0)
1050 gtk_text_buffer_apply_tag (view->buffer->buffer,
1059 tmp = g_slist_next (tmp);
1061 tmp = buffer->color_tags;
1074 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1076 GtkTextBuffer *buffer;
1078 GtkTextIter start, end;
1079 gchar *search_string;
1081 if (response_id != RESPONSE_FORWARD &&
1082 response_id != RESPONSE_BACKWARD)
1084 gtk_widget_destroy (dialog);
1088 buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
1090 gtk_text_buffer_get_bounds (buffer, &start, &end);
1092 /* Remove trailing newline */
1093 gtk_text_iter_backward_char (&end);
1095 search_string = gtk_text_iter_get_text (&start, &end);
1097 printf ("Searching for `%s'\n", search_string);
1099 if (response_id == RESPONSE_FORWARD)
1100 buffer_search_forward (view->buffer, search_string, view);
1101 else if (response_id == RESPONSE_BACKWARD)
1102 buffer_search_backward (view->buffer, search_string, view);
1104 g_free (search_string);
1106 gtk_widget_destroy (dialog);
1110 do_search (gpointer callback_data,
1111 guint callback_action,
1114 View *view = view_from_widget (widget);
1116 GtkWidget *search_text;
1117 GtkTextBuffer *buffer;
1119 dialog = gtk_dialog_new_with_buttons ("Search",
1120 GTK_WINDOW (view->window),
1121 GTK_DIALOG_DESTROY_WITH_PARENT,
1122 "Forward", RESPONSE_FORWARD,
1123 "Backward", RESPONSE_BACKWARD,
1124 GTK_STOCK_BUTTON_CANCEL,
1125 GTK_RESPONSE_NONE, NULL);
1128 buffer = gtk_text_buffer_new (NULL);
1130 search_text = gtk_text_view_new_with_buffer (buffer);
1132 g_object_unref (G_OBJECT (buffer));
1134 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1138 g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
1140 gtk_signal_connect (GTK_OBJECT (dialog),
1142 GTK_SIGNAL_FUNC (dialog_response_callback),
1145 gtk_widget_show (search_text);
1147 gtk_widget_grab_focus (search_text);
1149 gtk_widget_show_all (dialog);
1153 view_init_menus (View *view)
1155 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1156 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1157 GtkWidget *menu_item = NULL;
1161 case GTK_TEXT_DIR_LTR:
1162 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1164 case GTK_TEXT_DIR_RTL:
1165 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1172 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1177 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1180 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1183 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
1190 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1193 static GtkItemFactoryEntry menu_items[] =
1195 { "/_File", NULL, 0, 0, "<Branch>" },
1196 { "/File/_New", "<control>N", do_new, 0, NULL },
1197 { "/File/New _View", NULL, do_new_view, 0, NULL },
1198 { "/File/_Open", "<control>O", do_open, 0, NULL },
1199 { "/File/_Save", "<control>S", do_save, 0, NULL },
1200 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1201 { "/File/sep1", NULL, 0, 0, "<Separator>" },
1202 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1203 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1205 { "/_Edit", NULL, 0, 0, "<Branch>" },
1206 { "/Edit/Find...", NULL, do_search, 0, NULL },
1208 { "/_Settings", NULL, 0, 0, "<Branch>" },
1209 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAP_NONE, "<RadioItem>" },
1210 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAP_WORD, "/Settings/Wrap Off" },
1211 { "/Settings/Wrap _Chars", NULL, do_wrap_changed, GTK_WRAP_CHAR, "/Settings/Wrap Off" },
1212 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1213 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1214 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1215 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1217 { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "<RadioItem>" },
1218 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" },
1219 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1221 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1222 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1224 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1225 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1226 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1227 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1228 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1229 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1230 { "/_Attributes", NULL, 0, 0, "<Branch>" },
1231 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1232 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1233 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1234 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1235 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1236 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1237 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1238 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
1239 { "/_Test", NULL, 0, 0, "<Branch>" },
1240 { "/Test/_Example", NULL, do_example, 0, NULL },
1244 save_buffer (Buffer *buffer)
1246 GtkTextIter start, end;
1248 gboolean result = FALSE;
1249 gboolean have_backup = FALSE;
1250 gchar *bak_filename;
1253 g_return_val_if_fail (buffer->filename != NULL, FALSE);
1255 bak_filename = g_strconcat (buffer->filename, "~", NULL);
1257 if (rename (buffer->filename, bak_filename) != 0)
1259 if (errno != ENOENT)
1261 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1262 buffer->filename, bak_filename, g_strerror (errno));
1263 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1271 file = fopen (buffer->filename, "w");
1274 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1275 buffer->filename, bak_filename, g_strerror (errno));
1276 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1280 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1281 gtk_text_buffer_get_end_iter (buffer->buffer, &end);
1283 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1285 if (fputs (chars, file) == EOF ||
1286 fclose (file) == EOF)
1288 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1289 buffer->filename, g_strerror (errno));
1290 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1298 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
1304 if (!result && have_backup)
1306 if (rename (bak_filename, buffer->filename) != 0)
1308 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1309 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1310 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1315 g_free (bak_filename);
1321 save_as_ok_func (const char *filename, gpointer data)
1323 Buffer *buffer = data;
1324 char *old_filename = buffer->filename;
1326 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1328 struct stat statbuf;
1330 if (stat (filename, &statbuf) == 0)
1332 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1333 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1341 buffer->filename = g_strdup (filename);
1343 if (save_buffer (buffer))
1345 g_free (old_filename);
1346 buffer_filename_set (buffer);
1351 g_free (buffer->filename);
1352 buffer->filename = old_filename;
1358 save_as_buffer (Buffer *buffer)
1360 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1364 check_buffer_saved (Buffer *buffer)
1366 if (gtk_text_buffer_get_modified (buffer->buffer))
1368 char *pretty_name = buffer_pretty_name (buffer);
1369 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1372 g_free (pretty_name);
1374 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1378 return save_as_buffer (buffer);
1379 else if (result == 1)
1391 create_buffer (void)
1394 PangoTabArray *tabs;
1397 buffer = g_new (Buffer, 1);
1399 buffer->buffer = gtk_text_buffer_new (NULL);
1401 buffer->refcount = 1;
1402 buffer->filename = NULL;
1403 buffer->untitled_serial = -1;
1405 buffer->color_tags = NULL;
1406 buffer->color_cycle_timeout = 0;
1407 buffer->start_hue = 0.0;
1410 while (i < N_COLORS)
1414 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL, NULL);
1416 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1421 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1422 "invisible", TRUE, NULL);
1424 buffer->not_editable_tag =
1425 gtk_text_buffer_create_tag (buffer->buffer, NULL,
1427 "foreground", "purple", NULL);
1429 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1430 "foreground", "red", NULL);
1432 tabs = pango_tab_array_new_with_positions (4,
1437 PANGO_TAB_LEFT, 120);
1439 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1441 "foreground", "green", NULL);
1443 pango_tab_array_free (tabs);
1445 buffers = g_slist_prepend (buffers, buffer);
1451 buffer_pretty_name (Buffer *buffer)
1453 if (buffer->filename)
1456 char *result = g_path_get_basename (buffer->filename);
1457 p = strchr (result, '/');
1465 if (buffer->untitled_serial == -1)
1466 buffer->untitled_serial = untitled_serial++;
1468 if (buffer->untitled_serial == 1)
1469 return g_strdup ("Untitled");
1471 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1476 buffer_filename_set (Buffer *buffer)
1478 GSList *tmp_list = views;
1482 View *view = tmp_list->data;
1484 if (view->buffer == buffer)
1485 view_set_title (view);
1487 tmp_list = tmp_list->next;
1492 buffer_search (Buffer *buffer,
1498 GtkTextIter start, end;
1502 /* remove tag from whole buffer */
1503 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1504 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1507 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1508 gtk_text_buffer_get_mark (buffer->buffer,
1514 GtkTextIter match_start, match_end;
1518 while (gtk_text_iter_forward_search (&iter, str, TRUE, FALSE,
1519 &match_start, &match_end,
1523 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1524 &match_start, &match_end);
1531 while (gtk_text_iter_backward_search (&iter, str, TRUE, FALSE,
1532 &match_start, &match_end,
1536 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1537 &match_start, &match_end);
1544 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1547 GTK_DIALOG_DESTROY_WITH_PARENT,
1548 "%d strings found and marked in red",
1551 gtk_signal_connect_object (GTK_OBJECT (dialog),
1553 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1554 GTK_OBJECT (dialog));
1556 gtk_widget_show (dialog);
1560 buffer_search_forward (Buffer *buffer, const char *str,
1563 buffer_search (buffer, str, view, TRUE);
1567 buffer_search_backward (Buffer *buffer, const char *str,
1570 buffer_search (buffer, str, view, FALSE);
1574 buffer_ref (Buffer *buffer)
1580 buffer_unref (Buffer *buffer)
1583 if (buffer->refcount == 0)
1585 buffer_set_colors (buffer, FALSE);
1586 buffers = g_slist_remove (buffers, buffer);
1587 g_object_unref (G_OBJECT (buffer->buffer));
1588 g_free (buffer->filename);
1594 hsv_to_rgb (gdouble *h,
1598 gdouble hue, saturation, value;
1616 f = hue - (int) hue;
1617 p = value * (1.0 - saturation);
1618 q = value * (1.0 - saturation * f);
1619 t = value * (1.0 - saturation * (1.0 - f));
1660 g_assert_not_reached ();
1666 hue_to_color (gdouble hue,
1675 g_return_if_fail (hue <= 1.0);
1677 hsv_to_rgb (&h, &s, &v);
1679 color->red = h * 65535;
1680 color->green = s * 65535;
1681 color->blue = v * 65535;
1686 color_cycle_timeout (gpointer data)
1688 Buffer *buffer = data;
1690 buffer_cycle_colors (buffer);
1696 buffer_set_colors (Buffer *buffer,
1702 if (enabled && buffer->color_cycle_timeout == 0)
1703 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
1704 else if (!enabled && buffer->color_cycle_timeout != 0)
1706 gtk_timeout_remove (buffer->color_cycle_timeout);
1707 buffer->color_cycle_timeout = 0;
1710 tmp = buffer->color_tags;
1717 hue_to_color (hue, &color);
1719 g_object_set (G_OBJECT (tmp->data),
1720 "foreground_gdk", &color,
1724 g_object_set (G_OBJECT (tmp->data),
1725 "foreground_set", FALSE,
1728 hue += 1.0 / N_COLORS;
1730 tmp = g_slist_next (tmp);
1735 buffer_cycle_colors (Buffer *buffer)
1738 gdouble hue = buffer->start_hue;
1740 tmp = buffer->color_tags;
1745 hue_to_color (hue, &color);
1747 g_object_set (G_OBJECT (tmp->data),
1748 "foreground_gdk", &color,
1751 hue += 1.0 / N_COLORS;
1755 tmp = g_slist_next (tmp);
1758 buffer->start_hue += 1.0 / N_COLORS;
1759 if (buffer->start_hue > 1.0)
1760 buffer->start_hue = 0.0;
1764 close_view (View *view)
1766 views = g_slist_remove (views, view);
1767 buffer_unref (view->buffer);
1768 gtk_widget_destroy (view->window);
1769 g_object_unref (G_OBJECT (view->item_factory));
1778 check_close_view (View *view)
1780 if (view->buffer->refcount > 1 ||
1781 check_buffer_saved (view->buffer))
1786 view_set_title (View *view)
1788 char *pretty_name = buffer_pretty_name (view->buffer);
1789 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
1791 gtk_window_set_title (GTK_WINDOW (view->window), title);
1793 g_free (pretty_name);
1798 cursor_set_callback (GtkTextBuffer *buffer,
1799 const GtkTextIter *location,
1803 GtkTextView *text_view;
1805 /* Redraw tab windows if the cursor moves
1806 * on the mapped widget (windows may not exist before realization...
1809 text_view = GTK_TEXT_VIEW (user_data);
1811 if (GTK_WIDGET_MAPPED (text_view) &&
1812 mark == gtk_text_buffer_get_insert (buffer))
1814 GdkWindow *tab_window;
1816 tab_window = gtk_text_view_get_window (text_view,
1817 GTK_TEXT_WINDOW_TOP);
1819 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1821 tab_window = gtk_text_view_get_window (text_view,
1822 GTK_TEXT_WINDOW_BOTTOM);
1824 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1829 tab_stops_expose (GtkWidget *widget,
1830 GdkEventExpose *event,
1837 GdkWindow *bottom_win;
1838 GtkTextView *text_view;
1839 GtkTextWindowType type;
1840 GdkDrawable *target;
1841 gint *positions = NULL;
1843 GtkTextAttributes *attrs;
1845 GtkTextBuffer *buffer;
1848 text_view = GTK_TEXT_VIEW (widget);
1850 /* See if this expose is on the tab stop window */
1851 top_win = gtk_text_view_get_window (text_view,
1852 GTK_TEXT_WINDOW_TOP);
1854 bottom_win = gtk_text_view_get_window (text_view,
1855 GTK_TEXT_WINDOW_BOTTOM);
1857 if (event->window == top_win)
1859 type = GTK_TEXT_WINDOW_TOP;
1862 else if (event->window == bottom_win)
1864 type = GTK_TEXT_WINDOW_BOTTOM;
1865 target = bottom_win;
1870 first_x = event->area.x;
1871 last_x = first_x + event->area.width;
1873 gtk_text_view_window_to_buffer_coords (text_view,
1880 gtk_text_view_window_to_buffer_coords (text_view,
1887 buffer = gtk_text_view_get_buffer (text_view);
1889 gtk_text_buffer_get_iter_at_mark (buffer,
1891 gtk_text_buffer_get_mark (buffer,
1894 attrs = gtk_text_attributes_new ();
1896 gtk_text_iter_get_attributes (&insert, attrs);
1900 size = pango_tab_array_get_size (attrs->tabs);
1902 pango_tab_array_get_tabs (attrs->tabs,
1906 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
1914 gtk_text_attributes_unref (attrs);
1922 positions[i] = PANGO_PIXELS (positions[i]);
1924 gtk_text_view_buffer_to_window_coords (text_view,
1931 gdk_draw_line (target,
1932 widget->style->fg_gc [widget->state],
1945 get_lines (GtkTextView *text_view,
1948 GArray *buffer_coords,
1956 g_array_set_size (buffer_coords, 0);
1957 g_array_set_size (numbers, 0);
1959 /* Get iter at first y */
1960 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
1962 /* For each iter, get its location and add it to the arrays.
1963 * Stop when we pass last_y
1968 while (!gtk_text_iter_is_end (&iter))
1973 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
1975 g_array_append_val (buffer_coords, y);
1976 line_num = gtk_text_iter_get_line (&iter);
1977 g_array_append_val (numbers, line_num);
1981 if ((y + height) >= last_y)
1984 gtk_text_iter_forward_line (&iter);
1991 line_numbers_expose (GtkWidget *widget,
1992 GdkEventExpose *event,
2001 GdkWindow *left_win;
2002 GdkWindow *right_win;
2003 PangoLayout *layout;
2004 GtkTextView *text_view;
2005 GtkTextWindowType type;
2006 GdkDrawable *target;
2008 text_view = GTK_TEXT_VIEW (widget);
2010 /* See if this expose is on the line numbers window */
2011 left_win = gtk_text_view_get_window (text_view,
2012 GTK_TEXT_WINDOW_LEFT);
2014 right_win = gtk_text_view_get_window (text_view,
2015 GTK_TEXT_WINDOW_RIGHT);
2017 if (event->window == left_win)
2019 type = GTK_TEXT_WINDOW_LEFT;
2022 else if (event->window == right_win)
2024 type = GTK_TEXT_WINDOW_RIGHT;
2030 first_y = event->area.y;
2031 last_y = first_y + event->area.height;
2033 gtk_text_view_window_to_buffer_coords (text_view,
2040 gtk_text_view_window_to_buffer_coords (text_view,
2047 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2048 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2050 get_lines (text_view,
2057 /* Draw fully internationalized numbers! */
2059 layout = gtk_widget_create_pango_layout (widget, "");
2067 gtk_text_view_buffer_to_window_coords (text_view,
2070 g_array_index (pixels, gint, i),
2074 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2076 pango_layout_set_text (layout, str, -1);
2078 gtk_paint_layout (widget->style,
2080 GTK_WIDGET_STATE (widget),
2092 g_array_free (pixels, TRUE);
2093 g_array_free (numbers, TRUE);
2095 g_object_unref (G_OBJECT (layout));
2101 create_view (Buffer *buffer)
2108 view = g_new0 (View, 1);
2109 views = g_slist_prepend (views, view);
2111 view->buffer = buffer;
2112 buffer_ref (buffer);
2114 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2115 g_object_set_data (G_OBJECT (view->window), "view", view);
2117 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2118 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2120 view->accel_group = gtk_accel_group_new ();
2121 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2122 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2124 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2126 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2128 vbox = gtk_vbox_new (FALSE, 0);
2129 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2131 gtk_box_pack_start (GTK_BOX (vbox),
2132 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2135 sw = gtk_scrolled_window_new (NULL, NULL);
2136 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2137 GTK_POLICY_AUTOMATIC,
2138 GTK_POLICY_AUTOMATIC);
2140 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2141 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2144 /* Draw tab stops in the top and bottom windows. */
2146 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2147 GTK_TEXT_WINDOW_TOP,
2150 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2151 GTK_TEXT_WINDOW_BOTTOM,
2154 gtk_signal_connect (GTK_OBJECT (view->text_view),
2156 GTK_SIGNAL_FUNC (tab_stops_expose),
2159 g_signal_connect_data (G_OBJECT (view->buffer->buffer),
2161 GTK_SIGNAL_FUNC (cursor_set_callback),
2162 view->text_view, NULL, FALSE, FALSE);
2164 /* Draw line numbers in the side windows; we should really be
2165 * more scientific about what width we set them to.
2167 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2168 GTK_TEXT_WINDOW_RIGHT,
2171 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2172 GTK_TEXT_WINDOW_LEFT,
2175 gtk_signal_connect (GTK_OBJECT (view->text_view),
2177 GTK_SIGNAL_FUNC (line_numbers_expose),
2180 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2181 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2183 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2185 gtk_widget_grab_focus (view->text_view);
2187 view_set_title (view);
2188 view_init_menus (view);
2190 view_add_example_widgets (view);
2192 gtk_widget_show_all (view->window);
2197 view_add_example_widgets (View *view)
2199 GtkTextChildAnchor *anchor;
2204 buffer = view->buffer;
2206 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2209 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2213 widget = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
2214 GTK_ICON_SIZE_DIALOG);
2216 widget = gtk_button_new_with_label ("Foo");
2218 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2222 gtk_widget_show (widget);
2227 file_exists (const char *filename)
2229 struct stat statbuf;
2231 return stat (filename, &statbuf) == 0;
2236 if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
2238 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2239 putenv ("GTK_IM_MODULE_FILE=./gtk.immodules");
2244 main (int argc, char** argv)
2252 gtk_init (&argc, &argv);
2254 buffer = create_buffer ();
2255 view = create_view (buffer);
2256 buffer_unref (buffer);
2258 push_active_window (GTK_WINDOW (view->window));
2259 for (i=1; i < argc; i++)
2263 /* Quick and dirty canonicalization - better should be in GLib
2266 if (!g_path_is_absolute (argv[i]))
2268 char *cwd = g_get_current_dir ();
2269 filename = g_strconcat (cwd, "/", argv[i], NULL);
2275 open_ok_func (filename, view);
2277 if (filename != argv[i])
2280 pop_active_window ();