8 #include <gdk/gdkkeysyms.h>
10 #include "prop-editor.h"
12 typedef struct _Buffer Buffer;
13 typedef struct _View View;
15 static gint untitled_serial = 1;
17 GSList *active_window_stack = NULL;
22 GtkTextBuffer *buffer;
25 GtkTextTag *invisible_tag;
26 GtkTextTag *not_editable_tag;
27 GtkTextTag *found_text_tag;
28 GtkTextTag *custom_tabs_tag;
30 guint color_cycle_timeout;
38 GtkAccelGroup *accel_group;
39 GtkItemFactory *item_factory;
43 static void push_active_window (GtkWindow *window);
44 static void pop_active_window (void);
45 static GtkWindow *get_active_window (void);
47 static Buffer * create_buffer (void);
48 static gboolean check_buffer_saved (Buffer *buffer);
49 static gboolean save_buffer (Buffer *buffer);
50 static gboolean save_as_buffer (Buffer *buffer);
51 static char * buffer_pretty_name (Buffer *buffer);
52 static void buffer_filename_set (Buffer *buffer);
53 static void buffer_search_forward (Buffer *buffer,
56 static void buffer_search_backward (Buffer *buffer,
59 static void buffer_set_colors (Buffer *buffer,
61 static void buffer_cycle_colors (Buffer *buffer);
63 static View *view_from_widget (GtkWidget *widget);
65 static View *create_view (Buffer *buffer);
66 static void check_close_view (View *view);
67 static void close_view (View *view);
68 static void view_set_title (View *view);
69 static void view_init_menus (View *view);
70 static void view_add_example_widgets (View *view);
72 GSList *buffers = NULL;
76 push_active_window (GtkWindow *window)
78 g_object_ref (G_OBJECT (window));
79 active_window_stack = g_slist_prepend (active_window_stack, window);
83 pop_active_window (void)
85 gtk_object_unref (active_window_stack->data);
86 active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack);
90 get_active_window (void)
92 if (active_window_stack)
93 return active_window_stack->data;
99 * Filesel utility function
102 typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data);
105 filesel_ok_cb (GtkWidget *button, GtkWidget *filesel)
107 FileselOKFunc ok_func = g_object_get_data (G_OBJECT (filesel), "ok-func");
108 gpointer data = g_object_get_data (G_OBJECT (filesel), "ok-data");
109 gint *result = g_object_get_data (G_OBJECT (filesel), "ok-result");
111 gtk_widget_hide (filesel);
113 if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data))
115 gtk_widget_destroy (filesel);
119 gtk_widget_show (filesel);
123 filesel_run (GtkWindow *parent,
125 const char *start_file,
129 GtkWidget *filesel = gtk_file_selection_new (title);
130 gboolean result = FALSE;
133 parent = get_active_window ();
136 gtk_window_set_transient_for (GTK_WINDOW (filesel), parent);
139 gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file);
142 g_object_set_data (G_OBJECT (filesel), "ok-func", func);
143 g_object_set_data (G_OBJECT (filesel), "ok-data", data);
144 g_object_set_data (G_OBJECT (filesel), "ok-result", &result);
146 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
148 GTK_SIGNAL_FUNC (filesel_ok_cb), filesel);
149 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
151 GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (filesel));
153 gtk_signal_connect (GTK_OBJECT (filesel), "destroy",
154 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
155 gtk_window_set_modal (GTK_WINDOW (filesel), TRUE);
157 gtk_widget_show (filesel);
164 * MsgBox utility functions
168 msgbox_yes_cb (GtkWidget *widget, gboolean *result)
171 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
175 msgbox_no_cb (GtkWidget *widget, gboolean *result)
178 gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
182 msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
184 if (event->keyval == GDK_Escape)
186 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
187 gtk_object_destroy (GTK_OBJECT (widget));
195 msgbox_run (GtkWindow *parent,
197 const char *yes_button,
198 const char *no_button,
199 const char *cancel_button,
202 gboolean result = -1;
207 GtkWidget *button_box;
208 GtkWidget *separator;
210 g_return_val_if_fail (message != NULL, FALSE);
211 g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE);
214 parent = get_active_window ();
218 dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
219 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
221 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
222 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
224 /* Quit our recursive main loop when the dialog is destroyed.
226 gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
227 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
229 /* Catch Escape key presses and have them destroy the dialog
231 gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event",
232 GTK_SIGNAL_FUNC (msgbox_key_press_cb), NULL);
234 /* Fill in the contents of the widget
236 vbox = gtk_vbox_new (FALSE, 0);
237 gtk_container_add (GTK_CONTAINER (dialog), vbox);
239 label = gtk_label_new (message);
240 gtk_misc_set_padding (GTK_MISC (label), 12, 12);
241 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
242 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
244 separator = gtk_hseparator_new ();
245 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
247 button_box = gtk_hbutton_box_new ();
248 gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
249 gtk_container_set_border_width (GTK_CONTAINER (button_box), 8);
252 /* When Yes is clicked, call the msgbox_yes_cb
253 * This sets the result variable and destroys the dialog
257 button = gtk_button_new_with_label (yes_button);
258 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
259 gtk_container_add (GTK_CONTAINER (button_box), button);
261 if (default_index == 0)
262 gtk_widget_grab_default (button);
264 gtk_signal_connect (GTK_OBJECT (button), "clicked",
265 GTK_SIGNAL_FUNC (msgbox_yes_cb), &result);
268 /* When No is clicked, call the msgbox_no_cb
269 * This sets the result variable and destroys the dialog
273 button = gtk_button_new_with_label (no_button);
274 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
275 gtk_container_add (GTK_CONTAINER (button_box), button);
277 if (default_index == 0)
278 gtk_widget_grab_default (button);
280 gtk_signal_connect (GTK_OBJECT (button), "clicked",
281 GTK_SIGNAL_FUNC (msgbox_no_cb), &result);
284 /* When Cancel is clicked, destroy the dialog
288 button = gtk_button_new_with_label (cancel_button);
289 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
290 gtk_container_add (GTK_CONTAINER (button_box), button);
292 if (default_index == 1)
293 gtk_widget_grab_default (button);
295 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
296 GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (dialog));
299 gtk_widget_show_all (dialog);
301 /* Run a recursive main loop until a button is clicked
302 * or the user destroys the dialog through the window mananger */
309 * Example buffer filling code
312 blink_timeout (gpointer data)
315 static gboolean flip = FALSE;
317 tag = GTK_TEXT_TAG (data);
319 g_object_set (G_OBJECT (tag),
320 "foreground", flip ? "blue" : "purple",
329 tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
330 const GtkTextIter *iter, gpointer user_data)
334 char_index = gtk_text_iter_get_offset (iter);
338 case GDK_MOTION_NOTIFY:
339 printf ("Motion event at char %d tag `%s'\n",
340 char_index, tag->name);
343 case GDK_BUTTON_PRESS:
344 printf ("Button press at char %d tag `%s'\n",
345 char_index, tag->name);
348 case GDK_2BUTTON_PRESS:
349 printf ("Double click at char %d tag `%s'\n",
350 char_index, tag->name);
353 case GDK_3BUTTON_PRESS:
354 printf ("Triple click at char %d tag `%s'\n",
355 char_index, tag->name);
358 case GDK_BUTTON_RELEASE:
359 printf ("Button release at char %d tag `%s'\n",
360 char_index, tag->name);
364 case GDK_KEY_RELEASE:
365 printf ("Key event at char %d tag `%s'\n",
366 char_index, tag->name);
369 case GDK_ENTER_NOTIFY:
370 case GDK_LEAVE_NOTIFY:
371 case GDK_PROPERTY_NOTIFY:
372 case GDK_SELECTION_CLEAR:
373 case GDK_SELECTION_REQUEST:
374 case GDK_SELECTION_NOTIFY:
375 case GDK_PROXIMITY_IN:
376 case GDK_PROXIMITY_OUT:
379 case GDK_DRAG_MOTION:
380 case GDK_DRAG_STATUS:
382 case GDK_DROP_FINISHED:
391 setup_tag (GtkTextTag *tag)
393 g_signal_connect_data (G_OBJECT (tag),
395 G_CALLBACK (tag_event_handler),
396 NULL, NULL, FALSE, FALSE);
399 static const char *book_closed_xpm[] = {
425 fill_example_buffer (GtkTextBuffer *buffer)
427 GtkTextIter iter, iter2;
429 GtkTextChildAnchor *anchor;
436 /* FIXME this is broken if called twice on a buffer, since
437 * we try to create tags a second time.
440 tag = gtk_text_buffer_create_tag (buffer, "fg_blue", NULL);
442 /* gtk_timeout_add (1000, blink_timeout, tag); */
446 color.red = color.green = 0;
451 g_object_set (G_OBJECT (tag),
452 "foreground_gdk", &color,
453 "background_gdk", &color2,
457 tag = gtk_text_buffer_create_tag (buffer, "fg_red", NULL);
461 color.blue = color.green = 0;
463 g_object_set (G_OBJECT (tag),
464 "rise", -4 * PANGO_SCALE,
465 "foreground_gdk", &color,
468 tag = gtk_text_buffer_create_tag (buffer, "bg_green", NULL);
472 color.blue = color.red = 0;
473 color.green = 0xffff;
474 g_object_set (G_OBJECT (tag),
475 "background_gdk", &color,
479 tag = gtk_text_buffer_create_tag (buffer, "strikethrough", NULL);
483 g_object_set (G_OBJECT (tag),
484 "strikethrough", TRUE,
488 tag = gtk_text_buffer_create_tag (buffer, "underline", NULL);
492 g_object_set (G_OBJECT (tag),
493 "underline", PANGO_UNDERLINE_SINGLE,
498 g_object_set (G_OBJECT (tag),
499 "underline", PANGO_UNDERLINE_SINGLE,
502 tag = gtk_text_buffer_create_tag (buffer, "centered", NULL);
504 g_object_set (G_OBJECT (tag),
505 "justification", GTK_JUSTIFY_CENTER,
508 tag = gtk_text_buffer_create_tag (buffer, "rtl_quote", NULL);
510 g_object_set (G_OBJECT (tag),
511 "wrap_mode", GTK_WRAP_WORD,
512 "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);
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(שלום) 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);
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_end_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_get_modified (view->buffer->buffer))
699 return create_view (create_buffer ());
703 view_from_widget (GtkWidget *widget)
705 if (GTK_IS_MENU_ITEM (widget))
707 GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
708 return g_object_get_data (G_OBJECT (item_factory), "view");
712 GtkWidget *app = gtk_widget_get_toplevel (widget);
713 return g_object_get_data (G_OBJECT (app), "view");
718 do_new (gpointer callback_data,
719 guint callback_action,
722 create_view (create_buffer ());
726 do_new_view (gpointer callback_data,
727 guint callback_action,
730 View *view = view_from_widget (widget);
732 create_view (view->buffer);
736 open_ok_func (const char *filename, gpointer data)
739 View *new_view = get_empty_view (view);
741 if (!fill_file_buffer (new_view->buffer->buffer, filename))
743 if (new_view != view)
744 close_view (new_view);
749 g_free (new_view->buffer->filename);
750 new_view->buffer->filename = g_strdup (filename);
751 buffer_filename_set (new_view->buffer);
758 do_open (gpointer callback_data,
759 guint callback_action,
762 View *view = view_from_widget (widget);
764 push_active_window (GTK_WINDOW (view->window));
765 filesel_run (NULL, "Open File", NULL, open_ok_func, view);
766 pop_active_window ();
770 do_save_as (gpointer callback_data,
771 guint callback_action,
774 View *view = view_from_widget (widget);
776 push_active_window (GTK_WINDOW (view->window));
777 save_as_buffer (view->buffer);
778 pop_active_window ();
782 do_save (gpointer callback_data,
783 guint callback_action,
786 View *view = view_from_widget (widget);
788 push_active_window (GTK_WINDOW (view->window));
789 if (!view->buffer->filename)
790 do_save_as (callback_data, callback_action, widget);
792 save_buffer (view->buffer);
793 pop_active_window ();
797 do_close (gpointer callback_data,
798 guint callback_action,
801 View *view = view_from_widget (widget);
803 push_active_window (GTK_WINDOW (view->window));
804 check_close_view (view);
805 pop_active_window ();
809 do_exit (gpointer callback_data,
810 guint callback_action,
813 View *view = view_from_widget (widget);
815 GSList *tmp_list = buffers;
817 push_active_window (GTK_WINDOW (view->window));
820 if (!check_buffer_saved (tmp_list->data))
823 tmp_list = tmp_list->next;
827 pop_active_window ();
831 do_example (gpointer callback_data,
832 guint callback_action,
835 View *view = view_from_widget (widget);
838 new_view = get_empty_view (view);
840 fill_example_buffer (new_view->buffer->buffer);
842 view_add_example_widgets (new_view);
846 do_wrap_changed (gpointer callback_data,
847 guint callback_action,
850 View *view = view_from_widget (widget);
852 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
856 do_direction_changed (gpointer callback_data,
857 guint callback_action,
860 View *view = view_from_widget (widget);
862 gtk_widget_set_direction (view->text_view, callback_action);
863 gtk_widget_queue_resize (view->text_view);
868 do_spacing_changed (gpointer callback_data,
869 guint callback_action,
872 View *view = view_from_widget (widget);
876 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
878 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
880 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
885 gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
887 gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
889 gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
895 do_editable_changed (gpointer callback_data,
896 guint callback_action,
899 View *view = view_from_widget (widget);
901 gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
905 do_cursor_visible_changed (gpointer callback_data,
906 guint callback_action,
909 View *view = view_from_widget (widget);
911 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
915 do_color_cycle_changed (gpointer callback_data,
916 guint callback_action,
919 View *view = view_from_widget (widget);
921 buffer_set_colors (view->buffer, callback_action);
925 do_apply_editable (gpointer callback_data,
926 guint callback_action,
929 View *view = view_from_widget (widget);
933 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
938 gtk_text_buffer_remove_tag (view->buffer->buffer,
939 view->buffer->not_editable_tag,
944 gtk_text_buffer_apply_tag (view->buffer->buffer,
945 view->buffer->not_editable_tag,
952 do_apply_invisible (gpointer callback_data,
953 guint callback_action,
956 View *view = view_from_widget (widget);
960 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
965 gtk_text_buffer_remove_tag (view->buffer->buffer,
966 view->buffer->invisible_tag,
971 gtk_text_buffer_apply_tag (view->buffer->buffer,
972 view->buffer->invisible_tag,
979 do_apply_tabs (gpointer callback_data,
980 guint callback_action,
983 View *view = view_from_widget (widget);
987 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
992 gtk_text_buffer_remove_tag (view->buffer->buffer,
993 view->buffer->custom_tabs_tag,
998 gtk_text_buffer_apply_tag (view->buffer->buffer,
999 view->buffer->custom_tabs_tag,
1006 do_apply_colors (gpointer callback_data,
1007 guint callback_action,
1010 View *view = view_from_widget (widget);
1011 Buffer *buffer = view->buffer;
1015 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1018 if (!callback_action)
1022 tmp = buffer->color_tags;
1025 gtk_text_buffer_remove_tag (view->buffer->buffer,
1028 tmp = g_slist_next (tmp);
1035 tmp = buffer->color_tags;
1039 gboolean done = FALSE;
1042 gtk_text_iter_forward_char (&next);
1043 gtk_text_iter_forward_char (&next);
1045 if (gtk_text_iter_compare (&next, &end) > 0)
1051 gtk_text_buffer_apply_tag (view->buffer->buffer,
1060 tmp = g_slist_next (tmp);
1062 tmp = buffer->color_tags;
1069 do_remove_tags (gpointer callback_data,
1070 guint callback_action,
1073 View *view = view_from_widget (widget);
1077 if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
1080 gtk_text_buffer_remove_all_tags (view->buffer->buffer,
1086 do_properties (gpointer callback_data,
1087 guint callback_action,
1090 View *view = view_from_widget (widget);
1092 create_prop_editor (G_OBJECT (view->text_view), 0);
1102 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
1104 GtkTextBuffer *buffer;
1106 GtkTextIter start, end;
1107 gchar *search_string;
1109 if (response_id != RESPONSE_FORWARD &&
1110 response_id != RESPONSE_BACKWARD)
1112 gtk_widget_destroy (dialog);
1116 buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
1118 gtk_text_buffer_get_bounds (buffer, &start, &end);
1120 /* Remove trailing newline */
1121 gtk_text_iter_backward_char (&end);
1123 search_string = gtk_text_iter_get_text (&start, &end);
1125 printf ("Searching for `%s'\n", search_string);
1127 if (response_id == RESPONSE_FORWARD)
1128 buffer_search_forward (view->buffer, search_string, view);
1129 else if (response_id == RESPONSE_BACKWARD)
1130 buffer_search_backward (view->buffer, search_string, view);
1132 g_free (search_string);
1134 gtk_widget_destroy (dialog);
1138 do_search (gpointer callback_data,
1139 guint callback_action,
1142 View *view = view_from_widget (widget);
1144 GtkWidget *search_text;
1145 GtkTextBuffer *buffer;
1147 dialog = gtk_dialog_new_with_buttons ("Search",
1148 GTK_WINDOW (view->window),
1149 GTK_DIALOG_DESTROY_WITH_PARENT,
1150 "Forward", RESPONSE_FORWARD,
1151 "Backward", RESPONSE_BACKWARD,
1152 GTK_STOCK_BUTTON_CANCEL,
1153 GTK_RESPONSE_NONE, NULL);
1156 buffer = gtk_text_buffer_new (NULL);
1158 search_text = gtk_text_view_new_with_buffer (buffer);
1160 g_object_unref (G_OBJECT (buffer));
1162 gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1166 g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
1168 gtk_signal_connect (GTK_OBJECT (dialog),
1170 GTK_SIGNAL_FUNC (dialog_response_callback),
1173 gtk_widget_show (search_text);
1175 gtk_widget_grab_focus (search_text);
1177 gtk_widget_show_all (dialog);
1181 view_init_menus (View *view)
1183 GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
1184 GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
1185 GtkWidget *menu_item = NULL;
1189 case GTK_TEXT_DIR_LTR:
1190 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
1192 case GTK_TEXT_DIR_RTL:
1193 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
1200 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1205 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
1208 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
1211 menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
1218 gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1221 static GtkItemFactoryEntry menu_items[] =
1223 { "/_File", NULL, 0, 0, "<Branch>" },
1224 { "/File/_New", "<control>N", do_new, 0, NULL },
1225 { "/File/New _View", NULL, do_new_view, 0, NULL },
1226 { "/File/_Open", "<control>O", do_open, 0, NULL },
1227 { "/File/_Save", "<control>S", do_save, 0, NULL },
1228 { "/File/Save _As...", NULL, do_save_as, 0, NULL },
1229 { "/File/sep1", NULL, 0, 0, "<Separator>" },
1230 { "/File/_Close", "<control>W" , do_close, 0, NULL },
1231 { "/File/E_xit", "<control>Q" , do_exit, 0, NULL },
1233 { "/_Edit", NULL, 0, 0, "<Branch>" },
1234 { "/Edit/Find...", NULL, do_search, 0, NULL },
1236 { "/_Settings", NULL, 0, 0, "<Branch>" },
1237 { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAP_NONE, "<RadioItem>" },
1238 { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAP_WORD, "/Settings/Wrap Off" },
1239 { "/Settings/Wrap _Chars", NULL, do_wrap_changed, GTK_WRAP_CHAR, "/Settings/Wrap Off" },
1240 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1241 { "/Settings/Editable", NULL, do_editable_changed, TRUE, "<RadioItem>" },
1242 { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" },
1243 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1245 { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "<RadioItem>" },
1246 { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" },
1247 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1249 { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" },
1250 { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1252 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1253 { "/Settings/Sane spacing", NULL, do_spacing_changed, FALSE, "<RadioItem>" },
1254 { "/Settings/Funky spacing", NULL, do_spacing_changed, TRUE, "/Settings/Sane spacing" },
1255 { "/Settings/sep1", NULL, 0, 0, "<Separator>" },
1256 { "/Settings/Don't cycle color tags", NULL, do_color_cycle_changed, FALSE, "<RadioItem>" },
1257 { "/Settings/Cycle colors", NULL, do_color_cycle_changed, TRUE, "/Settings/Don't cycle color tags" },
1258 { "/_Attributes", NULL, 0, 0, "<Branch>" },
1259 { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL },
1260 { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL },
1261 { "/Attributes/Invisible", NULL, do_apply_invisible, FALSE, NULL },
1262 { "/Attributes/Visible", NULL, do_apply_invisible, TRUE, NULL },
1263 { "/Attributes/Custom tabs", NULL, do_apply_tabs, FALSE, NULL },
1264 { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
1265 { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
1266 { "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
1267 { "/Attributes/Remove all tags", NULL, do_remove_tags, 0, NULL },
1268 { "/Attributes/Properties", NULL, do_properties, 0, NULL },
1269 { "/_Test", NULL, 0, 0, "<Branch>" },
1270 { "/Test/_Example", NULL, do_example, 0, NULL },
1274 save_buffer (Buffer *buffer)
1276 GtkTextIter start, end;
1278 gboolean result = FALSE;
1279 gboolean have_backup = FALSE;
1280 gchar *bak_filename;
1283 g_return_val_if_fail (buffer->filename != NULL, FALSE);
1285 bak_filename = g_strconcat (buffer->filename, "~", NULL);
1287 if (rename (buffer->filename, bak_filename) != 0)
1289 if (errno != ENOENT)
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);
1301 file = fopen (buffer->filename, "w");
1304 gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1305 buffer->filename, bak_filename, g_strerror (errno));
1306 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1310 gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1311 gtk_text_buffer_get_end_iter (buffer->buffer, &end);
1313 chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1315 if (fputs (chars, file) == EOF ||
1316 fclose (file) == EOF)
1318 gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1319 buffer->filename, g_strerror (errno));
1320 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1328 gtk_text_buffer_set_modified (buffer->buffer, FALSE);
1334 if (!result && have_backup)
1336 if (rename (bak_filename, buffer->filename) != 0)
1338 gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1339 buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1340 msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1345 g_free (bak_filename);
1351 save_as_ok_func (const char *filename, gpointer data)
1353 Buffer *buffer = data;
1354 char *old_filename = buffer->filename;
1356 if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1358 struct stat statbuf;
1360 if (stat (filename, &statbuf) == 0)
1362 gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1363 gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1371 buffer->filename = g_strdup (filename);
1373 if (save_buffer (buffer))
1375 g_free (old_filename);
1376 buffer_filename_set (buffer);
1381 g_free (buffer->filename);
1382 buffer->filename = old_filename;
1388 save_as_buffer (Buffer *buffer)
1390 return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1394 check_buffer_saved (Buffer *buffer)
1396 if (gtk_text_buffer_get_modified (buffer->buffer))
1398 char *pretty_name = buffer_pretty_name (buffer);
1399 char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1402 g_free (pretty_name);
1404 result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1408 return save_as_buffer (buffer);
1409 else if (result == 1)
1421 create_buffer (void)
1424 PangoTabArray *tabs;
1427 buffer = g_new (Buffer, 1);
1429 buffer->buffer = gtk_text_buffer_new (NULL);
1431 buffer->refcount = 1;
1432 buffer->filename = NULL;
1433 buffer->untitled_serial = -1;
1435 buffer->color_tags = NULL;
1436 buffer->color_cycle_timeout = 0;
1437 buffer->start_hue = 0.0;
1440 while (i < N_COLORS)
1444 tag = gtk_text_buffer_create_tag (buffer->buffer, NULL, NULL);
1446 buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
1451 buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1452 "invisible", TRUE, NULL);
1454 buffer->not_editable_tag =
1455 gtk_text_buffer_create_tag (buffer->buffer, NULL,
1457 "foreground", "purple", NULL);
1459 buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1460 "foreground", "red", NULL);
1462 tabs = pango_tab_array_new_with_positions (4,
1467 PANGO_TAB_LEFT, 120);
1469 buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
1471 "foreground", "green", NULL);
1473 pango_tab_array_free (tabs);
1475 buffers = g_slist_prepend (buffers, buffer);
1481 buffer_pretty_name (Buffer *buffer)
1483 if (buffer->filename)
1486 char *result = g_path_get_basename (buffer->filename);
1487 p = strchr (result, '/');
1495 if (buffer->untitled_serial == -1)
1496 buffer->untitled_serial = untitled_serial++;
1498 if (buffer->untitled_serial == 1)
1499 return g_strdup ("Untitled");
1501 return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1506 buffer_filename_set (Buffer *buffer)
1508 GSList *tmp_list = views;
1512 View *view = tmp_list->data;
1514 if (view->buffer == buffer)
1515 view_set_title (view);
1517 tmp_list = tmp_list->next;
1522 buffer_search (Buffer *buffer,
1528 GtkTextIter start, end;
1532 /* remove tag from whole buffer */
1533 gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1534 gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag,
1537 gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1538 gtk_text_buffer_get_mark (buffer->buffer,
1544 GtkTextIter match_start, match_end;
1548 while (gtk_text_iter_forward_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 while (gtk_text_iter_backward_search (&iter, str, TRUE, FALSE,
1562 &match_start, &match_end,
1566 gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1567 &match_start, &match_end);
1574 dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1577 GTK_DIALOG_DESTROY_WITH_PARENT,
1578 "%d strings found and marked in red",
1581 gtk_signal_connect_object (GTK_OBJECT (dialog),
1583 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1584 GTK_OBJECT (dialog));
1586 gtk_widget_show (dialog);
1590 buffer_search_forward (Buffer *buffer, const char *str,
1593 buffer_search (buffer, str, view, TRUE);
1597 buffer_search_backward (Buffer *buffer, const char *str,
1600 buffer_search (buffer, str, view, FALSE);
1604 buffer_ref (Buffer *buffer)
1610 buffer_unref (Buffer *buffer)
1613 if (buffer->refcount == 0)
1615 buffer_set_colors (buffer, FALSE);
1616 buffers = g_slist_remove (buffers, buffer);
1617 g_object_unref (G_OBJECT (buffer->buffer));
1618 g_free (buffer->filename);
1624 hsv_to_rgb (gdouble *h,
1628 gdouble hue, saturation, value;
1646 f = hue - (int) hue;
1647 p = value * (1.0 - saturation);
1648 q = value * (1.0 - saturation * f);
1649 t = value * (1.0 - saturation * (1.0 - f));
1690 g_assert_not_reached ();
1696 hue_to_color (gdouble hue,
1705 g_return_if_fail (hue <= 1.0);
1707 hsv_to_rgb (&h, &s, &v);
1709 color->red = h * 65535;
1710 color->green = s * 65535;
1711 color->blue = v * 65535;
1716 color_cycle_timeout (gpointer data)
1718 Buffer *buffer = data;
1720 buffer_cycle_colors (buffer);
1726 buffer_set_colors (Buffer *buffer,
1732 if (enabled && buffer->color_cycle_timeout == 0)
1733 buffer->color_cycle_timeout = gtk_timeout_add (200, color_cycle_timeout, buffer);
1734 else if (!enabled && buffer->color_cycle_timeout != 0)
1736 gtk_timeout_remove (buffer->color_cycle_timeout);
1737 buffer->color_cycle_timeout = 0;
1740 tmp = buffer->color_tags;
1747 hue_to_color (hue, &color);
1749 g_object_set (G_OBJECT (tmp->data),
1750 "foreground_gdk", &color,
1754 g_object_set (G_OBJECT (tmp->data),
1755 "foreground_set", FALSE,
1758 hue += 1.0 / N_COLORS;
1760 tmp = g_slist_next (tmp);
1765 buffer_cycle_colors (Buffer *buffer)
1768 gdouble hue = buffer->start_hue;
1770 tmp = buffer->color_tags;
1775 hue_to_color (hue, &color);
1777 g_object_set (G_OBJECT (tmp->data),
1778 "foreground_gdk", &color,
1781 hue += 1.0 / N_COLORS;
1785 tmp = g_slist_next (tmp);
1788 buffer->start_hue += 1.0 / N_COLORS;
1789 if (buffer->start_hue > 1.0)
1790 buffer->start_hue = 0.0;
1794 close_view (View *view)
1796 views = g_slist_remove (views, view);
1797 buffer_unref (view->buffer);
1798 gtk_widget_destroy (view->window);
1799 g_object_unref (G_OBJECT (view->item_factory));
1808 check_close_view (View *view)
1810 if (view->buffer->refcount > 1 ||
1811 check_buffer_saved (view->buffer))
1816 view_set_title (View *view)
1818 char *pretty_name = buffer_pretty_name (view->buffer);
1819 char *title = g_strconcat ("testtext - ", pretty_name, NULL);
1821 gtk_window_set_title (GTK_WINDOW (view->window), title);
1823 g_free (pretty_name);
1828 cursor_set_callback (GtkTextBuffer *buffer,
1829 const GtkTextIter *location,
1833 GtkTextView *text_view;
1835 /* Redraw tab windows if the cursor moves
1836 * on the mapped widget (windows may not exist before realization...
1839 text_view = GTK_TEXT_VIEW (user_data);
1841 if (GTK_WIDGET_MAPPED (text_view) &&
1842 mark == gtk_text_buffer_get_insert (buffer))
1844 GdkWindow *tab_window;
1846 tab_window = gtk_text_view_get_window (text_view,
1847 GTK_TEXT_WINDOW_TOP);
1849 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1851 tab_window = gtk_text_view_get_window (text_view,
1852 GTK_TEXT_WINDOW_BOTTOM);
1854 gdk_window_invalidate_rect (tab_window, NULL, FALSE);
1859 tab_stops_expose (GtkWidget *widget,
1860 GdkEventExpose *event,
1867 GdkWindow *bottom_win;
1868 GtkTextView *text_view;
1869 GtkTextWindowType type;
1870 GdkDrawable *target;
1871 gint *positions = NULL;
1873 GtkTextAttributes *attrs;
1875 GtkTextBuffer *buffer;
1878 text_view = GTK_TEXT_VIEW (widget);
1880 /* See if this expose is on the tab stop window */
1881 top_win = gtk_text_view_get_window (text_view,
1882 GTK_TEXT_WINDOW_TOP);
1884 bottom_win = gtk_text_view_get_window (text_view,
1885 GTK_TEXT_WINDOW_BOTTOM);
1887 if (event->window == top_win)
1889 type = GTK_TEXT_WINDOW_TOP;
1892 else if (event->window == bottom_win)
1894 type = GTK_TEXT_WINDOW_BOTTOM;
1895 target = bottom_win;
1900 first_x = event->area.x;
1901 last_x = first_x + event->area.width;
1903 gtk_text_view_window_to_buffer_coords (text_view,
1910 gtk_text_view_window_to_buffer_coords (text_view,
1917 buffer = gtk_text_view_get_buffer (text_view);
1919 gtk_text_buffer_get_iter_at_mark (buffer,
1921 gtk_text_buffer_get_mark (buffer,
1924 attrs = gtk_text_attributes_new ();
1926 gtk_text_iter_get_attributes (&insert, attrs);
1930 size = pango_tab_array_get_size (attrs->tabs);
1932 pango_tab_array_get_tabs (attrs->tabs,
1936 in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
1944 gtk_text_attributes_unref (attrs);
1952 positions[i] = PANGO_PIXELS (positions[i]);
1954 gtk_text_view_buffer_to_window_coords (text_view,
1961 gdk_draw_line (target,
1962 widget->style->fg_gc [widget->state],
1975 get_lines (GtkTextView *text_view,
1978 GArray *buffer_coords,
1986 g_array_set_size (buffer_coords, 0);
1987 g_array_set_size (numbers, 0);
1989 /* Get iter at first y */
1990 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
1992 /* For each iter, get its location and add it to the arrays.
1993 * Stop when we pass last_y
1998 while (!gtk_text_iter_is_end (&iter))
2003 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
2005 g_array_append_val (buffer_coords, y);
2006 line_num = gtk_text_iter_get_line (&iter);
2007 g_array_append_val (numbers, line_num);
2011 if ((y + height) >= last_y)
2014 gtk_text_iter_forward_line (&iter);
2021 line_numbers_expose (GtkWidget *widget,
2022 GdkEventExpose *event,
2031 GdkWindow *left_win;
2032 GdkWindow *right_win;
2033 PangoLayout *layout;
2034 GtkTextView *text_view;
2035 GtkTextWindowType type;
2036 GdkDrawable *target;
2038 text_view = GTK_TEXT_VIEW (widget);
2040 /* See if this expose is on the line numbers window */
2041 left_win = gtk_text_view_get_window (text_view,
2042 GTK_TEXT_WINDOW_LEFT);
2044 right_win = gtk_text_view_get_window (text_view,
2045 GTK_TEXT_WINDOW_RIGHT);
2047 if (event->window == left_win)
2049 type = GTK_TEXT_WINDOW_LEFT;
2052 else if (event->window == right_win)
2054 type = GTK_TEXT_WINDOW_RIGHT;
2060 first_y = event->area.y;
2061 last_y = first_y + event->area.height;
2063 gtk_text_view_window_to_buffer_coords (text_view,
2070 gtk_text_view_window_to_buffer_coords (text_view,
2077 numbers = g_array_new (FALSE, FALSE, sizeof (gint));
2078 pixels = g_array_new (FALSE, FALSE, sizeof (gint));
2080 get_lines (text_view,
2087 /* Draw fully internationalized numbers! */
2089 layout = gtk_widget_create_pango_layout (widget, "");
2097 gtk_text_view_buffer_to_window_coords (text_view,
2100 g_array_index (pixels, gint, i),
2104 str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
2106 pango_layout_set_text (layout, str, -1);
2108 gtk_paint_layout (widget->style,
2110 GTK_WIDGET_STATE (widget),
2123 g_array_free (pixels, TRUE);
2124 g_array_free (numbers, TRUE);
2126 g_object_unref (G_OBJECT (layout));
2132 create_view (Buffer *buffer)
2139 view = g_new0 (View, 1);
2140 views = g_slist_prepend (views, view);
2142 view->buffer = buffer;
2143 buffer_ref (buffer);
2145 view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2146 g_object_set_data (G_OBJECT (view->window), "view", view);
2148 gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
2149 GTK_SIGNAL_FUNC (delete_event_cb), NULL);
2151 view->accel_group = gtk_accel_group_new ();
2152 view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
2153 g_object_set_data (G_OBJECT (view->item_factory), "view", view);
2155 gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
2157 gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
2159 vbox = gtk_vbox_new (FALSE, 0);
2160 gtk_container_add (GTK_CONTAINER (view->window), vbox);
2162 gtk_box_pack_start (GTK_BOX (vbox),
2163 gtk_item_factory_get_widget (view->item_factory, "<main>"),
2166 sw = gtk_scrolled_window_new (NULL, NULL);
2167 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2168 GTK_POLICY_AUTOMATIC,
2169 GTK_POLICY_AUTOMATIC);
2171 view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
2172 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
2175 /* Draw tab stops in the top and bottom windows. */
2177 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2178 GTK_TEXT_WINDOW_TOP,
2181 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2182 GTK_TEXT_WINDOW_BOTTOM,
2185 gtk_signal_connect (GTK_OBJECT (view->text_view),
2187 GTK_SIGNAL_FUNC (tab_stops_expose),
2190 g_signal_connect_data (G_OBJECT (view->buffer->buffer),
2192 GTK_SIGNAL_FUNC (cursor_set_callback),
2193 view->text_view, NULL, FALSE, FALSE);
2195 /* Draw line numbers in the side windows; we should really be
2196 * more scientific about what width we set them to.
2198 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2199 GTK_TEXT_WINDOW_RIGHT,
2202 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
2203 GTK_TEXT_WINDOW_LEFT,
2206 gtk_signal_connect (GTK_OBJECT (view->text_view),
2208 GTK_SIGNAL_FUNC (line_numbers_expose),
2211 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2212 gtk_container_add (GTK_CONTAINER (sw), view->text_view);
2214 gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
2216 gtk_widget_grab_focus (view->text_view);
2218 view_set_title (view);
2219 view_init_menus (view);
2221 view_add_example_widgets (view);
2223 gtk_widget_show_all (view->window);
2228 view_add_example_widgets (View *view)
2230 GtkTextChildAnchor *anchor;
2233 buffer = view->buffer;
2235 /* REMOVE to test widgets */
2238 anchor = g_object_get_data (G_OBJECT (buffer->buffer),
2241 if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
2245 widget = gtk_button_new_with_label ("Foo");
2247 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
2251 gtk_widget_show (widget);
2256 file_exists (const char *filename)
2258 struct stat statbuf;
2260 return stat (filename, &statbuf) == 0;
2265 if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
2267 putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
2268 putenv ("GTK_IM_MODULE_FILE=../modules/input/gtk.immodules");
2273 main (int argc, char** argv)
2281 gtk_init (&argc, &argv);
2283 buffer = create_buffer ();
2284 view = create_view (buffer);
2285 buffer_unref (buffer);
2287 push_active_window (GTK_WINDOW (view->window));
2288 for (i=1; i < argc; i++)
2292 /* Quick and dirty canonicalization - better should be in GLib
2295 if (!g_path_is_absolute (argv[i]))
2297 char *cwd = g_get_current_dir ();
2298 filename = g_strconcat (cwd, "/", argv[i], NULL);
2304 open_ok_func (filename, view);
2306 if (filename != argv[i])
2309 pop_active_window ();