/* charpick.c This is a gnome panel applet that allow users to select * accented (and other) characters to be pasted into other apps. */ #include #include #include #include #ifdef HAVE_GUCHARMAP # include #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}; 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 }; gboolean key_writable (PanelApplet *applet, const char *key) { gboolean writable; char *fullkey; static GConfClient *client = NULL; if (client == NULL) client = gconf_client_get_default (); fullkey = panel_applet_gconf_get_full_key (applet, key); writable = gconf_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_state (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; PanelApplet *applet = 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")) panel_applet_gconf_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_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 (GTK_WIDGET (curr_data->applet)->window, &tempx, &tempy); gdk_window_get_geometry (GTK_WIDGET (curr_data->applet)->window, NULL, NULL, &width, &height, NULL); switch (panel_applet_get_orient (PANEL_APPLET (curr_data->applet))) { case PANEL_APPLET_ORIENT_DOWN: tempy += height; break; case PANEL_APPLET_ORIENT_UP: tempy -= reqmenu.height; break; case PANEL_APPLET_ORIENT_LEFT: tempx -= reqmenu.width; break; case 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_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 (panel_applet_get_orient (PANEL_APPLET (p_curr_data->applet))) { case PANEL_APPLET_ORIENT_DOWN: arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); break; case PANEL_APPLET_ORIENT_UP: arrow = gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_OUT); break; case PANEL_APPLET_ORIENT_LEFT: arrow = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_OUT); break; case 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", (GtkSignalFunc) toggle_button_toggled_cb, p_curr_data); g_signal_connect (GTK_OBJECT (toggle_button[i]), "button_press_event", (GtkSignalFunc) 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 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(PanelApplet *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(PanelApplet *applet, PanelAppletOrient o, gpointer data) { charpick_data *curr_data = data; if (o == PANEL_APPLET_ORIENT_UP || o == PANEL_APPLET_ORIENT_DOWN) curr_data->panel_vertical = FALSE; else curr_data->panel_vertical = TRUE; build_table (curr_data); return; } static void about (BonoboUIComponent *uic, charpick_data *curr_data, const char *verb) { static const char * const authors[] = { "Alexandre Muñiz ", "Kevin Vandersloot", NULL }; static const gchar * const documenters[] = { "Dan Mueth ", "Sun GNOME Documentation Team ", NULL }; gtk_show_about_dialog (NULL, "version", VERSION, "copyright", "\xC2\xA9 1998, 2004-2005 GNOME Applets Maintainers " "and others", "comments", _("Gnome 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", "charpick", NULL); } static void help_cb (BonoboUIComponent *uic, charpick_data *curr_data, const char *verb) { GError *error = NULL; gnome_help_display_on_screen ( "char-palette", NULL, gtk_widget_get_screen (curr_data->applet), &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) { PanelApplet *applet = PANEL_APPLET (curr_data->applet); GConfValue *value; GList *list = curr_data->chartable; GSList *slist = NULL; while (list) { gchar *charlist = list->data; GConfValue *v1; v1 = gconf_value_new_from_string (GCONF_VALUE_STRING, charlist, NULL); slist = g_slist_append (slist, v1); list = g_list_next (list); } value = gconf_value_new (GCONF_VALUE_LIST); gconf_value_set_list_type (value, GCONF_VALUE_STRING); gconf_value_set_list_nocopy (value, slist); panel_applet_gconf_set_value (applet, "chartable", value, NULL); gconf_value_free (value); } static void get_chartable (charpick_data *curr_data) { PanelApplet *applet = PANEL_APPLET (curr_data->applet); GConfValue *value; gint i, n; value = panel_applet_gconf_get_value (applet, "chartable", NULL); if (value) { GSList *slist = gconf_value_get_list (value); while (slist) { GConfValue *v1 = slist->data; gchar *charlist; charlist = g_strdup (gconf_value_get_string (v1)); curr_data->chartable = g_list_append (curr_data->chartable, charlist); slist = g_slist_next (slist); } gconf_value_free (value); } else { n = G_N_ELEMENTS (chartable); for (i=0; ichartable = g_list_append (curr_data->chartable, string); } if ( ! key_writable (PANEL_APPLET (curr_data->applet), "chartable")) save_chartable (curr_data); } } static const BonoboUIVerb charpick_applet_menu_verbs [] = { BONOBO_UI_UNSAFE_VERB ("Preferences", show_preferences_dialog), BONOBO_UI_UNSAFE_VERB ("Help", help_cb), BONOBO_UI_UNSAFE_VERB ("About", about), BONOBO_UI_VERB_END }; 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 (PanelApplet *applet) { PanelAppletOrient orientation; charpick_data *curr_data; GdkAtom utf8_atom; GList *list; gchar *string; g_set_application_name (_("Character Palette")); gtk_window_set_default_icon_name ("charpick"); panel_applet_set_background_widget (applet, GTK_WIDGET (applet)); panel_applet_add_preferences (applet, "/schemas/apps/charpick/prefs", NULL); panel_applet_set_flags (applet, 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 = panel_applet_gconf_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 = panel_applet_get_size (applet); orientation = panel_applet_get_orient (applet); curr_data->panel_vertical = (orientation == PANEL_APPLET_ORIENT_LEFT) || (orientation == 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", GTK_SIGNAL_FUNC (charpick_selection_handler), curr_data); g_signal_connect (GTK_OBJECT (curr_data->applet), "selection_clear_event", GTK_SIGNAL_FUNC (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)); panel_applet_setup_menu_from_file (PANEL_APPLET (applet), DATADIR, "GNOME_CharpickerApplet.xml", NULL, charpick_applet_menu_verbs, curr_data); if (panel_applet_get_locked_down (PANEL_APPLET (applet))) { BonoboUIComponent *popup_component; popup_component = panel_applet_get_popup_component (PANEL_APPLET (applet)); bonobo_ui_component_set_prop (popup_component, "/commands/Preferences", "hidden", "1", NULL); } register_stock_for_edit (); populate_menu (curr_data); return TRUE; } static gboolean charpicker_applet_factory (PanelApplet *applet, const gchar *iid, gpointer data) { gboolean retval = FALSE; if (!strcmp (iid, "OAFIID:GNOME_CharpickerApplet")) retval = charpicker_applet_fill (applet); return retval; } PANEL_APPLET_BONOBO_FACTORY ("OAFIID:GNOME_CharpickerApplet_Factory", PANEL_TYPE_APPLET, "char-palette", "0", charpicker_applet_factory, NULL)