diff --git a/ui/ozone/platform/x11/x11_window_ozone.cc b/ui/ozone/platform/x11/x11_window_ozone.cc index 80a99ababbf04..917b6c0fdff70 100644 --- a/ui/ozone/platform/x11/x11_window_ozone.cc +++ b/ui/ozone/platform/x11/x11_window_ozone.cc @@ -6,6 +6,7 @@ #include "base/bind.h" #include "ui/base/dragdrop/os_exchange_data.h" +#include "ui/base/hit_test.h" #include "ui/base/x/x11_util.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" @@ -21,6 +22,60 @@ namespace ui { +namespace { + +// These constants are defined in the Extended Window Manager Hints +// standard...and aren't in any header that I can find. +const int k_NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0; +const int k_NET_WM_MOVERESIZE_SIZE_TOP = 1; +const int k_NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2; +const int k_NET_WM_MOVERESIZE_SIZE_RIGHT = 3; +const int k_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4; +const int k_NET_WM_MOVERESIZE_SIZE_BOTTOM = 5; +const int k_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6; +const int k_NET_WM_MOVERESIZE_SIZE_LEFT = 7; +const int k_NET_WM_MOVERESIZE_MOVE = 8; + +// Identifies the direction of the "hittest" for X11. +bool IdentifyDirection(int hittest, int* direction) { + DCHECK(direction); + *direction = -1; + switch (hittest) { + case HTBOTTOM: + *direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOM; + break; + case HTBOTTOMLEFT: + *direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; + break; + case HTBOTTOMRIGHT: + *direction = k_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; + break; + case HTCAPTION: + *direction = k_NET_WM_MOVERESIZE_MOVE; + break; + case HTLEFT: + *direction = k_NET_WM_MOVERESIZE_SIZE_LEFT; + break; + case HTRIGHT: + *direction = k_NET_WM_MOVERESIZE_SIZE_RIGHT; + break; + case HTTOP: + *direction = k_NET_WM_MOVERESIZE_SIZE_TOP; + break; + case HTTOPLEFT: + *direction = k_NET_WM_MOVERESIZE_SIZE_TOPLEFT; + break; + case HTTOPRIGHT: + *direction = k_NET_WM_MOVERESIZE_SIZE_TOPRIGHT; + break; + default: + return false; + } + return true; +} + +} // namespace + X11WindowOzone::X11WindowOzone(X11WindowManagerOzone* window_manager, PlatformWindowDelegate* delegate, const gfx::Rect& bounds) @@ -41,6 +96,10 @@ X11WindowOzone::X11WindowOzone(X11WindowManagerOzone* window_manager, XChangeProperty(xdisplay(), xwindow(), gfx::GetAtom(kXdndAware), XA_ATOM, 32, PropModeReplace, reinterpret_cast(&xdnd_version), 1); + + // Set a class property key, which allows |this| to be used for interactive + // events, e.g. move or resize. + SetWmMoveResizeHandler(this, AsWmMoveResizeHandler()); } X11WindowOzone::~X11WindowOzone() { @@ -175,6 +234,36 @@ void X11WindowOzone::OnDragSessionClose(int dnd_action) { NOTIMPLEMENTED_LOG_ONCE(); } +void X11WindowOzone::DispatchHostWindowDragMovement( + int hittest, + const gfx::Point& pointer_location) { + int direction; + if (!IdentifyDirection(hittest, &direction)) + return; + + // We most likely have an implicit grab right here. We need to dump it + // because what we're about to do is tell the window manager + // that it's now responsible for moving the window around; it immediately + // grabs when it receives the event below. + XUngrabPointer(xdisplay(), x11::CurrentTime); + + XEvent event; + memset(&event, 0, sizeof(event)); + event.xclient.type = ClientMessage; + event.xclient.display = xdisplay(); + event.xclient.window = xwindow(); + event.xclient.message_type = gfx::GetAtom("_NET_WM_MOVERESIZE"); + event.xclient.format = 32; + event.xclient.data.l[0] = pointer_location.x(); + event.xclient.data.l[1] = pointer_location.y(); + event.xclient.data.l[2] = direction; + event.xclient.data.l[3] = 0; + event.xclient.data.l[4] = 0; + + XSendEvent(xdisplay(), xroot_window(), x11::False, + SubstructureRedirectMask | SubstructureNotifyMask, &event); +} + void X11WindowOzone::OnDragMotion(const gfx::PointF& screen_point, int flags, ::Time event_time, @@ -296,4 +385,8 @@ bool X11WindowOzone::ProcessDragDropEvent(XEvent* xev) { return false; } +WmMoveResizeHandler* X11WindowOzone::AsWmMoveResizeHandler() { + return static_cast(this); +} + } // namespace ui diff --git a/ui/ozone/platform/x11/x11_window_ozone.h b/ui/ozone/platform/x11/x11_window_ozone.h index 29876f91bc2f3..b8bf7765b3c74 100644 --- a/ui/ozone/platform/x11/x11_window_ozone.h +++ b/ui/ozone/platform/x11/x11_window_ozone.h @@ -8,6 +8,7 @@ #include "base/macros.h" #include "ui/events/platform/platform_event_dispatcher.h" #include "ui/events/platform/x11/x11_event_source_libevent.h" +#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h" #include "ui/platform_window/x11/window_move_loop_client.h" #include "ui/platform_window/x11/x11_window_base.h" @@ -21,7 +22,8 @@ class X11WindowManagerOzone; // PlatformWindow implementation for X11 Ozone. PlatformEvents are ui::Events. class X11WindowOzone : public X11WindowBase, public PlatformEventDispatcher, - public XEventDispatcher { + public XEventDispatcher, + public WmMoveResizeHandler { public: X11WindowOzone(X11WindowManagerOzone* window_manager, PlatformWindowDelegate* delegate, @@ -61,6 +63,11 @@ class X11WindowOzone : public X11WindowBase, void OnMouseMoved(const gfx::Point& point, gfx::AcceleratedWidget* widget); void OnDragSessionClose(int dnd_action); + // WmMoveResizeHandler + void DispatchHostWindowDragMovement( + int hittest, + const gfx::Point& pointer_location) override; + private: enum SourceState { // |source_current_window_| will receive a drop once we receive an @@ -81,6 +88,8 @@ class X11WindowOzone : public X11WindowBase, uint32_t DispatchEvent(const PlatformEvent& event) override; bool ProcessDragDropEvent(XEvent* xev); + WmMoveResizeHandler* AsWmMoveResizeHandler(); + X11WindowManagerOzone* window_manager_; // TODO(msisov, tonikitoo): Add a dummy implementation for chromeos. diff --git a/ui/platform_window/x11/x11_window_base.h b/ui/platform_window/x11/x11_window_base.h index 92032f6f6818d..b8aeab98b3838 100644 --- a/ui/platform_window/x11/x11_window_base.h +++ b/ui/platform_window/x11/x11_window_base.h @@ -72,6 +72,7 @@ class X11_WINDOW_EXPORT X11WindowBase : public PlatformWindow, XDisplay* xdisplay() { return xdisplay_; } XID xwindow() const { return xwindow_; } + XID xroot_window() const { return xroot_window_; } void UnConfineCursor();