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 const char *leftover;
642 int to_read = 2047 - remaining;
644 count = fread (buf + remaining, 1, to_read, f);
645 buf[count + remaining] = '\0';
647 g_utf8_validate (buf, -1, &leftover);
649 g_assert (g_utf8_validate (buf, leftover - buf, NULL));
650 gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
652 remaining = (buf + remaining + count) - leftover;
653 g_memmove (buf, leftover, remaining);
655 if (remaining > 6 || count < to_read)
661 gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
662 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
666 /* We had a newline in the buffer to begin with. (The buffer always contains
667 * a newline, so we delete to the end of the buffer to clean up.
669 gtk_text_buffer_get_last_iter (buffer, &end);
670 gtk_text_buffer_delete (buffer, &iter, &end);
672 gtk_text_buffer_set_modified (buffer, FALSE);
678 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
680 View *view = view_from_widget (window);
682 push_active_window (GTK_WINDOW (window));
683 check_close_view (view);
684 pop_active_window ();
694 get_empty_view (View *view)
696 if (!view->buffer->filename &&
697 !gtk_text_buffer_modified (view->buffer->buffer))
700 return create_view (create_buffer ());
704 view_from_widget (GtkWidget *widget)
708 if (GTK_IS_MENU_ITEM (widget))
710 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
711 return gtk_object_get_data (GTK_OBJECT (item_factory), "view");
715 GtkWidget *app = gtk_widget_get_toplevel (widget);
716 return gtk_object_get_data (GTK_OBJECT (app), "view");
721 do_new (gpointer callback_data,
722 guint callback_action,
725 create_view (create_buffer ());
729 do_new_view (gpointer callback_data,
730 guint callback_action,
733 View *view = view_from_widget (widget);
735 create_view (view->buffer);
739 open_ok_func (const char *filename, gpointer data)
742 View *new_view = get_empty_view (view);
744 if (!fill_file_buffer (new_view->buffer->buffer, filename))
746 if (new_view != view)
747 close_view (new_view);
752 g_free (new_view->buffer->filename);
753 new_view->buffer->filename = g_strdup (filename);
754 buffer_filename_set (new_view->buffer);
761 do_open (gpointer callback_data,
762 guint callback_action,
765 View *view = view_from_widget (widget);
767 push_active_window (GTK_WINDOW (view->window));
768 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
769 pop_active_window ();
773 do_save_as (gpointer callback_data,
774 guint callback_action,
777 View *view = view_from_widget (widget);
779 push_active_window (GTK_WINDOW (view->window));
780 save_as_buffer (view->buffer);
781 pop_active_window ();
785 do_save (gpointer callback_data,
786 guint callback_action,
789 View *view = view_from_widget (widget);
791 push_active_window (GTK_WINDOW (view->window));
792 if (!view->buffer->filename)
793 do_save_as (callback_data, callback_action, widget);
795 save_buffer (view->buffer);
796 pop_active_window ();
800 do_close (gpointer callback_data,
801 guint callback_action,
804 View *view = view_from_widget (widget);
806 push_active_window (GTK_WINDOW (view->window));
807 check_close_view (view);
808 pop_active_window ();
812 do_exit (gpointer callback_data,
813 guint callback_action,
816 View *view = view_from_widget (widget);
818 GSList *tmp_list = buffers;
820 push_active_window (GTK_WINDOW (view->window));
823 if (!check_buffer_saved (tmp_list->data))
826 tmp_list = tmp_list->next;
830 pop_active_window ();
834 do_example (gpointer callback_data,
835 guint callback_action,
838 View *view = view_from_widget (widget);
841 new_view = get_empty_view (view);
843 fill_example_buffer (new_view->buffer->buffer);
845 view_add_example_widgets (new_view);
849 do_wrap_changed (gpointer callback_data,
850 guint callback_action,
853 View *view = view_from_widget (widget);
855 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
859 do_direction_changed (gpointer callback_data,
860 guint callback_action,
863 View *view = view_from_widget (widget);
865 gtk_widget_set_direction (view->text_view, callback_action);
866 gtk_widget_queue_resize (view->text_view);
871 do_spacing_changed (gpointer callback_data,
872 guint callback_action,
875 View *view = view_from_widget (widget);
879 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
881 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
883 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
888 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
890 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
892 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
898 do_editable_changed (gpointer callback_data,
899 guint callback_action,
902 View *view = view_from_widget (widget);
904 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
908 do_cursor_visible_changed (gpointer callback_data,
909 guint callback_action,
912 View *view = view_from_widget (widget);
914 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
918 do_color_cycle_changed (gpointer callback_data,
919 guint callback_action,
922 View *view = view_from_widget (widget);
924 buffer_set_colors (view->buffer, callback_action);
928 do_apply_editable (gpointer callback_data,
929 guint callback_action,
932 View *view = view_from_widget (widget);
936 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
941 gtk_text_buffer_remove_tag (view->buffer->buffer,
942 view->buffer->not_editable_tag,
947 gtk_text_buffer_apply_tag (view->buffer->buffer,
948 view->buffer->not_editable_tag,
955 do_apply_invisible (gpointer callback_data,
956 guint callback_action,
959 View *view = view_from_widget (widget);
963 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
968 gtk_text_buffer_remove_tag (view->buffer->buffer,
969 view->buffer->invisible_tag,
974 gtk_text_buffer_apply_tag (view->buffer->buffer,
975 view->buffer->invisible_tag,
982 do_apply_tabs (gpointer callback_data,
983 guint callback_action,
986 View *view = view_from_widget (widget);
990 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
995 gtk_text_buffer_remove_tag (view->buffer->buffer,
996 view->buffer->custom_tabs_tag,
1001 gtk_text_buffer_apply_tag (view->buffer->buffer,
1002 view->buffer->custom_tabs_tag,
1009 do_apply_colors (gpointer callback_data,
1010 guint callback_action,
1013 View *view = view_from_widget (widget);
1014 Buffer *buffer = view->buffer;
1018 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1021 if (!callback_action)
1025 tmp = buffer->color_tags;
1028 gtk_text_buffer_remove_tag (view->buffer->buffer,
1031 tmp = g_slist_next (tmp);
1038 tmp = buffer->color_tags;
1042 gboolean done = FALSE;
1045 gtk_text_iter_forward_char (&next);
1046 gtk_text_iter_forward_char (&next);
1048 if (gtk_text_iter_compare (&next, &end) > 0)
1054 gtk_text_buffer_apply_tag (view->buffer->buffer,
1063 tmp = g_slist_next (tmp);
1065 tmp = buffer->color_tags;
1078 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1080 GtkTextBuffer *buffer;
1082 GtkTextIter start, end;
1083 gchar *search_string;
1085 if (response_id != RESPONSE_FORWARD &&
1086 response_id != RESPONSE_BACKWARD)
1088 gtk_widget_destroy (dialog);
1092 buffer = gtk_object_get_data (GTK_OBJECT (dialog), "buffer");
1094 gtk_text_buffer_get_bounds (buffer, &start, &end);
1096 /* Remove trailing newline */
1097 gtk_text_iter_backward_char (&end);
1099 search_string = gtk_text_iter_get_text (&start, &end);
1101 printf ("Searching for `%s'\n", search_string);
1103 if (response_id == RESPONSE_FORWARD)
1104 buffer_search_forward (view->buffer, search_string, view);
1105 else if (response_id == RESPONSE_BACKWARD)
1106 buffer_search_backward (view->buffer, search_string, view);
1108 g_free (search_string);
1110 gtk_widget_destroy (dialog);
1114 do_search (gpointer callback_data,
1115 guint callback_action,
1118 View *view = view_from_widget (widget);
1120 GtkWidget *search_text;
1121 GtkTextBuffer *buffer;
1123 dialog = gtk_dialog_new_with_buttons ("Search",
1124 GTK_WINDOW (view->window),
1125 GTK_DIALOG_DESTROY_WITH_PARENT,
1126 "Forward", RESPONSE_FORWARD,
1127 "Backward", RESPONSE_BACKWARD,
1128 GTK_STOCK_BUTTON_CANCEL,
1129 GTK_RESPONSE_NONE, NULL);
1132 buffer = gtk_text_buffer_new (NULL);
1134 search_text = gtk_text_view_new_with_buffer (buffer);
1136 g_object_unref (G_OBJECT (buffer));
1138 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1142 gtk_object_set_data (GTK_OBJECT (dialog), "buffer", buffer);
1144 gtk_signal_connect (GTK_OBJECT (dialog),
1146 GTK_SIGNAL_FUNC (dialog_response_callback),
1149 gtk_widget_show (search_text);
1151 gtk_widget_grab_focus (search_text);
1153 gtk_widget_show_all (dialog);
1157 view_init_menus (View *view)
1159 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1160 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1161 GtkWidget *menu_item = NULL;
1165 case GTK_TEXT_DIR_LTR:
1166 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1168 case GTK_TEXT_DIR_RTL:
1169 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1176 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1180 case GTK_WRAPMODE_NONE:
1181 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1183 case GTK_WRAPMODE_WORD:
1184 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1191 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1194 static GtkItemFactoryEntry menu_items[] =
1196 { "/_File", NULL, 0, 0, "<Branch>" },
1197 { "/File/_New", "<control>N", do_new, 0, NULL },
1198 { "/File/New _View", NULL, do_new_view, 0, NULL },
1199 { "/File/_Open", "<control>O", do_open, 0, NULL },
1200 { "/File/_Save", "<control>S", do_save, 0, NULL },
1201 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1202 { "/File/sep1", NULL, 0, 0, "<Separator>" },
1203 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1204 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1206 { "/_Edit", NULL, 0, 0, "<Branch>" },
1207 { "/Edit/Find...", NULL, do_search, 0, NULL },
1209 { "/_Settings", NULL, 0, 0, "<Branch>" },
1210 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAPMODE_NONE, "<RadioItem>" },
1211 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAPMODE_WORD, "/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_last_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_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);
1416 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1421 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1422 gtk_object_set (GTK_OBJECT (buffer->invisible_tag),
1426 buffer->not_editable_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1427 gtk_object_set (GTK_OBJECT (buffer->not_editable_tag),
1429 "foreground", "purple", NULL);
1431 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1432 gtk_object_set (GTK_OBJECT (buffer->found_text_tag),
1433 "foreground", "red", NULL);
1435 tabs = pango_tab_array_new_with_positions (4,
1440 PANGO_TAB_LEFT, 120);
1442 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1443 gtk_object_set (GTK_OBJECT (buffer->custom_tabs_tag),
1445 "foreground", "green", NULL);
1447 pango_tab_array_free (tabs);
1449 buffers = g_slist_prepend (buffers, buffer);
1455 buffer_pretty_name (Buffer *buffer)
1457 if (buffer->filename)
1460 char *result = g_path_get_basename (buffer->filename);
1461 p = strchr (result, '/');
1469 if (buffer->untitled_serial == -1)
1470 buffer->untitled_serial = untitled_serial++;
1472 if (buffer->untitled_serial == 1)
1473 return g_strdup ("Untitled");
1475 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1480 buffer_filename_set (Buffer *buffer)
1482 GSList *tmp_list = views;
1486 View *view = tmp_list->data;
1488 if (view->buffer == buffer)
1489 view_set_title (view);
1491 tmp_list = tmp_list->next;
1496 buffer_search (Buffer *buffer,
1502 GtkTextIter start, end;
1506 /* remove tag from whole buffer */
1507 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1508 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1511 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1512 gtk_text_buffer_get_mark (buffer->buffer,
1518 GtkTextIter match_start, match_end;
1522 while (gtk_text_iter_forward_search (&iter, str, TRUE, FALSE,
1523 &match_start, &match_end,
1527 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1528 &match_start, &match_end);
1535 while (gtk_text_iter_backward_search (&iter, str, TRUE, FALSE,
1536 &match_start, &match_end,
1540 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1541 &match_start, &match_end);
1548 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1551 GTK_DIALOG_DESTROY_WITH_PARENT,
1552 "%d strings found and marked in red",
1555 gtk_signal_connect_object (GTK_OBJECT (dialog),
1557 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1558 GTK_OBJECT (dialog));
1560 gtk_widget_show (dialog);
1564 buffer_search_forward (Buffer *buffer, const char *str,
1567 buffer_search (buffer, str, view, TRUE);
1571 buffer_search_backward (Buffer *buffer, const char *str,
1574 buffer_search (buffer, str, view, FALSE);
1578 buffer_ref (Buffer *buffer)
1584 buffer_unref (Buffer *buffer)
1587 if (buffer->refcount == 0)
1589 buffer_set_colors (buffer, FALSE);
1590 buffers = g_slist_remove (buffers, buffer);
1591 gtk_object_unref (GTK_OBJECT (buffer->buffer));
1592 g_free (buffer->filename);
1598 hsv_to_rgb (gdouble *h,
1602 gdouble hue, saturation, value;
1620 f = hue - (int) hue;
1621 p = value * (1.0 - saturation);
1622 q = value * (1.0 - saturation * f);
1623 t = value * (1.0 - saturation * (1.0 - f));
1664 g_assert_not_reached ();
1670 hue_to_color (gdouble hue,
1679 g_return_if_fail (hue <= 1.0);
1681 hsv_to_rgb (&h, &s, &v);
1683 color->red = h * 65535;
1684 color->green = s * 65535;
1685 color->blue = v * 65535;
1690 color_cycle_timeout (gpointer data)
1692 Buffer *buffer = data;
1694 buffer_cycle_colors (buffer);
1700 buffer_set_colors (Buffer *buffer,
1706 if (enabled && buffer->color_cycle_timeout == 0)
1707 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
1708 else if (!enabled && buffer->color_cycle_timeout != 0)
1710 gtk_timeout_remove (buffer->color_cycle_timeout);
1711 buffer->color_cycle_timeout = 0;
1714 tmp = buffer->color_tags;
1721 hue_to_color (hue, &color);
1723 gtk_object_set (GTK_OBJECT (tmp->data),
1724 "foreground_gdk", &color,
1728 gtk_object_set (GTK_OBJECT (tmp->data),
1729 "foreground_set", FALSE,
1732 hue += 1.0 / N_COLORS;
1734 tmp = g_slist_next (tmp);
1739 buffer_cycle_colors (Buffer *buffer)
1742 gdouble hue = buffer->start_hue;
1744 tmp = buffer->color_tags;
1749 hue_to_color (hue, &color);
1751 gtk_object_set (GTK_OBJECT (tmp->data),
1752 "foreground_gdk", &color,
1755 hue += 1.0 / N_COLORS;
1759 tmp = g_slist_next (tmp);
1762 buffer->start_hue += 1.0 / N_COLORS;
1763 if (buffer->start_hue > 1.0)
1764 buffer->start_hue = 0.0;
1768 close_view (View *view)
1770 views = g_slist_remove (views, view);
1771 buffer_unref (view->buffer);
1772 gtk_widget_destroy (view->window);
1773 g_object_unref (G_OBJECT (view->item_factory));
1782 check_close_view (View *view)
1784 if (view->buffer->refcount > 1 ||
1785 check_buffer_saved (view->buffer))
1790 view_set_title (View *view)
1792 char *pretty_name = buffer_pretty_name (view->buffer);
1793 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
1795 gtk_window_set_title (GTK_WINDOW (view->window), title);
1797 g_free (pretty_name);
1802 cursor_set_callback (GtkTextBuffer *buffer,
1803 const GtkTextIter *location,
1807 GtkTextView *text_view;
1809 /* Redraw tab windows if the cursor moves
1810 * on the mapped widget (windows may not exist before realization...
1813 text_view = GTK_TEXT_VIEW (user_data);
1815 if (GTK_WIDGET_MAPPED (text_view) &&
1816 mark == gtk_text_buffer_get_insert (buffer))
1818 GdkWindow *tab_window;
1820 tab_window = gtk_text_view_get_window (text_view,
1821 GTK_TEXT_WINDOW_TOP);
1823 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1825 tab_window = gtk_text_view_get_window (text_view,
1826 GTK_TEXT_WINDOW_BOTTOM);
1828 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1833 tab_stops_expose (GtkWidget *widget,
1834 GdkEventExpose *event,
1841 GdkWindow *bottom_win;
1842 GtkTextView *text_view;
1843 GtkTextWindowType type;
1844 GdkDrawable *target;
1845 gint *positions = NULL;
1847 GtkTextAttributes *attrs;
1849 GtkTextBuffer *buffer;
1852 text_view = GTK_TEXT_VIEW (widget);
1854 /* See if this expose is on the tab stop window */
1855 top_win = gtk_text_view_get_window (text_view,
1856 GTK_TEXT_WINDOW_TOP);
1858 bottom_win = gtk_text_view_get_window (text_view,
1859 GTK_TEXT_WINDOW_BOTTOM);
1861 if (event->window == top_win)
1863 type = GTK_TEXT_WINDOW_TOP;
1866 else if (event->window == bottom_win)
1868 type = GTK_TEXT_WINDOW_BOTTOM;
1869 target = bottom_win;
1874 first_x = event->area.x;
1875 last_x = first_x + event->area.width;
1877 gtk_text_view_window_to_buffer_coords (text_view,
1884 gtk_text_view_window_to_buffer_coords (text_view,
1891 buffer = gtk_text_view_get_buffer (text_view);
1893 gtk_text_buffer_get_iter_at_mark (buffer,
1895 gtk_text_buffer_get_mark (buffer,
1898 attrs = gtk_text_attributes_new ();
1900 gtk_text_iter_get_attributes (&insert, attrs);
1904 size = pango_tab_array_get_size (attrs->tabs);
1906 pango_tab_array_get_tabs (attrs->tabs,
1910 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
1918 gtk_text_attributes_unref (attrs);
1926 positions[i] = PANGO_PIXELS (positions[i]);
1928 gtk_text_view_buffer_to_window_coords (text_view,
1935 gdk_draw_line (target,
1936 widget->style->fg_gc [widget->state],
1949 get_lines (GtkTextView *text_view,
1952 GArray *buffer_coords,
1960 g_array_set_size (buffer_coords, 0);
1961 g_array_set_size (numbers, 0);
1963 /* Get iter at first y */
1964 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
1966 /* For each iter, get its location and add it to the arrays.
1967 * Stop when we pass last_y
1972 while (!gtk_text_iter_is_last (&iter))
1977 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
1979 g_array_append_val (buffer_coords, y);
1980 line_num = gtk_text_iter_get_line (&iter);
1981 g_array_append_val (numbers, line_num);
1985 if ((y + height) >= last_y)
1988 gtk_text_iter_forward_line (&iter);
1995 line_numbers_expose (GtkWidget *widget,
1996 GdkEventExpose *event,
2005 GdkWindow *left_win;
2006 GdkWindow *right_win;
2007 PangoLayout *layout;
2008 GtkTextView *text_view;
2009 GtkTextWindowType type;
2010 GdkDrawable *target;
2012 text_view = GTK_TEXT_VIEW (widget);
2014 /* See if this expose is on the line numbers window */
2015 left_win = gtk_text_view_get_window (text_view,
2016 GTK_TEXT_WINDOW_LEFT);
2018 right_win = gtk_text_view_get_window (text_view,
2019 GTK_TEXT_WINDOW_RIGHT);
2021 if (event->window == left_win)
2023 type = GTK_TEXT_WINDOW_LEFT;
2026 else if (event->window == right_win)
2028 type = GTK_TEXT_WINDOW_RIGHT;
2034 first_y = event->area.y;
2035 last_y = first_y + event->area.height;
2037 gtk_text_view_window_to_buffer_coords (text_view,
2044 gtk_text_view_window_to_buffer_coords (text_view,
2051 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2052 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2054 get_lines (text_view,
2061 /* Draw fully internationalized numbers! */
2063 layout = gtk_widget_create_pango_layout (widget, "");
2071 gtk_text_view_buffer_to_window_coords (text_view,
2074 g_array_index (pixels, gint, i),
2078 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2080 pango_layout_set_text (layout, str, -1);
2083 gdk_draw_layout (target,
2084 widget->style->fg_gc [widget->state],
2085 /* 2 is just a random padding */
2094 g_array_free (pixels, TRUE);
2095 g_array_free (numbers, TRUE);
2097 g_object_unref (G_OBJECT (layout));
2103 create_view (Buffer *buffer)
2110 view = g_new0 (View, 1);
2111 views = g_slist_prepend (views, view);
2113 view->buffer = buffer;
2114 buffer_ref (buffer);
2116 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2117 gtk_object_set_data (GTK_OBJECT (view->window), "view", view);
2119 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2120 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2122 view->accel_group = gtk_accel_group_new ();
2123 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2124 gtk_object_set_data (GTK_OBJECT (view->item_factory), "view", view);
2126 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2128 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2130 vbox = gtk_vbox_new (FALSE, 0);
2131 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2133 gtk_box_pack_start (GTK_BOX (vbox),
2134 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2137 sw = gtk_scrolled_window_new (NULL, NULL);
2138 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2139 GTK_POLICY_AUTOMATIC,
2140 GTK_POLICY_AUTOMATIC);
2142 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2143 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2146 /* Draw tab stops in the top and bottom windows. */
2148 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2149 GTK_TEXT_WINDOW_TOP,
2152 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2153 GTK_TEXT_WINDOW_BOTTOM,
2156 gtk_signal_connect (GTK_OBJECT (view->text_view),
2158 GTK_SIGNAL_FUNC (tab_stops_expose),
2161 gtk_signal_connect (GTK_OBJECT (view->buffer->buffer),
2163 GTK_SIGNAL_FUNC (cursor_set_callback),
2166 /* Draw line numbers in the side windows; we should really be
2167 * more scientific about what width we set them to.
2169 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2170 GTK_TEXT_WINDOW_RIGHT,
2173 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2174 GTK_TEXT_WINDOW_LEFT,
2177 gtk_signal_connect (GTK_OBJECT (view->text_view),
2179 GTK_SIGNAL_FUNC (line_numbers_expose),
2182 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2183 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2185 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2187 gtk_widget_grab_focus (view->text_view);
2189 view_set_title (view);
2190 view_init_menus (view);
2192 view_add_example_widgets (view);
2194 gtk_widget_show_all (view->window);
2199 view_add_example_widgets (View *view)
2201 GtkTextChildAnchor *anchor;
2206 buffer = view->buffer;
2208 anchor = gtk_object_get_data (GTK_OBJECT (buffer->buffer),
2211 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2215 widget = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
2216 GTK_ICON_SIZE_DIALOG);
2218 widget = gtk_button_new_with_label ("Foo");
2220 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2224 gtk_widget_show (widget);
2229 file_exists (const char *filename)
2231 struct stat statbuf;
2233 return stat (filename, &statbuf) == 0;
2238 if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
2240 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2241 putenv ("GTK_IM_MODULE_FILE=./gtk.immodules");
2246 main (int argc, char** argv)
2254 gtk_init (&argc, &argv);
2256 buffer = create_buffer ();
2257 view = create_view (buffer);
2258 buffer_unref (buffer);
2260 push_active_window (GTK_WINDOW (view->window));
2261 for (i=1; i < argc; i++)
2265 /* Quick and dirty canonicalization - better should be in GLib
2268 if (!g_path_is_absolute (argv[i]))
2270 char *cwd = g_get_current_dir ();
2271 filename = g_strconcat (cwd, "/", argv[i], NULL);
2277 open_ok_func (filename, view);
2279 if (filename != argv[i])
2282 pop_active_window ();