--- /dev/null
+/*
+ * Copyright (C) 2000, Luca Padovani <luca.padovani@cs.unibo.it>.
+ *
+ * This file is part of HelmPot, a minimal browser for HELM.
+ *
+ * HelmPot is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * HelmPot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HelmPot; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * For details, see the HelmPot World-Wide-Web page,
+ * http://cs.unibo.it/helm/helmview, or send a mail to
+ * <luca.padovani@cs.unibo.it>
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#if HAVE_UNISTD_H
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <unistd.h>
+#endif
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gtkmathview.h"
+#include "guiGTK.h"
+
+#define XLINK_NS_URI "http://www.w3.org/1999/xlink"
+
+#define pot_width 16
+#define pot_height 16
+PRIVATE unsigned char pot_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x07,
+ 0x00, 0x00, 0xe6, 0x2f, 0x34, 0x5f, 0xdc, 0x5f, 0xf8, 0x3f, 0xf8, 0x3f,
+ 0xf0, 0x1f, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00};
+
+#define pot_mask_width 16
+#define pot_mask_height 16
+static unsigned char pot_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0xe0, 0x0f, 0xe0, 0x0f,
+ 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0x7f,
+ 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x1f, 0x00, 0x00};
+
+PRIVATE GtkWidget* window;
+PRIVATE GtkWidget* main_area;
+PRIVATE GtkWidget* scrolled_area;
+PRIVATE GtkWidget* status_bar;
+PRIVATE GtkMenuItem* kerning_item;
+PRIVATE GtkMenuItem* anti_aliasing_item;
+PRIVATE GtkMenuItem* font_size_item;
+PRIVATE gchar* file_name = NULL;
+
+PRIVATE GdkCursor* pot;
+
+PRIVATE guint statusbar_context;
+
+PRIVATE void create_widget_set(void);
+PRIVATE GtkWidget* get_main_menu(void);
+PRIVATE void options_font_size(GtkWidget*, guint);
+PRIVATE void options_font_manager(GtkWidget*, guint);
+PRIVATE void options_verbosity(GtkWidget*, guint);
+PRIVATE void options_kerning(GtkWidget*, gpointer);
+PRIVATE void options_anti_aliasing(GtkWidget*, gpointer);
+PRIVATE void help_about(GtkWidget*, gpointer);
+PRIVATE void save_as(GtkWidget*);
+PRIVATE void export_to_ps(GtkWidget*);
+
+PRIVATE GtkItemFactoryEntry menu_items[] = {
+ { "/_File", NULL, NULL, 0, "<Branch>" },
+ { "/File/Save _As...", NULL, save_as, 0, NULL },
+ { "/File/_Export to PostScript...", NULL, export_to_ps, 0, NULL },
+ { "/File/sep1", NULL, NULL, 0, "<Separator>" },
+ { "/File/_Quit", "<control>Q", gtk_main_quit, 0, NULL },
+
+ { "/_Options", NULL, NULL, 0, "<Branch>" },
+ { "/Options/Default _Font Size", NULL, NULL, 0, "<Branch>" },
+ { "/Options/Default Font Size/8pt", NULL, options_font_size, 8, "<RadioItem>" },
+ { "/Options/Default Font Size/10pt", NULL, options_font_size, 10, "/Options/Default Font Size/8pt" },
+ { "/Options/Default Font Size/12pt", NULL, options_font_size, 12, "/Options/Default Font Size/8pt" },
+ { "/Options/Default Font Size/14pt", NULL, options_font_size, 14, "/Options/Default Font Size/8pt" },
+ { "/Options/Default Font Size/18pt", NULL, options_font_size, 18, "/Options/Default Font Size/8pt" },
+ { "/Options/Default Font Size/24pt", NULL, options_font_size, 24, "/Options/Default Font Size/8pt" },
+ { "/Options/Font Manager", NULL, NULL, 0, "<Branch>" },
+ { "/Options/Font Manager/_GTK", NULL, options_font_manager, 0, "<RadioItem>" },
+ { "/Options/Font Manager/_Type 1", NULL, options_font_manager, 1, "/Options/Font Manager/GTK" },
+ { "/Options/Verbosity", NULL, NULL, 0, "<Branch>" },
+ { "/Options/Verbosity/_Errors", NULL, options_verbosity, 0, "<RadioItem>" },
+ { "/Options/Verbosity/_Warnings", NULL, options_verbosity, 1, "/Options/Verbosity/Errors" },
+ { "/Options/Verbosity/_Info", NULL, options_verbosity, 2, "/Options/Verbosity/Errors" },
+ { "/Options/Verbosity/_Debug", NULL, options_verbosity, 3, "/Options/Verbosity/Errors" },
+ { "/Options/sep1", NULL, NULL, 0, "<Separator>" },
+ { "/Options/_Kerning", NULL, options_kerning, 0, "<ToggleItem>" },
+ { "/Options/_Anti Aliasing", NULL, options_anti_aliasing, 0, "<ToggleItem>" },
+
+ { "/_Help" , NULL, NULL, 0, "<LastBranch>" },
+ { "/Help/About...", NULL, help_about, 0, NULL }
+};
+
+PRIVATE void
+quick_message(const gchar* msg)
+{
+ GtkWidget* dialog;
+ GtkWidget* label;
+ GtkWidget* okay_button;
+
+ /* Create the widgets */
+
+ dialog = gtk_dialog_new();
+ label = gtk_label_new (msg);
+ okay_button = gtk_button_new_with_label("OK");
+
+ gtk_widget_set_usize(dialog, 300, 100);
+
+ /* Ensure that the dialog box is destroyed when the user clicks ok. */
+
+ gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT(dialog));
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
+ okay_button);
+
+ /* Add the label, and show everything we've added to the dialog. */
+
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
+ gtk_widget_show_all (dialog);
+}
+
+PRIVATE void
+load_error_msg(const gchar* name)
+{
+ gchar* msg = g_strdup_printf("Could not load\n`%s'", name);
+ quick_message(msg);
+ g_free(msg);
+}
+
+PRIVATE void
+save_error_msg(const gchar* name)
+{
+ gchar* msg = g_strdup_printf("Could not save\n`%s'", name);
+ quick_message(msg);
+ g_free(msg);
+}
+
+void
+GUI_init(gint* argc, gchar*** argv, gchar* title, guint width, guint height, GtkFunction f, guint32 timeout)
+{
+ GdkPixmap* source;
+ GdkPixmap* mask;
+
+ GdkColor fg = { 0, 65535, 65535, 65535 };
+ GdkColor bg = { 0, 0, 0, 0 };
+
+ gtk_init(argc, argv);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(window), title);
+ gtk_window_set_default_size(GTK_WINDOW(window), width, height);
+ gtk_signal_connect(GTK_OBJECT(window), "delete_event", (GtkSignalFunc) gtk_main_quit, NULL);
+ create_widget_set();
+
+ gtk_widget_show(window);
+
+ gtk_timeout_add(timeout, f, NULL);
+
+ source = gdk_bitmap_create_from_data (NULL, pot_bits,
+ pot_width, pot_height);
+ mask = gdk_bitmap_create_from_data (NULL, pot_mask_bits,
+ pot_mask_width, pot_mask_height);
+ pot = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, 8, 8);
+ gdk_pixmap_unref (source);
+ gdk_pixmap_unref (mask);
+}
+
+void
+GUI_uninit()
+{
+}
+
+int
+GUI_load_document(const gchar* name)
+{
+ GtkMathView* math_view;
+ GtkMathViewClass* klass;
+
+ g_return_val_if_fail(name != NULL, -1);
+ g_return_val_if_fail(main_area != NULL, -1);
+ g_return_val_if_fail(GTK_IS_MATH_VIEW(main_area), -1);
+
+ math_view = GTK_MATH_VIEW(main_area);
+ g_return_val_if_fail(math_view != NULL, -1);
+
+ klass = (GtkMathViewClass*) gtk_type_class(gtk_math_view_get_type());
+ g_return_val_if_fail(klass != NULL, -1);
+
+ gdk_window_set_cursor (main_area->window, pot);
+
+ if (!gtk_math_view_load(math_view, name)) {
+ load_error_msg(name);
+ return -1;
+ }
+
+ gtk_statusbar_pop(GTK_STATUSBAR(status_bar), statusbar_context);
+ if (strlen(name) > 40) name += strlen(name) - 40;
+ gtk_statusbar_push(GTK_STATUSBAR(status_bar), statusbar_context, name);
+
+ gdk_window_set_cursor(main_area->window, klass->normal_cursor);
+
+ if (file_name != NULL) g_free(file_name);
+ file_name = g_strdup(name);
+
+ return 0;
+}
+
+void
+GUI_unload_document()
+{
+ GtkMathView* math_view;
+
+ g_return_if_fail(main_area != NULL);
+ g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
+
+ math_view = GTK_MATH_VIEW(main_area);
+
+ gtk_math_view_unload(math_view);
+}
+
+void
+GUI_run()
+{
+ gtk_main();
+}
+
+PRIVATE void
+options_font_size(GtkWidget* widget, guint size)
+{
+ GtkMathView* math_view;
+
+ g_return_if_fail(main_area != NULL);
+ g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
+
+ math_view = GTK_MATH_VIEW(main_area);
+
+ gtk_math_view_set_font_size(math_view, size);
+}
+
+PRIVATE void
+options_font_manager(GtkWidget* widget, guint id)
+{
+ GtkMathView* math_view;
+
+ g_return_if_fail(main_area != NULL);
+ g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
+
+ math_view = GTK_MATH_VIEW(main_area);
+
+ gtk_math_view_set_font_manager_type(math_view, id);
+}
+
+PRIVATE void
+options_anti_aliasing(GtkWidget* widget, gpointer data)
+{
+ gboolean aa = gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area));
+ gtk_math_view_set_anti_aliasing(GTK_MATH_VIEW(main_area), !aa);
+}
+
+PRIVATE void
+options_kerning(GtkWidget* widget, gpointer data)
+{
+ gboolean k = gtk_math_view_get_kerning(GTK_MATH_VIEW(main_area));
+ gtk_math_view_set_kerning(GTK_MATH_VIEW(main_area), !k);
+}
+
+PRIVATE void
+options_verbosity(GtkWidget* widget, guint level)
+{
+ gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), level);
+}
+
+PRIVATE void
+help_about(GtkWidget* widget, gpointer data)
+{
+ GtkWidget* dialog;
+ GtkWidget* label;
+ GtkWidget* ok;
+
+ dialog = gtk_dialog_new();
+ label = gtk_label_new("\n HELM PoT \n Copyright (C) 2001 Luca Padovani \n");
+ ok = gtk_button_new_with_label("Close");
+
+ gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
+ ok);
+
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
+
+ gtk_widget_show_all (dialog);
+}
+
+PRIVATE void
+export_filename(GtkFileSelection* selector, gpointer user_data)
+{
+ FILE* f;
+ GtkMathView* math_view;
+ gchar* selected_filename;
+
+ selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(user_data));
+
+ math_view = GTK_MATH_VIEW(main_area);
+
+ f = fopen(selected_filename, "wt");
+ if (f == NULL) {
+ save_error_msg(selected_filename);
+ /*g_free(selected_filename);*/
+ return;
+ }
+
+ gtk_math_view_export_to_postscript(math_view,
+ (21 * SCALED_POINTS_PER_CM) / SCALED_POINTS_PER_PX,
+ (29 * SCALED_POINTS_PER_CM) / SCALED_POINTS_PER_PX,
+ SCALED_POINTS_PER_IN / SCALED_POINTS_PER_PX,
+ SCALED_POINTS_PER_IN / SCALED_POINTS_PER_PX,
+ FALSE,
+ f);
+
+ fclose(f);
+ /*g_free(selected_filename);*/
+}
+
+PRIVATE void
+save_filename(GtkFileSelection* selector, gpointer user_data)
+{
+ FILE* source;
+ FILE* dest;
+ gchar* buffer;
+ gchar* selected_filename;
+
+ if (file_name == NULL) return;
+
+ source = fopen(file_name, "rt");
+ if (source == NULL) {
+ load_error_msg(file_name);
+ return;
+ }
+
+ selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(user_data));
+ if (selected_filename == NULL) return;
+
+ dest = fopen(selected_filename, "wt");
+ if (dest == NULL) {
+ save_error_msg(selected_filename);
+ /*g_free(selected_filename);*/
+ return;
+ }
+
+ /*g_free(selected_filename);*/
+
+ buffer = g_new(gchar, 2048);
+ while (!feof(source)) {
+ size_t n = fread(buffer, sizeof(gchar), 2048, source);
+ fwrite(buffer, sizeof(gchar), n, dest);
+ }
+
+ g_free(buffer);
+ fclose(source);
+ fclose(dest);
+}
+
+PRIVATE void
+file_dialog(const gchar* title, GtkSignalFunc f)
+{
+ GtkWidget* fs;
+
+ g_return_if_fail(title != NULL);
+ g_return_if_fail(f != NULL);
+
+ fs = gtk_file_selection_new(title);
+
+ gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
+ "clicked", f, fs);
+
+ /* Ensure that the dialog box is destroyed when the user clicks a button. */
+
+ gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
+ "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ (gpointer) fs);
+
+ gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
+ "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ (gpointer) fs);
+
+ /* Display that dialog */
+
+ gtk_widget_show (fs);
+}
+
+PRIVATE void
+export_to_ps(GtkWidget* widget)
+{
+ file_dialog("Export to PostScript", export_filename);
+#if 0
+ static GList* items = NULL;
+
+ GtkWidget* dialog;
+ GtkWidget* tmp;
+
+ if (items == NULL) {
+ items = g_list_append(items, "A4");
+ items = g_list_append(items, "A5");
+ }
+
+ dialog = gtk_dialog_new();
+ tmp = gtk_label_new("Paper size");
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), tmp);
+ tmp = gtk_combo_new();
+ gtk_combo_set_popdown_strings(GTK_COMBO(tmp), items);
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), tmp);
+#if 0
+ tmp = gtk_check_button_new_with_label("Disable Colors");
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), tmp);
+#endif
+
+ tmp = gtk_button_new_with_label("OK");
+ gtk_signal_connect_object(GTK_OBJECT(tmp), "clicked", GTK_SIGNAL_FUNC(export_to_ps_get_file_name), dialog);
+ gtk_signal_connect_object(GTK_OBJECT(tmp), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), dialog);
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), tmp);
+ tmp = gtk_button_new_with_label("Cancel");
+ gtk_signal_connect_object(GTK_OBJECT(tmp), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), dialog);
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), tmp);
+
+ gtk_widget_show_all(dialog);
+#endif
+}
+
+PRIVATE void
+save_as(GtkWidget* widget)
+{
+ file_dialog("Save As...", save_filename);
+}
+
+PRIVATE void
+selection_changed(GtkMathView* math_view, mDOMNodeRef node)
+{
+ g_return_if_fail(math_view != NULL);
+ g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
+ gtk_math_view_set_selection(math_view, node);
+}
+
+PRIVATE void
+jump(GtkMathView* math_view, mDOMNodeRef node)
+{
+ mDOMStringRef href;
+
+ g_return_if_fail(node != NULL);
+ href = mdom_node_get_attribute_ns(node, DOM_CONST_STRING("href"), XLINK_NS_URI);
+
+ if (href != NULL) {
+ pid_t pid;
+
+ g_assert(main_area != NULL);
+ gdk_window_set_cursor (main_area->window, pot);
+
+ pid = fork();
+ if (pid == -1) exit(-1);
+ if (pid == 0) {
+ gchar* open_url = g_strdup_printf("openURL(%s,cic)", href);
+ gint fd;
+
+ close(0);
+ close(1);
+ close(2);
+
+ fd = open("/dev/null", O_RDWR);
+ dup(fd);
+ dup(fd);
+
+ execlp("netscape", "netscape", "-noraise", "-remote", open_url, NULL);
+ perror("exec failed:");
+ exit(-1);
+ }
+ mdom_string_free(href);
+ }
+}
+
+PRIVATE void
+create_widget_set()
+{
+ GtkWidget* main_vbox;
+ GtkWidget* menu_bar;
+
+ main_vbox = gtk_vbox_new(FALSE, 1);
+ gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
+ gtk_container_add(GTK_CONTAINER(window), main_vbox);
+ gtk_widget_show(main_vbox);
+
+ menu_bar = get_main_menu();
+ gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, TRUE, 0);
+ gtk_widget_show(menu_bar);
+
+ main_area = gtk_math_view_new(NULL, NULL);
+ gtk_widget_show(main_area);
+
+ gtk_signal_connect_object (GTK_OBJECT (main_area),
+ "selection_changed", GTK_SIGNAL_FUNC (selection_changed),
+ (gpointer) main_area);
+
+ gtk_signal_connect_object (GTK_OBJECT (main_area), "jump", GTK_SIGNAL_FUNC(jump), NULL);
+
+ scrolled_area = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+ gtk_widget_show(scrolled_area);
+ gtk_container_add(GTK_CONTAINER(scrolled_area), main_area);
+ gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_area, TRUE, TRUE, 0);
+
+ status_bar = gtk_statusbar_new();
+ gtk_widget_show(status_bar);
+ gtk_box_pack_start(GTK_BOX(main_vbox), status_bar, FALSE, TRUE, 0);
+ statusbar_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), "filename");
+
+ gtk_widget_show(main_vbox);
+
+ if (gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area)))
+ gtk_menu_item_activate(anti_aliasing_item);
+
+ if (gtk_math_view_get_kerning(GTK_MATH_VIEW(main_area)))
+ gtk_menu_item_activate(kerning_item);
+
+ gtk_math_view_set_font_size(GTK_MATH_VIEW(main_area), DEFAULT_FONT_SIZE);
+ gtk_menu_item_activate(font_size_item);
+}
+
+GtkWidget*
+get_main_menu()
+{
+ GtkItemFactory* item_factory;
+ GtkAccelGroup* accel_group;
+ GtkWidget* menu_item;
+
+ gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
+
+ accel_group = gtk_accel_group_new();
+
+ item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
+
+ gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, NULL);
+
+ gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
+
+ menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Kerning");
+ kerning_item = GTK_MENU_ITEM(menu_item);
+
+ menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Anti Aliasing");
+ anti_aliasing_item = GTK_MENU_ITEM(menu_item);
+
+ /* !!!BEWARE!!! the default font size must be kept aligned with the definition
+ * in defs.h
+ */
+ menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Default Font Size/14pt");
+ font_size_item = GTK_MENU_ITEM(menu_item);
+
+ return gtk_item_factory_get_widget(item_factory, "<main>");
+}