8 #include <gdk/gdkkeysyms.h>
10 typedef struct _Buffer Buffer;
11 typedef struct _View View;
13 static gint untitled_serial = 1;
15 GSList *active_window_stack = NULL;
20 GtkTextBuffer *buffer;
23 GtkTextTag *invisible_tag;
24 GtkTextTag *not_editable_tag;
25 GtkTextTag *found_text_tag;
26 GtkTextTag *custom_tabs_tag;
28 guint color_cycle_timeout;
36 GtkAccelGroup *accel_group;
37 GtkItemFactory *item_factory;
41 static void push_active_window (GtkWindow *window);
42 static void pop_active_window (void);
43 static GtkWindow *get_active_window (void);
45 static Buffer * create_buffer (void);
46 static gboolean check_buffer_saved (Buffer *buffer);
47 static gboolean save_buffer (Buffer *buffer);
48 static gboolean save_as_buffer (Buffer *buffer);
49 static char * buffer_pretty_name (Buffer *buffer);
50 static void buffer_filename_set (Buffer *buffer);
51 static void buffer_search_forward (Buffer *buffer,
54 static void buffer_search_backward (Buffer *buffer,
57 static void buffer_set_colors (Buffer *buffer,
59 static void buffer_cycle_colors (Buffer *buffer);
61 static View *view_from_widget (GtkWidget *widget);
63 static View *create_view (Buffer *buffer);
64 static void check_close_view (View *view);
65 static void close_view (View *view);
66 static void view_set_title (View *view);
67 static void view_init_menus (View *view);
68 static void view_add_example_widgets (View *view);
70 GSList *buffers = NULL;
74 push_active_window (GtkWindow *window)
76 g_object_ref (G_OBJECT (window));
77 active_window_stack = g_slist_prepend (active_window_stack, window);
81 pop_active_window (void)
83 gtk_object_unref (active_window_stack->data);
84 active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack);
88 get_active_window (void)
90 if (active_window_stack)
91 return active_window_stack->data;
97 * Filesel utility function
100 typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data);
103 filesel_ok_cb (GtkWidget *button, GtkWidget *filesel)
105 FileselOKFunc ok_func = g_object_get_data (G_OBJECT (filesel), "ok-func");
106 gpointer data = g_object_get_data (G_OBJECT (filesel), "ok-data");
107 gint *result = g_object_get_data (G_OBJECT (filesel), "ok-result");
109 gtk_widget_hide (filesel);
111 if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data))
113 gtk_widget_destroy (filesel);
117 gtk_widget_show (filesel);
121 filesel_run (GtkWindow *parent,
123 const char *start_file,
127 GtkWidget *filesel = gtk_file_selection_new (title);
128 gboolean result = FALSE;
131 parent = get_active_window ();
134 gtk_window_set_transient_for (GTK_WINDOW (filesel), parent);
137 gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file);
140 g_object_set_data (G_OBJECT (filesel), "ok-func", func);
141 g_object_set_data (G_OBJECT (filesel), "ok-data", data);
142 g_object_set_data (G_OBJECT (filesel), "ok-result", &result);
144 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
146 GTK_SIGNAL_FUNC (filesel_ok_cb), filesel);
147 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
149 GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (filesel));
151 gtk_signal_connect (GTK_OBJECT (filesel), "destroy",
152 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
153 gtk_window_set_modal (GTK_WINDOW (filesel), TRUE);
155 gtk_widget_show (filesel);
162 * MsgBox utility functions
166 msgbox_yes_cb (GtkWidget *widget, gboolean *result)
169 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
173 msgbox_no_cb (GtkWidget *widget, gboolean *result)
176 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
180 msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
182 if (event->keyval == GDK_Escape)
184 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
185 gtk_object_destroy (GTK_OBJECT (widget));
193 msgbox_run (GtkWindow *parent,
195 const char *yes_button,
196 const char *no_button,
197 const char *cancel_button,
200 gboolean result = -1;
205 GtkWidget *button_box;
206 GtkWidget *separator;
208 g_return_val_if_fail (message != NULL, FALSE);
209 g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE);
212 parent = get_active_window ();
216 dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
217 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
219 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
220 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
222 /* Quit our recursive main loop when the dialog is destroyed.
224 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
225 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
227 /* Catch Escape key presses and have them destroy the dialog
229 gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event",
230 GTK_SIGNAL_FUNC (msgbox_key_press_cb), NULL);
232 /* Fill in the contents of the widget
234 vbox = gtk_vbox_new (FALSE, 0);
235 gtk_container_add (GTK_CONTAINER (dialog), vbox);
237 label = gtk_label_new (message);
238 gtk_misc_set_padding (GTK_MISC (label), 12, 12);
239 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
240 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
242 separator = gtk_hseparator_new ();
243 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
245 button_box = gtk_hbutton_box_new ();
246 gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
247 gtk_container_set_border_width (GTK_CONTAINER (button_box), 8);
250 /* When Yes is clicked, call the msgbox_yes_cb
251 * This sets the result variable and destroys the dialog
255 button = gtk_button_new_with_label (yes_button);
256 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
257 gtk_container_add (GTK_CONTAINER (button_box), button);
259 if (default_index == 0)
260 gtk_widget_grab_default (button);
262 gtk_signal_connect (GTK_OBJECT (button), "clicked",
263 GTK_SIGNAL_FUNC (msgbox_yes_cb), &result);
266 /* When No is clicked, call the msgbox_no_cb
267 * This sets the result variable and destroys the dialog
271 button = gtk_button_new_with_label (no_button);
272 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
273 gtk_container_add (GTK_CONTAINER (button_box), button);
275 if (default_index == 0)
276 gtk_widget_grab_default (button);
278 gtk_signal_connect (GTK_OBJECT (button), "clicked",
279 GTK_SIGNAL_FUNC (msgbox_no_cb), &result);
282 /* When Cancel is clicked, destroy the dialog
286 button = gtk_button_new_with_label (cancel_button);
287 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
288 gtk_container_add (GTK_CONTAINER (button_box), button);
290 if (default_index == 1)
291 gtk_widget_grab_default (button);
293 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
294 GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (dialog));
297 gtk_widget_show_all (dialog);
299 /* Run a recursive main loop until a button is clicked
300 * or the user destroys the dialog through the window mananger */
307 * Example buffer filling code
310 blink_timeout (gpointer data)
313 static gboolean flip = FALSE;
315 tag = GTK_TEXT_TAG (data);
317 g_object_set (G_OBJECT (tag),
318 "foreground", flip ? "blue" : "purple",
327 tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
328 const GtkTextIter *iter, gpointer user_data)
332 char_index = gtk_text_iter_get_offset (iter);
336 case GDK_MOTION_NOTIFY:
337 printf ("Motion event at char %d tag `%s'\n",
338 char_index, tag->name);
341 case GDK_BUTTON_PRESS:
342 printf ("Button press at char %d tag `%s'\n",
343 char_index, tag->name);
346 case GDK_2BUTTON_PRESS:
347 printf ("Double click at char %d tag `%s'\n",
348 char_index, tag->name);
351 case GDK_3BUTTON_PRESS:
352 printf ("Triple click at char %d tag `%s'\n",
353 char_index, tag->name);
356 case GDK_BUTTON_RELEASE:
357 printf ("Button release at char %d tag `%s'\n",
358 char_index, tag->name);
362 case GDK_KEY_RELEASE:
363 printf ("Key event at char %d tag `%s'\n",
364 char_index, tag->name);
367 case GDK_ENTER_NOTIFY:
368 case GDK_LEAVE_NOTIFY:
369 case GDK_PROPERTY_NOTIFY:
370 case GDK_SELECTION_CLEAR:
371 case GDK_SELECTION_REQUEST:
372 case GDK_SELECTION_NOTIFY:
373 case GDK_PROXIMITY_IN:
374 case GDK_PROXIMITY_OUT:
377 case GDK_DRAG_MOTION:
378 case GDK_DRAG_STATUS:
380 case GDK_DROP_FINISHED:
389 setup_tag (GtkTextTag *tag)
391 g_signal_connect_data (G_OBJECT (tag),
394 NULL, NULL, FALSE, FALSE);
397 static char *book_closed_xpm[] = {
423 fill_example_buffer (GtkTextBuffer *buffer)
425 GtkTextIter iter, iter2;
432 GtkTextChildAnchor *anchor;
434 /* FIXME this is broken if called twice on a buffer, since
435 * we try to create tags a second time.
438 tag = gtk_text_buffer_create_tag (buffer, "fg_blue");
440 /* gtk_timeout_add (1000, blink_timeout, tag); */
444 color.red = color.green = 0;
449 g_object_set (G_OBJECT (tag),
450 "foreground_gdk", &color,
451 "background_gdk", &color2,
455 tag = gtk_text_buffer_create_tag (buffer, "fg_red");
459 color.blue = color.green = 0;
461 g_object_set (G_OBJECT (tag),
462 "rise", -4 * PANGO_SCALE,
463 "foreground_gdk", &color,
466 tag = gtk_text_buffer_create_tag (buffer, "bg_green");
470 color.blue = color.red = 0;
471 color.green = 0xffff;
472 g_object_set (G_OBJECT (tag),
473 "background_gdk", &color,
477 tag = gtk_text_buffer_create_tag (buffer, "strikethrough");
481 g_object_set (G_OBJECT (tag),
482 "strikethrough", TRUE,
486 tag = gtk_text_buffer_create_tag (buffer, "underline");
490 g_object_set (G_OBJECT (tag),
491 "underline", PANGO_UNDERLINE_SINGLE,
496 g_object_set (G_OBJECT (tag),
497 "underline", PANGO_UNDERLINE_SINGLE,
500 tag = gtk_text_buffer_create_tag (buffer, "centered");
502 g_object_set (G_OBJECT (tag),
503 "justification", GTK_JUSTIFY_CENTER,
506 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote");
508 g_object_set (G_OBJECT (tag),
509 "wrap_mode", GTK_WRAP_WORD,
510 "direction", GTK_TEXT_DIR_RTL,
518 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
520 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
522 g_object_ref (G_OBJECT (anchor));
524 g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
525 (GDestroyNotify) g_object_unref);
528 pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
533 GtkTextMark * temp_mark;
535 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
537 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
539 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",
542 gtk_text_buffer_insert (buffer, &iter, str, -1);
546 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
548 gtk_text_buffer_insert (buffer, &iter,
549 "(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"
550 /* This is UTF8 stuff, Emacs doesn't
551 really know how to display it */
552 "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew שלום Japanese (日本語)\n", -1);
555 gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
558 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
559 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
561 gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
563 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
564 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
566 gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
568 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
569 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
571 gtk_text_buffer_apply_tag_by_name (buffer, "strikethrough", &iter, &iter2);
573 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
574 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
576 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
578 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
579 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
581 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
583 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
584 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
586 gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
589 gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
590 gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
592 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
593 gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
595 gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
596 gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
597 gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1);
598 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
599 gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
604 g_object_unref (G_OBJECT (pixbuf));
606 printf ("%d lines %d chars\n",
607 gtk_text_buffer_get_line_count (buffer),
608 gtk_text_buffer_get_char_count (buffer));
610 /* Move cursor to start */
611 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
612 gtk_text_buffer_place_cursor (buffer, &iter);
614 gtk_text_buffer_set_modified (buffer, FALSE);
618 fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
623 GtkTextIter iter, end;
625 f = fopen (filename, "r");
629 gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
630 filename, g_strerror (errno));
631 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
636 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
640 const char *leftover;
641 int to_read = 2047 - remaining;
643 count = fread (buf + remaining, 1, to_read, f);
644 buf[count + remaining] = '\0';
646 g_utf8_validate (buf, count + remaining, &leftover);
648 g_assert (g_utf8_validate (buf, leftover - buf, NULL));
649 gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
651 remaining = (buf + remaining + count) - leftover;
652 g_memmove (buf, leftover, remaining);
654 if (remaining > 6 || count < to_read)
660 gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
661 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
665 /* We had a newline in the buffer to begin with. (The buffer always contains
666 * a newline, so we delete to the end of the buffer to clean up.
668 gtk_text_buffer_get_last_iter (buffer, &end);
669 gtk_text_buffer_delete (buffer, &iter, &end);
671 gtk_text_buffer_set_modified (buffer, FALSE);
677 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
679 View *view = view_from_widget (window);
681 push_active_window (GTK_WINDOW (window));
682 check_close_view (view);
683 pop_active_window ();
693 get_empty_view (View *view)
695 if (!view->buffer->filename &&
696 !gtk_text_buffer_modified (view->buffer->buffer))
699 return create_view (create_buffer ());
703 view_from_widget (GtkWidget *widget)
707 if (GTK_IS_MENU_ITEM (widget))
709 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
710 return g_object_get_data (G_OBJECT (item_factory), "view");
714 GtkWidget *app = gtk_widget_get_toplevel (widget);
715 return g_object_get_data (G_OBJECT (app), "view");
720 do_new (gpointer callback_data,
721 guint callback_action,
724 create_view (create_buffer ());
728 do_new_view (gpointer callback_data,
729 guint callback_action,
732 View *view = view_from_widget (widget);
734 create_view (view->buffer);
738 open_ok_func (const char *filename, gpointer data)
741 View *new_view = get_empty_view (view);
743 if (!fill_file_buffer (new_view->buffer->buffer, filename))
745 if (new_view != view)
746 close_view (new_view);
751 g_free (new_view->buffer->filename);
752 new_view->buffer->filename = g_strdup (filename);
753 buffer_filename_set (new_view->buffer);
760 do_open (gpointer callback_data,
761 guint callback_action,
764 View *view = view_from_widget (widget);
766 push_active_window (GTK_WINDOW (view->window));
767 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
768 pop_active_window ();
772 do_save_as (gpointer callback_data,
773 guint callback_action,
776 View *view = view_from_widget (widget);
778 push_active_window (GTK_WINDOW (view->window));
779 save_as_buffer (view->buffer);
780 pop_active_window ();
784 do_save (gpointer callback_data,
785 guint callback_action,
788 View *view = view_from_widget (widget);
790 push_active_window (GTK_WINDOW (view->window));
791 if (!view->buffer->filename)
792 do_save_as (callback_data, callback_action, widget);
794 save_buffer (view->buffer);
795 pop_active_window ();
799 do_close (gpointer callback_data,
800 guint callback_action,
803 View *view = view_from_widget (widget);
805 push_active_window (GTK_WINDOW (view->window));
806 check_close_view (view);
807 pop_active_window ();
811 do_exit (gpointer callback_data,
812 guint callback_action,
815 View *view = view_from_widget (widget);
817 GSList *tmp_list = buffers;
819 push_active_window (GTK_WINDOW (view->window));
822 if (!check_buffer_saved (tmp_list->data))
825 tmp_list = tmp_list->next;
829 pop_active_window ();
833 do_example (gpointer callback_data,
834 guint callback_action,
837 View *view = view_from_widget (widget);
840 new_view = get_empty_view (view);
842 fill_example_buffer (new_view->buffer->buffer);
844 view_add_example_widgets (new_view);
848 do_wrap_changed (gpointer callback_data,
849 guint callback_action,
852 View *view = view_from_widget (widget);
854 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
858 do_direction_changed (gpointer callback_data,
859 guint callback_action,
862 View *view = view_from_widget (widget);
864 gtk_widget_set_direction (view->text_view, callback_action);
865 gtk_widget_queue_resize (view->text_view);
870 do_spacing_changed (gpointer callback_data,
871 guint callback_action,
874 View *view = view_from_widget (widget);
878 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
880 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
882 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
887 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
889 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
891 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
897 do_editable_changed (gpointer callback_data,
898 guint callback_action,
901 View *view = view_from_widget (widget);
903 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
907 do_cursor_visible_changed (gpointer callback_data,
908 guint callback_action,
911 View *view = view_from_widget (widget);
913 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
917 do_color_cycle_changed (gpointer callback_data,
918 guint callback_action,
921 View *view = view_from_widget (widget);
923 buffer_set_colors (view->buffer, callback_action);
927 do_apply_editable (gpointer callback_data,
928 guint callback_action,
931 View *view = view_from_widget (widget);
935 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
940 gtk_text_buffer_remove_tag (view->buffer->buffer,
941 view->buffer->not_editable_tag,
946 gtk_text_buffer_apply_tag (view->buffer->buffer,
947 view->buffer->not_editable_tag,
954 do_apply_invisible (gpointer callback_data,
955 guint callback_action,
958 View *view = view_from_widget (widget);
962 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
967 gtk_text_buffer_remove_tag (view->buffer->buffer,
968 view->buffer->invisible_tag,
973 gtk_text_buffer_apply_tag (view->buffer->buffer,
974 view->buffer->invisible_tag,
981 do_apply_tabs (gpointer callback_data,
982 guint callback_action,
985 View *view = view_from_widget (widget);
989 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
994 gtk_text_buffer_remove_tag (view->buffer->buffer,
995 view->buffer->custom_tabs_tag,
1000 gtk_text_buffer_apply_tag (view->buffer->buffer,
1001 view->buffer->custom_tabs_tag,
1008 do_apply_colors (gpointer callback_data,
1009 guint callback_action,
1012 View *view = view_from_widget (widget);
1013 Buffer *buffer = view->buffer;
1017 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1020 if (!callback_action)
1024 tmp = buffer->color_tags;
1027 gtk_text_buffer_remove_tag (view->buffer->buffer,
1030 tmp = g_slist_next (tmp);
1037 tmp = buffer->color_tags;
1041 gboolean done = FALSE;
1044 gtk_text_iter_forward_char (&next);
1045 gtk_text_iter_forward_char (&next);
1047 if (gtk_text_iter_compare (&next, &end) > 0)
1053 gtk_text_buffer_apply_tag (view->buffer->buffer,
1062 tmp = g_slist_next (tmp);
1064 tmp = buffer->color_tags;
1077 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1079 GtkTextBuffer *buffer;
1081 GtkTextIter start, end;
1082 gchar *search_string;
1084 if (response_id != RESPONSE_FORWARD &&
1085 response_id != RESPONSE_BACKWARD)
1087 gtk_widget_destroy (dialog);
1091 buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
1093 gtk_text_buffer_get_bounds (buffer, &start, &end);
1095 /* Remove trailing newline */
1096 gtk_text_iter_backward_char (&end);
1098 search_string = gtk_text_iter_get_text (&start, &end);
1100 printf ("Searching for `%s'\n", search_string);
1102 if (response_id == RESPONSE_FORWARD)
1103 buffer_search_forward (view->buffer, search_string, view);
1104 else if (response_id == RESPONSE_BACKWARD)
1105 buffer_search_backward (view->buffer, search_string, view);
1107 g_free (search_string);
1109 gtk_widget_destroy (dialog);
1113 do_search (gpointer callback_data,
1114 guint callback_action,
1117 View *view = view_from_widget (widget);
1119 GtkWidget *search_text;
1120 GtkTextBuffer *buffer;
1122 dialog = gtk_dialog_new_with_buttons ("Search",
1123 GTK_WINDOW (view->window),
1124 GTK_DIALOG_DESTROY_WITH_PARENT,
1125 "Forward", RESPONSE_FORWARD,
1126 "Backward", RESPONSE_BACKWARD,
1127 GTK_STOCK_BUTTON_CANCEL,
1128 GTK_RESPONSE_NONE, NULL);
1131 buffer = gtk_text_buffer_new (NULL);
1133 search_text = gtk_text_view_new_with_buffer (buffer);
1135 g_object_unref (G_OBJECT (buffer));
1137 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1141 g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
1143 gtk_signal_connect (GTK_OBJECT (dialog),
1145 GTK_SIGNAL_FUNC (dialog_response_callback),
1148 gtk_widget_show (search_text);
1150 gtk_widget_grab_focus (search_text);
1152 gtk_widget_show_all (dialog);
1156 view_init_menus (View *view)
1158 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1159 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1160 GtkWidget *menu_item = NULL;
1164 case GTK_TEXT_DIR_LTR:
1165 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1167 case GTK_TEXT_DIR_RTL:
1168 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1175 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1180 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1183 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1186 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
1193 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1196 static GtkItemFactoryEntry menu_items[] =
1198 { "/_File", NULL, 0, 0, "<Branch>" },
1199 { "/File/_New", "<control>N", do_new, 0, NULL },
1200 { "/File/New _View", NULL, do_new_view, 0, NULL },
1201 { "/File/_Open", "<control>O", do_open, 0, NULL },
1202 { "/File/_Save", "<control>S", do_save, 0, NULL },
1203 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1204 { "/File/sep1", NULL, 0, 0, "<Separator>" },
1205 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1206 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1208 { "/_Edit", NULL, 0, 0, "<Branch>" },
1209 { "/Edit/Find...", NULL, do_search, 0, NULL },
1211 { "/_Settings", NULL, 0, 0, "<Branch>" },
1212 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAP_NONE, "<RadioItem>" },
1213 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAP_WORD, "/Settings/Wrap Off" },
1214 { "/Settings/Wrap _Chars", NULL, do_wrap_changed, GTK_WRAP_CHAR, "/Settings/Wrap Off" },
1215 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1216 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1217 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1218 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1220 { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "<RadioItem>" },
1221 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" },
1222 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1224 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1225 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1227 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1228 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1229 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1230 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1231 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1232 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1233 { "/_Attributes", NULL, 0, 0, "<Branch>" },
1234 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1235 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1236 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1237 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1238 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1239 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1240 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1241 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
1242 { "/_Test", NULL, 0, 0, "<Branch>" },
1243 { "/Test/_Example", NULL, do_example, 0, NULL },
1247 save_buffer (Buffer *buffer)
1249 GtkTextIter start, end;
1251 gboolean result = FALSE;
1252 gboolean have_backup = FALSE;
1253 gchar *bak_filename;
1256 g_return_val_if_fail (buffer->filename != NULL, FALSE);
1258 bak_filename = g_strconcat (buffer->filename, "~", NULL);
1260 if (rename (buffer->filename, bak_filename) != 0)
1262 if (errno != ENOENT)
1264 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1265 buffer->filename, bak_filename, g_strerror (errno));
1266 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1274 file = fopen (buffer->filename, "w");
1277 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1278 buffer->filename, bak_filename, g_strerror (errno));
1279 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1283 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1284 gtk_text_buffer_get_last_iter (buffer->buffer, &end);
1286 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1288 if (fputs (chars, file) == EOF ||
1289 fclose (file) == EOF)
1291 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1292 buffer->filename, g_strerror (errno));
1293 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1301 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
1307 if (!result && have_backup)
1309 if (rename (bak_filename, buffer->filename) != 0)
1311 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1312 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1313 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1318 g_free (bak_filename);
1324 save_as_ok_func (const char *filename, gpointer data)
1326 Buffer *buffer = data;
1327 char *old_filename = buffer->filename;
1329 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1331 struct stat statbuf;
1333 if (stat (filename, &statbuf) == 0)
1335 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1336 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1344 buffer->filename = g_strdup (filename);
1346 if (save_buffer (buffer))
1348 g_free (old_filename);
1349 buffer_filename_set (buffer);
1354 g_free (buffer->filename);
1355 buffer->filename = old_filename;
1361 save_as_buffer (Buffer *buffer)
1363 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1367 check_buffer_saved (Buffer *buffer)
1369 if (gtk_text_buffer_modified (buffer->buffer))
1371 char *pretty_name = buffer_pretty_name (buffer);
1372 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1375 g_free (pretty_name);
1377 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1381 return save_as_buffer (buffer);
1382 else if (result == 1)
1394 create_buffer (void)
1397 PangoTabArray *tabs;
1400 buffer = g_new (Buffer, 1);
1402 buffer->buffer = gtk_text_buffer_new (NULL);
1404 buffer->refcount = 1;
1405 buffer->filename = NULL;
1406 buffer->untitled_serial = -1;
1408 buffer->color_tags = NULL;
1409 buffer->color_cycle_timeout = 0;
1410 buffer->start_hue = 0.0;
1413 while (i < N_COLORS)
1417 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1419 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1424 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1425 g_object_set (G_OBJECT (buffer->invisible_tag),
1429 buffer->not_editable_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1430 g_object_set (G_OBJECT (buffer->not_editable_tag),
1432 "foreground", "purple", NULL);
1434 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1435 g_object_set (G_OBJECT (buffer->found_text_tag),
1436 "foreground", "red", NULL);
1438 tabs = pango_tab_array_new_with_positions (4,
1443 PANGO_TAB_LEFT, 120);
1445 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1446 g_object_set (G_OBJECT (buffer->custom_tabs_tag),
1448 "foreground", "green", NULL);
1450 pango_tab_array_free (tabs);
1452 buffers = g_slist_prepend (buffers, buffer);
1458 buffer_pretty_name (Buffer *buffer)
1460 if (buffer->filename)
1463 char *result = g_path_get_basename (buffer->filename);
1464 p = strchr (result, '/');
1472 if (buffer->untitled_serial == -1)
1473 buffer->untitled_serial = untitled_serial++;
1475 if (buffer->untitled_serial == 1)
1476 return g_strdup ("Untitled");
1478 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1483 buffer_filename_set (Buffer *buffer)
1485 GSList *tmp_list = views;
1489 View *view = tmp_list->data;
1491 if (view->buffer == buffer)
1492 view_set_title (view);
1494 tmp_list = tmp_list->next;
1499 buffer_search (Buffer *buffer,
1505 GtkTextIter start, end;
1509 /* remove tag from whole buffer */
1510 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1511 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1514 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1515 gtk_text_buffer_get_mark (buffer->buffer,
1521 GtkTextIter match_start, match_end;
1525 while (gtk_text_iter_forward_search (&iter, str, TRUE, FALSE,
1526 &match_start, &match_end,
1530 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1531 &match_start, &match_end);
1538 while (gtk_text_iter_backward_search (&iter, str, TRUE, FALSE,
1539 &match_start, &match_end,
1543 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1544 &match_start, &match_end);
1551 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1554 GTK_DIALOG_DESTROY_WITH_PARENT,
1555 "%d strings found and marked in red",
1558 gtk_signal_connect_object (GTK_OBJECT (dialog),
1560 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1561 GTK_OBJECT (dialog));
1563 gtk_widget_show (dialog);
1567 buffer_search_forward (Buffer *buffer, const char *str,
1570 buffer_search (buffer, str, view, TRUE);
1574 buffer_search_backward (Buffer *buffer, const char *str,
1577 buffer_search (buffer, str, view, FALSE);
1581 buffer_ref (Buffer *buffer)
1587 buffer_unref (Buffer *buffer)
1590 if (buffer->refcount == 0)
1592 buffer_set_colors (buffer, FALSE);
1593 buffers = g_slist_remove (buffers, buffer);
1594 g_object_unref (G_OBJECT (buffer->buffer));
1595 g_free (buffer->filename);
1601 hsv_to_rgb (gdouble *h,
1605 gdouble hue, saturation, value;
1623 f = hue - (int) hue;
1624 p = value * (1.0 - saturation);
1625 q = value * (1.0 - saturation * f);
1626 t = value * (1.0 - saturation * (1.0 - f));
1667 g_assert_not_reached ();
1673 hue_to_color (gdouble hue,
1682 g_return_if_fail (hue <= 1.0);
1684 hsv_to_rgb (&h, &s, &v);
1686 color->red = h * 65535;
1687 color->green = s * 65535;
1688 color->blue = v * 65535;
1693 color_cycle_timeout (gpointer data)
1695 Buffer *buffer = data;
1697 buffer_cycle_colors (buffer);
1703 buffer_set_colors (Buffer *buffer,
1709 if (enabled && buffer->color_cycle_timeout == 0)
1710 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
1711 else if (!enabled && buffer->color_cycle_timeout != 0)
1713 gtk_timeout_remove (buffer->color_cycle_timeout);
1714 buffer->color_cycle_timeout = 0;
1717 tmp = buffer->color_tags;
1724 hue_to_color (hue, &color);
1726 g_object_set (G_OBJECT (tmp->data),
1727 "foreground_gdk", &color,
1731 g_object_set (G_OBJECT (tmp->data),
1732 "foreground_set", FALSE,
1735 hue += 1.0 / N_COLORS;
1737 tmp = g_slist_next (tmp);
1742 buffer_cycle_colors (Buffer *buffer)
1745 gdouble hue = buffer->start_hue;
1747 tmp = buffer->color_tags;
1752 hue_to_color (hue, &color);
1754 g_object_set (G_OBJECT (tmp->data),
1755 "foreground_gdk", &color,
1758 hue += 1.0 / N_COLORS;
1762 tmp = g_slist_next (tmp);
1765 buffer->start_hue += 1.0 / N_COLORS;
1766 if (buffer->start_hue > 1.0)
1767 buffer->start_hue = 0.0;
1771 close_view (View *view)
1773 views = g_slist_remove (views, view);
1774 buffer_unref (view->buffer);
1775 gtk_widget_destroy (view->window);
1776 g_object_unref (G_OBJECT (view->item_factory));
1785 check_close_view (View *view)
1787 if (view->buffer->refcount > 1 ||
1788 check_buffer_saved (view->buffer))
1793 view_set_title (View *view)
1795 char *pretty_name = buffer_pretty_name (view->buffer);
1796 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
1798 gtk_window_set_title (GTK_WINDOW (view->window), title);
1800 g_free (pretty_name);
1805 cursor_set_callback (GtkTextBuffer *buffer,
1806 const GtkTextIter *location,
1810 GtkTextView *text_view;
1812 /* Redraw tab windows if the cursor moves
1813 * on the mapped widget (windows may not exist before realization...
1816 text_view = GTK_TEXT_VIEW (user_data);
1818 if (GTK_WIDGET_MAPPED (text_view) &&
1819 mark == gtk_text_buffer_get_insert (buffer))
1821 GdkWindow *tab_window;
1823 tab_window = gtk_text_view_get_window (text_view,
1824 GTK_TEXT_WINDOW_TOP);
1826 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1828 tab_window = gtk_text_view_get_window (text_view,
1829 GTK_TEXT_WINDOW_BOTTOM);
1831 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1836 tab_stops_expose (GtkWidget *widget,
1837 GdkEventExpose *event,
1844 GdkWindow *bottom_win;
1845 GtkTextView *text_view;
1846 GtkTextWindowType type;
1847 GdkDrawable *target;
1848 gint *positions = NULL;
1850 GtkTextAttributes *attrs;
1852 GtkTextBuffer *buffer;
1855 text_view = GTK_TEXT_VIEW (widget);
1857 /* See if this expose is on the tab stop window */
1858 top_win = gtk_text_view_get_window (text_view,
1859 GTK_TEXT_WINDOW_TOP);
1861 bottom_win = gtk_text_view_get_window (text_view,
1862 GTK_TEXT_WINDOW_BOTTOM);
1864 if (event->window == top_win)
1866 type = GTK_TEXT_WINDOW_TOP;
1869 else if (event->window == bottom_win)
1871 type = GTK_TEXT_WINDOW_BOTTOM;
1872 target = bottom_win;
1877 first_x = event->area.x;
1878 last_x = first_x + event->area.width;
1880 gtk_text_view_window_to_buffer_coords (text_view,
1887 gtk_text_view_window_to_buffer_coords (text_view,
1894 buffer = gtk_text_view_get_buffer (text_view);
1896 gtk_text_buffer_get_iter_at_mark (buffer,
1898 gtk_text_buffer_get_mark (buffer,
1901 attrs = gtk_text_attributes_new ();
1903 gtk_text_iter_get_attributes (&insert, attrs);
1907 size = pango_tab_array_get_size (attrs->tabs);
1909 pango_tab_array_get_tabs (attrs->tabs,
1913 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
1921 gtk_text_attributes_unref (attrs);
1929 positions[i] = PANGO_PIXELS (positions[i]);
1931 gtk_text_view_buffer_to_window_coords (text_view,
1938 gdk_draw_line (target,
1939 widget->style->fg_gc [widget->state],
1952 get_lines (GtkTextView *text_view,
1955 GArray *buffer_coords,
1963 g_array_set_size (buffer_coords, 0);
1964 g_array_set_size (numbers, 0);
1966 /* Get iter at first y */
1967 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
1969 /* For each iter, get its location and add it to the arrays.
1970 * Stop when we pass last_y
1975 while (!gtk_text_iter_is_last (&iter))
1980 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
1982 g_array_append_val (buffer_coords, y);
1983 line_num = gtk_text_iter_get_line (&iter);
1984 g_array_append_val (numbers, line_num);
1988 if ((y + height) >= last_y)
1991 gtk_text_iter_forward_line (&iter);
1998 line_numbers_expose (GtkWidget *widget,
1999 GdkEventExpose *event,
2008 GdkWindow *left_win;
2009 GdkWindow *right_win;
2010 PangoLayout *layout;
2011 GtkTextView *text_view;
2012 GtkTextWindowType type;
2013 GdkDrawable *target;
2015 text_view = GTK_TEXT_VIEW (widget);
2017 /* See if this expose is on the line numbers window */
2018 left_win = gtk_text_view_get_window (text_view,
2019 GTK_TEXT_WINDOW_LEFT);
2021 right_win = gtk_text_view_get_window (text_view,
2022 GTK_TEXT_WINDOW_RIGHT);
2024 if (event->window == left_win)
2026 type = GTK_TEXT_WINDOW_LEFT;
2029 else if (event->window == right_win)
2031 type = GTK_TEXT_WINDOW_RIGHT;
2037 first_y = event->area.y;
2038 last_y = first_y + event->area.height;
2040 gtk_text_view_window_to_buffer_coords (text_view,
2047 gtk_text_view_window_to_buffer_coords (text_view,
2054 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2055 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2057 get_lines (text_view,
2064 /* Draw fully internationalized numbers! */
2066 layout = gtk_widget_create_pango_layout (widget, "");
2074 gtk_text_view_buffer_to_window_coords (text_view,
2077 g_array_index (pixels, gint, i),
2081 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2083 pango_layout_set_text (layout, str, -1);
2085 gtk_paint_layout (widget->style,
2087 GTK_WIDGET_STATE (widget),
2099 g_array_free (pixels, TRUE);
2100 g_array_free (numbers, TRUE);
2102 g_object_unref (G_OBJECT (layout));
2108 create_view (Buffer *buffer)
2115 view = g_new0 (View, 1);
2116 views = g_slist_prepend (views, view);
2118 view->buffer = buffer;
2119 buffer_ref (buffer);
2121 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2122 g_object_set_data (G_OBJECT (view->window), "view", view);
2124 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2125 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2127 view->accel_group = gtk_accel_group_new ();
2128 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2129 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2131 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2133 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2135 vbox = gtk_vbox_new (FALSE, 0);
2136 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2138 gtk_box_pack_start (GTK_BOX (vbox),
2139 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2142 sw = gtk_scrolled_window_new (NULL, NULL);
2143 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2144 GTK_POLICY_AUTOMATIC,
2145 GTK_POLICY_AUTOMATIC);
2147 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2148 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2151 /* Draw tab stops in the top and bottom windows. */
2153 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2154 GTK_TEXT_WINDOW_TOP,
2157 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2158 GTK_TEXT_WINDOW_BOTTOM,
2161 gtk_signal_connect (GTK_OBJECT (view->text_view),
2163 GTK_SIGNAL_FUNC (tab_stops_expose),
2166 g_signal_connect_data (G_OBJECT (view->buffer->buffer),
2168 GTK_SIGNAL_FUNC (cursor_set_callback),
2169 view->text_view, NULL, FALSE, FALSE);
2171 /* Draw line numbers in the side windows; we should really be
2172 * more scientific about what width we set them to.
2174 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2175 GTK_TEXT_WINDOW_RIGHT,
2178 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2179 GTK_TEXT_WINDOW_LEFT,
2182 gtk_signal_connect (GTK_OBJECT (view->text_view),
2184 GTK_SIGNAL_FUNC (line_numbers_expose),
2187 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2188 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2190 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2192 gtk_widget_grab_focus (view->text_view);
2194 view_set_title (view);
2195 view_init_menus (view);
2197 view_add_example_widgets (view);
2199 gtk_widget_show_all (view->window);
2204 view_add_example_widgets (View *view)
2206 GtkTextChildAnchor *anchor;
2211 buffer = view->buffer;
2213 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2216 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2220 widget = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
2221 GTK_ICON_SIZE_DIALOG);
2223 widget = gtk_button_new_with_label ("Foo");
2225 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2229 gtk_widget_show (widget);
2234 file_exists (const char *filename)
2236 struct stat statbuf;
2238 return stat (filename, &statbuf) == 0;
2243 if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
2245 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2246 putenv ("GTK_IM_MODULE_FILE=./gtk.immodules");
2251 main (int argc, char** argv)
2259 gtk_init (&argc, &argv);
2261 buffer = create_buffer ();
2262 view = create_view (buffer);
2263 buffer_unref (buffer);
2265 push_active_window (GTK_WINDOW (view->window));
2266 for (i=1; i < argc; i++)
2270 /* Quick and dirty canonicalization - better should be in GLib
2273 if (!g_path_is_absolute (argv[i]))
2275 char *cwd = g_get_current_dir ();
2276 filename = g_strconcat (cwd, "/", argv[i], NULL);
2282 open_ok_func (filename, view);
2284 if (filename != argv[i])
2287 pop_active_window ();