From 4eb4ae3be83fcc187ac0ca3bd104a14ceeb0786f Mon Sep 17 00:00:00 2001 From: Ettore Perazzoli Date: Wed, 23 Jan 2002 22:21:24 +0000 Subject: [Implement an Outlook-style "New" dropdown button. It is basically done but it needs pretty icons so I am leaving it disabled for now.] * e-combo-button.c: Remove member `separator' from `EComboButtonPrivate'. New members `icon', `label'. (init): There shall be no separator no more. Init `icon' and `label' to %NULL. (e_combo_button_construct): Set no relief. (e_combo_button_new): Don't get a @menu arg anymore. (e_combo_button_construct): Likewise. (e_combo_button_set_icon): New. (e_combo_button_set_label): New. (e_combo_button_set_menu): New. (impl_clicked): New, overriding the "clicked" method for GtkButton. (class_init): Install. (impl_button_release_event): Removed. (class_init): No need to override ::release_event with this anymore. (impl_released): New, override for the GtkButton::released method. (class_init): Install. * e-shell-user-creatable-items-handler.c: New member `id' in struct `Component'. New member `icon' in struct `MenuItem'. (component_free): Free ->id. (component_new): Renamed from `component_new_from_client'. Get an @id arg and set ->id accordingly. (e_shell_user_creatable_items_handler_add_component): New arg @id. Pass it to `component_new'. (e_shell_user_creatable_items_handler_setup_menus): New arg @current_component_id. (e_shell_user_creatable_items_handler_update_menus): New. (set_current_component): New helper function. (get_component_by_id): New helper function. (add_verbs): Renamed from `add_verbs_to_ui_component()'. Get a @shell_view instead of a @ui_component. Set the SHELL_VIEW_KEY on the ui_component of the shell_view to point to the shell_view itself. (ensure_menu_items): Set item->icon to NULL. (free_menu_items): Unref item->icon. (ensure_menu_xml): Set the icon as well. (get_default_action_for_view): New helper function. (find_menu_item_for_verb): New helper function. (shell_view_view_changed_callback): New callback, set up the label on the "New" button depending on the current component. (e_shell_user_creatable_items_handler_attach_menus): New. For now, do not display the toolbar button yet. (execute_verb): New helper function, splitting out code from `verb_fn'. (verb_fn): Use `execute_verb'. (combo_button_activate_default_callback): Callback for the "activate_default" signal on the EComboButton. (setup_toolbar_button): Connect. * evolution-shell-component.c: New member `icon' in `UserCreatableItemType'. (impl__get_userCreatableItemTypes): Put the ->icon in the corba_type as well. (user_creatable_item_type_new): Get a new @icon argument. (evolution_shell_component_add_user_creatable_item): New arg @icon. * Evolution-ShellComponent.idl: New member `icon' in struct `UserCreatableItemType'. * evolution-test-component.c (register_component): Pass a NULL @icon to `evolution_shell_component_add_user_creatable_item()'. * e-shell-view.c (class_init): Add the signal to the class. (e_shell_view_display_uri): Emit "view_changed". (e_shell_view_get_current_component_id): New. * evolution-shell-component-client.c: New member `id' in EvolutionShellComponentClientPrivate. (init): Init to NULL. (impl_destroy): Free. (evolution_shell_component_client_new_for_objref): Removed. (evolution_shell_component_client_construct): New arg @id. Initialize ->id from it. (evolution_shell_component_client_get_id): New. * e-shell-view.h: New signal "view_changed". * evolution-activity-client.c (create_icon_from_pixbuf): Removed. (create_corba_animated_icon_from_pixbuf_array): Removed. (evolution_activity_client_construct): Use `e_new_corba_animated_icon_from_pixbuf_array()' instead. svn path=/trunk/; revision=15438 --- shell/ChangeLog | 71 +++++ shell/Evolution-ShellComponent.idl | 1 + shell/Makefile.am | 2 + shell/e-shell-user-creatable-items-handler.c | 381 +++++++++++++++++++++------ shell/e-shell-user-creatable-items-handler.h | 5 +- shell/e-shell-view.c | 40 ++- shell/e-shell-view.h | 14 +- shell/e-shell.c | 1 + shell/evolution-activity-client.c | 74 +----- shell/evolution-shell-component-client.c | 41 ++- shell/evolution-shell-component-client.h | 14 +- shell/evolution-shell-component.c | 23 +- shell/evolution-shell-component.h | 11 +- shell/evolution-storage-listener.h | 4 +- shell/evolution-test-component.c | 6 +- widgets/misc/ChangeLog | 21 ++ widgets/misc/e-combo-button.c | 322 ++++++++++++++-------- widgets/misc/e-combo-button.h | 14 +- 18 files changed, 744 insertions(+), 301 deletions(-) diff --git a/shell/ChangeLog b/shell/ChangeLog index 6bacbf5c27..b5f56f25cc 100644 --- a/shell/ChangeLog +++ b/shell/ChangeLog @@ -1,3 +1,74 @@ +2002-01-23 Ettore Perazzoli + + * e-shell-user-creatable-items-handler.c: New member `id' in + struct `Component'. New member `icon' in struct `MenuItem'. + (component_free): Free ->id. + (component_new): Renamed from `component_new_from_client'. Get an + @id arg and set ->id accordingly. + (e_shell_user_creatable_items_handler_add_component): New arg @id. + Pass it to `component_new'. + (e_shell_user_creatable_items_handler_setup_menus): New arg + @current_component_id. + (e_shell_user_creatable_items_handler_update_menus): New. + (set_current_component): New helper function. + (get_component_by_id): New helper function. + (add_verbs): Renamed from `add_verbs_to_ui_component()'. Get a + @shell_view instead of a @ui_component. Set the SHELL_VIEW_KEY on + the ui_component of the shell_view to point to the shell_view + itself. + (ensure_menu_items): Set item->icon to NULL. + (free_menu_items): Unref item->icon. + (ensure_menu_xml): Set the icon as well. + (get_default_action_for_view): New helper function. + (find_menu_item_for_verb): New helper function. + (shell_view_view_changed_callback): New callback, set up the label + on the "New" button depending on the current component. + (e_shell_user_creatable_items_handler_attach_menus): New. For + now, do not display the toolbar button yet. + (execute_verb): New helper function, splitting out code from + `verb_fn'. + (verb_fn): Use `execute_verb'. + (combo_button_activate_default_callback): Callback for the + "activate_default" signal on the EComboButton. + (setup_toolbar_button): Connect. + + * evolution-shell-component.c: New member `icon' in + `UserCreatableItemType'. + (impl__get_userCreatableItemTypes): Put the ->icon in the + corba_type as well. + (user_creatable_item_type_new): Get a new @icon argument. + (evolution_shell_component_add_user_creatable_item): New arg + @icon. + + * Evolution-ShellComponent.idl: New member `icon' in struct + `UserCreatableItemType'. + + * evolution-test-component.c (register_component): Pass a NULL + @icon to `evolution_shell_component_add_user_creatable_item()'. + + * e-shell-view.c (class_init): Add the signal to the class. + (e_shell_view_display_uri): Emit "view_changed". + (e_shell_view_get_current_component_id): New. + + * evolution-shell-component-client.c: New member `id' in + EvolutionShellComponentClientPrivate. + (init): Init to NULL. + (impl_destroy): Free. + (evolution_shell_component_client_new_for_objref): Removed. + (evolution_shell_component_client_construct): New arg @id. + Initialize ->id from it. + (evolution_shell_component_client_get_id): New. + + * e-shell-view.h: New signal "view_changed". + + * evolution-activity-client.c (create_icon_from_pixbuf): Removed. + (create_corba_animated_icon_from_pixbuf_array): Removed. + (evolution_activity_client_construct): Use + `e_new_corba_animated_icon_from_pixbuf_array()' instead. + + * e-shell-icon-utils.h: New. + * e-shell-icon-utils.c: New. + 2002-01-23 Ettore Perazzoli [Patch by Michael Meeks .] diff --git a/shell/Evolution-ShellComponent.idl b/shell/Evolution-ShellComponent.idl index 04e45157c9..b5f5095c43 100644 --- a/shell/Evolution-ShellComponent.idl +++ b/shell/Evolution-ShellComponent.idl @@ -36,6 +36,7 @@ module Evolution { string description; string menuDescription; char menuShortcut; + Icon icon; }; typedef sequence UserCreatableItemTypeList; diff --git a/shell/Makefile.am b/shell/Makefile.am index c406707087..465b2a3250 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -77,6 +77,8 @@ eshellinclude_HEADERS = \ libeshell_la_SOURCES = \ $(IDL_GENERATED) \ e-folder-tree.c \ + e-shell-corba-icon-utils.c \ + e-shell-corba-icon-utils.h \ evolution-activity-client.c \ evolution-session.c \ evolution-shell-client.c \ diff --git a/shell/e-shell-user-creatable-items-handler.c b/shell/e-shell-user-creatable-items-handler.c index 4b2554fb66..cafd074605 100644 --- a/shell/e-shell-user-creatable-items-handler.c +++ b/shell/e-shell-user-creatable-items-handler.c @@ -26,12 +26,18 @@ #include "e-shell-user-creatable-items-handler.h" +#include "widgets/misc/e-combo-button.h" + #include "e-util/e-corba-utils.h" #include #include +#include + +#include + #include #include @@ -41,7 +47,9 @@ static GtkObjectClass *parent_class = NULL; #define VERB_PREFIX "ShellUserCreatableItemVerb" -#define SHELL_VIEW_DATA_KEY "EShellUserCreatableItemsHandler:shell_view" + +#define SHELL_VIEW_KEY "EShellUserCreatableItemsHandler:shell_view" +#define COMBO_BUTTON_WIDGET_KEY "EShellUserCreatableItemsHandler:combo_button" struct _Component { EvolutionShellComponentClient *component_client; @@ -50,9 +58,18 @@ struct _Component { }; typedef struct _Component Component; +struct _MenuItem { + const char *label; + char shortcut; + char *verb; + GdkPixbuf *icon; +}; +typedef struct _MenuItem MenuItem; + struct _EShellUserCreatableItemsHandlerPrivate { GSList *components; /* Component */ + GSList *menu_items; /* MenuItem */ char *menu_xml; }; @@ -60,7 +77,8 @@ struct _EShellUserCreatableItemsHandlerPrivate { /* Component struct handling. */ static Component * -component_new_from_client (EvolutionShellComponentClient *client) +component_new (const char *id, + EvolutionShellComponentClient *client) { CORBA_Environment ev; Component *new; @@ -106,14 +124,8 @@ create_verb_from_component_number_and_type_id (int component_num, } -/* Setting up the XML for the menus. */ - -struct _MenuItem { - const char *label; - char shortcut; - char *verb; -}; -typedef struct _MenuItem MenuItem; +/* Setting up menu items for the "File -> New" submenu and the "New" toolbar + button. */ static int item_types_sort_func (const void *a, @@ -156,51 +168,10 @@ item_types_sort_func (const void *a, } else { return +1; } - -} - -static char * -create_xml_from_menu_items (GSList *items) -{ - GString *xml; - GSList *p; - char *str; - - xml = g_string_new (""); - - g_string_append (xml, " "); - - g_string_append (xml, " "); - - for (p = items; p != NULL; p = p->next) { - const MenuItem *item; - char *encoded_label; - - item = (const MenuItem *) p->data; - - encoded_label = bonobo_ui_util_encode_str (item->label); - - g_string_sprintfa (xml, "verb, item->verb, encoded_label); - - if (item->shortcut != '\0') - g_string_sprintfa (xml, " accel=\"*Control**Shift*%c\"", item->shortcut); - - g_string_append (xml, "/> "); - - g_free (encoded_label); - } - - g_string_append (xml, " "); - - str = xml->str; - g_string_free (xml, FALSE); - - return str; } static void -setup_menu_xml (EShellUserCreatableItemsHandler *handler) +ensure_menu_items (EShellUserCreatableItemsHandler *handler) { EShellUserCreatableItemsHandlerPrivate *priv; GSList *menu_items; @@ -208,7 +179,8 @@ setup_menu_xml (EShellUserCreatableItemsHandler *handler) int component_num; priv = handler->priv; - g_assert (priv->menu_xml == NULL); + if (priv->menu_items != NULL) + return; menu_items = NULL; component_num = 0; @@ -228,6 +200,7 @@ setup_menu_xml (EShellUserCreatableItemsHandler *handler) item->label = type->menuDescription; item->shortcut = type->menuShortcut; item->verb = create_verb_from_component_number_and_type_id (component_num, type->id); + item->icon = NULL; menu_items = g_slist_prepend (menu_items, item); } @@ -236,36 +209,154 @@ setup_menu_xml (EShellUserCreatableItemsHandler *handler) component_num ++; } - if (menu_items == NULL) { - priv->menu_xml = g_strdup (""); - return; - } + if (menu_items == NULL) + priv->menu_items = NULL; + else + priv->menu_items = g_slist_sort (menu_items, item_types_sort_func); +} - menu_items = g_slist_sort (menu_items, item_types_sort_func); +static void +free_menu_items (GSList *menu_items) +{ + GSList *p; - priv->menu_xml = create_xml_from_menu_items (menu_items); + if (menu_items == NULL) + return; for (p = menu_items; p != NULL; p = p->next) { MenuItem *item; item = (MenuItem *) p->data; g_free (item->verb); + + if (item->icon != NULL) + gdk_pixbuf_unref (item->icon); + g_free (item); } + g_slist_free (menu_items); } +static const MenuItem * +find_menu_item_for_verb (EShellUserCreatableItemsHandler *handler, + const char *verb) +{ + EShellUserCreatableItemsHandlerPrivate *priv; + GSList *p; + + priv = handler->priv; + + for (p = priv->menu_items; p != NULL; p = p->next) { + const MenuItem *item; + + item = (const MenuItem *) p->data; + if (strcmp (item->verb, verb) == 0) + return item; + } + + return NULL; +} + +static const MenuItem * +get_default_action_for_view (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view) +{ + EShellUserCreatableItemsHandlerPrivate *priv; + const char *view_component_id; + const GSList *p; + int component_num; + + priv = handler->priv; + + /* FIXME-1.2: This should be based on the folder type not the component + that handles it. For this, we are going to have to make the IDL a + little more complex. Also, this is a pretty brutal and ugly hack. */ + + view_component_id = e_shell_view_get_current_component_id (shell_view); + + for (p = priv->components, component_num = 0; p != NULL; p = p->next, component_num ++) { + const Component *component; + const GNOME_Evolution_UserCreatableItemType *type; + const char *component_id; + + component = (const Component *) p->data; + type = & component->type_list->_buffer[0]; + component_id = evolution_shell_component_client_get_id (component->component_client); + + if (strcmp (component_id, view_component_id) == 0) { + const MenuItem *item; + char *verb; + + verb = create_verb_from_component_number_and_type_id (component_num, type->id); + item = find_menu_item_for_verb (handler, verb); + g_free (verb); + + return item; + } + } + + return NULL; +} + + +/* The XML description for "File -> New". */ + +static void +ensure_menu_xml (EShellUserCreatableItemsHandler *handler) +{ + EShellUserCreatableItemsHandlerPrivate *priv; + GString *xml; + GSList *p; + + priv = handler->priv; + if (priv->menu_xml != NULL) + return; + + ensure_menu_items (handler); + + xml = g_string_new (""); + + g_string_append (xml, ""); + + for (p = priv->menu_items; p != NULL; p = p->next) { + const MenuItem *item; + char *encoded_label; + + item = (const MenuItem *) p->data; + + encoded_label = bonobo_ui_util_encode_str (item->label); + + g_string_sprintfa (xml, "verb, item->verb, encoded_label); + + if (item->shortcut != '\0') + g_string_sprintfa (xml, " accel=\"*Control**Shift*%c\"", item->shortcut); + + if (item->icon != NULL) + g_string_sprintfa (xml, " pixtype=\"pixbuf\" pixname=\"%s\"", + bonobo_ui_util_pixbuf_to_xml (item->icon)); + + g_string_append (xml, "/> "); + + g_free (encoded_label); + } + + g_string_append (xml, ""); + + priv->menu_xml = xml->str; + g_string_free (xml, FALSE); +} + /* Verb handling. */ static void -verb_fn (BonoboUIComponent *ui_component, - void *data, - const char *verb_name) +execute_verb (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view, + const char *verb_name) { - EShellUserCreatableItemsHandler *handler; EShellUserCreatableItemsHandlerPrivate *priv; - EShellView *shell_view; const Component *component; int component_number; const char *p; @@ -273,10 +364,6 @@ verb_fn (BonoboUIComponent *ui_component, GSList *component_list_item; int i; - shell_view = gtk_object_get_data (GTK_OBJECT (ui_component), SHELL_VIEW_DATA_KEY); - g_assert (E_IS_SHELL_VIEW (shell_view)); - - handler = E_SHELL_USER_CREATABLE_ITEMS_HANDLER (data); priv = handler->priv; p = strchr (verb_name, ':'); @@ -318,15 +405,35 @@ verb_fn (BonoboUIComponent *ui_component, } static void -add_verbs_to_ui_component (EShellUserCreatableItemsHandler *handler, - BonoboUIComponent *ui_component) +verb_fn (BonoboUIComponent *ui_component, + void *data, + const char *verb_name) +{ + EShellUserCreatableItemsHandler *handler; + EShellView *shell_view; + + shell_view = gtk_object_get_data (GTK_OBJECT (ui_component), SHELL_VIEW_KEY); + g_assert (E_IS_SHELL_VIEW (shell_view)); + + handler = E_SHELL_USER_CREATABLE_ITEMS_HANDLER (data); + + execute_verb (handler, shell_view, verb_name); +} + +static void +add_verbs (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view) { EShellUserCreatableItemsHandlerPrivate *priv; + BonoboUIComponent *ui_component; int component_num; GSList *p; priv = handler->priv; + ui_component = e_shell_view_get_bonobo_ui_component (shell_view); + gtk_object_set_data (GTK_OBJECT (ui_component), SHELL_VIEW_KEY, shell_view); + component_num = 0; for (p = priv->components; p != NULL; p = p->next) { const Component *component; @@ -351,6 +458,99 @@ add_verbs_to_ui_component (EShellUserCreatableItemsHandler *handler, } } + +/* The "New" button in the toolbar. */ + +static void +combo_button_activate_default_callback (EComboButton *combo_button, + void *data) +{ + EShellView *shell_view; + EShellUserCreatableItemsHandler *handler; + const MenuItem *menu_item; + + shell_view = E_SHELL_VIEW (data); + handler = e_shell_get_user_creatable_items_handler (e_shell_view_get_shell (shell_view)); + + menu_item = get_default_action_for_view (handler, shell_view); + execute_verb (handler, shell_view, menu_item->verb); +} + +static void +setup_toolbar_button (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view) +{ + EShellUserCreatableItemsHandlerPrivate *priv; + BonoboUIComponent *ui_component; + GtkWidget *combo_button; + GtkWidget *menu; + BonoboControl *control; + + priv = handler->priv; + + menu = gtk_menu_new (); + + combo_button = e_combo_button_new (); + e_combo_button_set_menu (E_COMBO_BUTTON (combo_button), GTK_MENU (menu)); + e_combo_button_set_label (E_COMBO_BUTTON (combo_button), _("New")); + gtk_widget_show (combo_button); + + gtk_signal_connect (GTK_OBJECT (combo_button), "activate_default", + GTK_SIGNAL_FUNC (combo_button_activate_default_callback), + shell_view); + + ui_component = e_shell_view_get_bonobo_ui_component (shell_view); + bonobo_window_add_popup (BONOBO_WINDOW (shell_view), GTK_MENU (menu), "/popups/NewPopup"); + + control = bonobo_control_new (combo_button); + + bonobo_ui_component_object_set (ui_component, "/Toolbar/NewComboButton", + BONOBO_OBJREF (control), NULL); + + gtk_object_set_data (GTK_OBJECT (shell_view), COMBO_BUTTON_WIDGET_KEY, combo_button); +} + + +/* This handles the menus for a given EShellView. We have to rebuild the menu + and set the toolbar button every time the view changes, and clean up when + the view is destroyed. */ + +static void +shell_view_view_changed_callback (EShellView *shell_view, + const char *evolution_path, + const char *physical_uri, + const char *folder_type, + const char *component_id, + void *data) +{ + EShellUserCreatableItemsHandler *handler; + EShellUserCreatableItemsHandlerPrivate *priv; + GtkWidget *combo_button_widget; + const MenuItem *default_menu_item; + + handler = E_SHELL_USER_CREATABLE_ITEMS_HANDLER (data); + priv = handler->priv; + + combo_button_widget = gtk_object_get_data (GTK_OBJECT (shell_view), COMBO_BUTTON_WIDGET_KEY); + g_assert (E_IS_COMBO_BUTTON (combo_button_widget)); + + default_menu_item = get_default_action_for_view (handler, shell_view); + if (default_menu_item == NULL) { + gtk_widget_set_sensitive (combo_button_widget, FALSE); + e_combo_button_set_label (E_COMBO_BUTTON (combo_button_widget), _("New")); + e_combo_button_set_icon (E_COMBO_BUTTON (combo_button_widget), NULL); + return; + } + + gtk_widget_set_sensitive (combo_button_widget, TRUE); + + /* FIXME: This is temporary. We should just always say "New" once we + have the icons for all the actions. */ + e_combo_button_set_label (E_COMBO_BUTTON (combo_button_widget), default_menu_item->label); + + e_combo_button_set_icon (E_COMBO_BUTTON (combo_button_widget), default_menu_item->icon); +} + /* GtkObject methods. */ @@ -371,6 +571,8 @@ impl_destroy (GtkObject *object) g_free (priv->menu_xml); + free_menu_items (priv->menu_items); + g_free (priv); (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -393,6 +595,7 @@ init (EShellUserCreatableItemsHandler *shell_user_creatable_items_handler) priv = g_new (EShellUserCreatableItemsHandlerPrivate, 1); priv->components = NULL; priv->menu_xml = NULL; + priv->menu_items = NULL; shell_user_creatable_items_handler->priv = priv; } @@ -410,6 +613,7 @@ e_shell_user_creatable_items_handler_new (void) void e_shell_user_creatable_items_handler_add_component (EShellUserCreatableItemsHandler *handler, + const char *id, EvolutionShellComponentClient *shell_component_client) { EShellUserCreatableItemsHandlerPrivate *priv; @@ -422,15 +626,25 @@ e_shell_user_creatable_items_handler_add_component (EShellUserCreatableItemsHan priv = handler->priv; g_return_if_fail (priv->menu_xml == NULL); - priv->components = g_slist_prepend (priv->components, component_new_from_client (shell_component_client)); + priv->components = g_slist_prepend (priv->components, component_new (id, shell_component_client)); } + +/** + * e_shell_user_creatable_items_handler_attach_menus: + * @handler: + * @shell_view: + * + * Set up the menus and toolbar items for @shell_view. When the shell changes + * view, the menu and the toolbar item will update automatically (i.e. the + * actions for the current folder will go on top etc.). + **/ void -e_shell_user_creatable_items_handler_setup_menus (EShellUserCreatableItemsHandler *handler, - EShellView *shell_view) +e_shell_user_creatable_items_handler_attach_menus (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view) { - EShellUserCreatableItemsHandlerPrivate *priv; BonoboUIComponent *ui_component; + EShellUserCreatableItemsHandlerPrivate *priv; g_return_if_fail (handler != NULL); g_return_if_fail (E_IS_SHELL_USER_CREATABLE_ITEMS_HANDLER (handler)); @@ -439,17 +653,20 @@ e_shell_user_creatable_items_handler_setup_menus (EShellUserCreatableItemsHandle priv = handler->priv; - if (priv->menu_xml == NULL) - setup_menu_xml (handler); - - ui_component = e_shell_view_get_bonobo_ui_component (shell_view); - g_assert (ui_component); + /* FIXME: Re-enable this. */ + if (0) { + setup_toolbar_button (handler, shell_view); + gtk_signal_connect (GTK_OBJECT (shell_view), "view_changed", + GTK_SIGNAL_FUNC (shell_view_view_changed_callback), handler); + } - add_verbs_to_ui_component (handler, ui_component); + ensure_menu_xml (handler); - gtk_object_set_data (GTK_OBJECT (ui_component), SHELL_VIEW_DATA_KEY, shell_view); /* Yuck. */ + add_verbs (handler, shell_view); - bonobo_ui_component_set (ui_component, "/", priv->menu_xml, NULL); + ui_component = e_shell_view_get_bonobo_ui_component (shell_view); + bonobo_ui_component_set (ui_component, "/menu/File/New/NewItems", priv->menu_xml, NULL); + bonobo_ui_component_set (ui_component, "/popups/NewPopup", priv->menu_xml, NULL); } diff --git a/shell/e-shell-user-creatable-items-handler.h b/shell/e-shell-user-creatable-items-handler.h index a743e234be..77a3b6b608 100644 --- a/shell/e-shell-user-creatable-items-handler.h +++ b/shell/e-shell-user-creatable-items-handler.h @@ -61,10 +61,11 @@ GtkType e_shell_user_creatable_items_handler_get_type EShellUserCreatableItemsHandler *e_shell_user_creatable_items_handler_new (void); void e_shell_user_creatable_items_handler_add_component (EShellUserCreatableItemsHandler *handler, + const char *id, EvolutionShellComponentClient *shell_component_client); -void e_shell_user_creatable_items_handler_setup_menus (EShellUserCreatableItemsHandler *handler, - EShellView *shell_view); +void e_shell_user_creatable_items_handler_attach_menus (EShellUserCreatableItemsHandler *handler, + EShellView *shell_view); #ifdef __cplusplus } diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c index 9a9b09bd9c..6545af81bd 100644 --- a/shell/e-shell-view.c +++ b/shell/e-shell-view.c @@ -147,6 +147,7 @@ struct _EShellViewPrivate { enum { SHORTCUT_BAR_VISIBILITY_CHANGED, FOLDER_BAR_VISIBILITY_CHANGED, + VIEW_CHANGED, LAST_SIGNAL }; @@ -1167,6 +1168,18 @@ class_init (EShellViewClass *klass) GTK_TYPE_NONE, 1, GTK_TYPE_INT); + signals[VIEW_CHANGED] + = gtk_signal_new ("view_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (EShellViewClass, view_changed), + e_marshal_NONE__POINTER_POINTER_POINTER_POINTER, + GTK_TYPE_NONE, 4, + GTK_TYPE_STRING, + GTK_TYPE_STRING, + GTK_TYPE_STRING, + GTK_TYPE_STRING); + gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); load_images (); @@ -1407,8 +1420,8 @@ e_shell_view_construct (EShellView *shell_view, GTK_SIGNAL_FUNC (storage_set_removed_folder_callback), shell_view, GTK_OBJECT (shell_view)); - e_shell_user_creatable_items_handler_setup_menus (e_shell_get_user_creatable_items_handler (priv->shell), - shell_view); + e_shell_user_creatable_items_handler_attach_menus (e_shell_get_user_creatable_items_handler (priv->shell), + shell_view); return view; } @@ -2044,6 +2057,12 @@ e_shell_view_display_uri (EShellView *shell_view, bonobo_window_thaw (BONOBO_WINDOW (shell_view)); + gtk_signal_emit (GTK_OBJECT (shell_view), signals[VIEW_CHANGED], + e_shell_view_get_current_path (shell_view), + e_shell_view_get_current_uri (shell_view), + e_shell_view_get_current_folder_type (shell_view), + e_shell_view_get_current_component_id (shell_view)); + return retval; } @@ -2269,6 +2288,23 @@ e_shell_view_get_current_folder_type (EShellView *shell_view) return get_type_for_folder (shell_view, current_path, NULL); } +const char * +e_shell_view_get_current_component_id (EShellView *shell_view) +{ + EShellViewPrivate *priv; + EFolderTypeRegistry *type_registry; + EvolutionShellComponentClient *component_client; + const char *current_folder_type; + + priv = shell_view->priv; + + type_registry = e_shell_get_folder_type_registry (priv->shell); + current_folder_type = e_shell_view_get_current_folder_type (shell_view); + component_client = e_folder_type_registry_get_handler_for_type (type_registry, current_folder_type); + + return evolution_shell_component_client_get_id (component_client); +} + /** * e_shell_view_save_settings: diff --git a/shell/e-shell-view.h b/shell/e-shell-view.h index 9738171b9a..c5ba207e24 100644 --- a/shell/e-shell-view.h +++ b/shell/e-shell-view.h @@ -57,8 +57,17 @@ struct _EShellViewClass { BonoboWindowClass parent_class; /* Signals. */ - void (* shortcut_bar_visibility_changed) (EShellView *shell_view, gboolean visible); - void (* folder_bar_visibility_changed) (EShellView *shell_view, gboolean visible); + + void (* shortcut_bar_visibility_changed) (EShellView *shell_view, + gboolean visible); + void (* folder_bar_visibility_changed) (EShellView *shell_view, + gboolean visible); + + void (* view_changed) (EShellView *shell_view, + const char *evolution_path, + const char *physical_uri, + const char *folder_type, + const char *component_id); }; @@ -93,6 +102,7 @@ GtkWidget *e_shell_view_get_appbar (EShellView *shell_vi const char *e_shell_view_get_current_uri (EShellView *shell_view); const char *e_shell_view_get_current_physical_uri (EShellView *shell_view); const char *e_shell_view_get_current_folder_type (EShellView *shell_view); +const char *e_shell_view_get_current_component_id (EShellView *shell_view); const char *e_shell_view_get_current_path (EShellView *shell_view); gboolean e_shell_view_save_settings (EShellView *shell_view, diff --git a/shell/e-shell.c b/shell/e-shell.c index abcd11819f..1923226ca0 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -742,6 +742,7 @@ setup_components (EShell *shell, } else { e_shell_user_creatable_items_handler_add_component (priv->user_creatable_items_handler, + info->iid, e_component_registry_get_component_by_id (priv->component_registry, info->iid)); } diff --git a/shell/evolution-activity-client.c b/shell/evolution-activity-client.c index 5de8a4c217..6ecea011d7 100644 --- a/shell/evolution-activity-client.c +++ b/shell/evolution-activity-client.c @@ -31,6 +31,8 @@ #include "evolution-activity-client.h" +#include "e-shell-corba-icon-utils.h" + #include #include @@ -78,76 +80,6 @@ struct _EvolutionActivityClientPrivate { /* Utility functions. */ -/* Create an icon from @pixbuf in @icon_return. */ -static void -create_icon_from_pixbuf (GdkPixbuf *pixbuf, - GNOME_Evolution_Icon *icon_return) -{ - const char *sp; - CORBA_octet *dp; - int width, height, total_width, rowstride; - int i, j; - gboolean has_alpha; - - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); - - if (has_alpha) - total_width = 4 * width; - else - total_width = 3 * width; - - icon_return->width = width; - icon_return->height = height; - icon_return->hasAlpha = has_alpha; - - icon_return->rgbaData._length = icon_return->height * total_width; - icon_return->rgbaData._maximum = icon_return->rgbaData._length; - icon_return->rgbaData._buffer = CORBA_sequence_CORBA_octet_allocbuf (icon_return->rgbaData._maximum); - - sp = gdk_pixbuf_get_pixels (pixbuf); - dp = icon_return->rgbaData._buffer; - for (i = 0; i < height; i ++) { - for (j = 0; j < total_width; j++) - *(dp ++) = sp[j]; - sp += rowstride; - } - - CORBA_sequence_set_release (& icon_return->rgbaData, TRUE); -} - -/* Generate an AnimatedIcon from a NULL-terminated @pixbuf_array. */ -static GNOME_Evolution_AnimatedIcon * -create_corba_animated_icon_from_pixbuf_array (GdkPixbuf **pixbuf_array) -{ - GNOME_Evolution_AnimatedIcon *animated_icon; - GdkPixbuf **p; - int num_frames; - int i; - - num_frames = 0; - for (p = pixbuf_array; *p != NULL; p++) - num_frames++; - - if (num_frames == 0) - return NULL; - - animated_icon = GNOME_Evolution_AnimatedIcon__alloc (); - - animated_icon->_length = num_frames; - animated_icon->_maximum = num_frames; - animated_icon->_buffer = CORBA_sequence_GNOME_Evolution_Icon_allocbuf (animated_icon->_maximum); - - for (i = 0; i < num_frames; i++) - create_icon_from_pixbuf (pixbuf_array[i], & animated_icon->_buffer[i]); - - CORBA_sequence_set_release (animated_icon, TRUE); - - return animated_icon; -} - static gboolean corba_update_progress (EvolutionActivityClient *activity_client, const char *information, @@ -350,7 +282,7 @@ evolution_activity_client_construct (EvolutionActivityClient *activity_client, return FALSE; } - corba_animated_icon = create_corba_animated_icon_from_pixbuf_array (animated_icon); + corba_animated_icon = e_new_corba_animated_icon_from_pixbuf_array (animated_icon); GNOME_Evolution_Activity_operationStarted (activity_interface, component_id, diff --git a/shell/evolution-shell-component-client.c b/shell/evolution-shell-component-client.c index 4b35e2ac7a..574b75ecc8 100644 --- a/shell/evolution-shell-component-client.c +++ b/shell/evolution-shell-component-client.c @@ -44,6 +44,8 @@ char *evolution_debug_log; static BonoboObjectClass *parent_class = NULL; struct _EvolutionShellComponentClientPrivate { + char *id; + EvolutionShellComponentClientCallback callback; void *callback_data; @@ -298,6 +300,8 @@ impl_destroy (GtkObject *object) shell_component_client = EVOLUTION_SHELL_COMPONENT_CLIENT (object); priv = shell_component_client->priv; + g_free (priv->id); + if (priv->callback != NULL) dispatch_callback (shell_component_client, EVOLUTION_SHELL_COMPONENT_INTERRUPTED); @@ -347,6 +351,8 @@ init (EvolutionShellComponentClient *shell_component_client) priv = g_new (EvolutionShellComponentClientPrivate, 1); + priv->id = NULL; + priv->listener_interface = CORBA_OBJECT_NIL; priv->listener_servant = NULL; @@ -365,12 +371,18 @@ init (EvolutionShellComponentClient *shell_component_client) void evolution_shell_component_client_construct (EvolutionShellComponentClient *shell_component_client, + const char *id, CORBA_Object corba_object) { + EvolutionShellComponentClientPrivate *priv; + g_return_if_fail (shell_component_client != NULL); g_return_if_fail (EVOLUTION_IS_SHELL_COMPONENT_CLIENT (shell_component_client)); g_return_if_fail (corba_object != CORBA_OBJECT_NIL); + priv = shell_component_client->priv; + priv->id = g_strdup (id); + bonobo_object_client_construct (BONOBO_OBJECT_CLIENT (shell_component_client), corba_object); } @@ -378,6 +390,7 @@ evolution_shell_component_client_construct (EvolutionShellComponentClient *shell EvolutionShellComponentClient * evolution_shell_component_client_new (const char *id) { + EvolutionShellComponentClient *new; CORBA_Environment ev; CORBA_Object corba_object; @@ -392,12 +405,6 @@ evolution_shell_component_client_new (const char *id) return NULL; } -#if 0 - ior = CORBA_ORB_object_to_string (bonobo_orb (), corba_object, &ev); - g_print ("--- %s %s\n", id, ior); - CORBA_free (ior); -#endif - CORBA_exception_free (&ev); if (corba_object == CORBA_OBJECT_NIL) { @@ -406,20 +413,26 @@ evolution_shell_component_client_new (const char *id) return NULL; } - return evolution_shell_component_client_new_for_objref (corba_object); + new = gtk_type_new (evolution_shell_component_client_get_type ()); + evolution_shell_component_client_construct (new, id, corba_object); + + return new; } -EvolutionShellComponentClient * -evolution_shell_component_client_new_for_objref (const GNOME_Evolution_ShellComponent objref) + +/* Properties. */ + +const char * +evolution_shell_component_client_get_id (EvolutionShellComponentClient *shell_component_client) { - EvolutionShellComponentClient *new; + EvolutionShellComponentClientPrivate *priv; - g_return_val_if_fail (objref != CORBA_OBJECT_NIL, NULL); + g_return_val_if_fail (shell_component_client != NULL, NULL); + g_return_val_if_fail (EVOLUTION_IS_SHELL_COMPONENT_CLIENT (shell_component_client), NULL); - new = gtk_type_new (evolution_shell_component_client_get_type ()); - evolution_shell_component_client_construct (new, objref); + priv = shell_component_client->priv; - return new; + return priv->id; } diff --git a/shell/evolution-shell-component-client.h b/shell/evolution-shell-component-client.h index bea54f4b35..33b8cd92d3 100644 --- a/shell/evolution-shell-component-client.h +++ b/shell/evolution-shell-component-client.h @@ -61,11 +61,15 @@ typedef void (* EvolutionShellComponentClientCallback) (EvolutionShellComponentC /* Construction. */ -GtkType evolution_shell_component_client_get_type (void); -void evolution_shell_component_client_construct (EvolutionShellComponentClient *shell_component_client, - CORBA_Object corba_object); -EvolutionShellComponentClient *evolution_shell_component_client_new (const char *id); -EvolutionShellComponentClient *evolution_shell_component_client_new_for_objref (const GNOME_Evolution_ShellComponent objref); +GtkType evolution_shell_component_client_get_type (void); +void evolution_shell_component_client_construct (EvolutionShellComponentClient *shell_component_client, + const char *id, + CORBA_Object corba_object); +EvolutionShellComponentClient *evolution_shell_component_client_new (const char *id); + +/* Properties. */ + +const char *evolution_shell_component_client_get_id (EvolutionShellComponentClient *shell_component_client); /* Querying DnD interfaces. */ diff --git a/shell/evolution-shell-component.c b/shell/evolution-shell-component.c index a253b9278c..0357a20921 100644 --- a/shell/evolution-shell-component.c +++ b/shell/evolution-shell-component.c @@ -26,6 +26,8 @@ #include "evolution-shell-component.h" +#include "e-shell-corba-icon-utils.h" + #include #include @@ -35,8 +37,6 @@ #include -#include "Evolution.h" - #define PING_DELAY 10000 @@ -50,6 +50,7 @@ struct _UserCreatableItemType { char *description; char *menu_description; char menu_shortcut; + GdkPixbuf *icon; }; typedef struct _UserCreatableItemType UserCreatableItemType; @@ -93,7 +94,8 @@ static UserCreatableItemType * user_creatable_item_type_new (const char *id, const char *description, const char *menu_description, - char menu_shortcut) + char menu_shortcut, + GdkPixbuf *icon) { UserCreatableItemType *type; @@ -103,6 +105,11 @@ user_creatable_item_type_new (const char *id, type->menu_description = g_strdup (menu_description); type->menu_shortcut = menu_shortcut; + if (icon == NULL) + type->icon = NULL; + else + type->icon = gdk_pixbuf_ref (icon); + return type; } @@ -113,6 +120,9 @@ user_creatable_item_type_free (UserCreatableItemType *type) g_free (type->description); g_free (type->menu_description); + if (type->icon != NULL) + gdk_pixbuf_unref (type->icon); + g_free (type); } @@ -350,6 +360,8 @@ impl__get_userCreatableItemTypes (PortableServer_Servant servant, corba_type->description = CORBA_string_dup (type->description); corba_type->menuDescription = CORBA_string_dup (type->menu_description); corba_type->menuShortcut = type->menu_shortcut; + + e_store_corba_icon_from_pixbuf (type->icon, & corba_type->icon); } CORBA_sequence_set_release (list, TRUE); @@ -978,7 +990,8 @@ evolution_shell_component_add_user_creatable_item (EvolutionShellComponent *she const char *id, const char *description, const char *menu_description, - char menu_shortcut) + char menu_shortcut, + GdkPixbuf *icon) { EvolutionShellComponentPrivate *priv; UserCreatableItemType *type; @@ -991,7 +1004,7 @@ evolution_shell_component_add_user_creatable_item (EvolutionShellComponent *she priv = shell_component->priv; - type = user_creatable_item_type_new (id, description, menu_description, menu_shortcut); + type = user_creatable_item_type_new (id, description, menu_description, menu_shortcut, icon); priv->user_creatable_item_types = g_slist_prepend (priv->user_creatable_item_types, type); } diff --git a/shell/evolution-shell-component.h b/shell/evolution-shell-component.h index 3a3a1cff5e..7f7073572e 100644 --- a/shell/evolution-shell-component.h +++ b/shell/evolution-shell-component.h @@ -23,13 +23,15 @@ #ifndef EVOLUTION_SHELL_COMPONENT_H #define EVOLUTION_SHELL_COMPONENT_H -#include -#include - #include "Evolution.h" #include "evolution-shell-client.h" +#include + +#include +#include + #ifdef cplusplus extern "C" { #pragma } @@ -181,7 +183,8 @@ void evolution_shell_component_add_user_creatable_item (EvolutionShellComponen const char *id, const char *description, const char *menu_description, - char menu_shortcut); + char menu_shortcut, + GdkPixbuf *icon); const char *evolution_shell_component_result_to_string (EvolutionShellComponentResult result); diff --git a/shell/evolution-storage-listener.h b/shell/evolution-storage-listener.h index 084d4acc19..5e13435411 100644 --- a/shell/evolution-storage-listener.h +++ b/shell/evolution-storage-listener.h @@ -34,8 +34,8 @@ extern "C" { #define EVOLUTION_TYPE_STORAGE_LISTENER (evolution_storage_listener_get_type ()) #define EVOLUTION_STORAGE_LISTENER(obj) (GTK_CHECK_CAST ((obj), EVOLUTION_TYPE_STORAGE_LISTENER, EvolutionStorageListener)) #define EVOLUTION_STORAGE_LISTENER_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EVOLUTION_TYPE_STORAGE_LISTENER, EvolutionStorageListenerClass)) -#define EVOLUTION_IS_STORAGE_LISTENER(obj) (GTK_CHECK_TYPE ((obj), EVOLUTION_TYPE_STORAGE_LISTENER)) -#define EVOLUTION_IS_STORAGE_LISTENER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), EVOLUTION_TYPE_STORAGE_LISTENER)) +#define EVOLUTION_IS_STORAGE_LISTENER(obj) (GTK_CHECK_TYPE ((obj), EVOLUTION_TYPE_STORAGE_LISTENER)) +#define EVOLUTION_IS_STORAGE_LISTENER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), EVOLUTION_TYPE_STORAGE_LISTENER)) typedef struct _EvolutionStorageListener EvolutionStorageListener; diff --git a/shell/evolution-test-component.c b/shell/evolution-test-component.c index 23358ab6a6..8cf0856b88 100644 --- a/shell/evolution-test-component.c +++ b/shell/evolution-test-component.c @@ -312,8 +312,10 @@ register_component (void) gtk_signal_connect (GTK_OBJECT (shell_component), "owner_unset", GTK_SIGNAL_FUNC (owner_unset_callback), NULL); - evolution_shell_component_add_user_creatable_item (shell_component, "Stuff", "New Stuff", "New _Stuff", '\0'); - evolution_shell_component_add_user_creatable_item (shell_component, "MoreStuff", "New More Stuff", "New _More Stuff", 'n'); + evolution_shell_component_add_user_creatable_item (shell_component, "Stuff", + "New Stuff", "New _Stuff", '\0', NULL); + evolution_shell_component_add_user_creatable_item (shell_component, "MoreStuff", + "New More Stuff", "New _More Stuff", 'n', NULL); gtk_signal_connect (GTK_OBJECT (shell_component), "user_create_new_item", GTK_SIGNAL_FUNC (user_create_new_item_callback), NULL); diff --git a/widgets/misc/ChangeLog b/widgets/misc/ChangeLog index 5fd0471bb5..f59af32bcf 100644 --- a/widgets/misc/ChangeLog +++ b/widgets/misc/ChangeLog @@ -1,3 +1,24 @@ +2002-01-23 Ettore Perazzoli + + * e-combo-button.c: Remove member `separator' from + `EComboButtonPrivate'. New members `icon', `label'. + (init): There shall be no separator no more. Init `icon' and + `label' to %NULL. + (e_combo_button_construct): Set no relief. + (e_combo_button_new): Don't get a @menu arg anymore. + (e_combo_button_construct): Likewise. + (e_combo_button_set_icon): New. + (e_combo_button_set_label): New. + (e_combo_button_set_menu): New. + (impl_clicked): New, overriding the "clicked" method for + GtkButton. + (class_init): Install. + (impl_button_release_event): Removed. + (class_init): No need to override ::release_event with this + anymore. + (impl_released): New, override for the GtkButton::released method. + (class_init): Install. + 2002-01-04 Jeffrey Stedfast * e-charset-picker.c: Added iso-8859-8 (Hebrew; Visual) to the diff --git a/widgets/misc/e-combo-button.c b/widgets/misc/e-combo-button.c index 9f5a536ff2..c037586fc6 100644 --- a/widgets/misc/e-combo-button.c +++ b/widgets/misc/e-combo-button.c @@ -26,7 +26,6 @@ #include "e-combo-button.h" -#include #include #include #include @@ -35,18 +34,14 @@ #include - -enum { - ACTIVATE_DEFAULT, - LAST_SIGNAL -}; - struct _EComboButtonPrivate { + GdkPixbuf *icon; + + GtkWidget *icon_pixmap; + GtkWidget *label; GtkWidget *arrow_pixmap; GtkWidget *hbox; - GtkWidget *separator; - GtkWidget *label_hbox; GtkMenu *menu; @@ -56,7 +51,7 @@ struct _EComboButtonPrivate { #define SPACING 2 -static char *arrow_xpm[] = { +static const char *arrow_xpm[] = { "11 5 2 1", " c none", ". c #000000000000", @@ -70,7 +65,82 @@ static char *arrow_xpm[] = { #define PARENT_TYPE gtk_button_get_type () static GtkButtonClass *parent_class = NULL; -static guint combo_button_signals[LAST_SIGNAL] = { 0 }; + +enum { + ACTIVATE_DEFAULT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + + +/* Utility functions. */ + +static GtkWidget * +create_pixmap_widget_from_pixbuf (GdkPixbuf *pixbuf) +{ + GtkWidget *pixmap_widget; + GdkPixmap *pixmap; + GdkBitmap *mask; + + gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &mask, 128); + + pixmap_widget = gtk_pixmap_new (pixmap, mask); + + gdk_pixmap_unref (pixmap); + gdk_bitmap_unref (mask); + + return pixmap_widget; +} + +static GtkWidget * +create_empty_pixmap_widget (void) +{ + GtkWidget *pixmap_widget; + GdkPixbuf *pixbuf; + + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1); + + pixmap_widget = create_pixmap_widget_from_pixbuf (pixbuf); + + gdk_pixbuf_unref (pixbuf); + + return pixmap_widget; +} + +static GtkWidget * +create_arrow_pixmap_widget (void) +{ + GtkWidget *pixmap_widget; + GdkPixbuf *pixbuf; + + pixbuf = gdk_pixbuf_new_from_xpm_data (arrow_xpm); + + pixmap_widget = create_pixmap_widget_from_pixbuf (pixbuf); + + gdk_pixbuf_unref (pixbuf); + + return pixmap_widget; +} + +static void +set_icon (EComboButton *combo_button, + GdkPixbuf *pixbuf) +{ + EComboButtonPrivate *priv; + GdkPixmap *pixmap; + GdkBitmap *mask; + + priv = combo_button->priv; + + priv->icon = gdk_pixbuf_ref (pixbuf); + + gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &mask, 128); + gtk_pixmap_set (GTK_PIXMAP (priv->icon_pixmap), pixmap, mask); + + gdk_pixmap_unref (pixmap); + gdk_pixmap_unref (mask); +} /* Callbacks for the associated menu. */ @@ -140,6 +210,11 @@ impl_destroy (GtkObject *object) priv->arrow_pixmap = NULL; } + if (priv->icon != NULL) { + gdk_pixbuf_unref (priv->icon); + priv->icon = NULL; + } + g_free (priv); (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -148,48 +223,6 @@ impl_destroy (GtkObject *object) /* GtkWidget methods. */ -static void -impl_realize (GtkWidget *widget) -{ - EComboButton *combo_button; - EComboButtonPrivate *priv; - GdkPixmap *arrow_gdk_pixmap; - GdkBitmap *arrow_gdk_mask; - - combo_button = E_COMBO_BUTTON (widget); - priv = combo_button->priv; - - (* GTK_WIDGET_CLASS (parent_class)->realize) (widget); - - g_assert (priv->arrow_pixmap == NULL); - - arrow_gdk_pixmap = gdk_pixmap_create_from_xpm_d (widget->window, &arrow_gdk_mask, NULL, arrow_xpm); - priv->arrow_pixmap = gtk_pixmap_new (arrow_gdk_pixmap, arrow_gdk_mask); - gtk_widget_show (priv->arrow_pixmap); - - gtk_box_pack_start (GTK_BOX (priv->hbox), priv->arrow_pixmap, FALSE, TRUE, SPACING); - - gdk_pixmap_unref (arrow_gdk_pixmap); - gdk_bitmap_unref (arrow_gdk_mask); -} - -static void -impl_unrealize (GtkWidget *widget) -{ - EComboButton *combo_button; - EComboButtonPrivate *priv; - - combo_button = E_COMBO_BUTTON (widget); - priv = combo_button->priv; - - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); - - if (priv->arrow_pixmap != NULL) { - gtk_widget_destroy (priv->arrow_pixmap); - priv->arrow_pixmap = NULL; - } -} - static int impl_button_press_event (GtkWidget *widget, GdkEventButton *event) @@ -203,7 +236,7 @@ impl_button_press_event (GtkWidget *widget, if (event->type == GDK_BUTTON_PRESS && event->button == 1) { GTK_BUTTON (widget)->button_down = TRUE; - if (event->x >= priv->separator->allocation.x) { + if (event->x >= priv->arrow_pixmap->allocation.x) { /* User clicked on the right side: pop up the menu. */ gtk_button_pressed (GTK_BUTTON (widget)); @@ -222,18 +255,6 @@ impl_button_press_event (GtkWidget *widget, return TRUE; } -static int -impl_button_release_event (GtkWidget *widget, - GdkEventButton *event) -{ - if (event->button == 1) { - gtk_grab_remove (widget); - gtk_button_released (GTK_BUTTON (widget)); - } - - return TRUE; -} - static int impl_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event) @@ -254,39 +275,78 @@ impl_leave_notify_event (GtkWidget *widget, return FALSE; } + +/* GtkButton methods. */ + +static void +impl_released (GtkButton *button) +{ + EComboButton *combo_button; + EComboButtonPrivate *priv; + + combo_button = E_COMBO_BUTTON (button); + priv = combo_button->priv; + + /* Massive cut & paste from GtkButton here... The only change in + behavior here is that we want to emit ::activate_default when not + the menu hasn't been popped up. */ + + if (button->button_down) { + int new_state; + + button->button_down = FALSE; + + if (button->in_button) { + gtk_button_clicked (button); + + if (! priv->menu_popped_up) + gtk_signal_emit (GTK_OBJECT (button), signals[ACTIVATE_DEFAULT]); + } + + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + + /* We _draw () instead of queue_draw so that if the + operation blocks, the label doesn't vanish. */ + gtk_widget_draw (GTK_WIDGET (button), NULL); + } + } +} + static void class_init (GtkObjectClass *object_class) { GtkWidgetClass *widget_class; + GtkButtonClass *button_class; parent_class = gtk_type_class (PARENT_TYPE); object_class->destroy = impl_destroy; widget_class = GTK_WIDGET_CLASS (object_class); - widget_class->realize = impl_realize; - widget_class->unrealize = impl_unrealize; - widget_class->button_press_event = impl_button_press_event; - widget_class->button_release_event = impl_button_release_event; - widget_class->leave_notify_event = impl_leave_notify_event; - - combo_button_signals[ACTIVATE_DEFAULT] = - gtk_signal_new ("activate_default", - GTK_RUN_FIRST, - object_class->type, - GTK_SIGNAL_OFFSET (EComboButtonClass, activate_default), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - - gtk_object_class_add_signals (object_class, combo_button_signals, LAST_SIGNAL); + widget_class->button_press_event = impl_button_press_event; + widget_class->leave_notify_event = impl_leave_notify_event; + + button_class = GTK_BUTTON_CLASS (object_class); + button_class->released = impl_released; + + signals[ACTIVATE_DEFAULT] = gtk_signal_new ("activate_default", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (EComboButtonClass, activate_default), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); } static void init (EComboButton *combo_button) { EComboButtonPrivate *priv; - GtkWidget *label; priv = g_new (EComboButtonPrivate, 1); combo_button->priv = priv; @@ -295,58 +355,106 @@ init (EComboButton *combo_button) gtk_container_add (GTK_CONTAINER (combo_button), priv->hbox); gtk_widget_show (priv->hbox); - priv->label_hbox = gtk_hbox_new (FALSE, SPACING); - gtk_box_pack_start (GTK_BOX (priv->hbox), priv->label_hbox, TRUE, TRUE, 0); - gtk_widget_show (priv->label_hbox); + priv->icon_pixmap = create_empty_pixmap_widget (); + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->icon_pixmap, TRUE, TRUE, 0); + gtk_widget_show (priv->icon_pixmap); - priv->separator = gtk_vseparator_new (); - gtk_box_pack_start (GTK_BOX (priv->hbox), priv->separator, FALSE, TRUE, SPACING); - gtk_widget_show (priv->separator); + priv->label = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->label, TRUE, TRUE, 0); + gtk_widget_show (priv->label); - label = gtk_label_new ("TEST!!!"); - gtk_container_add (GTK_CONTAINER (priv->label_hbox), label); - gtk_widget_show (label); + priv->arrow_pixmap = create_arrow_pixmap_widget (); + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->arrow_pixmap, TRUE, TRUE, 0); + gtk_widget_show (priv->arrow_pixmap); - priv->arrow_pixmap = NULL; + priv->icon = NULL; priv->menu = NULL; priv->menu_popped_up = FALSE; } void -e_combo_button_construct (EComboButton *combo_button, - GtkMenu *menu) +e_combo_button_construct (EComboButton *combo_button) { EComboButtonPrivate *priv; g_return_if_fail (combo_button != NULL); g_return_if_fail (E_IS_COMBO_BUTTON (combo_button)); - g_return_if_fail (menu != NULL); - g_return_if_fail (GTK_IS_MENU (menu)); priv = combo_button->priv; g_return_if_fail (priv->menu == NULL); - priv->menu = menu; - gtk_menu_attach_to_widget (menu, GTK_WIDGET (combo_button), menu_detacher); - - gtk_signal_connect (GTK_OBJECT (menu), "deactivate", - GTK_SIGNAL_FUNC (menu_deactivate_callback), - combo_button); - GTK_WIDGET_UNSET_FLAGS (combo_button, GTK_CAN_FOCUS); + + gtk_button_set_relief (GTK_BUTTON (combo_button), GTK_RELIEF_NONE); } GtkWidget * -e_combo_button_new (GtkMenu *menu) +e_combo_button_new (void) { - GtkWidget *new; + EComboButton *new; new = gtk_type_new (e_combo_button_get_type ()); + e_combo_button_construct (new); - e_combo_button_construct (E_COMBO_BUTTON (new), menu); + return GTK_WIDGET (new); +} + + +void +e_combo_button_set_icon (EComboButton *combo_button, + GdkPixbuf *pixbuf) +{ + g_return_if_fail (combo_button != NULL); + g_return_if_fail (E_IS_COMBO_BUTTON (combo_button)); + g_return_if_fail (pixbuf != NULL); + + set_icon (combo_button, pixbuf); +} + +void +e_combo_button_set_label (EComboButton *combo_button, + const char *label) +{ + EComboButtonPrivate *priv; + + g_return_if_fail (combo_button != NULL); + g_return_if_fail (E_IS_COMBO_BUTTON (combo_button)); + g_return_if_fail (label != NULL); + + priv = combo_button->priv; + + if (label == NULL) + label = ""; + + gtk_label_parse_uline (GTK_LABEL (priv->label), label); +} + +void +e_combo_button_set_menu (EComboButton *combo_button, + GtkMenu *menu) +{ + EComboButtonPrivate *priv; + + g_return_if_fail (combo_button != NULL); + g_return_if_fail (E_IS_COMBO_BUTTON (combo_button)); + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); - return new; + priv = combo_button->priv; + + if (priv->menu != NULL) + gtk_menu_detach (priv->menu); + + priv->menu = menu; + if (menu == NULL) + return; + + gtk_menu_attach_to_widget (menu, GTK_WIDGET (combo_button), menu_detacher); + + gtk_signal_connect (GTK_OBJECT (menu), "deactivate", + GTK_SIGNAL_FUNC (menu_deactivate_callback), + combo_button); } diff --git a/widgets/misc/e-combo-button.h b/widgets/misc/e-combo-button.h index 7634194427..a0ad8af8f6 100644 --- a/widgets/misc/e-combo-button.h +++ b/widgets/misc/e-combo-button.h @@ -30,6 +30,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #pragma } @@ -60,10 +62,16 @@ struct _EComboButtonClass { }; -GtkType e_combo_button_get_type (void); -void e_combo_button_construct (EComboButton *combo_button, +GtkType e_combo_button_get_type (void); +void e_combo_button_construct (EComboButton *combo_button); +GtkWidget *e_combo_button_new (void); + +void e_combo_button_set_icon (EComboButton *combo_button, + GdkPixbuf *pixbuf); +void e_combo_button_set_label (EComboButton *combo_button, + const char *label); +void e_combo_button_set_menu (EComboButton *combo_button, GtkMenu *menu); -GtkWidget *e_combo_button_new (GtkMenu *menu); #ifdef __cplusplus } -- cgit v1.2.3