[epiphany/wip/gtkaction-to-gaction: 28/57] Use GAction for back/forward buttons



commit fcf142d958f5b1f38ba308ba4c5545c083f99a7b
Author: Iulian Radu <iulian radu67 gmail com>
Date:   Mon Jun 27 13:47:59 2016 +0300

    Use GAction for back/forward buttons

 src/Makefile.am                      |    3 -
 src/ephy-lockdown.c                  |   21 +-
 src/ephy-navigation-history-action.c |  553 ----------------------------------
 src/ephy-navigation-history-action.h |   61 ----
 src/ephy-toolbar.c                   |  476 +++++++++++++++++++++++++++--
 src/ephy-window.c                    |  168 +++++------
 src/window-commands.c                |   78 +++++
 src/window-commands.h                |    6 +
 8 files changed, 621 insertions(+), 745 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 551c326..ce61ce2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,7 +20,6 @@ TYPES_H_FILES = \
        ephy-session.h                          \
        ephy-shell.h                            \
        ephy-window.h                           \
-       ephy-navigation-history-action.h        \
        ephy-title-box.h                        \
        $(NULL)
 
@@ -51,8 +50,6 @@ libephymain_la_SOURCES = \
        ephy-location-controller.h              \
        ephy-lockdown.c                         \
        ephy-lockdown.h                         \
-       ephy-navigation-history-action.c        \
-       ephy-navigation-history-action.h        \
        ephy-notebook.c                         \
        ephy-notebook.h                         \
        ephy-private.h                          \
diff --git a/src/ephy-lockdown.c b/src/ephy-lockdown.c
index 9bc44fa..e30cf7c 100644
--- a/src/ephy-lockdown.c
+++ b/src/ephy-lockdown.c
@@ -123,11 +123,9 @@ static const BindAction popup_actions[] = {
   { EPHY_PREFS_LOCKDOWN_FULLSCREEN, "OpenLinkInNewWindow", "sensitive" }
 };
 
