summaryrefslogtreecommitdiff
path: root/charpick/charpick.c
diff options
context:
space:
mode:
Diffstat (limited to 'charpick/charpick.c')
-rw-r--r--charpick/charpick.c876
1 files changed, 876 insertions, 0 deletions
diff --git a/charpick/charpick.c b/charpick/charpick.c
new file mode 100644
index 00000000..6de91c57
--- /dev/null
+++ b/charpick/charpick.c
@@ -0,0 +1,876 @@
+/* charpick.c This is a mate panel applet that allow users to select
+ * accented (and other) characters to be pasted into other apps.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <mate-panel-applet.h>
+#ifdef HAVE_GUCHARMAP
+# include <gucharmap/gucharmap.h>
+#endif
+#include "charpick.h"
+
+/* The comment for each char list has the html entity names of the chars */
+/* All gunicar codes should end in 0 */
+
+
+/* This is the default list used when starting charpick the first time */
+/* aacute, agrave, eacute, iacute, oacute, frac12, copy*/
+/* static const gchar *def_list = "áàéíñóœ©"; */
+static const gunichar def_code[] = {225, 224, 233, 237, 241, 243, 189, 169, 1579, 8364, 0};
+
+/* aacute, agrave, acirc, atilde, auml. aring, aelig, ordf */
+/* static const gchar *a_list = "áàâãäåæª"; */
+static const gunichar a_code[] = {225, 224, 226, 227, 228, 229, 230, 170, 0};
+/* static const gchar *cap_a_list = "ÁÀÂÃÄÅƪ"; */
+static const gunichar cap_a_code[] = {192, 193, 194, 195, 196, 197, 198, 170, 0};
+/* ccedil, cent, copy */
+/* static const gchar *c_list = "çÇ¢©"; */
+static const gunichar c_code[] = {231, 199, 162, 169, 0};
+/* eacute, egrave, ecirc, euml, aelig */
+/* static const gchar *e_list = "éèêëæ"; */
+static const gunichar e_code[] = {232, 233, 234, 235, 230, 0};
+/* static const gchar *cap_e_list = "ÉÈÊËÆ"; */
+static const gunichar cap_e_code[] = {200, 201, 202, 203, 198, 0};
+/* iacute, igrave, icirc, iuml */
+/* static const gchar *i_list = "íìîï"; */
+static const gunichar i_code[] = {236, 237, 238, 239, 0};
+/* static const gchar *cap_i_list = "ÍÌÎÏ"; */
+static const gunichar cap_i_code[] = {204, 205, 206, 207, 0};
+/* ntilde (this is the most important line in this program.) */
+/* static const gchar *n_list = "ñ, Ñ"; */
+static const gunichar n_code[] = {241, 209, 0};
+/* oacute, ograve, ocirc, otilde, ouml, oslash, ordm */
+/* static const gchar *o_list = "óòôõöøº"; */
+static const gunichar o_code[] = {242, 243, 244, 245, 246, 248, 176, 0};
+/* static const gchar *cap_o_list = "ÓÒÔÕÖغ"; */
+static const gunichar cap_o_code[] = {210, 211, 212, 213, 214, 216, 176, 0};
+/* szlig, sect, dollar */
+/* static const gchar *s_list = "ߧ$"; */
+static const gunichar s_code[] = {223, 167, 36, 0};
+/* eth, thorn */
+/* static const gchar *t_list = "ðÐþÞ"; */
+static const gunichar t_code[] = {240, 208, 254, 222, 0};
+/* uacute, ugrave, ucirc, uuml */
+/* static const gchar *u_list = "úùûü"; */
+static const gunichar u_code[] = {249, 250, 251, 252, 0};
+/* static const gchar *cap_u_list = "ÚÙÛÜ"; */
+static const gunichar cap_u_code[] = {217, 218, 219, 220, 0};
+/* yacute, yuml, yen Yes, there is no capital yuml in iso 8859-1.*/
+/* static const gchar *y_list = "ýÝÿ¥"; */
+static const gunichar y_code[] = {253, 221, 255, 165, 0};
+
+/* extra characters unrelated to the latin alphabet. All characters in
+ ISO-8859-1 should now be accounted for.*/
+/* not shy macr plusmn */
+/* static const gchar *dash_list = "¬­¯±"; */
+static const gunichar dash_code[] = {172, 173, 175, 177, 0};
+/* laquo raquo uml */
+/* static const gchar *quote_list = "«»š·×"; */
+static const gunichar quote_code[] = {171, 187, 168, 183, 215, 0};
+/* curren, pound, yen, cent, dollar */
+/* static const gchar *currency_list = "€£¥¢$"; */
+static const gunichar currency_code[] = {164, 163, 165, 162, 36, 8364, 0};
+/* sup1 frac12 */
+/* static const gchar *one_list = "¹œŒ"; */
+static const gunichar one_code[] = {185, 178, 179, 188, 189, 190, 0};
+/* µ ¶ ® ¿ ¡ | */
+static const gunichar misc_code[] = {181, 182, 174, 191, 161, 124, 0};
+
+/* language/region specific character groups */
+/* South Africa: Venda, Tswana and Northern Sotho */
+/* static const gchar *ZA_list = "ḓḽṋṱḒḼṊṰṅṄšŠ"; */
+static const gunichar ZA_code[] = {7699, 7741, 7755, 7793, 7698, 7740, 7754, 7792, 7749, 7748, 353, 352, 0};
+/* South Africa: Afrikaans */
+/* static const gchar *af_ZA_list = "áéíóúýêîôûèäëïöüÁÉÍÓÚÝÊÎÔÛÈÄËÏÖÜ"; */
+static const gunichar af_ZA_code[] = {225, 233, 237, 243, 250, 253, 234, 238, 244, 251, 232, 228, 235, 239, 246, 252, 193, 201, 205, 211, 218, 221, 202, 206, 212, 219, 200, 196, 203, 207, 214, 220, 0};
+
+
+static const gunichar * const chartable[] = {
+ def_code,
+ a_code,
+ cap_a_code,
+ c_code,
+ e_code,
+ cap_e_code,
+ i_code,
+ cap_i_code,
+ n_code,
+ o_code,
+ cap_o_code,
+ s_code,
+ t_code,
+ u_code,
+ cap_u_code,
+ y_code,
+ dash_code,
+ quote_code,
+ currency_code,
+ one_code,
+ misc_code,
+ ZA_code,
+ af_ZA_code
+};
+
+gboolean
+key_writable (MatePanelApplet *applet, const char *key)
+{
+ gboolean writable;
+ char *fullkey;
+ static MateConfClient *client = NULL;
+ if (client == NULL)
+ client = mateconf_client_get_default ();
+
+ fullkey = mate_panel_applet_mateconf_get_full_key (applet, key);
+
+ writable = mateconf_client_key_is_writable (client, fullkey, NULL);
+
+ g_free (fullkey);
+
+ return writable;
+}
+
+
+/* sets the picked character as the selection when it gets a request */
+static void
+charpick_selection_handler(GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time,
+ gpointer data)
+{
+ charpick_data *p_curr_data = data;
+ gint num;
+ gchar tmp[7];
+ num = g_unichar_to_utf8 (p_curr_data->selected_unichar, tmp);
+ tmp[num] = '\0';
+
+ gtk_selection_data_set_text (selection_data, tmp, -1);
+
+ return;
+}
+
+/* untoggles the active toggle_button when we lose the selection */
+static gint
+selection_clear_cb (GtkWidget *widget, GdkEventSelection *event,
+ gpointer data)
+{
+ charpick_data *curr_data = data;
+
+ if (curr_data->last_toggle_button)
+ gtk_toggle_button_set_active (curr_data->last_toggle_button, FALSE);
+
+ curr_data->last_toggle_button = NULL;
+ return TRUE;
+}
+
+
+static gint
+toggle_button_toggled_cb(GtkToggleButton *button, gpointer data)
+{
+ charpick_data *curr_data = data;
+ gint button_index;
+ gboolean toggled;
+
+ button_index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "index"));
+ toggled = gtk_toggle_button_get_active (button);
+
+ if (toggled)
+ {
+ gunichar unichar;
+ if (curr_data->last_toggle_button && (button != curr_data->last_toggle_button))
+ gtk_toggle_button_set_active (curr_data->last_toggle_button,
+ FALSE);
+
+ curr_data->last_toggle_button = button;
+ gtk_widget_grab_focus(curr_data->applet);
+ unichar = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "unichar"));
+ curr_data->selected_unichar = unichar;
+ /* set this? widget as the selection owner */
+ gtk_selection_owner_set (curr_data->applet,
+ GDK_SELECTION_PRIMARY,
+ GDK_CURRENT_TIME);
+ gtk_selection_owner_set (curr_data->applet,
+ GDK_SELECTION_CLIPBOARD,
+ GDK_CURRENT_TIME);
+ curr_data->last_index = button_index;
+ }
+
+ return TRUE;
+}
+
+/* This is a hack around the fact that gtk+ doesn't
+ * propogate button presses on button2/3.
+ */
+static gboolean
+button_press_hack (GtkWidget *widget,
+ GdkEventButton *event,
+ GtkWidget *applet)
+{
+ if (event->button == 3 || event->button == 2) {
+ gtk_propagate_event (applet, (GdkEvent *) event);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gint
+key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+#if 0
+ charpick_data *p_curr_data = data;
+ const gunichar *code = NULL;
+ gchar inputchar = event->keyval;
+
+ switch (inputchar)
+ {
+ case 'a' : code = a_code;
+ break;
+ case 'A' : code = cap_a_code;
+ break;
+ case 'c' :
+ case 'C' : code = c_code;
+ break;
+ case 'e' : code = e_code;
+ break;
+ case 'E' : code = cap_e_code;
+ break;
+ case 'i' : code = i_code;
+ break;
+ case 'I' : code = cap_i_code;
+ break;
+ case 'n' :
+ case 'N' : code = n_code;
+ break;
+ case 'o' : code = o_code;
+ break;
+ case 'O' : code = cap_o_code;
+ break;
+ case 's' : code = s_code;
+ break;
+ case 't' :
+ case 'T' : code = t_code;
+ break;
+ case 'u' : code = u_code;
+ break;
+ case 'U' : code = cap_u_code;
+ break;
+ case 'y' :
+ case 'Y' : code = y_code;
+ break;
+ case '-' : code = dash_code;
+ break;
+ case '\"' : code = quote_code;
+ break;
+ case '$' : code = currency_code;
+ break;
+ case '1' :
+ case '2' :
+ case '3' : code = one_code;
+ break;
+ case 'd' : code = NULL;
+ break;
+ default :
+ return FALSE;
+ }
+ /* FIXME: what's wrong here ? */
+ if (code)
+ p_curr_data->charlist = g_ucs4_to_utf8 (code, -1, NULL, NULL, NULL);
+ else
+ p_curr_data->charlist = "hello";
+ p_curr_data->last_index = NO_LAST_INDEX;
+ p_curr_data->last_toggle_button = NULL;
+ build_table(p_curr_data);
+#endif
+ return FALSE;
+}
+
+static void
+menuitem_activated (GtkMenuItem *menuitem, charpick_data *curr_data)
+{
+ gchar *string;
+ MatePanelApplet *applet = MATE_PANEL_APPLET (curr_data->applet);
+
+ string = g_object_get_data (G_OBJECT (menuitem), "string");
+ if (g_ascii_strcasecmp (curr_data->charlist, string) == 0)
+ return;
+
+ curr_data->charlist = string;
+ build_table (curr_data);
+ if (key_writable (applet, "current_list"))
+ mate_panel_applet_mateconf_set_string (applet, "current_list", curr_data->charlist, NULL);
+}
+
+void
+populate_menu (charpick_data *curr_data)
+{
+ GList *list = curr_data->chartable;
+ GSList *group = NULL;
+ GtkMenu *menu;
+ GtkWidget *menuitem;
+
+ if (curr_data->menu)
+ gtk_widget_destroy (curr_data->menu);
+
+ curr_data->menu = gtk_menu_new ();
+ menu = GTK_MENU (curr_data->menu);
+
+ while (list) {
+ gchar *string = list->data;
+ menuitem = gtk_radio_menu_item_new_with_label (group, string);
+ group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem));
+ gtk_widget_show (menuitem);
+ g_object_set_data (G_OBJECT (menuitem), "string", string);
+ g_signal_connect (G_OBJECT (menuitem), "activate",
+ G_CALLBACK (menuitem_activated), curr_data);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+ if (g_ascii_strcasecmp (curr_data->charlist, string) == 0)
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), TRUE);
+ list = g_list_next (list);
+ }
+ build_table(curr_data);
+}
+
+static void
+get_menu_pos (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
+{
+ charpick_data *curr_data = data;
+ GtkRequisition reqmenu;
+ gint tempx, tempy, width, height;
+ gint screen_width, screen_height;
+
+ gtk_widget_size_request (GTK_WIDGET (menu), &reqmenu);
+ gdk_window_get_origin (GDK_WINDOW (gtk_widget_get_window(curr_data->applet)), &tempx, &tempy);
+ gdk_window_get_geometry (GDK_WINDOW (gtk_widget_get_window(curr_data->applet)), NULL, NULL,
+ &width, &height, NULL);
+
+ switch (mate_panel_applet_get_orient (MATE_PANEL_APPLET (curr_data->applet))) {
+ case MATE_PANEL_APPLET_ORIENT_DOWN:
+ tempy += height;
+ break;
+ case MATE_PANEL_APPLET_ORIENT_UP:
+ tempy -= reqmenu.height;
+ break;
+ case MATE_PANEL_APPLET_ORIENT_LEFT:
+ tempx -= reqmenu.width;
+ break;
+ case MATE_PANEL_APPLET_ORIENT_RIGHT:
+ tempx += width;
+ break;
+ }
+ screen_width = gdk_screen_width ();
+ screen_height = gdk_screen_height ();
+ *x = CLAMP (tempx, 0, MAX (0, screen_width - reqmenu.width));
+ *y = CLAMP (tempy, 0, MAX (0, screen_height - reqmenu.height));
+}
+
+static void
+chooser_button_clicked (GtkButton *button, charpick_data *curr_data)
+{
+ if (gtk_widget_get_visible (curr_data->menu))
+ gtk_menu_popdown (GTK_MENU (curr_data->menu));
+ else {
+ gtk_menu_set_screen (GTK_MENU (curr_data->menu),
+ gtk_widget_get_screen (GTK_WIDGET (curr_data->applet)));
+
+ gtk_menu_popup (GTK_MENU (curr_data->menu), NULL, NULL, get_menu_pos, curr_data,
+ 0, gtk_get_current_event_time());
+ }
+}
+
+/* Force the button not to have any focus padding and let the focus
+ indication be drawn on the label itself when space is tight. Taken from the clock applet.
+ FIXME : This is an Evil Hack and should be fixed when the focus padding can be overridden at the gtk+ level */
+
+static inline void force_no_focus_padding (GtkWidget *widget)
+{
+ gboolean first_time=TRUE;
+
+ if (first_time) {
+ gtk_rc_parse_string ("\n"
+ " style \"charpick-applet-button-style\"\n"
+ " {\n"
+ " GtkWidget::focus-line-width=0\n"
+ " GtkWidget::focus-padding=0\n"
+ " }\n"
+ "\n"
+ " widget \"*.charpick-applet-button\" style \"charpick-applet-button-style\"\n"
+ "\n");
+ first_time = FALSE;
+ }
+
+ gtk_widget_set_name (widget, "charpick-applet-button");
+}
+
+/* creates table of buttons, sets up their callbacks, and packs the table in
+ the event box */
+
+void
+build_table(charpick_data *p_curr_data)
+{
+ GtkWidget *box, *button_box, **row_box;
+ GtkWidget *button, *arrow;
+ gint i = 0, len = g_utf8_strlen (p_curr_data->charlist, -1);
+ GtkWidget **toggle_button;
+ gchar *charlist;
+ gint max_width=1, max_height=1;
+ gint size_ratio;
+
+ toggle_button = g_new (GtkWidget *, len);
+
+ if (p_curr_data->box)
+ gtk_widget_destroy(p_curr_data->box);
+
+ if (p_curr_data->panel_vertical)
+ box = gtk_vbox_new (FALSE, 0);
+ else
+ box = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (box);
+ p_curr_data->box = box;
+
+ button = gtk_button_new ();
+ if (g_list_length (p_curr_data->chartable) != 1)
+ {
+ gtk_widget_set_tooltip_text (button, _("Available palettes"));
+
+ switch (mate_panel_applet_get_orient (MATE_PANEL_APPLET (p_curr_data->applet))) {
+ case MATE_PANEL_APPLET_ORIENT_DOWN:
+ arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
+ break;
+ case MATE_PANEL_APPLET_ORIENT_UP:
+ arrow = gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_OUT);
+ break;
+ case MATE_PANEL_APPLET_ORIENT_LEFT:
+ arrow = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_OUT);
+ break;
+ case MATE_PANEL_APPLET_ORIENT_RIGHT:
+ arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_OUT);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ gtk_container_add (GTK_CONTAINER (button), arrow);
+ gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
+ /* FIXME : evil hack (see force_no_focus_padding) */
+ force_no_focus_padding (button);
+ gtk_box_pack_start (GTK_BOX (box), button, TRUE, TRUE, 0);
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (chooser_button_clicked),
+ p_curr_data);
+ g_signal_connect (G_OBJECT (button), "button_press_event",
+ G_CALLBACK (button_press_hack),
+ p_curr_data->applet);
+
+ }
+
+ charlist = g_strdup (p_curr_data->charlist);
+ for (i = 0; i < len; i++) {
+ gchar label[7];
+ GtkRequisition req;
+ gchar *atk_desc;
+ gchar *name;
+
+ g_utf8_strncpy (label, charlist, 1);
+ charlist = g_utf8_next_char (charlist);
+
+#ifdef HAVE_GUCHARMAP
+ /* TRANSLATOR: This sentance reads something like 'Insert "PILCROW SIGN"'
+ * hopefully, the name of the unicode character has already
+ * been translated.
+ */
+ name = g_strdup_printf (_("Insert \"%s\""),
+ gucharmap_get_unicode_name (g_utf8_get_char (label)));
+#else
+ name = g_strdup (_("Insert special character"));
+#endif
+
+ toggle_button[i] = gtk_toggle_button_new_with_label (label);
+ atk_desc = g_strdup_printf (_("insert special character %s"), label);
+ set_atk_name_description (toggle_button[i], NULL, atk_desc);
+ g_free (atk_desc);
+ gtk_widget_show (toggle_button[i]);
+ gtk_button_set_relief(GTK_BUTTON(toggle_button[i]), GTK_RELIEF_NONE);
+ /* FIXME : evil hack (see force_no_focus_padding) */
+ force_no_focus_padding (toggle_button[i]);
+ gtk_widget_set_tooltip_text (toggle_button[i], name);
+ g_free (name);
+
+ gtk_widget_size_request (toggle_button[i], &req);
+
+ max_width = MAX (max_width, req.width);
+ max_height = MAX (max_height, req.height-2);
+
+ g_object_set_data (G_OBJECT (toggle_button[i]), "unichar",
+ GINT_TO_POINTER(g_utf8_get_char (label)));
+ g_signal_connect (GTK_OBJECT (toggle_button[i]), "toggled",
+ G_CALLBACK (toggle_button_toggled_cb),
+ p_curr_data);
+ g_signal_connect (GTK_OBJECT (toggle_button[i]), "button_press_event",
+ G_CALLBACK (button_press_hack), p_curr_data->applet);
+ }
+
+ if (p_curr_data->panel_vertical) {
+ size_ratio = p_curr_data->panel_size / max_width;
+ button_box = gtk_hbox_new (TRUE, 0);
+ } else {
+ size_ratio = p_curr_data->panel_size / max_height;
+ button_box = gtk_vbox_new (TRUE, 0);
+ }
+
+ gtk_box_pack_start (GTK_BOX (box), button_box, TRUE, TRUE, 0);
+
+ size_ratio = MAX (size_ratio, 1);
+ row_box = g_new0 (GtkWidget *, size_ratio);
+ for (i=0; i < size_ratio; i++) {
+ if (!p_curr_data->panel_vertical) row_box[i] = gtk_hbox_new (TRUE, 0);
+ else row_box[i] = gtk_vbox_new (TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (button_box), row_box[i], TRUE, TRUE, 0);
+ }
+
+ for (i = 0; i <len; i++) {
+ int delta = len/size_ratio;
+ int index;
+
+ if (delta > 0)
+ index = i / delta;
+ else
+ index = i;
+
+ index = CLAMP (index, 0, size_ratio-1);
+ gtk_box_pack_start (GTK_BOX (row_box[index]), toggle_button[i], TRUE, TRUE, 0);
+ }
+
+ g_free (toggle_button);
+
+ gtk_container_add (GTK_CONTAINER(p_curr_data->applet), box);
+ gtk_widget_show_all (p_curr_data->box);
+
+ p_curr_data->last_index = NO_LAST_INDEX;
+ p_curr_data->last_toggle_button = NULL;
+
+}
+
+static void applet_size_allocate(MatePanelApplet *applet, GtkAllocation *allocation, gpointer data)
+{
+ charpick_data *curr_data = data;
+ if (curr_data->panel_vertical) {
+ if (curr_data->panel_size == allocation->width)
+ return;
+ curr_data->panel_size = allocation->width;
+ } else {
+ if (curr_data->panel_size == allocation->height)
+ return;
+ curr_data->panel_size = allocation->height;
+ }
+
+ build_table (curr_data);
+ return;
+}
+
+static void applet_change_orient(MatePanelApplet *applet, MatePanelAppletOrient o, gpointer data)
+{
+ charpick_data *curr_data = data;
+ if (o == MATE_PANEL_APPLET_ORIENT_UP ||
+ o == MATE_PANEL_APPLET_ORIENT_DOWN)
+ curr_data->panel_vertical = FALSE;
+ else
+ curr_data->panel_vertical = TRUE;
+ build_table (curr_data);
+ return;
+}
+
+
+static void
+about (GtkAction *action,
+ charpick_data *curr_data)
+{
+ static const char * const authors[] = {
+ "Alexandre Muñiz <[email protected]>",
+ "Kevin Vandersloot",
+ NULL
+ };
+
+ static const gchar * const documenters[] = {
+ "Dan Mueth <[email protected]>",
+ "Sun MATE Documentation Team <[email protected]>",
+ NULL
+ };
+
+ gtk_show_about_dialog (NULL,
+ "version", VERSION,
+ "copyright", "\xC2\xA9 1998, 2004-2005 MATE Applets Maintainers "
+ "and others",
+ "comments", _("Mate Panel applet for selecting strange "
+ "characters that are not on my keyboard. "
+ "Released under GNU General Public Licence."),
+ "authors", authors,
+ "documenters", documenters,
+ "translator-credits", _("translator-credits"),
+ "logo-icon-name", "accessories-character-map",
+ NULL);
+}
+
+
+static void
+help_cb (GtkAction *action,
+ charpick_data *curr_data)
+{
+ GError *error = NULL;
+
+ gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (curr_data->applet)),
+ "ghelp:char-palette",
+ gtk_get_current_event_time (),
+ &error);
+
+ if (error) { /* FIXME: the user needs to see this */
+ g_warning ("help error: %s\n", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+}
+
+static void
+applet_destroy (GtkWidget *widget, gpointer data)
+{
+ charpick_data *curr_data = data;
+
+ g_return_if_fail (curr_data);
+
+ if (curr_data->about_dialog)
+ gtk_widget_destroy (curr_data->about_dialog);
+ if (curr_data->propwindow)
+ gtk_widget_destroy (curr_data->propwindow);
+ if (curr_data->box)
+ gtk_widget_destroy (curr_data->box);
+ if (curr_data->menu)
+ gtk_widget_destroy (curr_data->menu);
+ g_free (curr_data);
+
+}
+
+void
+save_chartable (charpick_data *curr_data)
+{
+ MatePanelApplet *applet = MATE_PANEL_APPLET (curr_data->applet);
+ MateConfValue *value;
+ GList *list = curr_data->chartable;
+ GSList *slist = NULL;
+
+ while (list) {
+ gchar *charlist = list->data;
+ MateConfValue *v1;
+ v1 = mateconf_value_new_from_string (MATECONF_VALUE_STRING, charlist, NULL);
+ slist = g_slist_append (slist, v1);
+ list = g_list_next (list);
+ }
+
+ value = mateconf_value_new (MATECONF_VALUE_LIST);
+ mateconf_value_set_list_type (value, MATECONF_VALUE_STRING);
+ mateconf_value_set_list_nocopy (value, slist);
+ mate_panel_applet_mateconf_set_value (applet, "chartable", value, NULL);
+ mateconf_value_free (value);
+}
+
+static void
+get_chartable (charpick_data *curr_data)
+{
+ MatePanelApplet *applet = MATE_PANEL_APPLET (curr_data->applet);
+ MateConfValue *value;
+ gint i, n;
+
+ value = mate_panel_applet_mateconf_get_value (applet, "chartable", NULL);
+ if (value) {
+ GSList *slist = mateconf_value_get_list (value);
+ while (slist) {
+ MateConfValue *v1 = slist->data;
+ gchar *charlist;
+
+ charlist = g_strdup (mateconf_value_get_string (v1));
+ curr_data->chartable = g_list_append (curr_data->chartable, charlist);
+
+ slist = g_slist_next (slist);
+ }
+ mateconf_value_free (value);
+ }
+ else {
+ n = G_N_ELEMENTS (chartable);
+ for (i=0; i<n; i++) {
+ gchar *string;
+
+ string = g_ucs4_to_utf8 (chartable[i], -1, NULL, NULL, NULL);
+ curr_data->chartable = g_list_append (curr_data->chartable, string);
+
+ }
+ if ( ! key_writable (MATE_PANEL_APPLET (curr_data->applet), "chartable"))
+ save_chartable (curr_data);
+ }
+
+
+}
+
+static const GtkActionEntry charpick_applet_menu_actions [] = {
+ { "Preferences", GTK_STOCK_PROPERTIES, N_("_Preferences"),
+ NULL, NULL,
+ G_CALLBACK (show_preferences_dialog) },
+ { "Help", GTK_STOCK_HELP, N_("_Help"),
+ NULL, NULL,
+ G_CALLBACK (help_cb) },
+ { "About", GTK_STOCK_ABOUT, N_("_About"),
+ NULL, NULL,
+ G_CALLBACK (about) }
+};
+
+void
+set_atk_name_description (GtkWidget *widget, const gchar *name,
+ const gchar *description)
+{
+ AtkObject *aobj;
+ aobj = gtk_widget_get_accessible (widget);
+ /* return if gail is not loaded */
+ if (GTK_IS_ACCESSIBLE (aobj) == FALSE)
+ return;
+ if (name)
+ atk_object_set_name (aobj, name);
+ if (description)
+ atk_object_set_description (aobj, description);
+}
+
+static void
+make_applet_accessible (GtkWidget *applet)
+{
+ set_atk_name_description (applet, _("Character Palette"), _("Insert characters"));
+}
+
+static gboolean
+charpicker_applet_fill (MatePanelApplet *applet)
+{
+ MatePanelAppletOrient orientation;
+ charpick_data *curr_data;
+ GdkAtom utf8_atom;
+ GList *list;
+ gchar *string;
+ GtkActionGroup *action_group;
+ gchar *ui_path;
+
+ g_set_application_name (_("Character Palette"));
+
+ gtk_window_set_default_icon_name ("accessories-character-map");
+
+ mate_panel_applet_set_background_widget (applet, GTK_WIDGET (applet));
+
+ mate_panel_applet_add_preferences (applet, "/schemas/apps/charpick/prefs", NULL);
+ mate_panel_applet_set_flags (applet, MATE_PANEL_APPLET_EXPAND_MINOR);
+
+ curr_data = g_new0 (charpick_data, 1);
+ curr_data->last_index = NO_LAST_INDEX;
+ curr_data->applet = GTK_WIDGET (applet);
+ curr_data->about_dialog = NULL;
+ curr_data->add_edit_dialog = NULL;
+
+ get_chartable (curr_data);
+
+ string = mate_panel_applet_mateconf_get_string (applet, "current_list", NULL);
+ if (string) {
+ list = curr_data->chartable;
+ while (list) {
+ if (g_ascii_strcasecmp (list->data, string) == 0)
+ curr_data->charlist = list->data;
+ list = g_list_next (list);
+ }
+ /* FIXME: yeah leak, but this code is full of leaks and evil
+ point shuffling. This should really be rewritten
+ -George */
+ if (curr_data->charlist == NULL)
+ curr_data->charlist = string;
+ else
+ g_free (string);
+ } else {
+ curr_data->charlist = curr_data->chartable->data;
+ }
+
+ curr_data->panel_size = mate_panel_applet_get_size (applet);
+
+ orientation = mate_panel_applet_get_orient (applet);
+ curr_data->panel_vertical = (orientation == MATE_PANEL_APPLET_ORIENT_LEFT)
+ || (orientation == MATE_PANEL_APPLET_ORIENT_RIGHT);
+ build_table (curr_data);
+
+ g_signal_connect (G_OBJECT (curr_data->applet), "key_press_event",
+ G_CALLBACK (key_press_event), curr_data);
+
+ utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
+ gtk_selection_add_target (curr_data->applet,
+ GDK_SELECTION_PRIMARY,
+ utf8_atom,
+ 0);
+ gtk_selection_add_target (curr_data->applet,
+ GDK_SELECTION_CLIPBOARD,
+ utf8_atom,
+ 0);
+ g_signal_connect (GTK_OBJECT (curr_data->applet), "selection_get",
+ G_CALLBACK (charpick_selection_handler),
+ curr_data);
+ g_signal_connect (GTK_OBJECT (curr_data->applet), "selection_clear_event",
+ G_CALLBACK (selection_clear_cb),
+ curr_data);
+
+ make_applet_accessible (GTK_WIDGET (applet));
+
+ /* session save signal */
+ g_signal_connect (G_OBJECT (applet), "change_orient",
+ G_CALLBACK (applet_change_orient), curr_data);
+
+ g_signal_connect (G_OBJECT (applet), "size_allocate",
+ G_CALLBACK (applet_size_allocate), curr_data);
+
+ g_signal_connect (G_OBJECT (applet), "destroy",
+ G_CALLBACK (applet_destroy), curr_data);
+
+ gtk_widget_show_all (GTK_WIDGET (applet));
+
+ action_group = gtk_action_group_new ("Charpicker Applet Actions");
+ gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions (action_group,
+ charpick_applet_menu_actions,
+ G_N_ELEMENTS (charpick_applet_menu_actions),
+ curr_data);
+ ui_path = g_build_filename (CHARPICK_MENU_UI_DIR, "charpick-applet-menu.xml", NULL);
+ mate_panel_applet_setup_menu_from_file (MATE_PANEL_APPLET (applet),
+ ui_path, action_group);
+ g_free (ui_path);
+
+ if (mate_panel_applet_get_locked_down (MATE_PANEL_APPLET (applet))) {
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (action_group, "Preferences");
+ gtk_action_set_visible (action, FALSE);
+ }
+ g_object_unref (action_group);
+
+ register_stock_for_edit ();
+ populate_menu (curr_data);
+
+ return TRUE;
+}
+
+static gboolean
+charpicker_applet_factory (MatePanelApplet *applet,
+ const gchar *iid,
+ gpointer data)
+{
+ gboolean retval = FALSE;
+
+ if (!strcmp (iid, "CharpickerApplet"))
+ retval = charpicker_applet_fill (applet);
+
+ return retval;
+}
+
+MATE_PANEL_APPLET_OUT_PROCESS_FACTORY ("CharpickerAppletFactory",
+ PANEL_TYPE_APPLET,
+ "char-palette",
+ charpicker_applet_factory,
+ NULL)
+