| 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 6c0b3c6b9e7962b9c3410a2a6916458ee80179f8..5a49e462cfa7de59a0532cfef18c50daf42d99b6 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
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
|
|
|
| +#include <X11/extensions/XInput2.h>
|
| #include <X11/Xlib.h>
|
| // Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
|
| #undef RootWindow
|
| @@ -11,56 +12,23 @@
|
| #include "base/bind.h"
|
| #include "base/message_loop/message_loop.h"
|
| #include "base/run_loop.h"
|
| -#include "third_party/skia/include/core/SkBitmap.h"
|
| #include "ui/aura/env.h"
|
| #include "ui/aura/window.h"
|
| #include "ui/aura/window_event_dispatcher.h"
|
| -#include "ui/aura/window_tree_host.h"
|
| #include "ui/base/x/x11_util.h"
|
| #include "ui/events/event.h"
|
| #include "ui/events/event_utils.h"
|
| #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"
|
| -#include "ui/gfx/screen.h"
|
| -#include "ui/views/controls/image_view.h"
|
| -#include "ui/views/widget/widget.h"
|
|
|
| namespace views {
|
|
|
| -namespace {
|
| -
|
| -// The minimum alpha before we declare a pixel transparent when searching in
|
| -// our source image.
|
| -const uint32 kMinAlpha = 32;
|
| -const unsigned char kDragWidgetOpacity = 0xc0;
|
| -
|
| -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(
|
| X11WholeScreenMoveLoopDelegate* delegate)
|
| : delegate_(delegate),
|
| in_move_loop_(false),
|
| should_reset_mouse_flags_(false),
|
| - grab_input_window_(None),
|
| canceled_(false),
|
| has_grab_(false),
|
| weak_factory_(this) {
|
| @@ -82,17 +50,13 @@ void X11WholeScreenMoveLoop::DispatchMouseMovement() {
|
| // DesktopWindowTreeHostLinux, ui::PlatformEventDispatcher implementation:
|
|
|
| bool X11WholeScreenMoveLoop::CanDispatchEvent(const ui::PlatformEvent& event) {
|
| - return in_move_loop_;
|
| + NOTREACHED();
|
| + return true;
|
| }
|
|
|
| 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 mouse events for all windows while the move loop
|
| + // is active.
|
| if (!in_move_loop_)
|
| return ui::POST_DISPATCH_PERFORM_DEFAULT;
|
| XEvent* xev = event;
|
| @@ -101,13 +65,6 @@ uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
|
| // keyboard focus even though we took pointer grab.
|
| switch (xev->type) {
|
| case MotionNotify: {
|
| - if (drag_widget_.get()) {
|
| - gfx::Screen* screen = gfx::Screen::GetNativeScreen();
|
| - gfx::Point location = gfx::ToFlooredPoint(
|
| - screen->GetCursorScreenPoint() - drag_offset_);
|
| - drag_widget_->SetBounds(gfx::Rect(location, drag_image_.size()));
|
| - drag_widget_->StackAtTop();
|
| - }
|
| last_xmotion_ = xev->xmotion;
|
| if (!weak_factory_.HasWeakPtrs()) {
|
| // Post a task to dispatch mouse movement event when control returns to
|
| @@ -127,12 +84,24 @@ uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
|
| DispatchMouseMovement();
|
| delegate_->OnMouseReleased();
|
| }
|
| - return ui::POST_DISPATCH_NONE;
|
| + // Default will end up releasing capture in Widget::OnMouseEvent().
|
| + return ui::POST_DISPATCH_PERFORM_DEFAULT;
|
| }
|
| case KeyPress: {
|
| if (ui::KeyboardCodeFromXKeyEvent(xev) == ui::VKEY_ESCAPE) {
|
| canceled_ = true;
|
| EndMoveLoop();
|
| + // After the move loop ends the capture will get released.
|
| + // How it gets released depends on what move loop this is (i.e. tab
|
| + // dragging or drag and drop).
|
| + // When dragging browser tabs this will happen when the tab loses focus
|
| + // since either the dragged browser frame is getting destroyed (for
|
| + // dragging out into a new frame) or the focus gets moved back to the
|
| + // source browser (when trying to drag into another browser in which
|
| + // case the EscapeTracker will dispatch the KeyPress event).
|
| + // For drag and drop scenarios the capture is on the drag widget and
|
| + // will get lost when the drag widget is destroyed in
|
| + // DesktopDragDropClientAuraX11::OnMoveLoopEnded().
|
| return ui::POST_DISPATCH_NONE;
|
| }
|
| break;
|
| @@ -156,7 +125,9 @@ uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
|
| xevent.type = MotionNotify;
|
| }
|
| xevent.xany.display = xev->xgeneric.display;
|
| - xevent.xany.window = grab_input_window_;
|
| + XIDeviceEvent* xievent =
|
| + static_cast<XIDeviceEvent*>(xev->xcookie.data);
|
| + xevent.xany.window = xievent->event;
|
| // The fields used below are in the same place for all of events
|
| // above. Using xmotion from XEvent's unions to avoid repeating
|
| // the code.
|
| @@ -165,8 +136,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;
|
| @@ -174,41 +144,16 @@ 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) {
|
| +bool X11WholeScreenMoveLoop::RunMoveLoop() {
|
| 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.
|
| - }
|
| - // TODO(varkha): Consider integrating GrabPointerAndKeyboard with
|
| - // ScopedCapturer to avoid possibility of logically keeping multiple grabs.
|
| - if (!GrabPointerAndKeyboard(cursor)) {
|
| - XDestroyWindow(gfx::GetXDisplay(), grab_input_window_);
|
| - return false;
|
| - }
|
| -
|
| scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher =
|
| nested_dispatcher_.Pass();
|
| nested_dispatcher_ =
|
| - ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this);
|
| - if (!drag_image_.isNull() && CheckIfIconValid())
|
| - CreateDragImageWindow();
|
| + 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
|
| @@ -230,15 +175,6 @@ bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
|
| return !canceled_;
|
| }
|
|
|
| -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);
|
| - }
|
| -}
|
| -
|
| void X11WholeScreenMoveLoop::EndMoveLoop() {
|
| if (!in_move_loop_)
|
| return;
|
| @@ -253,141 +189,12 @@ void X11WholeScreenMoveLoop::EndMoveLoop() {
|
| should_reset_mouse_flags_ = false;
|
| }
|
|
|
| - // TODO(erg): Is this ungrab the cause of having to click to give input focus
|
| - // on drawn out windows? Not ungrabbing here screws the X server until I kill
|
| - // the chrome process.
|
| -
|
| - // 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_) {
|
| - XUngrabPointer(display, CurrentTime);
|
| - XUngrabKeyboard(display, CurrentTime);
|
| - }
|
| -
|
| // Restore the previous dispatcher.
|
| nested_dispatcher_.reset();
|
| - drag_widget_.reset();
|
| delegate_->OnMoveLoopEnded();
|
| - XDestroyWindow(display, grab_input_window_);
|
| - grab_input_window_ = None;
|
|
|
| in_move_loop_ = false;
|
| quit_closure_.Run();
|
| }
|
|
|
| -void X11WholeScreenMoveLoop::SetDragImage(const gfx::ImageSkia& image,
|
| - gfx::Vector2dF offset) {
|
| - drag_image_ = image;
|
| - drag_offset_ = offset;
|
| - // Reset the Y offset, so that the drag-image is always just below the cursor,
|
| - // so that it is possible to see where the cursor is going.
|
| - drag_offset_.set_y(0.f);
|
| -}
|
| -
|
| -bool X11WholeScreenMoveLoop::GrabPointerAndKeyboard(gfx::NativeCursor cursor) {
|
| - XDisplay* display = gfx::GetXDisplay();
|
| - XGrabServer(display);
|
| -
|
| - XUngrabPointer(display, CurrentTime);
|
| - int ret = XGrabPointer(
|
| - display,
|
| - grab_input_window_,
|
| - False,
|
| - ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
|
| - GrabModeAsync,
|
| - GrabModeAsync,
|
| - None,
|
| - cursor.platform(),
|
| - CurrentTime);
|
| - 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;
|
| -}
|
| -
|
| -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));
|
| - swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
|
| - KeyPressMask | KeyReleaseMask | StructureNotifyMask;
|
| - swa.override_redirect = True;
|
| - Window window = XCreateWindow(display,
|
| - DefaultRootWindow(display),
|
| - -100, -100, 10, 10,
|
| - 0, CopyFromParent, InputOnly, CopyFromParent,
|
| - attribute_mask, &swa);
|
| - XMapRaised(display, window);
|
| - ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(window);
|
| - return window;
|
| -}
|
| -
|
| -void X11WholeScreenMoveLoop::CreateDragImageWindow() {
|
| - Widget* widget = new Widget;
|
| - Widget::InitParams params(Widget::InitParams::TYPE_DRAG);
|
| - params.opacity = Widget::InitParams::OPAQUE_WINDOW;
|
| - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
| - params.accept_events = false;
|
| -
|
| - gfx::Point location = gfx::ToFlooredPoint(
|
| - gfx::Screen::GetNativeScreen()->GetCursorScreenPoint() - drag_offset_);
|
| - params.bounds = gfx::Rect(location, drag_image_.size());
|
| - widget->set_focus_on_creation(false);
|
| - widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE);
|
| - widget->Init(params);
|
| - widget->SetOpacity(kDragWidgetOpacity);
|
| - widget->GetNativeWindow()->SetName("DragWindow");
|
| -
|
| - ImageView* image = new ImageView();
|
| - image->SetImage(drag_image_);
|
| - image->SetBounds(0, 0, drag_image_.width(), drag_image_.height());
|
| - widget->SetContentsView(image);
|
| - widget->Show();
|
| - widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false);
|
| -
|
| - drag_widget_.reset(widget);
|
| -}
|
| -
|
| -bool X11WholeScreenMoveLoop::CheckIfIconValid() {
|
| - // Because we need a GL context per window, we do a quick check so that we
|
| - // don't make another context if the window would just be displaying a mostly
|
| - // transparent image.
|
| - const SkBitmap* in_bitmap = drag_image_.bitmap();
|
| - SkAutoLockPixels in_lock(*in_bitmap);
|
| - for (int y = 0; y < in_bitmap->height(); ++y) {
|
| - uint32* in_row = in_bitmap->getAddr32(0, y);
|
| -
|
| - for (int x = 0; x < in_bitmap->width(); ++x) {
|
| - if (SkColorGetA(in_row[x]) > kMinAlpha)
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| } // namespace views
|
|
|