-static const BindAction special_toolbar_actions[] = {
-  { EPHY_PREFS_LOCKDOWN_HISTORY, "NavigationBack", "visible" },
-  { EPHY_PREFS_LOCKDOWN_HISTORY, "NavigationBack", "sensitive" },
-  { EPHY_PREFS_LOCKDOWN_HISTORY, "NavigationForward", "visible" },
-  { EPHY_PREFS_LOCKDOWN_HISTORY, "NavigationForward", "sensitive" },
+static const BindAction toolbar_actions[] = {
+  { EPHY_PREFS_LOCKDOWN_HISTORY, "navigation-back", "enabled" },
+  { EPHY_PREFS_LOCKDOWN_HISTORY, "navigation-forward", "enabled" }
 };
 
 static gboolean
@@ -290,7 +288,7 @@ window_added_cb (GtkApplication *application,
   new_action_group = gtk_widget_get_action_group (GTK_WIDGET (window),
                                                   "win");
   new_bind_settings_and_actions (EPHY_SETTINGS_LOCKDOWN,
-                             G_ACTION_GROUP (new_action_group),
+                             new_action_group,
                              new_window_actions,
                              G_N_ELEMENTS (new_window_actions));
 
@@ -305,10 +303,13 @@ window_added_cb (GtkApplication *application,
   g_settings_bind_writable (settings, "picture-filename",
                             action, "sensitive", FALSE);
 
-  action_group = find_action_group (manager, "SpecialToolbarActions");
-  bind_settings_and_actions (EPHY_SETTINGS_LOCKDOWN,
-                             action_group, special_toolbar_actions,
-                             G_N_ELEMENTS (special_toolbar_actions));
+  new_action_group = gtk_widget_get_action_group (GTK_WIDGET (window),
+                                                  "toolbar");
+  new_bind_settings_and_actions (EPHY_SETTINGS_LOCKDOWN,
+                             new_action_group,
+                             toolbar_actions,
+                             G_N_ELEMENTS (toolbar_actions));
+
   if (ephy_embed_shell_get_mode (ephy_embed_shell_get_default ()) != EPHY_EMBED_SHELL_MODE_APPLICATION) {
     location_controller = ephy_window_get_location_controller (EPHY_WINDOW (window));
     bind_location_controller (EPHY_SETTINGS_LOCKDOWN, location_controller);
diff --git a/src/ephy-toolbar.c b/src/ephy-toolbar.c
index b10790d..559087a 100644
--- a/src/ephy-toolbar.c
+++ b/src/ephy-toolbar.c
@@ -20,13 +20,23 @@
 #include "config.h"
 #include "ephy-toolbar.h"
 
+#include "ephy-action-helper.h"
 #include "ephy-downloads-popover.h"
 #include "ephy-downloads-progress-icon.h"
+#include "ephy-embed.h"
+#include "ephy-embed-container.h"
+#include "ephy-embed-prefs.h"
+#include "ephy-embed-utils.h"
+#include "ephy-favicon-helpers.h"
+#include "ephy-gui.h"
+#include "ephy-history-service.h"
 #include "ephy-location-entry.h"
 #include "ephy-middle-clickable-button.h"
 #include "ephy-private.h"
 #include "ephy-shell.h"
 
+#include <webkit2/webkit2.h>
+
 enum {
   PROP_0,
   PROP_WINDOW,
@@ -35,6 +45,9 @@ enum {
 
 static GParamSpec *object_properties[N_PROPERTIES] = { NULL, };
 
+#define MAX_LABEL_LENGTH 48
+#define HISTORY_ITEM_DATA_KEY "history-item-data-key"
+
 struct _EphyToolbar {
   GtkHeaderBar parent_instance;
 
@@ -49,6 +62,8 @@ struct _EphyToolbar {
   GtkWidget *downloads_popover;
 
   GMenu *page_menu;
+
+  guint navigation_buttons_menu_timeout;
 };
 
 G_DEFINE_TYPE (EphyToolbar, ephy_toolbar, GTK_TYPE_HEADER_BAR)
@@ -153,6 +168,383 @@ sync_chromes_visibility (EphyToolbar *toolbar)
   gtk_widget_set_visible (toolbar->new_tab_button, chrome & EPHY_WINDOW_CHROME_TABSBAR);
 }
 
+typedef enum {
+  EPHY_NAVIGATION_HISTORY_DIRECTION_BACK,
+  EPHY_NAVIGATION_HISTORY_DIRECTION_FORWARD
+} EphyNavigationHistoryDirection;
+
+typedef enum {
+  WEBKIT_HISTORY_BACKWARD,
+  WEBKIT_HISTORY_FORWARD
+} WebKitHistoryType;
+
+static void
+ephy_history_cleared_cb (EphyHistoryService *history,
+                         gpointer           user_data)
+{
+  GActionGroup *action_group;
+  GAction *action;
+  guint i;
+  gchar **actions;
+
+  action_group = gtk_widget_get_action_group (GTK_WIDGET (user_data), "toolbar");
+  actions = g_action_group_list_actions (action_group);
+  for (i = 0; actions[i] != NULL; i++) {
+    action = g_action_map_lookup_action (G_ACTION_MAP (action_group), actions[i]);
+    new_ephy_action_change_sensitivity_flags (G_SIMPLE_ACTION (action), SENS_FLAG, TRUE);
+
+    g_free (actions[i]);
+  }
+
+  g_free (actions);
+}
+
+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, 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 = WEBKIT_FAVICON_DATABASE (source);
+  GdkPixbuf *favicon = NULL;
+  cairo_surface_t *icon_surface = webkit_favicon_database_get_favicon_finish (database, result, NULL);
+
+  if (icon_surface) {
+    favicon = ephy_pixbuf_get_from_surface_scaled (icon_surface, FAVICON_SIZE, FAVICON_SIZE);
+    cairo_surface_destroy (icon_surface);
+  }
+
+  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);
+  }
+
+  g_object_unref (item);
+}
+
+static GtkWidget *
+new_history_menu_item (EphyWebView *view,
+                       const char  *origtext,
+                       const char  *address)
+{
+  GtkWidget *item;
+  GtkLabel *label;
+  WebKitFaviconDatabase *database;
+  EphyEmbedShell *shell = ephy_embed_shell_get_default ();
+
+  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_web_context_get_favicon_database (ephy_embed_shell_get_web_context (shell));
+  webkit_favicon_database_get_favicon (database, address,
+                                       NULL,
+                                       (GAsyncReadyCallback)icon_loaded_cb,
+                                       g_object_ref (item));
+
+  g_object_set_data_full (G_OBJECT (item), "link-message", g_strdup (address), (GDestroyNotify)g_free);
+
+  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)
+{
+  /* TODO: WebKitBackForwardList: In WebKit2 WebKitBackForwardList can't be modified */
+}
+
+static void
+middle_click_handle_on_history_menu_item (EphyEmbed                 *embed,
+                                          WebKitBackForwardListItem *item)
+{
+  EphyEmbed *new_embed = NULL;
+  const gchar *url;
+  gint offset;
+
+  /* TODO: WebKitBackForwardList is read-only in WebKit2 */
+  offset = 0;
+
+  new_embed = ephy_shell_new_tab (ephy_shell_get_default (),
+                                  EPHY_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (embed))),
+                                  embed,
+                                  0);
+  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_back_forward_list_item_get_original_uri (item);
+  ephy_web_view_load_url (ephy_embed_get_web_view (new_embed), url);
+}
+
+static gboolean
+navigation_menu_item_pressed_cb (GtkWidget *menuitem,
+                                 GdkEvent  *event,
+                                 gpointer   user_data)
+{
+  EphyWindow *window = EPHY_WINDOW (user_data);
+  WebKitBackForwardListItem *item;
+  EphyEmbed *embed;
+
+  embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
+
+  item = (WebKitBackForwardListItem *)g_object_get_data (G_OBJECT (menuitem), HISTORY_ITEM_DATA_KEY);
+
+  if (((GdkEventButton *)event)->button == 2) {
+    middle_click_handle_on_history_menu_item (embed, item);
+  } else {
+    WebKitWebView *web_view;
+
+    web_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed);
+    webkit_web_view_go_to_back_forward_list_item (web_view, item);
+  }
+
+  return G_SOURCE_REMOVE;
+}
+
+static GList *
+construct_webkit_history_list (WebKitWebView    *web_view,
+                               WebKitHistoryType hist_type,
+                               int               limit)
+{
+  WebKitBackForwardList *back_forward_list;
+
+  back_forward_list = webkit_web_view_get_back_forward_list (web_view);
+  return hist_type == WEBKIT_HISTORY_FORWARD ?
+         g_list_reverse (webkit_back_forward_list_get_forward_list_with_limit (back_forward_list, limit)) :
+         webkit_back_forward_list_get_back_list_with_limit (back_forward_list, limit);
+}
+
+static GtkWidget *
+build_dropdown_menu (EphyWindow                    *window,
+                     EphyNavigationHistoryDirection direction)
+{
+  GtkMenuShell *menu;
+  EphyEmbed *embed;
+  GList *list, *l;
+  WebKitWebView *web_view;
+
+  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 (direction == EPHY_NAVIGATION_HISTORY_DIRECTION_BACK)
+    list = construct_webkit_history_list (web_view,
+                                          WEBKIT_HISTORY_BACKWARD, 10);
+  else
+    list = construct_webkit_history_list (web_view,
+                                          WEBKIT_HISTORY_FORWARD, 10);
+
+  for (l = list; l != NULL; l = l->next) {
+    GtkWidget *item;
+    WebKitBackForwardListItem *hitem;
+    const char *uri;
+    char *title;
+
+    hitem = (WebKitBackForwardListItem *)l->data;
+    uri = webkit_back_forward_list_item_get_uri (hitem);
+    title = g_strdup (webkit_back_forward_list_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, "button-release-event",
+                      G_CALLBACK (navigation_menu_item_pressed_cb), window);
+
+    gtk_menu_shell_append (menu, item);
+    gtk_widget_show_all (item);
+  }
+
+  g_list_free (list);
+
+  return GTK_WIDGET (menu);
+}
+
+static void
+popup_history_menu (GtkWidget                     *widget,
+                    EphyWindow                    *window,
+                    EphyNavigationHistoryDirection direction,
+                    GdkEventButton                *event)
+{
+  GtkWidget *menu;
+
+  menu = build_dropdown_menu (window, direction);
+  gtk_menu_popup (GTK_MENU (menu),
+                  NULL, NULL,
+                  ephy_gui_menu_position_under_widget, widget,
+                  event->button, event->time);
+}
+
+typedef struct {
+  GtkWidget *button;
+  EphyWindow *window;
+  EphyNavigationHistoryDirection direction;
+  GdkEventButton *event;
+} PopupData;
+
+static gboolean
+menu_timeout_cb (PopupData *data)
+{
+  if (data != NULL && data->window)
+    popup_history_menu (data->button, data->window, data->direction, data->event);
+
+  return G_SOURCE_REMOVE;
+}
+
+static gboolean
+navigation_button_press_event_cb (GtkButton *button,
+                                  GdkEvent  *event,
+                                  gpointer   user_data)
+{
+  EphyToolbar *toolbar = EPHY_TOOLBAR (user_data);
+  EphyNavigationHistoryDirection direction;
+  GVariant *variant;
+
+  variant = gtk_actionable_get_action_target_value (GTK_ACTIONABLE (button));
+
+  direction = g_strcmp0 (g_variant_get_string (variant, NULL), "back") == 0 ?
+              EPHY_NAVIGATION_HISTORY_DIRECTION_BACK : EPHY_NAVIGATION_HISTORY_DIRECTION_FORWARD;
+
+  if (((GdkEventButton *)event)->button == 3) {
+    popup_history_menu (GTK_WIDGET (button), toolbar->window,
+                        direction, (GdkEventButton *)event);
+  } else {
+    PopupData *data;
+
+    data = g_new (PopupData, 1);
+    data->button = GTK_WIDGET (button);
+    data->window = toolbar->window;
+    data->direction = direction;
+    data->event = (GdkEventButton *)event;
+
+    toolbar->navigation_buttons_menu_timeout = g_timeout_add_full (G_PRIORITY_DEFAULT, 500,
+                                                                   (GSourceFunc)menu_timeout_cb,
+                                                                   data,
+                                                                   (GDestroyNotify)g_free);
+    g_source_set_name_by_id (toolbar->navigation_buttons_menu_timeout, "[epiphany] menu_timeout_cb");
+  }
+
+  return FALSE;
+}
+
+static gboolean
+navigation_button_release_event_cb (GtkButton *button,
+                                    GdkEvent  *event,
+                                    gpointer   user_data)
+{
+  EphyToolbar *toolbar = EPHY_TOOLBAR (user_data);
+  GActionGroup *action_group;
+  GAction *action;
+  GVariant *variant;
+  EphyNavigationHistoryDirection direction;
+
+  variant = gtk_actionable_get_action_target_value (GTK_ACTIONABLE (button));
+  action_group = gtk_widget_get_action_group (GTK_WIDGET (toolbar->window), "toolbar");
+
+  direction = g_strcmp0 (g_variant_get_string (variant, NULL), "back") == 0 ?
+              EPHY_NAVIGATION_HISTORY_DIRECTION_BACK : EPHY_NAVIGATION_HISTORY_DIRECTION_FORWARD;
+
+  switch (((GdkEventButton *)event)->button) {
+    case 1:
+      if (direction == 0) {
+        action = g_action_map_lookup_action (G_ACTION_MAP (action_group),
+                                             "navigation-back");
+        g_action_activate (action, variant);
+      } else if (direction == 1) {
+        action = g_action_map_lookup_action (G_ACTION_MAP (action_group),
+                                             "navigation-forward");
+        g_action_activate (action, variant);
+      }
+      break;
+    case 2:
+      if (direction == EPHY_NAVIGATION_HISTORY_DIRECTION_BACK) {
+        action = g_action_map_lookup_action (G_ACTION_MAP (action_group),
+                                             "navigation-back-new-tab");
+        g_action_activate (action, variant);
+      } else if (direction == EPHY_NAVIGATION_HISTORY_DIRECTION_FORWARD) {
+        action = g_action_map_lookup_action (G_ACTION_MAP (action_group),
+                                             "navigation-forward-new-tab");
+        g_action_activate (action, variant);
+      }
+      break;
+    case 3:
+      popup_history_menu (GTK_WIDGET (button), toolbar->window,
+                          direction, (GdkEventButton *)event);
+      break;
+    default:
+      break;
+  }
+
+  return G_SOURCE_REMOVE;
+}
+
+static gboolean
+navigation_leave_notify_event_cb (GtkButton *button,
+                                  GdkEvent  *event,
+                                  gpointer   user_data)
+{
+  EphyToolbar *toolbar = EPHY_TOOLBAR (user_data);
+
+  if (toolbar->navigation_buttons_menu_timeout > 0)
+    g_source_remove (toolbar->navigation_buttons_menu_timeout);
+
+  toolbar->navigation_buttons_menu_timeout = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
 static void
 ephy_toolbar_constructed (GObject *object)
 {
@@ -163,6 +555,7 @@ ephy_toolbar_constructed (GObject *object)
   GtkMenu *menu;
   EphyDownloadsManager *downloads_manager;
   GtkBuilder *builder;
+  EphyHistoryService *history_service;
 
   G_OBJECT_CLASS (ephy_toolbar_parent_class)->constructed (object);
 
@@ -174,30 +567,45 @@ ephy_toolbar_constructed (GObject *object)
   toolbar->navigation_box = box;
 
   /* Back */
-  button = ephy_middle_clickable_button_new ();
-  /* FIXME: apparently we need an image inside the button for the action
-   * icon to appear. */
-  gtk_button_set_image (GTK_BUTTON (button), gtk_image_new ());
+  button = gtk_button_new ();
+  gtk_button_set_image (GTK_BUTTON (button),
+                        gtk_image_new_from_icon_name ("go-previous-symbolic",
+                        GTK_ICON_SIZE_BUTTON));
   gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
-  action_group = ephy_window_get_toolbar_action_group (toolbar->window);
-  action = gtk_action_group_get_action (action_group, "NavigationBack");
-  gtk_activatable_set_related_action (GTK_ACTIVATABLE (button),
-                                      action);
-  gtk_button_set_label (GTK_BUTTON (button), NULL);
-  gtk_style_context_add_class (gtk_widget_get_style_context (button), "image-button");
+  gtk_actionable_set_action_name (GTK_ACTIONABLE (button),
+                                  "toolbar.navigation-back");
+  gtk_actionable_set_action_target_value (GTK_ACTIONABLE (button),
+                                          g_variant_new ("s", "back"));
+  gtk_style_context_add_class (gtk_widget_get_style_context (button),
+                               "image-button");
+  g_signal_connect (button, "button-press-event",
+                    G_CALLBACK (navigation_button_press_event_cb), toolbar);
+  g_signal_connect (button, "button-release-event",
+                    G_CALLBACK (navigation_button_release_event_cb), toolbar);
+  g_signal_connect (button, "leave-notify-event",
+                    G_CALLBACK (navigation_leave_notify_event_cb), toolbar);
+  gtk_widget_show (GTK_WIDGET (button));
   gtk_container_add (GTK_CONTAINER (box), button);
 
   /* Forward */
-  button = ephy_middle_clickable_button_new ();
-  /* FIXME: apparently we need an image inside the button for the action
-   * icon to appear. */
-  gtk_button_set_image (GTK_BUTTON (button), gtk_image_new ());
+  button = gtk_button_new ();
+  gtk_button_set_image (GTK_BUTTON (button),
+                        gtk_image_new_from_icon_name ("go-next-symbolic",
+                        GTK_ICON_SIZE_BUTTON));
   gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
-  action = gtk_action_group_get_action (action_group, "NavigationForward");
-  gtk_activatable_set_related_action (GTK_ACTIVATABLE (button),
-                                      action);
-  gtk_button_set_label (GTK_BUTTON (button), NULL);
-  gtk_style_context_add_class (gtk_widget_get_style_context (button), "image-button");
+  gtk_actionable_set_action_name (GTK_ACTIONABLE (button),
+                                  "toolbar.navigation-forward");
+  gtk_actionable_set_action_target_value (GTK_ACTIONABLE (button),
+                                          g_variant_new ("s", "forward"));
+  gtk_style_context_add_class (gtk_widget_get_style_context (button),
+                               "image-button");
+  g_signal_connect (button, "button-press-event",
+                    G_CALLBACK (navigation_button_press_event_cb), toolbar);
+  g_signal_connect (button, "button-release-event",
+                    G_CALLBACK (navigation_button_release_event_cb), toolbar);
+  g_signal_connect (button, "leave-notify-event",
+                    G_CALLBACK (navigation_leave_notify_event_cb), toolbar);
+  gtk_widget_show (GTK_WIDGET (button));
   gtk_container_add (GTK_CONTAINER (box), button);
 
   gtk_style_context_add_class (gtk_widget_get_style_context (box),
@@ -208,6 +616,8 @@ ephy_toolbar_constructed (GObject *object)
   gtk_header_bar_pack_start (GTK_HEADER_BAR (toolbar), box);
 
   /* Reload/Stop */
+  action_group = ephy_window_get_toolbar_action_group (toolbar->window);
+
   button = gtk_button_new ();
   /* FIXME: apparently we need an image inside the button for the action
    * icon to appear. */
@@ -285,6 +695,28 @@ ephy_toolbar_constructed (GObject *object)
 
   gtk_header_bar_pack_end (GTK_HEADER_BAR (toolbar), toolbar->downloads_revealer);
   gtk_widget_show (toolbar->downloads_revealer);
+
+  history_service = EPHY_HISTORY_SERVICE (ephy_embed_shell_get_global_history_service 
(ephy_embed_shell_get_default ()));
+
+  toolbar->navigation_buttons_menu_timeout = 0;
+
+  g_signal_connect (history_service,
+                    "cleared", G_CALLBACK (ephy_history_cleared_cb),
+                    toolbar->window);
+}
+
+static void
+ephy_toolbar_init (EphyToolbar *toolbar)
+{
+}
+
+static void
+ephy_toolbar_finalize (GObject *object)
+{
+  if (EPHY_TOOLBAR (object)->navigation_buttons_menu_timeout > 0)
+    g_source_remove (EPHY_TOOLBAR (object)->navigation_buttons_menu_timeout);
+
+  G_OBJECT_CLASS (ephy_toolbar_parent_class)->finalize (object);
 }
 
 static void
@@ -292,6 +724,7 @@ ephy_toolbar_class_init (EphyToolbarClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  gobject_class->finalize = ephy_toolbar_finalize;
   gobject_class->set_property = ephy_toolbar_set_property;
   gobject_class->get_property = ephy_toolbar_get_property;
   gobject_class->constructed = ephy_toolbar_constructed;
@@ -308,11 +741,6 @@ ephy_toolbar_class_init (EphyToolbarClass *klass)
                                      object_properties);
 }
 
-static void
-ephy_toolbar_init (EphyToolbar *toolbar)
-{
-}
-
 GtkWidget *
 ephy_toolbar_new (EphyWindow *window)
 {
diff --git a/src/ephy-window.c b/src/ephy-window.c
index 8213313..a20682b 100644
--- a/src/ephy-window.c
+++ b/src/ephy-window.c
@@ -37,7 +37,6 @@
 #include "ephy-initial-state.h"
 #include "ephy-link.h"
 #include "ephy-location-entry.h"
-#include "ephy-navigation-history-action.h"
 #include "ephy-notebook.h"
 #include "ephy-prefs.h"
 #include "ephy-private.h"
@@ -256,8 +255,6 @@ static const struct {
    * when NumLock is on they are KP_9/3 and with NumLock and Control+Shift
    * They're KP_PageUp/Down again!
    */
-  { GDK_KEY_KP_4, GDK_MOD1_MASK /*Alt*/, "NavigationBack", TRUE },
-  { GDK_KEY_KP_6, GDK_MOD1_MASK /*Alt*/, "NavigationForward", TRUE },
   { GDK_KEY_KP_Page_Up, GDK_CONTROL_MASK, "TabsPrevious", FALSE },
   { GDK_KEY_KP_9, GDK_CONTROL_MASK, "TabsPrevious", FALSE },
   { GDK_KEY_KP_Page_Down, GDK_CONTROL_MASK, "TabsNext", FALSE },
@@ -267,8 +264,6 @@ static const struct {
   { GDK_KEY_KP_Page_Down, GDK_SHIFT_MASK | GDK_CONTROL_MASK, "TabsMoveRight", FALSE },
   { GDK_KEY_KP_3, GDK_SHIFT_MASK | GDK_CONTROL_MASK, "TabsMoveRight", FALSE },
 #ifdef HAVE_X11_XF86KEYSYM_H
-  { XF86XK_Back, 0, "NavigationBack", TRUE },
-  { XF86XK_Forward, 0, "NavigationForward", TRUE },
   { XF86XK_Go, 0, "GoLocation", FALSE },
   { XF86XK_OpenURL, 0, "GoLocation", FALSE },
   { XF86XK_AddFavorite, 0, "FileBookmarkPage", FALSE },
@@ -278,22 +273,13 @@ static const struct {
   { XF86XK_Stop, 0, "ViewStop", FALSE },
   /* FIXME: what about ScrollUp, ScrollDown, Menu*, Option, LogOff, Save,.. any others? */
 #endif /* HAVE_X11_XF86KEYSYM_H */
-}, navigation_keybindings_ltr [] = {
-  { GDK_KEY_Left, GDK_MOD1_MASK /*Alt*/, "NavigationBack", TRUE },
-  { GDK_KEY_KP_Left, GDK_MOD1_MASK /*Alt*/, "NavigationBack", TRUE },
-  { GDK_KEY_Right, GDK_MOD1_MASK /*Alt*/, "NavigationForward", TRUE },
-  { GDK_KEY_KP_Right, GDK_MOD1_MASK /*Alt*/, "NavigationForward", TRUE }
-}, navigation_keybindings_rtl [] = {
-  { GDK_KEY_Left, GDK_MOD1_MASK /*Alt*/, "NavigationForward", TRUE },
-  { GDK_KEY_KP_Left, GDK_MOD1_MASK /*Alt*/, "NavigationForward", TRUE },
-  { GDK_KEY_Right, GDK_MOD1_MASK /*Alt*/, "NavigationBack", TRUE },
-  { GDK_KEY_KP_Right, GDK_MOD1_MASK /*Alt*/, "NavigationBack", TRUE }
-}, *navigation_keybindings_rtl_ltr;
+};
 
 const struct {
   const gchar *action_and_target;
   const gchar *accelerators[5];
 } accels [] = {
+  /* Window accels */
   { "win.new-tab", { "<Primary>T", NULL } },
   { "win.open", { "<Primary>O", NULL } },
   { "win.save-as", { "<shift><Primary>S", "<Primary>S", NULL } },
@@ -314,8 +300,14 @@ const struct {
   { "win.encoding", { NULL } },
   { "win.page-source", { "<Primary>U", NULL } },
   { "win.toggle-inspector", { "<shift><Primary>I", "F12", NULL } },
-  { "win.close", { "<Primary>W", NULL } }
-};
+  { "win.close", { "<Primary>W", NULL } },
+}, accels_navigation_ltr [] = {
+  { "toolbar.navigation-back", { "<alt>Left", "<alt>KP_LEFT", "KP_4", "Back", NULL } },
+  { "toolbar.navigation-forward", { "<alt>Right", "<alt>KP_RIGHT", "KP_6", "Forward", NULL } }
+}, accels_navigation_rtl [] = {
+  { "toolbar.navigation-back", { "<alt>Left", "<alt>KP_LEFT", "KP_6", "Back", NULL } },
+  { "toolbar.navigation-forward", { "<alt>Right", "<alt>KP_RIGHT", "KP_4", "Forward", NULL } }
+}, *accels_navigation_ltr_rtl;
 
 #define SETTINGS_CONNECTION_DATA_KEY    "EphyWindowSettings"
 
@@ -729,9 +721,6 @@ ephy_window_bound_accels (GtkWidget   *widget,
   guint modifier = event->state & gtk_accelerator_get_default_mod_mask ();
   guint i;
 
-  navigation_keybindings_rtl_ltr = gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL ?
-                                   navigation_keybindings_rtl : navigation_keybindings_ltr;
-
   for (i = 0; i < G_N_ELEMENTS (extra_keybindings); i++) {
     if (event->keyval == extra_keybindings[i].keyval &&
         modifier == extra_keybindings[i].modifier) {
@@ -748,22 +737,6 @@ ephy_window_bound_accels (GtkWidget   *widget,
     }
   }
 
-  for (i = 0; i < G_N_ELEMENTS (navigation_keybindings_rtl); i++) {
-    if (event->keyval == navigation_keybindings_rtl_ltr[i].keyval &&
-        modifier == navigation_keybindings_rtl_ltr[i].modifier) {
-      GtkAction *action = gtk_action_group_get_action
-                            (navigation_keybindings_rtl_ltr[i].fromToolbar ?
-                            window->toolbar_action_group :
-                            window->action_group,
-                            navigation_keybindings_rtl_ltr[i].action);
-      if (gtk_action_is_sensitive (action)) {
-        gtk_action_activate (action);
-        return TRUE;
-      }
-      break;
-    }
-  }
-
   return FALSE;
 }
 
@@ -1078,6 +1051,13 @@ static const GActionEntry new_ephy_page_menu_entries [] =
   { "close-tab", window_cmd_file_close_window }
 };
 
+static const GActionEntry ephy_toolbar_entries [] = {
+  { "navigation-back", window_cmd_navigation, "s" },
+  { "navigation-back-new-tab", window_cmd_navigation_new_tab, "s" },
+  { "navigation-forward", window_cmd_navigation, "s" },
+  { "navigation-forward-new-tab", window_cmd_navigation_new_tab, "s" }
+};
+
 static void
 setup_ui_manager (EphyWindow *window)
 {
@@ -1122,29 +1102,6 @@ setup_ui_manager (EphyWindow *window)
   g_object_unref (action_group);
 
   action_group = gtk_action_group_new ("SpecialToolbarActions");
-  action =
-    g_object_new (EPHY_TYPE_NAVIGATION_HISTORY_ACTION,
-                  "name", "NavigationBack",
-                  "label", _("Back"),
-                  "icon-name", "go-previous-symbolic",
-                  "window", window,
-                  "direction", EPHY_NAVIGATION_HISTORY_DIRECTION_BACK,
-                  NULL);
-  gtk_action_group_add_action_with_accel (action_group, action,
-                                          "<alt>Left");
-  g_object_unref (action);
-
-  action =
-    g_object_new (EPHY_TYPE_NAVIGATION_HISTORY_ACTION,
-                  "name", "NavigationForward",
-                  "label", _("Forward"),
-                  "icon-name", "go-next-symbolic",
-                  "window", window,
-                  "direction", EPHY_NAVIGATION_HISTORY_DIRECTION_FORWARD,
-                  NULL);
-  gtk_action_group_add_action_with_accel (action_group, action,
-                                          "<alt>Right");
-  g_object_unref (action);
 
   action =
     g_object_new (EPHY_TYPE_HOME_ACTION,
@@ -1361,12 +1318,15 @@ static void
 _ephy_window_set_navigation_flags (EphyWindow                *window,
                                    EphyWebViewNavigationFlags flags)
 {
-  GtkAction *action;
+  GActionGroup *action_group;
+  GAction *action;
 
-  action = gtk_action_group_get_action (window->toolbar_action_group, "NavigationBack");
-  gtk_action_set_sensitive (action, flags & EPHY_WEB_VIEW_NAV_BACK);
-  action = gtk_action_group_get_action (window->toolbar_action_group, "NavigationForward");
-  gtk_action_set_sensitive (action, flags & EPHY_WEB_VIEW_NAV_FORWARD);
+  action_group = gtk_widget_get_action_group (GTK_WIDGET (window), "toolbar");
+
+  action = g_action_map_lookup_action (G_ACTION_MAP (action_group), "navigation-back");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), flags & EPHY_WEB_VIEW_NAV_BACK);
+  action = g_action_map_lookup_action (G_ACTION_MAP (action_group), "navigation-forward");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), flags & EPHY_WEB_VIEW_NAV_FORWARD);
 }
 
 static void
@@ -1546,10 +1506,18 @@ action_name_to_label_for_model (GMenuModel *menu_model, const gchar *action_name
   return NULL;
 }
 
+typedef struct {
+  GAction *action;
+  GVariant *parameter;
+} GActionData;
+
 static void
 action_activate_cb (GtkAction *action, gpointer user_data)
 {
-  g_action_activate (G_ACTION (user_data), NULL);
+  GActionData *action_data = (GActionData *) user_data;
+
+  printf("%s\n", g_variant_get_string (action_data->parameter, NULL));
+  g_action_activate (G_ACTION (action_data->action), action_data->parameter);
 }
 
 static WebKitContextMenuItem*
@@ -1557,10 +1525,12 @@ webkit_context_menu_item_new_from_gaction (GAction *action, const gchar *label)
 {
   GtkAction *gtk_action;
   WebKitContextMenuItem *item;
+  GActionData *action_data;
 
+  action_data = g_slice_new (GActionData);
   gtk_action = gtk_action_new (g_action_get_name (action), label, NULL, NULL);
   g_signal_connect (gtk_action, "activate",
-                            G_CALLBACK (action_activate_cb), action);
+                    G_CALLBACK (action_activate_cb), action_data);
 
   g_object_bind_property (action, "enabled", gtk_action, "sensitive", G_BINDING_BIDIRECTIONAL);
 
@@ -1572,15 +1542,15 @@ webkit_context_menu_item_new_from_gaction (GAction *action, const gchar *label)
 static void
 new_add_action_to_context_menu (WebKitContextMenu *context_menu,
                             GActionGroup      *action_group,
-                            const char        *action_name)
+                            const char        *action_name,
+                            GtkWidget         *toolbar)
 {
   GAction *action;
-  EphyToolbar *toolbar;
   const gchar *label;
 
-  toolbar = EPHY_TOOLBAR (EPHY_WINDOW (action_group)->toolbar);
   action = g_action_map_lookup_action (G_ACTION_MAP (action_group), action_name);
-  label = action_name_to_label_for_model (G_MENU_MODEL (ephy_toolbar_get_page_menu (toolbar)), action_name);
+  label = action_name_to_label_for_model (G_MENU_MODEL (ephy_toolbar_get_page_menu (EPHY_TOOLBAR (toolbar))),
+                                          action_name);
   webkit_context_menu_append (context_menu, webkit_context_menu_item_new_from_gaction (action, label));
 }
 
