[epiphany] Add context-sensitive menu option to search the web for selected text



commit 9fdf920fd0ce664c1cb82f2deceb01d57e2709e9
Author: Claudio Saavedra <csaavedra igalia com>
Date:   Thu Jun 4 17:48:25 2015 +0300

    Add context-sensitive menu option to search the web for selected text
    
    When building the context menu in the web process, use the web
    extension to find out whether there is text selected and pass it
    as custom data to the UI process. Let the UI process use the
    selection to build a new menu item that, when activated, will launch
    a new tab and search the selected text in the user-preferred search
    engine.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=663545

 embed/web-extension/ephy-web-extension.c |   41 ++++++++++++++++++
 src/ephy-window.c                        |   67 ++++++++++++++++++++++++++++++
 src/popup-commands.c                     |   20 +++++++++
 src/popup-commands.h                     |    3 +
 4 files changed, 131 insertions(+), 0 deletions(-)
---
diff --git a/embed/web-extension/ephy-web-extension.c b/embed/web-extension/ephy-web-extension.c
index 86e600a..11ed2c1 100644
--- a/embed/web-extension/ephy-web-extension.c
+++ b/embed/web-extension/ephy-web-extension.c
@@ -38,6 +38,8 @@
 #include <libsoup/soup.h>
 #include <string.h>
 #include <webkit2/webkit-web-extension.h>
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
 #include <JavaScriptCore/JavaScript.h>
 
 struct _EphyWebExtensionPrivate
@@ -994,6 +996,42 @@ web_page_uri_changed (WebKitWebPage *web_page,
   g_object_set_data_full (G_OBJECT (web_page), "ephy-web-overview", overview, g_object_unref);
 }
 
+static gboolean
+web_page_context_menu (WebKitWebPage *web_page,
+                       WebKitContextMenu *context_menu,
+                       WebKitWebHitTestResult *hit_test_result,
+                       gpointer user_data)
+{
+  char *string;
+  GVariantBuilder builder;
+  WebKitDOMDocument *document = webkit_web_page_get_dom_document (web_page);
+  WebKitDOMDOMWindow *window = webkit_dom_document_get_default_view (document);
+  WebKitDOMDOMSelection *selection = webkit_dom_dom_window_get_selection (window);
+
+  g_object_unref (window);
+
+  if (!selection)
+    return FALSE;
+
+  string = ephy_web_dom_utils_get_selection_as_string (selection);
+  g_object_unref (selection);
+
+  if (!string || *string == '\0')
+  {
+    g_free (string);
+    return FALSE;
+  }
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+  g_variant_builder_add (&builder, "{sv}", "SelectedText", g_variant_new_string (g_strstrip (string)));
+  webkit_context_menu_set_user_data (context_menu,
+                                     g_variant_builder_end (&builder));
+
+  g_free (string);
+
+  return TRUE;
+}
+
 static void
 ephy_web_extension_emit_page_created (EphyWebExtension *extension,
                                       guint64 page_id)
@@ -1062,6 +1100,9 @@ ephy_web_extension_page_created_cb (EphyWebExtension *extension,
   g_signal_connect (web_page, "notify::uri",
                     G_CALLBACK (web_page_uri_changed),
                     extension);
+  g_signal_connect (web_page, "context-menu",
+                    G_CALLBACK (web_page_context_menu),
+                    extension);
 }
 
 static WebKitWebPage *
diff --git a/src/ephy-window.c b/src/ephy-window.c
index 1e4198f..093f5d3 100644
--- a/src/ephy-window.c
+++ b/src/ephy-window.c
@@ -260,6 +260,10 @@ static const GtkActionEntry ephy_popups_entries [] = {
          NULL, G_CALLBACK (popup_cmd_save_media_as) },
        { "CopyAudioLocation", NULL, N_("_Copy Audio Address"), NULL,
          NULL, G_CALLBACK (popup_cmd_copy_media_location) },
+
+       /* Selection */
+       { "SearchSelection", NULL, "_Search Selection", NULL, NULL,
+         G_CALLBACK (popup_cmd_search_selection) },
 };
 
 static const struct
@@ -1628,6 +1632,39 @@ find_spelling_guess_context_menu_items (WebKitContextMenu *context_menu)
        return g_list_reverse (retval);
 }
 
