]> Pileus Git - ~andy/gtk/blob - tests/testtext.c
Use g_path_get_dirname instead of g_dirname, which is deprecated.
[~andy/gtk] / tests / testtext.c
1 #include <stdio.h>
2 #include <sys/stat.h>
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include <gtk/gtk.h>
8 #include <gdk/gdkkeysyms.h>
9
10 typedef struct _Buffer Buffer;
11 typedef struct _View View;
12
13 static gint untitled_serial = 1;
14
15 GSList *active_window_stack = NULL;
16
17 struct _Buffer
18 {
19   gint refcount;
20   GtkTextBuffer *buffer;
21   char *filename;
22   gint untitled_serial;
23   GtkTextTag *not_editable_tag;
24   GtkTextTag *found_text_tag;
25 };
26
27 struct _View
28 {
29   GtkWidget *window;
30   GtkWidget *text_view;
31   GtkAccelGroup *accel_group;
32   GtkItemFactory *item_factory;
33   Buffer *buffer;
34 };
35
36 static void push_active_window (GtkWindow *window);
37 static void pop_active_window (void);
38 static GtkWindow *get_active_window (void);
39
40 static Buffer * create_buffer      (void);
41 static gboolean check_buffer_saved (Buffer *buffer);
42 static gboolean save_buffer        (Buffer *buffer);
43 static gboolean save_as_buffer     (Buffer *buffer);
44 static char *   buffer_pretty_name (Buffer *buffer);
45 static void     buffer_filename_set (Buffer *buffer);
46 static void     buffer_search_forward (Buffer *buffer,
47                                        const char *str,
48                                        View *view);
49
50 static View *view_from_widget (GtkWidget *widget);
51
52 static View *create_view      (Buffer *buffer);
53 static void  check_close_view (View   *view);
54 static void  close_view       (View   *view);
55 static void  view_set_title   (View   *view);
56 static void  view_init_menus  (View   *view);
57
58 GSList *buffers = NULL;
59 GSList *views = NULL;
60
61 static void
62 push_active_window (GtkWindow *window)
63 {
64   gtk_object_ref (GTK_OBJECT (window));
65   active_window_stack = g_slist_prepend (active_window_stack, window);
66 }
67
68 static void
69 pop_active_window (void)
70 {
71   gtk_object_unref (active_window_stack->data);
72   active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack);
73 }
74
75 static GtkWindow *
76 get_active_window (void)
77 {
78   if (active_window_stack)
79     return active_window_stack->data;
80   else
81     return NULL;
82 }
83
84 /*
85  * Filesel utility function
86  */
87
88 typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data);
89
90 static void
91 filesel_ok_cb (GtkWidget *button, GtkWidget *filesel)
92 {
93   FileselOKFunc ok_func = gtk_object_get_data (GTK_OBJECT (filesel), "ok-func");
94   gpointer data = gtk_object_get_data (GTK_OBJECT (filesel), "ok-data");
95   gint *result = gtk_object_get_data (GTK_OBJECT (filesel), "ok-result");
96   
97   gtk_widget_hide (filesel);
98   
99   if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data))
100     {
101       gtk_widget_destroy (filesel);
102       *result = TRUE;
103     }
104   else
105     gtk_widget_show (filesel);
106 }
107
108 gboolean
109 filesel_run (GtkWindow    *parent, 
110              const char   *title,
111              const char   *start_file,
112              FileselOKFunc func,
113              gpointer      data)
114 {
115   GtkWidget *filesel = gtk_file_selection_new (title);
116   gboolean result = FALSE;
117
118   if (!parent)
119     parent = get_active_window ();
120   
121   if (parent)
122     gtk_window_set_transient_for (GTK_WINDOW (filesel), parent);
123
124   if (start_file)
125     gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file);
126
127   
128   gtk_object_set_data (GTK_OBJECT (filesel), "ok-func", func);
129   gtk_object_set_data (GTK_OBJECT (filesel), "ok-data", data);
130   gtk_object_set_data (GTK_OBJECT (filesel), "ok-result", &result);
131
132   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
133                       "clicked",
134                       GTK_SIGNAL_FUNC (filesel_ok_cb), filesel);
135   gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
136                              "clicked",
137                              GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (filesel));
138
139   gtk_signal_connect (GTK_OBJECT (filesel), "destroy",
140                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
141   gtk_window_set_modal (GTK_WINDOW (filesel), TRUE);
142
143   gtk_widget_show (filesel);
144   gtk_main ();
145
146   return result;
147 }
148
149 /*
150  * MsgBox utility functions
151  */
152
153 static void
154 msgbox_yes_cb (GtkWidget *widget, gboolean *result)
155 {
156   *result = 0;
157   gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
158 }
159
160 static void
161 msgbox_no_cb (GtkWidget *widget, gboolean *result)
162 {
163   *result = 1;
164   gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
165 }
166
167 static gboolean
168 msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
169 {
170   if (event->keyval == GDK_Escape)
171     {
172       gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
173       gtk_object_destroy (GTK_OBJECT (widget));
174       return TRUE;
175     }
176
177   return FALSE;
178 }
179
180 gint
181 msgbox_run (GtkWindow  *parent,
182             const char *message,
183             const char *yes_button,
184             const char *no_button,
185             const char *cancel_button,
186             gint default_index)
187 {
188   gboolean result = -1;
189   GtkWidget *dialog;
190   GtkWidget *button;
191   GtkWidget *label;
192   GtkWidget *vbox;
193   GtkWidget *button_box;
194   GtkWidget *separator;
195
196   g_return_val_if_fail (message != NULL, FALSE);
197   g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE);
198
199   if (!parent)
200     parent = get_active_window ();
201   
202   /* Create a dialog
203    */
204   dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
205   gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
206   if (parent)
207     gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
208   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
209
210   /* Quit our recursive main loop when the dialog is destroyed.
211    */
212   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
213                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
214
215   /* Catch Escape key presses and have them destroy the dialog
216    */
217   gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event",
218                       GTK_SIGNAL_FUNC (msgbox_key_press_cb), NULL);
219
220   /* Fill in the contents of the widget
221    */
222   vbox = gtk_vbox_new (FALSE, 0);
223   gtk_container_add (GTK_CONTAINER (dialog), vbox);
224   
225   label = gtk_label_new (message);
226   gtk_misc_set_padding (GTK_MISC (label), 12, 12);
227   gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
228   gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
229
230   separator = gtk_hseparator_new ();
231   gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
232
233   button_box = gtk_hbutton_box_new ();
234   gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
235   gtk_container_set_border_width (GTK_CONTAINER (button_box), 8);
236   
237
238   /* When Yes is clicked, call the msgbox_yes_cb
239    * This sets the result variable and destroys the dialog
240    */
241   if (yes_button)
242     {
243       button = gtk_button_new_with_label (yes_button);
244       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
245       gtk_container_add (GTK_CONTAINER (button_box), button);
246
247       if (default_index == 0)
248         gtk_widget_grab_default (button);
249       
250       gtk_signal_connect (GTK_OBJECT (button), "clicked",
251                           GTK_SIGNAL_FUNC (msgbox_yes_cb), &result);
252     }
253
254   /* When No is clicked, call the msgbox_no_cb
255    * This sets the result variable and destroys the dialog
256    */
257   if (no_button)
258     {
259       button = gtk_button_new_with_label (no_button);
260       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
261       gtk_container_add (GTK_CONTAINER (button_box), button);
262
263       if (default_index == 0)
264         gtk_widget_grab_default (button);
265       
266       gtk_signal_connect (GTK_OBJECT (button), "clicked",
267                           GTK_SIGNAL_FUNC (msgbox_no_cb), &result);
268     }
269
270   /* When Cancel is clicked, destroy the dialog
271    */
272   if (cancel_button)
273     {
274       button = gtk_button_new_with_label (cancel_button);
275       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
276       gtk_container_add (GTK_CONTAINER (button_box), button);
277       
278       if (default_index == 1)
279         gtk_widget_grab_default (button);
280       
281       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
282                                  GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (dialog));
283     }
284
285   gtk_widget_show_all (dialog);
286
287   /* Run a recursive main loop until a button is clicked
288    * or the user destroys the dialog through the window mananger */
289   gtk_main ();
290
291   return result;
292 }
293
294 /*
295  * Example buffer filling code
296  */
297 static gint
298 blink_timeout (gpointer data)
299 {
300   GtkTextTag *tag;
301   static gboolean flip = FALSE;
302   
303   tag = GTK_TEXT_TAG (data);
304
305   gtk_object_set (GTK_OBJECT (tag),
306                  "foreground", flip ? "blue" : "purple",
307                  NULL);
308
309   flip = !flip;
310
311   return TRUE;
312 }
313
314 static gint
315 tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
316                   const GtkTextIter *iter, gpointer user_data)
317 {
318   gint char_index;
319
320   char_index = gtk_text_iter_get_offset (iter);
321   
322   switch (event->type)
323     {
324     case GDK_MOTION_NOTIFY:
325       printf ("Motion event at char %d tag `%s'\n",
326              char_index, tag->name);
327       break;
328         
329     case GDK_BUTTON_PRESS:
330       printf ("Button press at char %d tag `%s'\n",
331              char_index, tag->name);
332       break;
333         
334     case GDK_2BUTTON_PRESS:
335       printf ("Double click at char %d tag `%s'\n",
336              char_index, tag->name);
337       break;
338         
339     case GDK_3BUTTON_PRESS:
340       printf ("Triple click at char %d tag `%s'\n",
341              char_index, tag->name);
342       break;
343         
344     case GDK_BUTTON_RELEASE:
345       printf ("Button release at char %d tag `%s'\n",
346              char_index, tag->name);
347       break;
348         
349     case GDK_KEY_PRESS:
350     case GDK_KEY_RELEASE:
351       printf ("Key event at char %d tag `%s'\n",
352               char_index, tag->name);
353       break;
354       
355     case GDK_ENTER_NOTIFY:
356     case GDK_LEAVE_NOTIFY:
357     case GDK_PROPERTY_NOTIFY:
358     case GDK_SELECTION_CLEAR:
359     case GDK_SELECTION_REQUEST:
360     case GDK_SELECTION_NOTIFY:
361     case GDK_PROXIMITY_IN:
362     case GDK_PROXIMITY_OUT:
363     case GDK_DRAG_ENTER:
364     case GDK_DRAG_LEAVE:
365     case GDK_DRAG_MOTION:
366     case GDK_DRAG_STATUS:
367     case GDK_DROP_START:
368     case GDK_DROP_FINISHED:
369     default:
370       break;
371     }
372
373   return FALSE;
374 }
375
376 static void
377 setup_tag (GtkTextTag *tag)
378 {
379
380   gtk_signal_connect (GTK_OBJECT (tag),
381                      "event",
382                      GTK_SIGNAL_FUNC (tag_event_handler),
383                      NULL);
384 }
385
386 static char  *book_closed_xpm[] = {
387 "16 16 6 1",
388 "       c None s None",
389 ".      c black",
390 "X      c red",
391 "o      c yellow",
392 "O      c #808080",
393 "#      c white",
394 "                ",
395 "       ..       ",
396 "     ..XX.      ",
397 "   ..XXXXX.     ",
398 " ..XXXXXXXX.    ",
399 ".ooXXXXXXXXX.   ",
400 "..ooXXXXXXXXX.  ",
401 ".X.ooXXXXXXXXX. ",
402 ".XX.ooXXXXXX..  ",
403 " .XX.ooXXX..#O  ",
404 "  .XX.oo..##OO. ",
405 "   .XX..##OO..  ",
406 "    .X.#OO..    ",
407 "     ..O..      ",
408 "      ..        ",
409 "                "};
410
411
412
413 void
414 fill_example_buffer (GtkTextBuffer *buffer)
415 {
416   GtkTextIter iter, iter2;
417   GtkTextTag *tag;
418   GdkColor color;
419   GdkColor color2;
420   GdkPixmap *pixmap;
421   GdkBitmap *mask;
422   int i;
423   char *str;
424   
425   tag = gtk_text_buffer_create_tag (buffer, "fg_blue");
426
427   /*       gtk_timeout_add (1000, blink_timeout, tag); */
428       
429   setup_tag (tag);
430   
431   color.red = color.green = 0;
432   color.blue = 0xffff;
433   color2.red = 0xfff;
434   color2.blue = 0x0;
435   color2.green = 0;
436   gtk_object_set (GTK_OBJECT (tag),
437                  "foreground_gdk", &color,
438                  "background_gdk", &color2,
439                  "font", "Sans 24",
440                  NULL);
441
442   tag = gtk_text_buffer_create_tag (buffer, "fg_red");
443
444   setup_tag (tag);
445       
446   color.blue = color.green = 0;
447   color.red = 0xffff;
448   gtk_object_set (GTK_OBJECT (tag),
449                  "offset", -4,
450                  "foreground_gdk", &color,
451                  NULL);
452
453   tag = gtk_text_buffer_create_tag (buffer, "bg_green");
454
455   setup_tag (tag);
456       
457   color.blue = color.red = 0;
458   color.green = 0xffff;
459   gtk_object_set (GTK_OBJECT (tag),
460                  "background_gdk", &color,
461                  "font", "Sans 10",
462                  NULL);
463
464   tag = gtk_text_buffer_create_tag (buffer, "overstrike");
465
466   setup_tag (tag);
467       
468   gtk_object_set (GTK_OBJECT (tag),
469                  "overstrike", TRUE,
470                  NULL);
471
472
473   tag = gtk_text_buffer_create_tag (buffer, "underline");
474
475   setup_tag (tag);
476       
477   gtk_object_set (GTK_OBJECT (tag),
478                  "underline", PANGO_UNDERLINE_SINGLE,
479                  NULL);
480
481   setup_tag (tag);
482       
483   gtk_object_set (GTK_OBJECT (tag),
484                  "underline", PANGO_UNDERLINE_SINGLE,
485                  NULL);
486
487   tag = gtk_text_buffer_create_tag (buffer, "centered");
488       
489   gtk_object_set (GTK_OBJECT (tag),
490                  "justify", GTK_JUSTIFY_CENTER,
491                  NULL);
492
493   tag = gtk_text_buffer_create_tag (buffer, "rtl_quote");
494       
495   gtk_object_set (GTK_OBJECT (tag),
496                  "wrap_mode", GTK_WRAPMODE_WORD,
497                  "direction", GTK_TEXT_DIR_RTL,
498                  "left_wrapped_line_margin", 20,
499                  "left_margin", 20,
500                  "right_margin", 20,
501                  NULL);
502   
503   pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
504                                                   gtk_widget_get_default_colormap (),
505                                                   &mask,
506                                                   NULL, book_closed_xpm);
507   
508   g_assert (pixmap != NULL);
509   
510   i = 0;
511   while (i < 100)
512     {
513       GtkTextMark * temp_mark;
514       
515       gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
516           
517       gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask);
518           
519       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",
520                             i);
521       
522       gtk_text_buffer_insert (buffer, &iter, str, -1);
523
524       g_free (str);
525       
526       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
527           
528       gtk_text_buffer_insert (buffer, &iter,
529                              "(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"
530                              /* This is UTF8 stuff, Emacs doesn't
531                                 really know how to display it */
532                              "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew   שלום Japanese (日本語)\n", -1);
533
534       temp_mark =
535         gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
536
537 #if 1
538       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
539       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
540
541       gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
542
543       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
544       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
545
546       gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
547
548       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
549       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
550
551       gtk_text_buffer_apply_tag_by_name (buffer, "overstrike", &iter, &iter2);
552           
553       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
554       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
555
556       gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
557   
558       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
559       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
560
561       gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
562
563       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
564       gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
565
566       gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
567 #endif
568
569       gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
570       gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
571           
572       gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
573       gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
574
575       gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
576       gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
577       gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1);
578       gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
579       gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
580           
581       ++i;
582     }
583
584   gdk_pixmap_unref (pixmap);
585   if (mask)
586     gdk_bitmap_unref (mask);
587   
588   printf ("%d lines %d chars\n",
589          gtk_text_buffer_get_line_count (buffer),
590          gtk_text_buffer_get_char_count (buffer));
591
592   gtk_text_buffer_set_modified (buffer, FALSE);
593 }
594
595 gboolean
596 fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
597 {
598   FILE* f;
599   gchar buf[2048];
600   gint remaining = 0;
601   GtkTextIter iter, end;
602
603   f = fopen (filename, "r");
604   
605   if (f == NULL)
606     {
607       gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
608                                     filename, g_strerror (errno));
609       msgbox_run (NULL, err, "OK", NULL, NULL, 0);
610       g_free (err);
611       return FALSE;
612     }
613   
614   gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
615   while (!feof (f))
616     {
617       gint count;
618       char *leftover, *next;
619       int to_read = 2047  - remaining;
620       
621       count = fread (buf + remaining, 1, to_read, f);
622       buf[count + remaining] = '\0';
623
624       leftover = next = buf;
625       while (next)
626         {
627           leftover = next;
628           if (!*leftover)
629             break;
630           
631           next = g_utf8_next_char (next);
632         }
633
634       gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
635
636       remaining = buf + remaining + count - leftover;
637       g_memmove (buf, leftover, remaining);
638
639       if (remaining > 6 || count < to_read)
640           break;
641     }
642
643   if (remaining)
644     {
645       gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
646       msgbox_run (NULL, err, "OK", NULL, NULL, 0);
647       g_free (err);
648     }
649   
650   /* We had a newline in the buffer to begin with. (The buffer always contains
651    * a newline, so we delete to the end of the buffer to clean up.
652    */
653   gtk_text_buffer_get_last_iter (buffer, &end);
654   gtk_text_buffer_delete (buffer, &iter, &end);
655   
656   gtk_text_buffer_set_modified (buffer, FALSE);
657
658   return TRUE;
659 }
660
661 static gint
662 delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
663 {
664   View *view = view_from_widget (window);
665
666   push_active_window (GTK_WINDOW (window));
667   check_close_view (view);
668   pop_active_window ();
669
670   return TRUE;
671 }
672
673 /*
674  * Menu callbacks
675  */
676
677 static View *
678 get_empty_view (View *view)
679 {
680   if (!view->buffer->filename &&
681       !gtk_text_buffer_modified (view->buffer->buffer))
682     return view;
683   else
684     return create_view (create_buffer ());
685 }
686
687 static View *
688 view_from_widget (GtkWidget *widget)
689 {
690   GtkWidget *app;
691
692   if (GTK_IS_MENU_ITEM (widget))
693     {
694       GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
695       return gtk_object_get_data (GTK_OBJECT (item_factory), "view");      
696     }
697   else
698     {
699       GtkWidget *app = gtk_widget_get_toplevel (widget);
700       return gtk_object_get_data (GTK_OBJECT (app), "view");
701     }
702 }
703
704 static void
705 do_new (gpointer             callback_data,
706         guint                callback_action,
707         GtkWidget           *widget)
708 {
709   create_view (create_buffer ());
710 }
711
712 static void
713 do_new_view (gpointer             callback_data,
714              guint                callback_action,
715              GtkWidget           *widget)
716 {
717   View *view = view_from_widget (widget);
718   
719   create_view (view->buffer);
720 }
721
722 gboolean
723 open_ok_func (const char *filename, gpointer data)
724 {
725   View *view = data;
726   View *new_view = get_empty_view (view);
727
728   if (!fill_file_buffer (new_view->buffer->buffer, filename))
729     {
730       if (new_view != view)
731         close_view (new_view);
732       return FALSE;
733     }
734   else
735     {
736       g_free (new_view->buffer->filename);
737       new_view->buffer->filename = g_strdup (filename);
738       buffer_filename_set (new_view->buffer);
739       
740       return TRUE;
741     }
742 }
743
744 static void
745 do_open (gpointer             callback_data,
746          guint                callback_action,
747          GtkWidget           *widget)
748 {
749   View *view = view_from_widget (widget);
750
751   push_active_window (GTK_WINDOW (view->window));
752   filesel_run (NULL, "Open File", NULL, open_ok_func, view);
753   pop_active_window ();
754 }
755
756 static void
757 do_save_as (gpointer             callback_data,
758             guint                callback_action,
759             GtkWidget           *widget)
760 {
761   View *view = view_from_widget (widget);  
762
763   push_active_window (GTK_WINDOW (view->window));
764   save_as_buffer (view->buffer);
765   pop_active_window ();
766 }
767
768 static void
769 do_save (gpointer             callback_data,
770          guint                callback_action,
771          GtkWidget           *widget)
772 {
773   View *view = view_from_widget (widget);
774
775   push_active_window (GTK_WINDOW (view->window));
776   if (!view->buffer->filename)
777     do_save_as (callback_data, callback_action, widget);
778   else
779     save_buffer (view->buffer);
780   pop_active_window ();
781 }
782
783 static void
784 do_close   (gpointer             callback_data,
785             guint                callback_action,
786             GtkWidget           *widget)
787 {
788   View *view = view_from_widget (widget);
789
790   push_active_window (GTK_WINDOW (view->window));
791   check_close_view (view);
792   pop_active_window ();
793 }
794
795 static void
796 do_exit    (gpointer             callback_data,
797             guint                callback_action,
798             GtkWidget           *widget)
799 {
800   View *view = view_from_widget (widget);
801
802   GSList *tmp_list = buffers;
803
804   push_active_window (GTK_WINDOW (view->window));
805   while (tmp_list)
806     {
807       if (!check_buffer_saved (tmp_list->data))
808         return;
809
810       tmp_list = tmp_list->next;
811     }
812
813   gtk_main_quit ();
814   pop_active_window ();
815 }
816
817 static void
818 do_example (gpointer             callback_data,
819             guint                callback_action,
820             GtkWidget           *widget)
821 {
822   View *view = view_from_widget (widget);
823   View *new_view;
824
825   new_view = get_empty_view (view);
826   
827   fill_example_buffer (new_view->buffer->buffer);
828 }
829
830 static void
831 do_wrap_changed (gpointer             callback_data,
832                  guint                callback_action,
833                  GtkWidget           *widget)
834 {
835   View *view = view_from_widget (widget);
836
837   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
838 }
839
840 static void
841 do_direction_changed (gpointer             callback_data,
842                       guint                callback_action,
843                       GtkWidget           *widget)
844 {
845   View *view = view_from_widget (widget);
846   
847   gtk_widget_set_direction (view->text_view, callback_action);
848   gtk_widget_queue_resize (view->text_view);
849 }
850
851 static void
852 do_editable_changed (gpointer callback_data,
853                      guint callback_action,
854                      GtkWidget *widget)
855 {
856   View *view = view_from_widget (widget);
857
858   gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
859 }
860
861 static void
862 do_cursor_visible_changed (gpointer callback_data,
863                            guint callback_action,
864                            GtkWidget *widget)
865 {
866   View *view = view_from_widget (widget);
867
868   gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
869 }
870
871 static void
872 do_apply_editable (gpointer callback_data,
873                    guint callback_action,
874                    GtkWidget *widget)
875 {
876   View *view = view_from_widget (widget);
877   GtkTextIter start;
878   GtkTextIter end;
879   
880   if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
881                                             &start, &end))
882     {
883       if (callback_action)
884         {
885           gtk_text_buffer_remove_tag (view->buffer->buffer,
886                                       view->buffer->not_editable_tag,
887                                       &start, &end);
888         }
889       else
890         {
891           gtk_text_buffer_apply_tag (view->buffer->buffer,
892                                      view->buffer->not_editable_tag,
893                                      &start, &end);
894         }
895     }
896 }
897
898 static void
899 dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
900 {
901   GtkTextBuffer *buffer;
902   View *view = data;
903   GtkTextIter start, end;
904   gchar *search_string;
905   
906   buffer = gtk_object_get_data (GTK_OBJECT (dialog), "buffer");
907
908   gtk_text_buffer_get_bounds (buffer, &start, &end);
909
910   /* Remove trailing newline */
911   gtk_text_iter_prev_char (&end);
912   
913   search_string = gtk_text_iter_get_text (&start, &end);
914
915   printf ("Searching for `%s'\n", search_string);
916   
917   buffer_search_forward (view->buffer, search_string, view);
918
919   g_free (search_string);
920   
921   gtk_widget_destroy (dialog);
922 }
923
924 static void
925 do_search (gpointer callback_data,
926            guint callback_action,
927            GtkWidget *widget)
928 {
929   View *view = view_from_widget (widget);
930   GtkWidget *dialog;
931   GtkWidget *search_text;
932   GtkTextBuffer *buffer;
933
934 #if 0
935   
936   dialog = gtk_dialog_new_with_buttons ("Search",
937                                         GTK_WINDOW (view->window),
938                                         GTK_DIALOG_DESTROY_WITH_PARENT,
939                                         GTK_STOCK_BUTTON_CLOSE,
940                                         GTK_RESPONSE_NONE, NULL);
941
942   buffer = gtk_text_buffer_new (NULL);
943
944   /* FIXME memory leak once buffer is a GObject */
945   search_text = gtk_text_view_new_with_buffer (buffer);
946
947   gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
948                     search_text,
949                     TRUE, TRUE, 0);
950
951   gtk_object_set_data (GTK_OBJECT (dialog), "buffer", buffer);
952   
953   gtk_signal_connect (GTK_OBJECT (dialog),
954                       "response",
955                       GTK_SIGNAL_FUNC (dialog_response_callback),
956                       view);
957
958   gtk_widget_show (search_text);
959
960   gtk_widget_grab_focus (search_text);
961   
962   gtk_widget_show_all (dialog);
963 #endif
964 }
965
966 static void
967 view_init_menus (View *view)
968 {
969   GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
970   GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
971   GtkWidget *menu_item = NULL;
972
973   switch (direction)
974     {
975     case GTK_TEXT_DIR_LTR:
976       menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
977       break;
978     case GTK_TEXT_DIR_RTL:
979       menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
980       break;
981     default:
982       break;
983     }
984
985   if (menu_item)
986     gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
987
988   switch (wrap_mode)
989     {
990     case GTK_WRAPMODE_NONE:
991       menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
992       break;
993     case GTK_WRAPMODE_WORD:
994       menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
995       break;
996     default:
997       break;
998     }
999   
1000   if (menu_item)
1001     gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
1002 }
1003
1004 static GtkItemFactoryEntry menu_items[] =
1005 {
1006   { "/_File",            NULL,         0,           0, "<Branch>" },
1007   { "/File/_New",        "<control>N", do_new,      0, NULL },
1008   { "/File/New _View",   NULL,         do_new_view, 0, NULL },
1009   { "/File/_Open",       "<control>O", do_open,     0, NULL },
1010   { "/File/_Save",       "<control>S", do_save,     0, NULL },
1011   { "/File/Save _As...", NULL,         do_save_as,  0, NULL },
1012   { "/File/sep1",        NULL,         0,           0, "<Separator>" },
1013   { "/File/_Close",     "<control>W" , do_close,    0, NULL },
1014   { "/File/E_xit",      "<control>Q" , do_exit,     0, NULL },
1015
1016   { "/_Edit", NULL, 0, 0, "<Branch>" },
1017   { "/Edit/Find...", NULL, do_search, 0, NULL },
1018
1019   { "/_Settings",         NULL,         0,                0, "<Branch>" },
1020   { "/Settings/Wrap _Off",   NULL,      do_wrap_changed,  GTK_WRAPMODE_NONE, "<RadioItem>" },
1021   { "/Settings/Wrap _Words", NULL,      do_wrap_changed,  GTK_WRAPMODE_WORD, "/Settings/Wrap Off" },
1022   { "/Settings/sep1",        NULL,      0,                0, "<Separator>" },
1023   { "/Settings/Editable", NULL,      do_editable_changed,  TRUE, "<RadioItem>" },
1024   { "/Settings/Not editable",    NULL,      do_editable_changed,  FALSE, "/Settings/Editable" },
1025   { "/Settings/sep1",        NULL,      0,                0, "<Separator>" },
1026
1027   { "/Settings/Cursor visible",    NULL,      do_cursor_visible_changed,  TRUE, "<RadioItem>" },
1028   { "/Settings/Cursor not visible", NULL,      do_cursor_visible_changed,  FALSE, "/Settings/Cursor visible" },
1029   { "/Settings/sep1",        NULL,      0,                0, "<Separator>" },
1030   
1031   { "/Settings/Left-to-Right", NULL,    do_direction_changed,  GTK_TEXT_DIR_LTR, "<RadioItem>" },
1032   { "/Settings/Right-to-Left", NULL,    do_direction_changed,  GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
1033   { "/_Attributes",       NULL,         0,                0, "<Branch>" },
1034   { "/Attributes/Editable",       NULL,         do_apply_editable, TRUE, NULL },
1035   { "/Attributes/Not editable",           NULL,         do_apply_editable, FALSE, NULL },
1036   { "/_Test",            NULL,         0,           0, "<Branch>" },
1037   { "/Test/_Example",    NULL,         do_example,  0, NULL },
1038 };
1039
1040 static gboolean
1041 save_buffer (Buffer *buffer)
1042 {
1043   GtkTextIter start, end;
1044   gchar *chars;
1045   gboolean result = FALSE;
1046   gboolean have_backup = FALSE;
1047   gchar *bak_filename;
1048   FILE *file;
1049
1050   g_return_val_if_fail (buffer->filename != NULL, FALSE);
1051
1052   bak_filename = g_strconcat (buffer->filename, "~", NULL);
1053   
1054   if (rename (buffer->filename, bak_filename) != 0)
1055     {
1056       if (errno != ENOENT)
1057         {
1058           gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1059                                         buffer->filename, bak_filename, g_strerror (errno));
1060           msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1061           g_free (err);
1062         }
1063       
1064       return FALSE;
1065     }
1066   else
1067     have_backup = TRUE;
1068   
1069   file = fopen (buffer->filename, "w");
1070   if (!file)
1071     {
1072       gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
1073                                     buffer->filename, bak_filename, g_strerror (errno));
1074       msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1075     }
1076   else
1077     {
1078       gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
1079       gtk_text_buffer_get_last_iter (buffer->buffer, &end);
1080   
1081       chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
1082
1083       if (fputs (chars, file) == EOF ||
1084           fclose (file) == EOF)
1085         {
1086           gchar *err = g_strdup_printf ("Error writing to '%s': %s",
1087                                         buffer->filename, g_strerror (errno));
1088           msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1089           g_free (err);
1090         }
1091       else
1092         {
1093           /* Success
1094            */
1095           result = TRUE;
1096           gtk_text_buffer_set_modified (buffer->buffer, FALSE);   
1097         }
1098         
1099       g_free (chars);
1100     }
1101
1102   if (!result && have_backup)
1103     {
1104       if (rename (bak_filename, buffer->filename) != 0)
1105         {
1106           gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
1107                                         buffer->filename, bak_filename, g_strerror (errno), bak_filename);
1108           msgbox_run (NULL, err, "OK", NULL, NULL, 0);
1109           g_free (err);
1110         }
1111     }
1112
1113   g_free (bak_filename);
1114   
1115   return result;
1116 }
1117
1118 static gboolean
1119 save_as_ok_func (const char *filename, gpointer data)
1120 {
1121   Buffer *buffer = data;
1122   char *old_filename = buffer->filename;
1123
1124   if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
1125     {
1126       struct stat statbuf;
1127
1128       if (stat (filename, &statbuf) == 0)
1129         {
1130           gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
1131           gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
1132           g_free (err);
1133
1134           if (result != 0)
1135             return FALSE;
1136         }
1137     }
1138   
1139   buffer->filename = g_strdup (filename);
1140
1141   if (save_buffer (buffer))
1142     {
1143       g_free (old_filename);
1144       buffer_filename_set (buffer);
1145       return TRUE;
1146     }
1147   else
1148     {
1149       g_free (buffer->filename);
1150       buffer->filename = old_filename;
1151       return FALSE;
1152     }
1153 }
1154
1155 static gboolean
1156 save_as_buffer (Buffer *buffer)
1157 {
1158   return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
1159 }
1160
1161 static gboolean
1162 check_buffer_saved (Buffer *buffer)
1163 {
1164   if (gtk_text_buffer_modified (buffer->buffer))
1165     {
1166       char *pretty_name = buffer_pretty_name (buffer);
1167       char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
1168       gint result;
1169       
1170       g_free (pretty_name);
1171       
1172       result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
1173       g_free (msg);
1174   
1175       if (result == 0)
1176         return save_as_buffer (buffer);
1177       else if (result == 1)
1178         return TRUE;
1179       else
1180         return FALSE;
1181     }
1182   else
1183     return TRUE;
1184 }
1185
1186 static Buffer *
1187 create_buffer (void)
1188 {
1189   Buffer *buffer;
1190
1191   buffer = g_new (Buffer, 1);
1192
1193   buffer->buffer = gtk_text_buffer_new (NULL);
1194   gtk_object_ref (GTK_OBJECT (buffer->buffer));
1195   gtk_object_sink (GTK_OBJECT (buffer->buffer));
1196   
1197   buffer->refcount = 1;
1198   buffer->filename = NULL;
1199   buffer->untitled_serial = -1;
1200
1201   buffer->not_editable_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1202   gtk_object_set (GTK_OBJECT (buffer->not_editable_tag),
1203                   "editable", FALSE,
1204                   "foreground", "purple", NULL);
1205
1206   buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
1207   gtk_object_set (GTK_OBJECT (buffer->found_text_tag),
1208                   "foreground", "red", NULL);
1209   
1210   buffers = g_slist_prepend (buffers, buffer);
1211   
1212   return buffer;
1213 }
1214
1215 static char *
1216 buffer_pretty_name (Buffer *buffer)
1217 {
1218   if (buffer->filename)
1219     {
1220       char *p;
1221       char *result = g_path_get_basename (buffer->filename);
1222       p = strchr (result, '/');
1223       if (p)
1224         *p = '\0';
1225
1226       return result;
1227     }
1228   else
1229     {
1230       if (buffer->untitled_serial == -1)
1231         buffer->untitled_serial = untitled_serial++;
1232
1233       if (buffer->untitled_serial == 1)
1234         return g_strdup ("Untitled");
1235       else
1236         return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
1237     }
1238 }
1239
1240 static void
1241 buffer_filename_set (Buffer *buffer)
1242 {
1243   GSList *tmp_list = views;
1244
1245   while (tmp_list)
1246     {
1247       View *view = tmp_list->data;
1248
1249       if (view->buffer == buffer)
1250         view_set_title (view);
1251
1252       tmp_list = tmp_list->next;
1253     }
1254 }
1255
1256 static void
1257 buffer_search_forward (Buffer *buffer, const char *str,
1258                        View *view)
1259 {
1260   GtkTextIter iter;
1261   GtkTextIter start, end;
1262   gint char_len;
1263   int i = 0;
1264   GtkWidget *dialog;
1265   
1266   /* remove tag from whole buffer */
1267   gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
1268   gtk_text_buffer_remove_tag (buffer->buffer,  buffer->found_text_tag,
1269                               &start, &end );
1270   
1271   gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
1272                                     gtk_text_buffer_get_mark (buffer->buffer,
1273                                                               "insert"));
1274
1275
1276   char_len = g_utf8_strlen (str, -1);
1277
1278   if (char_len > 0)
1279     {
1280       while (gtk_text_iter_forward_search (&iter, str, TRUE, FALSE))
1281         {
1282           GtkTextIter end = iter;
1283           
1284           gtk_text_iter_forward_chars (&end, char_len);
1285           
1286           gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
1287                                      &iter, &end);
1288
1289           iter = end;
1290           
1291           ++i;
1292         }
1293     }
1294
1295 #if 0  
1296   dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
1297                                    GTK_MESSAGE_INFO,
1298                                    GTK_BUTTONS_OK,
1299                                    GTK_DIALOG_DESTROY_WITH_PARENT,
1300                                    "%d strings found and marked in red",
1301                                    i);
1302
1303   gtk_signal_connect_object (GTK_OBJECT (dialog),
1304                              "response",
1305                              GTK_SIGNAL_FUNC (gtk_widget_destroy),
1306                              GTK_OBJECT (dialog));
1307   
1308   gtk_widget_show (dialog);
1309 #endif
1310 }
1311
1312 static void
1313 buffer_ref (Buffer *buffer)
1314 {
1315   buffer->refcount++;
1316 }
1317
1318 static void
1319 buffer_unref (Buffer *buffer)
1320 {
1321   buffer->refcount--;
1322   if (buffer->refcount == 0)
1323     {
1324       buffers = g_slist_remove (buffers, buffer);
1325       gtk_object_unref (GTK_OBJECT (buffer->buffer));
1326       g_free (buffer->filename);
1327       g_free (buffer);
1328     }
1329 }
1330
1331 static void
1332 close_view (View *view)
1333 {
1334   views = g_slist_remove (views, view);
1335   buffer_unref (view->buffer);
1336   gtk_widget_destroy (view->window);
1337   g_object_unref (G_OBJECT (view->item_factory));
1338   
1339   g_free (view);
1340   
1341   if (!views)
1342     gtk_main_quit ();
1343 }
1344
1345 static void
1346 check_close_view (View *view)
1347 {
1348   if (view->buffer->refcount > 1 ||
1349       check_buffer_saved (view->buffer))
1350     close_view (view);
1351 }
1352
1353 static void
1354 view_set_title (View *view)
1355 {
1356   char *pretty_name = buffer_pretty_name (view->buffer);
1357   char *title = g_strconcat ("testtext - ", pretty_name, NULL);
1358
1359   gtk_window_set_title (GTK_WINDOW (view->window), title);
1360
1361   g_free (pretty_name);
1362   g_free (title);
1363 }
1364
1365 static View *
1366 create_view (Buffer *buffer)
1367 {
1368   View *view;
1369   
1370   GtkWidget *sw;
1371   GtkWidget *vbox;
1372
1373   view = g_new0 (View, 1);
1374   views = g_slist_prepend (views, view);
1375
1376   view->buffer = buffer;
1377   buffer_ref (buffer);
1378   
1379   view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1380   gtk_object_set_data (GTK_OBJECT (view->window), "view", view);
1381   
1382   gtk_signal_connect (GTK_OBJECT (view->window), "delete_event",
1383                       GTK_SIGNAL_FUNC (delete_event_cb), NULL);
1384
1385   view->accel_group = gtk_accel_group_new ();
1386   view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
1387   gtk_object_set_data (GTK_OBJECT (view->item_factory), "view", view);
1388   
1389   gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
1390
1391   gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
1392
1393   vbox = gtk_vbox_new (FALSE, 0);
1394   gtk_container_add (GTK_CONTAINER (view->window), vbox);
1395
1396   gtk_box_pack_start (GTK_BOX (vbox),
1397                       gtk_item_factory_get_widget (view->item_factory, "<main>"),
1398                       FALSE, FALSE, 0);
1399   
1400   sw = gtk_scrolled_window_new (NULL, NULL);
1401   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
1402                                  GTK_POLICY_AUTOMATIC,
1403                                  GTK_POLICY_AUTOMATIC);
1404
1405   view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
1406   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), GTK_WRAPMODE_WORD);
1407
1408   gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
1409   gtk_container_add (GTK_CONTAINER (sw), view->text_view);
1410
1411   gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
1412
1413   gtk_widget_grab_focus (view->text_view);
1414
1415   view_set_title (view);
1416   view_init_menus (view);
1417   
1418   gtk_widget_show_all (view->window);
1419   return view;
1420 }
1421
1422 int
1423 main (int argc, char** argv)
1424 {
1425   Buffer *buffer;
1426   View *view;
1427   int i;
1428   
1429   gtk_init (&argc, &argv);
1430   gdk_rgb_init (); /* FIXME remove this */
1431   
1432   buffer = create_buffer ();
1433   view = create_view (buffer);
1434   buffer_unref (buffer);
1435   
1436   push_active_window (GTK_WINDOW (view->window));
1437   for (i=1; i < argc; i++)
1438     {
1439       char *filename;
1440
1441       /* Quick and dirty canonicalization - better should be in GLib
1442        */
1443
1444       if (!g_path_is_absolute (argv[i]))
1445         {
1446           char *cwd = g_get_current_dir ();
1447           filename = g_strconcat (cwd, "/", argv[i], NULL);
1448           g_free (cwd);
1449         }
1450       else
1451         filename = argv[i];
1452
1453       open_ok_func (filename, view);
1454
1455       if (filename != argv[i])
1456         g_free (filename);
1457     }
1458   pop_active_window ();
1459   
1460   gtk_main ();
1461
1462   return 0;
1463 }
1464
1465