| 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/gdkkeysyms.h> | 9 #include <gdk/gdkkeysyms.h> | 
| 10 #include <gdk/gdkx.h> | 10 #include <gdk/gdkx.h> | 
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 64                      G_CALLBACK(OnFocusOut), host_view); | 64                      G_CALLBACK(OnFocusOut), host_view); | 
| 65     g_signal_connect(widget, "button-press-event", | 65     g_signal_connect(widget, "button-press-event", | 
| 66                      G_CALLBACK(ButtonPressReleaseEvent), host_view); | 66                      G_CALLBACK(ButtonPressReleaseEvent), host_view); | 
| 67     g_signal_connect(widget, "button-release-event", | 67     g_signal_connect(widget, "button-release-event", | 
| 68                      G_CALLBACK(ButtonPressReleaseEvent), host_view); | 68                      G_CALLBACK(ButtonPressReleaseEvent), host_view); | 
| 69     g_signal_connect(widget, "motion-notify-event", | 69     g_signal_connect(widget, "motion-notify-event", | 
| 70                      G_CALLBACK(MouseMoveEvent), host_view); | 70                      G_CALLBACK(MouseMoveEvent), host_view); | 
| 71     g_signal_connect(widget, "scroll-event", | 71     g_signal_connect(widget, "scroll-event", | 
| 72                      G_CALLBACK(MouseScrollEvent), host_view); | 72                      G_CALLBACK(MouseScrollEvent), host_view); | 
| 73 | 73 | 
|  | 74     // Create a GtkIMContext instance and attach its signal handlers. | 
|  | 75     host_view->im_context_ = gtk_im_multicontext_new(); | 
|  | 76     g_signal_connect(host_view->im_context_, "preedit_start", | 
|  | 77                      G_CALLBACK(InputMethodPreeditStart), host_view); | 
|  | 78     g_signal_connect(host_view->im_context_, "preedit_end", | 
|  | 79                      G_CALLBACK(InputMethodPreeditEnd), host_view); | 
|  | 80     g_signal_connect(host_view->im_context_, "preedit_changed", | 
|  | 81                      G_CALLBACK(InputMethodPreeditChanged), host_view); | 
|  | 82     g_signal_connect(host_view->im_context_, "commit", | 
|  | 83                      G_CALLBACK(InputMethodCommit), host_view); | 
|  | 84 | 
| 74     GtkTargetList* target_list = gtk_target_list_new(NULL, 0); | 85     GtkTargetList* target_list = gtk_target_list_new(NULL, 0); | 
| 75     gtk_target_list_add_text_targets(target_list, 0); | 86     gtk_target_list_add_text_targets(target_list, 0); | 
| 76     gint num_targets = 0; | 87     gint num_targets = 0; | 
| 77     GtkTargetEntry* targets = gtk_target_table_new_from_list(target_list, | 88     GtkTargetEntry* targets = gtk_target_table_new_from_list(target_list, | 
| 78                                                              &num_targets); | 89                                                              &num_targets); | 
| 79     gtk_selection_clear_targets(widget, GDK_SELECTION_PRIMARY); | 90     gtk_selection_clear_targets(widget, GDK_SELECTION_PRIMARY); | 
| 80     gtk_selection_add_targets(widget, GDK_SELECTION_PRIMARY, targets, | 91     gtk_selection_add_targets(widget, GDK_SELECTION_PRIMARY, targets, | 
| 81                               num_targets); | 92                               num_targets); | 
| 82     gtk_target_list_unref(target_list); | 93     gtk_target_list_unref(target_list); | 
| 83     gtk_target_table_free(targets, num_targets); | 94     gtk_target_table_free(targets, num_targets); | 
| (...skipping 18 matching lines...) Expand all  Loading... | 
| 102                                        RenderWidgetHostViewGtk* host_view) { | 113                                        RenderWidgetHostViewGtk* host_view) { | 
| 103     if (host_view->parent_ && host_view->activatable() && | 114     if (host_view->parent_ && host_view->activatable() && | 
| 104         GDK_Escape == event->keyval) { | 115         GDK_Escape == event->keyval) { | 
| 105       // Force popups to close on Esc just in case the renderer is hung.  This | 116       // Force popups to close on Esc just in case the renderer is hung.  This | 
| 106       // allows us to release our keyboard grab. | 117       // allows us to release our keyboard grab. | 
| 107       host_view->host_->Shutdown(); | 118       host_view->host_->Shutdown(); | 
| 108     } else { | 119     } else { | 
| 109       NativeWebKeyboardEvent wke(event); | 120       NativeWebKeyboardEvent wke(event); | 
| 110       host_view->GetRenderWidgetHost()->ForwardKeyboardEvent(wke); | 121       host_view->GetRenderWidgetHost()->ForwardKeyboardEvent(wke); | 
| 111     } | 122     } | 
|  | 123 | 
|  | 124     // Dispatch this event to the GtkIMContext object. | 
|  | 125     // It sends a "commit" signal when it has a character to be inserted | 
|  | 126     // even when we use a US keyboard so that we can send a Char event | 
|  | 127     // (or an IME event) to the renderer in our "commit"-signal handler. | 
|  | 128     // We should send a KeyDown (or a KeyUp) event before dispatching this | 
|  | 129     // event to the GtkIMContext object (and send a Char event) so that WebKit | 
|  | 130     // can dispatch the JavaScript events in the following order: onkeydown(), | 
|  | 131     // onkeypress(), and onkeyup(). (Many JavaScript pages assume this.) | 
|  | 132     // TODO(hbono): we should not dispatch a key event when the input focus | 
|  | 133     // is in a password input? | 
|  | 134     if (!gtk_im_context_filter_keypress(host_view->im_context_, event)) { | 
|  | 135       // The GtkIMContext object cannot handle this key event. | 
|  | 136       // This case is caused by two reasons: | 
|  | 137       // 1. The given key event is a control-key event, (e.g. return, page up, | 
|  | 138       //    page down, tab, arrows, etc.) or; | 
|  | 139       // 2. The given key event is not a control-key event but printable | 
|  | 140       //    characters aren't assigned to the event, (e.g. alt+d, etc.) | 
|  | 141       // Create a Char event manually from this key event and send it to the | 
|  | 142       // renderer only when this event is a control-key event because | 
|  | 143       // control-key events should be processed by WebKit. | 
|  | 144       // TODO(hbono): Windows Chrome sends a Char event with its isSystemKey | 
|  | 145       // value true for the above case 2. We should emulate this behavior? | 
|  | 146       if (event->type == GDK_KEY_PRESS && | 
|  | 147           !gdk_keyval_to_unicode(event->keyval)) { | 
|  | 148         NativeWebKeyboardEvent wke(event); | 
|  | 149         wke.type = WebKit::WebInputEvent::Char; | 
|  | 150         host_view->GetRenderWidgetHost()->ForwardKeyboardEvent(wke); | 
|  | 151       } | 
|  | 152     } | 
|  | 153 | 
| 112     // We return TRUE because we did handle the event. If it turns out webkit | 154     // We return TRUE because we did handle the event. If it turns out webkit | 
| 113     // can't handle the event, we'll deal with it in | 155     // can't handle the event, we'll deal with it in | 
| 114     // RenderView::UnhandledKeyboardEvent(). | 156     // RenderView::UnhandledKeyboardEvent(). | 
| 115     return TRUE; | 157     return TRUE; | 
| 116   } | 158   } | 
| 117 | 159 | 
| 118   static gboolean OnFocusIn(GtkWidget* widget, GdkEventFocus* focus, | 160   static gboolean OnFocusIn(GtkWidget* widget, GdkEventFocus* focus, | 
| 119                             RenderWidgetHostViewGtk* host_view) { | 161                             RenderWidgetHostViewGtk* host_view) { | 
| 120     int x, y; | 162     int x, y; | 
| 121     gtk_widget_get_pointer(widget, &x, &y); | 163     gtk_widget_get_pointer(widget, &x, &y); | 
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 208     return FALSE; | 250     return FALSE; | 
| 209   } | 251   } | 
| 210 | 252 | 
| 211   static gboolean MouseScrollEvent(GtkWidget* widget, GdkEventScroll* event, | 253   static gboolean MouseScrollEvent(GtkWidget* widget, GdkEventScroll* event, | 
| 212                                    RenderWidgetHostViewGtk* host_view) { | 254                                    RenderWidgetHostViewGtk* host_view) { | 
| 213     host_view->GetRenderWidgetHost()->ForwardWheelEvent( | 255     host_view->GetRenderWidgetHost()->ForwardWheelEvent( | 
| 214         WebInputEventFactory::mouseWheelEvent(event)); | 256         WebInputEventFactory::mouseWheelEvent(event)); | 
| 215     return FALSE; | 257     return FALSE; | 
| 216   } | 258   } | 
| 217 | 259 | 
|  | 260   static void InputMethodCommit(GtkIMContext* im_context, | 
|  | 261                                 gchar* text, | 
|  | 262                                 RenderWidgetHostViewGtk* host_view) { | 
|  | 263     std::wstring im_text = UTF8ToWide(text); | 
|  | 264     if (!host_view->im_is_composing_cjk_text_ && im_text.length() == 1) { | 
|  | 265       // Send a Char event when we input a composed character without IMEs so | 
|  | 266       // that this event is to be dispatched to onkeypress() handlers, | 
|  | 267       // autofill, etc. | 
|  | 268       ForwardCharEvent(host_view, im_text[0]); | 
|  | 269     } else { | 
|  | 270       // Send an IME event. | 
|  | 271       // Unlike a Char event, an IME event is NOT dispatched to onkeypress() | 
|  | 272       // handlers or autofill. | 
|  | 273       host_view->GetRenderWidgetHost()->ImeConfirmComposition(im_text); | 
|  | 274     } | 
|  | 275   } | 
|  | 276 | 
|  | 277   static void InputMethodPreeditStart(GtkIMContext* im_context, | 
|  | 278                                       RenderWidgetHostViewGtk* host_view) { | 
|  | 279     // Start monitoring IME events of the renderer. | 
|  | 280     // TODO(hbono): a renderer sends these IME events not only for sending the | 
|  | 281     // caret position, but also for enabling/disabling IMEs. If we need to | 
|  | 282     // enable/disable IMEs, we should move this code to a better place. | 
|  | 283     // (This signal handler is called only when an IME is enabled. So, once | 
|  | 284     // we disable an IME, we cannot receive any IME events from the renderer, | 
|  | 285     // i.e. we cannot re-enable the IME any longer.) | 
|  | 286     host_view->GetRenderWidgetHost()->ImeSetInputMode(true); | 
|  | 287     host_view->im_is_composing_cjk_text_ = true; | 
|  | 288   } | 
|  | 289 | 
|  | 290   static void InputMethodPreeditEnd(GtkIMContext* im_context, | 
|  | 291                                     RenderWidgetHostViewGtk* host_view) { | 
|  | 292     // End monitoring IME events. | 
|  | 293     host_view->GetRenderWidgetHost()->ImeSetInputMode(false); | 
|  | 294     host_view->im_is_composing_cjk_text_ = false; | 
|  | 295   } | 
|  | 296 | 
|  | 297   static void InputMethodPreeditChanged(GtkIMContext* im_context, | 
|  | 298                                         RenderWidgetHostViewGtk* host_view) { | 
|  | 299     // Send an IME event to update the composition node of the renderer. | 
|  | 300     // TODO(hbono): an IME intercepts all key events while composing a text, | 
|  | 301     // i.e. we cannot receive any GDK_KEY_PRESS (or GDK_KEY_UP) events. | 
|  | 302     // Should we send pseudo KeyDown (and KeyUp) events to emulate Windows? | 
|  | 303     gchar* preedit_text = NULL; | 
|  | 304     gint cursor_position = 0; | 
|  | 305     gtk_im_context_get_preedit_string(im_context, &preedit_text, NULL, | 
|  | 306                                       &cursor_position); | 
|  | 307     host_view->GetRenderWidgetHost()->ImeSetComposition( | 
|  | 308         UTF8ToWide(preedit_text), cursor_position, -1, -1); | 
|  | 309     g_free(preedit_text); | 
|  | 310   } | 
|  | 311 | 
|  | 312   static void ForwardCharEvent(RenderWidgetHostViewGtk* host_view, | 
|  | 313                                wchar_t im_character) { | 
|  | 314     if (!im_character) | 
|  | 315       return; | 
|  | 316 | 
|  | 317     NativeWebKeyboardEvent char_event(im_character, | 
|  | 318                                       base::Time::Now().ToDoubleT()); | 
|  | 319     host_view->GetRenderWidgetHost()->ForwardKeyboardEvent(char_event); | 
|  | 320   } | 
|  | 321 | 
| 218   DISALLOW_IMPLICIT_CONSTRUCTORS(RenderWidgetHostViewGtkWidget); | 322   DISALLOW_IMPLICIT_CONSTRUCTORS(RenderWidgetHostViewGtkWidget); | 
| 219 }; | 323 }; | 
| 220 | 324 | 
| 221 // static | 325 // static | 
| 222 RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( | 326 RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( | 
| 223     RenderWidgetHost* widget) { | 327     RenderWidgetHost* widget) { | 
| 224   return new RenderWidgetHostViewGtk(widget); | 328   return new RenderWidgetHostViewGtk(widget); | 
| 225 } | 329 } | 
| 226 | 330 | 
| 227 RenderWidgetHostViewGtk::RenderWidgetHostViewGtk(RenderWidgetHost* widget_host) | 331 RenderWidgetHostViewGtk::RenderWidgetHostViewGtk(RenderWidgetHost* widget_host) | 
| 228     : host_(widget_host), | 332     : host_(widget_host), | 
| 229       about_to_validate_and_paint_(false), | 333       about_to_validate_and_paint_(false), | 
| 230       is_hidden_(false), | 334       is_hidden_(false), | 
| 231       is_loading_(false), | 335       is_loading_(false), | 
| 232       is_showing_context_menu_(false), | 336       is_showing_context_menu_(false), | 
| 233       parent_host_view_(NULL), | 337       parent_host_view_(NULL), | 
| 234       parent_(NULL), | 338       parent_(NULL), | 
| 235       is_popup_first_mouse_release_(true) { | 339       is_popup_first_mouse_release_(true), | 
|  | 340       im_context_(NULL), | 
|  | 341       im_is_composing_cjk_text_(false) { | 
| 236   host_->set_view(this); | 342   host_->set_view(this); | 
| 237 } | 343 } | 
| 238 | 344 | 
| 239 RenderWidgetHostViewGtk::~RenderWidgetHostViewGtk() { | 345 RenderWidgetHostViewGtk::~RenderWidgetHostViewGtk() { | 
|  | 346   if (im_context_) | 
|  | 347     g_object_unref(im_context_); | 
| 240   view_.Destroy(); | 348   view_.Destroy(); | 
| 241 } | 349 } | 
| 242 | 350 | 
| 243 void RenderWidgetHostViewGtk::InitAsChild() { | 351 void RenderWidgetHostViewGtk::InitAsChild() { | 
| 244   view_.Own(RenderWidgetHostViewGtkWidget::CreateNewWidget(this)); | 352   view_.Own(RenderWidgetHostViewGtkWidget::CreateNewWidget(this)); | 
| 245   gtk_widget_show(view_.get()); | 353   gtk_widget_show(view_.get()); | 
| 246 } | 354 } | 
| 247 | 355 | 
| 248 void RenderWidgetHostViewGtk::InitAsPopup( | 356 void RenderWidgetHostViewGtk::InitAsPopup( | 
| 249     RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) { | 357     RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) { | 
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 389 | 497 | 
| 390 void RenderWidgetHostViewGtk::SetIsLoading(bool is_loading) { | 498 void RenderWidgetHostViewGtk::SetIsLoading(bool is_loading) { | 
| 391   is_loading_ = is_loading; | 499   is_loading_ = is_loading; | 
| 392   // Only call ShowCurrentCursor() when it will actually change the cursor. | 500   // Only call ShowCurrentCursor() when it will actually change the cursor. | 
| 393   if (current_cursor_.GetCursorType() == GDK_LAST_CURSOR) | 501   if (current_cursor_.GetCursorType() == GDK_LAST_CURSOR) | 
| 394     ShowCurrentCursor(); | 502     ShowCurrentCursor(); | 
| 395 } | 503 } | 
| 396 | 504 | 
| 397 void RenderWidgetHostViewGtk::IMEUpdateStatus(int control, | 505 void RenderWidgetHostViewGtk::IMEUpdateStatus(int control, | 
| 398                                               const gfx::Rect& caret_rect) { | 506                                               const gfx::Rect& caret_rect) { | 
| 399   NOTIMPLEMENTED(); | 507   // The renderer has updated its IME status. | 
|  | 508   // Control the GtkIMContext object according to this status. | 
|  | 509   if (!im_context_) | 
|  | 510     return; | 
|  | 511 | 
|  | 512   if (control == IME_DISABLE) { | 
|  | 513     // TODO(hbono): this code just resets the GtkIMContext object and | 
|  | 514     // detaches it from this window. Should we prevent sending key events to | 
|  | 515     // the GtkIMContext object (or unref it) when we disable IMEs? | 
|  | 516     gtk_im_context_reset(im_context_); | 
|  | 517     gtk_im_context_set_client_window(im_context_, NULL); | 
|  | 518     gtk_im_context_set_cursor_location(im_context_, NULL); | 
|  | 519   } else { | 
|  | 520     // TODO(hbono): we should finish (not reset) an ongoing composition | 
|  | 521     // when |control| is IME_COMPLETE_COMPOSITION. | 
|  | 522 | 
|  | 523     // Attach the GtkIMContext object to this window. | 
|  | 524     gtk_im_context_set_client_window(im_context_, view_.get()->window); | 
|  | 525 | 
|  | 526     // Updates the position of the IME candidate window. | 
|  | 527     // The position sent from the renderer is a relative one, so we need to | 
|  | 528     // attach the GtkIMContext object to this window before changing the | 
|  | 529     // position. | 
|  | 530     GdkRectangle cursor_rect(caret_rect.ToGdkRectangle()); | 
|  | 531     gtk_im_context_set_cursor_location(im_context_, &cursor_rect); | 
|  | 532   } | 
| 400 } | 533 } | 
| 401 | 534 | 
| 402 void RenderWidgetHostViewGtk::DidPaintRect(const gfx::Rect& rect) { | 535 void RenderWidgetHostViewGtk::DidPaintRect(const gfx::Rect& rect) { | 
| 403   if (is_hidden_) | 536   if (is_hidden_) | 
| 404     return; | 537     return; | 
| 405 | 538 | 
| 406   if (about_to_validate_and_paint_) | 539   if (about_to_validate_and_paint_) | 
| 407     invalid_rect_ = invalid_rect_.Union(rect); | 540     invalid_rect_ = invalid_rect_.Union(rect); | 
| 408   else | 541   else | 
| 409     Paint(rect); | 542     Paint(rect); | 
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 546 void RenderWidgetHostViewGtk::ReceivedSelectionText(GtkClipboard* clipboard, | 679 void RenderWidgetHostViewGtk::ReceivedSelectionText(GtkClipboard* clipboard, | 
| 547     const gchar* text, gpointer userdata) { | 680     const gchar* text, gpointer userdata) { | 
| 548   // If there's nothing to paste (|text| is NULL), do nothing. | 681   // If there's nothing to paste (|text| is NULL), do nothing. | 
| 549   if (!text) | 682   if (!text) | 
| 550     return; | 683     return; | 
| 551   RenderWidgetHostViewGtk* host_view = | 684   RenderWidgetHostViewGtk* host_view = | 
| 552       reinterpret_cast<RenderWidgetHostViewGtk*>(userdata); | 685       reinterpret_cast<RenderWidgetHostViewGtk*>(userdata); | 
| 553   host_view->host_->Send(new ViewMsg_InsertText(host_view->host_->routing_id(), | 686   host_view->host_->Send(new ViewMsg_InsertText(host_view->host_->routing_id(), | 
| 554                                                 UTF8ToUTF16(text))); | 687                                                 UTF8ToUTF16(text))); | 
| 555 } | 688 } | 
| OLD | NEW | 
|---|