summaryrefslogtreecommitdiff
path: root/mate-dictionary/src
diff options
context:
space:
mode:
authorStefano Karapetsas <[email protected]>2011-12-14 10:13:54 +0100
committerStefano Karapetsas <[email protected]>2011-12-14 10:13:54 +0100
commitef0467789bfc8406b57ba553e4d59f4d6c3f9be8 (patch)
tree09d541636a16cb38448fe6183289ebdc3080c1bf /mate-dictionary/src
downloadmate-utils-ef0467789bfc8406b57ba553e4d59f4d6c3f9be8.tar.bz2
mate-utils-ef0467789bfc8406b57ba553e4d59f4d6c3f9be8.tar.xz
Moved from Mate-Extra repository
Diffstat (limited to 'mate-dictionary/src')
-rw-r--r--mate-dictionary/src/Makefile.am82
-rw-r--r--mate-dictionary/src/gdict-about.c90
-rw-r--r--mate-dictionary/src/gdict-about.h30
-rw-r--r--mate-dictionary/src/gdict-aligned-window.c348
-rw-r--r--mate-dictionary/src/gdict-aligned-window.h69
-rw-r--r--mate-dictionary/src/gdict-app.c475
-rw-r--r--mate-dictionary/src/gdict-app.h72
-rw-r--r--mate-dictionary/src/gdict-applet.c1333
-rw-r--r--mate-dictionary/src/gdict-applet.h48
-rw-r--r--mate-dictionary/src/gdict-common.c201
-rw-r--r--mate-dictionary/src/gdict-common.h48
-rw-r--r--mate-dictionary/src/gdict-pref-dialog.c744
-rw-r--r--mate-dictionary/src/gdict-pref-dialog.h65
-rw-r--r--mate-dictionary/src/gdict-print.c322
-rw-r--r--mate-dictionary/src/gdict-print.h38
-rw-r--r--mate-dictionary/src/gdict-sidebar.c568
-rw-r--r--mate-dictionary/src/gdict-sidebar.h75
-rw-r--r--mate-dictionary/src/gdict-source-dialog.c759
-rw-r--r--mate-dictionary/src/gdict-source-dialog.h54
-rw-r--r--mate-dictionary/src/gdict-window.c2214
-rw-r--r--mate-dictionary/src/gdict-window.h129
-rw-r--r--mate-dictionary/src/main.c24
22 files changed, 7788 insertions, 0 deletions
diff --git a/mate-dictionary/src/Makefile.am b/mate-dictionary/src/Makefile.am
new file mode 100644
index 00000000..ddde3d26
--- /dev/null
+++ b/mate-dictionary/src/Makefile.am
@@ -0,0 +1,82 @@
+NULL =
+
+INCLUDES = \
+ -DPREFIX=\""$(prefix)"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DLIBDIR=\""$(libdir)"\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DUIDATADIR=\""$(datadir)/mate-2.0/ui"\" \
+ -DPKGDATADIR=\""$(datadir)/mate-dictionary"\" \
+ -DMATELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ $(NULL)
+
+bin_PROGRAMS = mate-dictionary
+
+if BUILD_GDICT_APPLET
+libexec_PROGRAMS = mate-dictionary-applet
+endif
+
+mate_dictionary_SOURCES = \
+ gdict-about.c \
+ gdict-about.h \
+ gdict-app.c \
+ gdict-app.h \
+ gdict-common.c \
+ gdict-common.h \
+ gdict-pref-dialog.c \
+ gdict-pref-dialog.h \
+ gdict-print.c \
+ gdict-print.h \
+ gdict-sidebar.c \
+ gdict-sidebar.h \
+ gdict-source-dialog.c \
+ gdict-source-dialog.h \
+ gdict-window.c \
+ gdict-window.h \
+ main.c \
+ $(NULL)
+mate_dictionary_CFLAGS = \
+ -I$(top_builddir)/mate-dictionary \
+ -I$(top_srcdir)/mate-dictionary \
+ $(MATE_UTILS_CFLAGS) \
+ $(NULL)
+mate_dictionary_LDADD = \
+ -lm \
+ $(top_builddir)/mate-dictionary/libgdict/libmatedict.la \
+ $(MATE_UTILS_LIBS) \
+ $(NULL)
+
+if BUILD_GDICT_APPLET
+
+mate_dictionary_applet_SOURCES = \
+ gdict-about.c \
+ gdict-about.h \
+ gdict-aligned-window.c \
+ gdict-aligned-window.h \
+ gdict-applet.c \
+ gdict-applet.h \
+ gdict-common.c \
+ gdict-common.h \
+ gdict-pref-dialog.c \
+ gdict-pref-dialog.h \
+ gdict-print.c \
+ gdict-print.h \
+ gdict-sidebar.c \
+ gdict-sidebar.h \
+ gdict-source-dialog.c \
+ gdict-source-dialog.h \
+ $(NULL)
+mate_dictionary_applet_CFLAGS = \
+ -I$(top_builddir)/mate-dictionary \
+ -I$(top_srcdir)/mate-dictionary \
+ $(MATE_UTILS_CFLAGS) \
+ $(APPLET_CFLAGS) \
+ $(NULL)
+mate_dictionary_applet_LDADD = \
+ -lm \
+ $(top_builddir)/mate-dictionary/libgdict/libmatedict.la \
+ $(MATE_UTILS_LIBS) \
+ $(APPLET_LIBS) \
+ $(NULL)
+
+endif # BUILD_GDICT_APPLET
diff --git a/mate-dictionary/src/gdict-about.c b/mate-dictionary/src/gdict-about.c
new file mode 100644
index 00000000..dc74b560
--- /dev/null
+++ b/mate-dictionary/src/gdict-about.c
@@ -0,0 +1,90 @@
+/* gdict-about.c - GtkAboutDialog wrapper
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "gdict-about.h"
+
+void
+gdict_show_about_dialog (GtkWidget *parent)
+{
+ const gchar *authors[] = {
+ "Mike Hughes <[email protected]>",
+ "Spiros Papadimitriou <[email protected]>",
+ "Bradford Hovinen <[email protected]>",
+ "Vincent Noel <[email protected]>",
+ "Emmanuele Bassi <[email protected]>",
+ NULL
+ };
+
+ const gchar *documenters[] = {
+ "Sun MATE Documentation Team <[email protected]>",
+ "John Fleck <[email protected]>",
+ "Emmanuele Bassi <[email protected]>",
+ NULL
+ };
+
+ const gchar *translator_credits = _("translator-credits");
+ const gchar *copyright = "Copyright \xc2\xa9 2005-2006 Emmanuele Bassi";
+ const gchar *comments = _("Look up words in dictionaries");
+
+ const gchar *license =
+ "This program 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.\n"
+ "\n"
+ "This program 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.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License "
+ "along with this program; if not, write to the Free Software "
+ "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA "
+ "02111-1307, USA.\n";
+
+ g_return_if_fail (GTK_IS_WIDGET (parent));
+
+ gtk_show_about_dialog (GTK_IS_WINDOW (parent) ? GTK_WINDOW (parent) : NULL,
+ "name", _("Dictionary"),
+ "version", VERSION,
+ "copyright", copyright,
+ "comments", comments,
+ "authors", authors,
+ "documenters", documenters,
+ "translator-credits", translator_credits,
+ "logo-icon-name", "accessories-dictionary",
+ "license", license,
+ "wrap-license", TRUE,
+ "screen", gtk_widget_get_screen (parent),
+ NULL);
+}
diff --git a/mate-dictionary/src/gdict-about.h b/mate-dictionary/src/gdict-about.h
new file mode 100644
index 00000000..2e6467cf
--- /dev/null
+++ b/mate-dictionary/src/gdict-about.h
@@ -0,0 +1,30 @@
+/* gdict-about.h - GtkAboutDialog wrapper
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GDICT_ABOUT_H__
+#define __GDICT_ABOUT_H__
+
+#include <gtk/gtk.h>
+
+void gdict_show_about_dialog (GtkWidget *parent);
+
+#endif /* __GDICT_ABOUT_H__ */
diff --git a/mate-dictionary/src/gdict-aligned-window.c b/mate-dictionary/src/gdict-aligned-window.c
new file mode 100644
index 00000000..c7ddf83e
--- /dev/null
+++ b/mate-dictionary/src/gdict-aligned-window.c
@@ -0,0 +1,348 @@
+/* gdict-aligned-window.c - Popup window aligned to a widget
+ *
+ * Copyright (c) 2005-2006 Emmanuele Bassi <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Ported from Seth Nickell's Python class:
+ * Copyright (c) 2003 Seth Nickell
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "gdict-aligned-window.h"
+
+#define GDICT_ALIGNED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GDICT_TYPE_ALIGNED_WINDOW, GdictAlignedWindowPrivate))
+
+struct _GdictAlignedWindowPrivate
+{
+ GtkWidget *align_widget;
+
+ guint motion_id;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_ALIGN_WIDGET
+};
+
+static void gdict_aligned_window_finalize (GObject *object);
+static void gdict_aligned_window_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gdict_aligned_window_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void gdict_aligned_window_realize (GtkWidget *widget);
+static void gdict_aligned_window_show (GtkWidget *widget);
+
+static gboolean gdict_aligned_window_motion_notify_cb (GtkWidget *widget,
+ GdkEventMotion *event,
+ GdictAlignedWindow *aligned_window);
+
+
+G_DEFINE_TYPE (GdictAlignedWindow, gdict_aligned_window, GTK_TYPE_WINDOW);
+
+
+
+static void
+gdict_aligned_window_class_init (GdictAlignedWindowClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gobject_class->set_property = gdict_aligned_window_set_property;
+ gobject_class->get_property = gdict_aligned_window_get_property;
+ gobject_class->finalize = gdict_aligned_window_finalize;
+
+ widget_class->realize = gdict_aligned_window_realize;
+ widget_class->show = gdict_aligned_window_show;
+
+ g_object_class_install_property (gobject_class, PROP_ALIGN_WIDGET,
+ g_param_spec_object ("align-widget",
+ "Align Widget",
+ "The widget the window should align to",
+ GTK_TYPE_WIDGET,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (klass, sizeof (GdictAlignedWindowPrivate));
+}
+
+static void
+gdict_aligned_window_init (GdictAlignedWindow *aligned_window)
+{
+ GdictAlignedWindowPrivate *priv = GDICT_ALIGNED_WINDOW_GET_PRIVATE (aligned_window);
+ GtkWindow *window = GTK_WINDOW (aligned_window);
+
+ aligned_window->priv = priv;
+
+ priv->align_widget = NULL;
+ priv->motion_id = 0;
+
+ /* set window properties */
+#if 0
+ gtk_window_set_modal (window, TRUE);
+#endif
+ gtk_window_set_decorated (window, FALSE);
+ gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_DOCK);
+}
+
+static void
+gdict_aligned_window_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdictAlignedWindow *aligned_window = GDICT_ALIGNED_WINDOW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ALIGN_WIDGET:
+ g_value_set_object (value, aligned_window->priv->align_widget);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdict_aligned_window_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdictAlignedWindow *aligned_window = GDICT_ALIGNED_WINDOW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ALIGN_WIDGET:
+ gdict_aligned_window_set_widget (aligned_window,
+ g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdict_aligned_window_position (GdictAlignedWindow *window)
+{
+ GdictAlignedWindowPrivate *priv;
+ GtkWidget *align_widget;
+ gint our_width, our_height;
+ gint entry_x, entry_y, entry_width, entry_height;
+ gint x, y;
+ GdkGravity gravity = GDK_GRAVITY_NORTH_WEST;
+ GdkWindow *gdk_window;
+
+ g_assert (GDICT_IS_ALIGNED_WINDOW (window));
+ priv = window->priv;
+
+ if (!priv->align_widget)
+ return;
+
+ align_widget = priv->align_widget;
+ gdk_window = gtk_widget_get_window (align_widget);
+
+ gdk_flush ();
+
+ gdk_window_get_geometry (gtk_widget_get_window (GTK_WIDGET (window)),
+ NULL,
+ NULL,
+ &our_width,
+ &our_height,
+ NULL);
+
+ /* stick, skip taskbar and pager */
+ gtk_window_stick (GTK_WINDOW (window));
+ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
+ gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
+
+ /* make sure the align_widget is realized before we do anything */
+ gtk_widget_realize (align_widget);
+
+ /* get the positional and dimensional attributes of the align widget */
+ gdk_window_get_origin (gdk_window,
+ &entry_x,
+ &entry_y);
+ gdk_window_get_geometry (gdk_window,
+ NULL,
+ NULL,
+ &entry_width,
+ &entry_height,
+ NULL);
+
+ if (entry_x + our_width < gdk_screen_width ())
+ x = entry_x + 1;
+ else
+ {
+ x = entry_x + entry_width - our_width - 1;
+
+ gravity = GDK_GRAVITY_NORTH_EAST;
+ }
+
+ if (entry_y + entry_height + our_height < gdk_screen_height ())
+ y = entry_y + entry_height - 1;
+ else
+ {
+ y = entry_y - our_height + 1;
+
+ if (gravity == GDK_GRAVITY_NORTH_EAST)
+ gravity = GDK_GRAVITY_SOUTH_EAST;
+ else
+ gravity = GDK_GRAVITY_SOUTH_WEST;
+ }
+
+ gtk_window_set_gravity (GTK_WINDOW (window), gravity);
+ gtk_window_move (GTK_WINDOW (window), x, y);
+}
+
+static void
+gdict_aligned_window_realize (GtkWidget *widget)
+{
+ GTK_WIDGET_CLASS (gdict_aligned_window_parent_class)->realize (widget);
+
+ gdict_aligned_window_position (GDICT_ALIGNED_WINDOW (widget));
+}
+
+static void
+gdict_aligned_window_show (GtkWidget *widget)
+{
+ gdict_aligned_window_position (GDICT_ALIGNED_WINDOW (widget));
+
+ GTK_WIDGET_CLASS (gdict_aligned_window_parent_class)->show (widget);
+}
+
+static void
+gdict_aligned_window_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (gdict_aligned_window_parent_class)->finalize (object);
+}
+
+static gboolean
+gdict_aligned_window_motion_notify_cb (GtkWidget *widget,
+ GdkEventMotion *event,
+ GdictAlignedWindow *aligned_window)
+{
+ GtkAllocation alloc;
+ GdkRectangle rect;
+
+ gtk_widget_get_allocation (GTK_WIDGET (aligned_window), &alloc);
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = alloc.width;
+ rect.height = alloc.height;
+
+ gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (aligned_window)),
+ &rect,
+ FALSE);
+
+ return FALSE;
+}
+
+
+/**
+ * gdict_aligned_window_new:
+ * @align_widget: a #GtkWidget to which the window should align
+ *
+ * Creates a new window, aligned to a previously created widget.
+ *
+ * Return value: a new #GdictAlignedWindow
+ */
+GtkWidget *
+gdict_aligned_window_new (GtkWidget *align_widget)
+{
+ return g_object_new (GDICT_TYPE_ALIGNED_WINDOW,
+ "align-widget", align_widget,
+ NULL);
+}
+
+/**
+ * gdict_aligned_window_set_widget:
+ * @aligned_window: a #GdictAlignedWindow
+ * @align_widget: the #GtkWidget @aligned_window should align to
+ *
+ * Sets @align_widget as the #GtkWidget to which @aligned_window should
+ * align.
+ *
+ * Note that @align_widget must have a #GdkWindow in order to
+ * #GdictAlignedWindow to work.
+ */
+void
+gdict_aligned_window_set_widget (GdictAlignedWindow *aligned_window,
+ GtkWidget *align_widget)
+{
+ GdictAlignedWindowPrivate *priv;
+
+ g_return_if_fail (GDICT_IS_ALIGNED_WINDOW (aligned_window));
+ g_return_if_fail (GTK_IS_WIDGET (align_widget));
+
+#if 0
+ if (GTK_WIDGET_NO_WINDOW (align_widget))
+ {
+ g_warning ("Attempting to set a widget of class '%s' as the "
+ "align widget, but widgets of this class does not "
+ "have a GdkWindow.",
+ g_type_name (G_OBJECT_TYPE (align_widget)));
+
+ return;
+ }
+#endif
+
+ priv = GDICT_ALIGNED_WINDOW_GET_PRIVATE (aligned_window);
+
+ if (priv->align_widget)
+ {
+ g_signal_handler_disconnect (priv->align_widget, priv->motion_id);
+ priv->align_widget = NULL;
+ }
+
+ priv->align_widget = align_widget;
+ priv->motion_id = g_signal_connect (priv->align_widget, "motion-notify-event",
+ G_CALLBACK (gdict_aligned_window_motion_notify_cb),
+ aligned_window);
+}
+
+/**
+ * gdict_aligned_window_get_widget:
+ * @aligned_window: a #GdictAlignedWindow
+ *
+ * Retrieves the #GtkWidget to which @aligned_window is aligned to.
+ *
+ * Return value: the align widget.
+ */
+GtkWidget *
+gdict_aligned_window_get_widget (GdictAlignedWindow *aligned_window)
+{
+ g_return_val_if_fail (GDICT_IS_ALIGNED_WINDOW (aligned_window), NULL);
+
+ return aligned_window->priv->align_widget;
+}
diff --git a/mate-dictionary/src/gdict-aligned-window.h b/mate-dictionary/src/gdict-aligned-window.h
new file mode 100644
index 00000000..8647f272
--- /dev/null
+++ b/mate-dictionary/src/gdict-aligned-window.h
@@ -0,0 +1,69 @@
+/* gdict-aligned-widget.h - Popup window aligned to a widget
+ *
+ * Copyright (c) 2005 Emmanuele Bassi <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Ported from Seth Nickell's Python class:
+ * Copyright (c) 2003 Seth Nickell
+ */
+
+#ifndef __GDICT_ALIGNED_WINDOW_H__
+#define __GDICT_ALIGNED_WINDOW_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDICT_TYPE_ALIGNED_WINDOW (gdict_aligned_window_get_type ())
+#define GDICT_ALIGNED_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDICT_TYPE_ALIGNED_WINDOW, GdictAlignedWindow))
+#define GDICT_IS_ALIGNED_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDICT_TYPE_ALIGNED_WINDOW))
+#define GDICT_ALIGNED_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDICT_TYPE_ALIGNED_WINDOW, GdictAlignedWindowClass))
+#define GDICT_IS_ALIGNED_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDICT_TYPE_ALIGNED_WINDOW))
+#define GDICT_ALIGNED_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDICT_TYPE_ALIGNED_WINDOW, GdictAlignedWindowClass))
+
+typedef struct _GdictAlignedWindow GdictAlignedWindow;
+typedef struct _GdictAlignedWindowClass GdictAlignedWindowClass;
+typedef struct _GdictAlignedWindowPrivate GdictAlignedWindowPrivate;
+
+struct _GdictAlignedWindow
+{
+ /*< private >*/
+ GtkWindow parent_instance;
+
+ GdictAlignedWindowPrivate *priv;
+};
+
+struct _GdictAlignedWindowClass
+{
+ /*< private >*/
+ GtkWindowClass parent_class;
+
+ void (*_gdict_reserved1) (void);
+ void (*_gdict_reserved2) (void);
+ void (*_gdict_reserved3) (void);
+ void (*_gdict_reserved4) (void);
+};
+
+GType gdict_aligned_window_get_type (void) G_GNUC_CONST;
+
+GtkWidget *gdict_aligned_window_new (GtkWidget *align_widget);
+void gdict_aligned_window_set_widget (GdictAlignedWindow *aligned_window,
+ GtkWidget *align_widget);
+GtkWidget *gdict_aligned_window_get_widget (GdictAlignedWindow *aligned_window);
+
+G_END_DECLS
+
+#endif
diff --git a/mate-dictionary/src/gdict-app.c b/mate-dictionary/src/gdict-app.c
new file mode 100644
index 00000000..eab6bbd8
--- /dev/null
+++ b/mate-dictionary/src/gdict-app.c
@@ -0,0 +1,475 @@
+/* gdict-app.c - main application class
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <sys/stat.h>
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "gdict-common.h"
+#include "gdict-pref-dialog.h"
+#include "gdict-app.h"
+
+static GdictApp *singleton = NULL;
+
+
+struct _GdictAppClass
+{
+ GObjectClass parent_class;
+};
+
+
+
+G_DEFINE_TYPE (GdictApp, gdict_app, G_TYPE_OBJECT);
+
+
+static void
+gdict_app_finalize (GObject *object)
+{
+ GdictApp *app = GDICT_APP (object);
+
+ if (app->loader)
+ g_object_unref (app->loader);
+
+ app->current_window = NULL;
+
+ g_slist_foreach (app->windows,
+ (GFunc) gtk_widget_destroy,
+ NULL);
+ g_slist_free (app->windows);
+
+ g_slist_foreach (app->lookup_words, (GFunc) g_free, NULL);
+ g_slist_free (app->lookup_words);
+
+ g_slist_foreach (app->match_words, (GFunc) g_free, NULL);
+ g_slist_free (app->match_words);
+
+ g_free (app->database);
+ g_free (app->source_name);
+
+ G_OBJECT_CLASS (gdict_app_parent_class)->finalize (object);
+}
+
+static void
+gdict_app_class_init (GdictAppClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = gdict_app_finalize;
+}
+
+static void
+gdict_app_init (GdictApp *app)
+{
+ app->windows = NULL;
+ app->current_window = NULL;
+}
+
+static void
+gdict_window_destroy_cb (GtkWidget *widget,
+ gpointer user_data)
+{
+ GdictWindow *window = GDICT_WINDOW (widget);
+ GdictApp *app = GDICT_APP (user_data);
+
+ g_assert (GDICT_IS_APP (app));
+
+ app->windows = g_slist_remove (app->windows, window);
+
+ if (window == app->current_window)
+ app->current_window = app->windows ? app->windows->data : NULL;
+
+ if (app->windows == NULL)
+ gtk_main_quit ();
+}
+
+static void
+gdict_window_created_cb (GdictWindow *parent,
+ GdictWindow *new_window,
+ gpointer user_data)
+{
+ GdictApp *app = GDICT_APP (user_data);
+
+ /* this might seem convoluted - but it's necessary, since I don't want
+ * GdictWindow to know about the GdictApp singleton. every time a new
+ * window is created by a GdictWindow, it will register its "child window"
+ * here; the lifetime handlers will check every child window created and
+ * destroyed, and will add/remove it to the windows list accordingly
+ */
+ g_signal_connect (new_window, "created",
+ G_CALLBACK (gdict_window_created_cb), app);
+ g_signal_connect (new_window, "destroy",
+ G_CALLBACK (gdict_window_destroy_cb), app);
+
+ if (gtk_window_get_group (GTK_WINDOW (parent)))
+ gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (parent)),
+ GTK_WINDOW (new_window));
+
+ app->windows = g_slist_prepend (app->windows, new_window);
+ app->current_window = new_window;
+}
+
+static void
+gdict_create_window (GdictApp *app)
+{
+ GSList *l;
+
+ if (!singleton->lookup_words && !singleton->match_words)
+ {
+ GtkWidget *window;
+
+ window = gdict_window_new (GDICT_WINDOW_ACTION_CLEAR,
+ singleton->loader,
+ singleton->source_name,
+ NULL);
+ g_signal_connect (window, "created",
+ G_CALLBACK (gdict_window_created_cb), app);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gdict_window_destroy_cb), app);
+
+ app->windows = g_slist_prepend (app->windows, window);
+ app->current_window = GDICT_WINDOW (window);
+
+ gtk_widget_show (window);
+
+ return;
+ }
+
+ for (l = singleton->lookup_words; l != NULL; l = l->next)
+ {
+ gchar *word = l->data;
+ GtkWidget *window;
+
+ window = gdict_window_new (GDICT_WINDOW_ACTION_LOOKUP,
+ singleton->loader,
+ singleton->source_name,
+ word);
+
+ g_signal_connect (window, "created",
+ G_CALLBACK (gdict_window_created_cb), app);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gdict_window_destroy_cb), app);
+
+ app->windows = g_slist_prepend (app->windows, window);
+ app->current_window = GDICT_WINDOW (window);
+
+ gtk_widget_show (window);
+ }
+
+ for (l = singleton->match_words; l != NULL; l = l->next)
+ {
+ gchar *word = l->data;
+ GtkWidget *window;
+
+ window = gdict_window_new (GDICT_WINDOW_ACTION_MATCH,
+ singleton->loader,
+ singleton->source_name,
+ word);
+
+ g_signal_connect (window, "created",
+ G_CALLBACK (gdict_window_created_cb), app);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gdict_window_destroy_cb), app);
+
+ app->windows = g_slist_prepend (app->windows, window);
+ app->current_window = GDICT_WINDOW (window);
+
+ gtk_widget_show (window);
+ }
+}
+
+static void
+definition_found_cb (GdictContext *context,
+ GdictDefinition *definition,
+ gpointer user_data)
+{
+ /* Translators: the first is the word found, the second is the
+ * database name and the last is the definition's text; please
+ * keep the new lines. */
+ g_print (_("Definition for '%s'\n"
+ " From '%s':\n"
+ "\n"
+ "%s\n"),
+ gdict_definition_get_word (definition),
+ gdict_definition_get_database (definition),
+ gdict_definition_get_text (definition));
+}
+
+static void
+error_cb (GdictContext *context,
+ const GError *error,
+ gpointer user_data)
+{
+ g_print (_("Error: %s\n"), error->message);
+
+ gtk_main_quit ();
+}
+
+static void
+lookup_end_cb (GdictContext *context,
+ gpointer user_data)
+{
+ GdictApp *app = GDICT_APP (user_data);
+
+ app->remaining_words -= 1;
+
+ if (app->remaining_words == 0)
+ gtk_main_quit ();
+}
+
+static void
+gdict_look_up_word_and_quit (GdictApp *app)
+{
+ GdictSource *source;
+ GdictContext *context;
+ GSList *l;
+
+ if ((!app->lookup_words) || (!app->match_words))
+ {
+ g_print (_("See mate-dictionary --help for usage\n"));
+
+ gdict_cleanup ();
+ exit (1);
+ }
+
+ if (app->source_name)
+ source = gdict_source_loader_get_source (app->loader, app->source_name);
+ else
+ source = gdict_source_loader_get_source (app->loader, GDICT_DEFAULT_SOURCE_NAME);
+
+ if (!source)
+ {
+ g_warning (_("Unable to find a suitable dictionary source"));
+
+ gdict_cleanup ();
+ exit (1);
+ }
+
+ /* we'll just use this one context, so we can destroy it along with
+ * the source that contains it
+ */
+ context = gdict_source_peek_context (source);
+ g_assert (GDICT_IS_CONTEXT (context));
+
+ g_signal_connect (context, "definition-found",
+ G_CALLBACK (definition_found_cb), app);
+ g_signal_connect (context, "error",
+ G_CALLBACK (error_cb), app);
+ g_signal_connect (context, "lookup-end",
+ G_CALLBACK (lookup_end_cb), app);
+
+ app->remaining_words = 0;
+ for (l = app->lookup_words; l != NULL; l = l->next)
+ {
+ gchar *word = l->data;
+ GError *err = NULL;
+
+ app->remaining_words += 1;
+
+ gdict_context_define_word (context,
+ app->database,
+ word,
+ &err);
+
+ if (err)
+ {
+ g_warning (_("Error while looking up the definition of \"%s\":\n%s"),
+ word,
+ err->message);
+
+ g_error_free (err);
+ }
+ }
+
+ gtk_main ();
+
+ g_object_unref (source);
+
+ gdict_cleanup ();
+ exit (0);
+}
+
+void
+gdict_init (int *argc, char ***argv)
+{
+ GError *mateconf_error, *err = NULL;
+ GOptionContext *context;
+ gchar *loader_path;
+ gchar **lookup_words = NULL;
+ gchar **match_words = NULL;
+ gchar *database = NULL;
+ gchar *strategy = NULL;
+ gchar *source_name = NULL;
+ gboolean no_window = FALSE;
+ gboolean list_sources = FALSE;
+
+ const GOptionEntry gdict_app_goptions[] =
+ {
+ { "look-up", 0, 0, G_OPTION_ARG_STRING_ARRAY, &lookup_words,
+ N_("Words to look up"), N_("word") },
+ { "match", 0, 0, G_OPTION_ARG_STRING_ARRAY, &match_words,
+ N_("Words to match"), N_("word") },
+ { "source", 's', 0, G_OPTION_ARG_STRING, &source_name,
+ N_("Dictionary source to use"), N_("source") },
+ { "list-sources", 'l', 0, G_OPTION_ARG_NONE, &list_sources,
+ N_("Show available dictionary sources"), NULL },
+ { "no-window", 'n', 0, G_OPTION_ARG_NONE, &no_window,
+ N_("Print result to the console"), NULL },
+ { "database", 'D', 0, G_OPTION_ARG_STRING, &database,
+ N_("Database to use"), N_("db") },
+ { "strategy", 'S', 0, G_OPTION_ARG_STRING, &strategy,
+ N_("Strategy to use"), N_("strat") },
+ { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &lookup_words,
+ N_("Words to look up"), N_("word") },
+ { NULL },
+ };
+
+ /* we must have GLib's type system up and running in order to create the
+ * singleton object for mate-dictionary; thus, we can't rely on
+ * mate_program_init() calling g_type_init() for us.
+ */
+ g_type_init ();
+
+ g_assert (singleton == NULL);
+
+ singleton = GDICT_APP (g_object_new (GDICT_TYPE_APP, NULL));
+ g_assert (GDICT_IS_APP (singleton));
+
+ /* create the new option context */
+ context = g_option_context_new (_(" - Look up words in dictionaries"));
+
+ g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
+ g_option_context_add_main_entries (context, gdict_app_goptions, GETTEXT_PACKAGE);
+ g_option_context_add_group (context, gdict_get_option_group ());
+ g_option_context_add_group (context, gtk_get_option_group (TRUE));
+
+ g_option_context_parse (context, argc, argv, &err);
+ if (err)
+ {
+ g_critical ("Failed to parse argument: %s", err->message);
+ g_error_free (err);
+ g_option_context_free (context);
+ gdict_cleanup ();
+
+ exit (1);
+ }
+
+ g_set_application_name (_("Dictionary"));
+ gtk_window_set_default_icon_name ("accessories-dictionary");
+
+ if (!gdict_create_data_dir ())
+ {
+ gdict_cleanup ();
+
+ exit (1);
+ }
+
+ mateconf_error = NULL;
+ singleton->mateconf_client = mateconf_client_get_default ();
+ mateconf_client_add_dir (singleton->mateconf_client,
+ GDICT_MATECONF_DIR,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ &mateconf_error);
+ if (mateconf_error)
+ {
+ g_warning ("Unable to access MateConf: %s\n", mateconf_error->message);
+
+ g_error_free (mateconf_error);
+ g_object_unref (singleton->mateconf_client);
+ }
+
+ /* add user's path for fetching dictionary sources */
+ singleton->loader = gdict_source_loader_new ();
+ loader_path = gdict_get_data_dir ();
+ gdict_source_loader_add_search_path (singleton->loader, loader_path);
+ g_free (loader_path);
+
+ if (lookup_words)
+ {
+ gsize i;
+ gsize length = g_strv_length (lookup_words);
+
+ for (i = 0; i < length; i++)
+ singleton->lookup_words = g_slist_prepend (singleton->lookup_words,
+ g_strdup (lookup_words[i]));
+ }
+
+ if (match_words)
+ {
+ gsize i;
+ gsize length = g_strv_length (match_words);
+
+ for (i = 0; i < length; i++)
+ singleton->match_words = g_slist_prepend (singleton->match_words,
+ g_strdup (match_words[i]));
+ }
+
+ if (database)
+ singleton->database = g_strdup (database);
+
+ if (source_name)
+ singleton->source_name = g_strdup (source_name);
+
+ if (no_window)
+ singleton->no_window = TRUE;
+
+ if (list_sources)
+ singleton->list_sources = TRUE;
+}
+
+void
+gdict_main (void)
+{
+ if (!singleton)
+ {
+ g_warning ("You must initialize GdictApp using gdict_init()\n");
+ return;
+ }
+
+ if (!singleton->no_window)
+ gdict_create_window (singleton);
+ else
+ gdict_look_up_word_and_quit (singleton);
+
+ gtk_main ();
+}
+
+void
+gdict_cleanup (void)
+{
+ if (!singleton)
+ {
+ g_warning ("You must initialize GdictApp using gdict_init()\n");
+ return;
+ }
+
+ g_object_unref (singleton);
+}
diff --git a/mate-dictionary/src/gdict-app.h b/mate-dictionary/src/gdict-app.h
new file mode 100644
index 00000000..c66f8958
--- /dev/null
+++ b/mate-dictionary/src/gdict-app.h
@@ -0,0 +1,72 @@
+/* gdict-app.h - main application class
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GDICT_APP_H__
+#define __GDICT_APP_H__
+
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+#include <libgdict/gdict.h>
+
+#include "gdict-window.h"
+
+G_BEGIN_DECLS
+
+#define GDICT_TYPE_APP (gdict_app_get_type ())
+#define GDICT_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDICT_TYPE_APP, GdictApp))
+#define GDICT_IS_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDICT_TYPE_APP))
+
+typedef struct _GdictApp GdictApp;
+typedef struct _GdictAppClass GdictAppClass;
+
+
+struct _GdictApp
+{
+ GObject parent_instance;
+
+ MateConfClient *mateconf_client;
+
+ GSList *lookup_words;
+ GSList *match_words;
+ gint remaining_words;
+
+ gchar *database;
+ gchar *source_name;
+ gboolean no_window;
+ gboolean list_sources;
+
+ GdictSourceLoader *loader;
+
+ GdictWindow *current_window;
+ GSList *windows;
+};
+
+
+GType gdict_app_get_type (void) G_GNUC_CONST;
+
+void gdict_init (int *argc, char ***argv);
+void gdict_main (void);
+void gdict_cleanup (void);
+
+G_END_DECLS
+
+#endif /* __GDICT_APP_H__ */
diff --git a/mate-dictionary/src/gdict-applet.c b/mate-dictionary/src/gdict-applet.c
new file mode 100644
index 00000000..442381a6
--- /dev/null
+++ b/mate-dictionary/src/gdict-applet.c
@@ -0,0 +1,1333 @@
+/* gdict-applet.c - MATE Dictionary Applet
+ *
+ * Copyright (c) 2005 Emmanuele Bassi <[email protected]>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+
+#include "gdict-applet.h"
+#include "gdict-about.h"
+#include "gdict-pref-dialog.h"
+#include "gdict-print.h"
+#include "gdict-common.h"
+#include "gdict-aligned-window.h"
+
+#define GDICT_APPLET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDICT_TYPE_APPLET, GdictAppletClass))
+#define GDICT_APPLET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDICT_TYPE_APPLET, GdictAppletClass))
+
+struct _GdictAppletClass
+{
+ MatePanelAppletClass parent_class;
+};
+
+#define GDICT_APPLET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GDICT_TYPE_APPLET, GdictAppletPrivate))
+
+struct _GdictAppletPrivate
+{
+ guint size;
+ GtkOrientation orient;
+
+ MateConfClient *mateconf_client;
+ guint notify_id;
+ guint font_notify_id;
+
+ gchar *database;
+ gchar *strategy;
+ gchar *source_name;
+ gchar *print_font;
+ gchar *defbox_font;
+
+ gchar *word;
+ GdictContext *context;
+ guint lookup_start_id;
+ guint lookup_end_id;
+ guint error_id;
+
+ GdictSourceLoader *loader;
+
+ GtkWidget *box;
+ GtkWidget *toggle;
+ GtkWidget *image;
+ GtkWidget *entry;
+ GtkWidget *window;
+ GtkWidget *frame;
+ GtkWidget *defbox;
+
+ guint idle_draw_id;
+
+ GdkPixbuf *icon;
+
+ gint window_width;
+ gint window_height;
+
+ guint is_window_showing : 1;
+};
+
+#define WINDOW_MIN_WIDTH 300
+#define WINDOW_MIN_HEIGHT 200
+#define WINDOW_NUM_COLUMNS 47
+#define WINDOW_NUM_ROWS 20
+
+G_DEFINE_TYPE (GdictApplet, gdict_applet, PANEL_TYPE_APPLET);
+
+
+static const GtkTargetEntry drop_types[] =
+{
+ { "text/plain", 0, 0 },
+ { "TEXT", 0, 0 },
+ { "STRING", 0, 0 },
+ { "UTF8_STRING", 0, 0 },
+};
+static const guint n_drop_types = G_N_ELEMENTS (drop_types);
+
+
+static void
+set_atk_name_description (GtkWidget *widget,
+ const char *name,
+ const char *description)
+{
+ AtkObject *aobj;
+
+ aobj = gtk_widget_get_accessible (widget);
+ if (!GTK_IS_ACCESSIBLE (aobj))
+ return;
+
+ atk_object_set_name (aobj, name);
+ atk_object_set_description (aobj, description);
+}
+
+static void
+set_window_default_size (GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+ GtkWidget *widget, *defbox;
+ gint width, height;
+ gint font_size;
+ GdkScreen *screen;
+ gint monitor_num;
+ GtkRequisition req;
+ GdkRectangle monitor;
+
+ if (!priv->window)
+ return;
+
+ widget = priv->window;
+ defbox = priv->defbox;
+
+ /* Size based on the font size */
+ font_size = pango_font_description_get_size (gtk_widget_get_style (defbox)->font_desc);
+ font_size = PANGO_PIXELS (font_size);
+
+ width = font_size * WINDOW_NUM_COLUMNS;
+ height = font_size * WINDOW_NUM_ROWS;
+
+ /* Use at least the requisition size of the window... */
+ gtk_widget_size_request (widget, &req);
+ width = MAX (width, req.width);
+ height = MAX (height, req.height);
+
+ /* ... but make it no larger than half the monitor size */
+ screen = gtk_widget_get_screen (widget);
+ monitor_num = gdk_screen_get_monitor_at_window (screen,
+ gtk_widget_get_window (widget));
+
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+ width = MIN (width, monitor.width / 2);
+ height = MIN (height, monitor.height / 2);
+
+ /* Set size */
+ gtk_widget_set_size_request (priv->frame, width, height);
+}
+
+static void
+clear_cb (GtkWidget *widget,
+ GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+
+ gtk_entry_set_text (GTK_ENTRY (priv->entry), "");
+
+ if (!priv->defbox)
+ return;
+
+ gdict_defbox_clear (GDICT_DEFBOX (priv->defbox));
+}
+
+static void
+print_cb (GtkWidget *widget,
+ GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+
+ if (!priv->defbox)
+ return;
+
+ gdict_show_print_dialog (GTK_WINDOW (priv->window),
+ GDICT_DEFBOX (priv->defbox));
+}
+
+static void
+save_cb (GtkWidget *widget,
+ GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+ GtkWidget *dialog;
+
+ if (!priv->defbox)
+ return;
+
+ dialog = gtk_file_chooser_dialog_new (_("Save a Copy"),
+ GTK_WINDOW (priv->window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
+
+ /* default to user's $HOME */
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_home_dir ());
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), _("Untitled document"));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+ {
+ gchar *filename;
+ gchar *text;
+ gsize len;
+ GError *write_error = NULL;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+ text = gdict_defbox_get_text (GDICT_DEFBOX (priv->defbox), &len);
+
+ g_file_set_contents (filename,
+ text,
+ len,
+ &write_error);
+ if (write_error)
+ {
+ gchar *message;
+
+ message = g_strdup_printf (_("Error while writing to '%s'"), filename);
+
+ gdict_show_error_dialog (GTK_WINDOW (priv->window),
+ message,
+ write_error->message);
+
+ g_error_free (write_error);
+ g_free (message);
+ }
+
+ g_free (text);
+ g_free (filename);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+gdict_applet_set_menu_items_sensitive (GdictApplet *applet,
+ gboolean is_sensitive)
+{
+ MateComponentUIComponent *popup_component;
+
+ popup_component = mate_panel_applet_get_popup_component (MATE_PANEL_APPLET (applet));
+ if (!MATECOMPONENT_IS_UI_COMPONENT (popup_component))
+ return;
+
+ matecomponent_ui_component_set_prop (popup_component,
+ "/commands/Clear",
+ "sensitive", (is_sensitive ? "1" : "0"),
+ NULL);
+ matecomponent_ui_component_set_prop (popup_component,
+ "/commands/Print",
+ "sensitive", (is_sensitive ? "1" : "0"),
+ NULL);
+ matecomponent_ui_component_set_prop (popup_component,
+ "/commands/Save",
+ "sensitive", (is_sensitive ? "1" : "0"),
+ NULL);
+}
+
+static gboolean
+window_key_press_event_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+ GdictApplet *applet = GDICT_APPLET (user_data);
+
+ if (event->keyval == GDK_Escape)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (applet->priv->toggle), FALSE);
+ gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (applet->priv->toggle));
+
+ return TRUE;
+ }
+ else if ((event->keyval == GDK_l) &&
+ (event->state & GDK_CONTROL_MASK))
+ {
+ gtk_widget_grab_focus (applet->priv->entry);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+window_show_cb (GtkWidget *window,
+ GdictApplet *applet)
+{
+ set_window_default_size (applet);
+}
+
+static void
+gdict_applet_build_window (GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+ GtkWidget *window;
+ GtkWidget *frame;
+ GtkWidget *vbox;
+ GtkWidget *bbox;
+ GtkWidget *button;
+
+ if (!priv->entry)
+ {
+ g_warning ("No entry widget defined");
+
+ return;
+ }
+
+ window = gdict_aligned_window_new (priv->toggle);
+ g_signal_connect (window, "key-press-event",
+ G_CALLBACK (window_key_press_event_cb),
+ applet);
+ g_signal_connect (window, "show",
+ G_CALLBACK (window_show_cb),
+ applet);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (window), frame);
+ gtk_widget_show (frame);
+ priv->frame = frame;
+
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+ gtk_container_add (GTK_CONTAINER (frame), vbox);
+ gtk_widget_show (vbox);
+
+ priv->defbox = gdict_defbox_new ();
+ if (priv->context)
+ gdict_defbox_set_context (GDICT_DEFBOX (priv->defbox), priv->context);
+
+ gtk_box_pack_start (GTK_BOX (vbox), priv->defbox, TRUE, TRUE, 0);
+ gtk_widget_show (priv->defbox);
+ gtk_widget_set_can_focus (priv->defbox, TRUE);
+ gtk_widget_set_can_default (priv->defbox, TRUE);
+
+ bbox = gtk_hbutton_box_new ();
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing (GTK_BOX (bbox), 6);
+ gtk_box_pack_end (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
+ gtk_widget_show (bbox);
+
+ button = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
+ gtk_widget_set_tooltip_text (button, _("Clear the definitions found"));
+ set_atk_name_description (button,
+ _("Clear definition"),
+ _("Clear the text of the definition"));
+
+ g_signal_connect (button, "clicked", G_CALLBACK (clear_cb), applet);
+ gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_from_stock (GTK_STOCK_PRINT);
+ gtk_widget_set_tooltip_text (button, _("Print the definitions found"));
+ set_atk_name_description (button,
+ _("Print definition"),
+ _("Print the text of the definition"));
+
+ g_signal_connect (button, "clicked", G_CALLBACK (print_cb), applet);
+ gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
+ gtk_widget_set_tooltip_text (button, _("Save the definitions found"));
+ set_atk_name_description (button,
+ _("Save definition"),
+ _("Save the text of the definition to a file"));
+
+ g_signal_connect (button, "clicked", G_CALLBACK (save_cb), applet);
+ gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ gtk_window_set_default (GTK_WINDOW (window), priv->defbox);
+
+ priv->window = window;
+ priv->is_window_showing = FALSE;
+}
+
+static gboolean
+gdict_applet_icon_toggled_cb (GtkWidget *widget,
+ GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+
+ if (!priv->window)
+ gdict_applet_build_window (applet);
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+ {
+ gtk_window_set_screen (GTK_WINDOW (priv->window),
+ gtk_widget_get_screen (GTK_WIDGET (applet)));
+ gtk_window_present (GTK_WINDOW (priv->window));
+ gtk_widget_grab_focus (priv->defbox);
+
+ priv->is_window_showing = TRUE;
+ }
+ else
+ {
+ /* force hiding the find pane */
+ gdict_defbox_set_show_find (GDICT_DEFBOX (priv->defbox), FALSE);
+
+ gtk_widget_grab_focus (priv->entry);
+ gtk_widget_hide (priv->window);
+
+ priv->is_window_showing = FALSE;
+ }
+
+ return FALSE;
+}
+
+static void
+gdict_applet_entry_activate_cb (GtkWidget *widget,
+ GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+ gchar *text;
+
+ text = gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1);
+ if (!text)
+ return;
+
+ g_free (priv->word);
+ priv->word = text;
+
+ if (!priv->window)
+ gdict_applet_build_window (applet);
+
+ gdict_defbox_lookup (GDICT_DEFBOX (priv->defbox), priv->word);
+}
+
+static gboolean
+gdict_applet_entry_key_press_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+ GdictAppletPrivate *priv = GDICT_APPLET (user_data)->priv;
+
+ if (event->keyval == GDK_Escape)
+ {
+ if (priv->is_window_showing)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->toggle), FALSE);
+ gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (priv->toggle));
+
+ return TRUE;
+ }
+ }
+ else if (event->keyval == GDK_Tab)
+ {
+ if (priv->is_window_showing)
+ gtk_widget_grab_focus (priv->defbox);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gdict_applet_icon_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+
+ /* we don't want to block the applet's popup menu unless the
+ * user is toggling the button
+ */
+ if (event->button != 1)
+ g_signal_stop_emission_by_name (priv->toggle, "button-press-event");
+
+ return FALSE;
+}
+
+static gboolean
+gdict_applet_entry_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ GdictApplet *applet)
+{
+ mate_panel_applet_request_focus (MATE_PANEL_APPLET (applet), event->time);
+
+ return FALSE;
+}
+
+static gboolean
+gdict_applet_draw (GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+ GtkWidget *box;
+ GtkWidget *hbox;
+ gchar *text = NULL;
+
+ if (priv->entry)
+ text = gtk_editable_get_chars (GTK_EDITABLE (priv->entry), 0, -1);
+
+ if (priv->box)
+ gtk_widget_destroy (priv->box);
+
+ switch (priv->orient)
+ {
+ case GTK_ORIENTATION_VERTICAL:
+ box = gtk_vbox_new (FALSE, 0);
+ break;
+ case GTK_ORIENTATION_HORIZONTAL:
+ box = gtk_hbox_new (FALSE, 0);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ gtk_container_add (GTK_CONTAINER (applet), box);
+ gtk_widget_show (box);
+
+ /* toggle button */
+ priv->toggle = gtk_toggle_button_new ();
+ gtk_widget_set_tooltip_text (priv->toggle, _("Click to view the dictionary window"));
+ set_atk_name_description (priv->toggle,
+ _("Toggle dictionary window"),
+ _("Show or hide the definition window"));
+
+ gtk_button_set_relief (GTK_BUTTON (priv->toggle),
+ GTK_RELIEF_NONE);
+ g_signal_connect (priv->toggle, "toggled",
+ G_CALLBACK (gdict_applet_icon_toggled_cb),
+ applet);
+ g_signal_connect (priv->toggle, "button-press-event",
+ G_CALLBACK (gdict_applet_icon_button_press_event_cb),
+ applet);
+ gtk_box_pack_start (GTK_BOX (box), priv->toggle, FALSE, FALSE, 0);
+ gtk_widget_show (priv->toggle);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 0);
+ gtk_container_add (GTK_CONTAINER (priv->toggle), hbox);
+ gtk_widget_show (hbox);
+
+ if (priv->icon)
+ {
+ GdkPixbuf *scaled;
+
+ priv->image = gtk_image_new ();
+ gtk_image_set_pixel_size (GTK_IMAGE (priv->image), priv->size - 10);
+
+ scaled = gdk_pixbuf_scale_simple (priv->icon,
+ priv->size - 5,
+ priv->size - 5,
+ GDK_INTERP_BILINEAR);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), scaled);
+ g_object_unref (scaled);
+
+ gtk_box_pack_start (GTK_BOX (hbox), priv->image, FALSE, FALSE, 0);
+
+ gtk_widget_show (priv->image);
+ }
+ else
+ {
+ priv->image = gtk_image_new ();
+
+ gtk_image_set_pixel_size (GTK_IMAGE (priv->image), priv->size - 10);
+ gtk_image_set_from_stock (GTK_IMAGE (priv->image),
+ GTK_STOCK_MISSING_IMAGE,
+ -1);
+
+ gtk_box_pack_start (GTK_BOX (hbox), priv->image, FALSE, FALSE, 0);
+ gtk_widget_show (priv->image);
+ }
+
+ /* entry */
+ priv->entry = gtk_entry_new ();
+ gtk_widget_set_tooltip_text (priv->entry, _("Type the word you want to look up"));
+ set_atk_name_description (priv->entry,
+ _("Dictionary entry"),
+ _("Look up words in dictionaries"));
+
+ gtk_editable_set_editable (GTK_EDITABLE (priv->entry), TRUE);
+ gtk_entry_set_width_chars (GTK_ENTRY (priv->entry), 12);
+ g_signal_connect (priv->entry, "activate",
+ G_CALLBACK (gdict_applet_entry_activate_cb),
+ applet);
+ g_signal_connect (priv->entry, "button-press-event",
+ G_CALLBACK (gdict_applet_entry_button_press_event_cb),
+ applet);
+ g_signal_connect (priv->entry, "key-press-event",
+ G_CALLBACK (gdict_applet_entry_key_press_cb),
+ applet);
+ gtk_box_pack_end (GTK_BOX (box), priv->entry, FALSE, FALSE, 0);
+ gtk_widget_show (priv->entry);
+
+ if (text)
+ {
+ gtk_entry_set_text (GTK_ENTRY (priv->entry), text);
+
+ g_free (text);
+ }
+
+ priv->box = box;
+
+#if 0
+ gtk_widget_grab_focus (priv->entry);
+#endif
+
+ gtk_widget_show_all (GTK_WIDGET (applet));
+
+ return FALSE;
+}
+
+static void
+gdict_applet_queue_draw (GdictApplet *applet)
+{
+ if (!applet->priv->idle_draw_id)
+ applet->priv->idle_draw_id = g_idle_add ((GSourceFunc) gdict_applet_draw,
+ applet);
+}
+
+static void
+gdict_applet_lookup_start_cb (GdictContext *context,
+ GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+
+ if (!priv->window)
+ gdict_applet_build_window (applet);
+
+ if (!priv->is_window_showing)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->toggle), TRUE);
+
+ gtk_window_present (GTK_WINDOW (priv->window));
+ gtk_widget_grab_focus (priv->defbox);
+
+ priv->is_window_showing = TRUE;
+ }
+
+ gdict_applet_set_menu_items_sensitive (applet, FALSE);
+}
+
+static void
+gdict_applet_lookup_end_cb (GdictContext *context,
+ GdictApplet *applet)
+{
+ gdict_applet_set_menu_items_sensitive (applet, TRUE);
+
+ gtk_window_present (GTK_WINDOW (applet->priv->window));
+}
+
+static void
+gdict_applet_error_cb (GdictContext *context,
+ const GError *error,
+ GdictApplet *applet)
+{
+ /* disable menu items */
+ gdict_applet_set_menu_items_sensitive (applet, FALSE);
+}
+
+static void
+gdict_applet_cmd_lookup (MateComponentUIComponent *component,
+ GdictApplet *applet,
+ const gchar *cname)
+{
+ GdictAppletPrivate *priv = applet->priv;
+ gchar *text = NULL;;
+
+ text = gtk_editable_get_chars (GTK_EDITABLE (priv->entry), 0, -1);
+ if (!text)
+ return;
+
+ g_free (priv->word);
+ priv->word = text;
+
+ if (!priv->window)
+ gdict_applet_build_window (applet);
+
+ gdict_defbox_lookup (GDICT_DEFBOX (priv->defbox), priv->word);
+}
+
+static void
+gdict_applet_cmd_clear (MateComponentUIComponent *component,
+ GdictApplet *applet,
+ const gchar *cname)
+{
+ clear_cb (NULL, applet);
+}
+
+static void
+gdict_applet_cmd_print (MateComponentUIComponent *component,
+ GdictApplet *applet,
+ const gchar *cname)
+{
+ print_cb (NULL, applet);
+}
+
+static void
+gdict_applet_cmd_preferences (MateComponentUIComponent *component,
+ GdictApplet *applet,
+ const gchar *cname)
+{
+ gdict_show_pref_dialog (GTK_WIDGET (applet),
+ _("Dictionary Preferences"),
+ applet->priv->loader);
+}
+
+static void
+gdict_applet_cmd_about (MateComponentUIComponent *component,
+ GdictApplet *applet,
+ const gchar *cname)
+{
+ gdict_show_about_dialog (GTK_WIDGET (applet));
+}
+
+static void
+gdict_applet_cmd_help (MateComponentUIComponent *component,
+ GdictApplet *applet,
+ const gchar *cname)
+{
+ GError *err = NULL;
+
+ gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (applet)),
+ "ghelp:mate-dictionary#mate-dictionary-applet",
+ gtk_get_current_event_time (), &err);
+
+ if (err)
+ {
+ gdict_show_error_dialog (NULL,
+ _("There was an error while displaying help"),
+ err->message);
+ g_error_free (err);
+ }
+}
+
+static void
+gdict_applet_change_background (MatePanelApplet *applet,
+ MatePanelAppletBackgroundType type,
+ GdkColor *color,
+ GdkPixmap *pixmap)
+{
+ if (MATE_PANEL_APPLET_CLASS (gdict_applet_parent_class)->change_background)
+ MATE_PANEL_APPLET_CLASS (gdict_applet_parent_class)->change_background (applet,
+ type,
+ color,
+ pixmap);
+}
+
+static void
+gdict_applet_change_orient (MatePanelApplet *applet,
+ MatePanelAppletOrient orient)
+{
+ GdictAppletPrivate *priv = GDICT_APPLET (applet)->priv;
+ guint new_size;
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation (GTK_WIDGET (applet), &allocation);
+ switch (orient)
+ {
+ case MATE_PANEL_APPLET_ORIENT_LEFT:
+ case MATE_PANEL_APPLET_ORIENT_RIGHT:
+ priv->orient = GTK_ORIENTATION_VERTICAL;
+ new_size = allocation.width;
+ break;
+ case MATE_PANEL_APPLET_ORIENT_UP:
+ case MATE_PANEL_APPLET_ORIENT_DOWN:
+ priv->orient = GTK_ORIENTATION_HORIZONTAL;
+ new_size = allocation.height;
+ break;
+ }
+
+ if (new_size != priv->size)
+ priv->size = new_size;
+
+ gdict_applet_queue_draw (GDICT_APPLET (applet));
+
+ if (MATE_PANEL_APPLET_CLASS (gdict_applet_parent_class)->change_orient)
+ MATE_PANEL_APPLET_CLASS (gdict_applet_parent_class)->change_orient (applet,
+ orient);
+}
+
+static void
+gdict_applet_size_allocate (GtkWidget *widget,
+ GdkRectangle *allocation)
+{
+ GdictApplet *applet = GDICT_APPLET (widget);
+ GdictAppletPrivate *priv = applet->priv;
+ guint new_size;
+
+ if (priv->orient == GTK_ORIENTATION_HORIZONTAL)
+ new_size = allocation->height;
+ else
+ new_size = allocation->width;
+
+ if (priv->size != new_size)
+ {
+ priv->size = new_size;
+
+ gtk_image_set_pixel_size (GTK_IMAGE (priv->image), priv->size - 10);
+
+ /* re-scale the icon, if it was found */
+ if (priv->icon)
+ {
+ GdkPixbuf *scaled;
+
+ scaled = gdk_pixbuf_scale_simple (priv->icon,
+ priv->size - 5,
+ priv->size - 5,
+ GDK_INTERP_BILINEAR);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), scaled);
+ g_object_unref (scaled);
+ }
+ }
+
+ if (GTK_WIDGET_CLASS (gdict_applet_parent_class)->size_allocate)
+ GTK_WIDGET_CLASS (gdict_applet_parent_class)->size_allocate (widget,
+ allocation);
+}
+
+static void
+gdict_applet_style_set (GtkWidget *widget,
+ GtkStyle *old_style)
+{
+ if (GTK_WIDGET_CLASS (gdict_applet_parent_class)->style_set)
+ GTK_WIDGET_CLASS (gdict_applet_parent_class)->style_set (widget,
+ old_style);
+#if 0
+ set_window_default_size (GDICT_APPLET (widget));
+#endif
+}
+
+static void
+gdict_applet_set_database (GdictApplet *applet,
+ const gchar *database)
+{
+ GdictAppletPrivate *priv = applet->priv;
+
+ g_free (priv->database);
+
+ if (database)
+ priv->database = g_strdup (database);
+ else
+ priv->database = gdict_mateconf_get_string_with_default (priv->mateconf_client,
+ GDICT_MATECONF_DATABASE_KEY,
+ GDICT_DEFAULT_DATABASE);
+ if (priv->defbox)
+ gdict_defbox_set_database (GDICT_DEFBOX (priv->defbox),
+ priv->database);
+}
+
+static void
+gdict_applet_set_strategy (GdictApplet *applet,
+ const gchar *strategy)
+{
+ GdictAppletPrivate *priv = applet->priv;
+
+ g_free (priv->strategy);
+
+ if (strategy)
+ priv->strategy = g_strdup (strategy);
+ else
+ priv->strategy = gdict_mateconf_get_string_with_default (priv->mateconf_client,
+ GDICT_MATECONF_STRATEGY_KEY,
+ GDICT_DEFAULT_STRATEGY);
+}
+
+static GdictContext *
+get_context_from_loader (GdictApplet *applet)
+{
+ GdictAppletPrivate *priv = applet->priv;
+ GdictSource *source;
+ GdictContext *retval;
+
+ if (!priv->source_name)
+ priv->source_name = g_strdup (GDICT_DEFAULT_SOURCE_NAME);
+
+ source = gdict_source_loader_get_source (priv->loader,
+ priv->source_name);
+ if (!source)
+ {
+ gchar *detail;
+
+ detail = g_strdup_printf (_("No dictionary source available with name '%s'"),
+ priv->source_name);
+
+ gdict_show_error_dialog (NULL,
+ _("Unable to find dictionary source"),
+ NULL);
+
+ g_free (detail);
+
+ return NULL;
+ }
+
+ gdict_applet_set_database (applet, gdict_source_get_database (source));
+ gdict_applet_set_strategy (applet, gdict_source_get_strategy (source));
+
+ retval = gdict_source_get_context (source);
+ if (!retval)
+ {
+ gchar *detail;
+
+ detail = g_strdup_printf (_("No context available for source '%s'"),
+ gdict_source_get_description (source));
+
+ gdict_show_error_dialog (NULL,
+ _("Unable to create a context"),
+ detail);
+
+ g_free (detail);
+ g_object_unref (source);
+
+ return NULL;
+ }
+
+ g_object_unref (source);
+
+ return retval;
+}
+
+static void
+gdict_applet_set_print_font (GdictApplet *applet,
+ const gchar *print_font)
+{
+ GdictAppletPrivate *priv = applet->priv;
+
+ g_free (priv->print_font);
+
+ if (print_font)
+ priv->print_font = g_strdup (print_font);
+ else
+ priv->print_font = gdict_mateconf_get_string_with_default (priv->mateconf_client,
+ GDICT_MATECONF_PRINT_FONT_KEY,
+ GDICT_DEFAULT_PRINT_FONT);
+}
+
+static void
+gdict_applet_set_defbox_font (GdictApplet *applet,
+ const gchar *defbox_font)
+{
+ GdictAppletPrivate *priv = applet->priv;
+
+ g_free (priv->defbox_font);
+
+ if (defbox_font)
+ priv->defbox_font = g_strdup (defbox_font);
+ else
+ priv->defbox_font = gdict_mateconf_get_string_with_default (priv->mateconf_client,
+ DOCUMENT_FONT_KEY,
+ GDICT_DEFAULT_DEFBOX_FONT);
+
+ if (priv->defbox)
+ gdict_defbox_set_font_name (GDICT_DEFBOX (priv->defbox),
+ priv->defbox_font);
+}
+
+static void
+gdict_applet_set_context (GdictApplet *applet,
+ GdictContext *context)
+{
+ GdictAppletPrivate *priv = applet->priv;
+
+ if (priv->context)
+ {
+ g_signal_handler_disconnect (priv->context, priv->lookup_start_id);
+ g_signal_handler_disconnect (priv->context, priv->lookup_end_id);
+ g_signal_handler_disconnect (priv->context, priv->error_id);
+
+ priv->lookup_start_id = 0;
+ priv->lookup_end_id = 0;
+ priv->error_id = 0;
+
+ g_object_unref (priv->context);
+ priv->context = NULL;
+ }
+
+ if (priv->defbox)
+ gdict_defbox_set_context (GDICT_DEFBOX (priv->defbox), context);
+
+ if (!context)
+ return;
+
+ /* attach our callbacks */
+ priv->lookup_start_id = g_signal_connect (context, "lookup-start",
+ G_CALLBACK (gdict_applet_lookup_start_cb),
+ applet);
+ priv->lookup_end_id = g_signal_connect (context, "lookup-end",
+ G_CALLBACK (gdict_applet_lookup_end_cb),
+ applet);
+ priv->error_id = g_signal_connect (context, "error",
+ G_CALLBACK (gdict_applet_error_cb),
+ applet);
+
+ priv->context = context;
+}
+
+static void
+gdict_applet_set_source_name (GdictApplet *applet,
+ const gchar *source_name)
+{
+ GdictAppletPrivate *priv = applet->priv;
+ GdictContext *context;
+
+ g_free (priv->source_name);
+
+ if (source_name)
+ priv->source_name = g_strdup (source_name);
+ else
+ priv->source_name = gdict_mateconf_get_string_with_default (priv->mateconf_client,
+ GDICT_MATECONF_SOURCE_KEY,
+ GDICT_DEFAULT_SOURCE_NAME);
+
+ context = get_context_from_loader (applet);
+ gdict_applet_set_context (applet, context);
+}
+
+static void
+gdict_applet_mateconf_notify_cb (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ GdictApplet *applet = GDICT_APPLET (user_data);
+
+ if (strcmp (entry->key, GDICT_MATECONF_PRINT_FONT_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_STRING))
+ gdict_applet_set_print_font (applet, mateconf_value_get_string (entry->value));
+ else
+ gdict_applet_set_print_font (applet, GDICT_DEFAULT_PRINT_FONT);
+ }
+ else if (strcmp (entry->key, GDICT_MATECONF_SOURCE_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_STRING))
+ gdict_applet_set_source_name (applet, mateconf_value_get_string (entry->value));
+ else
+ gdict_applet_set_source_name (applet, GDICT_DEFAULT_SOURCE_NAME);
+ }
+ else if (strcmp (entry->key, GDICT_MATECONF_DATABASE_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_STRING))
+ gdict_applet_set_database (applet, mateconf_value_get_string (entry->value));
+ else
+ gdict_applet_set_database (applet, GDICT_DEFAULT_DATABASE);
+ }
+ else if (strcmp (entry->key, GDICT_MATECONF_STRATEGY_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_STRING))
+ gdict_applet_set_strategy (applet, mateconf_value_get_string (entry->value));
+ else
+ gdict_applet_set_strategy (applet, GDICT_DEFAULT_STRATEGY);
+ }
+ else if (strcmp (entry->key, DOCUMENT_FONT_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_STRING))
+ gdict_applet_set_defbox_font (applet, mateconf_value_get_string (entry->value));
+ else
+ gdict_applet_set_defbox_font (applet, GDICT_DEFAULT_DEFBOX_FONT);
+ }
+}
+
+static void
+gdict_applet_finalize (GObject *object)
+{
+ GdictApplet *applet = GDICT_APPLET (object);
+ GdictAppletPrivate *priv = applet->priv;
+
+ if (priv->idle_draw_id)
+ g_source_remove (priv->idle_draw_id);
+
+ if (priv->notify_id)
+ mateconf_client_notify_remove (priv->mateconf_client, priv->notify_id);
+
+ if (priv->font_notify_id)
+ mateconf_client_notify_remove (priv->mateconf_client, priv->font_notify_id);
+
+ if (priv->mateconf_client)
+ g_object_unref (priv->mateconf_client);
+
+ if (priv->context)
+ {
+ if (priv->lookup_start_id)
+ {
+ g_signal_handler_disconnect (priv->context, priv->lookup_start_id);
+ g_signal_handler_disconnect (priv->context, priv->lookup_end_id);
+ g_signal_handler_disconnect (priv->context, priv->error_id);
+ }
+
+ g_object_unref (priv->context);
+ }
+
+ if (priv->loader)
+ g_object_unref (priv->loader);
+
+ if (priv->icon)
+ g_object_unref (priv->icon);
+
+ g_free (priv->source_name);
+ g_free (priv->print_font);
+ g_free (priv->defbox_font);
+ g_free (priv->word);
+
+ G_OBJECT_CLASS (gdict_applet_parent_class)->finalize (object);
+}
+
+static void
+gdict_applet_class_init (GdictAppletClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ MatePanelAppletClass *applet_class = MATE_PANEL_APPLET_CLASS (klass);
+
+ gobject_class->finalize = gdict_applet_finalize;
+
+ widget_class->size_allocate = gdict_applet_size_allocate;
+ widget_class->style_set = gdict_applet_style_set;
+
+ applet_class->change_background = gdict_applet_change_background;
+ applet_class->change_orient = gdict_applet_change_orient;
+
+ g_type_class_add_private (gobject_class, sizeof (GdictAppletPrivate));
+}
+
+static void
+gdict_applet_init (GdictApplet *applet)
+{
+ GdictAppletPrivate *priv;
+ gchar *data_dir;
+ GError *mateconf_error;
+
+ priv = GDICT_APPLET_GET_PRIVATE (applet);
+ applet->priv = priv;
+
+ if (!priv->loader)
+ priv->loader = gdict_source_loader_new ();
+
+ /* add our data dir inside $HOME to the loader's search paths */
+ data_dir = gdict_get_data_dir ();
+ gdict_source_loader_add_search_path (priv->loader, data_dir);
+ g_free (data_dir);
+
+ gtk_window_set_default_icon_name ("accessories-dictionary");
+
+ mate_panel_applet_set_flags (MATE_PANEL_APPLET (applet),
+ MATE_PANEL_APPLET_EXPAND_MINOR);
+
+ /* get the default mateconf client */
+ if (!priv->mateconf_client)
+ priv->mateconf_client = mateconf_client_get_default ();
+
+ mateconf_error = NULL;
+ mateconf_client_add_dir (priv->mateconf_client,
+ GDICT_MATECONF_DIR,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ &mateconf_error);
+ if (mateconf_error)
+ {
+ gdict_show_gerror_dialog (NULL,
+ _("Unable to connect to MateConf"),
+ mateconf_error);
+ mateconf_error = NULL;
+ }
+
+ priv->notify_id = mateconf_client_notify_add (priv->mateconf_client,
+ GDICT_MATECONF_DIR,
+ gdict_applet_mateconf_notify_cb,
+ applet, NULL,
+ &mateconf_error);
+ if (mateconf_error)
+ {
+ gdict_show_gerror_dialog (NULL,
+ _("Unable to get notification for preferences"),
+ mateconf_error);
+
+ mateconf_error = NULL;
+ }
+
+ priv->font_notify_id = mateconf_client_notify_add (priv->mateconf_client,
+ DOCUMENT_FONT_KEY,
+ gdict_applet_mateconf_notify_cb,
+ applet, NULL,
+ &mateconf_error);
+ if (mateconf_error)
+ {
+ gdict_show_gerror_dialog (NULL,
+ _("Unable to get notification for the document font"),
+ mateconf_error);
+
+ mateconf_error = NULL;
+ }
+
+#ifndef GDICT_APPLET_STAND_ALONE
+ mate_panel_applet_set_background_widget (MATE_PANEL_APPLET (applet),
+ GTK_WIDGET (applet));
+
+ priv->size = mate_panel_applet_get_size (MATE_PANEL_APPLET (applet));
+
+ switch (mate_panel_applet_get_orient (MATE_PANEL_APPLET (applet)))
+ {
+ case MATE_PANEL_APPLET_ORIENT_LEFT:
+ case MATE_PANEL_APPLET_ORIENT_RIGHT:
+ priv->orient = GTK_ORIENTATION_VERTICAL;
+ break;
+ case MATE_PANEL_APPLET_ORIENT_UP:
+ case MATE_PANEL_APPLET_ORIENT_DOWN:
+ priv->orient = GTK_ORIENTATION_HORIZONTAL;
+ break;
+ }
+#else
+ priv->size = 24;
+ priv->orient = GTK_ORIENTATION_HORIZONTAL;
+ g_message ("(in %s) applet { size = %d, orient = %s }",
+ G_STRFUNC,
+ priv->size,
+ (priv->orient == GTK_ORIENTATION_HORIZONTAL ? "H" : "V"));
+#endif /* !GDICT_APPLET_STAND_ALONE */
+
+ priv->icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+ "accessories-dictionary",
+ 48,
+ 0,
+ NULL);
+
+ /* force first draw */
+ gdict_applet_draw (applet);
+
+ /* force retrieval of the configuration from MateConf */
+ gdict_applet_set_source_name (applet, NULL);
+ gdict_applet_set_defbox_font (applet, NULL);
+ gdict_applet_set_print_font (applet, NULL);
+}
+
+#ifndef GDICT_APPLET_STAND_ALONE
+static const MateComponentUIVerb gdict_applet_menu_verbs[] =
+{
+ MATECOMPONENT_UI_UNSAFE_VERB ("LookUp", gdict_applet_cmd_lookup),
+
+ MATECOMPONENT_UI_UNSAFE_VERB ("Clear", gdict_applet_cmd_clear),
+ MATECOMPONENT_UI_UNSAFE_VERB ("Print", gdict_applet_cmd_print),
+
+ MATECOMPONENT_UI_UNSAFE_VERB ("Preferences", gdict_applet_cmd_preferences),
+ MATECOMPONENT_UI_UNSAFE_VERB ("Help", gdict_applet_cmd_help),
+ MATECOMPONENT_UI_UNSAFE_VERB ("About", gdict_applet_cmd_about),
+
+ MATECOMPONENT_UI_VERB_END
+};
+
+static gboolean
+gdict_applet_factory (MatePanelApplet *applet,
+ const gchar *iid,
+ gpointer data)
+{
+ gboolean retval = FALSE;
+
+ if (((!strcmp (iid, "OAFIID:MATE_DictionaryApplet")) ||
+ (!strcmp (iid, "OAFIID:MATE_GDictApplet"))) &&
+ gdict_create_data_dir ())
+ {
+ /* Set up the menu */
+ mate_panel_applet_setup_menu_from_file (applet, UIDATADIR,
+ "MATE_DictionaryApplet.xml",
+ NULL,
+ gdict_applet_menu_verbs,
+ applet);
+
+ gtk_widget_show (GTK_WIDGET (applet));
+
+ /* set the menu items insensitive */
+ gdict_applet_set_menu_items_sensitive (GDICT_APPLET (applet), FALSE);
+
+ retval = TRUE;
+ }
+
+ return retval;
+}
+
+/* this defines the main () for the applet */
+MATE_PANEL_APPLET_MATECOMPONENT_FACTORY ("OAFIID:MATE_DictionaryApplet_Factory",
+ GDICT_TYPE_APPLET,
+ "mate-dictionary-applet",
+ VERSION,
+ gdict_applet_factory,
+ NULL);
+
+#else /* GDICT_APPLET_STAND_ALONE */
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *applet;
+
+ /* gettext stuff */
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+ applet = GTK_WIDGET (g_object_new (GDICT_TYPE_APPLET, NULL));
+ g_message ("(in %s) typeof(applet) = '%s'",
+ G_STRFUNC,
+ g_type_name (G_OBJECT_TYPE (applet)));
+
+ gdict_applet_queue_draw (GDICT_APPLET (applet));
+
+ gtk_container_set_border_width (GTK_CONTAINER (window), 12);
+ gtk_container_add (GTK_CONTAINER (window), applet);
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+
+ return 0;
+}
+
+#endif /* !GDICT_APPLET_STAND_ALONE */
diff --git a/mate-dictionary/src/gdict-applet.h b/mate-dictionary/src/gdict-applet.h
new file mode 100644
index 00000000..48f61c24
--- /dev/null
+++ b/mate-dictionary/src/gdict-applet.h
@@ -0,0 +1,48 @@
+/* gdict-applet.h - MATE Dictionary Applet
+ *
+ * Copyright (c) 2005 Emmanuele Bassi <[email protected]>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __GDICT_APPLET_H__
+#define __GDICT_APPLET_H__
+
+#include <gtk/gtk.h>
+#include <mate-panel-applet.h>
+#include <libgdict/gdict.h>
+
+G_BEGIN_DECLS
+
+#define GDICT_TYPE_APPLET (gdict_applet_get_type ())
+#define GDICT_APPLET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDICT_TYPE_APPLET, GdictApplet))
+#define GDICT_IS_APPLET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDICT_TYPE_APPLET))
+
+typedef struct _GdictApplet GdictApplet;
+typedef struct _GdictAppletClass GdictAppletClass;
+typedef struct _GdictAppletPrivate GdictAppletPrivate;
+
+struct _GdictApplet
+{
+ MatePanelApplet parent_instance;
+
+ GdictAppletPrivate *priv;
+};
+
+GType gdict_applet_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GDICT_APPLET_H__ */
diff --git a/mate-dictionary/src/gdict-common.c b/mate-dictionary/src/gdict-common.c
new file mode 100644
index 00000000..8f106c18
--- /dev/null
+++ b/mate-dictionary/src/gdict-common.c
@@ -0,0 +1,201 @@
+/* gdict-common.h - shared code between application and applet
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include "gdict-common.h"
+
+gchar *
+gdict_get_data_dir (void)
+{
+ gchar *retval;
+
+ retval = g_build_filename (g_get_home_dir (),
+ ".mate2",
+ "mate-dictionary",
+ NULL);
+
+ return retval;
+}
+
+/* create the data directory inside $HOME, if it doesn't exist yet */
+gboolean
+gdict_create_data_dir (void)
+{
+ gchar *data_dir_name;
+
+ data_dir_name = gdict_get_data_dir ();
+ if (g_mkdir (data_dir_name, 0700) == -1)
+ {
+ /* this is weird, but sometimes there's a "mate-dictionary" file
+ * inside $HOME/.mate2; see bug #329126.
+ */
+ if ((errno == EEXIST) &&
+ (g_file_test (data_dir_name, G_FILE_TEST_IS_REGULAR)))
+ {
+ gchar *backup = g_strdup_printf ("%s.pre-2-14", data_dir_name);
+
+ if (g_rename (data_dir_name, backup) == -1)
+ {
+ GtkWidget *error_dialog;
+
+ error_dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("Unable to rename file '%s' to '%s': %s"),
+ data_dir_name,
+ backup,
+ g_strerror (errno));
+
+ gtk_dialog_run (GTK_DIALOG (error_dialog));
+
+ gtk_widget_destroy (error_dialog);
+ g_free (backup);
+ g_free (data_dir_name);
+
+ return FALSE;
+ }
+
+ g_free (backup);
+
+ if (g_mkdir (data_dir_name, 0700) == -1)
+ {
+ GtkWidget *error_dialog;
+
+ error_dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("Unable to create the data directory '%s': %s"),
+ data_dir_name,
+ g_strerror (errno));
+
+ gtk_dialog_run (GTK_DIALOG (error_dialog));
+
+ gtk_widget_destroy (error_dialog);
+ g_free (data_dir_name);
+
+ return FALSE;
+ }
+
+ goto success;
+ }
+
+ if (errno != EEXIST)
+ {
+ GtkWidget *error_dialog;
+
+ error_dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("Unable to create the data directory '%s': %s"),
+ data_dir_name,
+ g_strerror (errno));
+
+ gtk_dialog_run (GTK_DIALOG (error_dialog));
+
+ gtk_widget_destroy (error_dialog);
+ g_free (data_dir_name);
+
+ return FALSE;
+ }
+ }
+
+success:
+ g_free (data_dir_name);
+
+ return TRUE;
+}
+
+/* shows an error dialog making it transient for @parent */
+void
+gdict_show_error_dialog (GtkWindow *parent,
+ const gchar *message,
+ const gchar *detail)
+{
+ GtkWidget *dialog;
+
+ g_return_if_fail ((parent == NULL) || (GTK_IS_WINDOW (parent)));
+ g_return_if_fail (message != NULL);
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "%s", message);
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+
+ if (detail)
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", detail);
+
+ if (parent && gtk_window_get_group (parent))
+ gtk_window_group_add_window (gtk_window_get_group (parent), GTK_WINDOW (dialog));
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (dialog);
+}
+
+void
+gdict_show_gerror_dialog (GtkWindow *parent,
+ const gchar *message,
+ GError *error)
+{
+ g_return_if_fail ((parent == NULL) || (GTK_IS_WINDOW (parent)));
+ g_return_if_fail (message != NULL);
+ g_return_if_fail (error != NULL);
+
+ gdict_show_error_dialog (parent, message, error->message);
+
+ g_error_free (error);
+ error = NULL;
+}
+
+gchar *
+gdict_mateconf_get_string_with_default (MateConfClient *client,
+ const gchar *key,
+ const gchar *def)
+{
+ gchar *val;
+
+ val = mateconf_client_get_string (client, key, NULL);
+ return val ? val : g_strdup (def);
+}
+
diff --git a/mate-dictionary/src/gdict-common.h b/mate-dictionary/src/gdict-common.h
new file mode 100644
index 00000000..f8bc903d
--- /dev/null
+++ b/mate-dictionary/src/gdict-common.h
@@ -0,0 +1,48 @@
+/* gdict-common.h - shared code between application and applet
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GDICT_COMMON_H__
+#define __GDICT_COMMON_H__
+
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+
+G_BEGIN_DECLS
+
+gboolean gdict_create_data_dir (void);
+gchar * gdict_get_data_dir (void) G_GNUC_MALLOC;
+
+void gdict_show_error_dialog (GtkWindow *parent,
+ const gchar *message,
+ const gchar *detail);
+void gdict_show_gerror_dialog (GtkWindow *parent,
+ const gchar *message,
+ GError *error);
+
+gchar * gdict_mateconf_get_string_with_default (MateConfClient *client,
+ const gchar *key,
+ const gchar *def);
+
+
+G_END_DECLS
+
+#endif /* __GDICT_COMMON_H__ */
diff --git a/mate-dictionary/src/gdict-pref-dialog.c b/mate-dictionary/src/gdict-pref-dialog.c
new file mode 100644
index 00000000..24b61980
--- /dev/null
+++ b/mate-dictionary/src/gdict-pref-dialog.c
@@ -0,0 +1,744 @@
+/* gdict-pref-dialog.c - preferences dialog
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <mateconf/mateconf-client.h>
+
+#include "gdict-source-dialog.h"
+#include "gdict-pref-dialog.h"
+#include "gdict-common.h"
+
+#define GDICT_PREFERENCES_UI PKGDATADIR "/mate-dictionary-preferences.ui"
+
+#define DEFAULT_MIN_WIDTH 220
+#define DEFAULT_MIN_HEIGHT 330
+
+/*******************
+ * GdictPrefDialog *
+ *******************/
+
+static GtkWidget *global_dialog = NULL;
+
+enum
+{
+ SOURCES_ACTIVE_COLUMN = 0,
+ SOURCES_NAME_COLUMN,
+ SOURCES_DESCRIPTION_COLUMN,
+
+ SOURCES_N_COLUMNS
+};
+
+struct _GdictPrefDialog
+{
+ GtkDialog parent_instance;
+
+ GtkBuilder *builder;
+
+ MateConfClient *mateconf_client;
+ guint notify_id;
+
+ gchar *active_source;
+ GdictSourceLoader *loader;
+ GtkListStore *sources_list;
+
+ /* direct pointers to widgets */
+ GtkWidget *notebook;
+
+ GtkWidget *sources_view;
+ GtkWidget *sources_add;
+ GtkWidget *sources_remove;
+
+ gchar *print_font;
+ GtkWidget *font_button;
+
+ GtkWidget *help_button;
+ GtkWidget *close_button;
+};
+
+struct _GdictPrefDialogClass
+{
+ GtkDialogClass parent_class;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_SOURCE_LOADER
+};
+
+
+G_DEFINE_TYPE (GdictPrefDialog, gdict_pref_dialog, GTK_TYPE_DIALOG);
+
+
+static gboolean
+select_active_source_name (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GdictPrefDialog *dialog = GDICT_PREF_DIALOG (data);
+ gboolean is_active;
+
+ gtk_tree_model_get (model, iter,
+ SOURCES_ACTIVE_COLUMN, &is_active,
+ -1);
+ if (is_active)
+ {
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->sources_view));
+
+ gtk_tree_selection_select_iter (selection, iter);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+update_sources_view (GdictPrefDialog *dialog)
+{
+ const GSList *sources, *l;
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->sources_view), NULL);
+
+ gtk_list_store_clear (dialog->sources_list);
+
+ /* force update of the sources list */
+ gdict_source_loader_update (dialog->loader);
+
+ sources = gdict_source_loader_get_sources (dialog->loader);
+ for (l = sources; l != NULL; l = l->next)
+ {
+ GdictSource *source = GDICT_SOURCE (l->data);
+ GtkTreeIter iter;
+ const gchar *name, *description;
+ gboolean is_active = FALSE;
+
+ name = gdict_source_get_name (source);
+ description = gdict_source_get_description (source);
+ if (!description)
+ description = name;
+
+ if (strcmp (name, dialog->active_source) == 0)
+ is_active = TRUE;
+
+ gtk_list_store_append (dialog->sources_list, &iter);
+ gtk_list_store_set (dialog->sources_list, &iter,
+ SOURCES_ACTIVE_COLUMN, is_active,
+ SOURCES_NAME_COLUMN, name,
+ SOURCES_DESCRIPTION_COLUMN, description,
+ -1);
+ }
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->sources_view),
+ GTK_TREE_MODEL (dialog->sources_list));
+
+ /* select the currently active source name */
+ gtk_tree_model_foreach (GTK_TREE_MODEL (dialog->sources_list),
+ select_active_source_name,
+ dialog);
+}
+
+static void
+source_renderer_toggled_cb (GtkCellRendererToggle *renderer,
+ const gchar *path,
+ GdictPrefDialog *dialog)
+{
+ GtkTreePath *treepath;
+ GtkTreeIter iter;
+ gboolean res;
+ gboolean is_active;
+ gchar *name;
+
+ treepath = gtk_tree_path_new_from_string (path);
+ res = gtk_tree_model_get_iter (GTK_TREE_MODEL (dialog->sources_list),
+ &iter,
+ treepath);
+ if (!res)
+ {
+ gtk_tree_path_free (treepath);
+
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (dialog->sources_list), &iter,
+ SOURCES_NAME_COLUMN, &name,
+ SOURCES_ACTIVE_COLUMN, &is_active,
+ -1);
+ if (!is_active && name != NULL)
+ {
+ g_free (dialog->active_source);
+ dialog->active_source = g_strdup (name);
+
+ mateconf_client_set_string (dialog->mateconf_client,
+ GDICT_MATECONF_SOURCE_KEY,
+ dialog->active_source,
+ NULL);
+
+ update_sources_view (dialog);
+
+ g_free (name);
+ }
+
+ gtk_tree_path_free (treepath);
+}
+
+static void
+sources_view_row_activated_cb (GtkTreeView *tree_view,
+ GtkTreePath *tree_path,
+ GtkTreeViewColumn *tree_iter,
+ GdictPrefDialog *dialog)
+{
+ GtkWidget *edit_dialog;
+ gchar *source_name;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (tree_view);
+ if (!model)
+ return;
+
+ if (!gtk_tree_model_get_iter (model, &iter, tree_path))
+ return;
+
+ gtk_tree_model_get (model, &iter, SOURCES_NAME_COLUMN, &source_name, -1);
+ if (!source_name)
+ return;
+
+ edit_dialog = gdict_source_dialog_new (GTK_WINDOW (dialog),
+ _("Edit Dictionary Source"),
+ GDICT_SOURCE_DIALOG_EDIT,
+ dialog->loader,
+ source_name);
+ gtk_dialog_run (GTK_DIALOG (edit_dialog));
+
+ gtk_widget_destroy (edit_dialog);
+ g_free (source_name);
+
+ update_sources_view (dialog);
+}
+
+static void
+build_sources_view (GdictPrefDialog *dialog)
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ if (dialog->sources_list)
+ return;
+
+ dialog->sources_list = gtk_list_store_new (SOURCES_N_COLUMNS,
+ G_TYPE_BOOLEAN, /* active */
+ G_TYPE_STRING, /* name */
+ G_TYPE_STRING /* description */);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (dialog->sources_list),
+ SOURCES_DESCRIPTION_COLUMN,
+ GTK_SORT_ASCENDING);
+
+ renderer = gtk_cell_renderer_toggle_new ();
+ gtk_cell_renderer_toggle_set_radio (GTK_CELL_RENDERER_TOGGLE (renderer), TRUE);
+ g_signal_connect (renderer, "toggled",
+ G_CALLBACK (source_renderer_toggled_cb),
+ dialog);
+
+ column = gtk_tree_view_column_new_with_attributes ("active",
+ renderer,
+ "active", SOURCES_ACTIVE_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->sources_view), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("description",
+ renderer,
+ "text", SOURCES_DESCRIPTION_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->sources_view), column);
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dialog->sources_view), FALSE);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->sources_view),
+ GTK_TREE_MODEL (dialog->sources_list));
+
+ g_signal_connect (dialog->sources_view, "row-activated",
+ G_CALLBACK (sources_view_row_activated_cb),
+ dialog);
+}
+
+static void
+source_add_clicked_cb (GtkWidget *widget,
+ GdictPrefDialog *dialog)
+{
+ GtkWidget *add_dialog;
+
+ add_dialog = gdict_source_dialog_new (GTK_WINDOW (dialog),
+ _("Add Dictionary Source"),
+ GDICT_SOURCE_DIALOG_CREATE,
+ dialog->loader,
+ NULL);
+
+ gtk_dialog_run (GTK_DIALOG (add_dialog));
+
+ gtk_widget_destroy (add_dialog);
+
+ update_sources_view (dialog);
+}
+
+static void
+source_remove_clicked_cb (GtkWidget *widget,
+ GdictPrefDialog *dialog)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean is_selected;
+ gchar *name, *description;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->sources_view));
+ if (!selection)
+ return;
+
+ is_selected = gtk_tree_selection_get_selected (selection, &model, &iter);
+ if (!is_selected)
+ return;
+
+ gtk_tree_model_get (model, &iter,
+ SOURCES_NAME_COLUMN, &name,
+ SOURCES_DESCRIPTION_COLUMN, &description,
+ -1);
+ if (!name)
+ return;
+ else
+ {
+ GtkWidget *confirm_dialog;
+ gint response;
+
+ confirm_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE,
+ _("Remove \"%s\"?"), description);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (confirm_dialog),
+ _("This will permanently remove the "
+ "dictionary source from the list."));
+
+ gtk_dialog_add_button (GTK_DIALOG (confirm_dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (confirm_dialog),
+ GTK_STOCK_REMOVE,
+ GTK_RESPONSE_OK);
+
+ gtk_window_set_title (GTK_WINDOW (confirm_dialog), "");
+
+ response = gtk_dialog_run (GTK_DIALOG (confirm_dialog));
+ if (response == GTK_RESPONSE_CANCEL)
+ {
+ gtk_widget_destroy (confirm_dialog);
+
+ goto out;
+ }
+
+ gtk_widget_destroy (confirm_dialog);
+ }
+
+ if (gdict_source_loader_remove_source (dialog->loader, name))
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ else
+ {
+ GtkWidget *error_dialog;
+ gchar *message;
+
+ message = g_strdup_printf (_("Unable to remove source '%s'"),
+ description);
+
+ error_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "%s", message);
+ gtk_window_set_title (GTK_WINDOW (error_dialog), "");
+
+ gtk_dialog_run (GTK_DIALOG (error_dialog));
+
+ gtk_widget_destroy (error_dialog);
+ }
+
+out:
+ g_free (name);
+ g_free (description);
+
+ update_sources_view (dialog);
+}
+
+static void
+set_source_loader (GdictPrefDialog *dialog,
+ GdictSourceLoader *loader)
+{
+ if (!dialog->sources_list)
+ return;
+
+ if (dialog->loader)
+ g_object_unref (dialog->loader);
+
+ dialog->loader = g_object_ref (loader);
+
+ update_sources_view (dialog);
+}
+
+static void
+font_button_font_set_cb (GtkWidget *font_button,
+ GdictPrefDialog *dialog)
+{
+ const gchar *font;
+
+ font = gtk_font_button_get_font_name (GTK_FONT_BUTTON (font_button));
+ if (!font || font[0] == '\0')
+ return;
+
+ if (dialog->print_font && (strcmp (dialog->print_font, font) == 0))
+ return;
+
+ g_free (dialog->print_font);
+ dialog->print_font = g_strdup (font);
+
+ mateconf_client_set_string (dialog->mateconf_client,
+ GDICT_MATECONF_PRINT_FONT_KEY,
+ dialog->print_font,
+ NULL);
+}
+
+static void
+gdict_pref_dialog_mateconf_notify_cb (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ GdictPrefDialog *dialog = GDICT_PREF_DIALOG (user_data);
+
+ if (strcmp (entry->key, GDICT_MATECONF_SOURCE_KEY) == 0)
+ {
+ if (entry->value && entry->value->type == MATECONF_VALUE_STRING)
+ {
+ g_free (dialog->active_source);
+ dialog->active_source = g_strdup (mateconf_value_get_string (entry->value));
+ }
+ else
+ {
+ g_free (dialog->active_source);
+ dialog->active_source = g_strdup (GDICT_DEFAULT_SOURCE_NAME);
+ }
+
+ update_sources_view (dialog);
+ }
+ else if (strcmp (entry->key, GDICT_MATECONF_PRINT_FONT_KEY) == 0)
+ {
+ if (entry->value && entry->value->type == MATECONF_VALUE_STRING)
+ {
+ g_free (dialog->print_font);
+ dialog->print_font = g_strdup (mateconf_value_get_string (entry->value));
+ }
+ else
+ {
+ g_free (dialog->print_font);
+ dialog->print_font = g_strdup (GDICT_DEFAULT_PRINT_FONT);
+ }
+
+ gtk_font_button_set_font_name (GTK_FONT_BUTTON (dialog->font_button),
+ dialog->print_font);
+ }
+}
+
+static void
+response_cb (GtkDialog *dialog,
+ gint response_id,
+ gpointer user_data)
+{
+ GError *err = NULL;
+
+ switch (response_id)
+ {
+ case GTK_RESPONSE_HELP:
+ gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (dialog)),
+ "ghelp:mate-dictionary#mate-dictionary-preferences",
+ gtk_get_current_event_time (), &err);
+ if (err)
+ {
+ GtkWidget *error_dialog;
+ gchar *message;
+
+ message = g_strdup_printf (_("There was an error while displaying help"));
+ error_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "%s", message);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog),
+ "%s", err->message);
+ gtk_window_set_title (GTK_WINDOW (error_dialog), "");
+
+ gtk_dialog_run (GTK_DIALOG (error_dialog));
+
+ gtk_widget_destroy (error_dialog);
+ g_error_free (err);
+ }
+
+ /* we don't want the dialog to close itself */
+ g_signal_stop_emission_by_name (dialog, "response");
+ break;
+ case GTK_RESPONSE_ACCEPT:
+ default:
+ gtk_widget_hide (GTK_WIDGET (dialog));
+ break;
+ }
+}
+
+static void
+gdict_pref_dialog_finalize (GObject *object)
+{
+ GdictPrefDialog *dialog = GDICT_PREF_DIALOG (object);
+
+ if (dialog->notify_id);
+ mateconf_client_notify_remove (dialog->mateconf_client, dialog->notify_id);
+
+ if (dialog->mateconf_client)
+ g_object_unref (dialog->mateconf_client);
+
+ if (dialog->builder)
+ g_object_unref (dialog->builder);
+
+ if (dialog->active_source)
+ g_free (dialog->active_source);
+
+ if (dialog->loader)
+ g_object_unref (dialog->loader);
+
+ G_OBJECT_CLASS (gdict_pref_dialog_parent_class)->finalize (object);
+}
+
+static void
+gdict_pref_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdictPrefDialog *dialog = GDICT_PREF_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE_LOADER:
+ set_source_loader (dialog, g_value_get_object (value));
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gdict_pref_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdictPrefDialog *dialog = GDICT_PREF_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE_LOADER:
+ g_value_set_object (value, dialog->loader);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gdict_pref_dialog_class_init (GdictPrefDialogClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = gdict_pref_dialog_set_property;
+ gobject_class->get_property = gdict_pref_dialog_get_property;
+ gobject_class->finalize = gdict_pref_dialog_finalize;
+
+ g_object_class_install_property (gobject_class,
+ PROP_SOURCE_LOADER,
+ g_param_spec_object ("source-loader",
+ "Source Loader",
+ "The GdictSourceLoader used by the application",
+ GDICT_TYPE_SOURCE_LOADER,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+}
+
+static void
+gdict_pref_dialog_init (GdictPrefDialog *dialog)
+{
+ gchar *font;
+ GError *error = NULL;
+
+ gtk_window_set_default_size (GTK_WINDOW (dialog),
+ DEFAULT_MIN_WIDTH,
+ DEFAULT_MIN_HEIGHT);
+
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+ /* add buttons */
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ "gtk-help",
+ GTK_RESPONSE_HELP);
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ "gtk-close",
+ GTK_RESPONSE_ACCEPT);
+
+ dialog->mateconf_client = mateconf_client_get_default ();
+ mateconf_client_add_dir (dialog->mateconf_client,
+ GDICT_MATECONF_DIR,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+ dialog->notify_id = mateconf_client_notify_add (dialog->mateconf_client,
+ GDICT_MATECONF_DIR,
+ gdict_pref_dialog_mateconf_notify_cb,
+ dialog,
+ NULL,
+ NULL);
+
+ /* get the UI from the GtkBuilder file */
+ dialog->builder = gtk_builder_new ();
+ gtk_builder_add_from_file (dialog->builder, GDICT_PREFERENCES_UI, &error);
+
+ if (error) {
+ g_critical ("Unable to load the preferences user interface: %s", error->message);
+ g_error_free (error);
+ g_assert_not_reached ();
+ }
+
+ /* the main widget */
+ gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+ GTK_WIDGET (gtk_builder_get_object (dialog->builder, "preferences_root")));
+
+ /* keep all the interesting widgets around */
+ dialog->notebook = GTK_WIDGET (gtk_builder_get_object (dialog->builder, "preferences_notebook"));
+
+ dialog->sources_view = GTK_WIDGET (gtk_builder_get_object (dialog->builder, "sources_treeview"));
+ build_sources_view (dialog);
+
+ dialog->active_source = gdict_mateconf_get_string_with_default (dialog->mateconf_client,
+ GDICT_MATECONF_SOURCE_KEY,
+ GDICT_DEFAULT_SOURCE_NAME);
+
+ dialog->sources_add = GTK_WIDGET (gtk_builder_get_object (dialog->builder, "add_button"));
+ gtk_widget_set_tooltip_text (dialog->sources_add,
+ _("Add a new dictionary source"));
+ g_signal_connect (dialog->sources_add, "clicked",
+ G_CALLBACK (source_add_clicked_cb), dialog);
+
+ dialog->sources_remove = GTK_WIDGET (gtk_builder_get_object (dialog->builder, "remove_button"));
+ gtk_widget_set_tooltip_text (dialog->sources_remove,
+ _("Remove the currently selected dictionary source"));
+ g_signal_connect (dialog->sources_remove, "clicked",
+ G_CALLBACK (source_remove_clicked_cb), dialog);
+
+ font = mateconf_client_get_string (dialog->mateconf_client,
+ GDICT_MATECONF_PRINT_FONT_KEY,
+ NULL);
+ if (!font)
+ font = g_strdup (GDICT_DEFAULT_PRINT_FONT);
+
+ dialog->font_button = GTK_WIDGET (gtk_builder_get_object (dialog->builder, "print_font_button"));
+ gtk_font_button_set_font_name (GTK_FONT_BUTTON (dialog->font_button), font);
+ gtk_widget_set_tooltip_text (dialog->font_button,
+ _("Set the font used for printing the definitions"));
+ g_signal_connect (dialog->font_button, "font-set",
+ G_CALLBACK (font_button_font_set_cb), dialog);
+ g_free (font);
+
+ gtk_widget_show_all (dialog->notebook);
+
+ /* we want to intercept the response signal before any other
+ * callbacks might be attached by the users of the
+ * GdictPrefDialog widget.
+ */
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (response_cb),
+ NULL);
+}
+
+void
+gdict_show_pref_dialog (GtkWidget *parent,
+ const gchar *title,
+ GdictSourceLoader *loader)
+{
+ GtkWidget *dialog;
+
+ g_return_if_fail (GTK_IS_WIDGET (parent));
+ g_return_if_fail (GDICT_IS_SOURCE_LOADER (loader));
+
+ if (parent)
+ dialog = g_object_get_data (G_OBJECT (parent), "gdict-pref-dialog");
+ else
+ dialog = global_dialog;
+
+ if (!dialog)
+ {
+ dialog = g_object_new (GDICT_TYPE_PREF_DIALOG,
+ "source-loader", loader,
+ "title", title,
+ NULL);
+
+ g_object_ref_sink (dialog);
+
+ g_signal_connect (dialog, "delete-event",
+ G_CALLBACK (gtk_widget_hide_on_delete),
+ NULL);
+
+ if (parent && GTK_IS_WINDOW (parent))
+ {
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent));
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+ g_object_set_data_full (G_OBJECT (parent), "gdict-pref-dialog",
+ dialog,
+ g_object_unref);
+ }
+ else
+ global_dialog = dialog;
+ }
+
+ gtk_window_set_screen (GTK_WINDOW (dialog),
+ gtk_widget_get_screen (parent));
+ gtk_window_present (GTK_WINDOW (dialog));
+}
diff --git a/mate-dictionary/src/gdict-pref-dialog.h b/mate-dictionary/src/gdict-pref-dialog.h
new file mode 100644
index 00000000..7cae7e57
--- /dev/null
+++ b/mate-dictionary/src/gdict-pref-dialog.h
@@ -0,0 +1,65 @@
+/* gdict-pref-dialog.h - preferences dialog
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GDICT_PREF_DIALOG_H__
+#define __GDICT_PREF_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include <libgdict/gdict.h>
+
+G_BEGIN_DECLS
+
+#define GDICT_TYPE_PREF_DIALOG (gdict_pref_dialog_get_type ())
+#define GDICT_PREF_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDICT_TYPE_PREF_DIALOG, GdictPrefDialog))
+#define GDICT_IS_PREF_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDICT_TYPE_PREF_DIALOG))
+
+#define GDICT_DEFAULT_DEFBOX_FONT "Sans 10"
+#define GDICT_DEFAULT_PRINT_FONT "Serif 10"
+#define GDICT_DEFAULT_SOURCE_NAME "Default"
+
+#define GDICT_MATECONF_DIR "/apps/mate-dictionary"
+#define GDICT_MATECONF_DATABASE_KEY GDICT_MATECONF_DIR "/database"
+#define GDICT_MATECONF_STRATEGY_KEY GDICT_MATECONF_DIR "/strategy"
+#define GDICT_MATECONF_PRINT_FONT_KEY GDICT_MATECONF_DIR "/print-font"
+#define GDICT_MATECONF_SOURCE_KEY GDICT_MATECONF_DIR "/source-name"
+#define GDICT_MATECONF_WINDOW_WIDTH_KEY GDICT_MATECONF_DIR "/default-window-width"
+#define GDICT_MATECONF_WINDOW_HEIGHT_KEY GDICT_MATECONF_DIR "/default-window-height"
+#define GDICT_MATECONF_WINDOW_IS_MAXIMIZED_KEY GDICT_MATECONF_DIR "/window-is-maximized"
+#define GDICT_MATECONF_SIDEBAR_VISIBLE_KEY GDICT_MATECONF_DIR "/sidebar-visible"
+#define GDICT_MATECONF_SIDEBAR_PAGE_KEY GDICT_MATECONF_DIR "/sidebar-page"
+#define GDICT_MATECONF_SIDEBAR_WIDTH_KEY GDICT_MATECONF_DIR "/sidebar-width"
+#define GDICT_MATECONF_STATUSBAR_VISIBLE_KEY GDICT_MATECONF_DIR "/statusbar-visible"
+
+#define DOCUMENT_FONT_KEY "/desktop/mate/interface/document_font_name"
+
+typedef struct _GdictPrefDialog GdictPrefDialog;
+typedef struct _GdictPrefDialogClass GdictPrefDialogClass;
+
+GType gdict_pref_dialog_get_type (void) G_GNUC_CONST;
+
+void gdict_show_pref_dialog (GtkWidget *parent,
+ const gchar *title,
+ GdictSourceLoader *loader);
+
+G_END_DECLS
+
+#endif /* __GDICT_PREF_DIALOG_H__ */
diff --git a/mate-dictionary/src/gdict-print.c b/mate-dictionary/src/gdict-print.c
new file mode 100644
index 00000000..855dbab6
--- /dev/null
+++ b/mate-dictionary/src/gdict-print.c
@@ -0,0 +1,322 @@
+/* gdict-print.c - print-related helper functions
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include <mateconf/mateconf-client.h>
+
+#include <libgdict/gdict.h>
+
+#include "gdict-pref-dialog.h"
+#include "gdict-print.h"
+
+#define HEADER_HEIGHT(lines) ((lines) * 72 / 25.4)
+#define HEADER_GAP(lines) ((lines) * 72 / 25.4)
+
+typedef struct _GdictPrintData
+{
+ GdictDefbox *defbox;
+ gchar *word;
+
+ PangoFontDescription *font_desc;
+ gdouble font_size;
+
+ gchar **lines;
+
+ gint n_lines;
+ gint lines_per_page;
+ gint n_pages;
+} GdictPrintData;
+
+static void
+begin_print (GtkPrintOperation *operation,
+ GtkPrintContext *context,
+ gpointer user_data)
+{
+ GdictPrintData *data = user_data;
+ gchar *contents;
+ gdouble height;
+
+ height = gtk_print_context_get_height (context)
+ - HEADER_HEIGHT (10)
+ - HEADER_GAP (3);
+
+ contents = gdict_defbox_get_text (data->defbox, NULL);
+
+ data->lines = g_strsplit (contents, "\n", 0);
+ data->n_lines = g_strv_length (data->lines);
+ data->lines_per_page = floor (height / data->font_size);
+
+ data->n_pages = (data->n_lines - 1) / data->lines_per_page + 1;
+
+ gtk_print_operation_set_n_pages (operation, data->n_pages);
+
+ g_free (contents);
+}
+
+static void
+draw_page (GtkPrintOperation *operation,
+ GtkPrintContext *context,
+ gint page_number,
+ gpointer user_data)
+{
+ GdictPrintData *data = user_data;
+ cairo_t *cr;
+ PangoLayout *layout;
+ gint text_width, text_height;
+ gdouble width;
+ gint line, i;
+ PangoFontDescription *desc;
+ gchar *page_str;
+
+ cr = gtk_print_context_get_cairo_context (context);
+ width = gtk_print_context_get_width (context);
+
+ cairo_rectangle (cr, 0, 0, width, HEADER_HEIGHT (10));
+
+ cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
+ cairo_fill_preserve (cr);
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_set_line_width (cr, 1);
+ cairo_stroke (cr);
+
+ /* header */
+ layout = gtk_print_context_create_pango_layout (context);
+
+ desc = pango_font_description_from_string ("sans 14");
+ pango_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+
+ pango_layout_set_text (layout, data->word, -1);
+ pango_layout_get_pixel_size (layout, &text_width, &text_height);
+
+ if (text_width > width)
+ {
+ pango_layout_set_width (layout, width);
+ pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_START);
+ pango_layout_get_pixel_size (layout, &text_width, &text_height);
+ }
+
+ cairo_move_to (cr, (width - text_width) / 2,
+ (HEADER_HEIGHT (10) - text_height) / 2);
+ pango_cairo_show_layout (cr, layout);
+
+ page_str = g_strdup_printf ("%d/%d", page_number + 1, data->n_pages);
+ pango_layout_set_text (layout, page_str, -1);
+ g_free (page_str);
+
+ pango_layout_set_width (layout, -1);
+ pango_layout_get_pixel_size (layout, &text_width, &text_height);
+ cairo_move_to (cr, width - text_width - 4,
+ (HEADER_HEIGHT (10) - text_height) / 2);
+ pango_cairo_show_layout (cr, layout);
+
+ g_object_unref (layout);
+
+ /* text */
+ layout = gtk_print_context_create_pango_layout (context);
+ pango_font_description_set_size (data->font_desc,
+ data->font_size * PANGO_SCALE);
+ pango_layout_set_font_description (layout, data->font_desc);
+
+ cairo_move_to (cr, 0, HEADER_HEIGHT (10) + HEADER_GAP (3));
+ line = page_number * data->lines_per_page;
+ for (i = 0; i < data->lines_per_page && line < data->n_lines; i++)
+ {
+ pango_layout_set_text (layout, data->lines[line], -1);
+
+ pango_cairo_show_layout (cr, layout);
+ cairo_rel_move_to (cr, 0, data->font_size);
+ line++;
+ }
+
+ g_object_unref (layout);
+}
+
+static void
+end_print (GtkPrintOperation *operation,
+ GtkPrintContext *context,
+ gpointer user_data)
+{
+ GdictPrintData *data = user_data;
+
+ pango_font_description_free (data->font_desc);
+ g_free (data->word);
+ g_strfreev (data->lines);
+ g_free (data);
+}
+
+static gchar *
+get_print_font (void)
+{
+ MateConfClient *client;
+ gchar *print_font;
+
+ client = mateconf_client_get_default ();
+ print_font = mateconf_client_get_string (client,
+ GDICT_MATECONF_PRINT_FONT_KEY,
+ NULL);
+ if (!print_font)
+ print_font = g_strdup (GDICT_DEFAULT_PRINT_FONT);
+
+ g_object_unref (client);
+
+ return print_font;
+}
+
+void
+gdict_show_print_preview (GtkWindow *parent,
+ GdictDefbox *defbox)
+{
+ GtkPrintOperation *operation;
+ GdictPrintData *data;
+ gchar *print_font;
+ gchar *word;
+ GError *error;
+
+ g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
+ g_return_if_fail (GDICT_IS_DEFBOX (defbox));
+
+ g_object_get (defbox, "word", &word, NULL);
+ if (!word)
+ {
+ g_warning ("Preview should be disabled.");
+ return;
+ }
+
+ data = g_new0 (GdictPrintData, 1);
+ data->defbox = defbox;
+ data->word = word;
+
+ operation = gtk_print_operation_new ();
+ print_font = get_print_font ();
+ data->font_desc = pango_font_description_from_string (print_font);
+ data->font_size = pango_font_description_get_size (data->font_desc)
+ / PANGO_SCALE;
+ g_free (print_font);
+
+ g_signal_connect (operation, "begin-print",
+ G_CALLBACK (begin_print), data);
+ g_signal_connect (operation, "draw-page",
+ G_CALLBACK (draw_page), data);
+ g_signal_connect (operation, "end-print",
+ G_CALLBACK (end_print), data);
+
+ error = NULL;
+ gtk_print_operation_run (operation,
+ GTK_PRINT_OPERATION_ACTION_PREVIEW,
+ parent,
+ &error);
+ g_object_unref (operation);
+
+ if (error)
+ {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("Unable to display the preview: %s"),
+ error->message);
+ g_error_free (error);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (dialog);
+ }
+}
+
+void
+gdict_show_print_dialog (GtkWindow *parent,
+ GdictDefbox *defbox)
+{
+ GtkPrintOperation *operation;
+ GdictPrintData *data;
+ gchar *print_font;
+ gchar *word;
+ GError *error;
+
+ g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
+ g_return_if_fail (GDICT_IS_DEFBOX (defbox));
+
+ g_object_get (defbox, "word", &word, NULL);
+ if (!word)
+ {
+ g_warning ("Print should be disabled.");
+ return;
+ }
+
+ data = g_new0 (GdictPrintData, 1);
+ data->defbox = defbox;
+ data->word = word;
+
+ operation = gtk_print_operation_new ();
+ print_font = get_print_font ();
+ data->font_desc = pango_font_description_from_string (print_font);
+ data->font_size = pango_font_description_get_size (data->font_desc)
+ / PANGO_SCALE;
+ g_free (print_font);
+
+ g_signal_connect (operation, "begin-print",
+ G_CALLBACK (begin_print), data);
+ g_signal_connect (operation, "draw-page",
+ G_CALLBACK (draw_page), data);
+ g_signal_connect (operation, "end-print",
+ G_CALLBACK (end_print), data);
+
+ error = NULL;
+ gtk_print_operation_run (operation,
+ GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+ parent,
+ &error);
+ g_object_unref (operation);
+
+ if (error)
+ {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("Unable to display the preview: %s"),
+ error->message);
+ g_error_free (error);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (dialog);
+ }
+}
diff --git a/mate-dictionary/src/gdict-print.h b/mate-dictionary/src/gdict-print.h
new file mode 100644
index 00000000..5c0fe25f
--- /dev/null
+++ b/mate-dictionary/src/gdict-print.h
@@ -0,0 +1,38 @@
+/* gdict-print.h - print-related helper functions
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GDICT_PRINT_H__
+#define __GDICT_PRINT_H__
+
+#include <gtk/gtk.h>
+#include <libgdict/gdict-defbox.h>
+
+G_BEGIN_DECLS
+
+void gdict_show_print_preview (GtkWindow *parent,
+ GdictDefbox *defbox);
+void gdict_show_print_dialog (GtkWindow *parent,
+ GdictDefbox *defbox);
+
+G_END_DECLS
+
+#endif /* __GDICT_PRINT_H__ */
diff --git a/mate-dictionary/src/gdict-sidebar.c b/mate-dictionary/src/gdict-sidebar.c
new file mode 100644
index 00000000..c8f51be0
--- /dev/null
+++ b/mate-dictionary/src/gdict-sidebar.c
@@ -0,0 +1,568 @@
+/* gdict-sidebar.c - sidebar widget
+ *
+ * Copyright (C) 2006 Emmanuele Bassi <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Based on the equivalent widget from Evince
+ * by Jonathan Blandford,
+ * Copyright (C) 2004 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "gdict-sidebar.h"
+
+typedef struct
+{
+ guint index;
+
+ gchar *id;
+ gchar *name;
+
+ GtkWidget *child;
+ GtkWidget *menu_item;
+} SidebarPage;
+
+#define GDICT_SIDEBAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GDICT_TYPE_SIDEBAR, GdictSidebarPrivate))
+
+struct _GdictSidebarPrivate
+{
+ GHashTable *pages_by_id;
+ GSList *pages;
+
+ GtkWidget *hbox;
+ GtkWidget *notebook;
+ GtkWidget *menu;
+ GtkWidget *close_button;
+ GtkWidget *label;
+ GtkWidget *select_button;
+};
+
+enum
+{
+ PAGE_CHANGED,
+ CLOSED,
+
+ LAST_SIGNAL
+};
+
+static guint sidebar_signals[LAST_SIGNAL] = { 0 };
+static GQuark sidebar_page_id_quark = 0;
+
+G_DEFINE_TYPE (GdictSidebar, gdict_sidebar, GTK_TYPE_VBOX);
+
+SidebarPage *
+sidebar_page_new (const gchar *id,
+ const gchar *name,
+ GtkWidget *widget)
+{
+ SidebarPage *page;
+
+ page = g_slice_new (SidebarPage);
+
+ page->id = g_strdup (id);
+ page->name = g_strdup (name);
+ page->child = widget;
+ page->index = -1;
+ page->menu_item = NULL;
+
+ return page;
+}
+
+void
+sidebar_page_free (SidebarPage *page)
+{
+ if (G_LIKELY (page))
+ {
+ g_free (page->name);
+ g_free (page->id);
+
+ g_slice_free (SidebarPage, page);
+ }
+}
+
+static void
+gdict_sidebar_finalize (GObject *object)
+{
+ GdictSidebar *sidebar = GDICT_SIDEBAR (object);
+ GdictSidebarPrivate *priv = sidebar->priv;
+
+ if (priv->pages_by_id)
+ g_hash_table_destroy (priv->pages_by_id);
+
+ if (priv->pages)
+ {
+ g_slist_foreach (priv->pages, (GFunc) sidebar_page_free, NULL);
+ g_slist_free (priv->pages);
+ }
+
+ G_OBJECT_CLASS (gdict_sidebar_parent_class)->finalize (object);
+}
+
+static void
+gdict_sidebar_dispose (GObject *object)
+{
+ GdictSidebar *sidebar = GDICT_SIDEBAR (object);
+
+ if (sidebar->priv->menu)
+ {
+ gtk_menu_detach (GTK_MENU (sidebar->priv->menu));
+ sidebar->priv->menu = NULL;
+ }
+
+ G_OBJECT_CLASS (gdict_sidebar_parent_class)->dispose (object);
+}
+
+static void
+gdict_sidebar_menu_position_function (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ GtkWidget *widget;
+ GtkAllocation allocation;
+
+ g_assert (GTK_IS_BUTTON (user_data));
+
+ widget = GTK_WIDGET (user_data);
+
+ gdk_window_get_origin (gtk_widget_get_window (widget), x, y);
+
+ gtk_widget_get_allocation (widget, &allocation);
+ *x += allocation.x;
+ *y += allocation.y + allocation.height;
+
+ *push_in = FALSE;
+}
+
+static gboolean
+gdict_sidebar_select_button_press_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ GdictSidebar *sidebar = GDICT_SIDEBAR (user_data);
+ GtkAllocation allocation;
+
+ if (event->button == 1)
+ {
+ GtkRequisition req;
+ gint width;
+
+ gtk_widget_get_allocation (widget, &allocation);
+ width = allocation.width;
+ gtk_widget_set_size_request (sidebar->priv->menu, -1, -1);
+ gtk_widget_size_request (sidebar->priv->menu, &req);
+ gtk_widget_set_size_request (sidebar->priv->menu,
+ MAX (width, req.width), -1);
+ gtk_widget_grab_focus (widget);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+ gtk_menu_popup (GTK_MENU (sidebar->priv->menu),
+ NULL, NULL,
+ gdict_sidebar_menu_position_function, widget,
+ event->button, event->time);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gdict_sidebar_select_key_press_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+ GdictSidebar *sidebar = GDICT_SIDEBAR (user_data);
+
+ if (event->keyval == GDK_space ||
+ event->keyval == GDK_KP_Space ||
+ event->keyval == GDK_Return ||
+ event->keyval == GDK_KP_Enter)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+ gtk_menu_popup (GTK_MENU (sidebar->priv->menu),
+ NULL, NULL,
+ gdict_sidebar_menu_position_function, widget,
+ 1, event->time);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+gdict_sidebar_close_clicked_cb (GtkWidget *widget,
+ gpointer user_data)
+{
+ GdictSidebar *sidebar = GDICT_SIDEBAR (user_data);
+
+ g_signal_emit (sidebar, sidebar_signals[CLOSED], 0);
+}
+
+static void
+gdict_sidebar_menu_deactivate_cb (GtkWidget *widget,
+ gpointer user_data)
+{
+ GdictSidebar *sidebar = GDICT_SIDEBAR (user_data);
+ GdictSidebarPrivate *priv = sidebar->priv;
+ GtkToggleButton *select_button = GTK_TOGGLE_BUTTON (priv->select_button);
+
+ gtk_toggle_button_set_active (select_button, FALSE);
+}
+
+static void
+gdict_sidebar_menu_detach_cb (GtkWidget *widget,
+ GtkMenu *menu)
+{
+ GdictSidebar *sidebar = GDICT_SIDEBAR (widget);
+
+ sidebar->priv->menu = NULL;
+}
+
+static void
+gdict_sidebar_menu_item_activate (GtkWidget *widget,
+ gpointer user_data)
+{
+ GdictSidebar *sidebar = GDICT_SIDEBAR (user_data);
+ GdictSidebarPrivate *priv = sidebar->priv;
+ GtkWidget *menu_item;
+ const gchar *id;
+ SidebarPage *page;
+ gint current_index;
+
+ menu_item = gtk_menu_get_active (GTK_MENU (priv->menu));
+ id = g_object_get_qdata (G_OBJECT (menu_item), sidebar_page_id_quark);
+ g_assert (id != NULL);
+
+ page = g_hash_table_lookup (priv->pages_by_id, id);
+ g_assert (page != NULL);
+
+ current_index = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+ if (current_index == page->index)
+ return;
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook),
+ page->index);
+ gtk_label_set_text (GTK_LABEL (priv->label), page->name);
+
+ g_signal_emit (sidebar, sidebar_signals[PAGE_CHANGED], 0);
+}
+
+static void
+gdict_sidebar_class_init (GdictSidebarClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (gobject_class, sizeof (GdictSidebarPrivate));
+
+ sidebar_page_id_quark = g_quark_from_static_string ("gdict-sidebar-page-id");
+
+ gobject_class->finalize = gdict_sidebar_finalize;
+ gobject_class->dispose = gdict_sidebar_dispose;
+
+ sidebar_signals[PAGE_CHANGED] =
+ g_signal_new ("page-changed",
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdictSidebarClass, page_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ sidebar_signals[CLOSED] =
+ g_signal_new ("closed",
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdictSidebarClass, closed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+gdict_sidebar_init (GdictSidebar *sidebar)
+{
+ GdictSidebarPrivate *priv;
+ GtkWidget *hbox;
+ GtkWidget *select_hbox;
+ GtkWidget *select_button;
+ GtkWidget *close_button;
+ GtkWidget *arrow;
+
+ sidebar->priv = priv = GDICT_SIDEBAR_GET_PRIVATE (sidebar);
+
+ /* we store all the pages inside the list, but we keep
+ * a pointer inside the hash table for faster look up
+ * times; what's inside the table will be destroyed with
+ * the list, so there's no need to supply the destroy
+ * functions for keys and values.
+ */
+ priv->pages = NULL;
+ priv->pages_by_id = g_hash_table_new (g_str_hash, g_str_equal);
+
+ /* top option menu */
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (sidebar), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+ priv->hbox = hbox;
+
+ select_button = gtk_toggle_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (select_button), GTK_RELIEF_NONE);
+ g_signal_connect (select_button, "button-press-event",
+ G_CALLBACK (gdict_sidebar_select_button_press_cb),
+ sidebar);
+ g_signal_connect (select_button, "key-press-event",
+ G_CALLBACK (gdict_sidebar_select_key_press_cb),
+ sidebar);
+ priv->select_button = select_button;
+
+ select_hbox = gtk_hbox_new (FALSE, 0);
+
+ priv->label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (select_hbox), priv->label, FALSE, FALSE, 0);
+ gtk_widget_show (priv->label);
+
+ arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+ gtk_box_pack_end (GTK_BOX (select_hbox), arrow, FALSE, FALSE, 0);
+ gtk_widget_show (arrow);
+
+ gtk_container_add (GTK_CONTAINER (select_button), select_hbox);
+ gtk_widget_show (select_hbox);
+
+ gtk_box_pack_start (GTK_BOX (hbox), select_button, TRUE, TRUE, 0);
+ gtk_widget_show (select_button);
+
+ close_button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
+ gtk_button_set_image (GTK_BUTTON (close_button),
+ gtk_image_new_from_stock (GTK_STOCK_CLOSE,
+ GTK_ICON_SIZE_SMALL_TOOLBAR));
+ g_signal_connect (close_button, "clicked",
+ G_CALLBACK (gdict_sidebar_close_clicked_cb),
+ sidebar);
+ gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
+ gtk_widget_show (close_button);
+ priv->close_button = close_button;
+
+ sidebar->priv->menu = gtk_menu_new ();
+ g_signal_connect (sidebar->priv->menu, "deactivate",
+ G_CALLBACK (gdict_sidebar_menu_deactivate_cb),
+ sidebar);
+ gtk_menu_attach_to_widget (GTK_MENU (sidebar->priv->menu),
+ GTK_WIDGET (sidebar),
+ gdict_sidebar_menu_detach_cb);
+ gtk_widget_show (sidebar->priv->menu);
+
+ sidebar->priv->notebook = gtk_notebook_new ();
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (sidebar->priv->notebook), FALSE);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (sidebar->priv->notebook), FALSE);
+ gtk_box_pack_start (GTK_BOX (sidebar), sidebar->priv->notebook, TRUE, TRUE, 6);
+ gtk_widget_show (sidebar->priv->notebook);
+}
+
+/*
+ * Public API
+ */
+
+GtkWidget *
+gdict_sidebar_new (void)
+{
+ return g_object_new (GDICT_TYPE_SIDEBAR, NULL);
+}
+
+void
+gdict_sidebar_add_page (GdictSidebar *sidebar,
+ const gchar *page_id,
+ const gchar *page_name,
+ GtkWidget *page_widget)
+{
+ GdictSidebarPrivate *priv;
+ SidebarPage *page;
+ GtkWidget *menu_item;
+
+ g_return_if_fail (GDICT_IS_SIDEBAR (sidebar));
+ g_return_if_fail (page_id != NULL);
+ g_return_if_fail (page_name != NULL);
+ g_return_if_fail (GTK_IS_WIDGET (page_widget));
+
+ priv = sidebar->priv;
+
+ if (g_hash_table_lookup (priv->pages_by_id, page_id))
+ {
+ g_warning ("Attempting to add a page to the sidebar with "
+ "id `%s', but there already is a page with the "
+ "same id. Aborting...",
+ page_id);
+ return;
+ }
+
+ /* add the page inside the page list */
+ page = sidebar_page_new (page_id, page_name, page_widget);
+
+ priv->pages = g_slist_append (priv->pages, page);
+ g_hash_table_insert (priv->pages_by_id, page->id, page);
+
+ page->index = gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
+ page_widget,
+ NULL);
+
+ /* add the menu item for the page */
+ menu_item = gtk_image_menu_item_new_with_label (page_name);
+ g_object_set_qdata_full (G_OBJECT (menu_item),
+ sidebar_page_id_quark,
+ g_strdup (page_id),
+ (GDestroyNotify) g_free);
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (gdict_sidebar_menu_item_activate),
+ sidebar);
+ gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
+ gtk_widget_show (menu_item);
+ page->menu_item = menu_item;
+
+ gtk_menu_shell_select_item (GTK_MENU_SHELL (priv->menu), menu_item);
+ gtk_label_set_text (GTK_LABEL (priv->label), page_name);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), page->index);
+}
+
+void
+gdict_sidebar_remove_page (GdictSidebar *sidebar,
+ const gchar *page_id)
+{
+ GdictSidebarPrivate *priv;
+ SidebarPage *page;
+ GList *children, *l;
+
+ g_return_if_fail (GDICT_IS_SIDEBAR (sidebar));
+ g_return_if_fail (page_id != NULL);
+
+ priv = sidebar->priv;
+
+ if ((page = g_hash_table_lookup (priv->pages_by_id, page_id)) == NULL)
+ {
+ g_warning ("Attempting to remove a page from the sidebar with "
+ "id `%s', but there is no page with this id. Aborting...",
+ page_id);
+ return;
+ }
+
+ children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
+ for (l = children; l != NULL; l = l->next)
+ {
+ GtkWidget *menu_item = l->data;
+
+ if (menu_item == page->menu_item)
+ {
+ gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
+ break;
+ }
+ }
+ g_list_free (children);
+
+ gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook), page->index);
+
+ g_hash_table_remove (priv->pages_by_id, page->id);
+ priv->pages = g_slist_remove (priv->pages, page);
+
+ sidebar_page_free (page);
+
+ /* select the first page, if present */
+ page = priv->pages->data;
+ if (page)
+ {
+ gtk_menu_shell_select_item (GTK_MENU_SHELL (priv->menu), page->menu_item);
+ gtk_label_set_text (GTK_LABEL (priv->label), page->name);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), page->index);
+ }
+ else
+ gtk_widget_hide (GTK_WIDGET (sidebar));
+}
+
+void
+gdict_sidebar_view_page (GdictSidebar *sidebar,
+ const gchar *page_id)
+{
+ GdictSidebarPrivate *priv;
+ SidebarPage *page;
+
+ g_return_if_fail (GDICT_IS_SIDEBAR (sidebar));
+ g_return_if_fail (page_id != NULL);
+
+ priv = sidebar->priv;
+ page = g_hash_table_lookup (priv->pages_by_id, page_id);
+ if (!page)
+ return;
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), page->index);
+ gtk_label_set_text (GTK_LABEL (priv->label), page->name);
+ gtk_menu_shell_select_item (GTK_MENU_SHELL (priv->menu), page->menu_item);
+}
+
+const gchar *
+gdict_sidebar_current_page (GdictSidebar *sidebar)
+{
+ GdictSidebarPrivate *priv;
+ gint index;
+ SidebarPage *page;
+
+ g_return_val_if_fail (GDICT_IS_SIDEBAR (sidebar), NULL);
+
+ priv = sidebar->priv;
+
+ index = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+ page = g_slist_nth_data (priv->pages, index);
+ g_assert (page != NULL);
+
+ return page->id;
+}
+
+gchar **
+gdict_sidebar_list_pages (GdictSidebar *sidebar,
+ gsize *length)
+{
+ GdictSidebarPrivate *priv;
+ gchar **retval;
+ gint i;
+ GSList *l;
+
+ g_return_val_if_fail (GDICT_IS_SIDEBAR (sidebar), NULL);
+
+ priv = sidebar->priv;
+
+ retval = g_new (gchar*, g_slist_length (priv->pages) + 1);
+ for (l = priv->pages, i = 0; l; l = l->next, i++)
+ retval[i++] = g_strdup (l->data);
+
+ retval[i] = NULL;
+
+ if (length)
+ *length = i;
+
+ return retval;
+}
diff --git a/mate-dictionary/src/gdict-sidebar.h b/mate-dictionary/src/gdict-sidebar.h
new file mode 100644
index 00000000..82fa5c4c
--- /dev/null
+++ b/mate-dictionary/src/gdict-sidebar.h
@@ -0,0 +1,75 @@
+/* gdict-sidebar.h - sidebar widget
+ *
+ * Copyright (C) 2006 Emmanuele Bassi <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Based on the equivalent widget from Evince
+ * by Jonathan Blandford,
+ * Copyright (C) 2004 Red Hat, Inc.
+ */
+
+#ifndef __GDICT_SIDEBAR_H__
+#define __GDICT_SIDEBAR_H__
+
+#include <gtk/gtk.h>
+
+#define GDICT_TYPE_SIDEBAR (gdict_sidebar_get_type ())
+#define GDICT_SIDEBAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDICT_TYPE_SIDEBAR, GdictSidebar))
+#define GDICT_IS_SIDEBAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDICT_TYPE_SIDEBAR))
+#define GDICT_SIDEBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDICT_TYPE_SIDEBAR, GdictSidebarClass))
+#define GDICT_IS_SIDEBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDICT_TYPE_SIDEBAR))
+#define GDICT_SIDEBAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDICT_TYPE_SIDEBAR, GdictSidebarClass))
+
+typedef struct _GdictSidebar GdictSidebar;
+typedef struct _GdictSidebarPrivate GdictSidebarPrivate;
+typedef struct _GdictSidebarClass GdictSidebarClass;
+
+struct _GdictSidebar
+{
+ GtkVBox parent_instance;
+
+ GdictSidebarPrivate *priv;
+};
+
+struct _GdictSidebarClass
+{
+ GtkVBoxClass parent_class;
+
+ void (*page_changed) (GdictSidebar *sidebar);
+ void (*closed) (GdictSidebar *sidebar);
+
+ void (*_gdict_padding_1) (void);
+ void (*_gdict_padding_2) (void);
+ void (*_gdict_padding_3) (void);
+ void (*_gdict_padding_4) (void);
+};
+
+GType gdict_sidebar_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gdict_sidebar_new (void);
+void gdict_sidebar_add_page (GdictSidebar *sidebar,
+ const gchar *page_id,
+ const gchar *page_name,
+ GtkWidget *page_widget);
+void gdict_sidebar_remove_page (GdictSidebar *sidebar,
+ const gchar *page_id);
+void gdict_sidebar_view_page (GdictSidebar *sidebar,
+ const gchar *page_id);
+const gchar *gdict_sidebar_current_page (GdictSidebar *sidebar);
+gchar ** gdict_sidebar_list_pages (GdictSidebar *sidebar,
+ gsize *length) G_GNUC_MALLOC;
+
+#endif /* __GDICT_SIDEBAR_H__ */
diff --git a/mate-dictionary/src/gdict-source-dialog.c b/mate-dictionary/src/gdict-source-dialog.c
new file mode 100644
index 00000000..2a3014ab
--- /dev/null
+++ b/mate-dictionary/src/gdict-source-dialog.c
@@ -0,0 +1,759 @@
+/* gdict-source-dialog.c - source dialog
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <mateconf/mateconf-client.h>
+
+#include "gdict-source-dialog.h"
+#include "gdict-common.h"
+
+#define GDICT_SOURCE_UI PKGDATADIR "/mate-dictionary-source.ui"
+
+/*********************
+ * GdictSourceDialog *
+ *********************/
+
+struct _GdictSourceDialog
+{
+ GtkDialog parent_instance;
+
+ GtkBuilder *builder;
+
+ MateConfClient *mateconf_client;
+ guint notify_id;
+
+ GdictSourceLoader *loader;
+ GdictSource *source;
+ gchar *source_name;
+ GdictContext *context;
+
+ GdictSourceDialogAction action;
+
+ GdictSourceTransport transport;
+
+ GtkWidget *add_button;
+ GtkWidget *close_button;
+ GtkWidget *cancel_button;
+ GtkWidget *help_button;
+
+ GtkWidget *db_chooser;
+ GtkWidget *strat_chooser;
+
+ GtkWidget *transport_combo;
+};
+
+struct _GdictSourceDialogClass
+{
+ GtkDialogClass parent_class;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_SOURCE_LOADER,
+ PROP_SOURCE_NAME,
+ PROP_ACTION
+};
+
+G_DEFINE_TYPE (GdictSourceDialog, gdict_source_dialog, GTK_TYPE_DIALOG);
+
+static void
+set_source_loader (GdictSourceDialog *dialog,
+ GdictSourceLoader *loader)
+{
+ if (dialog->loader)
+ g_object_unref (dialog->loader);
+
+ dialog->loader = g_object_ref (loader);
+}
+
+static void
+transport_combo_changed_cb (GtkWidget *widget,
+ gpointer user_data)
+{
+ GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (user_data);
+ gint transport;
+
+ transport = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+ if (transport == dialog->transport)
+ return;
+
+ if (transport == GDICT_SOURCE_TRANSPORT_DICTD)
+ {
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "hostname_label")));
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "hostname_entry")));
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "port_label")));
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "port_entry")));
+
+ if (dialog->action == GDICT_SOURCE_DIALOG_CREATE)
+ {
+ gtk_widget_set_sensitive (dialog->add_button, TRUE);
+
+ dialog->transport = GDICT_SOURCE_TRANSPORT_DICTD;
+ }
+ }
+ else
+ {
+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "hostname_label")));
+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "hostname_entry")));
+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "port_label")));
+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "port_entry")));
+
+ if (dialog->action == GDICT_SOURCE_DIALOG_CREATE)
+ {
+ gtk_widget_set_sensitive (dialog->add_button, FALSE);
+
+ dialog->transport = GDICT_SOURCE_TRANSPORT_INVALID;
+ }
+ }
+}
+
+static gchar *
+get_text_from_entry (GdictSourceDialog *dialog,
+ const gchar *entry_name)
+{
+ GtkWidget *entry;
+ gchar *retval;
+
+ entry = GTK_WIDGET (gtk_builder_get_object (dialog->builder, entry_name));
+ if (!entry)
+ return NULL;
+
+ retval = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+
+ return retval;
+}
+
+static void
+set_text_to_entry (GdictSourceDialog *dialog,
+ const gchar *entry_name,
+ const gchar *text)
+{
+ GtkWidget *entry;
+
+ entry = GTK_WIDGET (gtk_builder_get_object (dialog->builder, entry_name));
+ if (!entry)
+ return;
+
+ gtk_entry_set_text (GTK_ENTRY (entry), text);
+}
+
+static void
+set_transport_settings (GdictSourceDialog *dialog)
+{
+ switch (dialog->transport)
+ {
+ case GDICT_SOURCE_TRANSPORT_DICTD:
+ {
+ GdictClientContext *context;
+ const gchar *hostname;
+ gchar *port_str;
+ guint port;
+
+ context = GDICT_CLIENT_CONTEXT (dialog->context);
+ hostname = gdict_client_context_get_hostname (context);
+ port = gdict_client_context_get_port (context);
+ port_str = g_strdup_printf ("%d", port);
+
+ set_text_to_entry (dialog, "hostname_entry", hostname);
+ set_text_to_entry (dialog, "port_entry", port_str);
+
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "hostname_label")));
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "hostname_entry")));
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "port_label")));
+ gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (dialog->builder, "port_entry")));
+
+ g_free (port_str);
+ }
+ break;
+ case GDICT_SOURCE_TRANSPORT_INVALID:
+ default:
+ break;
+ }
+}
+
+static void
+update_dialog_ui (GdictSourceDialog *dialog)
+{
+ GdictSource *source;
+
+ /* TODO - add code to update the contents of the dialog depending
+ * on the action; if we are in _CREATE, no action is needed
+ */
+ switch (dialog->action)
+ {
+ case GDICT_SOURCE_DIALOG_VIEW:
+ case GDICT_SOURCE_DIALOG_EDIT:
+ if (!dialog->source_name)
+ {
+ g_warning ("Attempting to retrieve source, but no "
+ "source name has been defined. Aborting...");
+ return;
+ }
+
+ source = gdict_source_loader_get_source (dialog->loader,
+ dialog->source_name);
+ if (!source)
+ {
+ g_warning ("Attempting to retrieve source, but no "
+ "source named `%s' was found. Aborting...",
+ dialog->source_name);
+ return;
+ }
+
+ g_object_ref (source);
+
+ dialog->source = source;
+ set_text_to_entry (dialog, "description_entry",
+ gdict_source_get_description (source));
+
+ dialog->transport = gdict_source_get_transport (source);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->transport_combo),
+ (gint) dialog->transport);
+
+ /* set the context for the database and strategy choosers */
+ dialog->context = gdict_source_get_context (source);
+ if (!dialog->context)
+ {
+ g_warning ("Attempting to retrieve the context, but "
+ "none was found for source `%s'.",
+ dialog->source_name);
+ return;
+ }
+
+ set_transport_settings (dialog);
+
+ gdict_database_chooser_set_context (GDICT_DATABASE_CHOOSER (dialog->db_chooser),
+ dialog->context);
+ gdict_database_chooser_refresh (GDICT_DATABASE_CHOOSER (dialog->db_chooser));
+ gdict_strategy_chooser_set_context (GDICT_STRATEGY_CHOOSER (dialog->strat_chooser),
+ dialog->context);
+ gdict_strategy_chooser_refresh (GDICT_STRATEGY_CHOOSER (dialog->strat_chooser));
+ break;
+ case GDICT_SOURCE_DIALOG_CREATE:
+ /* DICTD transport is default */
+ gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->transport_combo), 0);
+ g_signal_emit_by_name (dialog->transport_combo, "changed");
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+build_new_source (GdictSourceDialog *dialog)
+{
+ GdictSource *source;
+ gchar *name, *text;
+ GdictSourceTransport transport;
+ gchar *host, *port;
+ gchar *data;
+ gsize length;
+ GError *error;
+ gchar *filename;
+ GdictDatabaseChooser *db_chooser;
+ GdictStrategyChooser *strat_chooser;
+
+ source = gdict_source_new ();
+
+ /* use the timestamp and the pid to get a unique name */
+ name = g_strdup_printf ("source-%lu-%u",
+ (gulong) time (NULL),
+ (guint) getpid ());
+ gdict_source_set_name (source, name);
+ g_free (name);
+
+ text = get_text_from_entry (dialog, "description_entry");
+ gdict_source_set_description (source, text);
+ g_free (text);
+
+ db_chooser = GDICT_DATABASE_CHOOSER (dialog->db_chooser);
+ text = gdict_database_chooser_get_current_database (db_chooser);
+ gdict_source_set_database (source, text);
+ g_free (text);
+
+ strat_chooser = GDICT_STRATEGY_CHOOSER (dialog->strat_chooser);
+ text = gdict_strategy_chooser_get_current_strategy (strat_chooser);
+ gdict_source_set_strategy (source, text);
+ g_free (text);
+
+ /* get the selected transport id */
+ transport = dialog->transport;
+ switch (transport)
+ {
+ case GDICT_SOURCE_TRANSPORT_DICTD:
+ host = get_text_from_entry (dialog, "hostname_entry");
+ port = get_text_from_entry (dialog, "port_entry");
+
+ gdict_source_set_transport (source, GDICT_SOURCE_TRANSPORT_DICTD,
+ "hostname", host,
+ "port", atoi (port),
+ NULL);
+
+ g_free (host);
+ g_free (port);
+ break;
+ case GDICT_SOURCE_TRANSPORT_INVALID:
+ default:
+ g_warning ("Invalid transport");
+ return;
+ }
+
+ error = NULL;
+ data = gdict_source_to_data (source, &length, &error);
+ if (error)
+ {
+ gdict_show_gerror_dialog (GTK_WINDOW (dialog),
+ _("Unable to create a source file"),
+ error);
+
+ g_object_unref (source);
+ return;
+ }
+
+ name = g_strdup_printf ("%s.desktop", gdict_source_get_name (source));
+ filename = g_build_filename (g_get_home_dir (),
+ ".mate2",
+ "mate-dictionary",
+ name,
+ NULL);
+ g_free (name);
+
+ g_file_set_contents (filename, data, length, &error);
+ if (error)
+ gdict_show_gerror_dialog (GTK_WINDOW (dialog),
+ _("Unable to save source file"),
+ error);
+
+ g_free (filename);
+ g_free (data);
+ g_object_unref (source);
+}
+
+static void
+save_source (GdictSourceDialog *dialog)
+{
+ GdictSource *source;
+ GdictDatabaseChooser *db_chooser;
+ GdictStrategyChooser *strat_chooser;
+ gchar *name, *text;
+ GdictSourceTransport transport;
+ gchar *host, *port;
+ gchar *data;
+ gsize length;
+ GError *error;
+ gchar *filename;
+
+ source = gdict_source_loader_get_source (dialog->loader,
+ dialog->source_name);
+ if (!source)
+ {
+ g_warning ("Attempting to save source `%s', but no "
+ "source for that name was found.",
+ dialog->source_name);
+
+ return;
+ }
+
+ text = get_text_from_entry (dialog, "description_entry");
+ gdict_source_set_description (source, text);
+ g_free (text);
+
+ db_chooser = GDICT_DATABASE_CHOOSER (dialog->db_chooser);
+ text = gdict_database_chooser_get_current_database (db_chooser);
+ gdict_source_set_database (source, text);
+ g_free (text);
+
+ strat_chooser = GDICT_STRATEGY_CHOOSER (dialog->strat_chooser);
+ text = gdict_strategy_chooser_get_current_strategy (strat_chooser);
+ gdict_source_set_strategy (source, text);
+ g_free (text);
+
+
+ /* get the selected transport id */
+ transport = dialog->transport;
+ switch (transport)
+ {
+ case GDICT_SOURCE_TRANSPORT_DICTD:
+ host = get_text_from_entry (dialog, "hostname_entry");
+ port = get_text_from_entry (dialog, "port_entry");
+
+ gdict_source_set_transport (source, GDICT_SOURCE_TRANSPORT_DICTD,
+ "hostname", host,
+ "port", atoi (port),
+ NULL);
+
+ g_free (host);
+ g_free (port);
+ break;
+ case GDICT_SOURCE_TRANSPORT_INVALID:
+ default:
+ g_warning ("Invalid transport");
+ return;
+ }
+
+ error = NULL;
+ data = gdict_source_to_data (source, &length, &error);
+ if (error)
+ {
+ gdict_show_gerror_dialog (GTK_WINDOW (dialog),
+ _("Unable to create a source file"),
+ error);
+
+ g_object_unref (source);
+ return;
+ }
+
+ name = g_strdup_printf ("%s.desktop", gdict_source_get_name (source));
+ filename = g_build_filename (g_get_home_dir (),
+ ".mate2",
+ "mate-dictionary",
+ name,
+ NULL);
+ g_free (name);
+
+ g_file_set_contents (filename, data, length, &error);
+ if (error)
+ gdict_show_gerror_dialog (GTK_WINDOW (dialog),
+ _("Unable to save source file"),
+ error);
+
+ g_free (filename);
+ g_free (data);
+ g_object_unref (source);
+}
+
+static void
+gdict_source_dialog_response_cb (GtkDialog *dialog,
+ gint response_id,
+ gpointer user_data)
+{
+ GError *err = NULL;
+
+ switch (response_id)
+ {
+ case GTK_RESPONSE_ACCEPT:
+ build_new_source (GDICT_SOURCE_DIALOG (dialog));
+ break;
+ case GTK_RESPONSE_HELP:
+ gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (dialog)),
+ "ghelp:mate-dictionary#mate-dictionary-add-source",
+ gtk_get_current_event_time (), &err);
+ if (err)
+ {
+ gdict_show_gerror_dialog (GTK_WINDOW (dialog),
+ _("There was an error while displaying help"),
+ err);
+ g_error_free (err);
+ }
+
+ /* we don't want the dialog to close itself */
+ g_signal_stop_emission_by_name (dialog, "response");
+ break;
+ case GTK_RESPONSE_CLOSE:
+ save_source (GDICT_SOURCE_DIALOG (dialog));
+ break;
+ case GTK_RESPONSE_CANCEL:
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gdict_source_dialog_finalize (GObject *object)
+{
+ GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (object);
+
+ if (dialog->mateconf_client)
+ g_object_unref (dialog->mateconf_client);
+
+ if (dialog->builder)
+ g_object_unref (dialog->builder);
+
+ if (dialog->source_name)
+ g_free (dialog->source_name);
+
+ if (dialog->source)
+ g_object_unref (dialog->source);
+
+ if (dialog->loader)
+ g_object_unref (dialog->loader);
+
+ G_OBJECT_CLASS (gdict_source_dialog_parent_class)->finalize (object);
+}
+
+static void
+gdict_source_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE_LOADER:
+ set_source_loader (dialog, g_value_get_object (value));
+ break;
+ case PROP_SOURCE_NAME:
+ g_free (dialog->source_name);
+ dialog->source_name = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_ACTION:
+ dialog->action = (GdictSourceDialogAction) g_value_get_int (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gdict_source_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE_LOADER:
+ g_value_set_object (value, dialog->loader);
+ break;
+ case PROP_SOURCE_NAME:
+ g_value_set_string (value, dialog->source_name);
+ break;
+ case PROP_ACTION:
+ g_value_set_int (value, dialog->action);
+ break;
+ default:
+ break;
+ }
+}
+
+static GObject *
+gdict_source_dialog_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GdictSourceDialog *dialog;
+ GtkWidget *vbox;
+ GError *error = NULL;
+
+ object = G_OBJECT_CLASS (gdict_source_dialog_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_params);
+ dialog = GDICT_SOURCE_DIALOG (object);
+
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
+
+ gtk_widget_push_composite_child ();
+
+ /* get the UI from the GtkBuilder file */
+ dialog->builder = gtk_builder_new ();
+ gtk_builder_add_from_file (dialog->builder, GDICT_SOURCE_UI, &error);
+
+ if (error) {
+ g_critical ("Unable to load the user interface definition file: %s",
+ error->message);
+ g_error_free (error);
+ g_assert_not_reached ();
+ }
+
+ /* the main widget */
+ gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+ GTK_WIDGET (gtk_builder_get_object (dialog->builder, "source_root")));
+
+ /* the transport combo changes the UI by changing the visible widgets
+ * bound to the transport's own options.
+ */
+ dialog->transport_combo = GTK_WIDGET (gtk_builder_get_object (dialog->builder, "transport_combo"));
+ g_signal_connect (dialog->transport_combo, "changed",
+ G_CALLBACK (transport_combo_changed_cb),
+ dialog);
+
+ /* the help button is always visible */
+ dialog->help_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_HELP,
+ GTK_RESPONSE_HELP);
+
+ vbox = GTK_WIDGET (gtk_builder_get_object (dialog->builder, "db-vbox"));
+ dialog->db_chooser = gdict_database_chooser_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), dialog->db_chooser, TRUE, TRUE, 0);
+ gtk_widget_show (dialog->db_chooser);
+
+ vbox = GTK_WIDGET (gtk_builder_get_object (dialog->builder, "strat-vbox"));
+ dialog->strat_chooser = gdict_strategy_chooser_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), dialog->strat_chooser, TRUE, TRUE, 0);
+ gtk_widget_show (dialog->strat_chooser);
+
+ /* the UI changes depending on the action that the source dialog
+ * should perform
+ */
+ switch (dialog->action)
+ {
+ case GDICT_SOURCE_DIALOG_VIEW:
+ /* disable every editable widget */
+ gtk_editable_set_editable (GTK_EDITABLE (gtk_builder_get_object (dialog->builder, "name_entry")), FALSE);
+ gtk_editable_set_editable (GTK_EDITABLE (gtk_builder_get_object (dialog->builder, "description_entry")), FALSE);
+ gtk_editable_set_editable (GTK_EDITABLE (gtk_builder_get_object (dialog->builder, "hostname_entry")), FALSE);
+ gtk_editable_set_editable (GTK_EDITABLE (gtk_builder_get_object (dialog->builder, "port_entry")), FALSE);
+
+ gtk_widget_set_sensitive (dialog->transport_combo, FALSE);
+
+ /* we just allow closing the dialog */
+ dialog->close_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_CLOSE);
+ break;
+ case GDICT_SOURCE_DIALOG_CREATE:
+ dialog->cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+ dialog->add_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_ADD,
+ GTK_RESPONSE_ACCEPT);
+ /* the "add" button sensitivity is controlled by the transport_combo
+ * since it's the only setting that makes a source usable.
+ */
+ gtk_widget_set_sensitive (dialog->add_button, FALSE);
+ break;
+ case GDICT_SOURCE_DIALOG_EDIT:
+ dialog->cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+ dialog->close_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_CLOSE);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* this will take care of updating the contents of the dialog
+ * based on the action
+ */
+ update_dialog_ui (dialog);
+
+ gtk_widget_pop_composite_child ();
+
+ return object;
+}
+
+static void
+gdict_source_dialog_class_init (GdictSourceDialogClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->constructor = gdict_source_dialog_constructor;
+ gobject_class->set_property = gdict_source_dialog_set_property;
+ gobject_class->get_property = gdict_source_dialog_get_property;
+ gobject_class->finalize = gdict_source_dialog_finalize;
+
+ g_object_class_install_property (gobject_class,
+ PROP_SOURCE_LOADER,
+ g_param_spec_object ("source-loader",
+ "Source Loader",
+ "The GdictSourceLoader used by the application",
+ GDICT_TYPE_SOURCE_LOADER,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+ g_object_class_install_property (gobject_class,
+ PROP_SOURCE_NAME,
+ g_param_spec_string ("source-name",
+ "Source Name",
+ "The source name",
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)));
+ g_object_class_install_property (gobject_class,
+ PROP_ACTION,
+ g_param_spec_int ("action",
+ "Action",
+ "The action the source dialog should perform",
+ -1,
+ GDICT_SOURCE_DIALOG_EDIT,
+ GDICT_SOURCE_DIALOG_VIEW,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+}
+
+static void
+gdict_source_dialog_init (GdictSourceDialog *dialog)
+{
+ gtk_widget_set_size_request (GTK_WIDGET (dialog), 400, 300);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+ dialog->transport = GDICT_SOURCE_TRANSPORT_INVALID;
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gdict_source_dialog_response_cb),
+ NULL);
+}
+
+GtkWidget *
+gdict_source_dialog_new (GtkWindow *parent,
+ const gchar *title,
+ GdictSourceDialogAction action,
+ GdictSourceLoader *loader,
+ const gchar *source_name)
+{
+ GtkWidget *retval;
+
+ g_return_val_if_fail ((parent == NULL || GTK_IS_WINDOW (parent)), NULL);
+ g_return_val_if_fail (GDICT_IS_SOURCE_LOADER (loader), NULL);
+
+ retval = g_object_new (GDICT_TYPE_SOURCE_DIALOG,
+ "source-loader", loader,
+ "source-name", source_name,
+ "action", action,
+ "title", title,
+ NULL);
+
+ if (parent)
+ {
+ gtk_window_set_transient_for (GTK_WINDOW (retval), parent);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (retval), TRUE);
+ gtk_window_set_screen (GTK_WINDOW (retval),
+ gtk_widget_get_screen (GTK_WIDGET (parent)));
+ }
+
+ return retval;
+}
diff --git a/mate-dictionary/src/gdict-source-dialog.h b/mate-dictionary/src/gdict-source-dialog.h
new file mode 100644
index 00000000..ecddd8ff
--- /dev/null
+++ b/mate-dictionary/src/gdict-source-dialog.h
@@ -0,0 +1,54 @@
+/* gdict-source-dialog.h - source dialog
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GDICT_SOURCE_DIALOG_H__
+#define __GDICT_SOURCE_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include <libgdict/gdict.h>
+
+G_BEGIN_DECLS
+
+#define GDICT_TYPE_SOURCE_DIALOG (gdict_source_dialog_get_type ())
+#define GDICT_SOURCE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDICT_TYPE_SOURCE_DIALOG, GdictSourceDialog))
+#define GDICT_IS_SOURCE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDICT_TYPE_SOURCE_DIALOG))
+
+typedef enum
+{
+ GDICT_SOURCE_DIALOG_VIEW,
+ GDICT_SOURCE_DIALOG_CREATE,
+ GDICT_SOURCE_DIALOG_EDIT
+} GdictSourceDialogAction;
+
+typedef struct _GdictSourceDialog GdictSourceDialog;
+typedef struct _GdictSourceDialogClass GdictSourceDialogClass;
+
+GType gdict_source_dialog_get_type (void) G_GNUC_CONST;
+GtkWidget *gdict_source_dialog_new (GtkWindow *parent,
+ const gchar *title,
+ GdictSourceDialogAction action,
+ GdictSourceLoader *loader,
+ const gchar *source_name);
+
+G_END_DECLS
+
+#endif /* __GDICT_SOURCE_DIALOG_H__ */
diff --git a/mate-dictionary/src/gdict-window.c b/mate-dictionary/src/gdict-window.c
new file mode 100644
index 00000000..1be0256c
--- /dev/null
+++ b/mate-dictionary/src/gdict-window.c
@@ -0,0 +1,2214 @@
+/* gdict-window.c - main application window
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <libgdict/gdict.h>
+
+#include "gdict-sidebar.h"
+#include "gdict-print.h"
+#include "gdict-pref-dialog.h"
+#include "gdict-about.h"
+#include "gdict-window.h"
+#include "gdict-common.h"
+
+#define GDICT_WINDOW_COLUMNS 56
+#define GDICT_WINDOW_ROWS 33
+
+#define GDICT_WINDOW_MIN_WIDTH 400
+#define GDICT_WINDOW_MIN_HEIGHT 330
+
+/* sidebar pages logical ids */
+#define GDICT_SIDEBAR_SPELLER_PAGE "speller"
+#define GDICT_SIDEBAR_DATABASES_PAGE "db-chooser"
+#define GDICT_SIDEBAR_STRATEGIES_PAGE "strat-chooser"
+#define GDICT_SIDEBAR_SOURCES_PAGE "source-chooser"
+
+enum
+{
+ COMPLETION_TEXT_COLUMN,
+
+ COMPLETION_N_COLUMNS
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_ACTION,
+ PROP_SOURCE_LOADER,
+ PROP_SOURCE_NAME,
+ PROP_PRINT_FONT,
+ PROP_DEFBOX_FONT,
+ PROP_WORD,
+ PROP_WINDOW_ID
+};
+
+enum
+{
+ CREATED,
+
+ LAST_SIGNAL
+};
+
+static guint gdict_window_signals[LAST_SIGNAL] = { 0 };
+
+static const GtkTargetEntry drop_types[] =
+{
+ { "text/plain", 0, 0 },
+ { "TEXT", 0, 0 },
+ { "STRING", 0, 0 },
+ { "UTF8_STRING", 0, 0 },
+};
+static const guint n_drop_types = G_N_ELEMENTS (drop_types);
+
+
+
+G_DEFINE_TYPE (GdictWindow, gdict_window, GTK_TYPE_WINDOW);
+
+
+static void
+gdict_window_finalize (GObject *gobject)
+{
+ GdictWindow *window = GDICT_WINDOW (gobject);
+
+ g_free (window->source_name);
+ g_free (window->print_font);
+ g_free (window->defbox_font);
+ g_free (window->word);
+ g_free (window->database);
+ g_free (window->strategy);
+
+ G_OBJECT_CLASS (gdict_window_parent_class)->finalize (gobject);
+}
+
+static void
+gdict_window_dispose (GObject *gobject)
+{
+ GdictWindow *window = GDICT_WINDOW (gobject);
+
+ if (window->notify_id)
+ {
+ mateconf_client_notify_remove (window->mateconf_client, window->notify_id);
+ window->notify_id = 0;
+ }
+
+ if (window->font_notify_id)
+ {
+ mateconf_client_notify_remove (window->mateconf_client,
+ window->font_notify_id);
+ window->font_notify_id = 0;
+ }
+
+ if (window->mateconf_client)
+ {
+ g_object_unref (window->mateconf_client);
+ window->mateconf_client = NULL;
+ }
+
+ if (window->context)
+ {
+ if (window->lookup_start_id)
+ {
+ g_signal_handler_disconnect (window->context,
+ window->lookup_start_id);
+ g_signal_handler_disconnect (window->context,
+ window->definition_id);
+ g_signal_handler_disconnect (window->context,
+ window->lookup_end_id);
+ g_signal_handler_disconnect (window->context,
+ window->error_id);
+
+ window->lookup_start_id = 0;
+ window->definition_id = 0;
+ window->lookup_end_id = 0;
+ window->error_id = 0;
+ }
+
+ g_object_unref (window->context);
+ window->context = NULL;
+ }
+
+ if (window->loader)
+ {
+ g_object_unref (window->loader);
+ window->loader = NULL;
+ }
+
+ if (window->ui_manager)
+ {
+ g_object_unref (window->ui_manager);
+ window->ui_manager = NULL;
+ }
+
+ if (window->action_group)
+ {
+ g_object_unref (window->action_group);
+ window->action_group = NULL;
+ }
+
+ if (window->completion)
+ {
+ g_object_unref (window->completion);
+ window->completion = NULL;
+ }
+
+ if (window->completion_model)
+ {
+ g_object_unref (window->completion_model);
+ window->completion_model = NULL;
+ }
+
+ if (window->busy_cursor)
+ {
+ gdk_cursor_unref (window->busy_cursor);
+ window->busy_cursor = NULL;
+ }
+
+ G_OBJECT_CLASS (gdict_window_parent_class)->dispose (gobject);
+}
+
+static const gchar *toggle_state[] = {
+ "/MainMenu/FileMenu/SaveAsMenu",
+ "/MainMenu/FileMenu/FilePreviewMenu",
+ "/MainMenu/FileMenu/FilePrintMenu",
+ "/MainMenu/GoMenu",
+};
+
+static gint n_toggle_state = G_N_ELEMENTS (toggle_state);
+
+static void
+gdict_window_ensure_menu_state (GdictWindow *window)
+{
+ gint i;
+ gboolean is_sensitive;
+
+ g_assert (GDICT_IS_WINDOW (window));
+
+ if (!window->ui_manager)
+ return;
+
+ is_sensitive = !!(window->word != NULL);
+ for (i = 0; i < n_toggle_state; i++)
+ {
+ GtkWidget *item;
+
+ item = gtk_ui_manager_get_widget (window->ui_manager, toggle_state[i]);
+ if (!item)
+ continue;
+
+ gtk_widget_set_sensitive (item, is_sensitive);
+ }
+}
+
+static void
+gdict_window_set_sidebar_visible (GdictWindow *window,
+ gboolean is_visible)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ if (is_visible != window->sidebar_visible)
+ {
+ GtkAction *action;
+
+ if (is_visible)
+ gtk_widget_show (window->sidebar_frame);
+ else
+ gtk_widget_hide (window->sidebar_frame);
+
+ action = gtk_action_group_get_action (window->action_group,
+ "ViewSidebar");
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), is_visible);
+
+ window->sidebar_visible = is_visible;
+ }
+}
+
+static void
+gdict_window_set_statusbar_visible (GdictWindow *window,
+ gboolean is_visible)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ if (is_visible != window->statusbar_visible)
+ {
+ GtkAction *action;
+
+ if (is_visible)
+ gtk_widget_show (window->status);
+ else
+ gtk_widget_hide (window->status);
+
+ action = gtk_action_group_get_action (window->action_group,
+ "ViewStatusbar");
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), is_visible);
+
+ window->statusbar_visible = is_visible;
+ }
+}
+
+static void
+gdict_window_definition_cb (GdictContext *context,
+ GdictDefinition *definition,
+ GdictWindow *window)
+{
+ gint total, n;
+ gdouble fraction;
+
+ g_assert (GDICT_IS_WINDOW (window));
+
+ total = gdict_definition_get_total (definition);
+ n = window->current_definition + 1;
+
+ fraction = CLAMP (((gdouble) n / (gdouble) total), 0.0, 1.0);
+
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->progress),
+ fraction);
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ window->current_definition = n;
+}
+
+static void
+gdict_window_lookup_start_cb (GdictContext *context,
+ GdictWindow *window)
+{
+ gchar *message;
+
+ if (!window->word)
+ return;
+
+ if (!window->busy_cursor)
+ window->busy_cursor = gdk_cursor_new (GDK_WATCH);
+
+ message = g_strdup_printf (_("Searching for '%s'..."), window->word);
+
+ if (window->status && window->statusbar_visible)
+ gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, message);
+
+ if (window->progress)
+ gtk_widget_show (window->progress);
+
+ window->max_definition = -1;
+ window->last_definition = 0;
+ window->current_definition = 0;
+
+ gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), window->busy_cursor);
+
+ g_free (message);
+}
+
+static void
+gdict_window_lookup_end_cb (GdictContext *context,
+ GdictWindow *window)
+{
+ gchar *message;
+ gint count;
+ GtkTreeIter iter;
+ GdictSource *source;
+ GdictContext *speller_context;
+
+ count = window->current_definition;
+
+ window->max_definition = count - 1;
+
+ if (count == 0)
+ message = g_strdup (_("No definitions found"));
+ else
+ message = g_strdup_printf (ngettext("A definition found",
+ "%d definitions found",
+ count),
+ count);
+
+ if (window->status && window->statusbar_visible)
+ gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, message);
+
+ if (window->progress)
+ gtk_widget_hide (window->progress);
+
+ /* we clone the context, so that the signals that it
+ * fires do not get caught by the signal handlers we
+ * use for getting the definitions.
+ */
+ source = gdict_source_loader_get_source (window->loader, window->source_name);
+ speller_context = gdict_source_get_context (source);
+ gdict_speller_set_context (GDICT_SPELLER (window->speller), speller_context);
+ g_object_unref (speller_context);
+ g_object_unref (source);
+
+ /* search for similar words; if we have a no-match we already started
+ * looking in the error signal handler
+ */
+ if (count != 0 && window->word)
+ {
+ gdict_speller_set_strategy (GDICT_SPELLER (window->speller), window->strategy);
+ gdict_speller_match (GDICT_SPELLER (window->speller), window->word);
+ gtk_list_store_append (window->completion_model, &iter);
+ gtk_list_store_set (window->completion_model, &iter,
+ COMPLETION_TEXT_COLUMN, window->word,
+ -1);
+ }
+
+ gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
+ g_free (message);
+
+ if (count == 0)
+ {
+ g_free (window->word);
+ window->word = NULL;
+ }
+
+ gdict_window_ensure_menu_state (window);
+}
+
+static void
+gdict_window_error_cb (GdictContext *context,
+ const GError *error,
+ GdictWindow *window)
+{
+ gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
+
+ if (window->status && window->statusbar_visible)
+ gtk_statusbar_push (GTK_STATUSBAR (window->status), 0,
+ _("No definitions found"));
+
+ gtk_widget_hide (window->progress);
+
+ /* launch the speller only on NO_MATCH */
+ if (error->code == GDICT_CONTEXT_ERROR_NO_MATCH)
+ {
+ GdictSource *source;
+ GdictContext *context;
+
+ gdict_window_set_sidebar_visible (window, TRUE);
+ gdict_sidebar_view_page (GDICT_SIDEBAR (window->sidebar),
+ GDICT_SIDEBAR_SPELLER_PAGE);
+
+ /* we clone the context, so that the signals that it
+ * fires do not get caught by the signal handlers we
+ * use for getting the definitions.
+ */
+ source = gdict_source_loader_get_source (window->loader,
+ window->source_name);
+ context = gdict_source_get_context (source);
+
+ gdict_speller_set_context (GDICT_SPELLER (window->speller),
+ context);
+ g_object_unref (context);
+ g_object_unref (source);
+
+ gdict_speller_set_strategy (GDICT_SPELLER (window->speller),
+ window->strategy);
+
+ gdict_speller_match (GDICT_SPELLER (window->speller),
+ window->word);
+ }
+
+ /* unset the word and update the UI */
+ g_free (window->word);
+ window->word = NULL;
+
+ gdict_window_ensure_menu_state (window);
+}
+
+static void
+gdict_window_set_database (GdictWindow *window,
+ const gchar *database)
+{
+ g_free (window->database);
+
+ if (database)
+ window->database = g_strdup (database);
+ else
+ window->database = gdict_mateconf_get_string_with_default (window->mateconf_client,
+ GDICT_MATECONF_DATABASE_KEY,
+ GDICT_DEFAULT_DATABASE);
+
+ if (window->defbox)
+ gdict_defbox_set_database (GDICT_DEFBOX (window->defbox),
+ window->database);
+
+ if (window->db_chooser)
+ gdict_database_chooser_set_current_database (GDICT_DATABASE_CHOOSER (window->db_chooser),
+ window->database);
+}
+
+static void
+gdict_window_set_strategy (GdictWindow *window,
+ const gchar *strategy)
+{
+ g_free (window->strategy);
+
+ if (strategy && strategy[0] != '\0')
+ window->strategy = g_strdup (strategy);
+ else
+ window->strategy = gdict_mateconf_get_string_with_default (window->mateconf_client,
+ GDICT_MATECONF_STRATEGY_KEY,
+ GDICT_DEFAULT_STRATEGY);
+
+ if (window->speller)
+ gdict_speller_set_strategy (GDICT_SPELLER (window->speller),
+ window->strategy);
+
+ if (window->strat_chooser)
+ gdict_strategy_chooser_set_current_strategy (GDICT_STRATEGY_CHOOSER (window->strat_chooser),
+ window->strategy);
+}
+
+static GdictContext *
+get_context_from_loader (GdictWindow *window)
+{
+ GdictSource *source;
+ GdictContext *retval;
+
+ if (!window->source_name)
+ window->source_name = g_strdup (GDICT_DEFAULT_SOURCE_NAME);
+
+ source = gdict_source_loader_get_source (window->loader,
+ window->source_name);
+ if (!source &&
+ strcmp (window->source_name, GDICT_DEFAULT_SOURCE_NAME) != 0)
+ {
+ g_free (window->source_name);
+ window->source_name = g_strdup (GDICT_DEFAULT_SOURCE_NAME);
+
+ source = gdict_source_loader_get_source (window->loader,
+ window->source_name);
+ }
+
+ if (!source)
+ {
+ gchar *detail;
+
+ detail = g_strdup_printf (_("No dictionary source available with name '%s'"),
+ window->source_name);
+
+ gdict_show_error_dialog (GTK_WINDOW (window),
+ _("Unable to find dictionary source"),
+ detail);
+
+ g_free (detail);
+
+ return NULL;
+ }
+
+ gdict_window_set_database (window, gdict_source_get_database (source));
+ gdict_window_set_strategy (window, gdict_source_get_strategy (source));
+
+ retval = gdict_source_get_context (source);
+ if (!retval)
+ {
+ gchar *detail;
+
+ detail = g_strdup_printf (_("No context available for source '%s'"),
+ gdict_source_get_description (source));
+
+ gdict_show_error_dialog (GTK_WINDOW (window),
+ _("Unable to create a context"),
+ detail);
+
+ g_free (detail);
+ g_object_unref (source);
+
+ return NULL;
+ }
+
+ g_object_unref (source);
+
+ return retval;
+}
+
+static void
+gdict_window_set_defbox_font (GdictWindow *window,
+ const gchar *defbox_font)
+{
+ g_free (window->defbox_font);
+
+ if (defbox_font)
+ window->defbox_font = g_strdup (defbox_font);
+ else
+ window->defbox_font = gdict_mateconf_get_string_with_default (window->mateconf_client,
+ DOCUMENT_FONT_KEY,
+ GDICT_DEFAULT_DEFBOX_FONT);
+
+ if (window->defbox)
+ gdict_defbox_set_font_name (GDICT_DEFBOX (window->defbox),
+ window->defbox_font);
+}
+
+static void
+gdict_window_set_print_font (GdictWindow *window,
+ const gchar *print_font)
+{
+ g_free (window->print_font);
+
+ if (print_font)
+ window->print_font = g_strdup (print_font);
+ else
+ window->print_font = gdict_mateconf_get_string_with_default (window->mateconf_client,
+ GDICT_MATECONF_PRINT_FONT_KEY,
+ GDICT_DEFAULT_PRINT_FONT);
+}
+
+static void
+gdict_window_set_word (GdictWindow *window,
+ const gchar *word,
+ const gchar *database)
+{
+ gchar *title;
+
+ g_free (window->word);
+ window->word = NULL;
+
+ if (word && word[0] != '\0')
+ window->word = g_strdup (word);
+ else
+ return;
+
+ if (!database || database[0] == '\0')
+ database = window->database;
+
+ if (window->word)
+ title = g_strdup_printf (_("%s - Dictionary"), window->word);
+ else
+ title = g_strdup (_("Dictionary"));
+
+ gtk_window_set_title (GTK_WINDOW (window), title);
+ g_free (title);
+
+ if (window->defbox)
+ {
+ gdict_defbox_set_database (GDICT_DEFBOX (window->defbox), database);
+ gdict_defbox_lookup (GDICT_DEFBOX (window->defbox), word);
+ }
+}
+
+static void
+gdict_window_set_context (GdictWindow *window,
+ GdictContext *context)
+{
+ if (window->context)
+ {
+ g_signal_handler_disconnect (window->context, window->definition_id);
+ g_signal_handler_disconnect (window->context, window->lookup_start_id);
+ g_signal_handler_disconnect (window->context, window->lookup_end_id);
+ g_signal_handler_disconnect (window->context, window->error_id);
+
+ window->definition_id = 0;
+ window->lookup_start_id = 0;
+ window->lookup_end_id = 0;
+ window->error_id = 0;
+
+ g_object_unref (window->context);
+ window->context = NULL;
+ }
+
+ if (window->defbox)
+ gdict_defbox_set_context (GDICT_DEFBOX (window->defbox), context);
+
+ if (window->db_chooser)
+ gdict_database_chooser_set_context (GDICT_DATABASE_CHOOSER (window->db_chooser), context);
+
+ if (window->strat_chooser)
+ gdict_strategy_chooser_set_context (GDICT_STRATEGY_CHOOSER (window->strat_chooser), context);
+
+ if (!context)
+ return;
+
+ /* attach our callbacks */
+ window->definition_id = g_signal_connect (context, "definition-found",
+ G_CALLBACK (gdict_window_definition_cb),
+ window);
+ window->lookup_start_id = g_signal_connect (context, "lookup-start",
+ G_CALLBACK (gdict_window_lookup_start_cb),
+ window);
+ window->lookup_end_id = g_signal_connect (context, "lookup-end",
+ G_CALLBACK (gdict_window_lookup_end_cb),
+ window);
+ window->error_id = g_signal_connect (context, "error",
+ G_CALLBACK (gdict_window_error_cb),
+ window);
+
+ window->context = context;
+}
+
+static void
+gdict_window_set_source_name (GdictWindow *window,
+ const gchar *source_name)
+{
+ GdictContext *context;
+
+ if (window->source_name && source_name &&
+ strcmp (window->source_name, source_name) == 0)
+ return;
+
+ g_free (window->source_name);
+
+ if (source_name)
+ window->source_name = g_strdup (source_name);
+ else
+ window->source_name = gdict_mateconf_get_string_with_default (window->mateconf_client,
+ GDICT_MATECONF_SOURCE_KEY,
+ GDICT_DEFAULT_SOURCE_NAME);
+
+ context = get_context_from_loader (window);
+ gdict_window_set_context (window, context);
+
+ if (window->source_chooser)
+ gdict_source_chooser_set_current_source (GDICT_SOURCE_CHOOSER (window->source_chooser),
+ window->source_name);
+
+ g_object_notify (G_OBJECT (window), "source-name");
+}
+
+static void
+gdict_window_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdictWindow *window = GDICT_WINDOW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTION:
+ window->action = g_value_get_enum (value);
+ break;
+ case PROP_SOURCE_LOADER:
+ if (window->loader)
+ g_object_unref (window->loader);
+ window->loader = g_value_get_object (value);
+ g_object_ref (window->loader);
+ break;
+ case PROP_SOURCE_NAME:
+ gdict_window_set_source_name (window, g_value_get_string (value));
+ break;
+ case PROP_WORD:
+ gdict_window_set_word (window, g_value_get_string (value), NULL);
+ break;
+ case PROP_PRINT_FONT:
+ gdict_window_set_print_font (window, g_value_get_string (value));
+ break;
+ case PROP_DEFBOX_FONT:
+ gdict_window_set_defbox_font (window, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdict_window_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdictWindow *window = GDICT_WINDOW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTION:
+ g_value_set_enum (value, window->action);
+ break;
+ case PROP_SOURCE_LOADER:
+ g_value_set_object (value, window->loader);
+ break;
+ case PROP_SOURCE_NAME:
+ g_value_set_string (value, window->source_name);
+ break;
+ case PROP_WORD:
+ g_value_set_string (value, window->word);
+ break;
+ case PROP_PRINT_FONT:
+ g_value_set_string (value, window->print_font);
+ break;
+ case PROP_DEFBOX_FONT:
+ g_value_set_string (value, window->defbox_font);
+ break;
+ case PROP_WINDOW_ID:
+ g_value_set_uint (value, window->window_id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdict_window_cmd_file_new (GtkAction *action,
+ GdictWindow *window)
+{
+ GtkWidget *new_window;
+ gchar *word = NULL;
+
+ /* store the default size of the window and its state, so that
+ * it's picked up by the newly created window
+ */
+ mateconf_client_set_int (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_WIDTH_KEY,
+ window->default_width,
+ NULL);
+ mateconf_client_set_int (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_HEIGHT_KEY,
+ window->default_height,
+ NULL);
+ mateconf_client_set_bool (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_IS_MAXIMIZED_KEY,
+ window->is_maximized,
+ NULL);
+ mateconf_client_set_bool (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_VISIBLE_KEY,
+ window->sidebar_visible,
+ NULL);
+ mateconf_client_set_int (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_WIDTH_KEY,
+ window->sidebar_width,
+ NULL);
+ mateconf_client_set_string (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_PAGE_KEY,
+ gdict_sidebar_current_page (GDICT_SIDEBAR (window->sidebar)),
+ NULL);
+ mateconf_client_set_bool (window->mateconf_client,
+ GDICT_MATECONF_STATUSBAR_VISIBLE_KEY,
+ window->statusbar_visible,
+ NULL);
+
+ word = gdict_defbox_get_selected_word (GDICT_DEFBOX (window->defbox));
+ if (word)
+ {
+ new_window = gdict_window_new (GDICT_WINDOW_ACTION_LOOKUP,
+ window->loader,
+ NULL, word);
+ g_free (word);
+ }
+ else
+ new_window = gdict_window_new (GDICT_WINDOW_ACTION_CLEAR,
+ window->loader,
+ NULL, NULL);
+
+ gtk_widget_show (new_window);
+
+ g_signal_emit (window, gdict_window_signals[CREATED], 0, new_window);
+}
+
+static void
+gdict_window_cmd_save_as (GtkAction *action,
+ GdictWindow *window)
+{
+ GtkWidget *dialog;
+
+ g_assert (GDICT_IS_WINDOW (window));
+
+ dialog = gtk_file_chooser_dialog_new (_("Save a Copy"),
+ GTK_WINDOW (window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
+
+ /* default to user's home */
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_home_dir ());
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), _("Untitled document"));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+ {
+ gchar *filename;
+ gchar *text;
+ gsize len;
+ GError *write_error = NULL;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+ text = gdict_defbox_get_text (GDICT_DEFBOX (window->defbox), &len);
+
+ g_file_set_contents (filename,
+ text,
+ len,
+ &write_error);
+ if (write_error)
+ {
+ gchar *message;
+
+ message = g_strdup_printf (_("Error while writing to '%s'"), filename);
+
+ gdict_show_gerror_dialog (GTK_WINDOW (window),
+ message,
+ write_error);
+
+ g_free (message);
+ }
+
+ g_free (text);
+ g_free (filename);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+gdict_window_cmd_file_preview (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_show_print_preview (GTK_WINDOW (window),
+ GDICT_DEFBOX (window->defbox));
+}
+
+static void
+gdict_window_cmd_file_print (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_show_print_dialog (GTK_WINDOW (window),
+ GDICT_DEFBOX (window->defbox));
+}
+
+static void
+gdict_window_cmd_file_close_window (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ /* store the default size of the window and its state */
+ mateconf_client_set_int (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_WIDTH_KEY,
+ window->default_width,
+ NULL);
+ mateconf_client_set_int (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_HEIGHT_KEY,
+ window->default_height,
+ NULL);
+ mateconf_client_set_bool (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_IS_MAXIMIZED_KEY,
+ window->is_maximized,
+ NULL);
+ mateconf_client_set_bool (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_VISIBLE_KEY,
+ window->sidebar_visible,
+ NULL);
+ mateconf_client_set_int (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_WIDTH_KEY,
+ window->sidebar_width,
+ NULL);
+ mateconf_client_set_string (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_PAGE_KEY,
+ gdict_sidebar_current_page (GDICT_SIDEBAR (window->sidebar)),
+ NULL);
+ mateconf_client_set_bool (window->mateconf_client,
+ GDICT_MATECONF_STATUSBAR_VISIBLE_KEY,
+ window->statusbar_visible,
+ NULL);
+
+ /* if this was called from the uimanager, destroy the widget;
+ * otherwise, if it was called from the delete_event, the widget
+ * will destroy itself.
+ */
+ if (action)
+ gtk_widget_destroy (GTK_WIDGET (window));
+}
+
+static void
+gdict_window_cmd_edit_copy (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_defbox_copy_to_clipboard (GDICT_DEFBOX (window->defbox),
+ gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
+}
+
+static void
+gdict_window_cmd_edit_select_all (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_defbox_select_all (GDICT_DEFBOX (window->defbox));
+}
+
+static void
+gdict_window_cmd_edit_find (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_defbox_set_show_find (GDICT_DEFBOX (window->defbox), TRUE);
+}
+
+static void
+gdict_window_cmd_edit_find_next (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_defbox_find_next (GDICT_DEFBOX (window->defbox));
+}
+
+static void
+gdict_window_cmd_edit_find_previous (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_defbox_find_previous (GDICT_DEFBOX (window->defbox));
+}
+
+static void
+gdict_window_cmd_edit_preferences (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_show_pref_dialog (GTK_WIDGET (window),
+ _("Dictionary Preferences"),
+ window->loader);
+}
+
+static void
+gdict_window_cmd_view_sidebar (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ if (window->sidebar_visible)
+ gdict_window_set_sidebar_visible (window, FALSE);
+ else
+ gdict_window_set_sidebar_visible (window, TRUE);
+}
+
+static void
+gdict_window_cmd_view_statusbar (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ if (window->statusbar_visible)
+ gdict_window_set_statusbar_visible (window, FALSE);
+ else
+ gdict_window_set_statusbar_visible (window, TRUE);
+}
+
+static void
+gdict_window_cmd_view_speller (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_sidebar_view_page (GDICT_SIDEBAR (window->sidebar),
+ GDICT_SIDEBAR_SPELLER_PAGE);
+ gdict_window_set_sidebar_visible (window, TRUE);
+}
+
+static void
+gdict_window_cmd_view_databases (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_sidebar_view_page (GDICT_SIDEBAR (window->sidebar),
+ GDICT_SIDEBAR_DATABASES_PAGE);
+ gdict_window_set_sidebar_visible (window, TRUE);
+}
+
+static void
+gdict_window_cmd_view_strategies (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_sidebar_view_page (GDICT_SIDEBAR (window->sidebar),
+ GDICT_SIDEBAR_STRATEGIES_PAGE);
+ gdict_window_set_sidebar_visible (window, TRUE);
+}
+
+static void
+gdict_window_cmd_view_sources (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_sidebar_view_page (GDICT_SIDEBAR (window->sidebar),
+ GDICT_SIDEBAR_SOURCES_PAGE);
+ gdict_window_set_sidebar_visible (window, TRUE);
+}
+
+static void
+gdict_window_cmd_go_first_def (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ window->last_definition = 0;
+ gdict_defbox_jump_to_definition (GDICT_DEFBOX (window->defbox),
+ window->last_definition);
+}
+
+static void
+gdict_window_cmd_go_previous_def (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ if (window->last_definition == 0)
+ return;
+
+ window->last_definition -= 1;
+ gdict_defbox_jump_to_definition (GDICT_DEFBOX (window->defbox),
+ window->last_definition);
+}
+
+static void
+gdict_window_cmd_go_next_def (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ if (window->max_definition == -1)
+ window->max_definition = gdict_defbox_count_definitions (GDICT_DEFBOX (window->defbox)) - 1;
+
+ if (window->last_definition == window->max_definition)
+ return;
+
+ window->last_definition += 1;
+ gdict_defbox_jump_to_definition (GDICT_DEFBOX (window->defbox),
+ window->last_definition);
+}
+
+static void
+gdict_window_cmd_go_last_def (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ if (window->max_definition == -1)
+ window->last_definition = gdict_defbox_count_definitions (GDICT_DEFBOX (window->defbox)) - 1;
+
+ window->last_definition = window->max_definition;
+ gdict_defbox_jump_to_definition (GDICT_DEFBOX (window->defbox),
+ window->last_definition);
+}
+
+static void
+gdict_window_cmd_help_contents (GtkAction *action,
+ GdictWindow *window)
+{
+ GError *err = NULL;
+
+ g_return_if_fail (GDICT_IS_WINDOW (window));
+
+ gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (window)),
+ "ghelp:mate-dictionary",
+ gtk_get_current_event_time (), &err);
+ if (err)
+ {
+ gdict_show_gerror_dialog (GTK_WINDOW (window),
+ _("There was an error while displaying help"),
+ err);
+ g_error_free (err);
+ }
+}
+
+static void
+gdict_window_cmd_help_about (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_show_about_dialog (GTK_WIDGET (window));
+}
+
+static void
+gdict_window_cmd_lookup (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gtk_widget_grab_focus (window->entry);
+}
+
+static void
+gdict_window_cmd_escape (GtkAction *action,
+ GdictWindow *window)
+{
+ g_assert (GDICT_IS_WINDOW (window));
+
+ gdict_defbox_set_show_find (GDICT_DEFBOX (window->defbox), FALSE);
+}
+
+static const GtkActionEntry entries[] =
+{
+ { "File", NULL, N_("_File") },
+ { "Edit", NULL, N_("_Edit") },
+ { "View", NULL, N_("_View") },
+ { "Go", NULL, N_("_Go") },
+ { "Help", NULL, N_("_Help") },
+
+ /* File menu */
+ { "FileNew", GTK_STOCK_NEW, N_("_New"), "<control>N",
+ N_("New look up"), G_CALLBACK (gdict_window_cmd_file_new) },
+ { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("_Save a Copy..."), NULL, NULL,
+ G_CALLBACK (gdict_window_cmd_save_as) },
+ { "FilePreview", NULL, N_("P_review..."), "<control><shift>P",
+ N_("Preview this document"), G_CALLBACK (gdict_window_cmd_file_preview) },
+ { "FilePrint", GTK_STOCK_PRINT, N_("_Print..."), "<control>P",
+ N_("Print this document"), G_CALLBACK (gdict_window_cmd_file_print) },
+ { "FileCloseWindow", GTK_STOCK_CLOSE, NULL, "<control>W", NULL,
+ G_CALLBACK (gdict_window_cmd_file_close_window) },
+
+ /* Edit menu */
+ { "EditCopy", GTK_STOCK_COPY, NULL, "<control>C", NULL,
+ G_CALLBACK (gdict_window_cmd_edit_copy) },
+ { "EditSelectAll", NULL, N_("Select _All"), "<control>A", NULL,
+ G_CALLBACK (gdict_window_cmd_edit_select_all) },
+ { "EditFind", GTK_STOCK_FIND, NULL, "<control>F",
+ N_("Find a word or phrase in the document"),
+ G_CALLBACK (gdict_window_cmd_edit_find) },
+ { "EditFindNext", NULL, N_("Find Ne_xt"), "<control>G", NULL,
+ G_CALLBACK (gdict_window_cmd_edit_find_next) },
+ { "EditFindPrevious", NULL, N_("Find Pre_vious"), "<control><shift>G", NULL,
+ G_CALLBACK (gdict_window_cmd_edit_find_previous) },
+ { "EditPreferences", GTK_STOCK_PREFERENCES, N_("_Preferences"), NULL, NULL,
+ G_CALLBACK (gdict_window_cmd_edit_preferences) },
+
+ /* Go menu */
+ { "GoPreviousDef", GTK_STOCK_GO_BACK, N_("_Previous Definition"), "<control>Page_Up",
+ N_("Go to the previous definition"), G_CALLBACK (gdict_window_cmd_go_previous_def) },
+ { "GoNextDef", GTK_STOCK_GO_FORWARD, N_("_Next Definition"), "<control>Page_Down",
+ N_("Go to the next definition"), G_CALLBACK (gdict_window_cmd_go_next_def) },
+ { "GoFirstDef", GTK_STOCK_GOTO_FIRST, N_("_First Definition"), "<control>Home",
+ N_("Go to the first definition"), G_CALLBACK (gdict_window_cmd_go_first_def) },
+ { "GoLastDef", GTK_STOCK_GOTO_LAST, N_("_Last Definition"), "<control>End",
+ N_("Go to the last definition"), G_CALLBACK (gdict_window_cmd_go_last_def) },
+
+ /* View menu */
+ { "ViewSpeller", NULL, N_("Similar _Words"), "<control>T", NULL,
+ G_CALLBACK (gdict_window_cmd_view_speller), },
+ { "ViewSource", NULL, N_("Dictionary Sources"), "<control>D", NULL,
+ G_CALLBACK (gdict_window_cmd_view_sources), },
+ { "ViewDB", NULL, N_("Available _Databases"), "<control>B", NULL,
+ G_CALLBACK (gdict_window_cmd_view_databases), },
+ { "ViewStrat", NULL, N_("Available St_rategies"), "<control>R", NULL,
+ G_CALLBACK (gdict_window_cmd_view_strategies), },
+
+ /* Help menu */
+ { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1", NULL,
+ G_CALLBACK (gdict_window_cmd_help_contents) },
+ { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL,
+ G_CALLBACK (gdict_window_cmd_help_about) },
+
+ /* Accelerators */
+ { "Lookup", NULL, "", "<control>L", NULL, G_CALLBACK (gdict_window_cmd_lookup) },
+ { "Escape", NULL, "", "Escape", "", G_CALLBACK (gdict_window_cmd_escape) },
+ { "Slash", GTK_STOCK_FIND, NULL, "slash", NULL, G_CALLBACK (gdict_window_cmd_edit_find) },
+};
+
+static const GtkToggleActionEntry toggle_entries[] = {
+ /* View menu */
+ { "ViewSidebar", NULL, N_("_Sidebar"), "F9", NULL,
+ G_CALLBACK (gdict_window_cmd_view_sidebar), FALSE },
+ { "ViewStatusbar", NULL, N_("S_tatusbar"), NULL, NULL,
+ G_CALLBACK (gdict_window_cmd_view_statusbar), FALSE },
+};
+
+static gboolean
+gdict_window_delete_event_cb (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ gdict_window_cmd_file_close_window (NULL, GDICT_WINDOW (widget));
+
+ return FALSE;
+}
+
+static gboolean
+gdict_window_state_event_cb (GtkWidget *widget,
+ GdkEventWindowState *event,
+ gpointer user_data)
+{
+ GdictWindow *window = GDICT_WINDOW (widget);
+
+ if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED)
+ window->is_maximized = TRUE;
+ else
+ window->is_maximized = FALSE;
+
+ return FALSE;
+}
+
+static void
+gdict_window_mateconf_notify_cb (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ GdictWindow *window;
+
+ window = GDICT_WINDOW (user_data);
+
+ if (strcmp (entry->key, GDICT_MATECONF_PRINT_FONT_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_STRING))
+ gdict_window_set_print_font (window, mateconf_value_get_string (entry->value));
+ else
+ gdict_window_set_print_font (window, GDICT_DEFAULT_PRINT_FONT);
+ }
+ else if (strcmp (entry->key, GDICT_MATECONF_SOURCE_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_STRING))
+ gdict_window_set_source_name (window, mateconf_value_get_string (entry->value));
+ else
+ gdict_window_set_source_name (window, GDICT_DEFAULT_SOURCE_NAME);
+ }
+ else if (strcmp (entry->key, GDICT_MATECONF_DATABASE_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_STRING))
+ gdict_window_set_database (window, mateconf_value_get_string (entry->value));
+ else
+ gdict_window_set_database (window, GDICT_DEFAULT_DATABASE);
+ }
+ else if (strcmp (entry->key, DOCUMENT_FONT_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_STRING))
+ gdict_window_set_defbox_font (window, mateconf_value_get_string (entry->value));
+ else
+ gdict_window_set_defbox_font (window, GDICT_DEFAULT_DEFBOX_FONT);
+ }
+ else if (strcmp (entry->key, GDICT_MATECONF_SIDEBAR_VISIBLE_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_BOOL))
+ gdict_window_set_sidebar_visible (window,
+ mateconf_value_get_bool (entry->value));
+ else
+ gdict_window_set_sidebar_visible (window, FALSE);
+ }
+ else if (strcmp (entry->key, GDICT_MATECONF_STATUSBAR_VISIBLE_KEY) == 0)
+ {
+ if (entry->value && (entry->value->type == MATECONF_VALUE_BOOL))
+ gdict_window_set_statusbar_visible (window,
+ mateconf_value_get_bool (entry->value));
+ else
+ gdict_window_set_statusbar_visible (window, FALSE);
+ }
+}
+
+static void
+lookup_word (GdictWindow *window,
+ gpointer dummy)
+{
+ const gchar *entry_text;
+ gchar *word;
+
+ g_assert (GDICT_IS_WINDOW (window));
+
+ if (!window->context)
+ return;
+
+ entry_text = gtk_entry_get_text (GTK_ENTRY (window->entry));
+ if (!entry_text || *entry_text == '\0')
+ return;
+
+ word = g_strdup (entry_text);
+ gdict_window_set_word (window, g_strstrip (word), NULL);
+
+ g_free (word);
+}
+
+static void
+source_activated_cb (GdictSourceChooser *chooser,
+ const gchar *source_name,
+ GdictSource *source,
+ GdictWindow *window)
+{
+ g_signal_handlers_block_by_func (chooser, source_activated_cb, window);
+ gdict_window_set_source_name (window, source_name);
+ g_signal_handlers_unblock_by_func (chooser, source_activated_cb, window);
+
+ if (window->status && window->statusbar_visible)
+ {
+ gchar *message;
+
+ message = g_strdup_printf (_("Dictionary source `%s' selected"),
+ gdict_source_get_description (source));
+ gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, message);
+ g_free (message);
+ }
+}
+
+static void
+strategy_activated_cb (GdictStrategyChooser *chooser,
+ const gchar *strat_name,
+ const gchar *strat_desc,
+ GdictWindow *window)
+{
+ g_signal_handlers_block_by_func (chooser, strategy_activated_cb, window);
+ gdict_window_set_strategy (window, strat_name);
+ g_signal_handlers_unblock_by_func (chooser, strategy_activated_cb, window);
+
+ if (window->status && window->statusbar_visible)
+ {
+ gchar *message;
+
+ message = g_strdup_printf (_("Strategy `%s' selected"), strat_desc);
+ gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, message);
+ g_free (message);
+ }
+}
+
+static void
+database_activated_cb (GdictDatabaseChooser *chooser,
+ const gchar *db_name,
+ const gchar *db_desc,
+ GdictWindow *window)
+{
+ g_signal_handlers_block_by_func (chooser, database_activated_cb, window);
+ gdict_window_set_database (window, db_name);
+ g_signal_handlers_unblock_by_func (chooser, database_activated_cb, window);
+
+ if (window->status && window->statusbar_visible)
+ {
+ gchar *message;
+
+ message = g_strdup_printf (_("Database `%s' selected"), db_desc);
+ gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, message);
+ g_free (message);
+ }
+}
+
+static void
+speller_word_activated_cb (GdictSpeller *speller,
+ const gchar *word,
+ const gchar *db_name,
+ GdictWindow *window)
+{
+ gtk_entry_set_text (GTK_ENTRY (window->entry), word);
+
+ gdict_window_set_word (window, word, db_name);
+
+ if (window->status && window->statusbar_visible)
+ {
+ gchar *message;
+
+ message = g_strdup_printf (_("Word `%s' selected"), word);
+ gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, message);
+ g_free (message);
+ }
+}
+
+static void
+sidebar_page_changed_cb (GdictSidebar *sidebar,
+ GdictWindow *window)
+{
+ const gchar *page_id;
+ const gchar *message;
+
+ page_id = gdict_sidebar_current_page (sidebar);
+
+ switch (page_id[0])
+ {
+ case 's':
+ {
+ switch (page_id[1])
+ {
+ case 'p': /* speller */
+ message = _("Double-click on the word to look up");
+ if (window->word)
+ gdict_speller_match (GDICT_SPELLER (window->speller),
+ window->word);
+ break;
+ case 't': /* strat-chooser */
+ message = _("Double-click on the matching strategy to use");
+
+ gdict_strategy_chooser_refresh (GDICT_STRATEGY_CHOOSER (window->strat_chooser));
+ break;
+ case 'o': /* source-chooser */
+ message = _("Double-click on the source to use");
+ gdict_source_chooser_refresh (GDICT_SOURCE_CHOOSER (window->source_chooser));
+ break;
+ default:
+ message = NULL;
+ }
+ }
+ break;
+ case 'd': /* db-chooser */
+ message = _("Double-click on the database to use");
+
+ gdict_database_chooser_refresh (GDICT_DATABASE_CHOOSER (window->db_chooser));
+ break;
+ default:
+ message = NULL;
+ break;
+ }
+
+ if (message && window->status && window->statusbar_visible)
+ gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, message);
+}
+
+static void
+sidebar_closed_cb (GdictSidebar *sidebar,
+ GdictWindow *window)
+{
+ gdict_window_set_sidebar_visible (window, FALSE);
+}
+
+static void
+gdict_window_link_clicked (GdictDefbox *defbox,
+ const gchar *link_text,
+ GdictWindow *window)
+{
+ GtkWidget *new_window;
+
+ /* store the default size of the window and its state, so that
+ * it's picked up by the newly created window
+ */
+ mateconf_client_set_int (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_WIDTH_KEY,
+ window->default_width,
+ NULL);
+ mateconf_client_set_int (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_HEIGHT_KEY,
+ window->default_height,
+ NULL);
+ mateconf_client_set_bool (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_IS_MAXIMIZED_KEY,
+ window->is_maximized,
+ NULL);
+ mateconf_client_set_bool (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_VISIBLE_KEY,
+ window->sidebar_visible,
+ NULL);
+ mateconf_client_set_int (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_WIDTH_KEY,
+ window->sidebar_width,
+ NULL);
+ mateconf_client_set_string (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_PAGE_KEY,
+ gdict_sidebar_current_page (GDICT_SIDEBAR (window->sidebar)),
+ NULL);
+ mateconf_client_set_bool (window->mateconf_client,
+ GDICT_MATECONF_STATUSBAR_VISIBLE_KEY,
+ window->statusbar_visible,
+ NULL);
+
+ new_window = gdict_window_new (GDICT_WINDOW_ACTION_LOOKUP,
+ window->loader,
+ NULL, link_text);
+ gtk_widget_show (new_window);
+
+ g_signal_emit (window, gdict_window_signals[CREATED], 0, new_window);
+}
+
+static void
+gdict_window_drag_data_received_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *data,
+ guint info,
+ guint time_,
+ gpointer user_data)
+{
+ GdictWindow *window = GDICT_WINDOW (user_data);
+ gchar *text;
+
+ text = (gchar *) gtk_selection_data_get_text (data);
+ if (text)
+ {
+ gtk_entry_set_text (GTK_ENTRY (window->entry), text);
+
+ gdict_window_set_word (window, text, NULL);
+ g_free (text);
+
+ gtk_drag_finish (context, TRUE, FALSE, time_);
+ }
+ else
+ gtk_drag_finish (context, FALSE, FALSE, time_);
+}
+
+static void
+gdict_window_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GdictWindow *window = GDICT_WINDOW (widget);
+
+ if (!window->is_maximized)
+ {
+ window->default_width = allocation->width;
+ window->default_height = allocation->height;
+ }
+
+ if (GTK_WIDGET_CLASS (gdict_window_parent_class)->size_allocate)
+ GTK_WIDGET_CLASS (gdict_window_parent_class)->size_allocate (widget,
+ allocation);
+}
+
+static void
+set_window_default_size (GdictWindow *window)
+{
+ GtkWidget *widget;
+ gboolean is_maximized;
+ gint width, height;
+ gint font_size;
+ GdkScreen *screen;
+ gint monitor_num;
+ GtkRequisition req;
+ GdkRectangle monitor;
+
+ g_assert (GDICT_IS_WINDOW (window));
+
+ widget = GTK_WIDGET (window);
+
+ /* make sure that the widget is realized */
+ gtk_widget_realize (widget);
+
+ /* recover the state from MateConf */
+ width = mateconf_client_get_int (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_WIDTH_KEY,
+ NULL);
+ height = mateconf_client_get_int (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_HEIGHT_KEY,
+ NULL);
+ is_maximized = mateconf_client_get_bool (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_IS_MAXIMIZED_KEY,
+ NULL);
+
+ /* XXX - the user wants mate-dictionary to resize itself, so
+ * we compute the minimum safe geometry needed for displaying
+ * the text returned by a dictionary server, which is based
+ * on the font size and the ANSI terminal. this is dumb,
+ * I know, but dictionary servers return pre-formatted text
+ * and we can't reformat it ourselves.
+ */
+ if (width == -1 || height == -1)
+ {
+ /* Size based on the font size */
+ GtkWidget *defbox = window->defbox;
+
+ font_size = pango_font_description_get_size (gtk_widget_get_style (defbox)->font_desc);
+ font_size = PANGO_PIXELS (font_size);
+
+ width = font_size * GDICT_WINDOW_COLUMNS;
+ height = font_size * GDICT_WINDOW_ROWS;
+
+ /* Use at least the requisition size of the window... */
+ gtk_widget_size_request (widget, &req);
+ width = MAX (width, req.width);
+ height = MAX (height, req.height);
+
+ /* ... but make it no larger than the monitor */
+ screen = gtk_widget_get_screen (widget);
+ monitor_num = gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window (widget));
+
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+ width = MIN (width, monitor.width * 3 / 4);
+ height = MIN (height, monitor.height * 3 / 4);
+ }
+
+ /* Set default size */
+ gtk_window_set_default_size (GTK_WINDOW (widget),
+ width,
+ height);
+
+ if (is_maximized)
+ gtk_window_maximize (GTK_WINDOW (widget));
+}
+
+static void
+gdict_window_style_set (GtkWidget *widget,
+ GtkStyle *old_style)
+{
+
+ if (GTK_WIDGET_CLASS (gdict_window_parent_class)->style_set)
+ GTK_WIDGET_CLASS (gdict_window_parent_class)->style_set (widget, old_style);
+
+ set_window_default_size (GDICT_WINDOW (widget));
+}
+
+static void
+gdict_window_handle_notify_position_cb (GtkWidget *widget,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GdictWindow *window = GDICT_WINDOW (user_data);
+ gint window_width, pos;
+ GtkAllocation allocation;
+
+ pos = gtk_paned_get_position (GTK_PANED (widget));
+ gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
+ window_width = allocation.width;
+
+ window->sidebar_width = window_width - pos;
+}
+
+static GObject *
+gdict_window_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GdictWindow *window;
+ gint width, height, sidebar_width;
+ gboolean is_maximized;
+ GtkWidget *hbox;
+ GtkWidget *handle;
+ GtkWidget *frame1, *frame2;
+ GtkWidget *vbox;
+ GtkWidget *button;
+ GtkActionGroup *action_group;
+ GtkAccelGroup *accel_group;
+ PangoFontDescription *font_desc;
+ gchar *font_name, *sidebar_page;
+ GError *error;
+ gboolean sidebar_visible;
+ gboolean statusbar_visible;
+ GtkAllocation allocation;
+
+ object = G_OBJECT_CLASS (gdict_window_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_params);
+ window = GDICT_WINDOW (object);
+
+ gtk_widget_push_composite_child ();
+
+ window->main_box = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), window->main_box);
+ gtk_widget_show (window->main_box);
+
+ /* build menus */
+ action_group = gtk_action_group_new ("MenuActions");
+ window->action_group = action_group;
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ gtk_action_group_add_actions (action_group, entries,
+ G_N_ELEMENTS (entries),
+ window);
+ gtk_action_group_add_toggle_actions (action_group, toggle_entries,
+ G_N_ELEMENTS (toggle_entries),
+ window);
+
+ window->ui_manager = gtk_ui_manager_new ();
+ gtk_ui_manager_insert_action_group (window->ui_manager, action_group, 0);
+
+ accel_group = gtk_ui_manager_get_accel_group (window->ui_manager);
+ gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+
+ error = NULL;
+ if (!gtk_ui_manager_add_ui_from_file (window->ui_manager,
+ PKGDATADIR "/mate-dictionary-ui.xml",
+ &error))
+ {
+ g_warning ("Building menus failed: %s", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ window->menubar = gtk_ui_manager_get_widget (window->ui_manager, "/MainMenu");
+
+ gtk_box_pack_start (GTK_BOX (window->main_box), window->menubar, FALSE, FALSE, 0);
+ gtk_widget_show (window->menubar);
+
+ gdict_window_ensure_menu_state (window);
+ }
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+ gtk_container_add (GTK_CONTAINER (window->main_box), vbox);
+ gtk_widget_show (vbox);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ button = gtk_button_new_with_mnemonic (_("Look _up:"));
+ g_signal_connect_swapped (button, "clicked",
+ G_CALLBACK (lookup_word),
+ window);
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ window->completion_model = gtk_list_store_new (COMPLETION_N_COLUMNS,
+ G_TYPE_STRING);
+
+ window->completion = gtk_entry_completion_new ();
+ gtk_entry_completion_set_popup_completion (window->completion, TRUE);
+ gtk_entry_completion_set_model (window->completion,
+ GTK_TREE_MODEL (window->completion_model));
+ gtk_entry_completion_set_text_column (window->completion,
+ COMPLETION_TEXT_COLUMN);
+
+ window->entry = gtk_entry_new ();
+ if (window->word)
+ gtk_entry_set_text (GTK_ENTRY (window->entry), window->word);
+
+ gtk_entry_set_completion (GTK_ENTRY (window->entry),
+ window->completion);
+ g_signal_connect_swapped (window->entry, "activate",
+ G_CALLBACK (lookup_word),
+ window);
+ gtk_box_pack_start (GTK_BOX (hbox), window->entry, TRUE, TRUE, 0);
+ gtk_widget_show (window->entry);
+
+ handle = gtk_hpaned_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), handle, TRUE, TRUE, 0);
+ gtk_widget_show (handle);
+
+ frame1 = gtk_vbox_new (FALSE, 0);
+ frame2 = gtk_vbox_new (FALSE, 0);
+
+ window->defbox = gdict_defbox_new ();
+ if (window->context)
+ gdict_defbox_set_context (GDICT_DEFBOX (window->defbox), window->context);
+
+ g_signal_connect (window->defbox, "link-clicked",
+ G_CALLBACK (gdict_window_link_clicked),
+ window);
+
+ gtk_drag_dest_set (window->defbox,
+ GTK_DEST_DEFAULT_ALL,
+ drop_types, n_drop_types,
+ GDK_ACTION_COPY);
+ g_signal_connect (window->defbox, "drag-data-received",
+ G_CALLBACK (gdict_window_drag_data_received_cb),
+ window);
+ gtk_container_add (GTK_CONTAINER (frame1), window->defbox);
+ gtk_widget_show (window->defbox);
+
+ /* Sidebar */
+ window->sidebar = gdict_sidebar_new ();
+ g_signal_connect (window->sidebar, "page-changed",
+ G_CALLBACK (sidebar_page_changed_cb),
+ window);
+ g_signal_connect (window->sidebar, "closed",
+ G_CALLBACK (sidebar_closed_cb),
+ window);
+
+ /* Speller */
+ window->speller = gdict_speller_new ();
+ if (window->context)
+ gdict_speller_set_context (GDICT_SPELLER (window->speller),
+ window->context);
+ g_signal_connect (window->speller, "word-activated",
+ G_CALLBACK (speller_word_activated_cb),
+ window);
+ gdict_sidebar_add_page (GDICT_SIDEBAR (window->sidebar),
+ GDICT_SIDEBAR_SPELLER_PAGE,
+ _("Similar words"),
+ window->speller);
+ gtk_widget_show (window->speller);
+
+ /* Database chooser */
+ if (window->context)
+ gdict_database_chooser_set_context (GDICT_DATABASE_CHOOSER (window->db_chooser),
+ window->context);
+ g_signal_connect (window->db_chooser, "database-activated",
+ G_CALLBACK (database_activated_cb),
+ window);
+ gdict_sidebar_add_page (GDICT_SIDEBAR (window->sidebar),
+ GDICT_SIDEBAR_DATABASES_PAGE,
+ _("Available dictionaries"),
+ window->db_chooser);
+ gtk_widget_show (window->db_chooser);
+
+ /* Strategy chooser */
+ if (window->context)
+ gdict_strategy_chooser_set_context (GDICT_STRATEGY_CHOOSER (window->strat_chooser),
+ window->context);
+ g_signal_connect (window->strat_chooser, "strategy-activated",
+ G_CALLBACK (strategy_activated_cb),
+ window);
+ gdict_sidebar_add_page (GDICT_SIDEBAR (window->sidebar),
+ GDICT_SIDEBAR_STRATEGIES_PAGE,
+ _("Available strategies"),
+ window->strat_chooser);
+ gtk_widget_show (window->strat_chooser);
+
+ /* Source chooser */
+ window->source_chooser = gdict_source_chooser_new_with_loader (window->loader);
+ g_signal_connect (window->source_chooser, "source-activated",
+ G_CALLBACK (source_activated_cb),
+ window);
+ gdict_sidebar_add_page (GDICT_SIDEBAR (window->sidebar),
+ GDICT_SIDEBAR_SOURCES_PAGE,
+ _("Dictionary sources"),
+ window->source_chooser);
+ gtk_widget_show (window->source_chooser);
+
+ gtk_container_add (GTK_CONTAINER (frame2), window->sidebar);
+ gtk_widget_show (window->sidebar);
+
+ gtk_paned_pack1 (GTK_PANED (handle), frame1, TRUE, FALSE);
+ gtk_paned_pack2 (GTK_PANED (handle), frame2, FALSE, TRUE);
+
+ window->defbox_frame = frame1;
+ window->sidebar_frame = frame2;
+
+ gtk_widget_show (window->defbox_frame);
+
+ window->status = gtk_statusbar_new ();
+ gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (window->status), TRUE);
+ gtk_box_pack_end (GTK_BOX (window->main_box), window->status, FALSE, FALSE, 0);
+ statusbar_visible = mateconf_client_get_bool (window->mateconf_client,
+ GDICT_MATECONF_STATUSBAR_VISIBLE_KEY,
+ NULL);
+ gdict_window_set_statusbar_visible (window, statusbar_visible);
+
+ window->progress = gtk_progress_bar_new ();
+ gtk_box_pack_end (GTK_BOX (window->status), window->progress, FALSE, FALSE, 0);
+
+ /* retrieve the font size from mateconf */
+ font_name = gdict_mateconf_get_string_with_default (window->mateconf_client,
+ DOCUMENT_FONT_KEY,
+ GDICT_DEFAULT_DEFBOX_FONT);
+
+ gdict_window_set_defbox_font (window, font_name);
+ font_desc = pango_font_description_from_string (font_name);
+ g_free (font_name);
+
+ sidebar_visible = mateconf_client_get_bool (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_VISIBLE_KEY,
+ NULL);
+ gdict_window_set_sidebar_visible (window, sidebar_visible);
+
+ /* retrieve the window state from mateconf */
+ is_maximized = mateconf_client_get_bool (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_IS_MAXIMIZED_KEY,
+ NULL);
+
+ width = mateconf_client_get_int (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_WIDTH_KEY,
+ NULL);
+ height = mateconf_client_get_int (window->mateconf_client,
+ GDICT_MATECONF_WINDOW_HEIGHT_KEY,
+ NULL);
+ sidebar_width = mateconf_client_get_int (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_WIDTH_KEY,
+ NULL);
+ sidebar_page = mateconf_client_get_string (window->mateconf_client,
+ GDICT_MATECONF_SIDEBAR_PAGE_KEY,
+ NULL);
+
+ /* if the (width, height) tuple is not defined, use the font to
+ * calculate the right window geometry
+ */
+ if (width == -1 || height == -1)
+ {
+ gint font_size;
+
+ font_size = pango_font_description_get_size (font_desc);
+ font_size = PANGO_PIXELS (font_size);
+
+ width = MAX (GDICT_WINDOW_COLUMNS * font_size, GDICT_WINDOW_MIN_WIDTH);
+ height = MAX (GDICT_WINDOW_ROWS * font_size, GDICT_WINDOW_MIN_HEIGHT);
+ }
+ else
+ {
+ window->default_width = width;
+ window->default_height = height;
+ }
+
+ pango_font_description_free (font_desc);
+
+ window->is_maximized = is_maximized;
+
+ gtk_window_set_title (GTK_WINDOW (window), _("Dictionary"));
+ gtk_window_set_default_size (GTK_WINDOW (window),
+ width,
+ height);
+ if (is_maximized)
+ gtk_window_maximize (GTK_WINDOW (window));
+
+ gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
+ gtk_paned_set_position (GTK_PANED (handle), allocation.width - sidebar_width);
+ if (sidebar_page)
+ {
+ gdict_sidebar_view_page (GDICT_SIDEBAR (window->sidebar), sidebar_page);
+ g_free (sidebar_page);
+ }
+
+ g_signal_connect (window, "delete-event",
+ G_CALLBACK (gdict_window_delete_event_cb),
+ NULL);
+ g_signal_connect (window, "window-state-event",
+ G_CALLBACK (gdict_window_state_event_cb),
+ NULL);
+ g_signal_connect (handle, "notify::position",
+ G_CALLBACK (gdict_window_handle_notify_position_cb),
+ window);
+
+ gtk_widget_grab_focus (window->entry);
+
+ gtk_widget_pop_composite_child ();
+
+ return object;
+}
+
+static void
+gdict_window_class_init (GdictWindowClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gobject_class->finalize = gdict_window_finalize;
+ gobject_class->dispose = gdict_window_dispose;
+ gobject_class->set_property = gdict_window_set_property;
+ gobject_class->get_property = gdict_window_get_property;
+ gobject_class->constructor = gdict_window_constructor;
+
+ widget_class->style_set = gdict_window_style_set;
+ widget_class->size_allocate = gdict_window_size_allocate;
+
+ g_object_class_install_property (gobject_class,
+ PROP_ACTION,
+ g_param_spec_enum ("action",
+ "Action",
+ "The default action performed by the window",
+ GDICT_TYPE_WINDOW_ACTION,
+ GDICT_WINDOW_ACTION_CLEAR,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
+ g_object_class_install_property (gobject_class,
+ PROP_SOURCE_LOADER,
+ g_param_spec_object ("source-loader",
+ "Source Loader",
+ "The GdictSourceLoader to be used to load dictionary sources",
+ GDICT_TYPE_SOURCE_LOADER,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+ g_object_class_install_property (gobject_class,
+ PROP_SOURCE_NAME,
+ g_param_spec_string ("source-name",
+ "Source Name",
+ "The name of the GdictSource to be used",
+ GDICT_DEFAULT_SOURCE_NAME,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_PRINT_FONT,
+ g_param_spec_string ("print-font",
+ "Print Font",
+ "The font name to be used when printing",
+ GDICT_DEFAULT_PRINT_FONT,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_DEFBOX_FONT,
+ g_param_spec_string ("defbox-font",
+ "Defbox Font",
+ "The font name to be used by the defbox widget",
+ GDICT_DEFAULT_DEFBOX_FONT,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_WORD,
+ g_param_spec_string ("word",
+ "Word",
+ "The word to search",
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_WINDOW_ID,
+ g_param_spec_uint ("window-id",
+ "Window ID",
+ "The unique identifier for this window",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READABLE));
+
+ gdict_window_signals[CREATED] =
+ g_signal_new ("created",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdictWindowClass, created),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GDICT_TYPE_WINDOW);
+}
+
+static void
+gdict_window_init (GdictWindow *window)
+{
+ GError *mateconf_error;
+
+ window->action = GDICT_WINDOW_ACTION_CLEAR;
+
+ window->loader = NULL;
+ window->context = NULL;
+
+ window->mateconf_client = mateconf_client_get_default ();
+
+ mateconf_error = NULL;
+ mateconf_client_add_dir (window->mateconf_client,
+ GDICT_MATECONF_DIR,
+ MATECONF_CLIENT_PRELOAD_NONE,
+ &mateconf_error);
+ if (mateconf_error)
+ {
+ gdict_show_gerror_dialog (NULL,
+ _("Unable to connect to MateConf"),
+ mateconf_error);
+ }
+
+ window->notify_id = mateconf_client_notify_add (window->mateconf_client,
+ GDICT_MATECONF_DIR,
+ gdict_window_mateconf_notify_cb,
+ window,
+ NULL,
+ &mateconf_error);
+ if (mateconf_error)
+ {
+ gdict_show_gerror_dialog (NULL,
+ _("Unable to get notification for preferences"),
+ mateconf_error);
+ }
+
+ window->font_notify_id = mateconf_client_notify_add (window->mateconf_client,
+ DOCUMENT_FONT_KEY,
+ gdict_window_mateconf_notify_cb,
+ window,
+ NULL,
+ &mateconf_error);
+ if (mateconf_error)
+ {
+ gdict_show_gerror_dialog (NULL,
+ _("Unable to get notification for the document font"),
+ mateconf_error);
+ }
+
+ window->word = NULL;
+ window->source_name = NULL;
+ window->print_font = NULL;
+ window->defbox_font = NULL;
+
+ window->database = NULL;
+ window->strategy = NULL;
+
+ window->default_width = -1;
+ window->default_height = -1;
+ window->is_maximized = FALSE;
+
+ window->window_id = (gulong) time (NULL);
+
+ /* we need to create the chooser widgets for the sidebar before
+ * we set the construction properties
+ */
+ window->db_chooser = gdict_database_chooser_new ();
+ window->strat_chooser = gdict_strategy_chooser_new ();
+}
+
+GtkWidget *
+gdict_window_new (GdictWindowAction action,
+ GdictSourceLoader *loader,
+ const gchar *source_name,
+ const gchar *word)
+{
+ GtkWidget *retval;
+ GdictWindow *window;
+
+ g_return_val_if_fail (GDICT_IS_SOURCE_LOADER (loader), NULL);
+
+ retval = g_object_new (GDICT_TYPE_WINDOW,
+ "action", action,
+ "source-loader", loader,
+ "source-name", source_name,
+ NULL);
+
+ window = GDICT_WINDOW (retval);
+
+ if (word && word[0] != '\0')
+ {
+ switch (action)
+ {
+ case GDICT_WINDOW_ACTION_LOOKUP:
+ gtk_entry_set_text (GTK_ENTRY (window->entry), word);
+ gdict_window_set_word (window, word, NULL);
+ break;
+ case GDICT_WINDOW_ACTION_MATCH:
+ {
+ GdictSource *source;
+ GdictContext *context;
+
+ gtk_entry_set_text (GTK_ENTRY (window->entry), word);
+
+ gdict_window_set_sidebar_visible (window, TRUE);
+ gdict_sidebar_view_page (GDICT_SIDEBAR (window->sidebar),
+ GDICT_SIDEBAR_SPELLER_PAGE);
+
+ /* we clone the context, so that the signals that it
+ * fires do not get caught by the signal handlers we
+ * use for getting the definitions.
+ */
+ source = gdict_source_loader_get_source (window->loader,
+ window->source_name);
+ context = gdict_source_get_context (source);
+
+ gdict_speller_set_context (GDICT_SPELLER (window->speller), context);
+
+ g_object_unref (context);
+ g_object_unref (source);
+
+ gdict_speller_set_strategy (GDICT_SPELLER (window->speller),
+ window->strategy);
+
+ gdict_speller_match (GDICT_SPELLER (window->speller), word);
+ }
+ case GDICT_WINDOW_ACTION_CLEAR:
+ gdict_defbox_clear (GDICT_DEFBOX (window->defbox));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ return retval;
+}
+
+/* GdictWindowAction */
+static const GEnumValue _gdict_window_action_values[] = {
+ { GDICT_WINDOW_ACTION_LOOKUP, "GDICT_WINDOW_ACTION_LOOKUP", "lookup" },
+ { GDICT_WINDOW_ACTION_MATCH, "GDICT_WINDOW_ACTION_MATCH", "match" },
+ { GDICT_WINDOW_ACTION_CLEAR, "GDICT_WINDOW_ACTION_CLEAR", "clear" },
+ { 0, NULL, NULL }
+};
+
+GType
+gdict_window_action_get_type (void)
+{
+ static GType our_type = 0;
+
+ if (!our_type)
+ our_type = g_enum_register_static ("GdictWindowAction", _gdict_window_action_values);
+
+ return our_type;
+}
diff --git a/mate-dictionary/src/gdict-window.h b/mate-dictionary/src/gdict-window.h
new file mode 100644
index 00000000..36455cba
--- /dev/null
+++ b/mate-dictionary/src/gdict-window.h
@@ -0,0 +1,129 @@
+/* gdict-window.h - main application window
+ *
+ * This file is part of MATE Dictionary
+ *
+ * Copyright (C) 2005 Emmanuele Bassi
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GDICT_WINDOW_H__
+#define __GDICT_WINDOW_H__
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+#include <libgdict/gdict.h>
+
+G_BEGIN_DECLS
+
+#define GDICT_TYPE_WINDOW (gdict_window_get_type ())
+#define GDICT_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDICT_TYPE_WINDOW, GdictWindow))
+#define GDICT_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDICT_TYPE_WINDOW))
+
+typedef enum {
+ GDICT_WINDOW_ACTION_LOOKUP,
+ GDICT_WINDOW_ACTION_MATCH,
+ GDICT_WINDOW_ACTION_CLEAR
+} GdictWindowAction;
+
+#define GDICT_TYPE_WINDOW_ACTION (gdict_window_action_get_type ())
+GType gdict_window_action_get_type (void) G_GNUC_CONST;
+
+typedef struct _GdictWindow GdictWindow;
+typedef struct _GdictWindowClass GdictWindowClass;
+
+struct _GdictWindow
+{
+ GtkWindow parent_instance;
+
+ GtkWidget *main_box;
+ GtkWidget *menubar;
+ GtkWidget *entry;
+
+ /* sidebar widgets */
+ GtkWidget *speller;
+ GtkWidget *db_chooser;
+ GtkWidget *strat_chooser;
+ GtkWidget *source_chooser;
+
+ GtkWidget *sidebar;
+ GtkWidget *sidebar_frame;
+
+ GtkWidget *defbox;
+ GtkWidget *defbox_frame;
+
+ GtkWidget *status;
+ GtkWidget *progress;
+
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+
+ GtkEntryCompletion *completion;
+ GtkListStore *completion_model;
+
+ GdictWindowAction action;
+
+ gchar *word;
+ gint max_definition;
+ gint last_definition;
+ gint current_definition;
+
+ gchar *source_name;
+ GdictSourceLoader *loader;
+ GdictContext *context;
+ guint definition_id;
+ guint lookup_start_id;
+ guint lookup_end_id;
+ guint error_id;
+
+ gchar *database;
+ gchar *strategy;
+ gchar *print_font;
+ gchar *defbox_font;
+
+ MateConfClient *mateconf_client;
+ guint notify_id;
+ guint font_notify_id;
+
+ GdkCursor *busy_cursor;
+
+ gint default_width;
+ gint default_height;
+ gint sidebar_width;
+
+ guint is_maximized : 1;
+ guint sidebar_visible : 1;
+ guint statusbar_visible : 1;
+
+ gulong window_id;
+};
+
+struct _GdictWindowClass
+{
+ GtkWindowClass parent_class;
+
+ void (*created) (GdictWindow *parent_window,
+ GdictWindow *new_window);
+};
+
+GType gdict_window_get_type (void) G_GNUC_CONST;
+GtkWidget *gdict_window_new (GdictWindowAction action,
+ GdictSourceLoader *loader,
+ const gchar *source_name,
+ const gchar *word);
+
+#endif /* __GDICT_WINDOW_H__ */
diff --git a/mate-dictionary/src/main.c b/mate-dictionary/src/main.c
new file mode 100644
index 00000000..f6dcc94d
--- /dev/null
+++ b/mate-dictionary/src/main.c
@@ -0,0 +1,24 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libintl.h>
+
+#include "gdict-app.h"
+
+int main (int argc, char *argv[])
+{
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gdict_init (&argc, &argv);
+
+ gdict_main ();
+
+ gdict_cleanup ();
+
+ return EXIT_SUCCESS;
+}