| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |