]> matita.cs.unibo.it Git - helm.git/blob - helm/helmpot/guiGTK.c
ocaml 3.09 transition
[helm.git] / helm / helmpot / guiGTK.c
1 /*
2  * Copyright (C) 2000-2002, Luca Padovani <luca.padovani@cs.unibo.it>.
3  * 
4  * This file is part of HelmPot, a minimal browser for HELM.
5  * 
6  * HelmPot is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  * 
11  * HelmPot is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with HelmPot; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  * 
20  * For details, see the HelmPot World-Wide-Web page,
21  * http://cs.unibo.it/helm/helmview, or send a mail to
22  * <luca.padovani@cs.unibo.it>
23  */
24
25 #include <config.h>
26
27 #include <glib.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #if HAVE_UNISTD_H
32 # include <sys/types.h>
33 # include <sys/stat.h>
34 # include <fcntl.h>
35 # include <unistd.h>
36 #endif
37 #include <gtk/gtk.h>
38 #include <gdk/gdkkeysyms.h>
39
40 #include "gtkmathview.h"
41 #include "guiGTK.h"
42
43 #define XLINK_NS_URI "http://www.w3.org/1999/xlink"
44
45 #define pot_width 16
46 #define pot_height 16
47 PRIVATE unsigned char pot_bits[] = {
48    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x07,
49    0x00, 0x00, 0xe6, 0x2f, 0x34, 0x5f, 0xdc, 0x5f, 0xf8, 0x3f, 0xf8, 0x3f,
50    0xf0, 0x1f, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00};
51
52 #define pot_mask_width 16
53 #define pot_mask_height 16
54 static unsigned char pot_mask_bits[] = {
55    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0xe0, 0x0f, 0xe0, 0x0f,
56    0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0x7f,
57    0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x1f, 0x00, 0x00};
58
59 PRIVATE GtkWidget* window;
60 PRIVATE GtkWidget* main_area;
61 PRIVATE GtkWidget* scrolled_area;
62 PRIVATE GtkWidget* status_bar;
63 PRIVATE GtkMenuItem* kerning_item;
64 PRIVATE GtkMenuItem* anti_aliasing_item;
65 PRIVATE GtkMenuItem* font_size_item;
66 PRIVATE gchar* file_name = NULL;
67
68 PRIVATE GdkCursor* normal_cursor;
69 PRIVATE GdkCursor* link_cursor;  
70 PRIVATE GdkCursor* pot_cursor;
71
72 PRIVATE gboolean loading = FALSE;
73 PRIVATE guint statusbar_context;
74
75 PRIVATE void create_widget_set(void);
76 PRIVATE GtkWidget* get_main_menu(void);
77 PRIVATE void options_font_size(GtkWidget*, guint);
78 PRIVATE void options_font_manager(GtkWidget*, guint);
79 PRIVATE void options_verbosity(GtkWidget*, guint);
80 PRIVATE void options_kerning(GtkWidget*, gpointer);
81 PRIVATE void options_anti_aliasing(GtkWidget*, gpointer);
82 PRIVATE void help_about(GtkWidget*, gpointer);
83 PRIVATE void save_as(GtkWidget*);
84 PRIVATE void export_to_ps(GtkWidget*);
85
86 PRIVATE GtkItemFactoryEntry menu_items[] = {
87   { "/_File",                          NULL,         NULL,          0, "<Branch>" },
88   { "/File/Save _As...",               NULL,         save_as,       0, NULL },
89   { "/File/_Export to PostScript...",  NULL,         export_to_ps,  0, NULL },
90   { "/File/sep1",                      NULL,         NULL,          0, "<Separator>" },
91   { "/File/_Quit",                     "<control>Q", gtk_main_quit, 0, NULL },
92
93   { "/_Options",                       NULL, NULL,                  0,  "<Branch>" },
94   { "/Options/Default _Font Size",     NULL, NULL,                  0,  "<Branch>" },
95   { "/Options/Default Font Size/8pt",  NULL, options_font_size,     8,  "<RadioItem>" },
96   { "/Options/Default Font Size/10pt", NULL, options_font_size,     10, "/Options/Default Font Size/8pt" },
97   { "/Options/Default Font Size/12pt", NULL, options_font_size,     12, "/Options/Default Font Size/8pt" },
98   { "/Options/Default Font Size/14pt", NULL, options_font_size,     14, "/Options/Default Font Size/8pt" },
99   { "/Options/Default Font Size/18pt", NULL, options_font_size,     18, "/Options/Default Font Size/8pt" },
100   { "/Options/Default Font Size/24pt", NULL, options_font_size,     24, "/Options/Default Font Size/8pt" },
101   { "/Options/Font Manager",           NULL, NULL,                  0,  "<Branch>" },
102   { "/Options/Font Manager/_GTK",      NULL, options_font_manager,  0,  "<RadioItem>" },
103   { "/Options/Font Manager/_Type 1",   NULL, options_font_manager,  1,  "/Options/Font Manager/GTK" },
104   { "/Options/Verbosity",              NULL, NULL,                  0,  "<Branch>" },
105   { "/Options/Verbosity/_Errors",      NULL, options_verbosity,     0,  "<RadioItem>" },
106   { "/Options/Verbosity/_Warnings",    NULL, options_verbosity,     1,  "/Options/Verbosity/Errors" },
107   { "/Options/Verbosity/_Info",        NULL, options_verbosity,     2,  "/Options/Verbosity/Errors" },
108   { "/Options/Verbosity/_Debug",       NULL, options_verbosity,     3,  "/Options/Verbosity/Errors" },
109   { "/Options/sep1",                   NULL, NULL,                  0,  "<Separator>" },
110   { "/Options/_Kerning",               NULL, options_kerning,       0,  "<ToggleItem>" },
111   { "/Options/_Anti Aliasing",         NULL, options_anti_aliasing, 0,  "<ToggleItem>" },
112
113   { "/_Help" ,        NULL,         NULL,          0, "<LastBranch>" },
114   { "/Help/About...", NULL,         help_about,    0, NULL }
115 };
116
117 PRIVATE void
118 quick_message(const gchar* msg)
119 {
120   GtkWidget* dialog;
121   GtkWidget* label;
122   GtkWidget* okay_button;
123      
124   /* Create the widgets */
125      
126   dialog = gtk_dialog_new();
127   label = gtk_label_new (msg);
128   okay_button = gtk_button_new_with_label("OK");
129
130   gtk_widget_set_usize(dialog, 300, 100);
131
132   /* Ensure that the dialog box is destroyed when the user clicks ok. */
133      
134   gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
135                              GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT(dialog));
136   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
137                      okay_button);
138   
139   /* Add the label, and show everything we've added to the dialog. */
140   
141   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
142   gtk_widget_show_all (dialog);
143 }
144
145 PRIVATE void
146 load_error_msg(const gchar* name)
147 {
148   gchar* msg = g_strdup_printf("Could not load\n`%s'", name);
149   quick_message(msg);
150   g_free(msg);
151 }
152
153 PRIVATE void
154 save_error_msg(const gchar* name)
155 {
156   gchar* msg = g_strdup_printf("Could not save\n`%s'", name);
157   quick_message(msg);
158   g_free(msg);
159 }
160
161 void
162 GUI_init(gint* argc, gchar*** argv, gchar* title, guint width, guint height, GtkFunction f, guint32 timeout)
163 {
164   GdkPixmap* source;
165   GdkPixmap* mask;
166
167   GdkColor fg = { 0, 65535, 65535, 65535 };
168   GdkColor bg = { 0, 0, 0, 0 };
169
170   gtk_init(argc, argv);
171
172   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
173   gtk_window_set_title(GTK_WINDOW(window), title);
174   gtk_window_set_default_size(GTK_WINDOW(window), width, height);
175   gtk_signal_connect(GTK_OBJECT(window), "delete_event", (GtkSignalFunc) gtk_main_quit, NULL);
176   create_widget_set();
177
178   gtk_widget_show(window);
179
180   gtk_timeout_add(timeout, f, NULL);
181
182   normal_cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
183   link_cursor = gdk_cursor_new(GDK_HAND2);
184   
185   source = gdk_bitmap_create_from_data (NULL, pot_bits,
186                                         pot_width, pot_height);
187   mask = gdk_bitmap_create_from_data (NULL, pot_mask_bits,
188                                       pot_mask_width, pot_mask_height);
189   pot_cursor = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, 8, 8);
190   gdk_pixmap_unref (source);
191   gdk_pixmap_unref (mask);  
192 }
193
194 void
195 GUI_uninit()
196 {
197 }
198
199 int
200 GUI_load_document(const gchar* name)
201 {
202   GtkMathView* math_view;
203   GtkMathViewClass* klass;
204   gboolean res;
205
206   g_return_val_if_fail(name != NULL, -1);
207   g_return_val_if_fail(main_area != NULL, -1);
208   g_return_val_if_fail(GTK_IS_MATH_VIEW(main_area), -1);
209
210   math_view = GTK_MATH_VIEW(main_area);
211   g_return_val_if_fail(math_view != NULL, -1);
212
213   klass = (GtkMathViewClass*) gtk_type_class(gtk_math_view_get_type());
214   g_return_val_if_fail(klass != NULL, -1);
215
216   res = gtk_math_view_load(math_view, name);
217   gdk_window_set_cursor(main_area->window, normal_cursor);
218   loading = FALSE;
219
220   if (!res) {
221     load_error_msg(name);
222     return -1;
223   }
224
225   gtk_statusbar_pop(GTK_STATUSBAR(status_bar), statusbar_context);
226   if (strlen(name) > 40) name += strlen(name) - 40;
227   gtk_statusbar_push(GTK_STATUSBAR(status_bar), statusbar_context, name);
228
229   if (file_name != NULL) g_free(file_name);
230   file_name = g_strdup(name);
231
232   return 0;
233 }
234
235 void
236 GUI_unload_document()
237 {
238   GtkMathView* math_view;
239
240   g_return_if_fail(main_area != NULL);
241   g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
242
243   math_view = GTK_MATH_VIEW(main_area);
244
245   gtk_math_view_unload(math_view);
246 }
247
248 void
249 GUI_run()
250 {
251   gtk_main();
252 }
253
254 PRIVATE void
255 options_font_size(GtkWidget* widget, guint size)
256 {
257   GtkMathView* math_view;
258
259   g_return_if_fail(main_area != NULL);
260   g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
261
262   math_view = GTK_MATH_VIEW(main_area);
263
264   gtk_math_view_set_font_size(math_view, size);
265 }
266
267 PRIVATE void
268 options_font_manager(GtkWidget* widget, guint id)
269 {
270   GtkMathView* math_view;
271
272   g_return_if_fail(main_area != NULL);
273   g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
274   
275   math_view = GTK_MATH_VIEW(main_area);
276
277   gtk_math_view_set_font_manager_type(math_view, id);
278 }
279
280 PRIVATE void
281 options_anti_aliasing(GtkWidget* widget, gpointer data)
282 {
283   gboolean aa = gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area));
284   gtk_math_view_set_anti_aliasing(GTK_MATH_VIEW(main_area), !aa);
285 }
286
287 PRIVATE void
288 options_kerning(GtkWidget* widget, gpointer data)
289 {
290   gboolean k = gtk_math_view_get_kerning(GTK_MATH_VIEW(main_area));
291   gtk_math_view_set_kerning(GTK_MATH_VIEW(main_area), !k);
292 }
293
294 PRIVATE void
295 options_verbosity(GtkWidget* widget, guint level)
296 {
297   gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), level);
298 }
299
300 PRIVATE void
301 help_about(GtkWidget* widget, gpointer data)
302 {
303   GtkWidget* dialog;
304   GtkWidget* label;
305   GtkWidget* ok;
306
307   dialog = gtk_dialog_new();
308   label = gtk_label_new("\n    HELM PoT    \n    Copyright (C) 2001-2002 Luca Padovani    \n");
309   ok = gtk_button_new_with_label("Close");
310
311   gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
312                              GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
313   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
314                      ok);
315
316   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
317
318   gtk_widget_show_all (dialog);
319 }
320
321 PRIVATE void
322 export_filename(GtkFileSelection* selector, gpointer user_data)
323 {
324   FILE* f;
325   GtkMathView* math_view;
326   gchar* selected_filename;
327   
328   selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(user_data));
329
330   math_view = GTK_MATH_VIEW(main_area);
331
332   f = fopen(selected_filename, "wt");
333   if (f == NULL) {
334     save_error_msg(selected_filename);
335     /*g_free(selected_filename);*/
336     return;
337   }
338
339   gtk_math_view_export_to_postscript(math_view,
340                                      (21 * SCALED_POINTS_PER_CM) / SCALED_POINTS_PER_PX,
341                                      (29 * SCALED_POINTS_PER_CM) / SCALED_POINTS_PER_PX,
342                                      SCALED_POINTS_PER_IN / SCALED_POINTS_PER_PX,
343                                      SCALED_POINTS_PER_IN / SCALED_POINTS_PER_PX,
344                                      FALSE,
345                                      f);
346
347   fclose(f);
348   /*g_free(selected_filename);*/
349 }
350
351 PRIVATE void
352 save_filename(GtkFileSelection* selector, gpointer user_data)
353 {
354   FILE* source;
355   FILE* dest;
356   gchar* buffer;
357   gchar* selected_filename;
358
359   if (file_name == NULL) return;
360
361   source = fopen(file_name, "rt");
362   if (source == NULL) {
363     load_error_msg(file_name);
364     return;
365   }
366
367   selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(user_data));
368   if (selected_filename == NULL) return;
369
370   dest = fopen(selected_filename, "wt");
371   if (dest == NULL) {
372     save_error_msg(selected_filename);
373     /*g_free(selected_filename);*/
374     return;
375   }
376
377   /*g_free(selected_filename);*/
378
379   buffer = g_new(gchar, 2048);
380   while (!feof(source)) {
381     size_t n = fread(buffer, sizeof(gchar), 2048, source);
382     fwrite(buffer, sizeof(gchar), n, dest);
383   }
384
385   g_free(buffer);
386   fclose(source);
387   fclose(dest);
388 }
389
390 PRIVATE void
391 file_dialog(const gchar* title, GtkSignalFunc f)
392 {
393   GtkWidget* fs;
394
395   g_return_if_fail(title != NULL);
396   g_return_if_fail(f != NULL);
397
398   fs = gtk_file_selection_new(title);
399
400   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
401                       "clicked", f, fs);
402                              
403   /* Ensure that the dialog box is destroyed when the user clicks a button. */
404      
405   gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
406                              "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
407                              (gpointer) fs);
408
409   gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
410                              "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
411                              (gpointer) fs);
412      
413   /* Display that dialog */
414      
415   gtk_widget_show (fs);
416 }
417
418 PRIVATE void
419 export_to_ps(GtkWidget* widget)
420 {
421   file_dialog("Export to PostScript", export_filename);
422 #if 0
423   static GList* items = NULL;
424
425   GtkWidget* dialog;
426   GtkWidget* tmp;
427
428   if (items == NULL) {
429     items = g_list_append(items, "A4");
430     items = g_list_append(items, "A5");
431   }
432
433   dialog = gtk_dialog_new();
434   tmp = gtk_label_new("Paper size");
435   gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), tmp);
436   tmp = gtk_combo_new();
437   gtk_combo_set_popdown_strings(GTK_COMBO(tmp), items);
438   gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), tmp);
439 #if 0
440   tmp = gtk_check_button_new_with_label("Disable Colors");
441   gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), tmp);
442 #endif
443
444   tmp = gtk_button_new_with_label("OK");
445   gtk_signal_connect_object(GTK_OBJECT(tmp), "clicked", GTK_SIGNAL_FUNC(export_to_ps_get_file_name), dialog);
446   gtk_signal_connect_object(GTK_OBJECT(tmp), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), dialog);
447   gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), tmp);
448   tmp = gtk_button_new_with_label("Cancel");
449   gtk_signal_connect_object(GTK_OBJECT(tmp), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), dialog);
450   gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), tmp);
451
452   gtk_widget_show_all(dialog);
453 #endif
454 }
455
456 PRIVATE void
457 save_as(GtkWidget* widget)
458 {
459   file_dialog("Save As...", save_filename);
460 }
461
462 PRIVATE void
463 element_changed(GtkMathView* math_view, GdomeElement* elem)
464 {
465   g_return_if_fail(math_view != NULL);
466   g_return_if_fail(main_area != NULL);
467   g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
468   /* fprintf(stderr, "node changed: %p %s\n", node, (node != NULL) ? mdom_node_get_name(node) : "-"); */
469
470   if (!loading) {
471     GdomeException exc = 0;
472     GdomeDOMString* namespaceURI = gdome_str_mkref(XLINK_NS_URI);
473     GdomeDOMString* localName = gdome_str_mkref("href");
474     
475     if (elem != NULL) {
476       gdome_el_ref(elem, &exc);
477       g_assert(exc == 0);
478     }
479
480     while (elem != NULL && !gdome_el_hasAttributeNS(elem, namespaceURI, localName, &exc)) {
481       GdomeElement* parent = gdome_cast_el(gdome_el_parentNode(elem, &exc));
482       g_assert(exc == 0);
483       gdome_el_unref(elem, &exc);
484       g_assert(exc == 0);
485       elem = parent;
486     }
487     g_assert(exc == 0);
488
489     gdome_str_unref(namespaceURI);
490     gdome_str_unref(localName);
491
492     if (elem != NULL) {
493       gdome_el_unref(elem, &exc);
494       g_assert(exc == 0);
495       gdk_window_set_cursor(main_area->window, link_cursor);
496     } else
497       gdk_window_set_cursor(main_area->window, normal_cursor);
498   }
499 }
500
501 PRIVATE void
502 selection_changed(GtkMathView* math_view, GdomeElement* elem)
503 {
504   GdomeException exc = 0;
505   GdomeDOMString* localName = gdome_str_mkref("xref");
506
507   g_return_if_fail(math_view != NULL);
508   g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
509
510   if (elem != NULL) {
511     gdome_el_ref(elem, &exc);
512     g_assert(exc == 0);
513   }
514
515   while (elem != NULL && !gdome_el_hasAttribute(elem, localName, &exc)) {
516     GdomeElement* parent = gdome_cast_el(gdome_el_parentNode(elem, &exc));
517     g_assert(exc == 0);
518     gdome_el_unref(elem, &exc);
519     g_assert(exc == 0);
520     elem = parent;
521   }
522
523   gdome_str_unref(localName);
524
525   gtk_math_view_set_selection(math_view, elem);
526   if (elem != NULL) {
527     gdome_el_unref(elem, &exc);
528     g_assert(exc == 0);
529   }
530 }
531
532 PRIVATE void
533 jump(GdomeDOMString* href)
534 {
535   pid_t pid;
536   g_return_if_fail(href != NULL);
537
538   gdk_window_set_cursor(main_area->window, pot_cursor);  
539   loading = TRUE;
540   pid = fork();
541   if (pid == -1) exit(-1);
542   if (pid == 0) {
543     gchar* open_url = g_strdup_printf("openURL(%s,cic)", href->str);
544     gint fd;
545     
546     close(0);
547     close(1);
548     close(2);
549     
550     fd = open("/dev/null", O_RDWR);
551     dup(fd);
552     dup(fd);
553     
554     execlp("netscape", "netscape", "-noraise", "-remote", open_url, NULL);
555     perror("exec failed:");
556     exit(-1);
557   }
558 }
559
560 PRIVATE void
561 clicked(GtkMathView* math_view, gpointer user_data)
562 {
563   GdomeException exc = 0;
564   GdomeDOMString* namespaceURI = gdome_str_mkref(XLINK_NS_URI);
565   GdomeDOMString* localName = gdome_str_mkref("href");
566
567   GdomeElement* p = gtk_math_view_get_element(math_view);
568   while (p != NULL && !gdome_el_hasAttributeNS(p, namespaceURI, localName, &exc)) {
569     GdomeElement* parent = gdome_cast_el(gdome_el_parentNode(p, &exc));
570     g_assert(exc == 0);
571     gdome_el_unref(p, &exc);
572     g_assert(exc == 0);
573     p = parent;
574   }
575   g_assert(exc == 0);
576
577   if (p != NULL) {
578     GdomeDOMString* href = gdome_el_getAttributeNS(p, namespaceURI, localName, &exc);
579     g_assert(exc == 0);
580     g_assert(href != NULL);
581
582     jump(href);
583     gdome_str_unref(href);
584     gdome_el_unref(p, &exc);
585     g_assert(exc == 0);
586   } else {
587     p = gtk_math_view_get_action(math_view);
588     if (p != NULL) {
589       gtk_math_view_action_toggle(math_view);
590       gdome_el_unref(p, &exc);
591       g_assert(exc == 0);
592     }
593   }
594
595   gdome_str_unref(namespaceURI);
596   gdome_str_unref(localName);
597 }
598
599 PRIVATE void
600 create_widget_set()
601 {
602   GtkWidget* main_vbox;
603   GtkWidget* menu_bar;
604
605   main_vbox = gtk_vbox_new(FALSE, 1);
606   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
607   gtk_container_add(GTK_CONTAINER(window), main_vbox);
608   gtk_widget_show(main_vbox);
609
610   menu_bar = get_main_menu();
611   gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, TRUE, 0);
612   gtk_widget_show(menu_bar);
613
614   main_area = gtk_math_view_new(NULL, NULL);
615   gtk_widget_show(main_area);
616
617   gtk_signal_connect_object (GTK_OBJECT (main_area),
618                              "element_changed", GTK_SIGNAL_FUNC (element_changed),
619                              (gpointer) main_area);
620
621   gtk_signal_connect_object (GTK_OBJECT (main_area),
622                              "selection_changed", GTK_SIGNAL_FUNC (selection_changed),
623                              (gpointer) main_area);
624
625   gtk_signal_connect_object (GTK_OBJECT (main_area), 
626                              "clicked", GTK_SIGNAL_FUNC(clicked),
627                              (gpointer) main_area);
628                              
629   scrolled_area = gtk_scrolled_window_new(NULL, NULL);
630   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
631                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
632   gtk_widget_show(scrolled_area);
633   gtk_container_add(GTK_CONTAINER(scrolled_area), main_area);
634   gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_area, TRUE, TRUE, 0);
635
636   status_bar = gtk_statusbar_new();
637   gtk_widget_show(status_bar);
638   gtk_box_pack_start(GTK_BOX(main_vbox), status_bar, FALSE, TRUE, 0);
639   statusbar_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), "filename");
640
641   gtk_widget_show(main_vbox);
642
643   if (gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area)))
644     gtk_menu_item_activate(anti_aliasing_item);
645
646   if (gtk_math_view_get_kerning(GTK_MATH_VIEW(main_area)))
647     gtk_menu_item_activate(kerning_item);
648
649   gtk_math_view_set_font_size(GTK_MATH_VIEW(main_area), DEFAULT_FONT_SIZE);
650   gtk_menu_item_activate(font_size_item);
651 }
652
653 GtkWidget*
654 get_main_menu()
655 {
656   GtkItemFactory* item_factory;
657   GtkAccelGroup* accel_group;
658   GtkWidget* menu_item;
659
660   gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
661
662   accel_group = gtk_accel_group_new();
663
664   item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
665
666   gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, NULL);
667
668   gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
669
670   menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Kerning");
671   kerning_item = GTK_MENU_ITEM(menu_item);
672
673   menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Anti Aliasing");
674   anti_aliasing_item = GTK_MENU_ITEM(menu_item);
675
676   /* !!!BEWARE!!! the default font size must be kept aligned with the definition
677    * in defs.h
678    */
679   menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Default Font Size/14pt");
680   font_size_item = GTK_MENU_ITEM(menu_item);
681
682   return gtk_item_factory_get_widget(item_factory, "<main>");
683 }
684