8 #include <gdk/gdkkeysyms.h>
10 typedef struct _Buffer Buffer;
11 typedef struct _View View;
13 static gint untitled_serial = 1;
15 GSList *active_window_stack = NULL;
20 GtkTextBuffer *buffer;
23 GtkTextTag *invisible_tag;
24 GtkTextTag *not_editable_tag;
25 GtkTextTag *found_text_tag;
26 GtkTextTag *custom_tabs_tag;
28 guint color_cycle_timeout;
36 GtkAccelGroup *accel_group;
37 GtkItemFactory *item_factory;
41 static void push_active_window (GtkWindow *window);
42 static void pop_active_window (void);
43 static GtkWindow *get_active_window (void);
45 static Buffer * create_buffer (void);
46 static gboolean check_buffer_saved (Buffer *buffer);
47 static gboolean save_buffer (Buffer *buffer);
48 static gboolean save_as_buffer (Buffer *buffer);
49 static char * buffer_pretty_name (Buffer *buffer);
50 static void buffer_filename_set (Buffer *buffer);
51 static void buffer_search_forward (Buffer *buffer,
54 static void buffer_search_backward (Buffer *buffer,
57 static void buffer_set_colors (Buffer *buffer,
59 static void buffer_cycle_colors (Buffer *buffer);
61 static View *view_from_widget (GtkWidget *widget);
63 static View *create_view (Buffer *buffer);
64 static void check_close_view (View *view);
65 static void close_view (View *view);
66 static void view_set_title (View *view);
67 static void view_init_menus (View *view);
68 static void view_add_example_widgets (View *view);
70 GSList *buffers = NULL;
74 push_active_window (GtkWindow *window)
76 g_object_ref (G_OBJECT (window));
77 active_window_stack = g_slist_prepend (active_window_stack, window);
81 pop_active_window (void)
83 gtk_object_unref (active_window_stack->data);
84 active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack);
88 get_active_window (void)
90 if (active_window_stack)
91 return active_window_stack->data;
97 * Filesel utility function
100 typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data);
103 filesel_ok_cb (GtkWidget *button, GtkWidget *filesel)
105 FileselOKFunc ok_func = g_object_get_data (G_OBJECT (filesel), "ok-func");
106 gpointer data = g_object_get_data (G_OBJECT (filesel), "ok-data");
107 gint *result = g_object_get_data (G_OBJECT (filesel), "ok-result");
109 gtk_widget_hide (filesel);
111 if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data))
113 gtk_widget_destroy (filesel);
117 gtk_widget_show (filesel);
121 filesel_run (GtkWindow *parent,
123 const char *start_file,
127 GtkWidget *filesel = gtk_file_selection_new (title);
128 gboolean result = FALSE;
131 parent = get_active_window ();
134 gtk_window_set_transient_for (GTK_WINDOW (filesel), parent);
137 gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file);
140 g_object_set_data (G_OBJECT (filesel), "ok-func", func);
141 g_object_set_data (G_OBJECT (filesel), "ok-data", data);
142 g_object_set_data (G_OBJECT (filesel), "ok-result", &result);
144 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
146 GTK_SIGNAL_FUNC (filesel_ok_cb), filesel);
147 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
149 GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (filesel));
151 gtk_signal_connect (GTK_OBJECT (filesel), "destroy",
152 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
153 gtk_window_set_modal (GTK_WINDOW (filesel), TRUE);
155 gtk_widget_show (filesel);
162 * MsgBox utility functions
166 msgbox_yes_cb (GtkWidget *widget, gboolean *result)
169 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
173 msgbox_no_cb (GtkWidget *widget, gboolean *result)
176 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
180 msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
182 if (event->keyval == GDK_Escape)
184 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
185 gtk_object_destroy (GTK_OBJECT (widget));
193 msgbox_run (GtkWindow *parent,
195 const char *yes_button,
196 const char *no_button,
197 const char *cancel_button,
200 gboolean result = -1;
205 GtkWidget *button_box;
206 GtkWidget *separator;
208 g_return_val_if_fail (message != NULL, FALSE);
209 g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE);
212 parent = get_active_window ();
216 dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
217 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
219 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
220 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
222 /* Quit our recursive main loop when the dialog is destroyed.
224 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
225 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
227 /* Catch Escape key presses and have them destroy the dialog
229 gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event",
230 GTK_SIGNAL_FUNC (msgbox_key_press_cb), NULL);
232 /* Fill in the contents of the widget
234 vbox = gtk_vbox_new (FALSE, 0);
235 gtk_container_add (GTK_CONTAINER (dialog), vbox);
237 label = gtk_label_new (message);
238 gtk_misc_set_padding (GTK_MISC (label), 12, 12);
239 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
240 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
242 separator = gtk_hseparator_new ();
243 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
245 button_box = gtk_hbutton_box_new ();
246 gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
247 gtk_container_set_border_width (GTK_CONTAINER (button_box), 8);
250 /* When Yes is clicked, call the msgbox_yes_cb
251 * This sets the result variable and destroys the dialog
255 button = gtk_button_new_with_label (yes_button);
256 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
257 gtk_container_add (GTK_CONTAINER (button_box), button);
259 if (default_index == 0)
260 gtk_widget_grab_default (button);
262 gtk_signal_connect (GTK_OBJECT (button), "clicked",
263 GTK_SIGNAL_FUNC (msgbox_yes_cb), &result);
266 /* When No is clicked, call the msgbox_no_cb
267 * This sets the result variable and destroys the dialog
271 button = gtk_button_new_with_label (no_button);
272 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
273 gtk_container_add (GTK_CONTAINER (button_box), button);
275 if (default_index == 0)
276 gtk_widget_grab_default (button);
278 gtk_signal_connect (GTK_OBJECT (button), "clicked",
279 GTK_SIGNAL_FUNC (msgbox_no_cb), &result);
282 /* When Cancel is clicked, destroy the dialog
286 button = gtk_button_new_with_label (cancel_button);
287 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
288 gtk_container_add (GTK_CONTAINER (button_box), button);
290 if (default_index == 1)
291 gtk_widget_grab_default (button);
293 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
294 GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (dialog));
297 gtk_widget_show_all (dialog);
299 /* Run a recursive main loop until a button is clicked
300 * or the user destroys the dialog through the window mananger */
307 * Example buffer filling code
310 blink_timeout (gpointer data)
313 static gboolean flip = FALSE;
315 tag = GTK_TEXT_TAG (data);
317 g_object_set (G_OBJECT (tag),
318 "foreground", flip ? "blue" : "purple",
327 tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
328 const GtkTextIter *iter, gpointer user_data)
332 char_index = gtk_text_iter_get_offset (iter);
336 case GDK_MOTION_NOTIFY:
337 printf ("Motion event at char %d tag `%s'\n",
338 char_index, tag->name);
341 case GDK_BUTTON_PRESS:
342 printf ("Button press at char %d tag `%s'\n",
343 char_index, tag->name);
346 case GDK_2BUTTON_PRESS:
347 printf ("Double click at char %d tag `%s'\n",
348 char_index, tag->name);
351 case GDK_3BUTTON_PRESS:
352 printf ("Triple click at char %d tag `%s'\n",
353 char_index, tag->name);
356 case GDK_BUTTON_RELEASE:
357 printf ("Button release at char %d tag `%s'\n",
358 char_index, tag->name);
362 case GDK_KEY_RELEASE:
363 printf ("Key event at char %d tag `%s'\n",
364 char_index, tag->name);
367 case GDK_ENTER_NOTIFY:
368 case GDK_LEAVE_NOTIFY:
369 case GDK_PROPERTY_NOTIFY:
370 case GDK_SELECTION_CLEAR:
371 case GDK_SELECTION_REQUEST:
372 case GDK_SELECTION_NOTIFY:
373 case GDK_PROXIMITY_IN:
374 case GDK_PROXIMITY_OUT:
377 case GDK_DRAG_MOTION:
378 case GDK_DRAG_STATUS:
380 case GDK_DROP_FINISHED:
389 setup_tag (GtkTextTag *tag)
391 g_signal_connect_data (G_OBJECT (tag),
393 G_CALLBACK (tag_event_handler),
394 NULL, NULL, FALSE, FALSE);
397 static const char *book_closed_xpm[] = {
423 fill_example_buffer (GtkTextBuffer *buffer)
425 GtkTextIter iter, iter2;
427 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", NULL);
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", NULL);
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", NULL);
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", NULL);
481 g_object_set (G_OBJECT (tag),
482 "strikethrough", TRUE,
486 tag = gtk_text_buffer_create_tag (buffer, "underline", NULL);
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", NULL);
502 g_object_set (G_OBJECT (tag),
503 "justification", GTK_JUSTIFY_CENTER,
506 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote", NULL);
508 g_object_set (G_OBJECT (tag),
509 "wrap_mode", GTK_WRAP_WORD,
510 "direction", GTK_TEXT_DIR_RTL,
517 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
519 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
521 g_object_ref (G_OBJECT (anchor));
523 g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
524 (GDestroyNotify) g_object_unref);
526 pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
531 GtkTextMark * temp_mark;
533 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
535 gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
537 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",
540 gtk_text_buffer_insert (buffer, &iter, str, -1);
544 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
546 gtk_text_buffer_insert (buffer, &iter,
547 "(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"
548 /* This is UTF8 stuff, Emacs doesn't
549 really know how to display it */
550 "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew(שלום) Hebrew punctuation(\xd6\xbfש\xd6\xbb\xd6\xbc\xd6\xbb\xd6\xbfל\xd6\xbcו\xd6\xbc\xd6\xbb\xd6\xbb\xd6\xbfם\xd6\xbc\xd6\xbb\xd6\xbf) Japanese (日本語) Thai (สวัสดีครับ) Thai wrong spelling (คำต่อไปนื่สะกดผิด พัั้ัั่งโกะ)\n", -1);
553 gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
556 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
557 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
559 gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
561 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
562 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
564 gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
566 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
567 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
569 gtk_text_buffer_apply_tag_by_name (buffer, "strikethrough", &iter, &iter2);
571 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
572 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
574 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
576 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
577 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
579 gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
581 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
582 gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
584 gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
587 gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
588 gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
590 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
591 gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
593 gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
594 gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
595 gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1);
596 gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
597 gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
602 g_object_unref (G_OBJECT (pixbuf));
604 printf ("%d lines %d chars\n",
605 gtk_text_buffer_get_line_count (buffer),
606 gtk_text_buffer_get_char_count (buffer));
608 /* Move cursor to start */
609 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
610 gtk_text_buffer_place_cursor (buffer, &iter);
612 gtk_text_buffer_set_modified (buffer, FALSE);
616 fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
621 GtkTextIter iter, end;
623 f = fopen (filename, "r");
627 gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
628 filename, g_strerror (errno));
629 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
634 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
638 const char *leftover;
639 int to_read = 2047 - remaining;
641 count = fread (buf + remaining, 1, to_read, f);
642 buf[count + remaining] = '\0';
644 g_utf8_validate (buf, count + remaining, &leftover);
646 g_assert (g_utf8_validate (buf, leftover - buf, NULL));
647 gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
649 remaining = (buf + remaining + count) - leftover;
650 g_memmove (buf, leftover, remaining);
652 if (remaining > 6 || count < to_read)
658 gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
659 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
663 /* We had a newline in the buffer to begin with. (The buffer always contains
664 * a newline, so we delete to the end of the buffer to clean up.
666 gtk_text_buffer_get_end_iter (buffer, &end);
667 gtk_text_buffer_delete (buffer, &iter, &end);
669 gtk_text_buffer_set_modified (buffer, FALSE);
675 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
677 View *view = view_from_widget (window);
679 push_active_window (GTK_WINDOW (window));
680 check_close_view (view);
681 pop_active_window ();
691 get_empty_view (View *view)
693 if (!view->buffer->filename &&
694 !gtk_text_buffer_get_modified (view->buffer->buffer))
697 return create_view (create_buffer ());
701 view_from_widget (GtkWidget *widget)
703 if (GTK_IS_MENU_ITEM (widget))
705 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
706 return g_object_get_data (G_OBJECT (item_factory), "view");
710 GtkWidget *app = gtk_widget_get_toplevel (widget);
711 return g_object_get_data (G_OBJECT (app), "view");
716 do_new (gpointer callback_data,
717 guint callback_action,
720 create_view (create_buffer ());
724 do_new_view (gpointer callback_data,
725 guint callback_action,
728 View *view = view_from_widget (widget);
730 create_view (view->buffer);
734 open_ok_func (const char *filename, gpointer data)
737 View *new_view = get_empty_view (view);
739 if (!fill_file_buffer (new_view->buffer->buffer, filename))
741 if (new_view != view)
742 close_view (new_view);
747 g_free (new_view->buffer->filename);
748 new_view->buffer->filename = g_strdup (filename);
749 buffer_filename_set (new_view->buffer);
756 do_open (gpointer callback_data,
757 guint callback_action,
760 View *view = view_from_widget (widget);
762 push_active_window (GTK_WINDOW (view->window));
763 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
764 pop_active_window ();
768 do_save_as (gpointer callback_data,
769 guint callback_action,
772 View *view = view_from_widget (widget);
774 push_active_window (GTK_WINDOW (view->window));
775 save_as_buffer (view->buffer);
776 pop_active_window ();
780 do_save (gpointer callback_data,
781 guint callback_action,
784 View *view = view_from_widget (widget);
786 push_active_window (GTK_WINDOW (view->window));
787 if (!view->buffer->filename)
788 do_save_as (callback_data, callback_action, widget);
790 save_buffer (view->buffer);
791 pop_active_window ();
795 do_close (gpointer callback_data,
796 guint callback_action,
799 View *view = view_from_widget (widget);
801 push_active_window (GTK_WINDOW (view->window));
802 check_close_view (view);
803 pop_active_window ();
807 do_exit (gpointer callback_data,
808 guint callback_action,
811 View *view = view_from_widget (widget);
813 GSList *tmp_list = buffers;
815 push_active_window (GTK_WINDOW (view->window));
818 if (!check_buffer_saved (tmp_list->data))
821 tmp_list = tmp_list->next;
825 pop_active_window ();
829 do_example (gpointer callback_data,
830 guint callback_action,
833 View *view = view_from_widget (widget);
836 new_view = get_empty_view (view);
838 fill_example_buffer (new_view->buffer->buffer);
840 view_add_example_widgets (new_view);
844 do_wrap_changed (gpointer callback_data,
845 guint callback_action,
848 View *view = view_from_widget (widget);
850 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
854 do_direction_changed (gpointer callback_data,
855 guint callback_action,
858 View *view = view_from_widget (widget);
860 gtk_widget_set_direction (view->text_view, callback_action);
861 gtk_widget_queue_resize (view->text_view);
866 do_spacing_changed (gpointer callback_data,
867 guint callback_action,
870 View *view = view_from_widget (widget);
874 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
876 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
878 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
883 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
885 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
887 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
893 do_editable_changed (gpointer callback_data,
894 guint callback_action,
897 View *view = view_from_widget (widget);
899 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
903 do_cursor_visible_changed (gpointer callback_data,
904 guint callback_action,
907 View *view = view_from_widget (widget);
909 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
913 do_color_cycle_changed (gpointer callback_data,
914 guint callback_action,
917 View *view = view_from_widget (widget);
919 buffer_set_colors (view->buffer, callback_action);
923 do_apply_editable (gpointer callback_data,
924 guint callback_action,
927 View *view = view_from_widget (widget);
931 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
936 gtk_text_buffer_remove_tag (view->buffer->buffer,
937 view->buffer->not_editable_tag,
942 gtk_text_buffer_apply_tag (view->buffer->buffer,
943 view->buffer->not_editable_tag,
950 do_apply_invisible (gpointer callback_data,
951 guint callback_action,
954 View *view = view_from_widget (widget);
958 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
963 gtk_text_buffer_remove_tag (view->buffer->buffer,
964 view->buffer->invisible_tag,
969 gtk_text_buffer_apply_tag (view->buffer->buffer,
970 view->buffer->invisible_tag,
977 do_apply_tabs (gpointer callback_data,
978 guint callback_action,
981 View *view = view_from_widget (widget);
985 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
990 gtk_text_buffer_remove_tag (view->buffer->buffer,
991 view->buffer->custom_tabs_tag,
996 gtk_text_buffer_apply_tag (view->buffer->buffer,
997 view->buffer->custom_tabs_tag,
1004 do_apply_colors (gpointer callback_data,
1005 guint callback_action,
1008 View *view = view_from_widget (widget);
1009 Buffer *buffer = view->buffer;
1013 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1016 if (!callback_action)
1020 tmp = buffer->color_tags;
1023 gtk_text_buffer_remove_tag (view->buffer->buffer,
1026 tmp = g_slist_next (tmp);
1033 tmp = buffer->color_tags;
1037 gboolean done = FALSE;
1040 gtk_text_iter_forward_char (&next);
1041 gtk_text_iter_forward_char (&next);
1043 if (gtk_text_iter_compare (&next, &end) > 0)
1049 gtk_text_buffer_apply_tag (view->buffer->buffer,
1058 tmp = g_slist_next (tmp);
1060 tmp = buffer->color_tags;
1067 do_remove_tags (gpointer callback_data,
1068 guint callback_action,
1071 View *view = view_from_widget (widget);
1075 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1078 gtk_text_buffer_remove_all_tags (view->buffer->buffer,
1090 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1092 GtkTextBuffer *buffer;
1094 GtkTextIter start, end;
1095 gchar *search_string;
1097 if (response_id != RESPONSE_FORWARD &&
1098 response_id != RESPONSE_BACKWARD)
1100 gtk_widget_destroy (dialog);
1104 buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
1106 gtk_text_buffer_get_bounds (buffer, &start, &end);
1108 /* Remove trailing newline */
1109 gtk_text_iter_backward_char (&end);
1111 search_string = gtk_text_iter_get_text (&start, &end);
1113 printf ("Searching for `%s'\n", search_string);
1115 if (response_id == RESPONSE_FORWARD)
1116 buffer_search_forward (view->buffer, search_string, view);
1117 else if (response_id == RESPONSE_BACKWARD)
1118 buffer_search_backward (view->buffer, search_string, view);
1120 g_free (search_string);
1122 gtk_widget_destroy (dialog);
1126 do_search (gpointer callback_data,
1127 guint callback_action,
1130 View *view = view_from_widget (widget);
1132 GtkWidget *search_text;
1133 GtkTextBuffer *buffer;
1135 dialog = gtk_dialog_new_with_buttons ("Search",
1136 GTK_WINDOW (view->window),
1137 GTK_DIALOG_DESTROY_WITH_PARENT,
1138 "Forward", RESPONSE_FORWARD,
1139 "Backward", RESPONSE_BACKWARD,
1140 GTK_STOCK_BUTTON_CANCEL,
1141 GTK_RESPONSE_NONE, NULL);
1144 buffer = gtk_text_buffer_new (NULL);
1146 search_text = gtk_text_view_new_with_buffer (buffer);
1148 g_object_unref (G_OBJECT (buffer));
1150 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1154 g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
1156 gtk_signal_connect (GTK_OBJECT (dialog),
1158 GTK_SIGNAL_FUNC (dialog_response_callback),
1161 gtk_widget_show (search_text);
1163 gtk_widget_grab_focus (search_text);
1165 gtk_widget_show_all (dialog);
1169 view_init_menus (View *view)
1171 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1172 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1173 GtkWidget *menu_item = NULL;
1177 case GTK_TEXT_DIR_LTR:
1178 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1180 case GTK_TEXT_DIR_RTL:
1181 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1188 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1193 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1196 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1199 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
1206 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1209 static GtkItemFactoryEntry menu_items[] =
1211 { "/_File", NULL, 0, 0, "<Branch>" },
1212 { "/File/_New", "<control>N", do_new, 0, NULL },
1213 { "/File/New _View", NULL, do_new_view, 0, NULL },
1214 { "/File/_Open", "<control>O", do_open, 0, NULL },
1215 { "/File/_Save", "<control>S", do_save, 0, NULL },
1216 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1217 { "/File/sep1", NULL, 0, 0, "<Separator>" },
1218 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1219 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1221 { "/_Edit", NULL, 0, 0, "<Branch>" },
1222 { "/Edit/Find...", NULL, do_search, 0, NULL },
1224 { "/_Settings", NULL, 0, 0, "<Branch>" },
1225 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAP_NONE, "<RadioItem>" },
1226 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAP_WORD, "/Settings/Wrap Off" },
1227 { "/Settings/Wrap _Chars", NULL, do_wrap_changed, GTK_WRAP_CHAR, "/Settings/Wrap Off" },
1228 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1229 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1230 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1231 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1233 { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "<RadioItem>" },
1234 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" },
1235 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1237 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1238 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1240 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1241 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1242 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1243 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1244 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1245 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1246 { "/_Attributes", NULL, 0, 0, "<Branch>" },
1247 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1248 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1249 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1250 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1251 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1252 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1253 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1254 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
1255 { "/Attributes/Remove all tags", NULL, do_remove_tags, 0, NULL },
1256 { "/_Test", NULL, 0, 0, "<Branch>" },
1257 { "/Test/_Example", NULL, do_example, 0, NULL },
1261 save_buffer (Buffer *buffer)
1263 GtkTextIter start, end;
1265 gboolean result = FALSE;
1266 gboolean have_backup = FALSE;
1267 gchar *bak_filename;
1270 g_return_val_if_fail (buffer->filename != NULL, FALSE);
1272 bak_filename = g_strconcat (buffer->filename, "~", NULL);
1274 if (rename (buffer->filename, bak_filename) != 0)
1276 if (errno != ENOENT)
1278 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1279 buffer->filename, bak_filename, g_strerror (errno));
1280 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1288 file = fopen (buffer->filename, "w");
1291 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1292 buffer->filename, bak_filename, g_strerror (errno));
1293 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1297 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1298 gtk_text_buffer_get_end_iter (buffer->buffer, &end);
1300 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1302 if (fputs (chars, file) == EOF ||
1303 fclose (file) == EOF)
1305 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1306 buffer->filename, g_strerror (errno));
1307 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1315 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
1321 if (!result && have_backup)
1323 if (rename (bak_filename, buffer->filename) != 0)
1325 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1326 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1327 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1332 g_free (bak_filename);
1338 save_as_ok_func (const char *filename, gpointer data)
1340 Buffer *buffer = data;
1341 char *old_filename = buffer->filename;
1343 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1345 struct stat statbuf;
1347 if (stat (filename, &statbuf) == 0)
1349 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1350 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1358 buffer->filename = g_strdup (filename);
1360 if (save_buffer (buffer))
1362 g_free (old_filename);
1363 buffer_filename_set (buffer);
1368 g_free (buffer->filename);
1369 buffer->filename = old_filename;
1375 save_as_buffer (Buffer *buffer)
1377 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1381 check_buffer_saved (Buffer *buffer)
1383 if (gtk_text_buffer_get_modified (buffer->buffer))
1385 char *pretty_name = buffer_pretty_name (buffer);
1386 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1389 g_free (pretty_name);
1391 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1395 return save_as_buffer (buffer);
1396 else if (result == 1)
1408 create_buffer (void)
1411 PangoTabArray *tabs;
1414 buffer = g_new (Buffer, 1);
1416 buffer->buffer = gtk_text_buffer_new (NULL);
1418 buffer->refcount = 1;
1419 buffer->filename = NULL;
1420 buffer->untitled_serial = -1;
1422 buffer->color_tags = NULL;
1423 buffer->color_cycle_timeout = 0;
1424 buffer->start_hue = 0.0;
1427 while (i < N_COLORS)
1431 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL, NULL);
1433 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1438 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1439 "invisible", TRUE, NULL);
1441 buffer->not_editable_tag =
1442 gtk_text_buffer_create_tag (buffer->buffer, NULL,
1444 "foreground", "purple", NULL);
1446 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1447 "foreground", "red", NULL);
1449 tabs = pango_tab_array_new_with_positions (4,
1454 PANGO_TAB_LEFT, 120);
1456 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1458 "foreground", "green", NULL);
1460 pango_tab_array_free (tabs);
1462 buffers = g_slist_prepend (buffers, buffer);
1468 buffer_pretty_name (Buffer *buffer)
1470 if (buffer->filename)
1473 char *result = g_path_get_basename (buffer->filename);
1474 p = strchr (result, '/');
1482 if (buffer->untitled_serial == -1)
1483 buffer->untitled_serial = untitled_serial++;
1485 if (buffer->untitled_serial == 1)
1486 return g_strdup ("Untitled");
1488 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1493 buffer_filename_set (Buffer *buffer)
1495 GSList *tmp_list = views;
1499 View *view = tmp_list->data;
1501 if (view->buffer == buffer)
1502 view_set_title (view);
1504 tmp_list = tmp_list->next;
1509 buffer_search (Buffer *buffer,
1515 GtkTextIter start, end;
1519 /* remove tag from whole buffer */
1520 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1521 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1524 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1525 gtk_text_buffer_get_mark (buffer->buffer,
1531 GtkTextIter match_start, match_end;
1535 while (gtk_text_iter_forward_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 while (gtk_text_iter_backward_search (&iter, str, TRUE, FALSE,
1549 &match_start, &match_end,
1553 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1554 &match_start, &match_end);
1561 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1564 GTK_DIALOG_DESTROY_WITH_PARENT,
1565 "%d strings found and marked in red",
1568 gtk_signal_connect_object (GTK_OBJECT (dialog),
1570 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1571 GTK_OBJECT (dialog));
1573 gtk_widget_show (dialog);
1577 buffer_search_forward (Buffer *buffer, const char *str,
1580 buffer_search (buffer, str, view, TRUE);
1584 buffer_search_backward (Buffer *buffer, const char *str,
1587 buffer_search (buffer, str, view, FALSE);
1591 buffer_ref (Buffer *buffer)
1597 buffer_unref (Buffer *buffer)
1600 if (buffer->refcount == 0)
1602 buffer_set_colors (buffer, FALSE);
1603 buffers = g_slist_remove (buffers, buffer);
1604 g_object_unref (G_OBJECT (buffer->buffer));
1605 g_free (buffer->filename);
1611 hsv_to_rgb (gdouble *h,
1615 gdouble hue, saturation, value;
1633 f = hue - (int) hue;
1634 p = value * (1.0 - saturation);
1635 q = value * (1.0 - saturation * f);
1636 t = value * (1.0 - saturation * (1.0 - f));
1677 g_assert_not_reached ();
1683 hue_to_color (gdouble hue,
1692 g_return_if_fail (hue <= 1.0);
1694 hsv_to_rgb (&h, &s, &v);
1696 color->red = h * 65535;
1697 color->green = s * 65535;
1698 color->blue = v * 65535;
1703 color_cycle_timeout (gpointer data)
1705 Buffer *buffer = data;
1707 buffer_cycle_colors (buffer);
1713 buffer_set_colors (Buffer *buffer,
1719 if (enabled && buffer->color_cycle_timeout == 0)
1720 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
1721 else if (!enabled && buffer->color_cycle_timeout != 0)
1723 gtk_timeout_remove (buffer->color_cycle_timeout);
1724 buffer->color_cycle_timeout = 0;
1727 tmp = buffer->color_tags;
1734 hue_to_color (hue, &color);
1736 g_object_set (G_OBJECT (tmp->data),
1737 "foreground_gdk", &color,
1741 g_object_set (G_OBJECT (tmp->data),
1742 "foreground_set", FALSE,
1745 hue += 1.0 / N_COLORS;
1747 tmp = g_slist_next (tmp);
1752 buffer_cycle_colors (Buffer *buffer)
1755 gdouble hue = buffer->start_hue;
1757 tmp = buffer->color_tags;
1762 hue_to_color (hue, &color);
1764 g_object_set (G_OBJECT (tmp->data),
1765 "foreground_gdk", &color,
1768 hue += 1.0 / N_COLORS;
1772 tmp = g_slist_next (tmp);
1775 buffer->start_hue += 1.0 / N_COLORS;
1776 if (buffer->start_hue > 1.0)
1777 buffer->start_hue = 0.0;
1781 close_view (View *view)
1783 views = g_slist_remove (views, view);
1784 buffer_unref (view->buffer);
1785 gtk_widget_destroy (view->window);
1786 g_object_unref (G_OBJECT (view->item_factory));
1795 check_close_view (View *view)
1797 if (view->buffer->refcount > 1 ||
1798 check_buffer_saved (view->buffer))
1803 view_set_title (View *view)
1805 char *pretty_name = buffer_pretty_name (view->buffer);
1806 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
1808 gtk_window_set_title (GTK_WINDOW (view->window), title);
1810 g_free (pretty_name);
1815 cursor_set_callback (GtkTextBuffer *buffer,
1816 const GtkTextIter *location,
1820 GtkTextView *text_view;
1822 /* Redraw tab windows if the cursor moves
1823 * on the mapped widget (windows may not exist before realization...
1826 text_view = GTK_TEXT_VIEW (user_data);
1828 if (GTK_WIDGET_MAPPED (text_view) &&
1829 mark == gtk_text_buffer_get_insert (buffer))
1831 GdkWindow *tab_window;
1833 tab_window = gtk_text_view_get_window (text_view,
1834 GTK_TEXT_WINDOW_TOP);
1836 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1838 tab_window = gtk_text_view_get_window (text_view,
1839 GTK_TEXT_WINDOW_BOTTOM);
1841 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1846 tab_stops_expose (GtkWidget *widget,
1847 GdkEventExpose *event,
1854 GdkWindow *bottom_win;
1855 GtkTextView *text_view;
1856 GtkTextWindowType type;
1857 GdkDrawable *target;
1858 gint *positions = NULL;
1860 GtkTextAttributes *attrs;
1862 GtkTextBuffer *buffer;
1865 text_view = GTK_TEXT_VIEW (widget);
1867 /* See if this expose is on the tab stop window */
1868 top_win = gtk_text_view_get_window (text_view,
1869 GTK_TEXT_WINDOW_TOP);
1871 bottom_win = gtk_text_view_get_window (text_view,
1872 GTK_TEXT_WINDOW_BOTTOM);
1874 if (event->window == top_win)
1876 type = GTK_TEXT_WINDOW_TOP;
1879 else if (event->window == bottom_win)
1881 type = GTK_TEXT_WINDOW_BOTTOM;
1882 target = bottom_win;
1887 first_x = event->area.x;
1888 last_x = first_x + event->area.width;
1890 gtk_text_view_window_to_buffer_coords (text_view,
1897 gtk_text_view_window_to_buffer_coords (text_view,
1904 buffer = gtk_text_view_get_buffer (text_view);
1906 gtk_text_buffer_get_iter_at_mark (buffer,
1908 gtk_text_buffer_get_mark (buffer,
1911 attrs = gtk_text_attributes_new ();
1913 gtk_text_iter_get_attributes (&insert, attrs);
1917 size = pango_tab_array_get_size (attrs->tabs);
1919 pango_tab_array_get_tabs (attrs->tabs,
1923 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
1931 gtk_text_attributes_unref (attrs);
1939 positions[i] = PANGO_PIXELS (positions[i]);
1941 gtk_text_view_buffer_to_window_coords (text_view,
1948 gdk_draw_line (target,
1949 widget->style->fg_gc [widget->state],
1962 get_lines (GtkTextView *text_view,
1965 GArray *buffer_coords,
1973 g_array_set_size (buffer_coords, 0);
1974 g_array_set_size (numbers, 0);
1976 /* Get iter at first y */
1977 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
1979 /* For each iter, get its location and add it to the arrays.
1980 * Stop when we pass last_y
1985 while (!gtk_text_iter_is_end (&iter))
1990 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
1992 g_array_append_val (buffer_coords, y);
1993 line_num = gtk_text_iter_get_line (&iter);
1994 g_array_append_val (numbers, line_num);
1998 if ((y + height) >= last_y)
2001 gtk_text_iter_forward_line (&iter);
2008 line_numbers_expose (GtkWidget *widget,
2009 GdkEventExpose *event,
2018 GdkWindow *left_win;
2019 GdkWindow *right_win;
2020 PangoLayout *layout;
2021 GtkTextView *text_view;
2022 GtkTextWindowType type;
2023 GdkDrawable *target;
2025 text_view = GTK_TEXT_VIEW (widget);
2027 /* See if this expose is on the line numbers window */
2028 left_win = gtk_text_view_get_window (text_view,
2029 GTK_TEXT_WINDOW_LEFT);
2031 right_win = gtk_text_view_get_window (text_view,
2032 GTK_TEXT_WINDOW_RIGHT);
2034 if (event->window == left_win)
2036 type = GTK_TEXT_WINDOW_LEFT;
2039 else if (event->window == right_win)
2041 type = GTK_TEXT_WINDOW_RIGHT;
2047 first_y = event->area.y;
2048 last_y = first_y + event->area.height;
2050 gtk_text_view_window_to_buffer_coords (text_view,
2057 gtk_text_view_window_to_buffer_coords (text_view,
2064 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2065 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2067 get_lines (text_view,
2074 /* Draw fully internationalized numbers! */
2076 layout = gtk_widget_create_pango_layout (widget, "");
2084 gtk_text_view_buffer_to_window_coords (text_view,
2087 g_array_index (pixels, gint, i),
2091 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2093 pango_layout_set_text (layout, str, -1);
2095 gtk_paint_layout (widget->style,
2097 GTK_WIDGET_STATE (widget),
2110 g_array_free (pixels, TRUE);
2111 g_array_free (numbers, TRUE);
2113 g_object_unref (G_OBJECT (layout));
2119 create_view (Buffer *buffer)
2126 view = g_new0 (View, 1);
2127 views = g_slist_prepend (views, view);
2129 view->buffer = buffer;
2130 buffer_ref (buffer);
2132 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2133 g_object_set_data (G_OBJECT (view->window), "view", view);
2135 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2136 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2138 view->accel_group = gtk_accel_group_new ();
2139 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2140 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2142 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2144 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2146 vbox = gtk_vbox_new (FALSE, 0);
2147 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2149 gtk_box_pack_start (GTK_BOX (vbox),
2150 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2153 sw = gtk_scrolled_window_new (NULL, NULL);
2154 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2155 GTK_POLICY_AUTOMATIC,
2156 GTK_POLICY_AUTOMATIC);
2158 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2159 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2162 /* Draw tab stops in the top and bottom windows. */
2164 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2165 GTK_TEXT_WINDOW_TOP,
2168 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2169 GTK_TEXT_WINDOW_BOTTOM,
2172 gtk_signal_connect (GTK_OBJECT (view->text_view),
2174 GTK_SIGNAL_FUNC (tab_stops_expose),
2177 g_signal_connect_data (G_OBJECT (view->buffer->buffer),
2179 GTK_SIGNAL_FUNC (cursor_set_callback),
2180 view->text_view, NULL, FALSE, FALSE);
2182 /* Draw line numbers in the side windows; we should really be
2183 * more scientific about what width we set them to.
2185 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2186 GTK_TEXT_WINDOW_RIGHT,
2189 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2190 GTK_TEXT_WINDOW_LEFT,
2193 gtk_signal_connect (GTK_OBJECT (view->text_view),
2195 GTK_SIGNAL_FUNC (line_numbers_expose),
2198 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2199 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2201 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2203 gtk_widget_grab_focus (view->text_view);
2205 view_set_title (view);
2206 view_init_menus (view);
2208 view_add_example_widgets (view);
2210 gtk_widget_show_all (view->window);
2215 view_add_example_widgets (View *view)
2217 GtkTextChildAnchor *anchor;
2220 buffer = view->buffer;
2222 /* REMOVE to test widgets */
2225 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2228 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2232 widget = gtk_button_new_with_label ("Foo");
2234 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2238 gtk_widget_show (widget);
2243 file_exists (const char *filename)
2245 struct stat statbuf;
2247 return stat (filename, &statbuf) == 0;
2252 if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
2254 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2255 putenv ("GTK_IM_MODULE_FILE=../modules/input/gtk.immodules");
2260 main (int argc, char** argv)
2268 gtk_init (&argc, &argv);
2270 buffer = create_buffer ();
2271 view = create_view (buffer);
2272 buffer_unref (buffer);
2274 push_active_window (GTK_WINDOW (view->window));
2275 for (i=1; i < argc; i++)
2279 /* Quick and dirty canonicalization - better should be in GLib
2282 if (!g_path_is_absolute (argv[i]))
2284 char *cwd = g_get_current_dir ();
2285 filename = g_strconcat (cwd, "/", argv[i], NULL);
2291 open_ok_func (filename, view);
2293 if (filename != argv[i])
2296 pop_active_window ();