1 /* Copyright (C) 2000-2007, Luca Padovani <padovani@sti.uniurb.it>.
2  *
3  * This file is part of GtkMathView, a flexible, high-quality rendering
4  * engine for MathML documents.
5  *
6  * GtkMathView is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published
8  * by the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GtkMathView is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <config.h>
21 
22 #include "defs.h"
23 #include <stdio.h>
24 #include <string.h>
25 #include <gtk/gtk.h>
26 #include <gdk/gdkkeysyms.h>
27 
28 #include <gdome.h>
29 #include "gtkmathview_gmetadom.h"
30 #include "guiGTK.h"
31 
32 extern GdomeDOMString* find_hyperlink(GdomeElement*, const char*, const char*);
33 extern GdomeElement* find_xref_element(GdomeElement*);
34 extern GdomeElement* find_common_ancestor(GdomeElement*, GdomeElement*);
35 extern GdomeElement* find_self_or_ancestor(GdomeElement*, const char*, const char*);
36 extern GdomeElement* find_action_element(GdomeElement*);
37 extern void action_toggle(GdomeElement*);
38 extern void delete_element(GdomeElement*);
39 
40 static GtkWidget* window;
41 static GtkWidget* main_area;
42 static GtkWidget* scrolled_area;
43 static GtkWidget* status_bar;
44 static GdkCursor* normal_cursor;
45 static GdkCursor* link_cursor;
46 static gboolean   semantic_selection = FALSE;
47 
48 static gchar* doc_name = NULL;
49 static GdomeElement* first_selected = NULL;
50 static GdomeElement* root_selected = NULL;
51 static GtkMathViewDefaultCursorDecorator* cursor = NULL;
52 
53 static guint statusbar_context;
54 
55 static void create_widget_set(void);
56 static GtkWidget* get_main_menu(void);
57 static void file_open(GtkWidget*, gpointer);
58 static void file_re_open(GtkWidget*, gpointer);
59 static void file_close(GtkWidget*, gpointer);
60 static void options_set_font_size(GtkWidget*, gpointer);
61 static void options_change_font_size(GtkWidget*, gboolean);
62 static void options_verbosity(GtkWidget*, guint);
63 static void options_transparent(GtkWidget*, gpointer);
64 static void options_anti_aliased(GtkWidget*, gpointer);
65 static void options_selection(GtkWidget*, gboolean);
66 static void selection_delete(GtkWidget*, gpointer);
67 static void selection_parent(GtkWidget*, gpointer);
68 static void selection_reset(GtkWidget*, gpointer);
69 static void help_about(GtkWidget*, gpointer);
70 
71 static GtkItemFactoryEntry menu_items[] = {
72   { "/_File",                          NULL,         NULL,          0, "<Branch>", 0 },
73   { "/File/_Open...",                  "<control>O", file_open,     0, NULL, 0 },
74   { "/File/_Reopen",                   NULL,         file_re_open,  0, NULL, 0 },
75   { "/File/_Close",                    "<control>W", file_close,    0, NULL, 0 },
76   { "/File/sep1",                      NULL,         NULL,          0, "<Separator>", 0 },
77   { "/File/_Quit",                     "<control>Q", gtk_main_quit, 0, NULL, 0 },
78 
79   { "/_Selection",                     NULL, NULL,                  0,  "<Branch>", 0 },
80   { "/Selection/Reset",                NULL, selection_reset,       0, NULL, 0 },
81   { "/Selection/Delete",               NULL, selection_delete,      0, NULL, 0 },
82   { "/Selection/Select Parent",        NULL, selection_parent,      0, NULL, 0 },
83 
84   { "/_Options",                       NULL, NULL,                  0,  "<Branch>", 0 },
85   { "/Options/Default _Font Size",     NULL, NULL,                  0,  "<Branch>", 0 },
86   { "/Options/Default Font Size/Set...", NULL, options_set_font_size, 0,  NULL, 0 },
87   { "/Options/Default Font Size/sep1", NULL, NULL,                  0,  "<Separator>", 0 },
88   { "/Options/Default Font Size/Larger", "<control>2", options_change_font_size, TRUE, NULL, 0 },
89   { "/Options/Default Font Size/Smaller", "<control>1", options_change_font_size, FALSE, NULL, 0 },
90   { "/Options/Verbosity",              NULL, NULL,                  0,  "<Branch>", 0 },
91   { "/Options/Verbosity/_Errors",      NULL, options_verbosity,     0,  "<RadioItem>", 0 },
92   { "/Options/Verbosity/_Warnings",    NULL, options_verbosity,     1,  "/Options/Verbosity/Errors", 0 },
93   { "/Options/Verbosity/_Info",        NULL, options_verbosity,     2,  "/Options/Verbosity/Errors", 0 },
94   { "/Options/Verbosity/_Debug",       NULL, options_verbosity,     3,  "/Options/Verbosity/Errors", 0 },
95   { "/Options/Type 1",                 NULL, NULL,                  0,  "<Branch>", 0 },
96   { "/Options/Type 1/_Transparent",    NULL, options_transparent,   TRUE,  "<CheckItem>", 0 },
97   { "/Options/Type 1/_Anti Aliased",   NULL, options_anti_aliased,  0,  "<CheckItem>", 0 },
98   { "/Options/sep1",                   NULL, NULL,                  0,  "<Separator>", 0 },
99   { "/Options/Selection/Structure",    NULL, options_selection,     0,  "<RadioItem>", 0 },
100   { "/Options/Selection/Semantics",    NULL, options_selection,     1,  "/Options/Selection/Structure", 0 },
101 
102   { "/_Help" ,        NULL,         NULL,          0, "<Branch>", 0 },
103   { "/Help/About...", NULL,         help_about,    0, NULL, 0 }
104 };
105 
106 #if 0
107 static void
108 quick_message(const char* msg)
109 {
110   GtkWidget* dialog;
111   GtkWidget* label;
112   GtkWidget* okay_button;
113 
114   /* Create the widgets */
115 
116   dialog = gtk_dialog_new();
117   label = gtk_label_new (msg);
118   okay_button = gtk_button_new_with_label("OK");
119 
120   gtk_widget_set_usize(dialog, 300, 100);
121 
122   /* Ensure that the dialog box is destroyed when the user clicks ok. */
123 
124   /* g_signal_connect_object(GTK_OBJECT (okay_button),
125 		  "clicked",
126 		  GTK_SIGNAL_FUNC(gtk_widget_destroy),
127 		  dialog,0);
128   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
129 		     okay_button);
130 		     */
131 
132   g_signal_connect_swapped(GTK_OBJECT(okay_button),
133 		  "clicked",
134 		  G_CALLBACK(gtk_widget_destroy),
135 		  dialog);
136 
137   /* Add the label, and show everything we've added to the dialog. */
138 
139   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
140   gtk_widget_show_all (dialog);
141 }
142 
143 static void
144 load_error_msg(const char* name)
145 {
146   char* msg = g_strdup_printf("Could not load\n`%s'", name);
147   quick_message(msg);
148   g_free(msg);
149 }
150 #endif
151 
152 void
GUI_init(int * argc,const char *** argv,char * title,guint width,guint height,gint logLevel)153 GUI_init(int* argc, const char*** argv, char* title, guint width, guint height, gint logLevel)
154 {
155   gtk_init(argc, argv);
156 
157   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
158   gtk_window_set_title(GTK_WINDOW(window), title);
159   gtk_window_set_default_size(GTK_WINDOW(window), width, height);
160 
161   g_signal_connect(GTK_OBJECT(window),
162 		  "delete_event",
163 		  (GtkSignalFunc) gtk_main_quit, NULL);
164 
165   create_widget_set();
166   g_assert(main_area != NULL);
167   g_assert(GTK_IS_MATH_VIEW(main_area));
168   gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), logLevel);
169 
170   gtk_widget_show(window);
171 
172   normal_cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
173   link_cursor = gdk_cursor_new(GDK_HAND2);
174 }
175 
176 void
GUI_uninit()177 GUI_uninit()
178 {
179   /*gtk_widget_unref(GTK_WIDGET(window));*/
180 }
181 
182 int
GUI_load_document(const char * name)183 GUI_load_document(const char* name)
184 {
185   GtkMathView* math_view;
186 
187   g_return_val_if_fail(name != NULL, -1);
188   g_return_val_if_fail(main_area != NULL, -1);
189   g_return_val_if_fail(GTK_IS_MATH_VIEW(main_area), -1);
190 
191   math_view = GTK_MATH_VIEW(main_area);
192 
193   gtk_math_view_load_uri(math_view, name);
194 
195   if (name != doc_name) {
196     if (doc_name != NULL) g_free(doc_name);
197     doc_name = g_strdup(name);
198   }
199 
200   gtk_statusbar_pop(GTK_STATUSBAR(status_bar), statusbar_context);
201   if (strlen(name) > 40) name += strlen(name) - 40;
202   gtk_statusbar_push(GTK_STATUSBAR(status_bar), statusbar_context, name);
203 
204   return 0;
205 }
206 
207 void
GUI_unload_document()208 GUI_unload_document()
209 {
210   GtkMathView* math_view;
211 
212   g_return_if_fail(main_area != NULL);
213   g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
214 
215   math_view = GTK_MATH_VIEW(main_area);
216 
217   gtk_math_view_unload(math_view);
218 
219   if (doc_name != NULL) g_free(doc_name);
220   doc_name = NULL;
221 
222   gtk_statusbar_pop(GTK_STATUSBAR(status_bar), statusbar_context);
223   gtk_statusbar_push(GTK_STATUSBAR(status_bar), statusbar_context, "");
224 }
225 
226 void
GUI_run()227 GUI_run()
228 {
229   gtk_main();
230 }
231 
232 static void
store_filename(GtkFileSelection * selector,GtkWidget * user_data)233 store_filename(GtkFileSelection* selector, GtkWidget* user_data)
234 {
235   const gchar* selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(user_data));
236   if (selected_filename != NULL)
237     GUI_load_document(selected_filename);
238 }
239 
240 static void
file_close(GtkWidget * widget,gpointer data)241 file_close(GtkWidget* widget, gpointer data)
242 {
243   GUI_unload_document();
244 }
245 
246 static void
file_re_open(GtkWidget * widget,gpointer data)247 file_re_open(GtkWidget* widget, gpointer data)
248 {
249   if (doc_name != NULL) {
250     GUI_load_document(doc_name);
251   }
252 }
253 
254 static void
file_open(GtkWidget * widget,gpointer data)255 file_open(GtkWidget* widget, gpointer data)
256 {
257   GtkWidget* fs = gtk_file_selection_new("Open File");
258 
259   g_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
260 		      "clicked",
261 		      GTK_SIGNAL_FUNC(store_filename), (gpointer) fs);
262 
263   /* Ensure that the dialog box is destroyed when the user clicks a button. */
264 
265   g_signal_connect_swapped(GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
266 			     "clicked",
267 			     G_CALLBACK(gtk_widget_destroy),
268 			     (gpointer) fs);
269 
270   /* gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
271 			     "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
272 			     (gpointer) fs);
273 			     */
274 
275   g_signal_connect_swapped(GTK_OBJECT(GTK_FILE_SELECTION(fs)->cancel_button),
276 		  "clicked",
277 		  G_CALLBACK(gtk_widget_destroy),
278 		  (gpointer) fs);
279 
280   /* Display that dialog */
281 
282   gtk_widget_show (fs);
283 }
284 
285 static void
options_verbosity(GtkWidget * widget,guint level)286 options_verbosity(GtkWidget* widget, guint level)
287 {
288   gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), level);
289 }
290 
291 static void
options_transparent(GtkWidget * widget,gpointer data)292 options_transparent(GtkWidget* widget, gpointer data)
293 {
294   GtkMathView* math_view = GTK_MATH_VIEW(main_area);
295   g_return_if_fail(math_view != NULL);
296   gtk_math_view_set_t1_opaque_mode(math_view, !gtk_math_view_get_t1_opaque_mode(math_view));
297 }
298 
299 static void
options_anti_aliased(GtkWidget * widget,gpointer data)300 options_anti_aliased(GtkWidget* widget, gpointer data)
301 {
302   GtkMathView* math_view = GTK_MATH_VIEW(main_area);
303   g_return_if_fail(math_view != NULL);
304   gtk_math_view_set_t1_anti_aliased_mode(math_view, !gtk_math_view_get_t1_anti_aliased_mode(math_view));
305 }
306 
307 static void
options_selection(GtkWidget * widget,gboolean semantic)308 options_selection(GtkWidget* widget, gboolean semantic)
309 {
310   semantic_selection = semantic;
311   selection_reset(widget, NULL);
312 }
313 
314 static void
selection_delete(GtkWidget * widget,gpointer data)315 selection_delete(GtkWidget* widget, gpointer data)
316 {
317   if (root_selected != NULL)
318     {
319       GdomeException exc;
320       gtk_math_view_freeze(GTK_MATH_VIEW(main_area));
321       delete_element(root_selected);
322       gdome_el_unref(root_selected, &exc);
323       g_assert(exc == 0);
324       root_selected = NULL;
325       gtk_math_view_thaw(GTK_MATH_VIEW(main_area));
326     }
327 }
328 
329 static void
selection_parent(GtkWidget * widget,gpointer data)330 selection_parent(GtkWidget* widget, gpointer data)
331 {
332   if (root_selected != NULL)
333     {
334       GdomeException exc = 0;
335       GdomeElement* parent = (GdomeElement*) gdome_n_parentNode((GdomeNode*) root_selected, &exc);
336       g_assert(exc == 0);
337       gdome_el_unref(root_selected, &exc);
338       g_assert(exc == 0);
339       root_selected = parent;
340       gtk_math_view_select(GTK_MATH_VIEW(main_area), root_selected);
341     }
342 }
343 
344 static void
selection_reset(GtkWidget * widget,gpointer data)345 selection_reset(GtkWidget* widget, gpointer data)
346 {
347   if (root_selected != NULL)
348     {
349       GdomeException exc = 0;
350       gtk_math_view_unselect(GTK_MATH_VIEW(main_area), root_selected);
351       gdome_el_unref(root_selected, &exc);
352       g_assert(exc == 0);
353       root_selected = NULL;
354     }
355 }
356 
357 static void
help_about(GtkWidget * widget,gpointer data)358 help_about(GtkWidget* widget, gpointer data)
359 {
360   GtkWidget* dialog;
361   GtkWidget* label;
362   GtkWidget* ok;
363 
364   dialog = gtk_dialog_new();
365   label = gtk_label_new("\n    MathML Viewer    \n    Copyright (C) 2000-2004 Luca Padovani    \n");
366   ok = gtk_button_new_with_label("Close");
367 
368   /* gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
369 			     GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog); */
370 
371   g_signal_connect_swapped(GTK_OBJECT(ok),
372 		  "clicked",
373 		  G_CALLBACK(gtk_widget_destroy),
374 		  (gpointer) dialog);
375 
376   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
377 		     ok);
378 
379   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
380 
381   gtk_widget_show_all (dialog);
382 }
383 
384 static void
change_default_font_size(GtkSpinButton * widget,GtkSpinButton * spin)385 change_default_font_size(GtkSpinButton* widget, GtkSpinButton* spin)
386 {
387   g_return_if_fail(spin != NULL);
388   gtk_math_view_set_font_size( GTK_MATH_VIEW(main_area), gtk_spin_button_get_value_as_int(spin));
389 }
390 
391 static void
options_change_font_size(GtkWidget * widget,gboolean larger)392 options_change_font_size(GtkWidget* widget, gboolean larger)
393 {
394   gfloat size = gtk_math_view_get_font_size (GTK_MATH_VIEW(main_area));
395   if (larger) size = size / 0.71;
396   else size = size * 0.71;
397   if (size < 1) size = 1;
398   gtk_math_view_set_font_size (GTK_MATH_VIEW(main_area), (gint) size + 0.5);
399 }
400 
401 static void
options_set_font_size(GtkWidget * widget,gpointer data)402 options_set_font_size(GtkWidget* widget, gpointer data)
403 {
404   GtkWidget* dialog;
405   GtkWidget* label;
406   GtkWidget* ok;
407   GtkWidget* cancel;
408   GtkWidget* spin;
409   GtkObject* adj;
410 
411   dialog = gtk_dialog_new();
412   label = gtk_label_new("Default font size:");
413   ok = gtk_button_new_with_label("OK");
414   cancel = gtk_button_new_with_label("Cancel");
415 
416   adj = gtk_adjustment_new (gtk_math_view_get_font_size (GTK_MATH_VIEW(main_area)), 1, 200, 1, 1, 1);
417   spin = gtk_spin_button_new (GTK_ADJUSTMENT(adj), 1, 0);
418   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE);
419 
420   /* gtk_signal_connect (GTK_OBJECT (ok), "clicked",
421 		      GTK_SIGNAL_FUNC (change_default_font_size), (gpointer) spin); */
422 
423   g_signal_connect(GTK_OBJECT(ok),
424 		  "clicked",
425 		  G_CALLBACK(change_default_font_size),
426 		  (gpointer) spin);
427 
428   /* gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
429 			     GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog); */
430 
431   g_signal_connect_swapped(GTK_OBJECT (ok),
432 		  "clicked",
433 		  G_CALLBACK(gtk_widget_destroy),
434 		  (gpointer) dialog);
435 
436 
437   /* gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
438 			     GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);*/
439 
440   /* gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
441 			     GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog); */
442 
443   g_signal_connect_swapped(GTK_OBJECT (cancel),
444 		  "clicked",
445 		  G_CALLBACK(gtk_widget_destroy),
446 		  (gpointer) dialog);
447 
448 
449   gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 5);
450 
451   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), ok);
452   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), cancel);
453   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
454   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), spin);
455 
456   gtk_widget_show_all (dialog);
457 }
458 
459 #if defined(HAVE_GMETADOM)
460 static void
element_over(GtkMathView * math_view,const GtkMathViewModelEvent * event)461 element_over(GtkMathView* math_view, const GtkMathViewModelEvent* event)
462 {
463   GdomeElement* action = NULL;
464   GdomeDOMString* link = NULL;
465 
466   g_return_if_fail(math_view != NULL);
467   g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
468   g_return_if_fail(event != NULL);
469 
470   link = find_hyperlink(event->id, XLINK_NS_URI, "href");
471   if (link != NULL)
472     gdk_window_set_cursor(GTK_WIDGET(math_view)->window, link_cursor);
473   else
474     gdk_window_set_cursor(GTK_WIDGET(math_view)->window, normal_cursor);
475 
476   if (link != NULL)
477     gdome_str_unref(link);
478 
479   action = find_action_element(event->id);
480 #if 0
481   if (action != NULL)
482     {
483       GdomeException exc = 0;
484       gtk_math_view_decor_default_cursor_set(cursor, TRUE, action, TRUE, -1, FALSE);
485       gdome_el_unref(action, &exc);
486       g_assert(exc == 0);
487     }
488 #endif
489 }
490 
491 static void
select_begin(GtkMathView * math_view,const GtkMathViewModelEvent * event)492 select_begin(GtkMathView* math_view, const GtkMathViewModelEvent* event)
493 {
494   g_return_if_fail(math_view != NULL);
495   g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
496   g_return_if_fail(event != NULL);
497 
498   if (event->id != NULL)
499     {
500       GdomeException exc = 0;
501 
502       gtk_math_view_freeze(math_view);
503 
504       if (root_selected != NULL)
505 	{
506 	  gtk_math_view_unselect(math_view, root_selected);
507 	  gdome_el_unref(root_selected, &exc);
508 	  g_assert(exc == 0);
509 	  root_selected = NULL;
510 	}
511 
512       if (semantic_selection)
513 	{
514 	  GdomeElement* new_elem = find_xref_element(event->id);
515 	  if (new_elem != NULL)
516             {
517 	      gdome_el_ref(new_elem, &exc);
518 	      g_assert(exc == 0);
519 	    }
520           first_selected = root_selected = new_elem;
521 	}
522       else
523 	{
524 	  gdome_el_ref(event->id, &exc);
525 	  g_assert(exc == 0);
526 	  gdome_el_ref(event->id, &exc);
527 	  g_assert(exc == 0);
528           first_selected = root_selected = event->id;
529 	}
530 
531       if (root_selected != NULL)
532 	gtk_math_view_select(math_view, root_selected);
533 
534       gtk_math_view_thaw(math_view);
535     }
536 }
537 
538 static void
select_over(GtkMathView * math_view,const GtkMathViewModelEvent * event)539 select_over(GtkMathView* math_view, const GtkMathViewModelEvent* event)
540 {
541   g_return_if_fail(math_view != NULL);
542   g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
543   g_return_if_fail(event != NULL);
544 
545   if (first_selected != NULL && event->id != NULL)
546     {
547       GdomeException exc = 0;
548 
549       gtk_math_view_freeze(math_view);
550 
551       if (root_selected != NULL)
552 	{
553 	  gtk_math_view_unselect(math_view, root_selected);
554 	  gdome_el_unref(root_selected, &exc);
555 	  g_assert(exc == 0);
556 	  root_selected = NULL;
557 	}
558 
559       if (semantic_selection)
560 	{
561 	  GdomeElement* new_root = find_common_ancestor(first_selected, event->id);
562 	  if (new_root != NULL)
563 	    {
564 	      root_selected = find_xref_element(new_root);
565 	      gdome_el_unref(new_root, &exc);
566 	      g_assert(exc == 0);
567 	    }
568 	  else
569 	    root_selected = NULL;
570 	}
571       else
572         root_selected = find_common_ancestor(first_selected, event->id);
573 
574       while (root_selected != NULL && !gtk_math_view_select(math_view, root_selected))
575 	{
576 	  GdomeElement* new_root = (GdomeElement*) gdome_el_parentNode(root_selected, &exc);
577 	  g_assert(exc == 0);
578 	  gdome_el_unref(root_selected, &exc);
579 	  g_assert(exc == 0);
580 	  root_selected = new_root;
581 	}
582 
583       gtk_math_view_thaw(math_view);
584     }
585 }
586 
587 static void
select_end(GtkMathView * math_view,const GtkMathViewModelEvent * event)588 select_end(GtkMathView* math_view, const GtkMathViewModelEvent* event)
589 {
590   g_return_if_fail(math_view != NULL);
591   g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
592   g_return_if_fail(event != NULL);
593 
594   if (first_selected != NULL)
595     {
596       GdomeException exc = 0;
597       gdome_el_unref(first_selected, &exc);
598       g_assert(exc == 0);
599       first_selected = NULL;
600     }
601 }
602 
603 static void
select_abort(GtkMathView * math_view)604 select_abort(GtkMathView* math_view)
605 {
606   GdomeException exc = 0;
607 
608   g_return_if_fail(math_view != NULL);
609   g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
610 
611   if (first_selected != NULL)
612     {
613       gdome_el_unref(first_selected, &exc);
614       g_assert(exc == 0);
615       first_selected = NULL;
616     }
617 
618   if (root_selected != NULL)
619     {
620       gtk_math_view_freeze(math_view);
621       gtk_math_view_unselect(math_view, root_selected);
622       gtk_math_view_thaw(math_view);
623       gdome_el_unref(root_selected, &exc);
624       g_assert(exc == 0);
625       root_selected = NULL;
626     }
627 }
628 
629 static void
click(GtkMathView * math_view,const GtkMathViewModelEvent * event)630 click(GtkMathView* math_view, const GtkMathViewModelEvent* event)
631 {
632   gboolean res;
633   gint index;
634   GdomeElement* elem;
635   GdomeException exc;
636   GdomeDOMString* name;
637   GdomeDOMString* ns_uri;
638   GdomeElement* p;
639 
640   gint w, h;
641   gtk_math_view_get_size(math_view, &w, &h);
642   printf("click signal %d %d\n", w, h);
643 
644   g_return_if_fail(math_view != NULL);
645   g_return_if_fail(event != NULL);
646 
647 #if 1
648   index = -1;
649   if (gtk_math_view_get_char_at(math_view, event->x, event->y, &elem, &index, NULL, NULL))
650     gtk_math_view_decor_default_cursor_set(cursor, TRUE, event->id, TRUE, index, TRUE);
651   else
652     gtk_math_view_decor_default_cursor_set(cursor, FALSE, NULL, FALSE, -1, FALSE);
653 #endif
654 
655   if (event->id != NULL)
656     {
657       name = gdome_el_nodeName(event->id, &exc);
658       g_assert(exc == 0);
659       printf("node name: %s\n", name->str);
660     }
661 
662   if (event->id != NULL)
663     {
664       GdomeElement* action;
665       GdomeDOMString* href = find_hyperlink(event->id, XLINK_NS_URI, "href");
666       if (href != NULL)
667 	{
668  	  printf("hyperlink %s\n", href->str);
669 	  gdome_str_unref(href);
670 	}
671 
672       action = find_action_element(event->id);
673       printf("action? %p\n", action);
674       if (action != NULL)
675 	{
676 	  gtk_math_view_freeze(math_view);
677 	  action_toggle(action);
678 	  gtk_math_view_thaw(math_view);
679 	  gdome_el_unref(action, &exc);
680 	  g_assert(exc == 0);
681 	  return;
682 	}
683     }
684 
685   if (root_selected != NULL)
686     {
687       gtk_math_view_freeze(math_view);
688       gtk_math_view_unselect(math_view, root_selected);
689       gtk_math_view_thaw(math_view);
690       gdome_el_unref(root_selected, &exc);
691       g_assert(exc == 0);
692       root_selected = NULL;
693     }
694 }
695 
696 #endif // HAVE_GMETADOM
697 
698 static gboolean
cursor_blink(GtkMathViewDefaultCursorDecorator * cursor)699 cursor_blink(GtkMathViewDefaultCursorDecorator* cursor)
700 {
701   gboolean enabled;
702   GdomeElement* focus;
703   gboolean draw_focus;
704   gint index;
705   gboolean char_index;
706   g_return_val_if_fail(cursor != NULL, FALSE);
707 
708   gtk_math_view_decor_default_cursor_get(cursor, &enabled, &focus, &draw_focus, &index, &char_index);
709   gtk_math_view_decor_default_cursor_set(cursor, !enabled, focus, draw_focus, index, char_index);
710 
711   return TRUE;
712 }
713 
714 static void
create_widget_set()715 create_widget_set()
716 {
717   GtkWidget* main_vbox;
718   GtkWidget* menu_bar;
719 
720   main_vbox = gtk_vbox_new(FALSE, 1);
721   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
722   gtk_container_add(GTK_CONTAINER(window), main_vbox);
723   gtk_widget_show(main_vbox);
724 
725   menu_bar = get_main_menu();
726   gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, TRUE, 0);
727   gtk_widget_show(menu_bar);
728 
729   scrolled_area = gtk_scrolled_window_new(NULL, NULL);
730   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
731 				 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
732   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_area),
733 				      GTK_SHADOW_IN);
734   gtk_widget_show(scrolled_area);
735   gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_area, TRUE, TRUE, 0);
736 
737   main_area = gtk_math_view_new(NULL, NULL);
738   gtk_widget_show(main_area);
739   gtk_container_add(GTK_CONTAINER(scrolled_area), main_area);
740   gtk_widget_set_double_buffered(main_area, FALSE);
741 
742   g_signal_connect(GTK_OBJECT (main_area),
743 		   "select_begin",
744 		   G_CALLBACK(select_begin),
745 		   (gpointer) main_area);
746 
747   g_signal_connect(GTK_OBJECT (main_area),
748 		   "select_over",
749 		   G_CALLBACK(select_over),
750 		   (gpointer) main_area);
751 
752   g_signal_connect(GTK_OBJECT (main_area),
753 		   "select_end",
754 		   G_CALLBACK(select_end),
755 		   (gpointer) main_area);
756 
757   g_signal_connect(GTK_OBJECT (main_area),
758 		   "select_abort",
759 		   G_CALLBACK(select_abort),
760 		   (gpointer) main_area);
761 
762   g_signal_connect(GTK_OBJECT (main_area),
763 		   "element_over",
764 		   G_CALLBACK(element_over),
765 		   (gpointer) main_area);
766 
767   g_signal_connect(GTK_OBJECT (main_area),
768 		   "click",
769 		   G_CALLBACK(click),
770 		   (gpointer) main_area);
771 
772   cursor = gtk_math_view_decor_default_cursor_new(GTK_MATH_VIEW(main_area));
773   g_timeout_add(500, cursor_blink, cursor);
774 
775   status_bar = gtk_statusbar_new();
776   gtk_widget_show(status_bar);
777   gtk_box_pack_start(GTK_BOX(main_vbox), status_bar, FALSE, TRUE, 0);
778   statusbar_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), "filename");
779 
780   gtk_widget_show(main_vbox);
781 }
782 
783 GtkWidget*
get_main_menu()784 get_main_menu()
785 {
786   GtkItemFactory* item_factory;
787   GtkAccelGroup* accel_group;
788 
789   gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
790 
791   accel_group = gtk_accel_group_new();
792 
793   item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
794 
795   gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, NULL);
796 
797   gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
798 
799   return gtk_item_factory_get_widget(item_factory, "<main>");
800 }
801