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 gtk_object_ref (GTK_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 = gtk_object_get_data (GTK_OBJECT (filesel), "ok-func");
106 gpointer data = gtk_object_get_data (GTK_OBJECT (filesel), "ok-data");
107 gint *result = gtk_object_get_data (GTK_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 gtk_object_set_data (GTK_OBJECT (filesel), "ok-func", func);
141 gtk_object_set_data (GTK_OBJECT (filesel), "ok-data", data);
142 gtk_object_set_data (GTK_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 gtk_object_set (GTK_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)
392 gtk_signal_connect (GTK_OBJECT (tag),
394 GTK_SIGNAL_FUNC (tag_event_handler),
398 static char *book_closed_xpm[] = {
424 fill_example_buffer (GtkTextBuffer *buffer)
426 GtkTextIter iter, iter2;
433 GtkTextChildAnchor *anchor;
435 /* FIXME this is broken if called twice on a buffer, since
436 * we try to create tags a second time.
439 tag = gtk_text_buffer_create_tag (buffer, "fg_blue");
441 /* gtk_timeout_add (1000, blink_timeout, tag); */
445 color.red = color.green = 0;
450 gtk_object_set (GTK_OBJECT (tag),
451 "foreground_gdk", &color,
452 "background_gdk", &color2,
456 tag = gtk_text_buffer_create_tag (buffer, "fg_red");
460 color.blue = color.green = 0;
462 gtk_object_set (GTK_OBJECT (tag),
463 "rise", -4 * PANGO_SCALE,
464 "foreground_gdk", &color,
467 tag = gtk_text_buffer_create_tag (buffer, "bg_green");
471 color.blue = color.red = 0;
472 color.green = 0xffff;
473 gtk_object_set (GTK_OBJECT (tag),
474 "background_gdk", &color,
478 tag = gtk_text_buffer_create_tag (buffer, "strikethrough");
482 gtk_object_set (GTK_OBJECT (tag),
483 "strikethrough", TRUE,
487 tag = gtk_text_buffer_create_tag (buffer, "underline");
491 gtk_object_set (GTK_OBJECT (tag),
492 "underline", PANGO_UNDERLINE_SINGLE,
497 gtk_object_set (GTK_OBJECT (tag),
498 "underline", PANGO_UNDERLINE_SINGLE,
501 tag = gtk_text_buffer_create_tag (buffer, "centered");
503 gtk_object_set (GTK_OBJECT (tag),
504 "justify", GTK_JUSTIFY_CENTER,
507 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote");
509 gtk_object_set (GTK_OBJECT (tag),
510 "wrap_mode", GTK_WRAPMODE_WORD,
511 "direction", GTK_TEXT_DIR_RTL,
519 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
521 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
523 g_object_ref (G_OBJECT (anchor));
525 g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
526 (GDestroyNotify) g_object_unref);
529 pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
534 GtkTextMark * temp_mark;
536 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
538 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
540 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",
543 gtk_text_buffer_insert (buffer, &iter, str, -1);
547 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
549 gtk_text_buffer_insert (buffer, &iter,
550 "(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"
551 /* This is UTF8 stuff, Emacs doesn't
552 really know how to display it */
553 "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew שלום Japanese (日本語)\n", -1);
556 gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
559 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
560 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
562 gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
564 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
565 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
567 gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
569 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
570 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
572 gtk_text_buffer_apply_tag_by_name (buffer, "strikethrough", &iter, &iter2);
574 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
575 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
577 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
579 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
580 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
582 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
584 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
585 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
587 gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
590 gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
591 gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
593 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
594 gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
596 gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
597 gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
598 gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1);
599 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
600 gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
605 g_object_unref (G_OBJECT (pixbuf));
607 printf ("%d lines %d chars\n",
608 gtk_text_buffer_get_line_count (buffer),
609 gtk_text_buffer_get_char_count (buffer));
611 /* Move cursor to start */
612 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
613 gtk_text_buffer_place_cursor (buffer, &iter);
615 gtk_text_buffer_set_modified (buffer, FALSE);
619 fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
624 GtkTextIter iter, end;
626 f = fopen (filename, "r");
630 gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
631 filename, g_strerror (errno));
632 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
637 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
641 char *leftover, *next;
642 int to_read = 2047 - remaining;
644 count = fread (buf + remaining, 1, to_read, f);
645 buf[count + remaining] = '\0';
647 leftover = next = buf;
654 next = g_utf8_next_char (next);
655 if (next > buf+count+remaining) {
661 gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
663 remaining = buf + remaining + count - leftover;
664 g_memmove (buf, leftover, remaining);
666 if (remaining > 6 || count < to_read)
672 gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
673 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
677 /* We had a newline in the buffer to begin with. (The buffer always contains
678 * a newline, so we delete to the end of the buffer to clean up.
680 gtk_text_buffer_get_last_iter (buffer, &end);
681 gtk_text_buffer_delete (buffer, &iter, &end);
683 gtk_text_buffer_set_modified (buffer, FALSE);
689 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
691 View *view = view_from_widget (window);
693 push_active_window (GTK_WINDOW (window));
694 check_close_view (view);
695 pop_active_window ();
705 get_empty_view (View *view)
707 if (!view->buffer->filename &&
708 !gtk_text_buffer_modified (view->buffer->buffer))
711 return create_view (create_buffer ());
715 view_from_widget (GtkWidget *widget)
719 if (GTK_IS_MENU_ITEM (widget))
721 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
722 return gtk_object_get_data (GTK_OBJECT (item_factory), "view");
726 GtkWidget *app = gtk_widget_get_toplevel (widget);
727 return gtk_object_get_data (GTK_OBJECT (app), "view");
732 do_new (gpointer callback_data,
733 guint callback_action,
736 create_view (create_buffer ());
740 do_new_view (gpointer callback_data,
741 guint callback_action,
744 View *view = view_from_widget (widget);
746 create_view (view->buffer);
750 open_ok_func (const char *filename, gpointer data)
753 View *new_view = get_empty_view (view);
755 if (!fill_file_buffer (new_view->buffer->buffer, filename))
757 if (new_view != view)
758 close_view (new_view);
763 g_free (new_view->buffer->filename);
764 new_view->buffer->filename = g_strdup (filename);
765 buffer_filename_set (new_view->buffer);
772 do_open (gpointer callback_data,
773 guint callback_action,
776 View *view = view_from_widget (widget);
778 push_active_window (GTK_WINDOW (view->window));
779 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
780 pop_active_window ();
784 do_save_as (gpointer callback_data,
785 guint callback_action,
788 View *view = view_from_widget (widget);
790 push_active_window (GTK_WINDOW (view->window));
791 save_as_buffer (view->buffer);
792 pop_active_window ();
796 do_save (gpointer callback_data,
797 guint callback_action,
800 View *view = view_from_widget (widget);
802 push_active_window (GTK_WINDOW (view->window));
803 if (!view->buffer->filename)
804 do_save_as (callback_data, callback_action, widget);
806 save_buffer (view->buffer);
807 pop_active_window ();
811 do_close (gpointer callback_data,
812 guint callback_action,
815 View *view = view_from_widget (widget);
817 push_active_window (GTK_WINDOW (view->window));
818 check_close_view (view);
819 pop_active_window ();
823 do_exit (gpointer callback_data,
824 guint callback_action,
827 View *view = view_from_widget (widget);
829 GSList *tmp_list = buffers;
831 push_active_window (GTK_WINDOW (view->window));
834 if (!check_buffer_saved (tmp_list->data))
837 tmp_list = tmp_list->next;
841 pop_active_window ();
845 do_example (gpointer callback_data,
846 guint callback_action,
849 View *view = view_from_widget (widget);
852 new_view = get_empty_view (view);
854 fill_example_buffer (new_view->buffer->buffer);
856 view_add_example_widgets (new_view);
860 do_wrap_changed (gpointer callback_data,
861 guint callback_action,
864 View *view = view_from_widget (widget);
866 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
870 do_direction_changed (gpointer callback_data,
871 guint callback_action,
874 View *view = view_from_widget (widget);
876 gtk_widget_set_direction (view->text_view, callback_action);
877 gtk_widget_queue_resize (view->text_view);
882 do_spacing_changed (gpointer callback_data,
883 guint callback_action,
886 View *view = view_from_widget (widget);
890 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
892 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
894 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
899 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
901 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
903 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
909 do_editable_changed (gpointer callback_data,
910 guint callback_action,
913 View *view = view_from_widget (widget);
915 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
919 do_cursor_visible_changed (gpointer callback_data,
920 guint callback_action,
923 View *view = view_from_widget (widget);
925 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
929 do_color_cycle_changed (gpointer callback_data,
930 guint callback_action,
933 View *view = view_from_widget (widget);
935 buffer_set_colors (view->buffer, callback_action);
939 do_apply_editable (gpointer callback_data,
940 guint callback_action,
943 View *view = view_from_widget (widget);
947 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
952 gtk_text_buffer_remove_tag (view->buffer->buffer,
953 view->buffer->not_editable_tag,
958 gtk_text_buffer_apply_tag (view->buffer->buffer,
959 view->buffer->not_editable_tag,
966 do_apply_invisible (gpointer callback_data,
967 guint callback_action,
970 View *view = view_from_widget (widget);
974 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
979 gtk_text_buffer_remove_tag (view->buffer->buffer,
980 view->buffer->invisible_tag,
985 gtk_text_buffer_apply_tag (view->buffer->buffer,
986 view->buffer->invisible_tag,
993 do_apply_tabs (gpointer callback_data,
994 guint callback_action,
997 View *view = view_from_widget (widget);
1001 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1004 if (callback_action)
1006 gtk_text_buffer_remove_tag (view->buffer->buffer,
1007 view->buffer->custom_tabs_tag,
1012 gtk_text_buffer_apply_tag (view->buffer->buffer,
1013 view->buffer->custom_tabs_tag,
1020 do_apply_colors (gpointer callback_data,
1021 guint callback_action,
1024 View *view = view_from_widget (widget);
1025 Buffer *buffer = view->buffer;
1029 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1032 if (!callback_action)
1036 tmp = buffer->color_tags;
1039 gtk_text_buffer_remove_tag (view->buffer->buffer,
1042 tmp = g_slist_next (tmp);
1049 tmp = buffer->color_tags;
1053 gboolean done = FALSE;
1056 gtk_text_iter_forward_char (&next);
1057 gtk_text_iter_forward_char (&next);
1059 if (gtk_text_iter_compare (&next, &end) > 0)
1065 gtk_text_buffer_apply_tag (view->buffer->buffer,
1074 tmp = g_slist_next (tmp);
1076 tmp = buffer->color_tags;
1089 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1091 GtkTextBuffer *buffer;
1093 GtkTextIter start, end;
1094 gchar *search_string;
1096 if (response_id != RESPONSE_FORWARD &&
1097 response_id != RESPONSE_BACKWARD)
1099 gtk_widget_destroy (dialog);
1103 buffer = gtk_object_get_data (GTK_OBJECT (dialog), "buffer");
1105 gtk_text_buffer_get_bounds (buffer, &start, &end);
1107 /* Remove trailing newline */
1108 gtk_text_iter_backward_char (&end);
1110 search_string = gtk_text_iter_get_text (&start, &end);
1112 printf ("Searching for `%s'\n", search_string);
1114 if (response_id == RESPONSE_FORWARD)
1115 buffer_search_forward (view->buffer, search_string, view);
1116 else if (response_id == RESPONSE_BACKWARD)
1117 buffer_search_backward (view->buffer, search_string, view);
1119 g_free (search_string);
1121 gtk_widget_destroy (dialog);
1125 do_search (gpointer callback_data,
1126 guint callback_action,
1129 View *view = view_from_widget (widget);
1131 GtkWidget *search_text;
1132 GtkTextBuffer *buffer;
1134 dialog = gtk_dialog_new_with_buttons ("Search",
1135 GTK_WINDOW (view->window),
1136 GTK_DIALOG_DESTROY_WITH_PARENT,
1137 "Forward", RESPONSE_FORWARD,
1138 "Backward", RESPONSE_BACKWARD,
1139 GTK_STOCK_BUTTON_CANCEL,
1140 GTK_RESPONSE_NONE, NULL);
1143 buffer = gtk_text_buffer_new (NULL);
1145 search_text = gtk_text_view_new_with_buffer (buffer);
1147 g_object_unref (G_OBJECT (buffer));
1149 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1153 gtk_object_set_data (GTK_OBJECT (dialog), "buffer", buffer);
1155 gtk_signal_connect (GTK_OBJECT (dialog),
1157 GTK_SIGNAL_FUNC (dialog_response_callback),
1160 gtk_widget_show (search_text);
1162 gtk_widget_grab_focus (search_text);
1164 gtk_widget_show_all (dialog);
1168 view_init_menus (View *view)
1170 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1171 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1172 GtkWidget *menu_item = NULL;
1176 case GTK_TEXT_DIR_LTR:
1177 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1179 case GTK_TEXT_DIR_RTL:
1180 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1187 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1191 case GTK_WRAPMODE_NONE:
1192 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1194 case GTK_WRAPMODE_WORD:
1195 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1202 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1205 static GtkItemFactoryEntry menu_items[] =
1207 { "/_File", NULL, 0, 0, "<Branch>" },
1208 { "/File/_New", "<control>N", do_new, 0, NULL },
1209 { "/File/New _View", NULL, do_new_view, 0, NULL },
1210 { "/File/_Open", "<control>O", do_open, 0, NULL },
1211 { "/File/_Save", "<control>S", do_save, 0, NULL },
1212 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1213 { "/File/sep1", NULL, 0, 0, "<Separator>" },
1214 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1215 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1217 { "/_Edit", NULL, 0, 0, "<Branch>" },
1218 { "/Edit/Find...", NULL, do_search, 0, NULL },
1220 { "/_Settings", NULL, 0, 0, "<Branch>" },
1221 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAPMODE_NONE, "<RadioItem>" },
1222 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAPMODE_WORD, "/Settings/Wrap Off" },
1223 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1224 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1225 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1226 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1228 { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "<RadioItem>" },
1229 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" },
1230 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1232 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1233 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1235 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1236 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1237 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1238 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1239 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1240 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1241 { "/_Attributes", NULL, 0, 0, "<Branch>" },
1242 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1243 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1244 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1245 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1246 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1247 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1248 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1249 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
1250 { "/_Test", NULL, 0, 0, "<Branch>" },
1251 { "/Test/_Example", NULL, do_example, 0, NULL },
1255 save_buffer (Buffer *buffer)
1257 GtkTextIter start, end;
1259 gboolean result = FALSE;
1260 gboolean have_backup = FALSE;
1261 gchar *bak_filename;
1264 g_return_val_if_fail (buffer->filename != NULL, FALSE);
1266 bak_filename = g_strconcat (buffer->filename, "~", NULL);
1268 if (rename (buffer->filename, bak_filename) != 0)
1270 if (errno != ENOENT)
1272 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1273 buffer->filename, bak_filename, g_strerror (errno));
1274 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1282 file = fopen (buffer->filename, "w");
1285 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1286 buffer->filename, bak_filename, g_strerror (errno));
1287 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1291 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1292 gtk_text_buffer_get_last_iter (buffer->buffer, &end);
1294 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1296 if (fputs (chars, file) == EOF ||
1297 fclose (file) == EOF)
1299 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1300 buffer->filename, g_strerror (errno));
1301 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1309 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
1315 if (!result && have_backup)
1317 if (rename (bak_filename, buffer->filename) != 0)
1319 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1320 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1321 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1326 g_free (bak_filename);
1332 save_as_ok_func (const char *filename, gpointer data)
1334 Buffer *buffer = data;
1335 char *old_filename = buffer->filename;
1337 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1339 struct stat statbuf;
1341 if (stat (filename, &statbuf) == 0)
1343 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1344 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1352 buffer->filename = g_strdup (filename);
1354 if (save_buffer (buffer))
1356 g_free (old_filename);
1357 buffer_filename_set (buffer);
1362 g_free (buffer->filename);
1363 buffer->filename = old_filename;
1369 save_as_buffer (Buffer *buffer)
1371 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1375 check_buffer_saved (Buffer *buffer)
1377 if (gtk_text_buffer_modified (buffer->buffer))
1379 char *pretty_name = buffer_pretty_name (buffer);
1380 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1383 g_free (pretty_name);
1385 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1389 return save_as_buffer (buffer);
1390 else if (result == 1)
1402 create_buffer (void)
1405 PangoTabArray *tabs;
1408 buffer = g_new (Buffer, 1);
1410 buffer->buffer = gtk_text_buffer_new (NULL);
1412 buffer->refcount = 1;
1413 buffer->filename = NULL;
1414 buffer->untitled_serial = -1;
1416 buffer->color_tags = NULL;
1417 buffer->color_cycle_timeout = 0;
1418 buffer->start_hue = 0.0;
1421 while (i < N_COLORS)
1425 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1427 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1432 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1433 gtk_object_set (GTK_OBJECT (buffer->invisible_tag),
1437 buffer->not_editable_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1438 gtk_object_set (GTK_OBJECT (buffer->not_editable_tag),
1440 "foreground", "purple", NULL);
1442 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1443 gtk_object_set (GTK_OBJECT (buffer->found_text_tag),
1444 "foreground", "red", NULL);
1446 tabs = pango_tab_array_new_with_positions (4,
1451 PANGO_TAB_LEFT, 120);
1453 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1454 gtk_object_set (GTK_OBJECT (buffer->custom_tabs_tag),
1456 "foreground", "green", NULL);
1458 pango_tab_array_free (tabs);
1460 buffers = g_slist_prepend (buffers, buffer);
1466 buffer_pretty_name (Buffer *buffer)
1468 if (buffer->filename)
1471 char *result = g_path_get_basename (buffer->filename);
1472 p = strchr (result, '/');
1480 if (buffer->untitled_serial == -1)
1481 buffer->untitled_serial = untitled_serial++;
1483 if (buffer->untitled_serial == 1)
1484 return g_strdup ("Untitled");
1486 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1491 buffer_filename_set (Buffer *buffer)
1493 GSList *tmp_list = views;
1497 View *view = tmp_list->data;
1499 if (view->buffer == buffer)
1500 view_set_title (view);
1502 tmp_list = tmp_list->next;
1507 buffer_search (Buffer *buffer,
1513 GtkTextIter start, end;
1517 /* remove tag from whole buffer */
1518 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1519 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1522 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1523 gtk_text_buffer_get_mark (buffer->buffer,
1529 GtkTextIter match_start, match_end;
1533 while (gtk_text_iter_forward_search (&iter, str, TRUE, FALSE,
1534 &match_start, &match_end,
1538 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1539 &match_start, &match_end);
1546 while (gtk_text_iter_backward_search (&iter, str, TRUE, FALSE,
1547 &match_start, &match_end,
1551 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1552 &match_start, &match_end);
1559 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1562 GTK_DIALOG_DESTROY_WITH_PARENT,
1563 "%d strings found and marked in red",
1566 gtk_signal_connect_object (GTK_OBJECT (dialog),
1568 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1569 GTK_OBJECT (dialog));
1571 gtk_widget_show (dialog);
1575 buffer_search_forward (Buffer *buffer, const char *str,
1578 buffer_search (buffer, str, view, TRUE);
1582 buffer_search_backward (Buffer *buffer, const char *str,
1585 buffer_search (buffer, str, view, FALSE);
1589 buffer_ref (Buffer *buffer)
1595 buffer_unref (Buffer *buffer)
1598 if (buffer->refcount == 0)
1600 buffer_set_colors (buffer, FALSE);
1601 buffers = g_slist_remove (buffers, buffer);
1602 gtk_object_unref (GTK_OBJECT (buffer->buffer));
1603 g_free (buffer->filename);
1609 hsv_to_rgb (gdouble *h,
1613 gdouble hue, saturation, value;
1631 f = hue - (int) hue;
1632 p = value * (1.0 - saturation);
1633 q = value * (1.0 - saturation * f);
1634 t = value * (1.0 - saturation * (1.0 - f));
1675 g_assert_not_reached ();
1681 hue_to_color (gdouble hue,
1690 g_return_if_fail (hue <= 1.0);
1692 hsv_to_rgb (&h, &s, &v);
1694 color->red = h * 65535;
1695 color->green = s * 65535;
1696 color->blue = v * 65535;
1701 color_cycle_timeout (gpointer data)
1703 Buffer *buffer = data;
1705 buffer_cycle_colors (buffer);
1711 buffer_set_colors (Buffer *buffer,
1717 if (enabled && buffer->color_cycle_timeout == 0)
1718 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
1719 else if (!enabled && buffer->color_cycle_timeout != 0)
1721 gtk_timeout_remove (buffer->color_cycle_timeout);
1722 buffer->color_cycle_timeout = 0;
1725 tmp = buffer->color_tags;
1732 hue_to_color (hue, &color);
1734 gtk_object_set (GTK_OBJECT (tmp->data),
1735 "foreground_gdk", &color,
1739 gtk_object_set (GTK_OBJECT (tmp->data),
1740 "foreground_set", FALSE,
1743 hue += 1.0 / N_COLORS;
1745 tmp = g_slist_next (tmp);
1750 buffer_cycle_colors (Buffer *buffer)
1753 gdouble hue = buffer->start_hue;
1755 tmp = buffer->color_tags;
1760 hue_to_color (hue, &color);
1762 gtk_object_set (GTK_OBJECT (tmp->data),
1763 "foreground_gdk", &color,
1766 hue += 1.0 / N_COLORS;
1770 tmp = g_slist_next (tmp);
1773 buffer->start_hue += 1.0 / N_COLORS;
1774 if (buffer->start_hue > 1.0)
1775 buffer->start_hue = 0.0;
1779 close_view (View *view)
1781 views = g_slist_remove (views, view);
1782 buffer_unref (view->buffer);
1783 gtk_widget_destroy (view->window);
1784 g_object_unref (G_OBJECT (view->item_factory));
1793 check_close_view (View *view)
1795 if (view->buffer->refcount > 1 ||
1796 check_buffer_saved (view->buffer))
1801 view_set_title (View *view)
1803 char *pretty_name = buffer_pretty_name (view->buffer);
1804 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
1806 gtk_window_set_title (GTK_WINDOW (view->window), title);
1808 g_free (pretty_name);
1813 cursor_set_callback (GtkTextBuffer *buffer,
1814 const GtkTextIter *location,
1818 GtkTextView *text_view;
1820 /* Redraw tab windows if the cursor moves
1821 * on the mapped widget (windows may not exist before realization...
1824 text_view = GTK_TEXT_VIEW (user_data);
1826 if (GTK_WIDGET_MAPPED (text_view) &&
1827 mark == gtk_text_buffer_get_insert (buffer))
1829 GdkWindow *tab_window;
1831 tab_window = gtk_text_view_get_window (text_view,
1832 GTK_TEXT_WINDOW_TOP);
1834 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1836 tab_window = gtk_text_view_get_window (text_view,
1837 GTK_TEXT_WINDOW_BOTTOM);
1839 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1844 tab_stops_expose (GtkWidget *widget,
1845 GdkEventExpose *event,
1852 GdkWindow *bottom_win;
1853 GtkTextView *text_view;
1854 GtkTextWindowType type;
1855 GdkDrawable *target;
1856 gint *positions = NULL;
1858 GtkTextAttributes *attrs;
1860 GtkTextBuffer *buffer;
1863 text_view = GTK_TEXT_VIEW (widget);
1865 /* See if this expose is on the tab stop window */
1866 top_win = gtk_text_view_get_window (text_view,
1867 GTK_TEXT_WINDOW_TOP);
1869 bottom_win = gtk_text_view_get_window (text_view,
1870 GTK_TEXT_WINDOW_BOTTOM);
1872 if (event->window == top_win)
1874 type = GTK_TEXT_WINDOW_TOP;
1877 else if (event->window == bottom_win)
1879 type = GTK_TEXT_WINDOW_BOTTOM;
1880 target = bottom_win;
1885 first_x = event->area.x;
1886 last_x = first_x + event->area.width;
1888 gtk_text_view_window_to_buffer_coords (text_view,
1895 gtk_text_view_window_to_buffer_coords (text_view,
1902 buffer = gtk_text_view_get_buffer (text_view);
1904 gtk_text_buffer_get_iter_at_mark (buffer,
1906 gtk_text_buffer_get_mark (buffer,
1909 attrs = gtk_text_attributes_new ();
1911 gtk_text_iter_get_attributes (&insert, attrs);
1915 size = pango_tab_array_get_size (attrs->tabs);
1917 pango_tab_array_get_tabs (attrs->tabs,
1921 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
1929 gtk_text_attributes_unref (attrs);
1937 positions[i] = PANGO_PIXELS (positions[i]);
1939 gtk_text_view_buffer_to_window_coords (text_view,
1946 gdk_draw_line (target,
1947 widget->style->fg_gc [widget->state],
1960 get_lines (GtkTextView *text_view,
1963 GArray *buffer_coords,
1971 g_array_set_size (buffer_coords, 0);
1972 g_array_set_size (numbers, 0);
1974 /* Get iter at first y */
1975 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
1977 /* For each iter, get its location and add it to the arrays.
1978 * Stop when we pass last_y
1983 while (!gtk_text_iter_is_last (&iter))
1988 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
1990 g_array_append_val (buffer_coords, y);
1991 line_num = gtk_text_iter_get_line (&iter);
1992 g_array_append_val (numbers, line_num);
1996 if ((y + height) >= last_y)
1999 gtk_text_iter_forward_line (&iter);
2006 line_numbers_expose (GtkWidget *widget,
2007 GdkEventExpose *event,
2016 GdkWindow *left_win;
2017 GdkWindow *right_win;
2018 PangoLayout *layout;
2019 GtkTextView *text_view;
2020 GtkTextWindowType type;
2021 GdkDrawable *target;
2023 text_view = GTK_TEXT_VIEW (widget);
2025 /* See if this expose is on the line numbers window */
2026 left_win = gtk_text_view_get_window (text_view,
2027 GTK_TEXT_WINDOW_LEFT);
2029 right_win = gtk_text_view_get_window (text_view,
2030 GTK_TEXT_WINDOW_RIGHT);
2032 if (event->window == left_win)
2034 type = GTK_TEXT_WINDOW_LEFT;
2037 else if (event->window == right_win)
2039 type = GTK_TEXT_WINDOW_RIGHT;
2045 first_y = event->area.y;
2046 last_y = first_y + event->area.height;
2048 gtk_text_view_window_to_buffer_coords (text_view,
2055 gtk_text_view_window_to_buffer_coords (text_view,
2062 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2063 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2065 get_lines (text_view,
2072 /* Draw fully internationalized numbers! */
2074 layout = gtk_widget_create_pango_layout (widget, "");
2082 gtk_text_view_buffer_to_window_coords (text_view,
2085 g_array_index (pixels, gint, i),
2089 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2091 pango_layout_set_text (layout, str, -1);
2094 gdk_draw_layout (target,
2095 widget->style->fg_gc [widget->state],
2096 /* 2 is just a random padding */
2105 g_array_free (pixels, TRUE);
2106 g_array_free (numbers, TRUE);
2108 g_object_unref (G_OBJECT (layout));
2114 create_view (Buffer *buffer)
2121 view = g_new0 (View, 1);
2122 views = g_slist_prepend (views, view);
2124 view->buffer = buffer;
2125 buffer_ref (buffer);
2127 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2128 gtk_object_set_data (GTK_OBJECT (view->window), "view", view);
2130 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2131 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2133 view->accel_group = gtk_accel_group_new ();
2134 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2135 gtk_object_set_data (GTK_OBJECT (view->item_factory), "view", view);
2137 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2139 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2141 vbox = gtk_vbox_new (FALSE, 0);
2142 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2144 gtk_box_pack_start (GTK_BOX (vbox),
2145 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2148 sw = gtk_scrolled_window_new (NULL, NULL);
2149 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2150 GTK_POLICY_AUTOMATIC,
2151 GTK_POLICY_AUTOMATIC);
2153 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2154 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2157 /* Draw tab stops in the top and bottom windows. */
2159 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2160 GTK_TEXT_WINDOW_TOP,
2163 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2164 GTK_TEXT_WINDOW_BOTTOM,
2167 gtk_signal_connect (GTK_OBJECT (view->text_view),
2169 GTK_SIGNAL_FUNC (tab_stops_expose),
2172 gtk_signal_connect (GTK_OBJECT (view->buffer->buffer),
2174 GTK_SIGNAL_FUNC (cursor_set_callback),
2177 /* Draw line numbers in the side windows; we should really be
2178 * more scientific about what width we set them to.
2180 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2181 GTK_TEXT_WINDOW_RIGHT,
2184 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2185 GTK_TEXT_WINDOW_LEFT,
2188 gtk_signal_connect (GTK_OBJECT (view->text_view),
2190 GTK_SIGNAL_FUNC (line_numbers_expose),
2193 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2194 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2196 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2198 gtk_widget_grab_focus (view->text_view);
2200 view_set_title (view);
2201 view_init_menus (view);
2203 view_add_example_widgets (view);
2205 gtk_widget_show_all (view->window);
2210 view_add_example_widgets (View *view)
2212 GtkTextChildAnchor *anchor;
2217 buffer = view->buffer;
2219 anchor = gtk_object_get_data (GTK_OBJECT (buffer->buffer),
2222 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2226 widget = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
2227 GTK_ICON_SIZE_DIALOG);
2229 widget = gtk_button_new_with_label ("Foo");
2231 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2235 gtk_widget_show (widget);
2240 file_exists (const char *filename)
2242 struct stat statbuf;
2244 return stat (filename, &statbuf) == 0;
2249 if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
2251 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2252 putenv ("GTK_IM_MODULE_FILE=./gtk.immodules");
2257 main (int argc, char** argv)
2265 gtk_init (&argc, &argv);
2267 buffer = create_buffer ();
2268 view = create_view (buffer);
2269 buffer_unref (buffer);
2271 push_active_window (GTK_WINDOW (view->window));
2272 for (i=1; i < argc; i++)
2276 /* Quick and dirty canonicalization - better should be in GLib
2279 if (!g_path_is_absolute (argv[i]))
2281 char *cwd = g_get_current_dir ();
2282 filename = g_strconcat (cwd, "/", argv[i], NULL);
2288 open_ok_func (filename, view);
2290 if (filename != argv[i])
2293 pop_active_window ();