Index: ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc |
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc |
index d428447e84aefcfdd8417359069c6921002b94ac..77c5966f8e4bc873bf5a71e3f306981b1201ecbe 100644 |
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc |
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc |
@@ -18,6 +18,7 @@ |
#include "third_party/skia/include/core/SkPath.h" |
#include "ui/aura/client/cursor_client.h" |
#include "ui/aura/client/focus_client.h" |
+#include "ui/aura/client/screen_position_client.h" |
#include "ui/aura/window.h" |
#include "ui/aura/window_event_dispatcher.h" |
#include "ui/aura/window_property.h" |
@@ -46,9 +47,9 @@ |
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h" |
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" |
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h" |
+#include "ui/views/widget/desktop_aura/x11_capture_window.h" |
#include "ui/views/widget/desktop_aura/x11_desktop_handler.h" |
#include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h" |
-#include "ui/views/widget/desktop_aura/x11_scoped_capture.h" |
#include "ui/views/widget/desktop_aura/x11_window_event_filter.h" |
#include "ui/wm/core/compound_event_filter.h" |
#include "ui/wm/core/window_util.h" |
@@ -901,24 +902,35 @@ gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const { |
} |
void DesktopWindowTreeHostX11::SetCapture() { |
- // This is vaguely based on the old NativeWidgetGtk implementation. |
- // |
- // X11's XPointerGrab() shouldn't be used for everything; it doesn't map |
- // cleanly to Windows' SetCapture(). GTK only provides a separate concept of |
- // a grab that wasn't the X11 pointer grab, but was instead a manual |
- // redirection of the event. (You need to drop into GDK if you want to |
- // perform a raw X11 grab). |
+ DesktopWindowTreeHostX11* old_capture = g_current_capture; |
+ g_current_capture = this; |
+ if (old_capture) { |
+ // Take ownership of |old_capture|'s capture window which already has a |
+ // mouse grab. Because there is no X11 mouse grab or mouse ungrab, the |
+ // capture change is sychronous. |
+ capture_window_ = old_capture->ReleaseCaptureWindow().Pass(); |
- if (g_current_capture) |
- g_current_capture->OnCaptureReleased(); |
+ old_capture->OnHostLostWindowCapture(); |
+ } |
- g_current_capture = this; |
- x11_capture_.reset(new X11ScopedCapture(xwindow_)); |
+ if (!capture_window_) { |
+ // Create an X11CaptureWindow to asynchronously grab the mouse. As |
+ // |xwindow_| is likely the topmost window underneath the mouse, we will |
+ // likely not miss any mouse events. |
+ capture_window_.reset(new X11CaptureWindow); |
+ } |
} |
void DesktopWindowTreeHostX11::ReleaseCapture() { |
- if (g_current_capture == this) |
- g_current_capture->OnCaptureReleased(); |
+ if (g_current_capture == this) { |
+ // Release mouse grab asynchronously. |xwindow_| is likely the topmost |
+ // window underneath the mouse so the capture release being asynchronous is |
+ // likely inconsequential. |
+ g_current_capture = NULL; |
+ capture_window_.reset(); |
+ |
+ OnHostLostWindowCapture(); |
+ } |
} |
void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) { |
@@ -1300,10 +1312,8 @@ void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) { |
ResetWindowRegion(); |
} |
-void DesktopWindowTreeHostX11::OnCaptureReleased() { |
- x11_capture_.reset(); |
- g_current_capture = NULL; |
- OnHostLostWindowCapture(); |
+scoped_ptr<X11CaptureWindow> DesktopWindowTreeHostX11::ReleaseCaptureWindow() { |
+ return capture_window_.Pass(); |
} |
void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) { |
@@ -1337,17 +1347,27 @@ void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) { |
if (event->IsAnyButton() || event->IsMouseWheelEvent()) |
FlashFrame(false); |
+ if (ui::EventTargetFromNative(event->native_event()) != xwindow_) { |
+ // The event was targeted at |capture_window_|'s X window. |
+ gfx::Point location = |
+ ui::EventSystemLocationFromNative(event->native_event()); |
+ aura::client::GetScreenPositionClient(window())->ConvertPointFromScreen( |
+ window(), &location); |
+ event->set_location(location); |
+ } |
+ |
if (!g_current_capture || g_current_capture == this) { |
SendEventToProcessor(event); |
} else { |
- // Another DesktopWindowTreeHostX11 has installed itself as |
- // capture. Translate the event's location and dispatch to the other. |
+ // Another DesktopWindowTreeHostX11 has capture. Translate the event's |
+ // location and dispatch to the other DesktopWindowTreeHostX11. |
event->ConvertLocationToTarget(window(), g_current_capture->window()); |
g_current_capture->SendEventToProcessor(event); |
} |
} |
void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) { |
+ DCHECK_EQ(ui::EventTargetFromNative(event->native_event()), xwindow_); |
if (g_current_capture && g_current_capture != this && |
event->type() == ui::ET_TOUCH_PRESSED) { |
event->ConvertLocationToTarget(window(), g_current_capture->window()); |
@@ -1526,9 +1546,9 @@ void DesktopWindowTreeHostX11::Relayout() { |
bool DesktopWindowTreeHostX11::CanDispatchEvent( |
const ui::PlatformEvent& event) { |
- return event->xany.window == xwindow_ || |
- (event->type == GenericEvent && |
- static_cast<XIDeviceEvent*>(event->xcookie.data)->event == xwindow_); |
+ XID target = ui::EventTargetFromNative(event); |
+ return target == xwindow_ || |
+ (capture_window_ && target == capture_window_->xwindow()); |
} |
uint32_t DesktopWindowTreeHostX11::DispatchEvent( |
@@ -1554,6 +1574,11 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( |
ui::MouseEvent mouse_event(xev); |
DispatchMouseEvent(&mouse_event); |
+ |
+ if (xev->xcrossing.mode == NotifyGrab || |
+ xev->xcrossing.mode == NotifyUngrab) { |
+ ReleaseCapture(); |
+ } |
break; |
} |
case Expose: { |