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 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
497 void WidgetGtk::Init(GtkWidget* parent, | 497 void WidgetGtk::Init(GtkWidget* parent, |
498 const gfx::Rect& bounds) { | 498 const gfx::Rect& bounds) { |
499 Widget::Init(parent, bounds); | 499 Widget::Init(parent, bounds); |
500 if (type_ != TYPE_CHILD) | 500 if (type_ != TYPE_CHILD) |
501 ActiveWindowWatcherX::AddObserver(this); | 501 ActiveWindowWatcherX::AddObserver(this); |
502 | 502 |
503 // Make container here. | 503 // Make container here. |
504 CreateGtkWidget(parent, bounds); | 504 CreateGtkWidget(parent, bounds); |
505 delegate_->OnNativeWidgetCreated(); | 505 delegate_->OnNativeWidgetCreated(); |
506 | 506 |
507 // Creates input method for toplevel widget after calling | |
508 // delegate_->OnNativeWidgetCreated(), to make sure that focus manager is | |
509 // already created at this point. | |
510 if (type_ != TYPE_CHILD) { | |
511 input_method_.reset(new InputMethodGtk(this)); | |
512 input_method_->Init(GetWidget()); | |
513 } | |
514 | |
507 if (opacity_ != 255) | 515 if (opacity_ != 255) |
508 SetOpacity(opacity_); | 516 SetOpacity(opacity_); |
509 | 517 |
510 // Make sure we receive our motion events. | 518 // Make sure we receive our motion events. |
511 | 519 |
512 // In general we register most events on the parent of all widgets. At a | 520 // In general we register most events on the parent of all widgets. At a |
513 // minimum we need painting to happen on the parent (otherwise painting | 521 // minimum we need painting to happen on the parent (otherwise painting |
514 // doesn't work at all), and similarly we need mouse release events on the | 522 // doesn't work at all), and similarly we need mouse release events on the |
515 // parent as windows don't get mouse releases. | 523 // parent as windows don't get mouse releases. |
516 gtk_widget_add_events(window_contents_, | 524 gtk_widget_add_events(window_contents_, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
561 G_CALLBACK(&OnShowThunk), this); | 569 G_CALLBACK(&OnShowThunk), this); |
562 g_signal_connect(widget_, "map", | 570 g_signal_connect(widget_, "map", |
563 G_CALLBACK(&OnMapThunk), this); | 571 G_CALLBACK(&OnMapThunk), this); |
564 g_signal_connect(widget_, "hide", | 572 g_signal_connect(widget_, "hide", |
565 G_CALLBACK(&OnHideThunk), this); | 573 G_CALLBACK(&OnHideThunk), this); |
566 | 574 |
567 // Views/FocusManager (re)sets the focus to the root window, | 575 // Views/FocusManager (re)sets the focus to the root window, |
568 // so we need to connect signal handlers to the gtk window. | 576 // so we need to connect signal handlers to the gtk window. |
569 // See views::Views::Focus and views::FocusManager::ClearNativeFocus | 577 // See views::Views::Focus and views::FocusManager::ClearNativeFocus |
570 // for more details. | 578 // for more details. |
571 g_signal_connect(widget_, "key_press_event", | 579 // Child Widget should never get keyboard focus. |
572 G_CALLBACK(&OnKeyEventThunk), this); | 580 if (type_ != TYPE_CHILD) { |
573 g_signal_connect(widget_, "key_release_event", | 581 g_signal_connect(widget_, "key_press_event", |
574 G_CALLBACK(&OnKeyEventThunk), this); | 582 G_CALLBACK(&OnKeyEventThunk), this); |
583 g_signal_connect(widget_, "key_release_event", | |
584 G_CALLBACK(&OnKeyEventThunk), this); | |
585 } | |
oshima
2011/03/22 01:50:39
This may break screen locker. Can you verify?
James Su
2011/03/22 08:41:14
Hmm, according to the code, it'll break screen loc
| |
575 | 586 |
576 // Drag and drop. | 587 // Drag and drop. |
577 gtk_drag_dest_set(window_contents_, static_cast<GtkDestDefaults>(0), | 588 gtk_drag_dest_set(window_contents_, static_cast<GtkDestDefaults>(0), |
578 NULL, 0, GDK_ACTION_COPY); | 589 NULL, 0, GDK_ACTION_COPY); |
579 g_signal_connect(window_contents_, "drag_motion", | 590 g_signal_connect(window_contents_, "drag_motion", |
580 G_CALLBACK(&OnDragMotionThunk), this); | 591 G_CALLBACK(&OnDragMotionThunk), this); |
581 g_signal_connect(window_contents_, "drag_data_received", | 592 g_signal_connect(window_contents_, "drag_data_received", |
582 G_CALLBACK(&OnDragDataReceivedThunk), this); | 593 G_CALLBACK(&OnDragDataReceivedThunk), this); |
583 g_signal_connect(window_contents_, "drag_drop", | 594 g_signal_connect(window_contents_, "drag_drop", |
584 G_CALLBACK(&OnDragDropThunk), this); | 595 G_CALLBACK(&OnDragDropThunk), this); |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
745 if (HasNativeCapture()) | 756 if (HasNativeCapture()) |
746 gtk_grab_remove(window_contents_); | 757 gtk_grab_remove(window_contents_); |
747 } | 758 } |
748 | 759 |
749 bool WidgetGtk::HasNativeCapture() const { | 760 bool WidgetGtk::HasNativeCapture() const { |
750 // TODO(beng): Should be able to use gtk_widget_has_grab() here but the | 761 // TODO(beng): Should be able to use gtk_widget_has_grab() here but the |
751 // trybots don't have Gtk 2.18. | 762 // trybots don't have Gtk 2.18. |
752 return GTK_WIDGET_HAS_GRAB(window_contents_); | 763 return GTK_WIDGET_HAS_GRAB(window_contents_); |
753 } | 764 } |
754 | 765 |
766 InputMethod* WidgetGtk::GetInputMethodNative() { | |
767 return input_method_.get(); | |
768 } | |
769 | |
770 void WidgetGtk::ReplaceInputMethod(InputMethod* input_method) { | |
771 input_method_.reset(input_method); | |
772 if (input_method) { | |
773 input_method->set_delegate(this); | |
774 input_method->Init(GetWidget()); | |
775 } | |
776 } | |
777 | |
755 gfx::Rect WidgetGtk::GetWindowScreenBounds() const { | 778 gfx::Rect WidgetGtk::GetWindowScreenBounds() const { |
756 // Client == Window bounds on Gtk. | 779 // Client == Window bounds on Gtk. |
757 return GetClientAreaScreenBounds(); | 780 return GetClientAreaScreenBounds(); |
758 } | 781 } |
759 | 782 |
760 gfx::Rect WidgetGtk::GetClientAreaScreenBounds() const { | 783 gfx::Rect WidgetGtk::GetClientAreaScreenBounds() const { |
761 // Due to timing we can get a request for bounds after Close(). | 784 // Due to timing we can get a request for bounds after Close(). |
762 // TODO(beng): Figure out if this is bogus. | 785 // TODO(beng): Figure out if this is bogus. |
763 if (!widget_) | 786 if (!widget_) |
764 return gfx::Rect(size_); | 787 return gfx::Rect(size_); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
840 if (close_widget_factory_.empty()) { | 863 if (close_widget_factory_.empty()) { |
841 // And we delay the close just in case we're on the stack. | 864 // And we delay the close just in case we're on the stack. |
842 MessageLoop::current()->PostTask(FROM_HERE, | 865 MessageLoop::current()->PostTask(FROM_HERE, |
843 close_widget_factory_.NewRunnableMethod( | 866 close_widget_factory_.NewRunnableMethod( |
844 &WidgetGtk::CloseNow)); | 867 &WidgetGtk::CloseNow)); |
845 } | 868 } |
846 } | 869 } |
847 | 870 |
848 void WidgetGtk::CloseNow() { | 871 void WidgetGtk::CloseNow() { |
849 if (widget_) { | 872 if (widget_) { |
873 input_method_.reset(); | |
850 gtk_widget_destroy(widget_); // Triggers OnDestroy(). | 874 gtk_widget_destroy(widget_); // Triggers OnDestroy(). |
851 } | 875 } |
852 } | 876 } |
853 | 877 |
854 void WidgetGtk::Show() { | 878 void WidgetGtk::Show() { |
855 if (widget_) { | 879 if (widget_) { |
856 gtk_widget_show(widget_); | 880 gtk_widget_show(widget_); |
857 if (widget_->window) | 881 if (widget_->window) |
858 gdk_window_raise(widget_->window); | 882 gdk_window_raise(widget_->window); |
859 } | 883 } |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1174 | 1198 |
1175 if (type_ == TYPE_CHILD) | 1199 if (type_ == TYPE_CHILD) |
1176 return false; | 1200 return false; |
1177 | 1201 |
1178 // The top-level window lost focus, store the focused view. | 1202 // The top-level window lost focus, store the focused view. |
1179 GetFocusManager()->StoreFocusedView(); | 1203 GetFocusManager()->StoreFocusedView(); |
1180 return false; | 1204 return false; |
1181 } | 1205 } |
1182 | 1206 |
1183 gboolean WidgetGtk::OnKeyEvent(GtkWidget* widget, GdkEventKey* event) { | 1207 gboolean WidgetGtk::OnKeyEvent(GtkWidget* widget, GdkEventKey* event) { |
1208 // Only top-level Widget could be focused and receive keyboard events. | |
1209 DCHECK(GTK_IS_WINDOW(widget_)); | |
1210 | |
1184 KeyEvent key(reinterpret_cast<NativeEvent>(event)); | 1211 KeyEvent key(reinterpret_cast<NativeEvent>(event)); |
1212 if (input_method_.get()) | |
1213 input_method_->DispatchKeyEvent(key); | |
1214 else | |
1215 DispatchKeyEventPostIME(key); | |
1185 | 1216 |
1186 // Always reset |should_handle_menu_key_release_| unless we are handling a | 1217 // Returns true to prevent GtkWindow's default key event handler. |
1187 // VKEY_MENU key release event. It ensures that VKEY_MENU accelerator can only | 1218 return true; |
1188 // be activated when handling a VKEY_MENU key release event which is preceded | |
1189 // by an unhandled VKEY_MENU key press event. See also HandleKeyboardEvent(). | |
1190 if (key.key_code() != ui::VKEY_MENU || event->type != GDK_KEY_RELEASE) | |
1191 should_handle_menu_key_release_ = false; | |
1192 | |
1193 bool handled = false; | |
1194 | |
1195 // Dispatch the key event to View hierarchy first. | |
1196 handled = GetRootView()->ProcessKeyEvent(key); | |
1197 | |
1198 // Dispatch the key event to native GtkWidget hierarchy. | |
1199 // To prevent GtkWindow from handling the key event as a keybinding, we need | |
1200 // to bypass GtkWindow's default key event handler and dispatch the event | |
1201 // here. | |
1202 if (!handled && GTK_IS_WINDOW(widget)) | |
1203 handled = gtk_window_propagate_key_event(GTK_WINDOW(widget), event); | |
1204 | |
1205 // On Linux, in order to handle VKEY_MENU (Alt) accelerator key correctly and | |
1206 // avoid issues like: http://crbug.com/40966 and http://crbug.com/49701, we | |
1207 // should only send the key event to the focus manager if it's not handled by | |
1208 // any View or native GtkWidget. | |
1209 // The flow is different when the focus is in a RenderWidgetHostViewGtk, which | |
1210 // always consumes the key event and send it back to us later by calling | |
1211 // HandleKeyboardEvent() directly, if it's not handled by webkit. | |
1212 if (!handled) | |
1213 handled = HandleKeyboardEvent(event); | |
1214 | |
1215 // Dispatch the key event for bindings processing. | |
1216 if (!handled && GTK_IS_WINDOW(widget)) | |
1217 handled = gtk_bindings_activate_event(GTK_OBJECT(widget), event); | |
1218 | |
1219 // Always return true for toplevel window to prevents GtkWindow's default key | |
1220 // event handler. | |
1221 return GTK_IS_WINDOW(widget) ? true : handled; | |
1222 } | 1219 } |
1223 | 1220 |
1224 gboolean WidgetGtk::OnQueryTooltip(GtkWidget* widget, | 1221 gboolean WidgetGtk::OnQueryTooltip(GtkWidget* widget, |
1225 gint x, | 1222 gint x, |
1226 gint y, | 1223 gint y, |
1227 gboolean keyboard_mode, | 1224 gboolean keyboard_mode, |
1228 GtkTooltip* tooltip) { | 1225 GtkTooltip* tooltip) { |
1229 return tooltip_manager_->ShowTooltip(x, y, keyboard_mode, tooltip); | 1226 return tooltip_manager_->ShowTooltip(x, y, keyboard_mode, tooltip); |
1230 } | 1227 } |
1231 | 1228 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1291 | 1288 |
1292 RootView* WidgetGtk::CreateRootView() { | 1289 RootView* WidgetGtk::CreateRootView() { |
1293 return new RootView(this); | 1290 return new RootView(this); |
1294 } | 1291 } |
1295 | 1292 |
1296 gfx::AcceleratedWidget WidgetGtk::GetAcceleratedWidget() { | 1293 gfx::AcceleratedWidget WidgetGtk::GetAcceleratedWidget() { |
1297 DCHECK(window_contents_ && window_contents_->window); | 1294 DCHECK(window_contents_ && window_contents_->window); |
1298 return GDK_WINDOW_XID(window_contents_->window); | 1295 return GDK_WINDOW_XID(window_contents_->window); |
1299 } | 1296 } |
1300 | 1297 |
1298 void WidgetGtk::DispatchKeyEventPostIME(const KeyEvent& key) { | |
1299 // Only top-level Widget could be focused and receive keyboard events. | |
1300 DCHECK(GTK_IS_WINDOW(widget_)); | |
1301 | |
1302 // Always reset |should_handle_menu_key_release_| unless we are handling a | |
1303 // VKEY_MENU key release event. It ensures that VKEY_MENU accelerator can only | |
1304 // be activated when handling a VKEY_MENU key release event which is preceded | |
1305 // by an unhandled VKEY_MENU key press event. See also HandleKeyboardEvent(). | |
1306 if (key.key_code() != ui::VKEY_MENU || key.type() != ui::ET_KEY_RELEASED) | |
1307 should_handle_menu_key_release_ = false; | |
1308 | |
1309 bool handled = false; | |
1310 | |
1311 // Dispatch the key event to View hierarchy first. | |
1312 handled = GetRootView()->ProcessKeyEvent(key); | |
1313 | |
1314 GdkEventKey* event = reinterpret_cast<GdkEventKey*>(key.native_event()); | |
1315 if (key.key_code() == ui::VKEY_PROCESSKEY || handled || !event) | |
1316 return; | |
1317 | |
1318 // Dispatch the key event to native GtkWidget hierarchy. | |
1319 // To prevent GtkWindow from handling the key event as a keybinding, we need | |
1320 // to bypass GtkWindow's default key event handler and dispatch the event | |
1321 // here. | |
1322 if (!handled && GTK_IS_WINDOW(widget_)) | |
1323 handled = gtk_window_propagate_key_event(GTK_WINDOW(widget_), event); | |
1324 | |
1325 // On Linux, in order to handle VKEY_MENU (Alt) accelerator key correctly and | |
1326 // avoid issues like: http://crbug.com/40966 and http://crbug.com/49701, we | |
1327 // should only send the key event to the focus manager if it's not handled by | |
1328 // any View or native GtkWidget. | |
1329 // The flow is different when the focus is in a RenderWidgetHostViewGtk, which | |
1330 // always consumes the key event and send it back to us later by calling | |
1331 // HandleKeyboardEvent() directly, if it's not handled by webkit. | |
1332 if (!handled) | |
1333 handled = HandleKeyboardEvent(event); | |
1334 | |
1335 // Dispatch the key event for bindings processing. | |
1336 if (!handled && GTK_IS_WINDOW(widget_)) | |
1337 gtk_bindings_activate_event(GTK_OBJECT(widget_), event); | |
1338 } | |
1339 | |
1301 gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { | 1340 gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { |
1302 // Clear the background to be totally transparent. We don't need to | 1341 // Clear the background to be totally transparent. We don't need to |
1303 // paint the root view here as that is done by OnPaint. | 1342 // paint the root view here as that is done by OnPaint. |
1304 DCHECK(transparent_); | 1343 DCHECK(transparent_); |
1305 DrawTransparentBackground(widget, event); | 1344 DrawTransparentBackground(widget, event); |
1306 return false; | 1345 return false; |
1307 } | 1346 } |
1308 | 1347 |
1309 bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) { | 1348 bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) { |
1310 if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { | 1349 if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { |
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1617 | 1656 |
1618 NativeWidget* native_widget = GetNativeWidgetForNativeView(native_view); | 1657 NativeWidget* native_widget = GetNativeWidgetForNativeView(native_view); |
1619 if (native_widget) | 1658 if (native_widget) |
1620 children->insert(native_widget); | 1659 children->insert(native_widget); |
1621 gtk_container_foreach(GTK_CONTAINER(native_view), | 1660 gtk_container_foreach(GTK_CONTAINER(native_view), |
1622 EnumerateChildWidgetsForNativeWidgets, | 1661 EnumerateChildWidgetsForNativeWidgets, |
1623 reinterpret_cast<gpointer>(children)); | 1662 reinterpret_cast<gpointer>(children)); |
1624 } | 1663 } |
1625 | 1664 |
1626 } // namespace views | 1665 } // namespace views |
OLD | NEW |