[evolution/webkit-composer: 4/150] Import GtkhtmlFace* classes as EEmoticon*
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/webkit-composer: 4/150] Import GtkhtmlFace* classes as EEmoticon*
- Date: Wed, 6 Feb 2013 00:11:17 +0000 (UTC)
commit 329561a3693f78816e001d0d0b274d916c91b4dc
Author: Dan VrÃtil <dvratil redhat com>
Date: Mon Jul 23 14:34:15 2012 +0200
Import GtkhtmlFace* classes as EEmoticon*
GtkhtmlFaceAction => EEmoticonAction
GtkhtmlFaceChooserMenu => EEmoticonChooserMenu
GtkhtmlFaceChooser => EEmoticonChooser
GtkhtmlToolButton => EEmoticonToolButton
GtkhtmlFace => EEmoticon
e-util/Makefile.am | 10 +
e-util/e-emoticon-action.c | 295 ++++++++++++++++
e-util/e-emoticon-action.h | 69 ++++
e-util/e-emoticon-chooser-menu.c | 206 +++++++++++
e-util/e-emoticon-chooser-menu.h | 65 ++++
e-util/e-emoticon-chooser.c | 180 ++++++++++
e-util/e-emoticon-chooser.h | 69 ++++
e-util/e-emoticon-tool-button.c | 711 ++++++++++++++++++++++++++++++++++++++
e-util/e-emoticon-tool-button.h | 71 ++++
e-util/e-emoticon.c | 89 +++++
e-util/e-emoticon.h | 48 +++
e-util/e-util.h | 5 +
12 files changed, 1818 insertions(+), 0 deletions(-)
---
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 44bb8db..7ba9595 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -170,6 +170,11 @@ eutilinclude_HEADERS = \
e-dialog-widgets.h \
e-editor-selection.h \
e-editor-widget.h \
+ e-emoticon-action.h \
+ e-emoticon-chooser-menu.h \
+ e-emoticon-chooser.h \
+ e-emoticon-tool-button.h \
+ e-emoticon.h \
e-event.h \
e-file-request.h \
e-file-utils.h \
@@ -417,6 +422,11 @@ libeutil_la_SOURCES = \
e-dialog-widgets.c \
e-editor-selection.c \
e-editor-widget.c \
+ e-emoticon-action.c \
+ e-emoticon-chooser-menu.c \
+ e-emoticon-chooser.c \
+ e-emoticon-tool-button.c \
+ e-emoticon.c \
e-event.c \
e-file-request.c \
e-file-utils.c \
diff --git a/e-util/e-emoticon-action.c b/e-util/e-emoticon-action.c
new file mode 100644
index 0000000..7ff674c
--- /dev/null
+++ b/e-util/e-emoticon-action.c
@@ -0,0 +1,295 @@
+/* e-emoticon-action.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser 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.
+ */
+
+#include "e-emoticon-action.h"
+
+#include "e-emoticon-chooser.h"
+#include "e-emoticon-chooser-menu.h"
+#include "e-emoticon-tool-button.h"
+
+struct _EEmoticonActionPrivate {
+ GList *choosers;
+ EEmoticonChooser *current_chooser;
+};
+
+enum {
+ PROP_0,
+ PROP_CURRENT_FACE
+};
+
+static gpointer parent_class;
+
+static void
+emoticon_action_proxy_item_activated_cb (EEmoticonAction *action,
+ EEmoticonChooser *chooser)
+{
+ action->priv->current_chooser = chooser;
+
+ g_signal_emit_by_name (action, "item-activated");
+}
+
+static void
+emoticon_action_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CURRENT_FACE:
+ e_emoticon_chooser_set_current_emoticon (
+ E_EMOTICON_CHOOSER (object),
+ g_value_get_boxed (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+emoticon_action_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CURRENT_FACE:
+ g_value_set_boxed (
+ value, e_emoticon_chooser_get_current_emoticon (
+ E_EMOTICON_CHOOSER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+emoticon_action_finalize (GObject *object)
+{
+ EEmoticonActionPrivate *priv;
+
+ priv = E_EMOTICON_ACTION (object)->priv;
+
+ g_list_free (priv->choosers);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+emoticon_action_activate (GtkAction *action)
+{
+ EEmoticonActionPrivate *priv;
+
+ priv = E_EMOTICON_ACTION (action)->priv;
+
+ priv->current_chooser = NULL;
+}
+
+static GtkWidget *
+emoticon_action_create_menu_item (GtkAction *action)
+{
+ GtkWidget *item;
+ GtkWidget *menu;
+
+ item = gtk_image_menu_item_new ();
+ menu = gtk_action_create_menu (action);
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
+ gtk_widget_show (menu);
+
+ return item;
+}
+
+static GtkWidget *
+emoticon_action_create_tool_item (GtkAction *action)
+{
+ return GTK_WIDGET (e_emoticon_tool_button_new ());
+}
+
+static void
+emoticon_action_connect_proxy (GtkAction *action,
+ GtkWidget *proxy)
+{
+ EEmoticonActionPrivate *priv;
+
+ priv = E_EMOTICON_ACTION (action)->priv;
+
+ if (!E_IS_EMOTICON_CHOOSER (proxy))
+ goto chainup;
+
+ if (g_list_find (priv->choosers, proxy) != NULL)
+ goto chainup;
+
+ g_signal_connect_swapped (
+ proxy, "item-activated",
+ G_CALLBACK (emoticon_action_proxy_item_activated_cb), action);
+
+chainup:
+ /* Chain up to parent's connect_proxy() method. */
+ GTK_ACTION_CLASS (parent_class)->connect_proxy (action, proxy);
+}
+
+static void
+emoticon_action_disconnect_proxy (GtkAction *action,
+ GtkWidget *proxy)
+{
+ EEmoticonActionPrivate *priv;
+
+ priv = E_EMOTICON_ACTION (action)->priv;
+
+ priv->choosers = g_list_remove (priv->choosers, proxy);
+
+ /* Chain up to parent's disconnect_proxy() method. */
+ GTK_ACTION_CLASS (parent_class)->disconnect_proxy (action, proxy);
+}
+
+static GtkWidget *
+emoticon_action_create_menu (GtkAction *action)
+{
+ EEmoticonActionPrivate *priv;
+ GtkWidget *widget;
+
+ priv = E_EMOTICON_ACTION (action)->priv;
+
+ widget = e_emoticon_chooser_menu_new ();
+
+ g_signal_connect_swapped (
+ widget, "item-activated",
+ G_CALLBACK (emoticon_action_proxy_item_activated_cb), action);
+
+ priv->choosers = g_list_prepend (priv->choosers, widget);
+
+ return widget;
+}
+
+static EEmoticon *
+emoticon_action_get_current_emoticon (EEmoticonChooser *chooser)
+{
+ EEmoticonActionPrivate *priv;
+ EEmoticon *emoticon = NULL;
+
+ priv = E_EMOTICON_ACTION (chooser)->priv;
+
+ if (priv->current_chooser != NULL)
+ emoticon = e_emoticon_chooser_get_current_emoticon (
+ priv->current_chooser);
+
+ return emoticon;
+}
+
+static void
+emoticon_action_set_current_emoticon (EEmoticonChooser *chooser,
+ EEmoticon *emoticon)
+{
+ EEmoticonActionPrivate *priv;
+ GList *iter;
+
+ priv = E_EMOTICON_ACTION (chooser)->priv;
+
+ for (iter = priv->choosers; iter != NULL; iter = iter->next) {
+ EEmoticonChooser *proxy_chooser = iter->data;
+
+ e_emoticon_chooser_set_current_emoticon (proxy_chooser, emoticon);
+ }
+}
+
+static void
+emoticon_action_class_init (EEmoticonActionClass *class)
+{
+ GObjectClass *object_class;
+ GtkActionClass *action_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EEmoticonAction));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = emoticon_action_set_property;
+ object_class->get_property = emoticon_action_get_property;
+ object_class->finalize = emoticon_action_finalize;
+
+ action_class = GTK_ACTION_CLASS (class);
+ action_class->activate = emoticon_action_activate;
+ action_class->create_menu_item = emoticon_action_create_menu_item;
+ action_class->create_tool_item = emoticon_action_create_tool_item;
+ action_class->connect_proxy = emoticon_action_connect_proxy;
+ action_class->disconnect_proxy = emoticon_action_disconnect_proxy;
+ action_class->create_menu = emoticon_action_create_menu;
+
+ g_object_class_override_property (
+ object_class, PROP_CURRENT_FACE, "current-emoticon");
+}
+
+static void
+emoticon_action_iface_init (EEmoticonChooserIface *iface)
+{
+ iface->get_current_emoticon = emoticon_action_get_current_emoticon;
+ iface->set_current_emoticon = emoticon_action_set_current_emoticon;
+}
+
+static void
+emoticon_action_init (EEmoticonAction *action)
+{
+ action->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+ action, E_TYPE_EMOTICON_ACTION, EEmoticonActionPrivate);
+}
+
+GType
+e_emoticon_action_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EEmoticonActionClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) emoticon_action_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EEmoticonAction),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) emoticon_action_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) emoticon_action_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interemoticon_data */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_ACTION, "EEmoticonAction", &type_info, 0);
+
+ g_type_add_interface_static (
+ type, E_TYPE_EMOTICON_CHOOSER, &iface_info);
+ }
+
+ return type;
+}
+
+GtkAction *
+e_emoticon_action_new (const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *stock_id)
+{
+ g_return_val_if_fail (name != NULL, NULL);
+
+ return g_object_new (
+ E_TYPE_EMOTICON_ACTION, "name", name, "label", label,
+ "tooltip", tooltip, "stock-id", stock_id, NULL);
+}
diff --git a/e-util/e-emoticon-action.h b/e-util/e-emoticon-action.h
new file mode 100644
index 0000000..388b851
--- /dev/null
+++ b/e-util/e-emoticon-action.h
@@ -0,0 +1,69 @@
+/* e-emoticon-action.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser 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.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_EMOTICON_ACTION_H
+#define E_EMOTICON_ACTION_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_EMOTICON_ACTION \
+ (e_emoticon_action_get_type ())
+#define E_EMOTICON_ACTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_EMOTICON_ACTION, EEmoticonAction))
+#define E_EMOTICON_ACTION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_EMOTICON_ACTION, EEmoticonActionClass))
+#define E_IS_EMOTICON_ACTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_EMOTICON_ACTION))
+#define E_IS_EMOTICON_ACTION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_EMOTICON_ACTION))
+#define E_EMOTICON_ACTION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_EMOTICON_ACTION, EEmoticonActionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EEmoticonAction EEmoticonAction;
+typedef struct _EEmoticonActionClass EEmoticonActionClass;
+typedef struct _EEmoticonActionPrivate EEmoticonActionPrivate;
+
+struct _EEmoticonAction {
+ GtkAction parent;
+ EEmoticonActionPrivate *priv;
+};
+
+struct _EEmoticonActionClass {
+ GtkActionClass parent_class;
+};
+
+GType e_emoticon_action_get_type (void);
+GtkAction * e_emoticon_action_new (const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *stock_id);
+
+G_END_DECLS
+
+#endif /* E_EMOTICON_ACTION_H */
diff --git a/e-util/e-emoticon-chooser-menu.c b/e-util/e-emoticon-chooser-menu.c
new file mode 100644
index 0000000..619bd21
--- /dev/null
+++ b/e-util/e-emoticon-chooser-menu.c
@@ -0,0 +1,206 @@
+/* e-emoticon-chooser-menu.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser 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 "e-emoticon-chooser-menu.h"
+#include "e-emoticon-chooser.h"
+
+#include <glib/gi18n-lib.h>
+
+enum {
+ PROP_0,
+ PROP_CURRENT_FACE
+};
+
+static gpointer parent_class;
+
+static void
+emoticon_chooser_menu_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CURRENT_FACE:
+ e_emoticon_chooser_set_current_emoticon (
+ E_EMOTICON_CHOOSER (object),
+ g_value_get_boxed (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+emoticon_chooser_menu_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CURRENT_FACE:
+ g_value_set_boxed (
+ value,
+ e_emoticon_chooser_get_current_emoticon (
+ E_EMOTICON_CHOOSER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static EEmoticon *
+emoticon_chooser_menu_get_current_emoticon (EEmoticonChooser *chooser)
+{
+ GtkWidget *item;
+
+ item = gtk_menu_get_active (GTK_MENU (chooser));
+ if (item == NULL)
+ return NULL;
+
+ return g_object_get_data (G_OBJECT (item), "emoticon");
+}
+
+static void
+emoticon_chooser_menu_set_current_emoticon (EEmoticonChooser *chooser,
+ EEmoticon *emoticon)
+{
+ GList *list, *iter;
+
+ list = gtk_container_get_children (GTK_CONTAINER (chooser));
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ GtkWidget *item = iter->data;
+ EEmoticon *candidate;
+
+ candidate = g_object_get_data (G_OBJECT (item), "emoticon");
+ if (candidate == NULL)
+ continue;
+
+ if (e_emoticon_equal (emoticon, candidate)) {
+ gtk_menu_shell_activate_item (
+ GTK_MENU_SHELL (chooser), item, TRUE);
+ break;
+ }
+ }
+
+ g_list_free (list);
+}
+
+static void
+emoticon_chooser_menu_class_init (EEmoticonChooserMenuClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = emoticon_chooser_menu_set_property;
+ object_class->get_property = emoticon_chooser_menu_get_property;
+
+ g_object_class_override_property (
+ object_class, PROP_CURRENT_FACE, "current-emoticon");
+}
+
+static void
+emoticon_chooser_menu_iface_init (EEmoticonChooserIface *iface)
+{
+ iface->get_current_emoticon = emoticon_chooser_menu_get_current_emoticon;
+ iface->set_current_emoticon = emoticon_chooser_menu_set_current_emoticon;
+}
+
+static void
+emoticon_chooser_menu_init (EEmoticonChooserMenu *chooser_menu)
+{
+ EEmoticonChooser *chooser;
+ GList *list, *iter;
+
+ chooser = E_EMOTICON_CHOOSER (chooser_menu);
+ list = e_emoticon_chooser_get_items (chooser);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ EEmoticon *face = iter->data;
+ GtkWidget *item;
+
+ /* To keep translated strings in subclasses */
+ item = gtk_image_menu_item_new_with_mnemonic (_(face->label));
+ gtk_image_menu_item_set_image (
+ GTK_IMAGE_MENU_ITEM (item),
+ gtk_image_new_from_icon_name (
+ face->icon_name, GTK_ICON_SIZE_MENU));
+ gtk_widget_show (item);
+
+ g_object_set_data_full (
+ G_OBJECT (item), "face",
+ e_emoticon_copy (face),
+ (GDestroyNotify) e_emoticon_free);
+
+ g_signal_connect_swapped (
+ item, "activate",
+ G_CALLBACK (e_emoticon_chooser_item_activated),
+ chooser);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (chooser_menu), item);
+ }
+
+ g_list_free (list);
+}
+
+GType
+e_emoticon_chooser_menu_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EEmoticonChooserMenuClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) emoticon_chooser_menu_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EEmoticonChooserMenu),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) emoticon_chooser_menu_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) emoticon_chooser_menu_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface_data */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_MENU, "EEmoticonChooserMenu",
+ &type_info, 0);
+
+ g_type_add_interface_static (
+ type, E_TYPE_EMOTICON_CHOOSER, &iface_info);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_emoticon_chooser_menu_new (void)
+{
+ return g_object_new (E_TYPE_EMOTICON_CHOOSER_MENU, NULL);
+}
diff --git a/e-util/e-emoticon-chooser-menu.h b/e-util/e-emoticon-chooser-menu.h
new file mode 100644
index 0000000..bbed9aa
--- /dev/null
+++ b/e-util/e-emoticon-chooser-menu.h
@@ -0,0 +1,65 @@
+/* e-emoticon-chooser-menu.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser 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.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_EMOTICON_CHOOSER_MENU_H
+#define E_EMOTICON_CHOOSER_MENU_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_EMOTICON_CHOOSER_MENU \
+ (e_emoticon_chooser_menu_get_type ())
+#define E_EMOTICON_CHOOSER_MENU(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_EMOTICON_CHOOSER_MENU, EEmoticonChooserMenu))
+#define E_EMOTICON_CHOOSER_MENU_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_EMOTICON_CHOOSER_MENU, EEmoticonChooserMenuClass))
+#define E_IS_EMOTICON_CHOOSER_MENU(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_EMOTICON_CHOOSER_MENU))
+#define E_IS_EMOTICON_CHOOSER_MENU_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_EMOTICON_CHOOSER_MENU))
+#define E_EMOTICON_CHOOSER_MENU_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_EMOTICON_CHOOSER_MENU, EEmoticonChooserMenuClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EEmoticonChooserMenu EEmoticonChooserMenu;
+typedef struct _EEmoticonChooserMenuClass EEmoticonChooserMenuClass;
+typedef struct _EEmoticonChooserMenuPrivate EEmoticonChooserMenuPrivate;
+
+struct _EEmoticonChooserMenu {
+ GtkMenu parent;
+};
+
+struct _EEmoticonChooserMenuClass {
+ GtkMenuClass parent_class;
+};
+
+GType e_emoticon_chooser_menu_get_type (void);
+GtkWidget * e_emoticon_chooser_menu_new (void);
+
+G_END_DECLS
+
+#endif /* E_EMOTICON_CHOOSER_MENU_H */
diff --git a/e-util/e-emoticon-chooser.c b/e-util/e-emoticon-chooser.c
new file mode 100644
index 0000000..c8a92b0
--- /dev/null
+++ b/e-util/e-emoticon-chooser.c
@@ -0,0 +1,180 @@
+/* e-emoticon-chooser.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser 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 "e-emoticon-chooser.h"
+
+#include <glib/gi18n-lib.h>
+
+/* Constant version of EEMoticon. */
+typedef struct {
+ const gchar *label;
+ const gchar *icon_name;
+ const gchar *text_face;
+} ConstantEmoticon;
+
+static ConstantEmoticon available_emoticons[] = {
+ /* Translators: :-) */
+ { N_("_Smile"), "face-smile", ":-)" },
+ /* Translators: :-( */
+ { N_("S_ad"), "face-sad", ":-(" },
+ /* Translators: ;-) */
+ { N_("_Wink"), "face-wink", ";-)" },
+ /* Translators: :-P */
+ { N_("Ton_gue"), "face-raspberry", ":-P" },
+ /* Translators: :-)) */
+ { N_("Laug_h"), "face-laugh", ":-))" },
+ /* Translators: :-| */
+ { N_("_Plain"), "face-plain", ":-|" },
+ /* Translators: :-! */
+ { N_("Smi_rk"), "face-smirk", ":-!" },
+ /* Translators: :"-) */
+ { N_("_Embarrassed"), "face-embarrassed", ":\"-)" },
+ /* Translators: :-D */
+ { N_("_Big Smile"), "face-smile-big", ":-D" },
+ /* Translators: :-/ */
+ { N_("Uncer_tain"), "face-uncertain", ":-/" },
+ /* Translators: :-O */
+ { N_("S_urprise"), "face-surprise", ":-O" },
+ /* Translators: :-S */
+ { N_("W_orried"), "face-worried", ":-S" },
+ /* Translators: :-* */
+ { N_("_Kiss"), "face-kiss", ":-*" },
+ /* Translators: X-( */
+ { N_("A_ngry"), "face-angry", "X-(" },
+ /* Translators: B-) */
+ { N_("_Cool"), "face-cool", "B-)" },
+ /* Translators: O:-) */
+ { N_("Ange_l"), "face-angel", "O:-)" },
+ /* Translators: :'( */
+ { N_("Cr_ying"), "face-crying", ":'(" },
+ /* Translators: :-Q */
+ { N_("S_ick"), "face-sick", ":-Q" },
+ /* Translators: |-) */
+ { N_("Tire_d"), "face-tired", "|-)" },
+ /* Translators: >:-) */
+ { N_("De_vilish"), "face-devilish", ">:-)" },
+ /* Translators: :-(|) */
+ { N_("_Monkey"), "face-monkey", ":-(|)" }
+};
+
+enum {
+ ITEM_ACTIVATED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+emoticon_chooser_class_init (EEmoticonChooserIface *iface)
+{
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boxed (
+ "current-emoticon",
+ "Current Emoticon",
+ "Currently selected emoticon",
+ E_TYPE_EMOTICON,
+ G_PARAM_READWRITE));
+
+ signals[ITEM_ACTIVATED] = g_signal_new (
+ "item-activated",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EEmoticonChooserIface, item_activated),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+GType
+e_emoticon_chooser_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EEmoticonChooserIface),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) emoticon_chooser_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ 0, /* instance_size */
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_INTERFACE, "EEmoticonChooser", &type_info, 0);
+
+ g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+ }
+
+ return type;
+}
+
+EEmoticon *
+e_emoticon_chooser_get_current_emoticon (EEmoticonChooser *chooser)
+{
+ EEmoticonChooserIface *iface;
+
+ g_return_val_if_fail (E_IS_EMOTICON_CHOOSER (chooser), NULL);
+
+ iface = E_EMOTICON_CHOOSER_GET_IFACE (chooser);
+ g_return_val_if_fail (iface->get_current_emoticon != NULL, NULL);
+
+ return iface->get_current_emoticon (chooser);
+}
+
+void
+e_emoticon_chooser_set_current_emoticon (EEmoticonChooser *chooser,
+ EEmoticon *emoticon)
+{
+ EEmoticonChooserIface *iface;
+
+ g_return_if_fail (E_IS_EMOTICON_CHOOSER (chooser));
+
+ iface = E_EMOTICON_CHOOSER_GET_IFACE (chooser);
+ g_return_if_fail (iface->set_current_emoticon != NULL);
+
+ iface->set_current_emoticon (chooser, emoticon);
+}
+
+void
+e_emoticon_chooser_item_activated (EEmoticonChooser *chooser)
+{
+ g_return_if_fail (E_IS_EMOTICON_CHOOSER (chooser));
+
+ g_signal_emit (chooser, signals[ITEM_ACTIVATED], 0);
+}
+
+GList *
+e_emoticon_chooser_get_items (EEmoticonChooser *chooser)
+{
+ GList *list = NULL;
+ gint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (available_emoticons); ii++)
+ list = g_list_prepend (list, &available_emoticons[ii]);
+
+ return g_list_reverse (list);
+}
diff --git a/e-util/e-emoticon-chooser.h b/e-util/e-emoticon-chooser.h
new file mode 100644
index 0000000..7390da3
--- /dev/null
+++ b/e-util/e-emoticon-chooser.h
@@ -0,0 +1,69 @@
+/* e-emoticon-chooser.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser 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.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_EMOTICON_CHOOSER_H
+#define E_EMOTICON_CHOOSER_H
+
+#include <e-util/e-emoticon.h>
+
+/* Standard GObject macros */
+#define E_TYPE_EMOTICON_CHOOSER \
+ (e_emoticon_chooser_get_type ())
+#define E_EMOTICON_CHOOSER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_EMOTICON_CHOOSER, EEmoticonChooser))
+#define E_IS_EMOTICON_CHOOSER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_EMOTICON_CHOOSER))
+#define E_EMOTICON_CHOOSER_GET_IFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE \
+ ((obj), E_TYPE_EMOTICON_CHOOSER, EEmoticonChooserIface))
+
+G_BEGIN_DECLS
+
+typedef struct _EEmoticonChooser EEmoticonChooser;
+typedef struct _EEmoticonChooserIface EEmoticonChooserIface;
+
+struct _EEmoticonChooserIface {
+ GTypeInterface parent_iface;
+
+ /* Methods */
+ EEmoticon * (*get_current_emoticon) (EEmoticonChooser *chooser);
+ void (*set_current_emoticon) (EEmoticonChooser *chooser,
+ EEmoticon *emoticon);
+
+ /* Signals */
+ void (*item_activated) (EEmoticonChooser *chooser);
+};
+
+GType e_emoticon_chooser_get_type (void);
+EEmoticon * e_emoticon_chooser_get_current_emoticon
+ (EEmoticonChooser *chooser);
+void e_emoticon_chooser_set_current_emoticon
+ (EEmoticonChooser *chooser,
+ EEmoticon *emoticon);
+void e_emoticon_chooser_item_activated
+ (EEmoticonChooser *chooser);
+GList * e_emoticon_chooser_get_items (EEmoticonChooser *chooser);
+
+G_END_DECLS
+
+#endif /* E_EMOTICON_CHOOSER_H */
diff --git a/e-util/e-emoticon-tool-button.c b/e-util/e-emoticon-tool-button.c
new file mode 100644
index 0000000..dc0d0dd
--- /dev/null
+++ b/e-util/e-emoticon-tool-button.c
@@ -0,0 +1,711 @@
+/* e-emoticon-tool-button.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser 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 "e-emoticon-tool-button.h"
+
+/* XXX The "button" aspects of this widget are based heavily on the
+ * GtkComboBox tree-view implementation. Consider splitting it
+ * into a reusable "button-with-an-empty-window" widget. */
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "e-emoticon-chooser.h"
+
+/* XXX Should calculate this dynamically. */
+#define NUM_ROWS 7
+#define NUM_COLS 3
+
+enum {
+ PROP_0,
+ PROP_CURRENT_EMOTICON,
+ PROP_POPUP_SHOWN
+};
+
+enum {
+ POPUP,
+ POPDOWN,
+ LAST_SIGNAL
+};
+
+struct _EEmoticonToolButtonPrivate {
+ GtkWidget *active_button; /* not referenced */
+ GtkWidget *table;
+ GtkWidget *window;
+
+ guint popup_shown : 1;
+ guint popup_in_progress : 1;
+ GdkDevice *grab_keyboard;
+ GdkDevice *grab_mouse;
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+/* XXX Copied from _gtk_toolbar_elide_underscores() */
+static gchar *
+emoticon_tool_button_elide_underscores (const gchar *original)
+{
+ gchar *q, *result;
+ const gchar *p, *end;
+ gsize len;
+ gboolean last_underscore;
+
+ if (!original)
+ return NULL;
+
+ len = strlen (original);
+ q = result = g_malloc (len + 1);
+ last_underscore = FALSE;
+
+ end = original + len;
+ for (p = original; p < end; p++) {
+ if (!last_underscore && *p == '_')
+ last_underscore = TRUE;
+ else {
+ last_underscore = FALSE;
+ if (original + 2 <= p && p + 1 <= end &&
+ p[-2] == '(' && p[-1] == '_' &&
+ p[0] != '_' && p[1] == ')') {
+ q--;
+ *q = '\0';
+ p++;
+ } else
+ *q++ = *p;
+ }
+ }
+
+ if (last_underscore)
+ *q++ = '_';
+
+ *q = '\0';
+
+ return result;
+}
+
+static void
+emoticon_tool_button_reposition_window (EEmoticonToolButton *button)
+{
+ GdkScreen *screen;
+ GdkWindow *window;
+ GdkRectangle monitor;
+ GtkAllocation allocation;
+ gint monitor_num;
+ gint x, y, width, height;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (button));
+ window = gtk_widget_get_window (GTK_WIDGET (button));
+ monitor_num = gdk_screen_get_monitor_at_window (screen, window);
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+ gdk_window_get_origin (window, &x, &y);
+
+ if (!gtk_widget_get_has_window (GTK_WIDGET (button))) {
+ gtk_widget_get_allocation (GTK_WIDGET (button), &allocation);
+ x += allocation.x;
+ y += allocation.y;
+ }
+
+ gtk_widget_get_allocation (button->priv->window, &allocation);
+ width = allocation.width;
+ height = allocation.height;
+
+ x = CLAMP (x, monitor.x, monitor.x + monitor.width - width);
+ y = CLAMP (y, monitor.y, monitor.y + monitor.height - height);
+
+ gtk_window_move (GTK_WINDOW (button->priv->window), x, y);
+}
+
+static void
+emoticon_tool_button_emoticon_clicked_cb (EEmoticonToolButton *button,
+ GtkWidget *emoticon_button)
+{
+ button->priv->active_button = emoticon_button;
+ e_emoticon_tool_button_popdown (button);
+}
+
+static gboolean
+emoticon_tool_button_emoticon_release_event_cb (EEmoticonToolButton *button,
+ GdkEventButton *event,
+ GtkButton *emoticon_button)
+{
+ GtkStateType state;
+
+ state = gtk_widget_get_state (GTK_WIDGET (button));
+
+ if (state != GTK_STATE_NORMAL)
+ gtk_button_clicked (emoticon_button);
+
+ return FALSE;
+}
+
+static gboolean
+emoticon_tool_button_button_release_event_cb (EEmoticonToolButton *button,
+ GdkEventButton *event)
+{
+ GtkToggleToolButton *tool_button;
+ GtkWidget *event_widget;
+ gboolean popup_in_progress;
+
+ tool_button = GTK_TOGGLE_TOOL_BUTTON (button);
+ event_widget = gtk_get_event_widget ((GdkEvent *) event);
+
+ popup_in_progress = button->priv->popup_in_progress;
+ button->priv->popup_in_progress = FALSE;
+
+ if (event_widget != GTK_WIDGET (button))
+ goto popdown;
+
+ if (popup_in_progress)
+ return FALSE;
+
+ if (gtk_toggle_tool_button_get_active (tool_button))
+ goto popdown;
+
+ return FALSE;
+
+popdown:
+ e_emoticon_tool_button_popdown (button);
+
+ return TRUE;
+}
+
+static void
+emoticon_tool_button_child_show_cb (EEmoticonToolButton *button)
+{
+ button->priv->popup_shown = TRUE;
+ g_object_notify (G_OBJECT (button), "popup-shown");
+}
+
+static void
+emoticon_tool_button_child_hide_cb (EEmoticonToolButton *button)
+{
+ button->priv->popup_shown = FALSE;
+ g_object_notify (G_OBJECT (button), "popup-shown");
+}
+
+static gboolean
+emoticon_tool_button_child_key_press_event_cb (EEmoticonToolButton *button,
+ GdkEventKey *event)
+{
+ GtkWidget *window = button->priv->window;
+
+ if (!gtk_bindings_activate_event (G_OBJECT (window), event))
+ gtk_bindings_activate_event (G_OBJECT (button), event);
+
+ return TRUE;
+}
+
+static void
+emoticon_tool_button_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CURRENT_EMOTICON:
+ e_emoticon_chooser_set_current_emoticon (
+ E_EMOTICON_CHOOSER (object),
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_POPUP_SHOWN:
+ if (g_value_get_boolean (value))
+ e_emoticon_tool_button_popup (
+ E_EMOTICON_TOOL_BUTTON (object));
+ else
+ e_emoticon_tool_button_popdown (
+ E_EMOTICON_TOOL_BUTTON (object));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+emoticon_tool_button_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EEmoticonToolButtonPrivate *priv;
+
+ priv = E_EMOTICON_TOOL_BUTTON (object)->priv;
+
+ switch (property_id) {
+ case PROP_CURRENT_EMOTICON:
+ g_value_set_boxed (
+ value,
+ e_emoticon_chooser_get_current_emoticon (
+ E_EMOTICON_CHOOSER (object)));
+ return;
+
+ case PROP_POPUP_SHOWN:
+ g_value_set_boolean (value, priv->popup_shown);
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+emoticon_tool_button_dispose (GObject *object)
+{
+ EEmoticonToolButtonPrivate *priv;
+
+ priv = E_EMOTICON_TOOL_BUTTON (object)->priv;
+
+ if (priv->window != NULL) {
+ g_object_unref (priv->window);
+ priv->window = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static gboolean
+emoticon_tool_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ EEmoticonToolButton *button;
+ GtkToggleToolButton *toggle_button;
+ GtkWidget *event_widget;
+
+ button = E_EMOTICON_TOOL_BUTTON (widget);
+
+ event_widget = gtk_get_event_widget ((GdkEvent *) event);
+
+ if (event_widget == button->priv->window)
+ return TRUE;
+
+ if (event_widget != widget)
+ return FALSE;
+
+ toggle_button = GTK_TOGGLE_TOOL_BUTTON (widget);
+ if (gtk_toggle_tool_button_get_active (toggle_button))
+ return FALSE;
+
+ e_emoticon_tool_button_popup (button);
+
+ button->priv->popup_in_progress = TRUE;
+
+ return TRUE;
+}
+
+static void
+emoticon_tool_button_toggled (GtkToggleToolButton *button)
+{
+ if (gtk_toggle_tool_button_get_active (button))
+ e_emoticon_tool_button_popup (
+ E_EMOTICON_TOOL_BUTTON (button));
+ else
+ e_emoticon_tool_button_popdown (
+ E_EMOTICON_TOOL_BUTTON (button));
+}
+
+static void
+emoticon_tool_button_popup (EEmoticonToolButton *button)
+{
+ GtkToggleToolButton *tool_button;
+ GdkWindow *window;
+ gboolean grab_status;
+ GdkDevice *device, *mouse, *keyboard;
+ guint32 activate_time;
+
+ device = gtk_get_current_event_device ();
+ g_return_if_fail (device != NULL);
+
+ if (!gtk_widget_get_realized (GTK_WIDGET (button)))
+ return;
+
+ if (button->priv->popup_shown)
+ return;
+
+ activate_time = gtk_get_current_event_time ();
+ if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) {
+ keyboard = device;
+ mouse = gdk_device_get_associated_device (device);
+ } else {
+ keyboard = gdk_device_get_associated_device (device);
+ mouse = device;
+ }
+
+ /* Position the window over the button. */
+ emoticon_tool_button_reposition_window (button);
+
+ /* Show the pop-up. */
+ gtk_widget_show (button->priv->window);
+ gtk_widget_grab_focus (button->priv->window);
+
+ /* Activate the tool button. */
+ tool_button = GTK_TOGGLE_TOOL_BUTTON (button);
+ gtk_toggle_tool_button_set_active (tool_button, TRUE);
+
+ /* Try to grab the pointer and keyboard. */
+ window = gtk_widget_get_window (button->priv->window);
+ grab_status = !keyboard ||
+ gdk_device_grab (keyboard, window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+ NULL, activate_time) == GDK_GRAB_SUCCESS;
+ if (grab_status) {
+ grab_status = !mouse ||
+ gdk_device_grab (mouse, window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK,
+ NULL, activate_time) == GDK_GRAB_SUCCESS;
+ if (!grab_status && keyboard)
+ gdk_device_ungrab (keyboard, activate_time);
+ }
+
+ if (grab_status) {
+ gtk_device_grab_add (button->priv->window, mouse, TRUE);
+ button->priv->grab_keyboard = keyboard;
+ button->priv->grab_mouse = mouse;
+ } else {
+ gtk_widget_hide (button->priv->window);
+ }
+}
+
+static void
+emoticon_tool_button_popdown (EEmoticonToolButton *button)
+{
+ GtkToggleToolButton *tool_button;
+
+ if (!gtk_widget_get_realized (GTK_WIDGET (button)))
+ return;
+
+ if (!button->priv->popup_shown)
+ return;
+
+ /* Hide the pop-up. */
+ gtk_device_grab_remove (button->priv->window, button->priv->grab_mouse);
+ gtk_widget_hide (button->priv->window);
+
+ /* Deactivate the tool button. */
+ tool_button = GTK_TOGGLE_TOOL_BUTTON (button);
+ gtk_toggle_tool_button_set_active (tool_button, FALSE);
+
+ if (button->priv->grab_keyboard)
+ gdk_device_ungrab (button->priv->grab_keyboard, GDK_CURRENT_TIME);
+ if (button->priv->grab_mouse)
+ gdk_device_ungrab (button->priv->grab_mouse, GDK_CURRENT_TIME);
+
+ button->priv->grab_keyboard = NULL;
+ button->priv->grab_mouse = NULL;
+}
+
+static EEmoticon *
+emoticon_tool_button_get_current_emoticon (EEmoticonChooser *chooser)
+{
+ EEmoticonToolButtonPrivate *priv;
+
+ priv = E_EMOTICON_TOOL_BUTTON (chooser)->priv;
+
+ if (priv->active_button == NULL)
+ return NULL;
+
+ return g_object_get_data (G_OBJECT (priv->active_button), "emoticon");
+}
+
+static void
+emoticon_tool_button_set_current_emoticon (EEmoticonChooser *chooser,
+ EEmoticon *emoticon)
+{
+ EEmoticonToolButtonPrivate *priv;
+ GList *list, *iter;
+
+ priv = E_EMOTICON_TOOL_BUTTON (chooser)->priv;
+
+ list = gtk_container_get_children (GTK_CONTAINER (priv->table));
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ GtkWidget *item = iter->data;
+ EEmoticon *candidate;
+
+ candidate = g_object_get_data (G_OBJECT (item), "emoticon");
+ if (candidate == NULL)
+ continue;
+
+ if (e_emoticon_equal (emoticon, candidate)) {
+ gtk_button_clicked (GTK_BUTTON (item));
+ break;
+ }
+ }
+
+ g_list_free (list);
+}
+
+static void
+emoticon_tool_button_class_init (EEmoticonToolButtonClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkToggleToolButtonClass *toggle_tool_button_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EEmoticonToolButtonPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = emoticon_tool_button_set_property;
+ object_class->get_property = emoticon_tool_button_get_property;
+ object_class->dispose = emoticon_tool_button_dispose;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->button_press_event = emoticon_tool_button_press_event;
+
+ toggle_tool_button_class = GTK_TOGGLE_TOOL_BUTTON_CLASS (class);
+ toggle_tool_button_class->toggled = emoticon_tool_button_toggled;
+
+ class->popup = emoticon_tool_button_popup;
+ class->popdown = emoticon_tool_button_popdown;
+
+ g_object_class_override_property (
+ object_class, PROP_CURRENT_EMOTICON, "current-emoticon");
+
+ g_object_class_install_property (
+ object_class,
+ PROP_POPUP_SHOWN,
+ g_param_spec_boolean (
+ "popup-shown",
+ "Popup Shown",
+ "Whether the button's dropdown is shown",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ signals[POPUP] = g_signal_new (
+ "popup",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EEmoticonToolButtonClass, popup),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[POPDOWN] = g_signal_new (
+ "popdown",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EEmoticonToolButtonClass, popdown),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ gtk_binding_entry_add_signal (
+ gtk_binding_set_by_class (class),
+ GDK_KEY_Down, GDK_MOD1_MASK, "popup", 0);
+ gtk_binding_entry_add_signal (
+ gtk_binding_set_by_class (class),
+ GDK_KEY_KP_Down, GDK_MOD1_MASK, "popup", 0);
+
+ gtk_binding_entry_add_signal (
+ gtk_binding_set_by_class (class),
+ GDK_KEY_Up, GDK_MOD1_MASK, "popdown", 0);
+ gtk_binding_entry_add_signal (
+ gtk_binding_set_by_class (class),
+ GDK_KEY_KP_Up, GDK_MOD1_MASK, "popdown", 0);
+ gtk_binding_entry_add_signal (
+ gtk_binding_set_by_class (class),
+ GDK_KEY_Escape, 0, "popdown", 0);
+}
+
+static void
+emoticon_tool_button_iemoticon_init (EEmoticonChooserIface *iemoticon)
+{
+ iemoticon->get_current_emoticon = emoticon_tool_button_get_current_emoticon;
+ iemoticon->set_current_emoticon = emoticon_tool_button_set_current_emoticon;
+}
+
+static void
+emoticon_tool_button_init (EEmoticonToolButton *button)
+{
+ EEmoticonChooser *chooser;
+ GtkWidget *toplevel;
+ GtkWidget *container;
+ GtkWidget *widget;
+ GtkWidget *window;
+ GList *list, *iter;
+ gint ii;
+
+ button->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+ button, E_TYPE_EMOTICON_TOOL_BUTTON,
+ EEmoticonToolButtonPrivate);
+
+ /* Build the pop-up window. */
+
+ window = gtk_window_new (GTK_WINDOW_POPUP);
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+ gtk_window_set_type_hint (
+ GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_COMBO);
+ if (gtk_widget_is_toplevel (toplevel)) {
+ gtk_window_group_add_window (
+ gtk_window_get_group (GTK_WINDOW (toplevel)),
+ GTK_WINDOW (window));
+ gtk_window_set_transient_for (
+ GTK_WINDOW (window), GTK_WINDOW (toplevel));
+ }
+ button->priv->window = g_object_ref (window);
+
+ g_signal_connect_swapped (
+ window, "show",
+ G_CALLBACK (emoticon_tool_button_child_show_cb), button);
+ g_signal_connect_swapped (
+ window, "hide",
+ G_CALLBACK (emoticon_tool_button_child_hide_cb), button);
+ g_signal_connect_swapped (
+ window, "button-release-event",
+ G_CALLBACK (emoticon_tool_button_button_release_event_cb),
+ button);
+ g_signal_connect_swapped (
+ window, "key-press-event",
+ G_CALLBACK (emoticon_tool_button_child_key_press_event_cb),
+ button);
+
+ /* Build the pop-up window contents. */
+
+ widget = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_OUT);
+ gtk_container_add (GTK_CONTAINER (window), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_table_new (NUM_ROWS, NUM_COLS, TRUE);
+ gtk_table_set_row_spacings (GTK_TABLE (widget), 0);
+ gtk_table_set_col_spacings (GTK_TABLE (widget), 0);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ button->priv->table = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ chooser = E_EMOTICON_CHOOSER (button);
+ list = e_emoticon_chooser_get_items (chooser);
+ g_assert (g_list_length (list) <= NUM_ROWS * NUM_COLS);
+
+ for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
+ EEmoticon *emoticon = iter->data;
+ guint left = ii % NUM_COLS;
+ guint top = ii / NUM_COLS;
+ gchar *tooltip;
+
+ tooltip = emoticon_tool_button_elide_underscores (
+ gettext (emoticon->label));
+
+ widget = gtk_button_new ();
+ gtk_button_set_image (
+ GTK_BUTTON (widget),
+ gtk_image_new_from_icon_name (
+ emoticon->icon_name, GTK_ICON_SIZE_BUTTON));
+ gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE);
+ gtk_widget_set_tooltip_text (widget, tooltip);
+ gtk_widget_show (widget);
+
+ g_object_set_data_full (
+ G_OBJECT (widget), "emoticon",
+ e_emoticon_copy (emoticon),
+ (GDestroyNotify) e_emoticon_free);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (emoticon_tool_button_emoticon_clicked_cb),
+ button);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_emoticon_chooser_item_activated),
+ chooser);
+
+ g_signal_connect_swapped (
+ widget, "button-release-event",
+ G_CALLBACK (emoticon_tool_button_emoticon_release_event_cb),
+ button);
+
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ left, left + 1, top, top + 1, 0, 0, 0, 0);
+
+ g_free (tooltip);
+ }
+
+ g_list_free (list);
+}
+
+GType
+e_emoticon_tool_button_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EEmoticonToolButtonClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) emoticon_tool_button_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EEmoticonToolButton),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) emoticon_tool_button_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo iemoticon_info = {
+ (GInterfaceInitFunc) emoticon_tool_button_iemoticon_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interemoticon_data */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_TOGGLE_TOOL_BUTTON,
+ "EEmoticonToolButton", &type_info, 0);
+
+ g_type_add_interface_static (
+ type, E_TYPE_EMOTICON_CHOOSER, &iemoticon_info);
+ }
+
+ return type;
+}
+
+GtkToolItem *
+e_emoticon_tool_button_new (void)
+{
+ return g_object_new (E_TYPE_EMOTICON_TOOL_BUTTON, NULL);
+}
+
+void
+e_emoticon_tool_button_popup (EEmoticonToolButton *button)
+{
+ g_return_if_fail (E_IS_EMOTICON_TOOL_BUTTON (button));
+
+ g_signal_emit (button, signals[POPUP], 0);
+}
+
+void
+e_emoticon_tool_button_popdown (EEmoticonToolButton *button)
+{
+ g_return_if_fail (E_IS_EMOTICON_TOOL_BUTTON (button));
+
+ g_signal_emit (button, signals[POPDOWN], 0);
+}
diff --git a/e-util/e-emoticon-tool-button.h b/e-util/e-emoticon-tool-button.h
new file mode 100644
index 0000000..6c1273e
--- /dev/null
+++ b/e-util/e-emoticon-tool-button.h
@@ -0,0 +1,71 @@
+/* e-emoticon-tool-button.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser 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.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_EMOTICON_TOOL_BUTTON_H
+#define E_EMOTICON_TOOL_BUTTON_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_EMOTICON_TOOL_BUTTON \
+ (e_emoticon_tool_button_get_type ())
+#define E_EMOTICON_TOOL_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_EMOTICON_TOOL_BUTTON, EEmoticonToolButton))
+#define E_EMOTICON_TOOL_BUTTON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_EMOTICON_TOOL_BUTTON, EEmoticonToolButtonClass))
+#define E_IS_EMOTICON_TOOL_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_EMOTICON_TOOL_BUTTON))
+#define E_IS_EMOTICON_TOOL_BUTTON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_EMOTICON_TOOL_BUTTON))
+#define E_EMOTICON_TOOL_BUTTON_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_EMOTICON_TOOL_BUTTON, EEmoticonToolButtonClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EEmoticonToolButton EEmoticonToolButton;
+typedef struct _EEmoticonToolButtonClass EEmoticonToolButtonClass;
+typedef struct _EEmoticonToolButtonPrivate EEmoticonToolButtonPrivate;
+
+struct _EEmoticonToolButton {
+ GtkToggleToolButton parent;
+ EEmoticonToolButtonPrivate *priv;
+};
+
+struct _EEmoticonToolButtonClass {
+ GtkToggleToolButtonClass parent_class;
+
+ void (*popup) (EEmoticonToolButton *button);
+ void (*popdown) (EEmoticonToolButton *button);
+};
+
+GType e_emoticon_tool_button_get_type (void);
+GtkToolItem * e_emoticon_tool_button_new (void);
+void e_emoticon_tool_button_popup (EEmoticonToolButton *button);
+void e_emoticon_tool_button_popdown (EEmoticonToolButton *button);
+
+G_END_DECLS
+
+#endif /* E_EMOTICON_TOOL_BUTTON_H */
diff --git a/e-util/e-emoticon.c b/e-util/e-emoticon.c
new file mode 100644
index 0000000..1d394e6
--- /dev/null
+++ b/e-util/e-emoticon.c
@@ -0,0 +1,89 @@
+/* e-emoticon.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser 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.
+ */
+
+#include "e-emoticon.h"
+
+static EEmoticon *
+emoticon_copy (EEmoticon *emoticon)
+{
+ EEmoticon *copy;
+
+ copy = g_slice_new (EEmoticon);
+ copy->label = g_strdup (emoticon->label);
+ copy->icon_name = g_strdup (emoticon->icon_name);
+ copy->text_face = g_strdup (emoticon->text_face);
+
+ return copy;
+}
+
+static void
+emoticon_free (EEmoticon *emoticon)
+{
+ g_free (emoticon->label);
+ g_free (emoticon->icon_name);
+ g_free (emoticon->text_face);
+ g_slice_free (EEmoticon, emoticon);
+}
+
+GType
+e_emoticon_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0))
+ type = g_boxed_type_register_static (
+ "EEmoticon",
+ (GBoxedCopyFunc) emoticon_copy,
+ (GBoxedFreeFunc) emoticon_free);
+
+ return type;
+}
+
+gboolean
+e_emoticon_equal (EEmoticon *emoticon_a,
+ EEmoticon *emoticon_b)
+{
+ if (((emoticon_a == NULL) && (emoticon_b != NULL)) ||
+ ((emoticon_a != NULL) && (emoticon_b == NULL)))
+ return FALSE;
+
+ if (emoticon_a == emoticon_b)
+ return TRUE;
+
+ if (g_strcmp0 (emoticon_a->label, emoticon_b->label) != 0)
+ return FALSE;
+
+ if (g_strcmp0 (emoticon_a->icon_name, emoticon_b->icon_name) != 0)
+ return FALSE;
+
+ if (g_strcmp0 (emoticon_a->text_face, emoticon_b->text_face) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+EEmoticon *
+e_emoticon_copy (EEmoticon *emoticon)
+{
+ return g_boxed_copy (E_TYPE_EMOTICON, emoticon);
+}
+
+void
+e_emoticon_free (EEmoticon *emoticon)
+{
+ g_boxed_free (E_TYPE_EMOTICON, emoticon);
+}
diff --git a/e-util/e-emoticon.h b/e-util/e-emoticon.h
new file mode 100644
index 0000000..cf270ef
--- /dev/null
+++ b/e-util/e-emoticon.h
@@ -0,0 +1,48 @@
+/* e-emoticon.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser 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.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_EMOTICON_H
+#define E_EMOTICON_H
+
+#include <glib-object.h>
+
+#define E_TYPE_EMOTICON \
+ (e_emoticon_get_type ())
+
+G_BEGIN_DECLS
+
+typedef struct _EEmoticon EEmoticon;
+
+struct _EEmoticon {
+ gchar *label;
+ gchar *icon_name;
+ gchar *text_face;
+};
+
+GType e_emoticon_get_type (void);
+gboolean e_emoticon_equal (EEmoticon *emoticon_a,
+ EEmoticon *emoticon_b);
+EEmoticon * e_emoticon_copy (EEmoticon *emoticon);
+void e_emoticon_free (EEmoticon *emoticon);
+
+G_END_DECLS
+
+#endif /* E_EMOTICON_H */
diff --git a/e-util/e-util.h b/e-util/e-util.h
index 8d1062d..e093752 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -89,6 +89,11 @@
#include <e-util/e-dialog-widgets.h>
#include <e-util/e-editor-selection.h>
#include <e-util/e-editor-widget.h>
+#include <e-util/e-emoticon-action.h>
+#include <e-util/e-emoticon-chooser-menu.h>
+#include <e-util/e-emoticon-chooser.h>
+#include <e-util/e-emoticon-tool-button.h>
+#include <e-util/e-emoticon.h>
#include <e-util/e-event.h>
#include <e-util/e-file-request.h>
#include <e-util/e-file-utils.h>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]