@@ -1683,6 +1653,7 @@ populate_context_menu (WebKitWebView       *web_view,
   WebKitContextMenuItem *toggle_loop_item = NULL;
   WebKitContextMenuItem *fullscreen_item = NULL;
   GActionGroup *window_action_group;
+  GActionGroup *toolbar_action_group;
   GList *spelling_guess_items = NULL;
   EphyEmbedEvent *embed_event;
   gboolean is_document = FALSE;
@@ -1696,6 +1667,8 @@ populate_context_menu (WebKitWebView       *web_view,
 
   window_action_group = gtk_widget_get_action_group (GTK_WIDGET (window),
                                                      "win");
+  toolbar_action_group = gtk_widget_get_action_group (GTK_WIDGET (window),
+                                                      "toolbar");
 
   is_image = webkit_hit_test_result_context_is_image (hit_test_result);
 
@@ -1783,7 +1756,7 @@ populate_context_menu (WebKitWebView       *web_view,
                                   webkit_context_menu_item_new_separator ());
     }
     new_add_action_to_context_menu (context_menu,
-                                window_action_group, "copy");
+                                window_action_group, "copy", window->toolbar);
     if (can_search_selection)
       add_action_to_context_menu (context_menu,
                                   window->popups_action_group, "SearchSelection");