+static char *
+ellipsize_string (const char *string,
+                 glong max_length)
+{
+       char *ellipsized;
+       glong length = g_utf8_strlen (string, -1);
+
+       if (length == 0)
+               return NULL;
+
+       if (length < max_length)
+       {
+               ellipsized = g_strdup (string);
+       }
+       else
+       {
+               char *str = g_utf8_substring (string, 0, max_length);
+               ellipsized = g_strconcat (str, "…", NULL);
+               g_free (str);
+       }
+       return ellipsized;
+}
+
+static void
+parse_context_menu_user_data (WebKitContextMenu *context_menu,
+                             const char** selected_text)
+{
+       GVariantDict dict;
+
+       g_variant_dict_init (&dict, webkit_context_menu_get_user_data (context_menu));
+       g_variant_dict_lookup (&dict, "SelectedText", "&s", selected_text);
+}
+
 static gboolean
 populate_context_menu (WebKitWebView *web_view,
                       WebKitContextMenu *context_menu,
@@ -1651,6 +1688,8 @@ populate_context_menu (WebKitWebView *web_view,
        gboolean is_media = FALSE;
        gboolean is_video = FALSE;
        gboolean is_audio = FALSE;
+       gboolean can_search_selection = FALSE;
+       const char *selected_text;
 
        is_image = webkit_hit_test_result_context_is_image (hit_test_result);
 
@@ -1690,6 +1729,28 @@ populate_context_menu (WebKitWebView *web_view,
                }
        }
 
+       parse_context_menu_user_data (context_menu, &selected_text);
+       if (selected_text)
+       {
+               char* ellipsized = ellipsize_string (selected_text, 32);
+               if (ellipsized)
+               {
+                       char* label;
+                       GtkAction *action;
+
+                       can_search_selection = TRUE;
+                       action = gtk_action_group_get_action (priv->popups_action_group,
+                                                             "SearchSelection");
+                       label = g_strdup_printf (_("Search the Web for '%s'"), ellipsized);
+                       gtk_action_set_label (action, label);
+                       g_object_set_data_full (G_OBJECT (action), "selection", g_strdup (selected_text),
+                                               (GDestroyNotify)g_free);
+                       g_free (ellipsized);
+                       g_free (label);
+                       can_search_selection = TRUE;
+               }
+       }
+
        webkit_context_menu_remove_all (context_menu);
 
        embed_event = ephy_embed_event_new ((GdkEventButton *)event, hit_test_result);
@@ -1726,6 +1787,9 @@ populate_context_menu (WebKitWebView *web_view,
                }
                add_action_to_context_menu (context_menu,
                                            priv->action_group, "EditCopy");
+               if (can_search_selection)
+                       add_action_to_context_menu (context_menu,
+                                                   priv->popups_action_group, "SearchSelection");
                webkit_context_menu_append (context_menu,
                                            webkit_context_menu_item_new_separator ());
                add_action_to_context_menu (context_menu,
@@ -1807,6 +1871,9 @@ populate_context_menu (WebKitWebView *web_view,
 
                add_action_to_context_menu (context_menu,
                                            priv->action_group, "EditCopy");
+               if (can_search_selection)
+                       add_action_to_context_menu (context_menu,
+                                                   priv->popups_action_group, "SearchSelection");
 
                if (!app_mode && !is_image && !is_media)
                {
diff --git a/src/popup-commands.c b/src/popup-commands.c
index 37cf424..ab6538a 100644
--- a/src/popup-commands.c
+++ b/src/popup-commands.c
@@ -382,3 +382,23 @@ popup_cmd_link_in_incognito_window (GtkAction *action,
        ephy_open_incognito_window (g_value_get_string (&value));
        g_value_unset (&value);
 }
+
+void
+popup_cmd_search_selection (GtkAction *action,
+                           EphyWindow *window)
+{
+       EphyEmbed *embed, *new_embed;
+       const char *text;
+       char *search_url;
+
+       embed = ephy_embed_container_get_active_child
+               (EPHY_EMBED_CONTAINER (window));
+       g_assert (EPHY_IS_EMBED (embed));
+
+       text = g_object_get_data (G_OBJECT (action), "selection");
+       search_url = ephy_embed_utils_autosearch_address (text);
+       new_embed = ephy_shell_new_tab (ephy_shell_get_default (),
+                                       window, embed, EPHY_NEW_TAB_APPEND_AFTER);
+       ephy_web_view_load_url (ephy_embed_get_web_view (new_embed), search_url);
+       g_free (search_url);
+}
diff --git a/src/popup-commands.h b/src/popup-commands.h
index a701ca1..ae33759 100644
--- a/src/popup-commands.h
+++ b/src/popup-commands.h
@@ -77,6 +77,9 @@ void popup_cmd_copy_media_location      (GtkAction *action,
 void popup_cmd_save_media_as            (GtkAction *action,
                                          EphyWindow *window);
 
+void popup_cmd_search_selection         (GtkAction *action,
+                                        EphyWindow *window);
+
 G_END_DECLS
 
 #endif


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