OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "views/widget/widget_gtk.h" | 5 #include "views/widget/widget_gtk.h" |
6 | 6 |
7 #include <gdk/gdk.h> | 7 #include <gdk/gdk.h> |
8 #include <gdk/gdkx.h> | 8 #include <gdk/gdkx.h> |
9 #include <X11/extensions/shape.h> | 9 #include <X11/extensions/shape.h> |
10 | 10 |
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
487 void WidgetGtk::Init(GtkWidget* parent, | 487 void WidgetGtk::Init(GtkWidget* parent, |
488 const gfx::Rect& bounds) { | 488 const gfx::Rect& bounds) { |
489 Widget::Init(parent, bounds); | 489 Widget::Init(parent, bounds); |
490 if (type_ != TYPE_CHILD) | 490 if (type_ != TYPE_CHILD) |
491 ActiveWindowWatcherX::AddObserver(this); | 491 ActiveWindowWatcherX::AddObserver(this); |
492 | 492 |
493 // Make container here. | 493 // Make container here. |
494 CreateGtkWidget(parent, bounds); | 494 CreateGtkWidget(parent, bounds); |
495 delegate_->OnNativeWidgetCreated(); | 495 delegate_->OnNativeWidgetCreated(); |
496 | 496 |
497 // Creates input method for toplevel widget after calling | |
498 // delegate_->OnNativeWidgetCreated(), to make sure that focus manager is | |
499 // already created at this point. | |
500 if (type_ != TYPE_CHILD) { | |
501 input_method_.reset(new InputMethodGtk(this)); | |
502 input_method_->Init(GetWidget()); | |
503 } | |
504 | |
497 if (opacity_ != 255) | 505 if (opacity_ != 255) |
498 SetOpacity(opacity_); | 506 SetOpacity(opacity_); |
499 | 507 |
500 // Make sure we receive our motion events. | 508 // Make sure we receive our motion events. |
501 | 509 |
502 // In general we register most events on the parent of all widgets. At a | 510 // In general we register most events on the parent of all widgets. At a |
503 // minimum we need painting to happen on the parent (otherwise painting | 511 // minimum we need painting to happen on the parent (otherwise painting |
504 // doesn't work at all), and similarly we need mouse release events on the | 512 // doesn't work at all), and similarly we need mouse release events on the |
505 // parent as windows don't get mouse releases. | 513 // parent as windows don't get mouse releases. |
506 gtk_widget_add_events(window_contents_, | 514 gtk_widget_add_events(window_contents_, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
551 G_CALLBACK(&OnShowThunk), this); | 559 G_CALLBACK(&OnShowThunk), this); |
552 g_signal_connect(widget_, "map", | 560 g_signal_connect(widget_, "map", |
553 G_CALLBACK(&OnMapThunk), this); | 561 G_CALLBACK(&OnMapThunk), this); |
554 g_signal_connect(widget_, "hide", | 562 g_signal_connect(widget_, "hide", |
555 G_CALLBACK(&OnHideThunk), this); | 563 G_CALLBACK(&OnHideThunk), this); |
556 | 564 |
557 // Views/FocusManager (re)sets the focus to the root window, | 565 // Views/FocusManager (re)sets the focus to the root window, |
558 // so we need to connect signal handlers to the gtk window. | 566 // so we need to connect signal handlers to the gtk window. |
559 // See views::Views::Focus and views::FocusManager::ClearNativeFocus | 567 // See views::Views::Focus and views::FocusManager::ClearNativeFocus |
560 // for more details. | 568 // for more details. |
561 g_signal_connect(widget_, "key_press_event", | 569 // Child Widget should never get keyboard focus. |
562 G_CALLBACK(&OnKeyEventThunk), this); | 570 if (type_ != TYPE_CHILD) { |
563 g_signal_connect(widget_, "key_release_event", | 571 g_signal_connect(widget_, "key_press_event", |
564 G_CALLBACK(&OnKeyEventThunk), this); | 572 G_CALLBACK(&OnKeyEventThunk), this); |
573 g_signal_connect(widget_, "key_release_event", | |
574 G_CALLBACK(&OnKeyEventThunk), this); | |
575 } | |
565 | 576 |
566 // Drag and drop. | 577 // Drag and drop. |
567 gtk_drag_dest_set(window_contents_, static_cast<GtkDestDefaults>(0), | 578 gtk_drag_dest_set(window_contents_, static_cast<GtkDestDefaults>(0), |
568 NULL, 0, GDK_ACTION_COPY); | 579 NULL, 0, GDK_ACTION_COPY); |
569 g_signal_connect(window_contents_, "drag_motion", | 580 g_signal_connect(window_contents_, "drag_motion", |
570 G_CALLBACK(&OnDragMotionThunk), this); | 581 G_CALLBACK(&OnDragMotionThunk), this); |
571 g_signal_connect(window_contents_, "drag_data_received", | 582 g_signal_connect(window_contents_, "drag_data_received", |
572 G_CALLBACK(&OnDragDataReceivedThunk), this); | 583 G_CALLBACK(&OnDragDataReceivedThunk), this); |
573 g_signal_connect(window_contents_, "drag_drop", | 584 g_signal_connect(window_contents_, "drag_drop", |
574 G_CALLBACK(&OnDragDropThunk), this); | 585 G_CALLBACK(&OnDragDropThunk), this); |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
735 if (HasNativeCapture()) | 746 if (HasNativeCapture()) |
736 gtk_grab_remove(window_contents_); | 747 gtk_grab_remove(window_contents_); |
737 } | 748 } |
738 | 749 |
739 bool WidgetGtk::HasNativeCapture() const { | 750 bool WidgetGtk::HasNativeCapture() const { |
740 // TODO(beng): Should be able to use gtk_widget_has_grab() here but the | 751 // TODO(beng): Should be able to use gtk_widget_has_grab() here but the |
741 // trybots don't have Gtk 2.18. | 752 // trybots don't have Gtk 2.18. |
742 return GTK_WIDGET_HAS_GRAB(window_contents_); | 753 return GTK_WIDGET_HAS_GRAB(window_contents_); |
743 } | 754 } |
744 | 755 |
756 InputMethod* WidgetGtk::GetInputMethodNative() { | |
757 return input_method_.get(); | |
758 } | |
759 | |
760 void WidgetGtk::ReplaceInputMethod(InputMethod* input_method) { | |
761 input_method_.reset(input_method); | |
762 if (input_method) { | |
763 input_method->set_delegate(this); | |
764 input_method->Init(GetWidget()); | |
765 } | |
766 } | |
767 | |
745 gfx::Rect WidgetGtk::GetWindowScreenBounds() const { | 768 gfx::Rect WidgetGtk::GetWindowScreenBounds() const { |
746 // Client == Window bounds on Gtk. | 769 // Client == Window bounds on Gtk. |
747 return GetClientAreaScreenBounds(); | 770 return GetClientAreaScreenBounds(); |
748 } | 771 } |
749 | 772 |
750 gfx::Rect WidgetGtk::GetClientAreaScreenBounds() const { | 773 gfx::Rect WidgetGtk::GetClientAreaScreenBounds() const { |
751 // Due to timing we can get a request for bounds after Close(). | 774 // Due to timing we can get a request for bounds after Close(). |
752 // TODO(beng): Figure out if this is bogus. | 775 // TODO(beng): Figure out if this is bogus. |
753 if (!widget_) | 776 if (!widget_) |
754 return gfx::Rect(size_); | 777 return gfx::Rect(size_); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
830 if (close_widget_factory_.empty()) { | 853 if (close_widget_factory_.empty()) { |
831 // And we delay the close just in case we're on the stack. | 854 // And we delay the close just in case we're on the stack. |
832 MessageLoop::current()->PostTask(FROM_HERE, | 855 MessageLoop::current()->PostTask(FROM_HERE, |
833 close_widget_factory_.NewRunnableMethod( | 856 close_widget_factory_.NewRunnableMethod( |
834 &WidgetGtk::CloseNow)); | 857 &WidgetGtk::CloseNow)); |
835 } | 858 } |
836 } | 859 } |
837 | 860 |
838 void WidgetGtk::CloseNow() { | 861 void WidgetGtk::CloseNow() { |
839 if (widget_) { | 862 if (widget_) { |
863 input_method_.reset(); | |
840 gtk_widget_destroy(widget_); // Triggers OnDestroy(). | 864 gtk_widget_destroy(widget_); // Triggers OnDestroy(). |
841 } | 865 } |
842 } | 866 } |
843 | 867 |
844 void WidgetGtk::Show() { | 868 void WidgetGtk::Show() { |
845 if (widget_) { | 869 if (widget_) { |
846 gtk_widget_show(widget_); | 870 gtk_widget_show(widget_); |
847 if (widget_->window) | 871 if (widget_->window) |
848 gdk_window_raise(widget_->window); | 872 gdk_window_raise(widget_->window); |
849 } | 873 } |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1165 if (type_ == TYPE_CHILD) | 1189 if (type_ == TYPE_CHILD) |
1166 return false; | 1190 return false; |
1167 | 1191 |
1168 // The top-level window lost focus, store the focused view. | 1192 // The top-level window lost focus, store the focused view. |
1169 GetFocusManager()->StoreFocusedView(); | 1193 GetFocusManager()->StoreFocusedView(); |
1170 return false; | 1194 return false; |
1171 } | 1195 } |
1172 | 1196 |
1173 gboolean WidgetGtk::OnKeyEvent(GtkWidget* widget, GdkEventKey* event) { | 1197 gboolean WidgetGtk::OnKeyEvent(GtkWidget* widget, GdkEventKey* event) { |
1174 KeyEvent key(reinterpret_cast<NativeEvent>(event)); | 1198 KeyEvent key(reinterpret_cast<NativeEvent>(event)); |
1199 if (input_method_.get()) | |
1200 input_method_->DispatchKeyEvent(key); | |
1201 else | |
1202 DispatchKeyEventPostIME(key); | |
sadrul
2011/03/21 19:57:45
return DispatchKeyEventPostIME(key);
James Su
2011/03/21 21:34:07
It's intentionally to always return true to preven
| |
1175 | 1203 |
1176 // Always reset |should_handle_menu_key_release_| unless we are handling a | 1204 // Returns true to prevent GtkWindow's default key event handler. |
1177 // VKEY_MENU key release event. It ensures that VKEY_MENU accelerator can only | 1205 return true; |
1178 // be activated when handling a VKEY_MENU key release event which is preceded | |
1179 // by an unhandled VKEY_MENU key press event. See also HandleKeyboardEvent(). | |
1180 if (key.key_code() != ui::VKEY_MENU || event->type != GDK_KEY_RELEASE) | |
1181 should_handle_menu_key_release_ = false; | |
1182 | |
1183 bool handled = false; | |
1184 | |
1185 // Dispatch the key event to View hierarchy first. | |
1186 handled = GetRootView()->ProcessKeyEvent(key); | |
1187 | |
1188 // Dispatch the key event to native GtkWidget hierarchy. | |
1189 // To prevent GtkWindow from handling the key event as a keybinding, we need | |
1190 // to bypass GtkWindow's default key event handler and dispatch the event | |
1191 // here. | |
1192 if (!handled && GTK_IS_WINDOW(widget)) | |
1193 handled = gtk_window_propagate_key_event(GTK_WINDOW(widget), event); | |
1194 | |
1195 // On Linux, in order to handle VKEY_MENU (Alt) accelerator key correctly and | |
1196 // avoid issues like: http://crbug.com/40966 and http://crbug.com/49701, we | |
1197 // should only send the key event to the focus manager if it's not handled by | |
1198 // any View or native GtkWidget. | |
1199 // The flow is different when the focus is in a RenderWidgetHostViewGtk, which | |
1200 // always consumes the key event and send it back to us later by calling | |
1201 // HandleKeyboardEvent() directly, if it's not handled by webkit. | |
1202 if (!handled) | |
1203 handled = HandleKeyboardEvent(event); | |
1204 | |
1205 // Dispatch the key event for bindings processing. | |
1206 if (!handled && GTK_IS_WINDOW(widget)) | |
1207 handled = gtk_bindings_activate_event(GTK_OBJECT(widget), event); | |
1208 | |
1209 // Always return true for toplevel window to prevents GtkWindow's default key | |
1210 // event handler. | |
1211 return GTK_IS_WINDOW(widget) ? true : handled; | |
1212 } | 1206 } |
1213 | 1207 |
1214 gboolean WidgetGtk::OnQueryTooltip(GtkWidget* widget, | 1208 gboolean WidgetGtk::OnQueryTooltip(GtkWidget* widget, |
1215 gint x, | 1209 gint x, |
1216 gint y, | 1210 gint y, |
1217 gboolean keyboard_mode, | 1211 gboolean keyboard_mode, |
1218 GtkTooltip* tooltip) { | 1212 GtkTooltip* tooltip) { |
1219 return tooltip_manager_->ShowTooltip(x, y, keyboard_mode, tooltip); | 1213 return tooltip_manager_->ShowTooltip(x, y, keyboard_mode, tooltip); |
1220 } | 1214 } |
1221 | 1215 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1281 | 1275 |
1282 RootView* WidgetGtk::CreateRootView() { | 1276 RootView* WidgetGtk::CreateRootView() { |
1283 return new RootView(this); | 1277 return new RootView(this); |
1284 } | 1278 } |
1285 | 1279 |
1286 gfx::AcceleratedWidget WidgetGtk::GetAcceleratedWidget() { | 1280 gfx::AcceleratedWidget WidgetGtk::GetAcceleratedWidget() { |
1287 DCHECK(window_contents_ && window_contents_->window); | 1281 DCHECK(window_contents_ && window_contents_->window); |
1288 return GDK_WINDOW_XID(window_contents_->window); | 1282 return GDK_WINDOW_XID(window_contents_->window); |
1289 } | 1283 } |
1290 | 1284 |
1285 void WidgetGtk::DispatchKeyEventPostIME(const KeyEvent& key) { | |
1286 // Always reset |should_handle_menu_key_release_| unless we are handling a | |
1287 // VKEY_MENU key release event. It ensures that VKEY_MENU accelerator can only | |
1288 // be activated when handling a VKEY_MENU key release event which is preceded | |
1289 // by an unhandled VKEY_MENU key press event. See also HandleKeyboardEvent(). | |
1290 if (key.key_code() != ui::VKEY_MENU || key.type() != ui::ET_KEY_RELEASED) | |
1291 should_handle_menu_key_release_ = false; | |
1292 | |
1293 bool handled = false; | |
1294 | |
1295 // Dispatch the key event to View hierarchy first. | |
1296 handled = GetRootView()->ProcessKeyEvent(key); | |
1297 | |
1298 GdkEventKey* event = reinterpret_cast<GdkEventKey*>(key.native_event()); | |
1299 if (key.key_code() == ui::VKEY_PROCESSKEY || handled || !event) | |
1300 return; | |
1301 | |
1302 // Dispatch the key event to native GtkWidget hierarchy. | |
1303 // To prevent GtkWindow from handling the key event as a keybinding, we need | |
1304 // to bypass GtkWindow's default key event handler and dispatch the event | |
1305 // here. | |
1306 if (!handled && GTK_IS_WINDOW(widget_)) | |
1307 handled = gtk_window_propagate_key_event(GTK_WINDOW(widget_), event); | |
1308 | |
1309 // On Linux, in order to handle VKEY_MENU (Alt) accelerator key correctly and | |
1310 // avoid issues like: http://crbug.com/40966 and http://crbug.com/49701, we | |
1311 // should only send the key event to the focus manager if it's not handled by | |
1312 // any View or native GtkWidget. | |
1313 // The flow is different when the focus is in a RenderWidgetHostViewGtk, which | |
1314 // always consumes the key event and send it back to us later by calling | |
1315 // HandleKeyboardEvent() directly, if it's not handled by webkit. | |
1316 if (!handled) | |
1317 handled = HandleKeyboardEvent(event); | |
1318 | |
1319 // Dispatch the key event for bindings processing. | |
1320 if (!handled && GTK_IS_WINDOW(widget_)) | |
1321 handled = gtk_bindings_activate_event(GTK_OBJECT(widget_), event); | |
1322 } | |
sadrul
2011/03/21 19:57:45
return GTK_IS_WINDOW(widget) ? true : handled;
James Su
2011/03/21 21:34:07
See my comment in OnKeyEvent().
| |
1323 | |
1291 gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { | 1324 gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { |
1292 // Clear the background to be totally transparent. We don't need to | 1325 // Clear the background to be totally transparent. We don't need to |
1293 // paint the root view here as that is done by OnPaint. | 1326 // paint the root view here as that is done by OnPaint. |
1294 DCHECK(transparent_); | 1327 DCHECK(transparent_); |
1295 DrawTransparentBackground(widget, event); | 1328 DrawTransparentBackground(widget, event); |
1296 return false; | 1329 return false; |
1297 } | 1330 } |
1298 | 1331 |
1299 bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) { | 1332 bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) { |
1300 if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { | 1333 if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1614 | 1647 |
1615 NativeWidget* native_widget = GetNativeWidgetForNativeView(native_view); | 1648 NativeWidget* native_widget = GetNativeWidgetForNativeView(native_view); |
1616 if (native_widget) | 1649 if (native_widget) |
1617 children->insert(native_widget); | 1650 children->insert(native_widget); |
1618 gtk_container_foreach(GTK_CONTAINER(native_view), | 1651 gtk_container_foreach(GTK_CONTAINER(native_view), |
1619 EnumerateChildWidgetsForNativeWidgets, | 1652 EnumerateChildWidgetsForNativeWidgets, |
1620 reinterpret_cast<gpointer>(children)); | 1653 reinterpret_cast<gpointer>(children)); |
1621 } | 1654 } |
1622 | 1655 |
1623 } // namespace views | 1656 } // namespace views |
OLD | NEW |