Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(338)

Unified Diff: ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc

Issue 455553003: Do not release capture when starting a move loop on Desktop Linux (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
diff --git a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
index 76a56186095856d66cabb5ac87091bf5848419e3..afef9ab86eeda3e8e1814ca5fbdcee0bf52f65e7 100644
--- a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
+++ b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "ui/aura/client/capture_client.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
@@ -19,38 +20,17 @@
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
#include "ui/events/platform/scoped_event_dispatcher.h"
#include "ui/events/platform/x11/x11_event_source.h"
-#include "ui/gfx/point_conversions.h"
namespace views {
-namespace {
-
-class ScopedCapturer {
- public:
- explicit ScopedCapturer(aura::WindowTreeHost* host)
- : host_(host) {
- host_->SetCapture();
- }
-
- ~ScopedCapturer() {
- host_->ReleaseCapture();
- }
-
- private:
- aura::WindowTreeHost* host_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedCapturer);
-};
-
-} // namespace
-
X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(X11MoveLoopDelegate* delegate)
: delegate_(delegate),
in_move_loop_(false),
+ initial_cursor_(ui::kCursorNull),
should_reset_mouse_flags_(false),
grab_input_window_(None),
+ grabbed_pointer_(false),
canceled_(false),
- has_grab_(false),
weak_factory_(this) {
last_xmotion_.type = LASTEvent;
}
@@ -74,19 +54,11 @@ bool X11WholeScreenMoveLoop::CanDispatchEvent(const ui::PlatformEvent& event) {
}
uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
- // This method processes all events for the grab_input_window_ as well as
- // mouse events for all windows while the move loop is active - even before
- // the grab is granted by X. This allows mouse notification events that were
- // sent after the capture was requested but before the capture was granted
- // to be dispatched. It is especially important to process the mouse release
- // event that should have stopped the drag even if that mouse release happened
- // before the grab was granted.
+ // This method processes all events while the move loop is active.
if (!in_move_loop_)
return ui::POST_DISPATCH_PERFORM_DEFAULT;
- XEvent* xev = event;
- // Note: the escape key is handled in the tab drag controller, which has
- // keyboard focus even though we took pointer grab.
+ XEvent* xev = event;
switch (xev->type) {
case MotionNotify: {
last_xmotion_ = xev->xmotion;
@@ -107,6 +79,13 @@ uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
// break the drag if the left mouse button was released.
DispatchMouseMovement();
delegate_->OnMouseReleased();
+
+ if (!grabbed_pointer_) {
+ // If the source widget had capture prior to the move loop starting,
+ // it may be relying on views::Widget getting the mouse release and
+ // releasing capture in Widget::OnMouseEvent().
+ return ui::POST_DISPATCH_PERFORM_DEFAULT;
+ }
}
return ui::POST_DISPATCH_NONE;
}
@@ -118,11 +97,6 @@ uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
}
break;
}
- case FocusOut: {
- if (xev->xfocus.mode != NotifyGrab)
- has_grab_ = false;
- break;
- }
case GenericEvent: {
ui::EventType type = ui::EventTypeFromNative(xev);
switch (type) {
@@ -146,8 +120,7 @@ uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
gfx::Point point(ui::EventSystemLocationFromNative(xev));
xevent.xmotion.x_root = point.x();
xevent.xmotion.y_root = point.y();
- DispatchEvent(&xevent);
- return ui::POST_DISPATCH_NONE;
+ return DispatchEvent(&xevent);
}
default:
break;
@@ -155,31 +128,39 @@ uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
}
}
- return (event->xany.window == grab_input_window_) ?
- ui::POST_DISPATCH_NONE : ui::POST_DISPATCH_PERFORM_DEFAULT;
+ return ui::POST_DISPATCH_PERFORM_DEFAULT;
}
bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
gfx::NativeCursor cursor) {
DCHECK(!in_move_loop_); // Can only handle one nested loop at a time.
- // Start a capture on the host, so that it continues to receive events during
- // the drag. This may be second time we are capturing the mouse events - the
- // first being when a mouse is first pressed. That first capture needs to be
- // released before the call to GrabPointerAndKeyboard below, otherwise it may
- // get released while we still need the pointer grab, which is why we restrict
- // the scope here.
- {
- ScopedCapturer capturer(source->GetHost());
-
- grab_input_window_ = CreateDragInputWindow(gfx::GetXDisplay());
- // Releasing ScopedCapturer ensures that any other instance of
- // X11ScopedCapture will not prematurely release grab that will be acquired
- // below.
+ // Query the mouse cursor prior to the move loop starting so that it can be
+ // restored when the move loop finishes.
+ initial_cursor_ = source->GetHost()->last_cursor();
+
+ grab_input_window_ = CreateDragInputWindow(gfx::GetXDisplay());
+
+ // Only grab mouse capture of |grab_input_window_| if |source| does not have
+ // capture.
+ // - The caller may intend to transfer capture to a different aura::Window
+ // when the move loop ends and not release capture.
+ // - Releasing capture and X window destruction are both asynchronous. We drop
+ // events targeted at |grab_input_window_| in the time between the move
+ // loop ends and |grab_input_window_| loses capture.
+ grabbed_pointer_ = false;
+ if (!source->HasCapture()) {
+ aura::client::CaptureClient* capture_client =
+ aura::client::GetCaptureClient(source->GetRootWindow());
+ CHECK(capture_client->GetGlobalCaptureWindow() == NULL);
+ grabbed_pointer_ = GrabPointer(cursor);
+ if (!grabbed_pointer_) {
+ XDestroyWindow(gfx::GetXDisplay(), grab_input_window_);
+ return false;
+ }
}
- // TODO(varkha): Consider integrating GrabPointerAndKeyboard with
- // ScopedCapturer to avoid possibility of logically keeping multiple grabs.
- if (!GrabPointerAndKeyboard(cursor)) {
+
+ if (!GrabKeyboard()) {
XDestroyWindow(gfx::GetXDisplay(), grab_input_window_);
return false;
}
@@ -189,9 +170,9 @@ bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
nested_dispatcher_ =
ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this);
- // We are handling a mouse drag outside of the aura::RootWindow system. We
- // must manually make aura think that the mouse button is pressed so that we
- // don't draw extraneous tooltips.
+ // We are handling a mouse drag outside of the aura::Window system. We must
+ // manually make aura think that the mouse button is pressed so that we don't
+ // draw extraneous tooltips.
aura::Env* env = aura::Env::GetInstance();
if (!env->IsMouseButtonDown()) {
env->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON);
@@ -211,10 +192,13 @@ bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
void X11WholeScreenMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {
if (in_move_loop_) {
- // If we're still in the move loop, regrab the pointer with the updated
- // cursor. Note: we can be called from handling an XdndStatus message after
- // EndMoveLoop() was called, but before we return from the nested RunLoop.
- GrabPointerAndKeyboard(cursor);
+ // We cannot call GrabPointer() because we do not want to change the
+ // "owner_events" property of the active pointer grab.
+ XChangeActivePointerGrab(
+ gfx::GetXDisplay(),
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+ cursor.platform(),
+ CurrentTime);
}
}
@@ -238,11 +222,12 @@ void X11WholeScreenMoveLoop::EndMoveLoop() {
// Ungrab before we let go of the window.
XDisplay* display = gfx::GetXDisplay();
- // Only ungrab pointer if capture was not switched to another window.
- if (has_grab_) {
+ if (grabbed_pointer_)
XUngrabPointer(display, CurrentTime);
- XUngrabKeyboard(display, CurrentTime);
- }
+ else
+ UpdateCursor(initial_cursor_);
+
+ XUngrabKeyboard(display, CurrentTime);
// Restore the previous dispatcher.
nested_dispatcher_.reset();
@@ -254,15 +239,16 @@ void X11WholeScreenMoveLoop::EndMoveLoop() {
quit_closure_.Run();
}
-bool X11WholeScreenMoveLoop::GrabPointerAndKeyboard(gfx::NativeCursor cursor) {
+bool X11WholeScreenMoveLoop::GrabPointer(gfx::NativeCursor cursor) {
XDisplay* display = gfx::GetXDisplay();
XGrabServer(display);
- XUngrabPointer(display, CurrentTime);
+ // Pass "owner_events" as false so that X sends all mouse events to
+ // |grab_input_window_|.
int ret = XGrabPointer(
display,
grab_input_window_,
- False,
+ False, // owner_events
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync,
GrabModeAsync,
@@ -272,33 +258,29 @@ bool X11WholeScreenMoveLoop::GrabPointerAndKeyboard(gfx::NativeCursor cursor) {
if (ret != GrabSuccess) {
DLOG(ERROR) << "Grabbing pointer for dragging failed: "
<< ui::GetX11ErrorString(display, ret);
- } else {
- has_grab_ = true;
- XUngrabKeyboard(display, CurrentTime);
- ret = XGrabKeyboard(
- display,
- grab_input_window_,
- False,
- GrabModeAsync,
- GrabModeAsync,
- CurrentTime);
- if (ret != GrabSuccess) {
- DLOG(ERROR) << "Grabbing keyboard for dragging failed: "
- << ui::GetX11ErrorString(display, ret);
- }
}
-
XUngrabServer(display);
XFlush(display);
return ret == GrabSuccess;
}
+bool X11WholeScreenMoveLoop::GrabKeyboard() {
+ XDisplay* display = gfx::GetXDisplay();
+ int ret = XGrabKeyboard(display,
+ grab_input_window_,
+ False,
+ GrabModeAsync,
+ GrabModeAsync,
+ CurrentTime);
+ if (ret != GrabSuccess) {
+ DLOG(ERROR) << "Grabbing keyboard for dragging failed: "
+ << ui::GetX11ErrorString(display, ret);
+ return false;
+ }
+ return true;
+}
+
Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
- // Creates an invisible, InputOnly toplevel window. This window will receive
- // all mouse movement for drags. It turns out that normal windows doing a
- // grab doesn't redirect pointer motion events if the pointer isn't over the
- // grabbing window. But InputOnly windows are able to grab everything. This
- // is what GTK+ does, and I found a patch to KDE that did something similar.
unsigned long attribute_mask = CWEventMask | CWOverrideRedirect;
XSetWindowAttributes swa;
memset(&swa, 0, sizeof(swa));
« no previous file with comments | « ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698