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

Side by Side 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, 8 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/renderer_host/render_widget_host_view_gtk.h" 5 #include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
6 6
7 #include <gtk/gtk.h> 7 #include <gtk/gtk.h>
8 #include <gdk/gdk.h> 8 #include <gdk/gdk.h>
9 #include <gdk/gdkx.h>
9 #include <cairo/cairo.h> 10 #include <cairo/cairo.h>
10 11
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "base/string_util.h" 13 #include "base/string_util.h"
13 #include "chrome/common/native_web_keyboard_event.h" 14 #include "chrome/common/native_web_keyboard_event.h"
14 #include "chrome/common/render_messages.h" 15 #include "chrome/common/render_messages.h"
15 #include "chrome/common/x11_util.h" 16 #include "chrome/common/x11_util.h"
16 #include "chrome/browser/renderer_host/backing_store.h" 17 #include "chrome/browser/renderer_host/backing_store.h"
17 #include "chrome/browser/renderer_host/render_widget_host.h" 18 #include "chrome/browser/renderer_host/render_widget_host.h"
18 #include "third_party/WebKit/WebKit/chromium/public/gtk/WebInputEventFactory.h" 19 #include "third_party/WebKit/WebKit/chromium/public/gtk/WebInputEventFactory.h"
20 #include "webkit/glue/webcursor_gtk_data.h"
19 21
20 using WebKit::WebInputEventFactory; 22 using WebKit::WebInputEventFactory;
21 23
22 namespace {
23
24 #include "webkit/glue/webcursor_gtk_data.h"
25
26 // This class is a simple convenience wrapper for Gtk functions. It has only 24 // This class is a simple convenience wrapper for Gtk functions. It has only
27 // static methods. 25 // static methods.
28 class RenderWidgetHostViewGtkWidget { 26 class RenderWidgetHostViewGtkWidget {
29 public: 27 public:
30 static GtkWidget* CreateNewWidget(RenderWidgetHostViewGtk* host_view) { 28 static GtkWidget* CreateNewWidget(RenderWidgetHostViewGtk* host_view) {
31 GtkWidget* widget = gtk_drawing_area_new(); 29 GtkWidget* widget = gtk_drawing_area_new();
32 gtk_widget_set_double_buffered(widget, FALSE); 30 gtk_widget_set_double_buffered(widget, FALSE);
33 31
34 gtk_widget_add_events(widget, GDK_EXPOSURE_MASK | 32 gtk_widget_add_events(widget, GDK_EXPOSURE_MASK |
35 GDK_POINTER_MOTION_MASK | 33 GDK_POINTER_MOTION_MASK |
36 GDK_BUTTON_PRESS_MASK | 34 GDK_BUTTON_PRESS_MASK |
37 GDK_BUTTON_RELEASE_MASK | 35 GDK_BUTTON_RELEASE_MASK |
38 GDK_KEY_PRESS_MASK | 36 GDK_KEY_PRESS_MASK |
39 GDK_KEY_RELEASE_MASK); 37 GDK_KEY_RELEASE_MASK);
40 GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS); 38 GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS);
41 39
42 g_signal_connect(widget, "configure-event", 40 g_signal_connect(widget, "configure-event",
43 G_CALLBACK(ConfigureEvent), host_view); 41 G_CALLBACK(ConfigureEvent), host_view);
44 g_signal_connect(widget, "expose-event", 42 g_signal_connect(widget, "expose-event",
45 G_CALLBACK(ExposeEvent), host_view); 43 G_CALLBACK(ExposeEvent), host_view);
46 g_signal_connect(widget, "key-press-event", 44 g_signal_connect(widget, "key-press-event",
47 G_CALLBACK(KeyPressReleaseEvent), host_view); 45 G_CALLBACK(KeyPressReleaseEvent), host_view);
48 g_signal_connect(widget, "key-release-event", 46 g_signal_connect(widget, "key-release-event",
49 G_CALLBACK(KeyPressReleaseEvent), host_view); 47 G_CALLBACK(KeyPressReleaseEvent), host_view);
50 g_signal_connect(widget, "focus-in-event", 48 g_signal_connect(widget, "focus-in-event",
51 G_CALLBACK(FocusIn), host_view); 49 G_CALLBACK(OnFocusIn), host_view);
52 g_signal_connect(widget, "focus-out-event", 50 g_signal_connect(widget, "focus-out-event",
53 G_CALLBACK(FocusOut), host_view); 51 G_CALLBACK(OnFocusOut), host_view);
54 g_signal_connect(widget, "button-press-event", 52 g_signal_connect(widget, "button-press-event",
55 G_CALLBACK(ButtonPressReleaseEvent), host_view); 53 G_CALLBACK(ButtonPressReleaseEvent), host_view);
56 g_signal_connect(widget, "button-release-event", 54 g_signal_connect(widget, "button-release-event",
57 G_CALLBACK(ButtonPressReleaseEvent), host_view); 55 G_CALLBACK(ButtonPressReleaseEvent), host_view);
58 g_signal_connect(widget, "motion-notify-event", 56 g_signal_connect(widget, "motion-notify-event",
59 G_CALLBACK(MouseMoveEvent), host_view); 57 G_CALLBACK(MouseMoveEvent), host_view);
60 g_signal_connect(widget, "scroll-event", 58 g_signal_connect(widget, "scroll-event",
61 G_CALLBACK(MouseScrollEvent), host_view); 59 G_CALLBACK(MouseScrollEvent), host_view);
62 60
61 GtkTargetList* target_list = gtk_target_list_new(NULL, 0);
62 gtk_target_list_add_text_targets(target_list, 0);
63 gint num_targets = 0;
64 GtkTargetEntry* targets = gtk_target_table_new_from_list(target_list,
65 &num_targets);
66 gtk_selection_clear_targets(widget, GDK_SELECTION_PRIMARY);
67 gtk_selection_add_targets(widget, GDK_SELECTION_PRIMARY, targets,
68 num_targets);
69 gtk_target_table_free(targets, num_targets);
70
71 // When X requests the contents of the clipboard, GTK will emit the
72 // selection_request_event signal. The default handler would then
73 // synchronously emit the selection_get signal. However, we want to
74 // respond to the selection_request_event asynchronously, so we intercept
75 // the signal in OnSelectionRequest, request the selection text from the
76 // render view, and return TRUE so the default handler won't be called. Then
77 // when we get the selection text back from the renderer in
78 // SetSelectionText() we will call manually the selection_request_event
79 // default handler.
80 g_signal_connect(widget, "selection_request_event",
81 G_CALLBACK(OnSelectionRequest), host_view);
82 g_signal_connect(widget, "selection_get",
83 G_CALLBACK(OnSelectionGet), host_view);
84
85 // In OnSelectionGet, we need to access |host_view| to get the selection
86 // text.
87 g_object_set_data(G_OBJECT(widget), "render-widget-host-view-gtk",
88 host_view);
63 return widget; 89 return widget;
64 } 90 }
65 91
66 private: 92 private:
67 static gboolean ConfigureEvent(GtkWidget* widget, GdkEventConfigure* config, 93 static gboolean ConfigureEvent(GtkWidget* widget, GdkEventConfigure* config,
68 RenderWidgetHostViewGtk* host_view) { 94 RenderWidgetHostViewGtk* host_view) {
69 host_view->GetRenderWidgetHost()->WasResized(); 95 host_view->GetRenderWidgetHost()->WasResized();
70 return FALSE; 96 return FALSE;
71 } 97 }
72 98
73 static gboolean ExposeEvent(GtkWidget* widget, GdkEventExpose* expose, 99 static gboolean ExposeEvent(GtkWidget* widget, GdkEventExpose* expose,
74 RenderWidgetHostViewGtk* host_view) { 100 RenderWidgetHostViewGtk* host_view) {
75 const gfx::Rect damage_rect(expose->area); 101 const gfx::Rect damage_rect(expose->area);
76 host_view->Paint(damage_rect); 102 host_view->Paint(damage_rect);
77 return FALSE; 103 return FALSE;
78 } 104 }
79 105
80 static gboolean KeyPressReleaseEvent(GtkWidget* widget, GdkEventKey* event, 106 static gboolean KeyPressReleaseEvent(GtkWidget* widget, GdkEventKey* event,
81 RenderWidgetHostViewGtk* host_view) { 107 RenderWidgetHostViewGtk* host_view) {
82 NativeWebKeyboardEvent wke(event); 108 NativeWebKeyboardEvent wke(event);
83 host_view->GetRenderWidgetHost()->ForwardKeyboardEvent(wke); 109 host_view->GetRenderWidgetHost()->ForwardKeyboardEvent(wke);
84 // We return TRUE because we did handle the event. If it turns out webkit 110 // We return TRUE because we did handle the event. If it turns out webkit
85 // can't handle the event, we'll deal with it in 111 // can't handle the event, we'll deal with it in
86 // RenderView::UnhandledKeyboardEvent(). 112 // RenderView::UnhandledKeyboardEvent().
87 return TRUE; 113 return TRUE;
88 } 114 }
89 115
90 static gboolean FocusIn(GtkWidget* widget, GdkEventFocus* focus, 116 static gboolean OnFocusIn(GtkWidget* widget, GdkEventFocus* focus,
91 RenderWidgetHostViewGtk* host_view) { 117 RenderWidgetHostViewGtk* host_view) {
92 host_view->GetRenderWidgetHost()->Focus(); 118 host_view->GetRenderWidgetHost()->Focus();
93 return FALSE; 119 return FALSE;
94 } 120 }
95 121
96 static gboolean FocusOut(GtkWidget* widget, GdkEventFocus* focus, 122 static gboolean OnFocusOut(GtkWidget* widget, GdkEventFocus* focus,
97 RenderWidgetHostViewGtk* host_view) { 123 RenderWidgetHostViewGtk* host_view) {
98 // Whenever we lose focus, set the cursor back to that of our parent window, 124 // Whenever we lose focus, set the cursor back to that of our parent window,
99 // which should be the default arrow. 125 // which should be the default arrow.
100 gdk_window_set_cursor(widget->window, NULL); 126 gdk_window_set_cursor(widget->window, NULL);
101 host_view->GetRenderWidgetHost()->Blur(); 127 host_view->GetRenderWidgetHost()->Blur();
102 return FALSE; 128 return FALSE;
103 } 129 }
104 130
105 static gboolean ButtonPressReleaseEvent( 131 static gboolean ButtonPressReleaseEvent(
106 GtkWidget* widget, GdkEventButton* event, 132 GtkWidget* widget, GdkEventButton* event,
(...skipping 16 matching lines...) Expand all
123 return FALSE; 149 return FALSE;
124 } 150 }
125 151
126 static gboolean MouseScrollEvent(GtkWidget* widget, GdkEventScroll* event, 152 static gboolean MouseScrollEvent(GtkWidget* widget, GdkEventScroll* event,
127 RenderWidgetHostViewGtk* host_view) { 153 RenderWidgetHostViewGtk* host_view) {
128 host_view->GetRenderWidgetHost()->ForwardWheelEvent( 154 host_view->GetRenderWidgetHost()->ForwardWheelEvent(
129 WebInputEventFactory::mouseWheelEvent(event)); 155 WebInputEventFactory::mouseWheelEvent(event));
130 return FALSE; 156 return FALSE;
131 } 157 }
132 158
159
160 static gboolean OnSelectionRequest(GtkWidget* widget,
161 GdkEventSelection* event) {
162 RenderWidgetHostViewGtk* host_view =
163 reinterpret_cast<RenderWidgetHostViewGtk*>(
164 g_object_get_data(G_OBJECT(widget), "render-widget-host-view-gtk"));
165
166 // If we already know the selection text, return FALSE to let the default
167 // handler run. Also, don't try to handle two events simultaneously,
168 // because we might end up sending the wrong |event_selection_| back to GTK.
169 if (!host_view->selection_text_.empty() ||
170 host_view->event_selection_active_)
171 return FALSE;
172
173 host_view->event_selection_ = *event;
174 host_view->event_selection_active_ = true;
175 if (host_view->selection_text_.empty())
176 host_view->RequestSelectionText();
177
178 return TRUE;
179 }
180
181 static void OnSelectionGet(GtkWidget* widget,
182 GtkSelectionData* data,
183 guint info, guint time,
184 RenderWidgetHostViewGtk* host_view) {
185 DCHECK(!host_view->selection_text_.empty() ||
186 host_view->event_selection_active_);
187
188 gtk_selection_data_set(data, data->target, 8,
189 reinterpret_cast<const guchar*>(host_view->selection_text_.c_str()),
190 host_view->selection_text_.length());
191 }
192
133 DISALLOW_IMPLICIT_CONSTRUCTORS(RenderWidgetHostViewGtkWidget); 193 DISALLOW_IMPLICIT_CONSTRUCTORS(RenderWidgetHostViewGtkWidget);
134 }; 194 };
135 195
136 gboolean OnPopupParentFocusOut(GtkWidget* parent, GdkEventFocus* focus, 196 static gboolean OnPopupParentFocusOut(GtkWidget* parent, GdkEventFocus* focus,
137 RenderWidgetHost* host) { 197 RenderWidgetHost* host) {
138 host->Shutdown(); 198 host->Shutdown();
139 return FALSE; 199 return FALSE;
140 } 200 }
141 201
142 } // namespace
143
144 // static 202 // static
145 RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( 203 RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget(
146 RenderWidgetHost* widget) { 204 RenderWidgetHost* widget) {
147 return new RenderWidgetHostViewGtk(widget); 205 return new RenderWidgetHostViewGtk(widget);
148 } 206 }
149 207
150 RenderWidgetHostViewGtk::RenderWidgetHostViewGtk(RenderWidgetHost* widget_host) 208 RenderWidgetHostViewGtk::RenderWidgetHostViewGtk(RenderWidgetHost* widget_host)
151 : host_(widget_host), 209 : host_(widget_host),
152 parent_host_view_(NULL), 210 parent_host_view_(NULL),
153 parent_(NULL), 211 parent_(NULL),
154 popup_signal_id_(0), 212 popup_signal_id_(0),
155 activatable_(true), 213 activatable_(true),
156 is_loading_(false) { 214 is_loading_(false),
215 event_selection_active_(false) {
157 host_->set_view(this); 216 host_->set_view(this);
158 } 217 }
159 218
160 RenderWidgetHostViewGtk::~RenderWidgetHostViewGtk() { 219 RenderWidgetHostViewGtk::~RenderWidgetHostViewGtk() {
161 } 220 }
162 221
163 void RenderWidgetHostViewGtk::InitAsChild() { 222 void RenderWidgetHostViewGtk::InitAsChild() {
164 view_.Own(RenderWidgetHostViewGtkWidget::CreateNewWidget(this)); 223 view_.Own(RenderWidgetHostViewGtkWidget::CreateNewWidget(this));
165 gtk_widget_show(view_.get()); 224 gtk_widget_show(view_.get());
166 } 225 }
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 } 360 }
302 361
303 void RenderWidgetHostViewGtk::SetTooltipText(const std::wstring& tooltip_text) { 362 void RenderWidgetHostViewGtk::SetTooltipText(const std::wstring& tooltip_text) {
304 if (tooltip_text.empty()) { 363 if (tooltip_text.empty()) {
305 gtk_widget_set_has_tooltip(view_.get(), FALSE); 364 gtk_widget_set_has_tooltip(view_.get(), FALSE);
306 } else { 365 } else {
307 gtk_widget_set_tooltip_text(view_.get(), WideToUTF8(tooltip_text).c_str()); 366 gtk_widget_set_tooltip_text(view_.get(), WideToUTF8(tooltip_text).c_str());
308 } 367 }
309 } 368 }
310 369
370 void RenderWidgetHostViewGtk::SelectionChanged() {
371 selection_text_.clear();
372
373 guint32 timestamp = gdk_x11_get_server_time(view_.get()->window);
374 gtk_selection_owner_set(view_.get(), GDK_SELECTION_PRIMARY, timestamp);
375 }
376
377 void RenderWidgetHostViewGtk::SetSelectionText(const std::string& text) {
378 selection_text_ = text;
379 DCHECK(event_selection_active_);
380 event_selection_active_ = false;
381 // Resume normal handling of the active selection_request_event.
382 GtkWidgetClass* klass = GTK_WIDGET_CLASS(gtk_type_class(GTK_TYPE_WIDGET));
383 klass->selection_request_event(view_.get(), &event_selection_);
384 }
385
311 BackingStore* RenderWidgetHostViewGtk::AllocBackingStore( 386 BackingStore* RenderWidgetHostViewGtk::AllocBackingStore(
312 const gfx::Size& size) { 387 const gfx::Size& size) {
313 Display* display = x11_util::GetXDisplay(); 388 Display* display = x11_util::GetXDisplay();
314 void* visual = x11_util::GetVisualFromGtkWidget(view_.get()); 389 void* visual = x11_util::GetVisualFromGtkWidget(view_.get());
315 XID root_window = x11_util::GetX11RootWindow(); 390 XID root_window = x11_util::GetX11RootWindow();
316 bool use_render = x11_util::QueryRenderSupport(display); 391 bool use_render = x11_util::QueryRenderSupport(display);
317 bool use_shared_memory = x11_util::QuerySharedMemorySupport(display); 392 bool use_shared_memory = x11_util::QuerySharedMemorySupport(display);
318 int depth = gtk_widget_get_visual(view_.get())->depth; 393 int depth = gtk_widget_get_visual(view_.get())->depth;
319 394
320 return new BackingStore(size, display, depth, visual, root_window, 395 return new BackingStore(size, display, depth, visual, root_window,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 455
381 default: 456 default:
382 gdk_cursor = gdk_cursor_new(current_cursor_.GetCursorType()); 457 gdk_cursor = gdk_cursor_new(current_cursor_.GetCursorType());
383 } 458 }
384 gdk_window_set_cursor(view_.get()->window, gdk_cursor); 459 gdk_window_set_cursor(view_.get()->window, gdk_cursor);
385 // The window now owns the cursor. 460 // The window now owns the cursor.
386 if (gdk_cursor) 461 if (gdk_cursor)
387 gdk_cursor_unref(gdk_cursor); 462 gdk_cursor_unref(gdk_cursor);
388 } 463 }
389 464
465 void RenderWidgetHostViewGtk::RequestSelectionText() {
466 host_->Send(new ViewMsg_RequestSelectionText(host_->routing_id()));
467 }
468
390 void RenderWidgetHostViewGtk::ReceivedSelectionText(GtkClipboard* clipboard, 469 void RenderWidgetHostViewGtk::ReceivedSelectionText(GtkClipboard* clipboard,
391 const gchar* text, gpointer userdata) { 470 const gchar* text, gpointer userdata) {
392 RenderWidgetHostViewGtk* host_view = 471 RenderWidgetHostViewGtk* host_view =
393 reinterpret_cast<RenderWidgetHostViewGtk*>(userdata); 472 reinterpret_cast<RenderWidgetHostViewGtk*>(userdata);
394 host_view->host_->Send(new ViewMsg_InsertText(host_view->host_->routing_id(), 473 host_view->host_->Send(new ViewMsg_InsertText(host_view->host_->routing_id(),
395 UTF8ToUTF16(text))); 474 UTF8ToUTF16(text)));
396 } 475 }
OLDNEW
« 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