@@ -1820,21 +1793,21 @@ populate_context_menu (WebKitWebView       *web_view,
     update_edit_actions_sensitivity (window, FALSE);
 
     new_add_action_to_context_menu (context_menu,
-                                window_action_group, "undo");
+                                window_action_group, "undo", window->toolbar);
     new_add_action_to_context_menu (context_menu,
-                                window_action_group, "redo");
+                                window_action_group, "redo", window->toolbar);
     webkit_context_menu_append (context_menu,
                                 webkit_context_menu_item_new_separator ());
     new_add_action_to_context_menu (context_menu,
-                                window_action_group, "cut");
+                                window_action_group, "cut", window->toolbar);
     new_add_action_to_context_menu (context_menu,
-                                window_action_group, "copy");
+                                window_action_group, "copy", window->toolbar);
     new_add_action_to_context_menu (context_menu,
-                                window_action_group, "paste");
+                                window_action_group, "paste", window->toolbar);
     webkit_context_menu_append (context_menu,
                                 webkit_context_menu_item_new_separator ());
     new_add_action_to_context_menu (context_menu,
-                                window_action_group, "select-all");
+                                window_action_group, "select-all", window->toolbar);
     if (input_methods_item || unicode_item)
       webkit_context_menu_append (context_menu,
                                   webkit_context_menu_item_new_separator ());
