Skip to content

Commit

Permalink
wayland: provide support for testing if window has capture
Browse files Browse the repository at this point in the history
Wayland does implicit capture. This adds plumbing to track when the
WaylandWindow has implicit capture, and adds function to
PlatformWindow to test for capture.

Also notifies when activation changes.

BUG=none
TEST=covered by tests

Change-Id: I9d73ade6cb8e5e909fe3fe3940eb6f48b0dbd5c7
Reviewed-on: https://chromium-review.googlesource.com/998307
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: Michael Spang <spang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548543}
  • Loading branch information
Scott Violet authored and Commit Bot committed Apr 5, 2018
1 parent af7a242 commit 5f83d22
Show file tree
Hide file tree
Showing 23 changed files with 175 additions and 14 deletions.
3 changes: 3 additions & 0 deletions ui/aura/window_tree_host_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ class AURA_EXPORT WindowTreeHostPlatform : public WindowTreeHost,

void SetPlatformWindow(std::unique_ptr<ui::PlatformWindow> window);
ui::PlatformWindow* platform_window() { return platform_window_.get(); }
const ui::PlatformWindow* platform_window() const {
return platform_window_.get();
}

// ui::PlatformWindowDelegate:
void OnBoundsChanged(const gfx::Rect& new_bounds) override;
Expand Down
4 changes: 4 additions & 0 deletions ui/ozone/platform/cast/platform_window_cast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ void PlatformWindowCast::SetBounds(const gfx::Rect& bounds) {
void PlatformWindowCast::SetTitle(const base::string16& title) {
}

bool PlatformWindowCast::HasCapture() const {
return false;
}

PlatformImeController* PlatformWindowCast::GetPlatformImeController() {
return nullptr;
}
Expand Down
1 change: 1 addition & 0 deletions ui/ozone/platform/cast/platform_window_cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class PlatformWindowCast : public PlatformWindow,
void PrepareForShutdown() override {}
void SetCapture() override {}
void ReleaseCapture() override {}
bool HasCapture() const override;
void ToggleFullscreen() override {}
void Maximize() override {}
void Minimize() override {}
Expand Down
4 changes: 4 additions & 0 deletions ui/ozone/platform/drm/host/drm_window_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ void DrmWindowHost::ReleaseCapture() {
window_manager_->UngrabEvents(widget_);
}

bool DrmWindowHost::HasCapture() const {
return widget_ == window_manager_->event_grabber();
}

void DrmWindowHost::ToggleFullscreen() {
}

Expand Down
1 change: 1 addition & 0 deletions ui/ozone/platform/drm/host/drm_window_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class DrmWindowHost : public PlatformWindow,
void SetTitle(const base::string16& title) override;
void SetCapture() override;
void ReleaseCapture() override;
bool HasCapture() const override;
void ToggleFullscreen() override;
void Maximize() override;
void Minimize() override;
Expand Down
4 changes: 4 additions & 0 deletions ui/ozone/platform/headless/headless_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ void HeadlessWindow::SetCapture() {}

void HeadlessWindow::ReleaseCapture() {}

bool HeadlessWindow::HasCapture() const {
return false;
}

void HeadlessWindow::ToggleFullscreen() {}

void HeadlessWindow::Maximize() {}
Expand Down
1 change: 1 addition & 0 deletions ui/ozone/platform/headless/headless_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class HeadlessWindow : public PlatformWindow {
void PrepareForShutdown() override;
void SetCapture() override;
void ReleaseCapture() override;
bool HasCapture() const override;
void ToggleFullscreen() override;
void Maximize() override;
void Minimize() override;
Expand Down
3 changes: 3 additions & 0 deletions ui/ozone/platform/wayland/wayland_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class WaylandConnection : public PlatformEventSource,

int GetKeyboardModifiers();

// Returns the current pointer, which may be null.
WaylandPointer* pointer() { return pointer_.get(); }

private:
void Flush();
void DispatchUiEvent(Event* event);
Expand Down
32 changes: 27 additions & 5 deletions ui/ozone/platform/wayland/wayland_pointer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ bool VerifyFlagsAfterMasking(int flags, int original_flags, int modifiers) {
return flags == original_flags;
}

bool HasAnyButtonFlag(int flags) {
return (flags & (EF_LEFT_MOUSE_BUTTON | EF_MIDDLE_MOUSE_BUTTON |
EF_RIGHT_MOUSE_BUTTON | EF_BACK_MOUSE_BUTTON |
EF_FORWARD_MOUSE_BUTTON)) != 0;
}

} // namespace

WaylandPointer::WaylandPointer(wl_pointer* pointer,
Expand All @@ -38,7 +44,12 @@ WaylandPointer::WaylandPointer(wl_pointer* pointer,
cursor_.reset(new WaylandCursor);
}

WaylandPointer::~WaylandPointer() {}
WaylandPointer::~WaylandPointer() {
if (window_with_pointer_focus_) {
window_with_pointer_focus_->set_pointer_focus(false);
window_with_pointer_focus_->set_has_implicit_grab(false);
}
}

// static
void WaylandPointer::Enter(void* data,
Expand All @@ -50,8 +61,11 @@ void WaylandPointer::Enter(void* data,
WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
pointer->location_.SetPoint(wl_fixed_to_double(surface_x),
wl_fixed_to_double(surface_y));
if (surface)
WaylandWindow::FromSurface(surface)->set_pointer_focus(true);
if (surface) {
WaylandWindow* window = WaylandWindow::FromSurface(surface);
window->set_pointer_focus(true);
pointer->window_with_pointer_focus_ = window;
}
}

// static
Expand All @@ -63,8 +77,11 @@ void WaylandPointer::Leave(void* data,
MouseEvent event(ET_MOUSE_EXITED, gfx::Point(), gfx::Point(),
EventTimeForNow(), pointer->flags_, 0);
pointer->callback_.Run(&event);
if (surface)
WaylandWindow::FromSurface(surface)->set_pointer_focus(false);
if (surface) {
WaylandWindow* window = WaylandWindow::FromSurface(surface);
window->set_pointer_focus(false);
pointer->window_with_pointer_focus_ = nullptr;
}
}

// static
Expand Down Expand Up @@ -123,6 +140,11 @@ void WaylandPointer::Button(void* data,
pointer->flags_ &= ~changed_button;
}

if (pointer->window_with_pointer_focus_) {
pointer->window_with_pointer_focus_->set_has_implicit_grab(
HasAnyButtonFlag(pointer->flags_));
}

// MouseEvent's flags should contain the button that was released too.
const int flags = pointer->GetFlagsWithKeyboardModifiers() | changed_button;
MouseEvent event(type, gfx::Point(), gfx::Point(),
Expand Down
14 changes: 14 additions & 0 deletions ui/ozone/platform/wayland/wayland_pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_POINTER_H_
#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_POINTER_H_

#include "base/macros.h"
#include "ui/events/ozone/evdev/event_dispatch_callback.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/ozone/platform/wayland/wayland_cursor.h"
#include "ui/ozone/platform/wayland/wayland_object.h"

namespace ui {

class WaylandWindow;

class WaylandPointer {
public:
WaylandPointer(wl_pointer* pointer, const EventDispatchCallback& callback);
Expand All @@ -26,6 +29,10 @@ class WaylandPointer {

WaylandCursor* cursor() { return cursor_.get(); }

void reset_window_with_pointer_focus() {
window_with_pointer_focus_ = nullptr;
}

private:
// wl_pointer_listener
static void Enter(void* data,
Expand Down Expand Up @@ -60,11 +67,18 @@ class WaylandPointer {
wl::Object<wl_pointer> obj_;
EventDispatchCallback callback_;
gfx::PointF location_;
// Flags is a bitmask of EventFlags corresponding to the pointer/keyboard
// state.
int flags_ = 0;

// Keeps track of current modifiers. These are needed in order to properly
// update |flags_| with newest modifiers.
int keyboard_modifiers_ = 0;

// The window the mouse is over.
WaylandWindow* window_with_pointer_focus_ = nullptr;

DISALLOW_COPY_AND_ASSIGN(WaylandPointer);
};

} // namespace ui
Expand Down
22 changes: 20 additions & 2 deletions ui/ozone/platform/wayland/wayland_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "ui/events/event.h"
#include "ui/events/ozone/events_ozone.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
#include "ui/ozone/platform/wayland/wayland_pointer.h"
#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v5.h"
#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v6.h"

Expand Down Expand Up @@ -55,6 +56,8 @@ WaylandWindow::~WaylandWindow() {
PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
connection_->RemoveWindow(surface_.id());
}
if (has_pointer_focus_)
connection_->pointer()->reset_window_with_pointer_focus();
}

// static
Expand Down Expand Up @@ -134,13 +137,21 @@ void WaylandWindow::SetTitle(const base::string16& title) {
}

void WaylandWindow::SetCapture() {
// Wayland does implicit grabs, and doesn't allow for explicit grabs. The
// exception to that seems to be popups, which can do a grab during show. Need
// to evaluate under what circumstances we need this.
NOTIMPLEMENTED();
}

void WaylandWindow::ReleaseCapture() {
// See comment in SetCapture() for details on wayland and grabs.
NOTIMPLEMENTED();
}

bool WaylandWindow::HasCapture() const {
return has_implicit_grab_;
}

void WaylandWindow::ToggleFullscreen() {
DCHECK(xdg_surface_);

Expand Down Expand Up @@ -267,14 +278,21 @@ void WaylandWindow::HandleSurfaceConfigure(int32_t width,
else
state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_NORMAL;

if (old_state != state_)
delegate_->OnWindowStateChanged(state_);
// Update state before notifying delegate.
const bool did_active_change = is_active_ != is_activated;
is_active_ = is_activated;

// Rather than call SetBounds here for every configure event, just save the
// most recent bounds, and have WaylandConnection call ApplyPendingBounds
// when it has finished processing events. We may get many configure events
// in a row during an interactive resize, and only the last one matters.
SetPendingBounds(width, height);

if (old_state != state_)
delegate_->OnWindowStateChanged(state_);

if (did_active_change)
delegate_->OnActivationChanged(is_active_);
}

void WaylandWindow::OnCloseRequest() {
Expand Down
12 changes: 12 additions & 0 deletions ui/ozone/platform/wayland/wayland_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,21 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {

// Set whether this window has pointer focus and should dispatch mouse events.
void set_pointer_focus(bool focus) { has_pointer_focus_ = focus; }
bool has_pointer_focus() const { return has_pointer_focus_; }

// Set whether this window has keyboard focus and should dispatch key events.
void set_keyboard_focus(bool focus) { has_keyboard_focus_ = focus; }

// Set whether this window has touch focus and should dispatch touch events.
void set_touch_focus(bool focus) { has_touch_focus_ = focus; }

// Set whether this window has an implicit grab (often referred to as capture
// in Chrome code). Implicit grabs happen while a pointer is down.
void set_has_implicit_grab(bool value) { has_implicit_grab_ = value; }
bool has_implicit_grab() const { return has_implicit_grab_; }

bool is_active() const { return is_active_; }

// PlatformWindow
void Show() override;
void Hide() override;
Expand All @@ -60,6 +68,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
void SetTitle(const base::string16& title) override;
void SetCapture() override;
void ReleaseCapture() override;
bool HasCapture() const override;
void ToggleFullscreen() override;
void Maximize() override;
void Minimize() override;
Expand Down Expand Up @@ -113,10 +122,13 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
bool has_pointer_focus_ = false;
bool has_keyboard_focus_ = false;
bool has_touch_focus_ = false;
bool has_implicit_grab_ = false;

// Stores current states of the window.
ui::PlatformWindowState state_;

bool is_active_ = false;

DISALLOW_COPY_AND_ASSIGN(WaylandWindow);
};

Expand Down
58 changes: 56 additions & 2 deletions ui/ozone/platform/wayland/wayland_window_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -323,13 +323,18 @@ TEST_P(WaylandWindowTest, CanDispatchMouseEventDefault) {
}

TEST_P(WaylandWindowTest, CanDispatchMouseEventFocus) {
// set_pointer_focus(true) requires a WaylandPointer.
wl_seat_send_capabilities(server_.seat()->resource(),
WL_SEAT_CAPABILITY_POINTER);
Sync();
ASSERT_TRUE(connection_->pointer());
window_->set_pointer_focus(true);
EXPECT_TRUE(window_->CanDispatchEvent(&test_mouse_event_));
}

TEST_P(WaylandWindowTest, CanDispatchMouseEventUnfocus) {
window_->set_pointer_focus(true);
EXPECT_TRUE(window_->CanDispatchEvent(&test_mouse_event_));
EXPECT_FALSE(window_->has_pointer_focus());
EXPECT_FALSE(window_->CanDispatchEvent(&test_mouse_event_));
}

ACTION_P(CloneEvent, ptr) {
Expand All @@ -352,6 +357,35 @@ TEST_P(WaylandWindowTest, DispatchEvent) {
test_mouse_event_.changed_button_flags());
}

TEST_P(WaylandWindowTest, HasCaptureUpdatedOnPointerEvents) {
wl_seat_send_capabilities(server_.seat()->resource(),
WL_SEAT_CAPABILITY_POINTER);

Sync();

wl::MockPointer* pointer = server_.seat()->pointer_.get();
ASSERT_TRUE(pointer);

wl_pointer_send_enter(pointer->resource(), 1, surface_->resource(), 0, 0);
Sync();
EXPECT_FALSE(window_->HasCapture());

wl_pointer_send_button(pointer->resource(), 2, 1002, BTN_LEFT,
WL_POINTER_BUTTON_STATE_PRESSED);
Sync();
EXPECT_TRUE(window_->HasCapture());

wl_pointer_send_motion(pointer->resource(), 1003, wl_fixed_from_int(400),
wl_fixed_from_int(500));
Sync();
EXPECT_TRUE(window_->HasCapture());

wl_pointer_send_button(pointer->resource(), 4, 1004, BTN_LEFT,
WL_POINTER_BUTTON_STATE_RELEASED);
Sync();
EXPECT_FALSE(window_->HasCapture());
}

TEST_P(WaylandWindowTest, ConfigureEvent) {
wl_array states;
wl_array_init(&states);
Expand Down Expand Up @@ -385,6 +419,26 @@ TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) {
EXPECT_CALL(*xdg_surface_, AckConfigure(14));
}

TEST_P(WaylandWindowTest, OnActivationChanged) {
EXPECT_FALSE(window_->is_active());

{
wl_array states;
InitializeWlArrayWithActivatedState(&states);
EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
SendConfigureEvent(0, 0, 1, &states);
Sync();
EXPECT_TRUE(window_->is_active());
}

wl_array states;
wl_array_init(&states);
EXPECT_CALL(delegate_, OnActivationChanged(Eq(false)));
SendConfigureEvent(0, 0, 2, &states);
Sync();
EXPECT_FALSE(window_->is_active());
}

INSTANTIATE_TEST_CASE_P(XdgVersionV5Test,
WaylandWindowTest,
::testing::Values(kXdgShellV5));
Expand Down
5 changes: 5 additions & 0 deletions ui/platform_window/android/platform_window_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ void PlatformWindowAndroid::ReleaseCapture() {
NOTIMPLEMENTED();
}

bool PlatformWindowAndroid::HasCapture() const {
NOTIMPLEMENTED();
return false;
}

void PlatformWindowAndroid::ToggleFullscreen() {
NOTIMPLEMENTED();
}
Expand Down
Loading

0 comments on commit 5f83d22

Please sign in to comment.