aboutsummaryrefslogtreecommitdiffstats
path: root/src/ephy-navigation-history-action.c
diff options
context:
space:
mode:
authorDiego Escalante Urrelo <diegoe@igalia.com>2012-03-08 07:04:43 +0800
committerXan Lopez <xan@igalia.com>2012-05-02 04:51:58 +0800
commita166462bcaf8211416c3e19a421c0ae5279e1b9f (patch)
tree7a78498e31ae43368ea139742a2059f4c9d6197f /src/ephy-navigation-history-action.c
parentafc5412ee87d1bf9bae16ff1c2b6ea7e3043d1e2 (diff)
downloadgsoc2013-epiphany-a166462bcaf8211416c3e19a421c0ae5279e1b9f.tar
gsoc2013-epiphany-a166462bcaf8211416c3e19a421c0ae5279e1b9f.tar.gz
gsoc2013-epiphany-a166462bcaf8211416c3e19a421c0ae5279e1b9f.tar.bz2
gsoc2013-epiphany-a166462bcaf8211416c3e19a421c0ae5279e1b9f.tar.lz
gsoc2013-epiphany-a166462bcaf8211416c3e19a421c0ae5279e1b9f.tar.xz
gsoc2013-epiphany-a166462bcaf8211416c3e19a421c0ae5279e1b9f.tar.zst
gsoc2013-epiphany-a166462bcaf8211416c3e19a421c0ae5279e1b9f.zip
ephy-navigation-history-action: restore menus
In ebbb1c48197f53b98575b0cb4f6d9fa1e4535abc back/forward drop-downs were removed. This commit brings them back, using the removed code with minor updates. https://bugzilla.gnome.org/show_bug.cgi?id=671609
Diffstat (limited to 'src/ephy-navigation-history-action.c')
-rw-r--r--src/ephy-navigation-history-action.c396
1 files changed, 396 insertions, 0 deletions
diff --git a/src/ephy-navigation-history-action.c b/src/ephy-navigation-history-action.c
index f0f0a5e48..bbf6c72b3 100644
--- a/src/ephy-navigation-history-action.c
+++ b/src/ephy-navigation-history-action.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* Copyright © 2003, 2004 Marco Pesenti Gritti
* Copyright © 2003, 2004 Christian Persch
@@ -26,6 +27,7 @@
#include "ephy-action-helper.h"
#include "ephy-debug.h"
#include "ephy-embed-container.h"
+#include "ephy-embed-prefs.h"
#include "ephy-embed-shell.h"
#include "ephy-embed-utils.h"
#include "ephy-gui.h"
@@ -46,6 +48,7 @@
struct _EphyNavigationHistoryActionPrivate {
EphyNavigationHistoryDirection direction;
EphyHistoryService *history;
+ guint menu_timeout;
};
enum {
@@ -53,6 +56,15 @@ enum {
PROP_DIRECTION
};
+#define MAX_LABEL_LENGTH 48
+#define HISTORY_ITEM_DATA_KEY "history-item-data-key"
+
+typedef enum {
+ WEBKIT_HISTORY_BACKWARD,
+ WEBKIT_HISTORY_FORWARD
+} WebKitHistoryType;
+
+
static void ephy_navigation_history_action_init (EphyNavigationHistoryAction *action);
static void ephy_navigation_history_action_class_init (EphyNavigationHistoryActionClass *klass);
@@ -132,6 +144,8 @@ ephy_navigation_history_action_init (EphyNavigationHistoryAction *action)
action->priv->history = EPHY_HISTORY_SERVICE (ephy_embed_shell_get_global_history_service (embed_shell));
+ action->priv->menu_timeout = 0;
+
g_signal_connect (action->priv->history,
"cleared", G_CALLBACK (ephy_history_cleared_cb),
action);
@@ -142,6 +156,9 @@ ephy_navigation_history_action_finalize (GObject *object)
{
EphyNavigationHistoryAction *action = EPHY_NAVIGATION_HISTORY_ACTION (object);
+ if (action->priv->menu_timeout > 0)
+ g_source_remove (action->priv->menu_timeout);
+
g_signal_handlers_disconnect_by_func (action->priv->history,
ephy_history_cleared_cb,
action);
@@ -185,6 +202,383 @@ ephy_navigation_history_action_get_property (GObject *object,
}
}
+static gboolean
+item_enter_notify_event_cb (GtkWidget *widget,
+ GdkEvent *event,
+ EphyWebView *view)
+{
+ char *text;
+
+ text = g_object_get_data (G_OBJECT (widget), "link-message");
+ ephy_web_view_set_link_message (view, g_strdup (text));
+ g_object_set_data (G_OBJECT (widget), "link-message", text);
+
+ return FALSE;
+}
+
+static gboolean
+item_leave_notify_event_cb (GtkWidget *widget,
+ GdkEvent *event,
+ EphyWebView *view)
+{
+ ephy_web_view_set_link_message (view, NULL);
+ return FALSE;
+}
+
+static void
+icon_loaded_cb (GObject *source,
+ GAsyncResult *result,
+ GtkImageMenuItem *item)
+{
+ WebKitFaviconDatabase* database;
+ GdkPixbuf *favicon;
+
+ database = webkit_get_favicon_database ();
+ favicon = webkit_favicon_database_get_favicon_pixbuf_finish (database, result, NULL);
+
+ if (favicon) {
+ GtkWidget *image;
+
+ image = gtk_image_new_from_pixbuf (favicon);
+ gtk_image_menu_item_set_image (item, image);
+ gtk_image_menu_item_set_always_show_image (item, TRUE);
+
+ g_object_unref (favicon);
+ }
+}
+
+static GtkWidget *
+new_history_menu_item (EphyWebView *view,
+ const char *origtext,
+ const char *address)
+{
+ GtkWidget *item;
+ GtkLabel *label;
+ WebKitFaviconDatabase* database;
+ GdkPixbuf *favicon;
+
+ g_return_val_if_fail (address != NULL && origtext != NULL, NULL);
+
+ item = gtk_image_menu_item_new_with_label (origtext);
+
+ label = GTK_LABEL (gtk_bin_get_child (GTK_BIN (item)));
+ gtk_label_set_ellipsize (label, PANGO_ELLIPSIZE_END);
+ gtk_label_set_max_width_chars (label, MAX_LABEL_LENGTH);
+
+ database = webkit_get_favicon_database ();
+ favicon = webkit_favicon_database_try_get_favicon_pixbuf (database, address,
+ FAVICON_SIZE, FAVICON_SIZE);
+
+ if (favicon) {
+ GtkWidget *image;
+
+ image = gtk_image_new_from_pixbuf (favicon);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (item), TRUE);
+
+ g_object_unref (favicon);
+ } else {
+ webkit_favicon_database_get_favicon_pixbuf (database, address,
+ FAVICON_SIZE, FAVICON_SIZE, NULL,
+ (GAsyncReadyCallback) icon_loaded_cb,
+ GTK_IMAGE_MENU_ITEM (item));
+ }
+
+ g_object_set_data (G_OBJECT (item), "link-message", g_strdup (address));
+
+ g_signal_connect (item, "enter-notify-event",
+ G_CALLBACK (item_enter_notify_event_cb), view);
+ g_signal_connect (item, "leave-notify-event",
+ G_CALLBACK (item_leave_notify_event_cb), view);
+
+ gtk_widget_show (item);
+
+ return item;
+}
+
+static void
+set_new_back_history (EphyEmbed *source,
+ EphyEmbed *dest,
+ gint offset)
+{
+ WebKitWebView *source_view, *dest_view;
+ WebKitWebBackForwardList* source_list, *dest_list;
+ WebKitWebHistoryItem *item;
+ GList *items;
+ guint limit;
+ guint i;
+
+ source_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (source);
+ dest_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (dest);
+
+ source_list = webkit_web_view_get_back_forward_list (source_view);
+ dest_list = webkit_web_view_get_back_forward_list (dest_view);
+
+ if (offset >= 0) {
+ /* Copy the whole back history in this case (positive offset) */
+ ephy_web_view_copy_back_history (ephy_embed_get_web_view (source),
+ ephy_embed_get_web_view (dest));
+
+ items = webkit_web_back_forward_list_get_forward_list_with_limit (source_list,
+ EPHY_WEBKIT_BACK_FORWARD_LIMIT);
+ limit = offset - 1;
+ } else {
+ items = webkit_web_back_forward_list_get_back_list_with_limit (source_list,
+ EPHY_WEBKIT_BACK_FORWARD_LIMIT);
+ limit = g_list_length (items) + offset;
+ }
+
+ /* Add the remaining items to the BackForward list */
+ items = g_list_reverse (items);
+ for (i = 0; i < limit; i++) {
+ item = webkit_web_history_item_copy ((WebKitWebHistoryItem *) items->data);
+ webkit_web_back_forward_list_add_item (dest_list, item);
+ g_object_unref (item);
+
+ items = items->next;
+ }
+ g_list_free (items);
+}
+
+static void
+middle_click_handle_on_history_menu_item (EphyNavigationHistoryAction *action,
+ EphyEmbed *embed,
+ WebKitWebHistoryItem *item)
+{
+ EphyEmbed *new_embed = NULL;
+ WebKitWebView *web_view;
+ WebKitWebBackForwardList *history;
+ GList *list;
+ const gchar *url;
+ guint current;
+ gint offset;
+
+ web_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed);
+
+ /* Save old history and item's offset from current */
+ history = webkit_web_view_get_back_forward_list (web_view);
+ if (action->priv->direction == EPHY_NAVIGATION_HISTORY_DIRECTION_BACK) {
+ list = webkit_web_back_forward_list_get_back_list_with_limit (history,
+ EPHY_WEBKIT_BACK_FORWARD_LIMIT);
+ current = -1;
+ } else {
+ list = webkit_web_back_forward_list_get_forward_list_with_limit (history,
+ EPHY_WEBKIT_BACK_FORWARD_LIMIT);
+ current = g_list_length (list);
+ }
+ offset = current - g_list_index (list, item);
+
+ new_embed = ephy_shell_new_tab (ephy_shell_get_default (),
+ EPHY_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (embed))),
+ embed,
+ NULL,
+ EPHY_NEW_TAB_IN_EXISTING_WINDOW |
+ EPHY_NEW_TAB_DONT_COPY_HISTORY);
+ g_return_if_fail (new_embed != NULL);
+
+ /* We manually set the back history instead of trusting
+ ephy_shell_new_tab because the logic is more complex than
+ usual, due to handling also the forward history */
+ set_new_back_history (embed, new_embed, offset);
+
+ /* Load the new URL */
+ url = webkit_web_history_item_get_original_uri (item);
+ ephy_web_view_load_url (ephy_embed_get_web_view (new_embed), url);
+}
+
+static void
+activate_menu_item_cb (GtkWidget *menuitem,
+ EphyNavigationHistoryAction *action)
+{
+ WebKitWebHistoryItem *item;
+ EphyWindow *window;
+ EphyEmbed *embed;
+
+ window = ephy_window_action_get_window (EPHY_WINDOW_ACTION (action));
+ embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
+ g_return_if_fail (embed != NULL);
+
+ item = (WebKitWebHistoryItem *) g_object_get_data (G_OBJECT (menuitem), HISTORY_ITEM_DATA_KEY);
+ g_return_if_fail (item != NULL);
+
+ if (ephy_gui_is_middle_click ())
+ middle_click_handle_on_history_menu_item (action, embed, item);
+ else {
+ WebKitWebView *web_view;
+
+ web_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed);
+ webkit_web_view_go_to_back_forward_item (web_view, item);
+ }
+}
+static GList*
+webkit_construct_history_list (WebKitWebView *web_view,
+ WebKitHistoryType hist_type,
+ int limit)
+{
+ WebKitWebBackForwardList *web_back_forward_list;
+ GList *webkit_items;
+
+ web_back_forward_list = webkit_web_view_get_back_forward_list (web_view);
+
+ if (hist_type == WEBKIT_HISTORY_FORWARD)
+ webkit_items = g_list_reverse (webkit_web_back_forward_list_get_forward_list_with_limit (web_back_forward_list,
+ limit));
+ else
+ webkit_items = webkit_web_back_forward_list_get_back_list_with_limit (web_back_forward_list,
+ limit);
+
+ return webkit_items;
+}
+
+static GtkWidget *
+build_dropdown_menu (EphyNavigationHistoryAction *action)
+{
+ EphyWindow *window;
+ GtkMenuShell *menu;
+ EphyEmbed *embed;
+ GList *list, *l;
+ WebKitWebView *web_view;
+
+ window = ephy_window_action_get_window (EPHY_WINDOW_ACTION (action));
+ embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
+ g_return_val_if_fail (embed != NULL, NULL);
+
+ menu = GTK_MENU_SHELL (gtk_menu_new ());
+
+ web_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed);
+
+ if (action->priv->direction == EPHY_NAVIGATION_HISTORY_DIRECTION_BACK)
+ list = webkit_construct_history_list (web_view,
+ WEBKIT_HISTORY_BACKWARD, 10);
+ else
+ list = webkit_construct_history_list (web_view,
+ WEBKIT_HISTORY_FORWARD, 10);
+
+ for (l = list; l != NULL; l = l->next) {
+ GtkWidget *item;
+ WebKitWebHistoryItem *hitem;
+ const char *uri;
+ char *title;
+
+ hitem = (WebKitWebHistoryItem *) l->data;
+ uri = webkit_web_history_item_get_uri (hitem);
+
+ title = g_strdup (webkit_web_history_item_get_title (hitem));
+
+ if (title == NULL || g_strstrip (title)[0] == '\0')
+ item = new_history_menu_item (EPHY_WEB_VIEW (web_view), uri, uri);
+ else
+ item = new_history_menu_item (EPHY_WEB_VIEW (web_view), title, uri);
+
+ g_free (title);
+
+ g_object_set_data_full (G_OBJECT (item), HISTORY_ITEM_DATA_KEY,
+ g_object_ref (hitem), g_object_unref);
+
+ g_signal_connect (item, "activate",
+ G_CALLBACK (activate_menu_item_cb), action);
+
+ gtk_menu_shell_append (menu, item);
+ gtk_widget_show_all (item);
+ }
+
+ g_list_free (list);
+
+ return GTK_WIDGET (menu);
+}
+
+typedef struct {
+ EphyNavigationHistoryAction *action;
+ GdkEventButton *event;
+ GtkWidget *widget;
+} PopupData;
+
+static GtkWidget *
+popup_history_menu (EphyNavigationHistoryAction *action,
+ GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GtkWidget *menu;
+
+ menu = build_dropdown_menu (action);
+ gtk_menu_popup (GTK_MENU (menu),
+ NULL, NULL,
+ ephy_gui_menu_position_under_widget, widget,
+ event->button, event->time);
+
+ return menu;
+}
+
+static gboolean
+menu_timeout_cb (PopupData *data)
+{
+ if (data != NULL && data->widget)
+ popup_history_menu (data->action, data->widget, data->event);
+
+ return FALSE;
+}
+
+static gboolean
+tool_button_press_event_cb (GtkButton *button,
+ GdkEventButton *event,
+ EphyNavigationHistoryAction *action)
+{
+ if (event->button == 1) {
+ PopupData *data;
+
+ data = g_new (PopupData, 1);
+ data->action = action;
+ data->event = event;
+ data->widget = GTK_WIDGET (button);
+
+ action->priv->menu_timeout = g_timeout_add_full (G_PRIORITY_DEFAULT, 500,
+ (GSourceFunc) menu_timeout_cb,
+ data,
+ (GDestroyNotify) g_free);
+ } else if (event->button == 3)
+ popup_history_menu (action, GTK_WIDGET (button), event);
+
+ return FALSE;
+}
+
+static gboolean
+tool_leave_notify_event_cb (GtkButton *button,
+ GdkEvent *event,
+ EphyNavigationHistoryAction *action)
+{
+ if (action->priv->menu_timeout > 0)
+ g_source_remove (action->priv->menu_timeout);
+
+ action->priv->menu_timeout = 0;
+ return FALSE;
+}
+
+static void
+connect_proxy (GtkAction *gaction,
+ GtkWidget *proxy)
+{
+ g_signal_connect (proxy, "button-press-event",
+ G_CALLBACK (tool_button_press_event_cb), gaction);
+ g_signal_connect (proxy, "button-release-event",
+ G_CALLBACK (tool_leave_notify_event_cb), gaction);
+ g_signal_connect (proxy, "leave-notify-event",
+ G_CALLBACK (tool_leave_notify_event_cb), gaction);
+
+ GTK_ACTION_CLASS (ephy_navigation_history_action_parent_class)->connect_proxy (gaction, proxy);
+}
+
+static void
+disconnect_proxy (GtkAction *gaction,
+ GtkWidget *proxy)
+{
+ g_signal_handlers_disconnect_by_func (proxy,
+ G_CALLBACK (tool_button_press_event_cb), gaction);
+ g_signal_handlers_disconnect_by_func (proxy,
+ G_CALLBACK (tool_leave_notify_event_cb), gaction);
+
+ GTK_ACTION_CLASS (ephy_navigation_history_action_parent_class)->disconnect_proxy (gaction, proxy);
+}
+
static void
ephy_navigation_history_action_class_init (EphyNavigationHistoryActionClass *klass)
{
@@ -196,6 +590,8 @@ ephy_navigation_history_action_class_init (EphyNavigationHistoryActionClass *kla
object_class->get_property = ephy_navigation_history_action_get_property;
action_class->activate = action_activate;
+ action_class->connect_proxy = connect_proxy;
+ action_class->disconnect_proxy = disconnect_proxy;
g_object_class_install_property (object_class,
PROP_DIRECTION,