[epiphany] ephy-navigation-history-action: restore menus



commit a166462bcaf8211416c3e19a421c0ae5279e1b9f
Author: Diego Escalante Urrelo <diegoe igalia com>
Date:   Wed Mar 7 18:04:43 2012 -0500

    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

 src/ephy-navigation-history-action.c |  396 ++++++++++++++++++++++++++++++++++
 1 files changed, 396 insertions(+), 0 deletions(-)
---
diff --git a/src/ephy-navigation-history-action.c b/src/ephy-navigation-history-action.c
index f0f0a5e..bbf6c72 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,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]