]> spindle.queued.net Git - midori/commitdiff
Finish refactoring the toolbar to use only actions
authorChristian Dywan <christian@twotoasts.de>
Fri, 10 Oct 2008 20:31:37 +0000 (22:31 +0200)
committerChristian Dywan <christian@twotoasts.de>
Fri, 10 Oct 2008 20:31:37 +0000 (22:31 +0200)
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
katze/katze-arrayaction.c [new file with mode: 0644]
katze/katze-arrayaction.h [new file with mode: 0644]
katze/katze-utils.c
katze/katze-utils.h
katze/katze.h
midori/midori-browser.c
midori/sokoke.c
po/POTFILES.in

index 8e6caa71c91c4c634fd409a3a78a78d487344c6e..f357f6a558270348ba1f7a78f00867d7bec3d44b 100644 (file)
@@ -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 (file)
index 0000000..a47f4f9
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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 <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+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 (file)
index 0000000..b4e9ee2
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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__ */
index 061e7c3d396f696b900feccef4228a9ffcef2487..af2d3857b4079044b5a117044eae100041b1ce1b 100644 (file)
@@ -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;
+}
index 6ff7b8634e40173dc43dbe835e851d5307de47a1..52ac45a8f90f4e92244cfd95f6840797f696a2c8 100644 (file)
@@ -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__ */
index d38bd99fa65eb9e3f20638bf0a67eabc5a6ebae2..eb4e2c40029e440852f5bebad85c5e64824b4e06 100644 (file)
@@ -17,5 +17,6 @@
 #include "katze-item.h"
 #include "katze-list.h"
 #include "katze-array.h"
+#include "katze-arrayaction.h"
 
 #endif /* __KATZE_H__ */
index 0608ed577c1d33a91182d603f6042c8b6a8fd48d..aa5acd69ce29285cc3d4db99dc0547cbe90145bb 100644 (file)
@@ -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)
+{
+    /* Nothing to do */
+}
+
+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)
 {
-    GtkWidget* menu;
     guint i, n;
-    KatzeItem* item;
-    const gchar* title;
-    const gchar* uri;
-    GtkWidget* menuitem;
-    GtkWidget* icon;
-    GtkAction* action;
+    GtkWidget* view;
 
-    menu = gtk_menu_new ();
-    n = katze_array_get_length (browser->trash);
+    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"), "<Ctrl><Shift>t",
    N_("Open the last closed tab"), G_CALLBACK (_action_undo_tab_close_activate) },
 
- { "Bookmarks", NULL, N_("_Bookmarks") },
  { "BookmarkAdd", STOCK_BOOKMARK_ADD,
    NULL, "<Ctrl>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"), "<Ctrl>Page_Up",
    N_("Switch to the previous tab"), G_CALLBACK (_action_tab_previous_activate) },
@@ -3086,28 +3095,15 @@ static const gchar* ui_markup =
     "<menuitem action='Location'/>"
     "<menuitem action='Search'/>"
     "<menuitem action='OpenInPageholder'/>"
-    "<menu action='Trash'>"
-    /* Closed tabs shall be prepended here */
-     "<separator/>"
-     "<menuitem action='TrashEmpty'/>"
-    "</menu>"
-    "<menuitem action='UndoTabClose'/>"
-   "</menu>"
-   "<menu action='Bookmarks'>"
-    "<menuitem action='BookmarkAdd'/>"
-    "<separator/>"
-    /* Bookmarks shall be appended here */
+    "<menuitem action='Trash'/>"
+    /* "<menuitem action='RecentlyVisited'/>" */
    "</menu>"
+   "<menuitem action='Bookmarks'/>"
    "<menu action='Tools'>"
     "<menuitem action='ManageSearchEngines'/>"
     /* Panel items shall be appended here */
    "</menu>"
-   "<menu action='Window'>"
-    "<menuitem action='TabPrevious'/>"
-    "<menuitem action='TabNext'/>"
-    "<separator/>"
-    /* All open tabs shall be appended here */
-   "</menu>"
+   "<menuitem action='Window'/>"
    "<menu action='Help'>"
     "<menuitem action='HelpContents'/>"
     "<menuitem action='HelpFAQ'/>"
@@ -3124,7 +3120,7 @@ static const gchar* ui_markup =
    "<toolitem action='Homepage'/>"
    "<toolitem action='Location'/>"
    "<toolitem action='Search'/>"
-   "<placeholder name='Trash'/>"
+   "<toolitem action='Trash'/>"
   "</toolbar>"
   "<toolbar name='toolbar_bookmarks'>"
    "<toolitem action='BookmarkAdd'/>"
@@ -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, "<Ctrl>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;
 }
 
index 4efd01c8879fb2e31f229dc137f60fe859c02553..7be3c2b4a72b78494497ac29288adef4af89b855 100644 (file)
@@ -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);
 }
 
 /**
index 61ab1ba730785c5110abe9d2f5683593a80253e2..7552c1a2bd33944c511f7bf1d9c4ef3e37d6b9f3 100644 (file)
@@ -19,3 +19,4 @@ katze/katze-utils.c
 katze/katze-item.c
 katze/katze-list.c
 katze/katze-array.c
+katze/katze-arrayaction.c