Commit 830286c2 authored by Alexander Dunaev's avatar Alexander Dunaev Committed by Commit Bot

[ozone/x11] Fixed the host window drag movement.

This CL adds the missing handlers that enable window move via the non-client
area of the window.

Bug: 991512
Change-Id: I4890969ea8fc4c0aa405cdf0db7fca7769dc7b15
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1741684
Commit-Queue: Alexander Dunaev <adunaev@igalia.com>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarThomas Anderson <thomasanderson@chromium.org>
Reviewed-by: default avatarkylechar <kylechar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#687352}
parent 8e096d3a
......@@ -63,6 +63,20 @@ buildflag_header("buildflags") {
]
}
source_set("hit_test") {
sources = [
"hit_test.cc",
"hit_test.h",
]
if (use_x11 || use_ozone) {
sources += [
"hit_test_x11.cc",
"hit_test_x11.h",
]
}
}
jumbo_component("base") {
output_name = "ui_base"
......@@ -166,8 +180,6 @@ jumbo_component("base") {
"dragdrop/os_exchange_data_provider_mac.mm",
"dragdrop/os_exchange_data_provider_win.cc",
"dragdrop/os_exchange_data_provider_win.h",
"hit_test.cc",
"hit_test.h",
"l10n/formatter.cc",
"l10n/formatter.h",
"l10n/l10n_font_util.cc",
......@@ -386,6 +398,7 @@ jumbo_component("base") {
public_deps = [
":buildflags",
":features",
":hit_test",
":ui_data_pack",
"//base",
"//skia",
......
......@@ -5,9 +5,6 @@
#ifndef UI_BASE_HIT_TEST_H_
#define UI_BASE_HIT_TEST_H_
#include "build/build_config.h"
#include "ui/base/ui_base_export.h"
#if !defined(OS_WIN)
// Defines the same symbolic names used by the WM_NCHITTEST Notification under
......@@ -48,11 +45,11 @@ enum HitTestCompat {
namespace ui {
// Returns true if the |component| is for resizing, like HTTOP or HTBOTTOM.
UI_BASE_EXPORT bool IsResizingComponent(int component);
bool IsResizingComponent(int component);
// Returns true if the |component| is HTCAPTION or one of the resizing
// components.
UI_BASE_EXPORT bool CanPerformDragOrResize(int component);
bool CanPerformDragOrResize(int component);
} // namespace ui
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/base/hit_test_x11.h"
#include "ui/base/hit_test.h"
namespace ui {
namespace {
// These constants are said to be defined in the Extended Window Manager Hints
// standard but to be not found in any headers...
constexpr int kSizeTopLeft = 0;
constexpr int kSizeTop = 1;
constexpr int kSizeTopRight = 2;
constexpr int kSizeRight = 3;
constexpr int kSizeBottomRight = 4;
constexpr int kSizeBottom = 5;
constexpr int kSizeBottomLeft = 6;
constexpr int kSizeLeft = 7;
constexpr int kMove = 8;
} // namespace
int HitTestToWmMoveResizeDirection(int hittest) {
switch (hittest) {
case HTBOTTOM:
return kSizeBottom;
case HTBOTTOMLEFT:
return kSizeBottomLeft;
case HTBOTTOMRIGHT:
return kSizeBottomRight;
case HTCAPTION:
return kMove;
case HTLEFT:
return kSizeLeft;
case HTRIGHT:
return kSizeRight;
case HTTOP:
return kSizeTop;
case HTTOPLEFT:
return kSizeTopLeft;
case HTTOPRIGHT:
return kSizeTopRight;
default:
return -1;
}
}
} // namespace ui
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_BASE_HIT_TEST_X11_H_
#define UI_BASE_HIT_TEST_X11_H_
namespace ui {
// Converts a HitTestCompat into an X11 direction recognisable by
// NET_WM_MOVERESIZE event. Returns -1 if no conversion is possible.
int HitTestToWmMoveResizeDirection(int hittest);
} // namespace ui
#endif // UI_BASE_HIT_TEST_X11_H_
......@@ -38,6 +38,7 @@ jumbo_component("x") {
"//base",
"//base:i18n",
"//skia",
"//ui/base:hit_test",
"//ui/display/util",
"//ui/events",
"//ui/events/devices/x11",
......
......@@ -944,6 +944,32 @@ void SetWMSpecState(XID window, bool enabled, XAtom state1, XAtom state2) {
SubstructureRedirectMask | SubstructureNotifyMask, &xclient);
}
void DoWMMoveResize(XDisplay* display,
XID root_window,
XID window,
const gfx::Point& location_px,
int direction) {
// This handler is usually sent when the window has the implicit grab. 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(display, x11::CurrentTime);
XEvent event;
memset(&event, 0, sizeof(event));
event.xclient.type = ClientMessage;
event.xclient.display = display;
event.xclient.window = window;
event.xclient.message_type = gfx::GetAtom("_NET_WM_MOVERESIZE");
event.xclient.format = 32;
event.xclient.data.l[0] = location_px.x();
event.xclient.data.l[1] = location_px.y();
event.xclient.data.l[2] = direction;
XSendEvent(display, root_window, x11::False,
SubstructureRedirectMask | SubstructureNotifyMask, &event);
}
bool HasWMSpecProperty(const base::flat_set<XAtom>& properties, XAtom atom) {
return properties.find(atom) != properties.end();
}
......
......@@ -33,7 +33,7 @@ namespace gfx {
class Insets;
class Point;
class Rect;
}
} // namespace gfx
class SkBitmap;
namespace ui {
......@@ -206,6 +206,18 @@ void SetWindowRole(XDisplay* display, XID window, const std::string& role);
COMPONENT_EXPORT(UI_BASE_X)
void SetWMSpecState(XID window, bool enabled, XAtom state1, XAtom state2);
// Sends a NET_WM_MOVERESIZE message to the x11 window manager, enabling the
// move/resize mode. As per NET_WM_MOVERESIZE spec, |location| is the position
// in pixels (relative to the root window) of mouse button press, and
// |direction| indicates whether this is a move or resize event, and if it is a
// resize event, which edges of the window the size grip applies to.
COMPONENT_EXPORT(UI_BASE_X)
void DoWMMoveResize(XDisplay* display,
XID root_window,
XID window,
const gfx::Point& location_px,
int direction);
// Checks if the window manager has set a specific state.
COMPONENT_EXPORT(UI_BASE_X)
bool HasWMSpecProperty(const base::flat_set<XAtom>& properties, XAtom atom);
......
......@@ -11,6 +11,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/base/hit_test_x11.h"
#include "ui/base/x/x11_pointer_grab.h"
#include "ui/base/x/x11_util.h"
#include "ui/base/x/x11_util_internal.h"
......@@ -1005,6 +1006,14 @@ bool XWindow::IsTargetedBy(const XEvent& xev) const {
return target_window == xwindow_;
}
void XWindow::WmMoveResize(int hittest, const gfx::Point& location) const {
int direction = HitTestToWmMoveResizeDirection(hittest);
if (direction == -1)
return;
DoWMMoveResize(xdisplay_, x_root_window_, xwindow_, location, direction);
}
// In Ozone, there are no ui::*Event constructors receiving XEvent* as input,
// in this case ui::PlatformEvent is expected. Furthermore,
// X11EventSourceLibevent is used in that case, which already translates
......
......@@ -107,6 +107,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow {
void ReleasePointerGrab();
void StackAtTop();
bool IsTargetedBy(const XEvent& xev) const;
void WmMoveResize(int hittest, const gfx::Point& location) const;
void ProcessEvent(XEvent* xev);
void SetSize(const gfx::Size& size_in_pixels);
......
......@@ -57,6 +57,7 @@ source_set("x11") {
"//ui/ozone:ozone_base",
"//ui/ozone/common",
"//ui/platform_window",
"//ui/platform_window/platform_window_handler",
"//ui/platform_window/x11",
]
......
......@@ -99,6 +99,10 @@ X11WindowOzone::~X11WindowOzone() {
void X11WindowOzone::Init(const PlatformWindowInitProperties& params) {
XWindow::Configuration config = ConvertInitPropertiesToXWindowConfig(params);
x11_window_->Init(config);
// Set a class property key, which allows |this| to be used for interactive
// events, e.g. move or resize.
SetWmMoveResizeHandler(this, static_cast<WmMoveResizeHandler*>(this));
}
void X11WindowOzone::Show() {
......@@ -314,6 +318,12 @@ uint32_t X11WindowOzone::DispatchEvent(const PlatformEvent& event) {
return window_manager_->event_grabber()->DispatchEvent(event);
}
void X11WindowOzone::DispatchHostWindowDragMovement(
int hittest,
const gfx::Point& pointer_location) {
x11_window_->WmMoveResize(hittest, pointer_location);
}
void X11WindowOzone::SetWidget(XID xid) {
// In spite of being defined in Xlib as `unsigned long`, XID (|xid|'s type)
// is fixed at 32-bits (CARD32) in X11 Protocol, therefore can't be larger
......
......@@ -17,6 +17,7 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
namespace ui {
......@@ -26,6 +27,7 @@ struct PlatformWindowInitProperties;
// PlatformWindow implementation for X11 Ozone. PlatformEvents are ui::Events.
class X11WindowOzone : public PlatformWindow,
public PlatformEventDispatcher,
public WmMoveResizeHandler,
public XEventDispatcher,
public XWindow::Delegate {
public:
......@@ -87,6 +89,11 @@ class X11WindowOzone : public PlatformWindow,
bool CanDispatchEvent(const PlatformEvent& event) override;
uint32_t DispatchEvent(const PlatformEvent& event) override;
// WmMoveResizeHandler
void DispatchHostWindowDragMovement(
int hittest,
const gfx::Point& pointer_location) override;
void Init(const PlatformWindowInitProperties& params);
void SetWidget(XID xwindow);
void RemoveFromWindowManager();
......
......@@ -762,6 +762,7 @@ jumbo_component("views") {
"widget/desktop_aura/window_event_filter.cc",
"widget/desktop_aura/window_event_filter.h",
]
deps += [ "//ui/base:hit_test" ]
}
if ((is_linux && !use_x11) || is_fuchsia) {
public += [ "widget/desktop_aura/desktop_window_tree_host_platform.h" ]
......
......@@ -8,7 +8,8 @@
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
#include "ui/base/hit_test_x11.h"
#include "ui/base/x/x11_util.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
......@@ -21,22 +22,6 @@
#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/widget.h"
namespace {
// These constants are defined in the Extended Window Manager Hints
// standard...and aren't in any header that I can find.
constexpr int k_NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0;
constexpr int k_NET_WM_MOVERESIZE_SIZE_TOP = 1;
constexpr int k_NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2;
constexpr int k_NET_WM_MOVERESIZE_SIZE_RIGHT = 3;
constexpr int k_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4;
constexpr int k_NET_WM_MOVERESIZE_SIZE_BOTTOM = 5;
constexpr int k_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6;
constexpr int k_NET_WM_MOVERESIZE_SIZE_LEFT = 7;
constexpr int k_NET_WM_MOVERESIZE_MOVE = 8;
} // namespace
namespace views {
X11WindowEventFilter::X11WindowEventFilter(
......@@ -67,61 +52,12 @@ void X11WindowEventFilter::LowerWindow() {
bool X11WindowEventFilter::DispatchHostWindowDragMovement(
int hittest,
const gfx::Point& screen_location) {
int 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;
}
// 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] = screen_location.x();
event.xclient.data.l[1] = screen_location.y();
event.xclient.data.l[2] = direction;
event.xclient.data.l[3] = 0;
event.xclient.data.l[4] = 0;
XSendEvent(xdisplay_, x_root_window_, x11::False,
SubstructureRedirectMask | SubstructureNotifyMask, &event);
int direction = ui::HitTestToWmMoveResizeDirection(hittest);
if (direction == -1)
return false;
ui::DoWMMoveResize(xdisplay_, x_root_window_, xwindow_, screen_location,
direction);
return true;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment