From e1b828edf2d014f9eb5c78e5df020a45ecaed902 Mon Sep 17 00:00:00 2001 From: Christian Dywan Date: Fri, 10 Oct 2008 22:31:37 +0200 Subject: [PATCH] Finish refactoring the toolbar to use only actions Finally the trash, which was the last item that needed to be implemented as an action, is an action, a KatzeArrayAction to be exact. This simplifies more code and also makes Window and RecentlyVisited generically implementable. Incidentally this change also fixes a bug where the browser tried to add a new tab when the last one was closed, even while destroying itself. Furthermore sokoke_image_menu_item_ellipsized and sokoke_widget_popup were promoted to Katze. We're still keeping the old functions for now. --- katze/Makefile.am | 3 +- katze/katze-arrayaction.c | 361 ++++++++++++++++++++++++++++++++++++++ katze/katze-arrayaction.h | 47 +++++ katze/katze-utils.c | 123 +++++++++++++ katze/katze-utils.h | 15 ++ katze/katze.h | 1 + midori/midori-browser.c | 323 +++++++++++++++++++--------------- midori/sokoke.c | 91 +--------- po/POTFILES.in | 1 + 9 files changed, 732 insertions(+), 233 deletions(-) create mode 100644 katze/katze-arrayaction.c create mode 100644 katze/katze-arrayaction.h diff --git a/katze/Makefile.am b/katze/Makefile.am index 8e6caa71..f357f6a5 100644 --- a/katze/Makefile.am +++ b/katze/Makefile.am @@ -16,4 +16,5 @@ libkatze_la_SOURCES = \ katze-utils.c katze-utils.h \ katze-item.c katze-item.h \ katze-list.c katze-list.h \ - katze-array.c katze-array.h + katze-array.c katze-array.h \ + katze-arrayaction.c katze-arrayaction.h diff --git a/katze/katze-arrayaction.c b/katze/katze-arrayaction.c new file mode 100644 index 00000000..a47f4f92 --- /dev/null +++ b/katze/katze-arrayaction.c @@ -0,0 +1,361 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#include "katze-arrayaction.h" + +#include "katze-utils.h" + +#include +#include + +struct _KatzeArrayAction +{ + GtkAction parent_instance; + + KatzeArray* array; +}; + +struct _KatzeArrayActionClass +{ + GtkActionClass parent_class; +}; + +G_DEFINE_TYPE (KatzeArrayAction, katze_array_action, GTK_TYPE_ACTION) + +enum +{ + PROP_0, + + PROP_ARRAY +}; + +enum +{ + POPULATE_POPUP, + ACTIVATE_ITEM, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void +katze_array_action_finalize (GObject* object); + +static void +katze_array_action_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec); + +static void +katze_array_action_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec); + +static void +katze_array_action_activate (GtkAction* object); + +static GtkWidget* +katze_array_action_create_tool_item (GtkAction* action); + +static GtkWidget* +katze_array_action_create_menu_item (GtkAction* action); + +static void +katze_array_action_connect_proxy (GtkAction* action, + GtkWidget* proxy); + +static void +katze_array_action_disconnect_proxy (GtkAction* action, + GtkWidget* proxy); + +static void +katze_array_action_class_init (KatzeArrayActionClass* class) +{ + GObjectClass* gobject_class; + GtkActionClass* action_class; + + signals[POPULATE_POPUP] = g_signal_new ("populate-popup", + G_TYPE_FROM_CLASS (class), + (GSignalFlags) (G_SIGNAL_RUN_LAST), + 0, + 0, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GTK_TYPE_MENU); + + signals[ACTIVATE_ITEM] = g_signal_new ("activate-item", + G_TYPE_FROM_CLASS (class), + (GSignalFlags) (G_SIGNAL_RUN_LAST), + 0, + 0, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + KATZE_TYPE_ITEM); + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = katze_array_action_finalize; + gobject_class->set_property = katze_array_action_set_property; + gobject_class->get_property = katze_array_action_get_property; + + action_class = GTK_ACTION_CLASS (class); + action_class->activate = katze_array_action_activate; + action_class->create_menu_item = katze_array_action_create_menu_item; + action_class->create_tool_item = katze_array_action_create_tool_item; + action_class->connect_proxy = katze_array_action_connect_proxy; + action_class->disconnect_proxy = katze_array_action_disconnect_proxy; + + g_object_class_install_property (gobject_class, + PROP_ARRAY, + g_param_spec_object ( + "array", + _("Array"), + _("The array the action represents"), + KATZE_TYPE_ARRAY, + G_PARAM_READWRITE)); +} + +static void +katze_array_action_init (KatzeArrayAction* array_action) +{ + array_action->array = NULL; +} + +static void +katze_array_action_finalize (GObject* object) +{ + KatzeArrayAction* array_action = KATZE_ARRAY_ACTION (object); + + if (array_action->array) + g_object_unref (array_action->array); + + G_OBJECT_CLASS (katze_array_action_parent_class)->finalize (object); +} + +static void +katze_array_action_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec) +{ + KatzeArrayAction* array_action = KATZE_ARRAY_ACTION (object); + + switch (prop_id) + { + case PROP_ARRAY: + katze_array_action_set_array (array_action, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +katze_array_action_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec) +{ + KatzeArrayAction* array_action = KATZE_ARRAY_ACTION (object); + + switch (prop_id) + { + case PROP_ARRAY: + g_value_set_object (value, array_action->array); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +katze_array_action_activate (GtkAction* action) +{ + GSList* proxies; + + proxies = gtk_action_get_proxies (action); + if (!proxies) + return; + + do + if (GTK_IS_TOOL_ITEM (proxies->data)) + { + + } + while ((proxies = g_slist_next (proxies))); + + if (GTK_ACTION_CLASS (katze_array_action_parent_class)->activate) + GTK_ACTION_CLASS (katze_array_action_parent_class)->activate (action); +} + +static void +katze_array_action_menu_item_activate_cb (GtkWidget* proxy, + KatzeArrayAction* array_action) +{ + KatzeItem* item = g_object_get_data (G_OBJECT (proxy), "KatzeItem"); + g_signal_emit (array_action, signals[ACTIVATE_ITEM], 0, item); +} + +static void +katze_array_action_proxy_clicked_cb (GtkWidget* proxy, + KatzeArrayAction* array_action) +{ + GtkWidget* menu; + guint n, i; + GtkWidget* menuitem; + KatzeItem* item; + GdkPixbuf* pixbuf; + GtkWidget* icon; + + if (GTK_IS_MENU_ITEM (proxy)) + { + if (!(menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy)))) + { + menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (proxy), menu); + } + gtk_container_foreach (GTK_CONTAINER (menu), (GtkCallback)(gtk_widget_destroy), NULL); + } + else + menu = gtk_menu_new (); + + n = katze_array_get_length (array_action->array); + if (n > 0) + for (i = 0; i < n; i++) + { + item = katze_array_get_nth_item (array_action->array, i); + /* FIXME: The menu item should reflect changes to the item */ + menuitem = katze_image_menu_item_new_ellipsized ( + katze_item_get_name (item)); + pixbuf = gtk_widget_render_icon (menuitem, GTK_STOCK_FILE, + GTK_ICON_SIZE_MENU, NULL); + icon = gtk_image_new_from_pixbuf (pixbuf); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); + g_object_unref (pixbuf); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_object_set_data (G_OBJECT (menuitem), "KatzeItem", item); + g_signal_connect (menuitem, "activate", + G_CALLBACK (katze_array_action_menu_item_activate_cb), array_action); + gtk_widget_show (menuitem); + } + else + { + menuitem = gtk_image_menu_item_new_with_label (_("Empty")); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + } + + g_signal_emit (array_action, signals[POPULATE_POPUP], 0, menu); + + if (!GTK_IS_MENU_ITEM (proxy)) + katze_widget_popup (GTK_WIDGET (proxy), GTK_MENU (menu), + NULL, KATZE_MENU_POSITION_LEFT); +} + +static GtkWidget* +katze_array_action_create_menu_item (GtkAction* action) +{ + GtkWidget* menuitem; + + menuitem = gtk_menu_item_new (); + return menuitem; +} + +static GtkWidget* +katze_array_action_create_tool_item (GtkAction* action) +{ + GtkWidget* toolitem; + + toolitem = GTK_WIDGET (gtk_tool_button_new (NULL, NULL)); + return toolitem; +} + +static void +katze_array_action_connect_proxy (GtkAction* action, + GtkWidget* proxy) +{ + GTK_ACTION_CLASS (katze_array_action_parent_class)->connect_proxy ( + action, proxy); + + if (GTK_IS_TOOL_ITEM (proxy)) + { + g_signal_connect (proxy, "clicked", + G_CALLBACK (katze_array_action_proxy_clicked_cb), action); + } + else if (GTK_IS_MENU_ITEM (proxy)) + { + /* FIXME: 'select' doesn't cover all ways of selection */ + g_signal_connect (proxy, "select", + G_CALLBACK (katze_array_action_proxy_clicked_cb), action); + } +} + +static void +katze_array_action_disconnect_proxy (GtkAction* action, + GtkWidget* proxy) +{ + g_signal_handlers_disconnect_by_func (proxy, + G_CALLBACK (katze_array_action_proxy_clicked_cb), action); + + GTK_ACTION_CLASS (katze_array_action_parent_class)->disconnect_proxy + (action, proxy); +} + +KatzeArray* +katze_array_action_get_array (KatzeArrayAction* array_action) +{ + g_return_val_if_fail (KATZE_IS_ARRAY_ACTION (array_action), NULL); + + return array_action->array; +} + +void +katze_array_action_set_array (KatzeArrayAction* array_action, + KatzeArray* array) +{ + GSList* proxies; + + g_return_if_fail (KATZE_IS_ARRAY_ACTION (array_action)); + g_return_if_fail (!array || katze_array_is_a (array, KATZE_TYPE_ITEM)); + + /* FIXME: Disconnect old array */ + + if (array) + g_object_ref (array); + katze_object_assign (array_action->array, array); + + /* FIXME: Add and remove items dynamically */ + /*g_object_connect (array, + "signal-after::add-item", + katze_array_action_engines_add_item_cb, array_action, + "signal-after::remove-item", + katze_array_action_engines_remove_item_cb, array_action, + NULL);*/ + + g_object_notify (G_OBJECT (array_action), "array"); + + proxies = gtk_action_get_proxies (GTK_ACTION (array_action)); + if (!proxies) + return; + + do + if (GTK_IS_TOOL_ITEM (proxies->data)) + { + + } + while ((proxies = g_slist_next (proxies))); +} diff --git a/katze/katze-arrayaction.h b/katze/katze-arrayaction.h new file mode 100644 index 00000000..b4e9ee22 --- /dev/null +++ b/katze/katze-arrayaction.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#ifndef __KATZE_ARRAY_ACTION_H__ +#define __KATZE_ARRAY_ACTION_H__ + +#include "katze-array.h" + +G_BEGIN_DECLS + +#define KATZE_TYPE_ARRAY_ACTION \ + (katze_array_action_get_type ()) +#define KATZE_ARRAY_ACTION(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_ARRAY_ACTION, KatzeArrayAction)) +#define KATZE_ARRAY_ACTION_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_ARRAY_ACTION, KatzeArrayActionClass)) +#define KATZE_IS_ARRAY_ACTION(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_ARRAY_ACTION)) +#define KATZE_IS_ARRAY_ACTION_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_ARRAY_ACTION)) +#define KATZE_ARRAY_ACTION_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_ARRAY_ACTION, KatzeArrayActionClass)) + +typedef struct _KatzeArrayAction KatzeArrayAction; +typedef struct _KatzeArrayActionClass KatzeArrayActionClass; + +GType +katze_array_action_get_type (void); + +KatzeArray* +katze_array_action_get_array (KatzeArrayAction* array_action); + +void +katze_array_action_set_array (KatzeArrayAction* array_action, + KatzeArray* array); + +G_END_DECLS + +#endif /* __KATZE_ARRAY_ACTION_H__ */ diff --git a/katze/katze-utils.c b/katze/katze-utils.c index 061e7c3d..af2d3857 100644 --- a/katze/katze-utils.c +++ b/katze/katze-utils.c @@ -328,3 +328,126 @@ katze_property_label (gpointer object, return widget; } + +typedef struct +{ + GtkWidget* widget; + KatzeMenuPos position; +} KatzePopupInfo; + +static void +katze_widget_popup_position_menu (GtkMenu* menu, + gint* x, + gint* y, + gboolean* push_in, + gpointer user_data) +{ + gint wx, wy; + gint menu_width; + GtkRequisition menu_req; + GtkRequisition widget_req; + KatzePopupInfo* info = user_data; + GtkWidget* widget = info->widget; + gint widget_height; + + /* Retrieve size and position of both widget and menu */ + if (GTK_WIDGET_NO_WINDOW (widget)) + { + gdk_window_get_position (widget->window, &wx, &wy); + wx += widget->allocation.x; + wy += widget->allocation.y; + } + else + gdk_window_get_origin (widget->window, &wx, &wy); + gtk_widget_size_request (GTK_WIDGET (menu), &menu_req); + gtk_widget_size_request (widget, &widget_req); + menu_width = menu_req.width; + widget_height = widget_req.height; /* Better than allocation.height */ + + /* Calculate menu position */ + if (info->position == KATZE_MENU_POSITION_CURSOR) + ; /* Do nothing? */ + else if (info->position == KATZE_MENU_POSITION_RIGHT) + { + *x = wx + widget->allocation.width - menu_width; + *y = wy + widget_height; + } else if (info->position == KATZE_MENU_POSITION_LEFT) + { + *x = wx; + *y = wy + widget_height; + } + + *push_in = TRUE; +} + +/** + * katze_widget_popup: + * @widget: a widget + * @menu: the menu to popup + * @event: a button event, or %NULL + * @pos: the preferred positioning + * + * Pops up the given menu relative to @widget. Use this + * instead of writing custom positioning functions. + * + * Return value: a new label widget + **/ +void +katze_widget_popup (GtkWidget* widget, + GtkMenu* menu, + GdkEventButton* event, + KatzeMenuPos pos) +{ + int button, event_time; + if (event) + { + button = event->button; + event_time = event->time; + } + else + { + button = 0; + event_time = gtk_get_current_event_time (); + } + + if (!gtk_menu_get_attach_widget (menu)) + gtk_menu_attach_to_widget (menu, widget, NULL); + + + if (widget) + { + KatzePopupInfo info = { widget, pos }; + gtk_menu_popup (menu, NULL, NULL, + katze_widget_popup_position_menu, &info, + button, event_time); + } + else + gtk_menu_popup (menu, NULL, NULL, NULL, NULL, button, event_time); +} + +/** + * katze_image_menu_item_new_ellipsized: + * @label: a label or %NULL + * + * Creates an image menu item where the label is + * reasonably ellipsized for you. + * + * Return value: a new label widget + **/ +GtkWidget* +katze_image_menu_item_new_ellipsized (const gchar* label) +{ + GtkWidget* menuitem; + GtkWidget* label_widget; + + menuitem = gtk_image_menu_item_new (); + label_widget = gtk_label_new (label); + /* FIXME: Should text direction be respected here? */ + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.0); + gtk_label_set_max_width_chars (GTK_LABEL (label_widget), 50); + gtk_label_set_ellipsize (GTK_LABEL (label_widget), PANGO_ELLIPSIZE_MIDDLE); + gtk_widget_show (label_widget); + gtk_container_add (GTK_CONTAINER (menuitem), label_widget); + + return menuitem; +} diff --git a/katze/katze-utils.h b/katze/katze-utils.h index 6ff7b863..52ac45a8 100644 --- a/katze/katze-utils.h +++ b/katze/katze-utils.h @@ -63,6 +63,21 @@ GtkWidget* katze_property_label (gpointer object, const gchar* property); +typedef enum { + KATZE_MENU_POSITION_CURSOR = 0, + KATZE_MENU_POSITION_LEFT, + KATZE_MENU_POSITION_RIGHT +} KatzeMenuPos; + +void +katze_widget_popup (GtkWidget* widget, + GtkMenu* menu, + GdkEventButton* event, + KatzeMenuPos pos); + +GtkWidget* +katze_image_menu_item_new_ellipsized (const gchar* label); + G_END_DECLS #endif /* __KATZE_UTILS_H__ */ diff --git a/katze/katze.h b/katze/katze.h index d38bd99f..eb4e2c40 100644 --- a/katze/katze.h +++ b/katze/katze.h @@ -17,5 +17,6 @@ #include "katze-item.h" #include "katze-list.h" #include "katze-array.h" +#include "katze-arrayaction.h" #endif /* __KATZE_H__ */ diff --git a/midori/midori-browser.c b/midori/midori-browser.c index 0608ed57..aa5acd69 100644 --- a/midori/midori-browser.c +++ b/midori/midori-browser.c @@ -44,9 +44,7 @@ struct _MidoriBrowser GtkActionGroup* action_group; GtkWidget* menubar; - GtkWidget* menu_bookmarks; GtkWidget* menu_tools; - GtkWidget* menu_window; GtkWidget* popup_bookmark; GtkWidget* popup_history; GtkWidget* throbber; @@ -72,12 +70,11 @@ struct _MidoriBrowser GtkWidget* statusbar; GtkWidget* progressbar; - gchar* statusbar_text; - MidoriWebSettings* settings; - KatzeArray* bookmarks; + MidoriWebSettings* settings; KatzeArray* proxy_array; + KatzeArray* bookmarks; KatzeArray* trash; KatzeArray* search_engines; KatzeArray* history; @@ -733,32 +730,19 @@ midori_browser_tab_destroy_cb (GtkWidget* widget, g_signal_emit (browser, signals[REMOVE_TAB], 0, widget); /* We don't ever want to be in a situation with no tabs, - so just create an empty one if the last one is closed. */ - if (!midori_browser_get_current_tab (browser)) + so just create an empty one if the last one is closed. + The only exception is when we are closing the window, + which is indicated by the proxy array having been unset. */ + if (browser->proxy_array && !midori_browser_get_current_tab (browser)) midori_browser_add_uri (browser, ""); return FALSE; } -static void -midori_browser_window_menu_item_activate_cb (GtkWidget* menuitem, - GtkWidget* widget) -{ - MidoriBrowser* browser; - - g_return_if_fail (GTK_IS_WIDGET (widget)); - - browser = MIDORI_BROWSER (gtk_widget_get_toplevel (widget)); - g_return_if_fail (browser); - - midori_browser_set_current_tab (browser, widget); -} - static void _midori_browser_add_tab (MidoriBrowser* browser, GtkWidget* view) { GtkWidget* tab_label; - GtkWidget* menuitem; KatzeItem* item; guint n; @@ -770,14 +754,10 @@ _midori_browser_add_tab (MidoriBrowser* browser, GTK_SHADOW_ETCHED_IN); tab_label = midori_view_get_proxy_tab_label (MIDORI_VIEW (view)); - menuitem = midori_view_get_proxy_menu_item (MIDORI_VIEW (view)); - if (browser->proxy_array) - { - item = midori_view_get_proxy_item (MIDORI_VIEW (view)); - g_object_ref (item); - katze_array_add_item (browser->proxy_array, item); - } + item = midori_view_get_proxy_item (MIDORI_VIEW (view)); + g_object_ref (item); + katze_array_add_item (browser->proxy_array, item); g_object_connect (view, "signal::notify::icon", @@ -828,14 +808,7 @@ _midori_browser_add_tab (MidoriBrowser* browser, view, TRUE); #endif - gtk_widget_show (menuitem); - g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_browser_window_menu_item_activate_cb), view); - gtk_menu_shell_append (GTK_MENU_SHELL (browser->menu_window), menuitem); - /* We want the tab to be removed if the widget is destroyed */ - g_signal_connect_swapped (view, "destroy", - G_CALLBACK (gtk_widget_destroy), menuitem); g_signal_connect (view, "destroy", G_CALLBACK (midori_browser_tab_destroy_cb), browser); @@ -1427,63 +1400,105 @@ midori_browser_navigationbar_notify_style_cb (GObject* object, } static void -midori_browser_menu_trash_item_activate_cb (GtkWidget* menuitem, - MidoriBrowser* browser) +_action_trash_populate_popup (GtkAction* action, + GtkMenu* menu, + MidoriBrowser* browser) { - KatzeItem* item; - gint n; + GtkWidget* menuitem; - /* Create a new web view with an uri which has been closed before */ - item = g_object_get_data (G_OBJECT (menuitem), "KatzeItem"); - n = midori_browser_add_item (browser, item); + menuitem = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + menuitem = sokoke_action_create_popup_menu_item ( + _action_by_name (browser, "TrashEmpty")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); +} + +static void +_action_trash_activate_item (GtkAction* action, + KatzeItem* item, + MidoriBrowser* browser) +{ + gint n = midori_browser_add_item (browser, item); midori_browser_set_current_page (browser, n); katze_array_remove_item (browser->trash, item); _midori_browser_update_actions (browser); } static void -midori_browser_menu_trash_activate_cb (GtkWidget* widget, - MidoriBrowser* browser) +_action_history_populate_popup (GtkAction* action, + GtkMenu* menu, + MidoriBrowser* browser) { - GtkWidget* menu; - guint i, n; - KatzeItem* item; - const gchar* title; - const gchar* uri; - GtkWidget* menuitem; - GtkWidget* icon; - GtkAction* action; + /* Nothing to do */ +} - menu = gtk_menu_new (); - n = katze_array_get_length (browser->trash); +static void +_action_history_activate_item (GtkAction* action, + KatzeItem* item, + MidoriBrowser* browser) +{ + _midori_browser_open_uri (browser, katze_item_get_uri (item)); +} + +static void +_action_bookmarks_populate_popup (GtkAction* action, + GtkMenu* menu, + MidoriBrowser* browser) +{ + GtkWidget* menuitem = gtk_separator_menu_item_new (); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + menuitem = sokoke_action_create_popup_menu_item ( + _action_by_name (browser, "BookmarkAdd")); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); +} + +static void +_action_bookmarks_activate_item (GtkAction* action, + KatzeItem* item, + MidoriBrowser* browser) +{ + gint n = midori_browser_add_item (browser, item); + midori_browser_set_current_page (browser, n); + _midori_browser_update_actions (browser); +} + +static void +_action_window_populate_popup (GtkAction* action, + GtkMenu* menu, + MidoriBrowser* browser) +{ + GtkWidget* menuitem = gtk_separator_menu_item_new (); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + menuitem = sokoke_action_create_popup_menu_item ( + _action_by_name (browser, "TabPrevious")); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + menuitem = sokoke_action_create_popup_menu_item ( + _action_by_name (browser, "TabNext")); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); +} + +static void +_action_window_activate_item (GtkAction* action, + KatzeItem* item, + MidoriBrowser* browser) +{ + guint i, n; + GtkWidget* view; + + n = katze_array_get_length (browser->proxy_array); for (i = 0; i < n; i++) { - item = katze_array_get_nth_item (browser->trash, i); - title = katze_item_get_name (item); - uri = katze_item_get_uri (item); - menuitem = sokoke_image_menu_item_new_ellipsized (title ? title : uri); - /* FIXME: Get the real icon */ - icon = gtk_image_new_from_stock (GTK_STOCK_FILE, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - g_object_set_data (G_OBJECT (menuitem), "KatzeItem", item); - g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_browser_menu_trash_item_activate_cb), browser); - gtk_widget_show (menuitem); + view = gtk_notebook_get_nth_page (GTK_NOTEBOOK (browser->notebook), i); + if (midori_view_get_proxy_item (MIDORI_VIEW (view)) == item) + gtk_notebook_set_current_page (GTK_NOTEBOOK (browser->notebook), i); } - - menuitem = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - gtk_widget_show (menuitem); - action = gtk_action_group_get_action (browser->action_group, "TrashEmpty"); - menuitem = gtk_action_create_menu_item (action); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - gtk_widget_show (menuitem); - if (GTK_IS_MENU_ITEM (widget)) - gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), menu); - else - sokoke_widget_popup (widget, GTK_MENU (menu), NULL, - SOKOKE_MENU_POSITION_RIGHT); } static void @@ -2877,10 +2892,6 @@ static const GtkActionEntry entries[] = { { "OpenInPageholder", GTK_STOCK_JUMP_TO, N_("Open in Page_holder..."), "", N_("Open the current page in the pageholder"), G_CALLBACK (_action_open_in_panel_activate) }, - { "Trash", STOCK_USER_TRASH, - NULL, "", -/* N_("Reopen a previously closed tab or window"), G_CALLBACK (_action_trash_activate) }, */ - N_("Reopen a previously closed tab or window"), NULL }, { "TrashEmpty", GTK_STOCK_CLEAR, N_("Empty Trash"), "", N_("Delete the contents of the trash"), G_CALLBACK (_action_trash_empty_activate) }, @@ -2888,7 +2899,6 @@ static const GtkActionEntry entries[] = { N_("Undo Close Tab"), "t", N_("Open the last closed tab"), G_CALLBACK (_action_undo_tab_close_activate) }, - { "Bookmarks", NULL, N_("_Bookmarks") }, { "BookmarkAdd", STOCK_BOOKMARK_ADD, NULL, "d", N_("Add a new bookmark"), G_CALLBACK (_action_bookmark_add_activate) }, @@ -2925,7 +2935,6 @@ static const GtkActionEntry entries[] = { N_("Add, edit and remove search engines..."), G_CALLBACK (_action_manage_search_engines_activate) }, - { "Window", NULL, N_("_Window") }, { "TabPrevious", GTK_STOCK_GO_BACK, N_("_Previous Tab"), "Page_Up", N_("Switch to the previous tab"), G_CALLBACK (_action_tab_previous_activate) }, @@ -3086,28 +3095,15 @@ static const gchar* ui_markup = "" "" "" - "" - /* Closed tabs shall be prepended here */ - "" - "" - "" - "" - "" - "" - "" - "" - /* Bookmarks shall be appended here */ + "" + /* "" */ "" + "" "" "" /* Panel items shall be appended here */ "" - "" - "" - "" - "" - /* All open tabs shall be appended here */ - "" + "" "" "" "" @@ -3124,7 +3120,7 @@ static const gchar* ui_markup = "" "" "" - "" + "" "" "" "" @@ -3186,6 +3182,7 @@ midori_browser_init (MidoriBrowser* browser) GtkRcStyle* rcstyle; browser->settings = midori_web_settings_new (); + browser->proxy_array = katze_array_new (KATZE_TYPE_ARRAY); browser->bookmarks = NULL; browser->trash = NULL; browser->search_engines = NULL; @@ -3292,6 +3289,70 @@ midori_browser_init (MidoriBrowser* browser) action, "K"); g_object_unref (action); + action = g_object_new (KATZE_TYPE_ARRAY_ACTION, + "name", "Trash", + "stock-id", STOCK_USER_TRASH, + "tooltip", _("Reopen a previously closed tab or window"), + NULL); + g_object_connect (action, + "signal::populate-popup", + _action_trash_populate_popup, browser, + "signal::activate-item", + _action_trash_activate_item, browser, + NULL); + gtk_action_group_add_action_with_accel (browser->action_group, + action, ""); + g_object_unref (action); + + action = g_object_new (KATZE_TYPE_ARRAY_ACTION, + "name", "RecentlyVisited", + "label", _("_Recently visited pages"), + "stock-id", STOCK_HISTORY, + "tooltip", _("Revisit pages that you opened before"), + NULL); + g_object_connect (action, + "signal::populate-popup", + _action_history_populate_popup, browser, + "signal::activate-item", + _action_history_activate_item, browser, + NULL); + gtk_action_group_add_action_with_accel (browser->action_group, + action, ""); + g_object_unref (action); + + action = g_object_new (KATZE_TYPE_ARRAY_ACTION, + "name", "Bookmarks", + "label", _("_Bookmarks"), + "stock-id", STOCK_BOOKMARKS, + "tooltip", _("Reopen a previously closed tab or window"), + NULL); + g_object_connect (action, + "signal::populate-popup", + _action_bookmarks_populate_popup, browser, + "signal::activate-item", + _action_bookmarks_activate_item, browser, + NULL); + gtk_action_group_add_action_with_accel (browser->action_group, + action, ""); + g_object_unref (action); + + action = g_object_new (KATZE_TYPE_ARRAY_ACTION, + "name", "Window", + "label", _("Window"), + "stock-id", GTK_STOCK_INDEX, + "tooltip", _("Show a list of all open tabs"), + "array", browser->proxy_array, + NULL); + g_object_connect (action, + "signal::populate-popup", + _action_window_populate_popup, browser, + "signal::activate-item", + _action_window_activate_item, browser, + NULL); + gtk_action_group_add_action_with_accel (browser->action_group, + action, ""); + g_object_unref (action); + /* Create the menubar */ browser->menubar = gtk_ui_manager_get_widget (ui_manager, "/menubar"); GtkWidget* menuitem = gtk_menu_item_new (); @@ -3303,31 +3364,15 @@ midori_browser_init (MidoriBrowser* browser) gtk_menu_item_set_right_justified (GTK_MENU_ITEM (menuitem), TRUE); gtk_menu_shell_append (GTK_MENU_SHELL (browser->menubar), menuitem); gtk_box_pack_start (GTK_BOX (vbox), browser->menubar, FALSE, FALSE, 0); - menuitem = gtk_ui_manager_get_widget (ui_manager, "/menubar/Go/Trash"); - g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_browser_menu_trash_activate_cb), - browser); - browser->menu_bookmarks = gtk_menu_item_get_submenu (GTK_MENU_ITEM ( - gtk_ui_manager_get_widget (ui_manager, "/menubar/Bookmarks"))); - menuitem = gtk_separator_menu_item_new (); - gtk_widget_show (menuitem); - gtk_menu_shell_append (GTK_MENU_SHELL (browser->menu_bookmarks), menuitem); - browser->popup_bookmark = gtk_ui_manager_get_widget ( - ui_manager, "/popup_bookmark"); - g_object_ref (browser->popup_bookmark); - browser->popup_history = gtk_ui_manager_get_widget ( - ui_manager, "/popup_history"); - g_object_ref (browser->popup_history); + browser->popup_bookmark = g_object_ref (gtk_ui_manager_get_widget ( + ui_manager, "/popup_bookmark")); + browser->popup_history = g_object_ref (gtk_ui_manager_get_widget ( + ui_manager, "/popup_history")); browser->menu_tools = gtk_menu_item_get_submenu (GTK_MENU_ITEM ( gtk_ui_manager_get_widget (ui_manager, "/menubar/Tools"))); menuitem = gtk_separator_menu_item_new (); gtk_widget_show (menuitem); gtk_menu_shell_append (GTK_MENU_SHELL (browser->menu_tools), menuitem); - browser->menu_window = gtk_menu_item_get_submenu (GTK_MENU_ITEM ( - gtk_ui_manager_get_widget (ui_manager, "/menubar/Window"))); - menuitem = gtk_separator_menu_item_new (); - gtk_widget_show (menuitem); - gtk_menu_shell_append (GTK_MENU_SHELL (browser->menu_window), menuitem); gtk_widget_show (browser->menubar); _action_set_sensitive (browser, "PrivateBrowsing", FALSE); @@ -3348,13 +3393,9 @@ midori_browser_init (MidoriBrowser* browser) ui_manager, "/toolbar_navigation/Homepage"); browser->search = gtk_ui_manager_get_widget ( ui_manager, "/toolbar_navigation/Search"); + browser->button_trash = gtk_ui_manager_get_widget ( + ui_manager, "/toolbar_navigation/Trash"); - action = gtk_action_group_get_action (browser->action_group, "Trash"); - browser->button_trash = gtk_action_create_tool_item (action); - g_signal_connect (browser->button_trash, "clicked", - G_CALLBACK (midori_browser_menu_trash_activate_cb), browser); - gtk_toolbar_insert (GTK_TOOLBAR (browser->navigationbar), - GTK_TOOL_ITEM (browser->button_trash), -1); sokoke_container_show_children (GTK_CONTAINER (browser->navigationbar)); gtk_widget_hide (browser->navigationbar); action = gtk_action_group_get_action (browser->action_group, "Fullscreen"); @@ -3637,8 +3678,7 @@ midori_browser_dispose (GObject* object) MidoriBrowser* browser = MIDORI_BROWSER (object); /* We are done, the session mustn't change anymore */ - if (browser->proxy_array) - katze_object_assign (browser->proxy_array, NULL); + katze_object_assign (browser->proxy_array, NULL); G_OBJECT_CLASS (midori_browser_parent_class)->dispose (object); } @@ -3827,8 +3867,6 @@ midori_browser_load_bookmarks (MidoriBrowser* browser) if (!browser->bookmarks) return; - _midori_browser_create_bookmark_menu (browser, browser->bookmarks, - browser->menu_bookmarks); n = katze_array_get_length (browser->bookmarks); for (i = 0; i < n; i++) { @@ -4022,6 +4060,8 @@ midori_browser_set_property (GObject* object, ; /* FIXME: Disconnect handlers */ katze_object_assign (browser->bookmarks, g_value_get_object (value)); g_object_ref (browser->bookmarks); + g_object_set (_action_by_name (browser, "Bookmarks"), "array", + browser->bookmarks, NULL); midori_browser_load_bookmarks (browser); /* FIXME: Connect to updates */ break; @@ -4029,6 +4069,8 @@ midori_browser_set_property (GObject* object, ; /* FIXME: Disconnect handlers */ katze_object_assign (browser->trash, g_value_get_object (value)); g_object_ref (browser->trash); + g_object_set (_action_by_name (browser, "Trash"), "array", + browser->trash, NULL); /* FIXME: Connect to updates */ _midori_browser_update_actions (browser); break; @@ -4052,7 +4094,10 @@ midori_browser_set_property (GObject* object, case PROP_HISTORY: ; /* FIXME: Disconnect handlers */ katze_object_assign (browser->history, g_value_get_object (value)); + g_object_ref (browser->history); midori_browser_load_history (browser); + g_object_set (_action_by_name (browser, "RecentlyVisited"), "array", + browser->history, NULL); /* FIXME: Connect to updates */ break; default: @@ -4358,10 +4403,7 @@ midori_browser_get_current_tab (MidoriBrowser* browser) * Retrieves a proxy array representing the respective proxy items * of the present views that can be used for session management. * - * The folder is created on the first call and will be updated to reflect - * changes to all items automatically. - * - * Note that this implicitly creates proxy items of all views. + * The array is updated automatically. * * Note: Calling this function doesn't add a reference and the browser * may release its reference at some point. @@ -4373,11 +4415,6 @@ midori_browser_get_proxy_array (MidoriBrowser* browser) { g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL); - if (!browser->proxy_array) - { - browser->proxy_array = katze_array_new (KATZE_TYPE_ITEM); - /* FIXME: Fill in items of all present views */ - } return browser->proxy_array; } diff --git a/midori/sokoke.c b/midori/sokoke.c index 4efd01c8..7be3c2b4 100644 --- a/midori/sokoke.c +++ b/midori/sokoke.c @@ -217,88 +217,13 @@ sokoke_container_show_children (GtkContainer* container) gtk_container_foreach (container, (GtkCallback)(gtk_widget_show_all), NULL); } -typedef struct -{ - GtkWidget* widget; - SokokeMenuPos position; -} SokokePopupInfo; - -static void -sokoke_widget_popup_position_menu (GtkMenu* menu, - gint* x, - gint* y, - gboolean* push_in, - gpointer user_data) -{ - gint wx, wy; - gint menu_width; - GtkRequisition menu_req; - GtkRequisition widget_req; - SokokePopupInfo* info = user_data; - GtkWidget* widget = info->widget; - - /* Retrieve size and position of both widget and menu */ - if (GTK_WIDGET_NO_WINDOW (widget)) - { - gdk_window_get_position (widget->window, &wx, &wy); - wx += widget->allocation.x; - wy += widget->allocation.y; - } - else - gdk_window_get_origin (widget->window, &wx, &wy); - gtk_widget_size_request (GTK_WIDGET (menu), &menu_req); - gtk_widget_size_request (widget, &widget_req); - menu_width = menu_req.width; - gint widget_height = widget_req.height; /* Better than allocation.height */ - - /* Calculate menu position */ - if (info->position == SOKOKE_MENU_POSITION_CURSOR) - ; /* Do nothing? */ - else if (info->position == SOKOKE_MENU_POSITION_RIGHT) - { - *x = wx + widget->allocation.width - menu_width; - *y = wy + widget_height; - } else if (info->position == SOKOKE_MENU_POSITION_LEFT) - { - *x = wx; - *y = wy + widget_height; - } - - *push_in = TRUE; -} - - void sokoke_widget_popup (GtkWidget* widget, GtkMenu* menu, GdkEventButton* event, SokokeMenuPos pos) { - int button, event_time; - if (event) - { - button = event->button; - event_time = event->time; - } - else - { - button = 0; - event_time = gtk_get_current_event_time (); - } - - if (!gtk_menu_get_attach_widget (menu)) - gtk_menu_attach_to_widget (menu, widget, NULL); - - - if (widget) - { - SokokePopupInfo info = { widget, pos }; - gtk_menu_popup (menu, NULL, NULL, - sokoke_widget_popup_position_menu, &info, - button, event_time); - } - else - gtk_menu_popup (menu, NULL, NULL, NULL, NULL, button, event_time); + katze_widget_popup (widget, menu, event, (KatzeMenuPos)pos); } typedef enum @@ -704,19 +629,7 @@ sokoke_action_create_popup_menu_item (GtkAction* action) GtkWidget* sokoke_image_menu_item_new_ellipsized (const gchar* label) { - GtkWidget* menuitem; - GtkWidget* label_widget; - - menuitem = gtk_image_menu_item_new (); - label_widget = gtk_label_new (label); - /* FIXME: Should text direction be respected here? */ - gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.0); - gtk_label_set_max_width_chars (GTK_LABEL (label_widget), 50); - gtk_label_set_ellipsize (GTK_LABEL (label_widget), PANGO_ELLIPSIZE_MIDDLE); - gtk_widget_show (label_widget); - gtk_container_add (GTK_CONTAINER (menuitem), label_widget); - - return menuitem; + return katze_image_menu_item_new_ellipsized (label); } /** diff --git a/po/POTFILES.in b/po/POTFILES.in index 61ab1ba7..7552c1a2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -19,3 +19,4 @@ katze/katze-utils.c katze/katze-item.c katze/katze-list.c katze/katze-array.c +katze/katze-arrayaction.c