Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Unified Diff: chrome/browser/renderer_host/render_widget_host_view_gtk.cc

Issue 55052: Copy selection to x clipboard. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/renderer_host/render_widget_host_view_gtk.cc
===================================================================
--- chrome/browser/renderer_host/render_widget_host_view_gtk.cc (revision 13031)
+++ chrome/browser/renderer_host/render_widget_host_view_gtk.cc (working copy)
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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::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 @@
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 =
« no previous file with comments | « chrome/browser/renderer_host/render_widget_host_view_gtk.h ('k') | chrome/common/render_messages_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698