]> matita.cs.unibo.it Git - helm.git/blob - helm/DEVEL/mathml_editor/test/guiGTK.c
Bug fixed: wrong exception was raised (instead of returning false)
[helm.git] / helm / DEVEL / mathml_editor / test / guiGTK.c
1 /* This file is part of EdiTeX, an editor of mathematical
2  * expressions based on TeX syntax.
3  * 
4  * Copyright (C) 2002-2003 Luca Padovani <lpadovan@cs.unibo.it>,
5  *                    2003 Paolo Marinelli <pmarinel@cs.unibo.it>.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * For more information, please visit the project's home page
22  * http://helm.cs.unibo.it/editex/
23  * or send an email to <lpadovan@cs.unibo.it>
24  */
25
26 #include <config.h>
27 #include <stdio.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30
31 #include "guiGTK.h"
32
33 #define XLINK_NS_URI "http://www.w3.org/1999/xlink"
34
35 static GtkWidget* window;
36 static GtkWidget* main_area;
37 static GtkWidget* scrolled_area;
38
39 static gpointer context = NULL;
40 static gchar* doc_name = NULL;
41 static GdomeElement* first_selected = NULL;
42 static GdomeElement* root_selected = NULL;
43
44 static void create_widget_set(gpointer);
45 static GtkWidget* get_main_menu(void);
46 static void file_open(GtkWidget*, gpointer);
47 static void file_re_open(GtkWidget*, gpointer);
48 static void file_close(GtkWidget*, gpointer);
49 static void file_output_tex(GtkWidget*, gpointer);
50 static void options_set_font_size(GtkWidget*, gpointer);
51 static void options_change_font_size(GtkWidget*, gboolean);
52 static void options_verbosity(GtkWidget*, guint);
53 static void edit_delete_selection(GtkWidget*, gpointer);
54 static void edit_select_parent(GtkWidget*, gpointer);
55 static void edit_reset_selection(GtkWidget*, gpointer);
56 static void edit_reset(GtkWidget*, gpointer);
57 static void edit_insert(GtkWidget*, gpointer);
58 static void help_about(GtkWidget*, gpointer);
59
60 static GtkItemFactoryEntry menu_items[] = {
61   { "/_File",                          NULL,         NULL,          0, "<Branch>" },
62   { "/File/_Open...",                  "<control>O", file_open,     0, NULL },
63   { "/File/_Reopen",                   NULL,         file_re_open,  0, NULL },
64   { "/File/_Close",                    "<control>W", file_close,    0, NULL },
65   { "/File/Output _TeX",               NULL,         file_output_tex, 0, NULL },
66   { "/File/sep1",                      NULL,         NULL,          0, "<Separator>" },
67   { "/File/_Quit",                     "<control>Q", gtk_main_quit, 0, NULL },
68
69   { "/_Edit",                          NULL, NULL,                  0,  "<Branch>" },
70   { "/Edit/Reset Selection",           NULL, edit_reset_selection,  0, NULL },
71   { "/Edit/Delete Selection",          NULL, edit_delete_selection, 0, NULL },
72   { "/Edit/Select Parent",             NULL, edit_select_parent,    0, NULL },
73   { "/Edit/sep1",                      NULL,         NULL,          0, "<Separator>" },
74   { "/Edit/_Reset",                    NULL, edit_reset,            0, NULL },
75   { "/Edit/Insert...",                 "<control>I", edit_insert,   0, NULL },
76
77   { "/_Options",                       NULL, NULL,                  0,  "<Branch>" },
78   { "/Options/Default _Font Size",     NULL, NULL,                  0,  "<Branch>" },
79   { "/Options/Default Font Size/Set...", NULL, options_set_font_size, 0,  NULL },
80   { "/Options/Default Font Size/sep1", NULL, NULL,                  0,  "<Separator>" },
81   { "/Options/Default Font Size/Larger", NULL, options_change_font_size, TRUE, NULL },
82   { "/Options/Default Font Size/Smaller", NULL, options_change_font_size, FALSE, NULL },
83   { "/Options/Verbosity",              NULL, NULL,                  0,  "<Branch>" },
84   { "/Options/Verbosity/_Errors",      NULL, options_verbosity,     0,  "<RadioItem>" },
85   { "/Options/Verbosity/_Warnings",    NULL, options_verbosity,     1,  "/Options/Verbosity/Errors" },
86   { "/Options/Verbosity/_Info",        NULL, options_verbosity,     2,  "/Options/Verbosity/Errors" },
87   { "/Options/Verbosity/_Debug",       NULL, options_verbosity,     3,  "/Options/Verbosity/Errors" },
88
89   { "/_Help" ,        NULL,         NULL,          0, "<LastBranch>" },
90   { "/Help/About...", NULL,         help_about,    0, NULL }
91 };
92
93 static void
94 quick_message(const char* msg)
95 {
96   GtkWidget* dialog;
97   GtkWidget* label;
98   GtkWidget* okay_button;
99      
100   /* Create the widgets */
101      
102   dialog = gtk_dialog_new();
103   label = gtk_label_new (msg);
104   okay_button = gtk_button_new_with_label("OK");
105
106   gtk_widget_set_usize(dialog, 300, 100);
107
108   /* Ensure that the dialog box is destroyed when the user clicks ok. */
109      
110   gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
111                              GTK_SIGNAL_FUNC (gtk_widget_destroy), dialog);
112   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
113                      okay_button);
114   
115   /* Add the label, and show everything we've added to the dialog. */
116   
117   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
118   gtk_widget_show_all (dialog);
119 }
120
121 static void
122 load_error_msg(const char* name)
123 {
124   char* msg = g_strdup_printf("Could not load\n`%s'", name);
125   quick_message(msg);
126   g_free(msg);
127 }
128
129 static guint edit_timeout_id;
130 extern void edit_timeout(gpointer);
131
132 void
133 GUI_init(int* argc, char*** argv, char* title, guint width, guint height, gpointer c)
134 {
135   gtk_init(argc, argv);
136
137   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
138   gtk_window_set_title(GTK_WINDOW(window), title);
139   gtk_window_set_default_size(GTK_WINDOW(window), width, height);
140   gtk_signal_connect(GTK_OBJECT(window), "delete_event", (GtkSignalFunc) gtk_main_quit, NULL);
141   create_widget_set(context);
142
143   gtk_widget_show(window);
144
145   context = c;
146   /*edit_timeout_id = gtk_timeout_add(50, edit_timeout, context);*/
147 }
148
149 void
150 GUI_uninit()
151 {
152   GdomeException exc = 0;
153
154   if (first_selected != NULL)
155     {
156       gdome_el_unref(first_selected, &exc);
157       g_assert(exc == 0);
158       first_selected = NULL;
159     }
160
161   if (root_selected != NULL)
162     {
163       gdome_el_unref(root_selected, &exc);
164       g_assert(exc == 0);
165       root_selected = NULL;
166     }
167
168   context = NULL;
169 }
170
171 int
172 GUI_load_document(GdomeDocument* doc)
173 {
174   GtkMathView* math_view;
175
176   g_return_val_if_fail(doc != NULL, -1);
177   g_return_val_if_fail(main_area != NULL, -1);
178   g_return_val_if_fail(GTK_IS_MATH_VIEW(main_area), -1);
179
180   math_view = GTK_MATH_VIEW(main_area);
181
182   if (!gtk_math_view_load_document(math_view, doc)) return -1;
183
184   return 0;
185 }
186
187 void
188 GUI_freeze()
189 {
190   gtk_math_view_freeze(GTK_MATH_VIEW(main_area));
191 }
192
193 void
194 GUI_thaw()
195 {
196   gtk_math_view_thaw(GTK_MATH_VIEW(main_area));
197 }
198
199 void
200 GUI_unload_document()
201 {
202   GtkMathView* math_view;
203
204   g_return_if_fail(main_area != NULL);
205   g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
206
207   math_view = GTK_MATH_VIEW(main_area);
208
209   gtk_math_view_unload(math_view);
210
211   if (doc_name != NULL) g_free(doc_name);
212   doc_name = NULL;
213 }
214
215 void
216 GUI_run()
217 {
218   gtk_main();
219 }
220
221 #if 0
222 void
223 GUI_set_font_manager(FontManagerId id)
224 {
225   gboolean t1;
226   GtkMathView* math_view;
227
228   g_return_if_fail(id != FONT_MANAGER_UNKNOWN);
229   g_return_if_fail(main_area != NULL);
230   g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
231
232   t1 = id == FONT_MANAGER_T1;
233
234   math_view = GTK_MATH_VIEW(main_area);
235
236   gtk_math_view_freeze(math_view);
237
238   if (id != gtk_math_view_get_font_manager_type(math_view))
239     gtk_math_view_set_font_manager_type(math_view, id);
240
241   gtk_widget_set_sensitive(anti_aliasing(math_view, GTK_CHECK_MENU_ITEM(anti_aliasing_item)->active);
242       gtk_math_view_set_transparency(math_view, GTK_CHECK_MENU_ITEM(transparency_item)->active);
243     }
244
245   gtk_math_view_thaw(math_view);
246 }
247 #endif
248
249 static void
250 store_filename(GtkFileSelection* selector, GtkWidget* user_data)
251 {
252   gchar* selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(user_data));
253   if (selected_filename != NULL)
254     GUI_load_document(selected_filename);
255 }
256
257 static void
258 file_close(GtkWidget* widget, gpointer data)
259 {
260   GUI_unload_document();
261 }
262
263 static void
264 file_re_open(GtkWidget* widget, gpointer data)
265 {
266   if (doc_name != NULL) {
267     GUI_load_document(doc_name);
268   }
269 }
270
271 static void
272 file_open(GtkWidget* widget, gpointer data)
273 {
274   GtkWidget* fs = gtk_file_selection_new("Open File");
275
276   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
277                       "clicked", GTK_SIGNAL_FUNC (store_filename), (gpointer) fs);
278                              
279   /* Ensure that the dialog box is destroyed when the user clicks a button. */
280      
281   gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
282                              "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
283                              (gpointer) fs);
284
285   gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
286                              "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
287                              (gpointer) fs);
288      
289   /* Display that dialog */
290      
291   gtk_widget_show (fs);
292 }
293
294 static void
295 file_output_tex(GtkWidget* widget, gpointer data)
296 {
297   g_assert(context != NULL);
298   edit_output_tex(context);
299 }
300
301 #if 0
302 static void
303 options_font_manager(GtkWidget* widget, FontManagerId id)
304 {
305   g_return_if_fail(id != FONT_MANAGER_UNKNOWN);
306   GUI_set_font_manager(id);
307 }
308 #endif
309
310 static void
311 options_verbosity(GtkWidget* widget, guint level)
312 {
313   gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), level);
314 }
315
316 static void
317 edit_delete_selection(GtkWidget* widget, gpointer data)
318 {
319   if (root_selected != NULL)
320     {
321       GdomeException exc;
322       gtk_math_view_freeze(GTK_MATH_VIEW(main_area));
323       printf("about to remove element %p\n", root_selected);
324       delete_element(root_selected);
325       gdome_el_unref(root_selected, &exc);
326       g_assert(exc == 0);
327       root_selected = NULL;
328       gtk_math_view_thaw(GTK_MATH_VIEW(main_area));
329     }
330 }
331
332 static void
333 edit_select_parent(GtkWidget* widget, gpointer data)
334 {
335   if (root_selected != NULL)
336     {
337       GdomeException exc = 0;
338       GdomeElement* parent = gdome_n_parentNode(root_selected, &exc);
339       g_assert(exc == 0);
340       gdome_el_unref(root_selected, &exc);
341       g_assert(exc == 0);
342       root_selected = parent;
343       /* gtk_math_view_set_selection(GTK_MATH_VIEW(main_area), root_selected); */
344     }
345 }
346
347 static void
348 edit_reset_selection(GtkWidget* widget, gpointer data)
349 {
350   if (root_selected != NULL)
351     {
352       GdomeException exc = 0;
353       /* gtk_math_view_reset_selection(GTK_MATH_VIEW(main_area), root_selected); */
354       gdome_el_unref(root_selected, &exc);
355       g_assert(exc == 0);
356       root_selected = NULL;
357     }
358 }
359
360 static void
361 edit_reset(GtkWidget* widget, gpointer data)
362 {
363   g_assert(context != NULL);
364   edit_reset_tex(context);
365 }
366
367 static void
368 insert_tex(GtkWidget* widget, GtkEntry* entry)
369 {
370   gchar* text;
371   g_return_if_fail(entry != NULL);
372
373   text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
374   edit_push_string(context, text);
375   g_free(text);
376 }
377
378 static void
379 edit_insert(GtkWidget* widget, gpointer data)
380 {
381   GtkWidget* dialog;
382   GtkWidget* entry;
383   GtkWidget* ok;
384   GtkWidget* cancel;
385
386   dialog = gtk_dialog_new();
387   entry = gtk_entry_new();
388   ok = gtk_button_new_with_label("OK");
389   cancel = gtk_button_new_with_label("Cancel");
390
391   gtk_signal_connect (GTK_OBJECT (ok), "clicked",
392                       GTK_SIGNAL_FUNC (insert_tex), (gpointer) entry);
393
394   gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
395                              GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
396
397   gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
398                              GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
399
400   gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
401                              GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
402
403   gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 5);
404
405   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), entry);
406   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), ok);
407   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), cancel);
408
409   gtk_widget_show_all (dialog);
410 }
411
412 static void
413 help_about(GtkWidget* widget, gpointer data)
414 {
415   GtkWidget* dialog;
416   GtkWidget* label;
417   GtkWidget* ok;
418
419   dialog = gtk_dialog_new();
420   label = gtk_label_new("\n    MathML Editor    \n    Copyright (C) 2003 Luca Padovani    \n");
421   ok = gtk_button_new_with_label("Close");
422
423   gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
424                              GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
425   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
426                      ok);
427
428   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
429
430   gtk_widget_show_all (dialog);
431 }
432
433 static void
434 change_default_font_size(GtkWidget* widget, GtkSpinButton* spin)
435 {
436   g_return_if_fail(spin != NULL);
437   gtk_math_view_set_font_size( GTK_MATH_VIEW(main_area), gtk_spin_button_get_value_as_int(spin));
438 }
439
440 static void
441 options_change_font_size(GtkWidget* widget, gboolean larger)
442 {
443   gfloat size = gtk_math_view_get_font_size (GTK_MATH_VIEW(main_area));
444   if (larger) size = size / 0.71;
445   else size = size * 0.71;
446   if (size < 1) size = 1;
447   gtk_math_view_set_font_size (GTK_MATH_VIEW(main_area), (gint) size + 0.5);
448 }
449
450 static void
451 options_set_font_size(GtkWidget* widget, gpointer data)
452 {
453   GtkWidget* dialog;
454   GtkWidget* label;
455   GtkWidget* ok;
456   GtkWidget* cancel;
457   GtkWidget* spin;
458   GtkObject* adj;
459
460   dialog = gtk_dialog_new();
461   label = gtk_label_new("Default font size:");
462   ok = gtk_button_new_with_label("OK");
463   cancel = gtk_button_new_with_label("Cancel");
464
465   adj = gtk_adjustment_new (gtk_math_view_get_font_size (GTK_MATH_VIEW(main_area)), 1, 200, 1, 1, 1);
466   spin = gtk_spin_button_new (GTK_ADJUSTMENT(adj), 1, 0);
467   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE);
468
469   gtk_signal_connect (GTK_OBJECT (ok), "clicked",
470                       GTK_SIGNAL_FUNC (change_default_font_size), (gpointer) spin);
471
472   gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
473                              GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
474
475   gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
476                              GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
477
478   gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
479                              GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
480
481   gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 5);
482
483   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), ok);
484   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), cancel);
485   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
486   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), spin);
487
488   gtk_widget_show_all (dialog);
489 }
490
491 static void
492 select_begin(GtkMathView* math_view, GdomeElement* first, gint state)
493 {
494   GdomeException exc = 0;
495
496   g_return_if_fail(math_view != NULL);
497   g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
498   g_return_if_fail(first != NULL);
499
500   gtk_math_view_freeze(math_view);
501
502   if (root_selected != NULL)
503     {
504       gtk_math_view_unselect(math_view, root_selected);
505       gdome_el_unref(root_selected, &exc);
506       g_assert(exc == 0);
507     }
508
509   root_selected = first_selected = find_element_with_ref(first);
510
511   if (root_selected != NULL)
512     {
513       gtk_math_view_select(math_view, root_selected);
514       gdome_el_ref(root_selected, &exc);
515       g_assert(exc == 0);
516     }
517
518   gtk_math_view_thaw(math_view);
519 }
520
521 static void
522 select_over(GtkMathView* math_view, GdomeElement* elem, gint state)
523 {
524   GdomeElement* new_selected = NULL;
525   GdomeException exc = 0;
526
527   g_return_if_fail(math_view != NULL);
528   g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
529   g_return_if_fail(elem != NULL);
530
531   if (first_selected == NULL || elem == NULL)
532     new_selected = NULL;
533   else
534     new_selected = find_common_ancestor_with_ref(first_selected, elem);
535
536   if (new_selected != root_selected)
537     {
538       gtk_math_view_freeze(math_view);
539       if (root_selected != NULL)
540         {
541           gtk_math_view_unselect(math_view, root_selected);
542           gdome_el_unref(root_selected, &exc);
543           g_assert(exc == 0);
544         }
545       root_selected = new_selected;
546       if (root_selected != NULL)
547         gtk_math_view_select(math_view, root_selected);
548       gtk_math_view_thaw(math_view);
549     }
550   else if (new_selected != NULL)
551     {
552       gdome_el_unref(new_selected, &exc);
553       g_assert(exc == 0);
554     }
555
556 }
557
558 static gboolean
559 key_press_event(gpointer c,
560                 GdkEventKey* event,
561                 GtkWidget* widget)
562 {
563   g_return_val_if_fail(widget != NULL, FALSE);
564   g_return_val_if_fail(event != NULL, FALSE);
565   g_return_val_if_fail(context != NULL, FALSE);
566
567   if (event->type != GDK_KEY_PRESS) return FALSE;
568
569   switch (event->keyval)
570     {
571     case GDK_BackSpace:
572       edit_drop(context, event->state & GDK_MOD1_MASK, event->state & GDK_CONTROL_MASK);
573       break;
574     case GDK_Tab:
575       edit_complete(context);
576       break;
577     default:
578       if ((event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) == 0 && event->keyval < 0x80)
579         edit_push_char(context, event->keyval);
580       return FALSE;
581     }
582
583   return TRUE;
584 }
585
586 static void
587 create_widget_set(gpointer context)
588 {
589   GtkWidget* main_vbox;
590   GtkWidget* menu_bar;
591
592   main_vbox = gtk_vbox_new(FALSE, 1);
593   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
594   gtk_container_add(GTK_CONTAINER(window), main_vbox);
595   gtk_widget_show(main_vbox);
596
597   menu_bar = get_main_menu();
598   gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, TRUE, 0);
599   gtk_widget_show(menu_bar);
600
601   main_area = gtk_math_view_new(NULL, NULL);
602   gtk_widget_show(main_area);
603
604   //gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), 3);
605
606   gtk_signal_connect_object (GTK_OBJECT (main_area),
607                              "select_begin", GTK_SIGNAL_FUNC (select_begin),
608                              (gpointer) main_area);
609
610   gtk_signal_connect_object (GTK_OBJECT (main_area),
611                              "select_over", GTK_SIGNAL_FUNC (select_over),
612                              (gpointer) main_area);
613
614   gtk_signal_connect_object (GTK_OBJECT(window),
615                              "key_press_event", GTK_SIGNAL_FUNC(key_press_event),
616                              context);
617
618   gtk_widget_add_events(GTK_WIDGET(main_area), GDK_KEY_PRESS_MASK);
619
620   scrolled_area = gtk_scrolled_window_new(NULL, NULL);
621   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
622                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
623
624   gtk_widget_show(scrolled_area);
625   gtk_container_add(GTK_CONTAINER(scrolled_area), main_area);
626   gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_area, TRUE, TRUE, 0);
627
628   gtk_widget_show(main_vbox);
629 }
630
631 GtkWidget*
632 get_main_menu()
633 {
634   GtkItemFactory* item_factory;
635   GtkAccelGroup* accel_group;
636   GtkWidget* menu_item;
637
638   gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
639
640   accel_group = gtk_accel_group_new();
641
642   item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
643
644   gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, NULL);
645
646   gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
647
648   return gtk_item_factory_get_widget(item_factory, "<main>");
649 }