summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-02 22:30:26 +0000
committerestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-02 22:30:26 +0000
commit2e417c8257e0007ef3fb6929a507268d0450bd4a (patch)
tree756cbb26e6225ef36abddb2cf59a73800587dcbd /chrome
parent0cac83aa1536b90dd25db93808c4371c675e4cf2 (diff)
downloadchromium_src-2e417c8257e0007ef3fb6929a507268d0450bd4a.zip
chromium_src-2e417c8257e0007ef3fb6929a507268d0450bd4a.tar.gz
chromium_src-2e417c8257e0007ef3fb6929a507268d0450bd4a.tar.bz2
Copy selection to x clipboard.
Review URL: http://codereview.chromium.org/55052 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13044 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc24
-rw-r--r--chrome/browser/renderer_host/render_view_host.h5
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view.h6
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc105
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.h27
-rw-r--r--chrome/common/render_messages_internal.h13
-rw-r--r--chrome/renderer/render_view.cc22
-rw-r--r--chrome/renderer/render_view.h10
8 files changed, 190 insertions, 22 deletions
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
index 84994bb..83c55a7 100644
--- a/chrome/browser/renderer_host/render_view_host.cc
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -772,8 +772,10 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
OnRemoveAutofillEntry)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFeedList, OnMsgUpdateFeedList)
IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionRequest, OnExtensionRequest)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SelectionChanged, OnMsgSelectionChanged)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SetSelectionText, OnMsgSetSelectionText)
IPC_MESSAGE_HANDLER(ViewHostMsg_PasteFromSelectionClipboard,
- OnPasteFromSelectionClipboard)
+ OnMsgPasteFromSelectionClipboard)
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(RenderWidgetHost::OnMessageReceived(msg))
IPC_END_MESSAGE_MAP_EX()
@@ -1094,6 +1096,21 @@ void RenderViewHost::OnMsgSetTooltipText(const std::wstring& tooltip_text) {
view()->SetTooltipText(tooltip_text);
}
+void RenderViewHost::OnMsgSelectionChanged() {
+ if (view())
+ view()->SelectionChanged();
+}
+
+void RenderViewHost::OnMsgSetSelectionText(const std::string& text) {
+ if (view())
+ view()->SetSelectionText(text);
+}
+
+void RenderViewHost::OnMsgPasteFromSelectionClipboard() {
+ if (view())
+ view()->PasteFromSelectionClipboard();
+}
+
void RenderViewHost::OnMsgRunFileChooser(bool multiple_files,
const std::wstring& title,
const std::wstring& default_file,
@@ -1366,8 +1383,3 @@ void RenderViewHost::SendExtensionResponse(int callback_id,
const std::string& response) {
Send(new ViewMsg_ExtensionResponse(routing_id(), callback_id, response));
}
-
-void RenderViewHost::OnPasteFromSelectionClipboard() {
- if (view())
- view()->PasteFromSelectionClipboard();
-}
diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h
index c150259..f7a63a5 100644
--- a/chrome/browser/renderer_host/render_view_host.h
+++ b/chrome/browser/renderer_host/render_view_host.h
@@ -506,6 +506,9 @@ class RenderViewHost : public RenderWidgetHost {
#endif
void OnMsgGoToEntryAtOffset(int offset);
void OnMsgSetTooltipText(const std::wstring& tooltip_text);
+ void OnMsgSelectionChanged();
+ void OnMsgSetSelectionText(const std::string& text);
+ void OnMsgPasteFromSelectionClipboard();
void OnMsgRunFileChooser(bool multiple_files,
const std::wstring& title,
const std::wstring& default_file,
@@ -565,8 +568,6 @@ class RenderViewHost : public RenderWidgetHost {
void OnExtensionRequest(const std::string& name, const std::string& args,
int callback_id);
- void OnPasteFromSelectionClipboard();
-
// Helper function to send a navigation message. If a cross-site request is
// in progress, we may be suspended while waiting for the onbeforeunload
// handler, so this function might buffer the message rather than sending it.
diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h
index 255f6644..1a9dead 100644
--- a/chrome/browser/renderer_host/render_widget_host_view.h
+++ b/chrome/browser/renderer_host/render_widget_host_view.h
@@ -112,6 +112,12 @@ class RenderWidgetHostView {
// the page has changed.
virtual void SetTooltipText(const std::wstring& tooltip_text) = 0;
+ // Notifies the View that the renderer text selection has changed.
+ virtual void SelectionChanged() { };
+
+ // Notifies the View what the current selection text is.
+ virtual void SetSelectionText(const std::string& text) { };
+
// Tells the View to get the text from the selection clipboard and send it
// back to the renderer asynchronously.
virtual void PasteFromSelectionClipboard() { }
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
index 21b45d1..74eaf57 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -6,6 +6,7 @@
#include <gtk/gtk.h>
#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
#include <cairo/cairo.h>
#include "base/logging.h"
@@ -16,13 +17,10 @@
#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "third_party/WebKit/WebKit/chromium/public/gtk/WebInputEventFactory.h"
+#include "webkit/glue/webcursor_gtk_data.h"
using WebKit::WebInputEventFactory;
-namespace {
-
-#include "webkit/glue/webcursor_gtk_data.h"
-
// This class is a simple convenience wrapper for Gtk functions. It has only
// static methods.
class RenderWidgetHostViewGtkWidget {
@@ -48,9 +46,9 @@ class RenderWidgetHostViewGtkWidget {
g_signal_connect(widget, "key-release-event",
G_CALLBACK(KeyPressReleaseEvent), host_view);
g_signal_connect(widget, "focus-in-event",
- G_CALLBACK(FocusIn), host_view);
+ G_CALLBACK(OnFocusIn), host_view);
g_signal_connect(widget, "focus-out-event",
- G_CALLBACK(FocusOut), host_view);
+ G_CALLBACK(OnFocusOut), host_view);
g_signal_connect(widget, "button-press-event",
G_CALLBACK(ButtonPressReleaseEvent), host_view);
g_signal_connect(widget, "button-release-event",
@@ -60,6 +58,34 @@ class RenderWidgetHostViewGtkWidget {
g_signal_connect(widget, "scroll-event",
G_CALLBACK(MouseScrollEvent), host_view);
+ GtkTargetList* target_list = gtk_target_list_new(NULL, 0);
+ gtk_target_list_add_text_targets(target_list, 0);
+ gint num_targets = 0;
+ GtkTargetEntry* targets = gtk_target_table_new_from_list(target_list,
+ &num_targets);
+ gtk_selection_clear_targets(widget, GDK_SELECTION_PRIMARY);
+ gtk_selection_add_targets(widget, GDK_SELECTION_PRIMARY, targets,
+ num_targets);
+ gtk_target_table_free(targets, num_targets);
+
+ // When X requests the contents of the clipboard, GTK will emit the
+ // selection_request_event signal. The default handler would then
+ // synchronously emit the selection_get signal. However, we want to
+ // respond to the selection_request_event asynchronously, so we intercept
+ // the signal in OnSelectionRequest, request the selection text from the
+ // render view, and return TRUE so the default handler won't be called. Then
+ // when we get the selection text back from the renderer in
+ // SetSelectionText() we will call manually the selection_request_event
+ // default handler.
+ g_signal_connect(widget, "selection_request_event",
+ G_CALLBACK(OnSelectionRequest), host_view);
+ g_signal_connect(widget, "selection_get",
+ G_CALLBACK(OnSelectionGet), host_view);
+
+ // In OnSelectionGet, we need to access |host_view| to get the selection
+ // text.
+ g_object_set_data(G_OBJECT(widget), "render-widget-host-view-gtk",
+ host_view);
return widget;
}
@@ -87,13 +113,13 @@ class RenderWidgetHostViewGtkWidget {
return TRUE;
}
- static gboolean FocusIn(GtkWidget* widget, GdkEventFocus* focus,
+ static gboolean OnFocusIn(GtkWidget* widget, GdkEventFocus* focus,
RenderWidgetHostViewGtk* host_view) {
host_view->GetRenderWidgetHost()->Focus();
return FALSE;
}
- static gboolean FocusOut(GtkWidget* widget, GdkEventFocus* focus,
+ static gboolean OnFocusOut(GtkWidget* widget, GdkEventFocus* focus,
RenderWidgetHostViewGtk* host_view) {
// Whenever we lose focus, set the cursor back to that of our parent window,
// which should be the default arrow.
@@ -130,17 +156,49 @@ class RenderWidgetHostViewGtkWidget {
return FALSE;
}
+
+ static gboolean OnSelectionRequest(GtkWidget* widget,
+ GdkEventSelection* event) {
+ RenderWidgetHostViewGtk* host_view =
+ reinterpret_cast<RenderWidgetHostViewGtk*>(
+ g_object_get_data(G_OBJECT(widget), "render-widget-host-view-gtk"));
+
+ // If we already know the selection text, return FALSE to let the default
+ // handler run. Also, don't try to handle two events simultaneously,
+ // because we might end up sending the wrong |event_selection_| back to GTK.
+ if (!host_view->selection_text_.empty() ||
+ host_view->event_selection_active_)
+ return FALSE;
+
+ host_view->event_selection_ = *event;
+ host_view->event_selection_active_ = true;
+ if (host_view->selection_text_.empty())
+ host_view->RequestSelectionText();
+
+ return TRUE;
+ }
+
+ static void OnSelectionGet(GtkWidget* widget,
+ GtkSelectionData* data,
+ guint info, guint time,
+ RenderWidgetHostViewGtk* host_view) {
+ DCHECK(!host_view->selection_text_.empty() ||
+ host_view->event_selection_active_);
+
+ gtk_selection_data_set(data, data->target, 8,
+ reinterpret_cast<const guchar*>(host_view->selection_text_.c_str()),
+ host_view->selection_text_.length());
+ }
+
DISALLOW_IMPLICIT_CONSTRUCTORS(RenderWidgetHostViewGtkWidget);
};
-gboolean OnPopupParentFocusOut(GtkWidget* parent, GdkEventFocus* focus,
- RenderWidgetHost* host) {
+static gboolean OnPopupParentFocusOut(GtkWidget* parent, GdkEventFocus* focus,
+ RenderWidgetHost* host) {
host->Shutdown();
return FALSE;
}
-} // namespace
-
// static
RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget(
RenderWidgetHost* widget) {
@@ -153,7 +211,8 @@ RenderWidgetHostViewGtk::RenderWidgetHostViewGtk(RenderWidgetHost* widget_host)
parent_(NULL),
popup_signal_id_(0),
activatable_(true),
- is_loading_(false) {
+ is_loading_(false),
+ event_selection_active_(false) {
host_->set_view(this);
}
@@ -308,6 +367,22 @@ void RenderWidgetHostViewGtk::SetTooltipText(const std::wstring& tooltip_text) {
}
}
+void RenderWidgetHostViewGtk::SelectionChanged() {
+ selection_text_.clear();
+
+ guint32 timestamp = gdk_x11_get_server_time(view_.get()->window);
+ gtk_selection_owner_set(view_.get(), GDK_SELECTION_PRIMARY, timestamp);
+}
+
+void RenderWidgetHostViewGtk::SetSelectionText(const std::string& text) {
+ selection_text_ = text;
+ DCHECK(event_selection_active_);
+ event_selection_active_ = false;
+ // Resume normal handling of the active selection_request_event.
+ GtkWidgetClass* klass = GTK_WIDGET_CLASS(gtk_type_class(GTK_TYPE_WIDGET));
+ klass->selection_request_event(view_.get(), &event_selection_);
+}
+
BackingStore* RenderWidgetHostViewGtk::AllocBackingStore(
const gfx::Size& size) {
Display* display = x11_util::GetXDisplay();
@@ -387,6 +462,10 @@ void RenderWidgetHostViewGtk::ShowCurrentCursor() {
gdk_cursor_unref(gdk_cursor);
}
+void RenderWidgetHostViewGtk::RequestSelectionText() {
+ host_->Send(new ViewMsg_RequestSelectionText(host_->routing_id()));
+}
+
void RenderWidgetHostViewGtk::ReceivedSelectionText(GtkClipboard* clipboard,
const gchar* text, gpointer userdata) {
RenderWidgetHostViewGtk* host_view =
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.h b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
index f3fc7ba..5d260a1 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
@@ -5,16 +5,19 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_GTK_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_GTK_H_
+#include <gdk/gdk.h>
#include <vector>
#include "base/gfx/native_widget_types.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/common/owned_widget_gtk.h"
+#include "chrome/common/render_messages.h"
#include "webkit/glue/webcursor.h"
class RenderWidgetHost;
typedef struct _GtkClipboard GtkClipboard;
+typedef struct _GtkSelectionData GtkSelectionData;
// -----------------------------------------------------------------------------
// See comments in render_widget_host_view.h about this class and its members.
@@ -58,6 +61,8 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
void RenderViewGone();
void Destroy();
void SetTooltipText(const std::wstring& tooltip_text);
+ void SelectionChanged();
+ void SetSelectionText(const std::string& text);
void PasteFromSelectionClipboard();
BackingStore* AllocBackingStore(const gfx::Size& size);
// ---------------------------------------------------------------------------
@@ -67,9 +72,20 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
void Paint(const gfx::Rect&);
private:
+ friend class RenderWidgetHostViewGtkWidget;
+
+ void set_event_selection(GdkEventSelection* event_selection) {
+ event_selection_ = *event_selection;
+ event_selection_active_ = true;
+ }
+
// Update the display cursor for the render view.
void ShowCurrentCursor();
+ void RequestSelectionText();
+
+ // When we've requested the text from the X clipboard, GTK returns it to us
+ // through this callback.
static void ReceivedSelectionText(GtkClipboard* clipboard,
const gchar* text,
gpointer userdata);
@@ -99,6 +115,17 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
// The cursor for the page. This is passed up from the renderer.
WebCursor current_cursor_;
+
+ // We cache the text that is selected on the page. This is used for copying to
+ // the X clipboard. We update |selection_text_| whenever X asks us for it and
+ // the cache is empty. We invalidate it (set it to empty) whenever the
+ // renderer sends a SelectionChanged message.
+ std::string selection_text_;
+
+ // A struct that keeps state for the XSelectionEvent we are handling (if any).
+ GdkEventSelection event_selection_;
+ // Tracks whether we are currently handling an XSelectionEvent.
+ bool event_selection_active_;
};
#endif // CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_GTK_H_
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 5e664c3..cc296a6 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -108,6 +108,10 @@ IPC_BEGIN_MESSAGES(View)
// node.
IPC_MESSAGE_ROUTED1(ViewMsg_SetInitialFocus, bool /* reverse */)
+ // Ask the renderer to send us the selection text via the SetSelectionText
+ // message.
+ IPC_MESSAGE_ROUTED0(ViewMsg_RequestSelectionText)
+
// Tells the renderer to perform the specified navigation, interrupting any
// existing navigation.
IPC_MESSAGE_ROUTED1(ViewMsg_Navigate, ViewMsg_Navigate_Params)
@@ -900,6 +904,13 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_ROUTED1(ViewHostMsg_SetTooltipText,
std::wstring /* tooltip text string */)
+ // Notification that the text selection has changed.
+ IPC_MESSAGE_ROUTED0(ViewHostMsg_SelectionChanged)
+
+ // Send the current text selection.
+ IPC_MESSAGE_ROUTED1(ViewHostMsg_SetSelectionText,
+ std::string /* currently selected text */)
+
// Asks the browser to display the file chooser. The result is returned in a
// ViewHost_RunFileChooserResponse message.
IPC_MESSAGE_ROUTED4(ViewHostMsg_RunFileChooser,
@@ -1063,7 +1074,7 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_ROUTED1(ViewHostMsg_CrashedPlugin,
FilePath /* plugin_path */)
- // Dsiplays a JavaScript out-of-memory message in the infobar.
+ // Displays a JavaScript out-of-memory message in the infobar.
IPC_MESSAGE_ROUTED0(ViewHostMsg_JSOutOfMemory)
// Displays a box to confirm that the user wants to navigate away from the
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 1011647..6ed31e2 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -297,6 +297,12 @@ void RenderView::Init(gfx::NativeViewId parent_hwnd,
MessageLoop::current());
webwidget_ = WebView::Create(this, webkit_prefs);
+#if defined(OS_LINUX)
+ // We have to enable ourselves as the editor delegate on linux so we can copy
+ // text selections to the X clipboard.
+ webview()->SetUseEditorDelegate(true);
+#endif
+
// Don't let WebCore keep a B/F list - we have our own.
// We let it keep 1 entry because FrameLoader::goToItem expects an item in the
// backForwardList, which is used only in ASSERTs.
@@ -425,6 +431,7 @@ void RenderView::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_HandleExtensionMessage,
OnHandleExtensionMessage)
IPC_MESSAGE_HANDLER(ViewMsg_ExtensionResponse, OnExtensionResponse)
+ IPC_MESSAGE_HANDLER(ViewMsg_RequestSelectionText, OnRequestSelectionText)
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(RenderWidget::OnMessageReceived(message))
@@ -454,6 +461,10 @@ void RenderView::SendThumbnail() {
Send(new ViewHostMsg_Thumbnail(routing_id_, url, score, thumbnail));
}
+void RenderView::OnRequestSelectionText() {
+ Send(new ViewHostMsg_SetSelectionText(routing_id_, selection_text_));
+}
+
void RenderView::PrintPage(const ViewMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
WebFrame* frame) {
@@ -2422,6 +2433,17 @@ void RenderView::SetTooltipText(WebView* webview,
Send(new ViewHostMsg_SetTooltipText(routing_id_, tooltip_text));
}
+void RenderView::DidChangeSelection(bool is_empty_selection) {
+#if defined(OS_LINUX)
+ if (!is_empty_selection) {
+ // TODO(estade): find a way to incrementally update the selection text.
+ selection_text_ = webview()->GetMainFrame()->GetSelection(false);
+ Send(new ViewHostMsg_SelectionChanged(routing_id_));
+ }
+#endif
+}
+
+
void RenderView::DownloadUrl(const GURL& url, const GURL& referrer) {
Send(new ViewHostMsg_DownloadUrl(routing_id_, url, referrer));
}
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 7f20d60..25692f2 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -280,6 +280,9 @@ class RenderView : public RenderWidget,
virtual void OnNavStateChanged(WebView* webview);
virtual void SetTooltipText(WebView* webview,
const std::wstring& tooltip_text);
+ // Called when the text selection changed. This is only called on linux since
+ // on other platforms the RenderView doesn't act as an editor client delegate.
+ virtual void DidChangeSelection(bool is_empty_selection);
virtual void DownloadUrl(const GURL& url, const GURL& referrer);
@@ -593,6 +596,9 @@ class RenderView : public RenderWidget,
void OnHandleExtensionMessage(const std::string& message, int channel_id);
+ // Sends the selection text to the browser.
+ void OnRequestSelectionText();
+
// Prints the page listed in |params|.
void PrintPage(const ViewMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
@@ -815,6 +821,10 @@ class RenderView : public RenderWidget,
// Maps pending callback IDs to their frames.
IDMap<WebFrame> pending_extension_callbacks_;
+ // The currently selected text. This is currently only updated on Linux, where
+ // it's for the selection clipboard.
+ std::string selection_text_;
+
DISALLOW_COPY_AND_ASSIGN(RenderView);
};