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 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
285 static bool installed_message_loop_observer = false; | 285 static bool installed_message_loop_observer = false; |
286 if (!installed_message_loop_observer) { | 286 if (!installed_message_loop_observer) { |
287 installed_message_loop_observer = true; | 287 installed_message_loop_observer = true; |
288 MessageLoopForUI* loop = MessageLoopForUI::current(); | 288 MessageLoopForUI* loop = MessageLoopForUI::current(); |
289 if (loop) | 289 if (loop) |
290 loop->AddObserver(DropObserver::GetInstance()); | 290 loop->AddObserver(DropObserver::GetInstance()); |
291 } | 291 } |
292 } | 292 } |
293 | 293 |
294 WidgetGtk::~WidgetGtk() { | 294 WidgetGtk::~WidgetGtk() { |
295 // We need to delete the input method before calling DestroyRootView(), | |
296 // because it'll set focus_manager_ to NULL. | |
297 input_method_.reset(); | |
295 DestroyRootView(); | 298 DestroyRootView(); |
296 DCHECK(delete_on_destroy_ || widget_ == NULL); | 299 DCHECK(delete_on_destroy_ || widget_ == NULL); |
297 if (type_ != TYPE_CHILD) | 300 if (type_ != TYPE_CHILD) |
298 ActiveWindowWatcherX::RemoveObserver(this); | 301 ActiveWindowWatcherX::RemoveObserver(this); |
299 } | 302 } |
300 | 303 |
301 void WidgetGtk::SetCreateParams(const CreateParams& params) { | 304 void WidgetGtk::SetCreateParams(const CreateParams& params) { |
302 // Set non-style attributes. | 305 // Set non-style attributes. |
303 set_delete_on_destroy(params.delete_on_destroy); | 306 set_delete_on_destroy(params.delete_on_destroy); |
304 | 307 |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
497 void WidgetGtk::Init(GtkWidget* parent, | 500 void WidgetGtk::Init(GtkWidget* parent, |
498 const gfx::Rect& bounds) { | 501 const gfx::Rect& bounds) { |
499 Widget::Init(parent, bounds); | 502 Widget::Init(parent, bounds); |
500 if (type_ != TYPE_CHILD) | 503 if (type_ != TYPE_CHILD) |
501 ActiveWindowWatcherX::AddObserver(this); | 504 ActiveWindowWatcherX::AddObserver(this); |
502 | 505 |
503 // Make container here. | 506 // Make container here. |
504 CreateGtkWidget(parent, bounds); | 507 CreateGtkWidget(parent, bounds); |
505 delegate_->OnNativeWidgetCreated(); | 508 delegate_->OnNativeWidgetCreated(); |
506 | 509 |
510 // Creates input method for toplevel widget after calling | |
511 // delegate_->OnNativeWidgetCreated(), to make sure that focus manager is | |
512 // already created at this point. | |
513 if (type_ != TYPE_CHILD) { | |
514 input_method_.reset(new InputMethodGtk(this)); | |
515 input_method_->Init(GetWidget()); | |
516 } | |
oshima
2011/03/24 22:58:47
Looks like we create InputMethodGtk for regular ch
James Su
2011/03/25 05:57:21
Yes. I'll disable this piece of code for ChromeOS.
| |
517 | |
507 if (opacity_ != 255) | 518 if (opacity_ != 255) |
508 SetOpacity(opacity_); | 519 SetOpacity(opacity_); |
509 | 520 |
510 // Make sure we receive our motion events. | 521 // Make sure we receive our motion events. |
511 | 522 |
512 // In general we register most events on the parent of all widgets. At a | 523 // 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 | 524 // 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 | 525 // doesn't work at all), and similarly we need mouse release events on the |
515 // parent as windows don't get mouse releases. | 526 // parent as windows don't get mouse releases. |
516 gtk_widget_add_events(window_contents_, | 527 gtk_widget_add_events(window_contents_, |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
646 | 657 |
647 void WidgetGtk::ClearNativeFocus() { | 658 void WidgetGtk::ClearNativeFocus() { |
648 DCHECK(type_ != TYPE_CHILD); | 659 DCHECK(type_ != TYPE_CHILD); |
649 if (!GetNativeView()) { | 660 if (!GetNativeView()) { |
650 NOTREACHED(); | 661 NOTREACHED(); |
651 return; | 662 return; |
652 } | 663 } |
653 gtk_window_set_focus(GTK_WINDOW(GetNativeView()), NULL); | 664 gtk_window_set_focus(GTK_WINDOW(GetNativeView()), NULL); |
654 } | 665 } |
655 | 666 |
656 bool WidgetGtk::HandleKeyboardEvent(GdkEventKey* event) { | 667 bool WidgetGtk::HandleKeyboardEvent(const KeyEvent& key) { |
657 if (!GetFocusManager()) | 668 if (!GetFocusManager()) |
658 return false; | 669 return false; |
659 | 670 |
660 KeyEvent key(reinterpret_cast<NativeEvent>(event)); | 671 const int key_code = key.key_code(); |
661 int key_code = key.key_code(); | |
662 bool handled = false; | 672 bool handled = false; |
663 | 673 |
664 // Always reset |should_handle_menu_key_release_| unless we are handling a | 674 // Always reset |should_handle_menu_key_release_| unless we are handling a |
665 // VKEY_MENU key release event. It ensures that VKEY_MENU accelerator can only | 675 // VKEY_MENU key release event. It ensures that VKEY_MENU accelerator can only |
666 // be activated when handling a VKEY_MENU key release event which is preceded | 676 // be activated when handling a VKEY_MENU key release event which is preceded |
667 // by an un-handled VKEY_MENU key press event. | 677 // by an un-handled VKEY_MENU key press event. |
668 if (key_code != ui::VKEY_MENU || event->type != GDK_KEY_RELEASE) | 678 if (key_code != ui::VKEY_MENU || key.type() != ui::ET_KEY_RELEASED) |
669 should_handle_menu_key_release_ = false; | 679 should_handle_menu_key_release_ = false; |
670 | 680 |
671 if (event->type == GDK_KEY_PRESS) { | 681 if (key.type() == ui::ET_KEY_PRESSED) { |
672 // VKEY_MENU is triggered by key release event. | 682 // VKEY_MENU is triggered by key release event. |
673 // FocusManager::OnKeyEvent() returns false when the key has been consumed. | 683 // FocusManager::OnKeyEvent() returns false when the key has been consumed. |
674 if (key_code != ui::VKEY_MENU) | 684 if (key_code != ui::VKEY_MENU) |
675 handled = !GetFocusManager()->OnKeyEvent(key); | 685 handled = !GetFocusManager()->OnKeyEvent(key); |
676 else | 686 else |
677 should_handle_menu_key_release_ = true; | 687 should_handle_menu_key_release_ = true; |
678 } else if (key_code == ui::VKEY_MENU && should_handle_menu_key_release_ && | 688 } else if (key_code == ui::VKEY_MENU && should_handle_menu_key_release_ && |
679 (key.flags() & ~ui::EF_ALT_DOWN) == 0) { | 689 (key.flags() & ~ui::EF_ALT_DOWN) == 0) { |
680 // Trigger VKEY_MENU when only this key is pressed and released, and both | 690 // Trigger VKEY_MENU when only this key is pressed and released, and both |
681 // press and release events are not handled by others. | 691 // press and release events are not handled by others. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
745 if (HasNativeCapture()) | 755 if (HasNativeCapture()) |
746 gtk_grab_remove(window_contents_); | 756 gtk_grab_remove(window_contents_); |
747 } | 757 } |
748 | 758 |
749 bool WidgetGtk::HasNativeCapture() const { | 759 bool WidgetGtk::HasNativeCapture() const { |
750 // TODO(beng): Should be able to use gtk_widget_has_grab() here but the | 760 // TODO(beng): Should be able to use gtk_widget_has_grab() here but the |
751 // trybots don't have Gtk 2.18. | 761 // trybots don't have Gtk 2.18. |
752 return GTK_WIDGET_HAS_GRAB(window_contents_); | 762 return GTK_WIDGET_HAS_GRAB(window_contents_); |
753 } | 763 } |
754 | 764 |
765 InputMethod* WidgetGtk::GetInputMethodNative() { | |
766 return input_method_.get(); | |
767 } | |
768 | |
769 void WidgetGtk::ReplaceInputMethod(InputMethod* input_method) { | |
770 input_method_.reset(input_method); | |
771 if (input_method) { | |
772 input_method->set_delegate(this); | |
773 input_method->Init(GetWidget()); | |
774 } | |
775 } | |
776 | |
755 gfx::Rect WidgetGtk::GetWindowScreenBounds() const { | 777 gfx::Rect WidgetGtk::GetWindowScreenBounds() const { |
756 // Client == Window bounds on Gtk. | 778 // Client == Window bounds on Gtk. |
757 return GetClientAreaScreenBounds(); | 779 return GetClientAreaScreenBounds(); |
758 } | 780 } |
759 | 781 |
760 gfx::Rect WidgetGtk::GetClientAreaScreenBounds() const { | 782 gfx::Rect WidgetGtk::GetClientAreaScreenBounds() const { |
761 // Due to timing we can get a request for bounds after Close(). | 783 // Due to timing we can get a request for bounds after Close(). |
762 // TODO(beng): Figure out if this is bogus. | 784 // TODO(beng): Figure out if this is bogus. |
763 if (!widget_) | 785 if (!widget_) |
764 return gfx::Rect(size_); | 786 return gfx::Rect(size_); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
840 if (close_widget_factory_.empty()) { | 862 if (close_widget_factory_.empty()) { |
841 // And we delay the close just in case we're on the stack. | 863 // And we delay the close just in case we're on the stack. |
842 MessageLoop::current()->PostTask(FROM_HERE, | 864 MessageLoop::current()->PostTask(FROM_HERE, |
843 close_widget_factory_.NewRunnableMethod( | 865 close_widget_factory_.NewRunnableMethod( |
844 &WidgetGtk::CloseNow)); | 866 &WidgetGtk::CloseNow)); |
845 } | 867 } |
846 } | 868 } |
847 | 869 |
848 void WidgetGtk::CloseNow() { | 870 void WidgetGtk::CloseNow() { |
849 if (widget_) { | 871 if (widget_) { |
872 input_method_.reset(); | |
850 gtk_widget_destroy(widget_); // Triggers OnDestroy(). | 873 gtk_widget_destroy(widget_); // Triggers OnDestroy(). |
851 } | 874 } |
852 } | 875 } |
853 | 876 |
854 void WidgetGtk::Show() { | 877 void WidgetGtk::Show() { |
855 if (widget_) { | 878 if (widget_) { |
856 gtk_widget_show(widget_); | 879 gtk_widget_show(widget_); |
857 if (widget_->window) | 880 if (widget_->window) |
858 gdk_window_raise(widget_->window); | 881 gdk_window_raise(widget_->window); |
859 } | 882 } |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1176 if (type_ == TYPE_CHILD) | 1199 if (type_ == TYPE_CHILD) |
1177 return false; | 1200 return false; |
1178 | 1201 |
1179 // The top-level window lost focus, store the focused view. | 1202 // The top-level window lost focus, store the focused view. |
1180 GetFocusManager()->StoreFocusedView(); | 1203 GetFocusManager()->StoreFocusedView(); |
1181 return false; | 1204 return false; |
1182 } | 1205 } |
1183 | 1206 |
1184 gboolean WidgetGtk::OnKeyEvent(GtkWidget* widget, GdkEventKey* event) { | 1207 gboolean WidgetGtk::OnKeyEvent(GtkWidget* widget, GdkEventKey* event) { |
1185 KeyEvent key(reinterpret_cast<NativeEvent>(event)); | 1208 KeyEvent key(reinterpret_cast<NativeEvent>(event)); |
1209 if (input_method_.get()) | |
1210 input_method_->DispatchKeyEvent(key); | |
1211 else | |
1212 DispatchKeyEventPostIME(key); | |
1186 | 1213 |
1187 // Always reset |should_handle_menu_key_release_| unless we are handling a | 1214 // Returns true to prevent GtkWindow's default key event handler. |
1188 // VKEY_MENU key release event. It ensures that VKEY_MENU accelerator can only | 1215 return true; |
1189 // be activated when handling a VKEY_MENU key release event which is preceded | |
1190 // by an unhandled VKEY_MENU key press event. See also HandleKeyboardEvent(). | |
1191 if (key.key_code() != ui::VKEY_MENU || event->type != GDK_KEY_RELEASE) | |
1192 should_handle_menu_key_release_ = false; | |
1193 | |
1194 bool handled = false; | |
1195 | |
1196 // Dispatch the key event to View hierarchy first. | |
1197 handled = GetRootView()->ProcessKeyEvent(key); | |
1198 | |
1199 // Dispatch the key event to native GtkWidget hierarchy. | |
1200 // To prevent GtkWindow from handling the key event as a keybinding, we need | |
1201 // to bypass GtkWindow's default key event handler and dispatch the event | |
1202 // here. | |
1203 if (!handled && GTK_IS_WINDOW(widget)) | |
1204 handled = gtk_window_propagate_key_event(GTK_WINDOW(widget), event); | |
1205 | |
1206 // On Linux, in order to handle VKEY_MENU (Alt) accelerator key correctly and | |
1207 // avoid issues like: http://crbug.com/40966 and http://crbug.com/49701, we | |
1208 // should only send the key event to the focus manager if it's not handled by | |
1209 // any View or native GtkWidget. | |
1210 // The flow is different when the focus is in a RenderWidgetHostViewGtk, which | |
1211 // always consumes the key event and send it back to us later by calling | |
1212 // HandleKeyboardEvent() directly, if it's not handled by webkit. | |
1213 if (!handled) | |
1214 handled = HandleKeyboardEvent(event); | |
1215 | |
1216 // Dispatch the key event for bindings processing. | |
1217 if (!handled && GTK_IS_WINDOW(widget)) | |
1218 handled = gtk_bindings_activate_event(GTK_OBJECT(widget), event); | |
1219 | |
1220 // Always return true for toplevel window to prevents GtkWindow's default key | |
1221 // event handler. | |
1222 return GTK_IS_WINDOW(widget) ? true : handled; | |
1223 } | 1216 } |
1224 | 1217 |
1225 gboolean WidgetGtk::OnQueryTooltip(GtkWidget* widget, | 1218 gboolean WidgetGtk::OnQueryTooltip(GtkWidget* widget, |
1226 gint x, | 1219 gint x, |
1227 gint y, | 1220 gint y, |
1228 gboolean keyboard_mode, | 1221 gboolean keyboard_mode, |
1229 GtkTooltip* tooltip) { | 1222 GtkTooltip* tooltip) { |
1230 return tooltip_manager_->ShowTooltip(x, y, keyboard_mode, tooltip); | 1223 return tooltip_manager_->ShowTooltip(x, y, keyboard_mode, tooltip); |
1231 } | 1224 } |
1232 | 1225 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1292 | 1285 |
1293 RootView* WidgetGtk::CreateRootView() { | 1286 RootView* WidgetGtk::CreateRootView() { |
1294 return new RootView(this); | 1287 return new RootView(this); |
1295 } | 1288 } |
1296 | 1289 |
1297 gfx::AcceleratedWidget WidgetGtk::GetAcceleratedWidget() { | 1290 gfx::AcceleratedWidget WidgetGtk::GetAcceleratedWidget() { |
1298 DCHECK(window_contents_ && window_contents_->window); | 1291 DCHECK(window_contents_ && window_contents_->window); |
1299 return GDK_WINDOW_XID(window_contents_->window); | 1292 return GDK_WINDOW_XID(window_contents_->window); |
1300 } | 1293 } |
1301 | 1294 |
1295 void WidgetGtk::DispatchKeyEventPostIME(const KeyEvent& key) { | |
1296 // Always reset |should_handle_menu_key_release_| unless we are handling a | |
1297 // VKEY_MENU key release event. It ensures that VKEY_MENU accelerator can only | |
1298 // be activated when handling a VKEY_MENU key release event which is preceded | |
1299 // by an unhandled VKEY_MENU key press event. See also HandleKeyboardEvent(). | |
1300 if (key.key_code() != ui::VKEY_MENU || key.type() != ui::ET_KEY_RELEASED) | |
1301 should_handle_menu_key_release_ = false; | |
1302 | |
1303 bool handled = false; | |
1304 | |
1305 // Dispatch the key event to View hierarchy first. | |
1306 handled = GetRootView()->ProcessKeyEvent(key); | |
1307 | |
1308 if (key.key_code() == ui::VKEY_PROCESSKEY || handled) | |
1309 return; | |
1310 | |
1311 // Dispatch the key event to native GtkWidget hierarchy. | |
1312 // To prevent GtkWindow from handling the key event as a keybinding, we need | |
1313 // to bypass GtkWindow's default key event handler and dispatch the event | |
1314 // here. | |
1315 GdkEventKey* event = reinterpret_cast<GdkEventKey*>(key.native_event()); | |
1316 if (!handled && event && GTK_IS_WINDOW(widget_)) | |
1317 handled = gtk_window_propagate_key_event(GTK_WINDOW(widget_), event); | |
1318 | |
1319 // On Linux, in order to handle VKEY_MENU (Alt) accelerator key correctly and | |
1320 // avoid issues like: http://crbug.com/40966 and http://crbug.com/49701, we | |
1321 // should only send the key event to the focus manager if it's not handled by | |
1322 // any View or native GtkWidget. | |
1323 // The flow is different when the focus is in a RenderWidgetHostViewGtk, which | |
1324 // always consumes the key event and send it back to us later by calling | |
1325 // HandleKeyboardEvent() directly, if it's not handled by webkit. | |
1326 if (!handled) | |
1327 handled = HandleKeyboardEvent(key); | |
1328 | |
1329 // Dispatch the key event for bindings processing. | |
1330 if (!handled && event && GTK_IS_WINDOW(widget_)) | |
1331 gtk_bindings_activate_event(GTK_OBJECT(widget_), event); | |
1332 } | |
1333 | |
1302 gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { | 1334 gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { |
1303 // Clear the background to be totally transparent. We don't need to | 1335 // Clear the background to be totally transparent. We don't need to |
1304 // paint the root view here as that is done by OnPaint. | 1336 // paint the root view here as that is done by OnPaint. |
1305 DCHECK(transparent_); | 1337 DCHECK(transparent_); |
1306 DrawTransparentBackground(widget, event); | 1338 DrawTransparentBackground(widget, event); |
1307 return false; | 1339 return false; |
1308 } | 1340 } |
1309 | 1341 |
1310 bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) { | 1342 bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) { |
1311 if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { | 1343 if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1644 | 1676 |
1645 NativeWidget* native_widget = GetNativeWidgetForNativeView(native_view); | 1677 NativeWidget* native_widget = GetNativeWidgetForNativeView(native_view); |
1646 if (native_widget) | 1678 if (native_widget) |
1647 children->insert(native_widget); | 1679 children->insert(native_widget); |
1648 gtk_container_foreach(GTK_CONTAINER(native_view), | 1680 gtk_container_foreach(GTK_CONTAINER(native_view), |
1649 EnumerateChildWidgetsForNativeWidgets, | 1681 EnumerateChildWidgetsForNativeWidgets, |
1650 reinterpret_cast<gpointer>(children)); | 1682 reinterpret_cast<gpointer>(children)); |
1651 } | 1683 } |
1652 | 1684 |
1653 } // namespace views | 1685 } // namespace views |
OLD | NEW |