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.
This commit is contained in:
Christian Dywan 2008-10-10 22:31:37 +02:00
parent 16e47a6a1f
commit e1b828edf2
9 changed files with 732 additions and 233 deletions

View file

@ -16,4 +16,5 @@ libkatze_la_SOURCES = \
katze-utils.c katze-utils.h \ katze-utils.c katze-utils.h \
katze-item.c katze-item.h \ katze-item.c katze-item.h \
katze-list.c katze-list.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

361
katze/katze-arrayaction.c Normal file
View file

@ -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)));
}

47
katze/katze-arrayaction.h Normal file
View file

@ -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__ */

View file

@ -328,3 +328,126 @@ katze_property_label (gpointer object,
return widget; 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;
}

View file

@ -63,6 +63,21 @@ GtkWidget*
katze_property_label (gpointer object, katze_property_label (gpointer object,
const gchar* property); 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 G_END_DECLS
#endif /* __KATZE_UTILS_H__ */ #endif /* __KATZE_UTILS_H__ */

View file

@ -17,5 +17,6 @@
#include "katze-item.h" #include "katze-item.h"
#include "katze-list.h" #include "katze-list.h"
#include "katze-array.h" #include "katze-array.h"
#include "katze-arrayaction.h"
#endif /* __KATZE_H__ */ #endif /* __KATZE_H__ */

View file

@ -44,9 +44,7 @@ struct _MidoriBrowser
GtkActionGroup* action_group; GtkActionGroup* action_group;
GtkWidget* menubar; GtkWidget* menubar;
GtkWidget* menu_bookmarks;
GtkWidget* menu_tools; GtkWidget* menu_tools;
GtkWidget* menu_window;
GtkWidget* popup_bookmark; GtkWidget* popup_bookmark;
GtkWidget* popup_history; GtkWidget* popup_history;
GtkWidget* throbber; GtkWidget* throbber;
@ -72,12 +70,11 @@ struct _MidoriBrowser
GtkWidget* statusbar; GtkWidget* statusbar;
GtkWidget* progressbar; GtkWidget* progressbar;
gchar* statusbar_text; gchar* statusbar_text;
MidoriWebSettings* settings;
KatzeArray* bookmarks;
MidoriWebSettings* settings;
KatzeArray* proxy_array; KatzeArray* proxy_array;
KatzeArray* bookmarks;
KatzeArray* trash; KatzeArray* trash;
KatzeArray* search_engines; KatzeArray* search_engines;
KatzeArray* history; KatzeArray* history;
@ -733,32 +730,19 @@ midori_browser_tab_destroy_cb (GtkWidget* widget,
g_signal_emit (browser, signals[REMOVE_TAB], 0, widget); g_signal_emit (browser, signals[REMOVE_TAB], 0, widget);
/* We don't ever want to be in a situation with no tabs, /* 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. */ so just create an empty one if the last one is closed.
if (!midori_browser_get_current_tab (browser)) 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, ""); midori_browser_add_uri (browser, "");
return FALSE; 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 static void
_midori_browser_add_tab (MidoriBrowser* browser, _midori_browser_add_tab (MidoriBrowser* browser,
GtkWidget* view) GtkWidget* view)
{ {
GtkWidget* tab_label; GtkWidget* tab_label;
GtkWidget* menuitem;
KatzeItem* item; KatzeItem* item;
guint n; guint n;
@ -770,14 +754,10 @@ _midori_browser_add_tab (MidoriBrowser* browser,
GTK_SHADOW_ETCHED_IN); GTK_SHADOW_ETCHED_IN);
tab_label = midori_view_get_proxy_tab_label (MIDORI_VIEW (view)); 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)); item = midori_view_get_proxy_item (MIDORI_VIEW (view));
g_object_ref (item); g_object_ref (item);
katze_array_add_item (browser->proxy_array, item); katze_array_add_item (browser->proxy_array, item);
}
g_object_connect (view, g_object_connect (view,
"signal::notify::icon", "signal::notify::icon",
@ -828,14 +808,7 @@ _midori_browser_add_tab (MidoriBrowser* browser,
view, TRUE); view, TRUE);
#endif #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 */ /* 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_signal_connect (view, "destroy",
G_CALLBACK (midori_browser_tab_destroy_cb), browser); G_CALLBACK (midori_browser_tab_destroy_cb), browser);
@ -1427,63 +1400,105 @@ midori_browser_navigationbar_notify_style_cb (GObject* object,
} }
static void static void
midori_browser_menu_trash_item_activate_cb (GtkWidget* menuitem, _action_trash_populate_popup (GtkAction* action,
GtkMenu* menu,
MidoriBrowser* browser) MidoriBrowser* browser)
{ {
KatzeItem* item; GtkWidget* menuitem;
gint n;
/* Create a new web view with an uri which has been closed before */ menuitem = gtk_separator_menu_item_new ();
item = g_object_get_data (G_OBJECT (menuitem), "KatzeItem"); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
n = midori_browser_add_item (browser, item); 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); midori_browser_set_current_page (browser, n);
katze_array_remove_item (browser->trash, item); katze_array_remove_item (browser->trash, item);
_midori_browser_update_actions (browser); _midori_browser_update_actions (browser);
} }
static void static void
midori_browser_menu_trash_activate_cb (GtkWidget* widget, _action_history_populate_popup (GtkAction* action,
GtkMenu* menu,
MidoriBrowser* browser) MidoriBrowser* browser)
{ {
GtkWidget* menu; /* Nothing to do */
guint i, n; }
KatzeItem* item;
const gchar* title;
const gchar* uri;
GtkWidget* menuitem;
GtkWidget* icon;
GtkAction* action;
menu = gtk_menu_new (); static void
n = katze_array_get_length (browser->trash); _action_history_activate_item (GtkAction* action,
for (i = 0; i < n; i++) KatzeItem* item,
MidoriBrowser* browser)
{ {
item = katze_array_get_nth_item (browser->trash, i); _midori_browser_open_uri (browser, katze_item_get_uri (item));
title = katze_item_get_name (item); }
uri = katze_item_get_uri (item);
menuitem = sokoke_image_menu_item_new_ellipsized (title ? title : uri); static void
/* FIXME: Get the real icon */ _action_bookmarks_populate_popup (GtkAction* action,
icon = gtk_image_new_from_stock (GTK_STOCK_FILE, GTK_ICON_SIZE_MENU); GtkMenu* menu,
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); MidoriBrowser* browser)
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); {
g_object_set_data (G_OBJECT (menuitem), "KatzeItem", item); GtkWidget* menuitem = gtk_separator_menu_item_new ();
g_signal_connect (menuitem, "activate", gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menuitem);
G_CALLBACK (midori_browser_menu_trash_item_activate_cb), browser); 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); gtk_widget_show (menuitem);
} }
menuitem = gtk_separator_menu_item_new (); static void
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); _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); gtk_widget_show (menuitem);
action = gtk_action_group_get_action (browser->action_group, "TrashEmpty"); menuitem = sokoke_action_create_popup_menu_item (
menuitem = gtk_action_create_menu_item (action); _action_by_name (browser, "TabPrevious"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem); gtk_widget_show (menuitem);
if (GTK_IS_MENU_ITEM (widget)) menuitem = sokoke_action_create_popup_menu_item (
gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), menu); _action_by_name (browser, "TabNext"));
else gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menuitem);
sokoke_widget_popup (widget, GTK_MENU (menu), NULL, gtk_widget_show (menuitem);
SOKOKE_MENU_POSITION_RIGHT); }
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++)
{
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);
}
} }
static void static void
@ -2877,10 +2892,6 @@ static const GtkActionEntry entries[] = {
{ "OpenInPageholder", GTK_STOCK_JUMP_TO, { "OpenInPageholder", GTK_STOCK_JUMP_TO,
N_("Open in Page_holder..."), "", N_("Open in Page_holder..."), "",
N_("Open the current page in the pageholder"), G_CALLBACK (_action_open_in_panel_activate) }, 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, { "TrashEmpty", GTK_STOCK_CLEAR,
N_("Empty Trash"), "", N_("Empty Trash"), "",
N_("Delete the contents of the trash"), G_CALLBACK (_action_trash_empty_activate) }, 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_("Undo Close Tab"), "<Ctrl><Shift>t",
N_("Open the last closed tab"), G_CALLBACK (_action_undo_tab_close_activate) }, N_("Open the last closed tab"), G_CALLBACK (_action_undo_tab_close_activate) },
{ "Bookmarks", NULL, N_("_Bookmarks") },
{ "BookmarkAdd", STOCK_BOOKMARK_ADD, { "BookmarkAdd", STOCK_BOOKMARK_ADD,
NULL, "<Ctrl>d", NULL, "<Ctrl>d",
N_("Add a new bookmark"), G_CALLBACK (_action_bookmark_add_activate) }, 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..."), N_("Add, edit and remove search engines..."),
G_CALLBACK (_action_manage_search_engines_activate) }, G_CALLBACK (_action_manage_search_engines_activate) },
{ "Window", NULL, N_("_Window") },
{ "TabPrevious", GTK_STOCK_GO_BACK, { "TabPrevious", GTK_STOCK_GO_BACK,
N_("_Previous Tab"), "<Ctrl>Page_Up", N_("_Previous Tab"), "<Ctrl>Page_Up",
N_("Switch to the previous tab"), G_CALLBACK (_action_tab_previous_activate) }, 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='Location'/>"
"<menuitem action='Search'/>" "<menuitem action='Search'/>"
"<menuitem action='OpenInPageholder'/>" "<menuitem action='OpenInPageholder'/>"
"<menu action='Trash'>" "<menuitem action='Trash'/>"
/* Closed tabs shall be prepended here */ /* "<menuitem action='RecentlyVisited'/>" */
"<separator/>"
"<menuitem action='TrashEmpty'/>"
"</menu>"
"<menuitem action='UndoTabClose'/>"
"</menu>"
"<menu action='Bookmarks'>"
"<menuitem action='BookmarkAdd'/>"
"<separator/>"
/* Bookmarks shall be appended here */
"</menu>" "</menu>"
"<menuitem action='Bookmarks'/>"
"<menu action='Tools'>" "<menu action='Tools'>"
"<menuitem action='ManageSearchEngines'/>" "<menuitem action='ManageSearchEngines'/>"
/* Panel items shall be appended here */ /* Panel items shall be appended here */
"</menu>" "</menu>"
"<menu action='Window'>" "<menuitem action='Window'/>"
"<menuitem action='TabPrevious'/>"
"<menuitem action='TabNext'/>"
"<separator/>"
/* All open tabs shall be appended here */
"</menu>"
"<menu action='Help'>" "<menu action='Help'>"
"<menuitem action='HelpContents'/>" "<menuitem action='HelpContents'/>"
"<menuitem action='HelpFAQ'/>" "<menuitem action='HelpFAQ'/>"
@ -3124,7 +3120,7 @@ static const gchar* ui_markup =
"<toolitem action='Homepage'/>" "<toolitem action='Homepage'/>"
"<toolitem action='Location'/>" "<toolitem action='Location'/>"
"<toolitem action='Search'/>" "<toolitem action='Search'/>"
"<placeholder name='Trash'/>" "<toolitem action='Trash'/>"
"</toolbar>" "</toolbar>"
"<toolbar name='toolbar_bookmarks'>" "<toolbar name='toolbar_bookmarks'>"
"<toolitem action='BookmarkAdd'/>" "<toolitem action='BookmarkAdd'/>"
@ -3186,6 +3182,7 @@ midori_browser_init (MidoriBrowser* browser)
GtkRcStyle* rcstyle; GtkRcStyle* rcstyle;
browser->settings = midori_web_settings_new (); browser->settings = midori_web_settings_new ();
browser->proxy_array = katze_array_new (KATZE_TYPE_ARRAY);
browser->bookmarks = NULL; browser->bookmarks = NULL;
browser->trash = NULL; browser->trash = NULL;
browser->search_engines = NULL; browser->search_engines = NULL;
@ -3292,6 +3289,70 @@ midori_browser_init (MidoriBrowser* browser)
action, "<Ctrl>K"); action, "<Ctrl>K");
g_object_unref (action); 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 */ /* Create the menubar */
browser->menubar = gtk_ui_manager_get_widget (ui_manager, "/menubar"); browser->menubar = gtk_ui_manager_get_widget (ui_manager, "/menubar");
GtkWidget* menuitem = gtk_menu_item_new (); 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_item_set_right_justified (GTK_MENU_ITEM (menuitem), TRUE);
gtk_menu_shell_append (GTK_MENU_SHELL (browser->menubar), menuitem); gtk_menu_shell_append (GTK_MENU_SHELL (browser->menubar), menuitem);
gtk_box_pack_start (GTK_BOX (vbox), browser->menubar, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), browser->menubar, FALSE, FALSE, 0);
menuitem = gtk_ui_manager_get_widget (ui_manager, "/menubar/Go/Trash"); browser->popup_bookmark = g_object_ref (gtk_ui_manager_get_widget (
g_signal_connect (menuitem, "activate", ui_manager, "/popup_bookmark"));
G_CALLBACK (midori_browser_menu_trash_activate_cb), browser->popup_history = g_object_ref (gtk_ui_manager_get_widget (
browser); ui_manager, "/popup_history"));
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->menu_tools = gtk_menu_item_get_submenu (GTK_MENU_ITEM ( browser->menu_tools = gtk_menu_item_get_submenu (GTK_MENU_ITEM (
gtk_ui_manager_get_widget (ui_manager, "/menubar/Tools"))); gtk_ui_manager_get_widget (ui_manager, "/menubar/Tools")));
menuitem = gtk_separator_menu_item_new (); menuitem = gtk_separator_menu_item_new ();
gtk_widget_show (menuitem); gtk_widget_show (menuitem);
gtk_menu_shell_append (GTK_MENU_SHELL (browser->menu_tools), 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); gtk_widget_show (browser->menubar);
_action_set_sensitive (browser, "PrivateBrowsing", FALSE); _action_set_sensitive (browser, "PrivateBrowsing", FALSE);
@ -3348,13 +3393,9 @@ midori_browser_init (MidoriBrowser* browser)
ui_manager, "/toolbar_navigation/Homepage"); ui_manager, "/toolbar_navigation/Homepage");
browser->search = gtk_ui_manager_get_widget ( browser->search = gtk_ui_manager_get_widget (
ui_manager, "/toolbar_navigation/Search"); 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)); sokoke_container_show_children (GTK_CONTAINER (browser->navigationbar));
gtk_widget_hide (browser->navigationbar); gtk_widget_hide (browser->navigationbar);
action = gtk_action_group_get_action (browser->action_group, "Fullscreen"); action = gtk_action_group_get_action (browser->action_group, "Fullscreen");
@ -3637,7 +3678,6 @@ midori_browser_dispose (GObject* object)
MidoriBrowser* browser = MIDORI_BROWSER (object); MidoriBrowser* browser = MIDORI_BROWSER (object);
/* We are done, the session mustn't change anymore */ /* 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); G_OBJECT_CLASS (midori_browser_parent_class)->dispose (object);
@ -3827,8 +3867,6 @@ midori_browser_load_bookmarks (MidoriBrowser* browser)
if (!browser->bookmarks) if (!browser->bookmarks)
return; return;
_midori_browser_create_bookmark_menu (browser, browser->bookmarks,
browser->menu_bookmarks);
n = katze_array_get_length (browser->bookmarks); n = katze_array_get_length (browser->bookmarks);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
@ -4022,6 +4060,8 @@ midori_browser_set_property (GObject* object,
; /* FIXME: Disconnect handlers */ ; /* FIXME: Disconnect handlers */
katze_object_assign (browser->bookmarks, g_value_get_object (value)); katze_object_assign (browser->bookmarks, g_value_get_object (value));
g_object_ref (browser->bookmarks); g_object_ref (browser->bookmarks);
g_object_set (_action_by_name (browser, "Bookmarks"), "array",
browser->bookmarks, NULL);
midori_browser_load_bookmarks (browser); midori_browser_load_bookmarks (browser);
/* FIXME: Connect to updates */ /* FIXME: Connect to updates */
break; break;
@ -4029,6 +4069,8 @@ midori_browser_set_property (GObject* object,
; /* FIXME: Disconnect handlers */ ; /* FIXME: Disconnect handlers */
katze_object_assign (browser->trash, g_value_get_object (value)); katze_object_assign (browser->trash, g_value_get_object (value));
g_object_ref (browser->trash); g_object_ref (browser->trash);
g_object_set (_action_by_name (browser, "Trash"), "array",
browser->trash, NULL);
/* FIXME: Connect to updates */ /* FIXME: Connect to updates */
_midori_browser_update_actions (browser); _midori_browser_update_actions (browser);
break; break;
@ -4052,7 +4094,10 @@ midori_browser_set_property (GObject* object,
case PROP_HISTORY: case PROP_HISTORY:
; /* FIXME: Disconnect handlers */ ; /* FIXME: Disconnect handlers */
katze_object_assign (browser->history, g_value_get_object (value)); katze_object_assign (browser->history, g_value_get_object (value));
g_object_ref (browser->history);
midori_browser_load_history (browser); midori_browser_load_history (browser);
g_object_set (_action_by_name (browser, "RecentlyVisited"), "array",
browser->history, NULL);
/* FIXME: Connect to updates */ /* FIXME: Connect to updates */
break; break;
default: default:
@ -4358,10 +4403,7 @@ midori_browser_get_current_tab (MidoriBrowser* browser)
* Retrieves a proxy array representing the respective proxy items * Retrieves a proxy array representing the respective proxy items
* of the present views that can be used for session management. * 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 * The array is updated automatically.
* changes to all items automatically.
*
* Note that this implicitly creates proxy items of all views.
* *
* Note: Calling this function doesn't add a reference and the browser * Note: Calling this function doesn't add a reference and the browser
* may release its reference at some point. * 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); 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; return browser->proxy_array;
} }

View file

@ -217,88 +217,13 @@ sokoke_container_show_children (GtkContainer* container)
gtk_container_foreach (container, (GtkCallback)(gtk_widget_show_all), NULL); 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 void
sokoke_widget_popup (GtkWidget* widget, sokoke_widget_popup (GtkWidget* widget,
GtkMenu* menu, GtkMenu* menu,
GdkEventButton* event, GdkEventButton* event,
SokokeMenuPos pos) SokokeMenuPos pos)
{ {
int button, event_time; katze_widget_popup (widget, menu, event, (KatzeMenuPos)pos);
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);
} }
typedef enum typedef enum
@ -704,19 +629,7 @@ sokoke_action_create_popup_menu_item (GtkAction* action)
GtkWidget* GtkWidget*
sokoke_image_menu_item_new_ellipsized (const gchar* label) sokoke_image_menu_item_new_ellipsized (const gchar* label)
{ {
GtkWidget* menuitem; return katze_image_menu_item_new_ellipsized (label);
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;
} }
/** /**

View file

@ -19,3 +19,4 @@ katze/katze-utils.c
katze/katze-item.c katze/katze-item.c
katze/katze-list.c katze/katze-list.c
katze/katze-array.c katze/katze-array.c
katze/katze-arrayaction.c