@@ -1846,10 +1819,10 @@ populate_context_menu (WebKitWebView       *web_view,
     update_edit_actions_sensitivity (window, TRUE);
 
     if (!is_image && !is_media) {
-      add_action_to_context_menu (context_menu,
-                                  window->toolbar_action_group, "NavigationBack");
-      add_action_to_context_menu (context_menu,
-                                  window->toolbar_action_group, "NavigationForward");
+      new_add_action_to_context_menu (context_menu, toolbar_action_group,
+                                      "navigation-back", window->toolbar);
+      new_add_action_to_context_menu (context_menu, toolbar_action_group,
+                                      "navigation-forward", window->toolbar);
       add_action_to_context_menu (context_menu,
                                   window->action_group, "ViewReload");
       webkit_context_menu_append (context_menu,
@@ -1857,7 +1830,7 @@ populate_context_menu (WebKitWebView       *web_view,
     }
 
     new_add_action_to_context_menu (context_menu,
-                                window_action_group, "copy");
+                                window_action_group, "copy", window->toolbar);
     if (can_search_selection)
       add_action_to_context_menu (context_menu,
                                   window->popups_action_group, "SearchSelection");
@@ -3068,7 +3041,6 @@ static GtkWidget *
 setup_toolbar (EphyWindow *window)
 {
   GtkWidget *toolbar;
-  GtkAction *action;
   EphyEmbedShellMode app_mode;
   EphyTitleBox *title_box;
 
@@ -3080,16 +3052,6 @@ setup_toolbar (EphyWindow *window)
   if (app_mode == EPHY_EMBED_SHELL_MODE_INCOGNITO)
     gtk_style_context_add_class (gtk_widget_get_style_context (toolbar), "incognito-mode");
 
-  action = gtk_action_group_get_action (window->toolbar_action_group,
-                                        "NavigationBack");
-  g_signal_connect_swapped (action, "open-link",
-                            G_CALLBACK (ephy_link_open), window);
-
-  action = gtk_action_group_get_action (window->toolbar_action_group,
-                                        "NavigationForward");
-  g_signal_connect_swapped (action, "open-link",
-                            G_CALLBACK (ephy_link_open), window);
-
   title_box = ephy_toolbar_get_title_box (EPHY_TOOLBAR (toolbar));
   g_signal_connect (title_box, "lock-clicked",
                     G_CALLBACK (title_box_lock_clicked_cb), window);
@@ -3214,6 +3176,15 @@ ephy_window_constructor (GType                  type,
                                   "win",
                                   G_ACTION_GROUP (new_simple_action_group));
 
+  new_simple_action_group = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (new_simple_action_group),
+                                   ephy_toolbar_entries,
+                                   G_N_ELEMENTS (ephy_toolbar_entries),
+                                   window);
+  gtk_widget_insert_action_group (GTK_WIDGET (window),
+                                  "toolbar",
+                                  G_ACTION_GROUP (new_simple_action_group));
+
   /* Set accels for actions */
   app = g_application_get_default ();
   for (i = 0; i < G_N_ELEMENTS (accels); i++) {
@@ -3222,6 +3193,15 @@ ephy_window_constructor (GType                  type,
                                            accels[i].accelerators);
   }
 
+  accels_navigation_ltr_rtl = gtk_widget_get_default_direction () == GTK_TEXT_DIR_LTR ?
+                              accels_navigation_ltr : accels_navigation_rtl;
+
+  for (i = 0; i < G_N_ELEMENTS (accels_navigation_ltr_rtl); i++) {
+    gtk_application_set_accels_for_action (GTK_APPLICATION (app),
+                                           accels_navigation_ltr_rtl[i].action_and_target,
+                                           accels_navigation_ltr_rtl[i].accelerators);
+  }
+
   ephy_gui_ensure_window_group (GTK_WINDOW (window));
 
   /* initialize the listener for the key theme
diff --git a/src/window-commands.c b/src/window-commands.c
index 84e5b56..4047d68 100644
--- a/src/window-commands.c
+++ b/src/window-commands.c
@@ -62,6 +62,84 @@
 #define FAVICON_SIZE 16
 
 void
+window_cmd_navigation (GSimpleAction *action,
+                       GVariant      *value,
+                       gpointer       user_data)
+{
+  EphyWindow *window = EPHY_WINDOW (user_data);
+  const gchar *direction = g_variant_get_string (value, 0);
+  EphyEmbed *embed;
+  WebKitWebView *web_view;
+
+  embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
+  g_return_if_fail (embed != NULL);
+
+  web_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed);
+
+  if (g_strcmp0 (direction, "back") == 0) {
+    webkit_web_view_go_back (web_view);
+    gtk_widget_grab_focus (GTK_WIDGET (embed));
+  } else {
+    webkit_web_view_go_forward (web_view);
+    gtk_widget_grab_focus (GTK_WIDGET (embed));
+  }
+}
+
+void
+window_cmd_navigation_new_tab (GSimpleAction *action,
+                               GVariant      *value,
+                               gpointer       user_data)
+{
+  EphyWindow *window = EPHY_WINDOW (user_data);
+  const gchar *direction = g_variant_get_string (value, 0);
+  EphyEmbed *embed;
+  WebKitWebView *web_view;
+
+  embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
+  g_return_if_fail (embed != NULL);
+
+  web_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed);
+
+  if (g_strcmp0 (direction, "back") == 0) {
+      const char *back_uri;
+      WebKitBackForwardList *history;
+      WebKitBackForwardListItem *back_item;
+
+      history = webkit_web_view_get_back_forward_list (web_view);
+      back_item = webkit_back_forward_list_get_back_item (history);
+      back_uri = webkit_back_forward_list_item_get_original_uri (back_item);
+
+      embed = ephy_shell_new_tab (ephy_shell_get_default (),
+                                  EPHY_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (embed))),
+                                  NULL,
+                                  0);
+
+      web_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed);
+      webkit_web_view_load_uri (web_view, back_uri);
+      gtk_widget_grab_focus (GTK_WIDGET (embed));
+  } else {
+      const char *forward_uri;
+      WebKitBackForwardList *history;
+      WebKitBackForwardListItem *forward_item;
+
+      /* Forward history is not copied when opening
+         a new tab, so get the forward URI manually
+         and load it */
+      history = webkit_web_view_get_back_forward_list (EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed));
+      forward_item = webkit_back_forward_list_get_forward_item (history);
+      forward_uri = webkit_back_forward_list_item_get_original_uri (forward_item);
+
+      embed = ephy_shell_new_tab (ephy_shell_get_default (),
+                                  EPHY_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (embed))),
+                                  embed,
+                                  0);
+
+      web_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed);
+      webkit_web_view_load_uri (web_view, forward_uri);
+  }
+}
+
+void
 window_cmd_undo_close_tab (GtkAction  *action,
                            EphyWindow *window)
 {
diff --git a/src/window-commands.h b/src/window-commands.h
index c5252d8..463306f 100644
--- a/src/window-commands.h
+++ b/src/window-commands.h
@@ -24,6 +24,12 @@
 
 G_BEGIN_DECLS
 
+void window_cmd_navigation                (GSimpleAction *action,
+                                           GVariant      *value,
+                                           gpointer       user_data);
+void window_cmd_navigation_new_tab        (GSimpleAction *action,
+                                           GVariant      *value,
+                                           gpointer       user_data);
 void window_cmd_view_stop                 (GtkAction  *action,
                                            EphyWindow *window);
 void window_cmd_go_location               (GtkAction  *action,



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