Chromium Code Reviews| 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 86cacf1cfd2b5fd7fe0082df4542da2fae843821..f3dc181bdc1f2275bb563561d2f712aa5ae73bca 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 |
| @@ -18,7 +18,10 @@ |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/base/x/x11_util.h" |
| #include "ui/events/event.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 { |
| @@ -47,8 +50,7 @@ X11WholeScreenMoveLoop::X11WholeScreenMoveLoop( |
| X11WholeScreenMoveLoopDelegate* delegate) |
| : delegate_(delegate), |
| in_move_loop_(false), |
| - grab_input_window_(None) /*, |
| - root_window_(NULL)*/ { |
| + grab_input_window_(None) { |
| } |
| X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {} |
| @@ -63,6 +65,12 @@ bool X11WholeScreenMoveLoop::Dispatch(const base::NativeEvent& 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())); |
| + } |
| delegate_->OnMouseMovement(&xev->xmotion); |
| break; |
| } |
| @@ -93,31 +101,12 @@ bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source, |
| XDisplay* display = gfx::GetXDisplay(); |
| - // 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 | |
| - StructureNotifyMask; |
| - swa.override_redirect = True; |
| - grab_input_window_ = XCreateWindow( |
| - display, |
| - DefaultRootWindow(display), |
| - -100, -100, 10, 10, |
| - 0, 0, InputOnly, CopyFromParent, |
| - attribute_mask, &swa); |
| + grab_input_window_ = CreateDragInputWindow(display); |
| + if (!drag_image_.isNull()) |
| + CreateDragImageWindow(); |
| base::MessagePumpX11::Current()->AddDispatcherForWindow( |
| this, grab_input_window_); |
| - // Wait for the window to be mapped. If we don't, XGrabPointer fails. |
| - XMapRaised(display, grab_input_window_); |
| - base::MessagePumpX11::Current()->BlockUntilWindowMapped( |
| - grab_input_window_); |
| - |
| if (!GrabPointerWithCursor(cursor)) |
| return false; |
| @@ -156,6 +145,7 @@ void X11WholeScreenMoveLoop::EndMoveLoop() { |
| base::MessagePumpX11::Current()->RemoveDispatcherForWindow( |
| grab_input_window_); |
| + drag_widget_.reset(); |
| delegate_->OnMoveLoopEnded(); |
| XDestroyWindow(display, grab_input_window_); |
| @@ -163,6 +153,15 @@ void X11WholeScreenMoveLoop::EndMoveLoop() { |
| 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::GrabPointerWithCursor(gfx::NativeCursor cursor) { |
| XDisplay* display = gfx::GetXDisplay(); |
| XGrabServer(display); |
| @@ -187,4 +186,54 @@ bool X11WholeScreenMoveLoop::GrabPointerWithCursor(gfx::NativeCursor cursor) { |
| 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)); |
| + swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | |
| + 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); |
| + base::MessagePumpX11::Current()->BlockUntilWindowMapped(window); |
| + return window; |
| +} |
| + |
| +void X11WholeScreenMoveLoop::CreateDragImageWindow() { |
| + Widget* widget = new Widget; |
| + Widget::InitParams params(Widget::InitParams::TYPE_POPUP); |
|
Elliot Glaysher
2013/11/22 20:19:19
I'm pretty sure you want to do something here that
sadrul
2013/11/22 21:16:30
Good point. Done.
|
| + params.opacity = Widget::InitParams::OPAQUE_WINDOW; |
| + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| + params.can_activate = false; |
| + params.keep_on_top = true; |
| + params.accept_events = true; |
| + |
| + 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->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); |
| +} |
| + |
| } // namespace views |