2 * Copyright (C) 2000, Luca Padovani <luca.padovani@cs.unibo.it>.
4 * This file is part of HelmPot, a minimal browser for HELM.
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.
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.
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.
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>
32 # include <sys/types.h>
33 # include <sys/stat.h>
38 #include <gdk/gdkkeysyms.h>
40 #include "gtkmathview.h"
43 #define XLINK_NS_URI "http://www.w3.org/1999/xlink"
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};
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};
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;
68 PRIVATE GdkCursor* normal_cursor;
69 PRIVATE GdkCursor* link_cursor;
70 PRIVATE GdkCursor* pot_cursor;
72 PRIVATE gboolean loading = FALSE;
73 PRIVATE guint statusbar_context;
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*);
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 },
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>" },
113 { "/_Help" , NULL, NULL, 0, "<LastBranch>" },
114 { "/Help/About...", NULL, help_about, 0, NULL }
118 quick_message(const gchar* msg)
122 GtkWidget* okay_button;
124 /* Create the widgets */
126 dialog = gtk_dialog_new();
127 label = gtk_label_new (msg);
128 okay_button = gtk_button_new_with_label("OK");
130 gtk_widget_set_usize(dialog, 300, 100);
132 /* Ensure that the dialog box is destroyed when the user clicks ok. */
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),
139 /* Add the label, and show everything we've added to the dialog. */
141 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
142 gtk_widget_show_all (dialog);
146 load_error_msg(const gchar* name)
148 gchar* msg = g_strdup_printf("Could not load\n`%s'", name);
154 save_error_msg(const gchar* name)
156 gchar* msg = g_strdup_printf("Could not save\n`%s'", name);
162 GUI_init(gint* argc, gchar*** argv, gchar* title, guint width, guint height, GtkFunction f, guint32 timeout)
167 GdkColor fg = { 0, 65535, 65535, 65535 };
168 GdkColor bg = { 0, 0, 0, 0 };
170 gtk_init(argc, argv);
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);
178 gtk_widget_show(window);
180 gtk_timeout_add(timeout, f, NULL);
182 normal_cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
183 link_cursor = gdk_cursor_new(GDK_HAND2);
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);
200 GUI_load_document(const gchar* name)
202 GtkMathView* math_view;
203 GtkMathViewClass* klass;
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);
210 math_view = GTK_MATH_VIEW(main_area);
211 g_return_val_if_fail(math_view != NULL, -1);
213 klass = (GtkMathViewClass*) gtk_type_class(gtk_math_view_get_type());
214 g_return_val_if_fail(klass != NULL, -1);
216 gdk_window_set_cursor(main_area->window, pot_cursor);
218 res = gtk_math_view_load(math_view, name);
219 gdk_window_set_cursor(main_area->window, normal_cursor);
223 load_error_msg(name);
227 gtk_statusbar_pop(GTK_STATUSBAR(status_bar), statusbar_context);
228 if (strlen(name) > 40) name += strlen(name) - 40;
229 gtk_statusbar_push(GTK_STATUSBAR(status_bar), statusbar_context, name);
231 if (file_name != NULL) g_free(file_name);
232 file_name = g_strdup(name);
238 GUI_unload_document()
240 GtkMathView* math_view;
242 g_return_if_fail(main_area != NULL);
243 g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
245 math_view = GTK_MATH_VIEW(main_area);
247 gtk_math_view_unload(math_view);
257 options_font_size(GtkWidget* widget, guint size)
259 GtkMathView* math_view;
261 g_return_if_fail(main_area != NULL);
262 g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
264 math_view = GTK_MATH_VIEW(main_area);
266 gtk_math_view_set_font_size(math_view, size);
270 options_font_manager(GtkWidget* widget, guint id)
272 GtkMathView* math_view;
274 g_return_if_fail(main_area != NULL);
275 g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
277 math_view = GTK_MATH_VIEW(main_area);
279 gtk_math_view_set_font_manager_type(math_view, id);
283 options_anti_aliasing(GtkWidget* widget, gpointer data)
285 gboolean aa = gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area));
286 gtk_math_view_set_anti_aliasing(GTK_MATH_VIEW(main_area), !aa);
290 options_kerning(GtkWidget* widget, gpointer data)
292 gboolean k = gtk_math_view_get_kerning(GTK_MATH_VIEW(main_area));
293 gtk_math_view_set_kerning(GTK_MATH_VIEW(main_area), !k);
297 options_verbosity(GtkWidget* widget, guint level)
299 gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), level);
303 help_about(GtkWidget* widget, gpointer data)
309 dialog = gtk_dialog_new();
310 label = gtk_label_new("\n HELM PoT \n Copyright (C) 2001 Luca Padovani \n");
311 ok = gtk_button_new_with_label("Close");
313 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
314 GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
315 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
318 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
320 gtk_widget_show_all (dialog);
324 export_filename(GtkFileSelection* selector, gpointer user_data)
327 GtkMathView* math_view;
328 gchar* selected_filename;
330 selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(user_data));
332 math_view = GTK_MATH_VIEW(main_area);
334 f = fopen(selected_filename, "wt");
336 save_error_msg(selected_filename);
337 /*g_free(selected_filename);*/
341 gtk_math_view_export_to_postscript(math_view,
342 (21 * SCALED_POINTS_PER_CM) / SCALED_POINTS_PER_PX,
343 (29 * SCALED_POINTS_PER_CM) / SCALED_POINTS_PER_PX,
344 SCALED_POINTS_PER_IN / SCALED_POINTS_PER_PX,
345 SCALED_POINTS_PER_IN / SCALED_POINTS_PER_PX,
350 /*g_free(selected_filename);*/
354 save_filename(GtkFileSelection* selector, gpointer user_data)
359 gchar* selected_filename;
361 if (file_name == NULL) return;
363 source = fopen(file_name, "rt");
364 if (source == NULL) {
365 load_error_msg(file_name);
369 selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(user_data));
370 if (selected_filename == NULL) return;
372 dest = fopen(selected_filename, "wt");
374 save_error_msg(selected_filename);
375 /*g_free(selected_filename);*/
379 /*g_free(selected_filename);*/
381 buffer = g_new(gchar, 2048);
382 while (!feof(source)) {
383 size_t n = fread(buffer, sizeof(gchar), 2048, source);
384 fwrite(buffer, sizeof(gchar), n, dest);
393 file_dialog(const gchar* title, GtkSignalFunc f)
397 g_return_if_fail(title != NULL);
398 g_return_if_fail(f != NULL);
400 fs = gtk_file_selection_new(title);
402 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
405 /* Ensure that the dialog box is destroyed when the user clicks a button. */
407 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
408 "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
411 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
412 "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
415 /* Display that dialog */
417 gtk_widget_show (fs);
421 export_to_ps(GtkWidget* widget)
423 file_dialog("Export to PostScript", export_filename);
425 static GList* items = NULL;
431 items = g_list_append(items, "A4");
432 items = g_list_append(items, "A5");
435 dialog = gtk_dialog_new();
436 tmp = gtk_label_new("Paper size");
437 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), tmp);
438 tmp = gtk_combo_new();
439 gtk_combo_set_popdown_strings(GTK_COMBO(tmp), items);
440 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), tmp);
442 tmp = gtk_check_button_new_with_label("Disable Colors");
443 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), tmp);
446 tmp = gtk_button_new_with_label("OK");
447 gtk_signal_connect_object(GTK_OBJECT(tmp), "clicked", GTK_SIGNAL_FUNC(export_to_ps_get_file_name), dialog);
448 gtk_signal_connect_object(GTK_OBJECT(tmp), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), dialog);
449 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), tmp);
450 tmp = gtk_button_new_with_label("Cancel");
451 gtk_signal_connect_object(GTK_OBJECT(tmp), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), dialog);
452 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), tmp);
454 gtk_widget_show_all(dialog);
459 save_as(GtkWidget* widget)
461 file_dialog("Save As...", save_filename);
465 element_changed(GtkMathView* math_view, mDOMNodeRef node)
467 g_return_if_fail(math_view != NULL);
468 g_return_if_fail(main_area != NULL);
469 g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
470 /* fprintf(stderr, "node changed: %p %s\n", node, (node != NULL) ? mdom_node_get_name(node) : "-"); */
473 while (node != NULL && !mdom_node_has_attribute_ns(node, DOM_CONST_STRING("href"), XLINK_NS_URI))
474 node = mdom_node_get_parent(node);
477 gdk_window_set_cursor(main_area->window, link_cursor);
479 gdk_window_set_cursor(main_area->window, normal_cursor);
484 selection_changed(GtkMathView* math_view, mDOMNodeRef node)
486 g_return_if_fail(math_view != NULL);
487 g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
489 while (node != NULL && !mdom_node_has_attribute(node, DOM_CONST_STRING("xref")))
490 node = mdom_node_get_parent(node);
492 gtk_math_view_set_selection(math_view, node);
496 jump(mDOMConstStringRef href)
499 g_return_if_fail(href != NULL);
502 if (pid == -1) exit(-1);
504 gchar* open_url = g_strdup_printf("openURL(%s,cic)", href);
511 fd = open("/dev/null", O_RDWR);
515 execlp("netscape", "netscape", "-noraise", "-remote", open_url, NULL);
516 perror("exec failed:");
522 clicked(GtkMathView* math_view, gpointer user_data)
524 mDOMNodeRef p = gtk_math_view_get_element(math_view);
525 while (p != NULL && !mdom_node_has_attribute_ns(p, DOM_CONST_STRING("href"), XLINK_NS_URI))
526 p = mdom_node_get_parent(p);
529 mDOMStringRef href = mdom_node_get_attribute_ns(p, DOM_CONST_STRING("href"), XLINK_NS_URI);
530 g_assert(href != NULL);
532 jump(C_CONST_STRING(href));
533 mdom_string_free(href);
534 } else if (gtk_math_view_get_action(math_view) != NULL)
535 gtk_math_view_action_toggle(math_view);
541 GtkWidget* main_vbox;
544 main_vbox = gtk_vbox_new(FALSE, 1);
545 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
546 gtk_container_add(GTK_CONTAINER(window), main_vbox);
547 gtk_widget_show(main_vbox);
549 menu_bar = get_main_menu();
550 gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, TRUE, 0);
551 gtk_widget_show(menu_bar);
553 main_area = gtk_math_view_new(NULL, NULL);
554 gtk_widget_show(main_area);
556 gtk_signal_connect_object (GTK_OBJECT (main_area),
557 "element_changed", GTK_SIGNAL_FUNC (element_changed),
558 (gpointer) main_area);
560 gtk_signal_connect_object (GTK_OBJECT (main_area),
561 "selection_changed", GTK_SIGNAL_FUNC (selection_changed),
562 (gpointer) main_area);
564 gtk_signal_connect_object (GTK_OBJECT (main_area),
565 "clicked", GTK_SIGNAL_FUNC(clicked),
566 (gpointer) main_area);
568 scrolled_area = gtk_scrolled_window_new(NULL, NULL);
569 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
570 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
571 gtk_widget_show(scrolled_area);
572 gtk_container_add(GTK_CONTAINER(scrolled_area), main_area);
573 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_area, TRUE, TRUE, 0);
575 status_bar = gtk_statusbar_new();
576 gtk_widget_show(status_bar);
577 gtk_box_pack_start(GTK_BOX(main_vbox), status_bar, FALSE, TRUE, 0);
578 statusbar_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), "filename");
580 gtk_widget_show(main_vbox);
582 if (gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area)))
583 gtk_menu_item_activate(anti_aliasing_item);
585 if (gtk_math_view_get_kerning(GTK_MATH_VIEW(main_area)))
586 gtk_menu_item_activate(kerning_item);
588 gtk_math_view_set_font_size(GTK_MATH_VIEW(main_area), DEFAULT_FONT_SIZE);
589 gtk_menu_item_activate(font_size_item);
595 GtkItemFactory* item_factory;
596 GtkAccelGroup* accel_group;
597 GtkWidget* menu_item;
599 gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
601 accel_group = gtk_accel_group_new();
603 item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
605 gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, NULL);
607 gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
609 menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Kerning");
610 kerning_item = GTK_MENU_ITEM(menu_item);
612 menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Anti Aliasing");
613 anti_aliasing_item = GTK_MENU_ITEM(menu_item);
615 /* !!!BEWARE!!! the default font size must be kept aligned with the definition
618 menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Default Font Size/14pt");
619 font_size_item = GTK_MENU_ITEM(menu_item);
621 return gtk_item_factory_get_widget(item_factory, "<main>");