| 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 } |
| 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 228 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 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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) { |
| 1184 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); |
| 1185 | 1213 |
| 1186 // Always reset |should_handle_menu_key_release_| unless we are handling a | 1214 // Returns true to prevent GtkWindow's default key event handler. |
| 1187 // VKEY_MENU key release event. It ensures that VKEY_MENU accelerator can only | 1215 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 } | 1216 } |
| 1223 | 1217 |
| 1224 gboolean WidgetGtk::OnQueryTooltip(GtkWidget* widget, | 1218 gboolean WidgetGtk::OnQueryTooltip(GtkWidget* widget, |
| 1225 gint x, | 1219 gint x, |
| 1226 gint y, | 1220 gint y, |
| 1227 gboolean keyboard_mode, | 1221 gboolean keyboard_mode, |
| 1228 GtkTooltip* tooltip) { | 1222 GtkTooltip* tooltip) { |
| 1229 return tooltip_manager_->ShowTooltip(x, y, keyboard_mode, tooltip); | 1223 return tooltip_manager_->ShowTooltip(x, y, keyboard_mode, tooltip); |
| 1230 } | 1224 } |
| 1231 | 1225 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1291 | 1285 |
| 1292 RootView* WidgetGtk::CreateRootView() { | 1286 RootView* WidgetGtk::CreateRootView() { |
| 1293 return new RootView(this); | 1287 return new RootView(this); |
| 1294 } | 1288 } |
| 1295 | 1289 |
| 1296 gfx::AcceleratedWidget WidgetGtk::GetAcceleratedWidget() { | 1290 gfx::AcceleratedWidget WidgetGtk::GetAcceleratedWidget() { |
| 1297 DCHECK(window_contents_ && window_contents_->window); | 1291 DCHECK(window_contents_ && window_contents_->window); |
| 1298 return GDK_WINDOW_XID(window_contents_->window); | 1292 return GDK_WINDOW_XID(window_contents_->window); |
| 1299 } | 1293 } |
| 1300 | 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 GdkEventKey* event = reinterpret_cast<GdkEventKey*>(key.native_event()); |
| 1309 if (key.key_code() == ui::VKEY_PROCESSKEY || handled || !event) |
| 1310 return; |
| 1311 |
| 1312 // Dispatch the key event to native GtkWidget hierarchy. |
| 1313 // To prevent GtkWindow from handling the key event as a keybinding, we need |
| 1314 // to bypass GtkWindow's default key event handler and dispatch the event |
| 1315 // here. |
| 1316 if (!handled && 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(event); |
| 1328 |
| 1329 // Dispatch the key event for bindings processing. |
| 1330 if (!handled && GTK_IS_WINDOW(widget_)) |
| 1331 gtk_bindings_activate_event(GTK_OBJECT(widget_), event); |
| 1332 } |
| 1333 |
| 1301 gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { | 1334 gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { |
| 1302 // 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 |
| 1303 // paint the root view here as that is done by OnPaint. | 1336 // paint the root view here as that is done by OnPaint. |
| 1304 DCHECK(transparent_); | 1337 DCHECK(transparent_); |
| 1305 DrawTransparentBackground(widget, event); | 1338 DrawTransparentBackground(widget, event); |
| 1306 return false; | 1339 return false; |
| 1307 } | 1340 } |
| 1308 | 1341 |
| 1309 bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) { | 1342 bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) { |
| 1310 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... |
| 1643 | 1676 |
| 1644 NativeWidget* native_widget = GetNativeWidgetForNativeView(native_view); | 1677 NativeWidget* native_widget = GetNativeWidgetForNativeView(native_view); |
| 1645 if (native_widget) | 1678 if (native_widget) |
| 1646 children->insert(native_widget); | 1679 children->insert(native_widget); |
| 1647 gtk_container_foreach(GTK_CONTAINER(native_view), | 1680 gtk_container_foreach(GTK_CONTAINER(native_view), |
| 1648 EnumerateChildWidgetsForNativeWidgets, | 1681 EnumerateChildWidgetsForNativeWidgets, |
| 1649 reinterpret_cast<gpointer>(children)); | 1682 reinterpret_cast<gpointer>(children)); |
| 1650 } | 1683 } |
| 1651 | 1684 |
| 1652 } // namespace views | 1685 } // namespace views |
| OLD | NEW |