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

Side by Side Diff: ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc

Issue 83783003: linux aura: Show the drag-image when available. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h ('k') | ui/views/widget/widget.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h" 5 #include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
6 6
7 #include <X11/Xlib.h> 7 #include <X11/Xlib.h>
8 // Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. 8 // Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
9 #undef RootWindow 9 #undef RootWindow
10 10
11 #include "base/debug/stack_trace.h" 11 #include "base/debug/stack_trace.h"
12 #include "base/message_loop/message_loop.h" 12 #include "base/message_loop/message_loop.h"
13 #include "base/message_loop/message_pump_x11.h" 13 #include "base/message_loop/message_pump_x11.h"
14 #include "base/run_loop.h" 14 #include "base/run_loop.h"
15 #include "ui/aura/env.h" 15 #include "ui/aura/env.h"
16 #include "ui/aura/root_window.h" 16 #include "ui/aura/root_window.h"
17 #include "ui/aura/window.h" 17 #include "ui/aura/window.h"
18 #include "ui/aura/window_tree_host.h" 18 #include "ui/aura/window_tree_host.h"
19 #include "ui/base/x/x11_util.h" 19 #include "ui/base/x/x11_util.h"
20 #include "ui/events/event.h" 20 #include "ui/events/event.h"
21 #include "ui/gfx/point_conversions.h"
21 #include "ui/gfx/screen.h" 22 #include "ui/gfx/screen.h"
23 #include "ui/views/controls/image_view.h"
24 #include "ui/views/widget/widget.h"
22 25
23 namespace views { 26 namespace views {
24 27
25 namespace { 28 namespace {
26 29
27 class ScopedCapturer { 30 class ScopedCapturer {
28 public: 31 public:
29 explicit ScopedCapturer(aura::RootWindowHost* host) 32 explicit ScopedCapturer(aura::RootWindowHost* host)
30 : host_(host) { 33 : host_(host) {
31 host_->SetCapture(); 34 host_->SetCapture();
32 } 35 }
33 36
34 ~ScopedCapturer() { 37 ~ScopedCapturer() {
35 host_->ReleaseCapture(); 38 host_->ReleaseCapture();
36 } 39 }
37 40
38 private: 41 private:
39 aura::RootWindowHost* host_; 42 aura::RootWindowHost* host_;
40 43
41 DISALLOW_COPY_AND_ASSIGN(ScopedCapturer); 44 DISALLOW_COPY_AND_ASSIGN(ScopedCapturer);
42 }; 45 };
43 46
44 } // namespace 47 } // namespace
45 48
46 X11WholeScreenMoveLoop::X11WholeScreenMoveLoop( 49 X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(
47 X11WholeScreenMoveLoopDelegate* delegate) 50 X11WholeScreenMoveLoopDelegate* delegate)
48 : delegate_(delegate), 51 : delegate_(delegate),
49 in_move_loop_(false), 52 in_move_loop_(false),
50 grab_input_window_(None) /*, 53 grab_input_window_(None) {
51 root_window_(NULL)*/ {
52 } 54 }
53 55
54 X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {} 56 X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {}
55 57
56 //////////////////////////////////////////////////////////////////////////////// 58 ////////////////////////////////////////////////////////////////////////////////
57 // DesktopRootWindowHostLinux, MessageLoop::Dispatcher implementation: 59 // DesktopRootWindowHostLinux, MessageLoop::Dispatcher implementation:
58 60
59 bool X11WholeScreenMoveLoop::Dispatch(const base::NativeEvent& event) { 61 bool X11WholeScreenMoveLoop::Dispatch(const base::NativeEvent& event) {
60 XEvent* xev = event; 62 XEvent* xev = event;
61 63
62 // Note: the escape key is handled in the tab drag controller, which has 64 // Note: the escape key is handled in the tab drag controller, which has
63 // keyboard focus even though we took pointer grab. 65 // keyboard focus even though we took pointer grab.
64 switch (xev->type) { 66 switch (xev->type) {
65 case MotionNotify: { 67 case MotionNotify: {
68 if (drag_widget_.get()) {
69 gfx::Screen* screen = gfx::Screen::GetNativeScreen();
70 gfx::Point location = gfx::ToFlooredPoint(
71 screen->GetCursorScreenPoint() - drag_offset_);
72 drag_widget_->SetBounds(gfx::Rect(location, drag_image_.size()));
73 }
66 delegate_->OnMouseMovement(&xev->xmotion); 74 delegate_->OnMouseMovement(&xev->xmotion);
67 break; 75 break;
68 } 76 }
69 case ButtonRelease: { 77 case ButtonRelease: {
70 if (xev->xbutton.button == Button1) { 78 if (xev->xbutton.button == Button1) {
71 // Assume that drags are being done with the left mouse button. Only 79 // Assume that drags are being done with the left mouse button. Only
72 // break the drag if the left mouse button was released. 80 // break the drag if the left mouse button was released.
73 delegate_->OnMouseReleased(); 81 delegate_->OnMouseReleased();
74 } 82 }
75 break; 83 break;
(...skipping 10 matching lines...) Expand all
86 gfx::NativeCursor cursor) { 94 gfx::NativeCursor cursor) {
87 // Start a capture on the host, so that it continues to receive events during 95 // Start a capture on the host, so that it continues to receive events during
88 // the drag. 96 // the drag.
89 ScopedCapturer capturer(source->GetDispatcher()->host()); 97 ScopedCapturer capturer(source->GetDispatcher()->host());
90 98
91 DCHECK(!in_move_loop_); // Can only handle one nested loop at a time. 99 DCHECK(!in_move_loop_); // Can only handle one nested loop at a time.
92 in_move_loop_ = true; 100 in_move_loop_ = true;
93 101
94 XDisplay* display = gfx::GetXDisplay(); 102 XDisplay* display = gfx::GetXDisplay();
95 103
96 // Creates an invisible, InputOnly toplevel window. This window will receive 104 grab_input_window_ = CreateDragInputWindow(display);
97 // all mouse movement for drags. It turns out that normal windows doing a 105 if (!drag_image_.isNull())
98 // grab doesn't redirect pointer motion events if the pointer isn't over the 106 CreateDragImageWindow();
99 // grabbing window. But InputOnly windows are able to grab everything. This
100 // is what GTK+ does, and I found a patch to KDE that did something similar.
101 unsigned long attribute_mask = CWEventMask | CWOverrideRedirect;
102 XSetWindowAttributes swa;
103 memset(&swa, 0, sizeof(swa));
104 swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
105 StructureNotifyMask;
106 swa.override_redirect = True;
107 grab_input_window_ = XCreateWindow(
108 display,
109 DefaultRootWindow(display),
110 -100, -100, 10, 10,
111 0, 0, InputOnly, CopyFromParent,
112 attribute_mask, &swa);
113 base::MessagePumpX11::Current()->AddDispatcherForWindow( 107 base::MessagePumpX11::Current()->AddDispatcherForWindow(
114 this, grab_input_window_); 108 this, grab_input_window_);
115 109
116 // Wait for the window to be mapped. If we don't, XGrabPointer fails.
117 XMapRaised(display, grab_input_window_);
118 base::MessagePumpX11::Current()->BlockUntilWindowMapped(
119 grab_input_window_);
120
121 if (!GrabPointerWithCursor(cursor)) 110 if (!GrabPointerWithCursor(cursor))
122 return false; 111 return false;
123 112
124 // We are handling a mouse drag outside of the aura::RootWindow system. We 113 // We are handling a mouse drag outside of the aura::RootWindow system. We
125 // must manually make aura think that the mouse button is pressed so that we 114 // must manually make aura think that the mouse button is pressed so that we
126 // don't draw extraneous tooltips. 115 // don't draw extraneous tooltips.
127 aura::Env::GetInstance()->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON); 116 aura::Env::GetInstance()->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON);
128 117
129 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 118 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
130 base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop); 119 base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
(...skipping 18 matching lines...) Expand all
149 // TODO(erg): Is this ungrab the cause of having to click to give input focus 138 // TODO(erg): Is this ungrab the cause of having to click to give input focus
150 // on drawn out windows? Not ungrabbing here screws the X server until I kill 139 // on drawn out windows? Not ungrabbing here screws the X server until I kill
151 // the chrome process. 140 // the chrome process.
152 141
153 // Ungrab before we let go of the window. 142 // Ungrab before we let go of the window.
154 XDisplay* display = gfx::GetXDisplay(); 143 XDisplay* display = gfx::GetXDisplay();
155 XUngrabPointer(display, CurrentTime); 144 XUngrabPointer(display, CurrentTime);
156 145
157 base::MessagePumpX11::Current()->RemoveDispatcherForWindow( 146 base::MessagePumpX11::Current()->RemoveDispatcherForWindow(
158 grab_input_window_); 147 grab_input_window_);
148 drag_widget_.reset();
159 delegate_->OnMoveLoopEnded(); 149 delegate_->OnMoveLoopEnded();
160 XDestroyWindow(display, grab_input_window_); 150 XDestroyWindow(display, grab_input_window_);
161 151
162 in_move_loop_ = false; 152 in_move_loop_ = false;
163 quit_closure_.Run(); 153 quit_closure_.Run();
164 } 154 }
165 155
156 void X11WholeScreenMoveLoop::SetDragImage(const gfx::ImageSkia& image,
157 gfx::Vector2dF offset) {
158 drag_image_ = image;
159 drag_offset_ = offset;
160 // Reset the Y offset, so that the drag-image is always just below the cursor,
161 // so that it is possible to see where the cursor is going.
162 drag_offset_.set_y(0.f);
163 }
164
166 bool X11WholeScreenMoveLoop::GrabPointerWithCursor(gfx::NativeCursor cursor) { 165 bool X11WholeScreenMoveLoop::GrabPointerWithCursor(gfx::NativeCursor cursor) {
167 XDisplay* display = gfx::GetXDisplay(); 166 XDisplay* display = gfx::GetXDisplay();
168 XGrabServer(display); 167 XGrabServer(display);
169 XUngrabPointer(display, CurrentTime); 168 XUngrabPointer(display, CurrentTime);
170 int ret = XGrabPointer( 169 int ret = XGrabPointer(
171 display, 170 display,
172 grab_input_window_, 171 grab_input_window_,
173 False, 172 False,
174 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, 173 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
175 GrabModeAsync, 174 GrabModeAsync,
176 GrabModeAsync, 175 GrabModeAsync,
177 None, 176 None,
178 cursor.platform(), 177 cursor.platform(),
179 CurrentTime); 178 CurrentTime);
180 XUngrabServer(display); 179 XUngrabServer(display);
181 if (ret != GrabSuccess) { 180 if (ret != GrabSuccess) {
182 DLOG(ERROR) << "Grabbing new tab for dragging failed: " 181 DLOG(ERROR) << "Grabbing new tab for dragging failed: "
183 << ui::GetX11ErrorString(display, ret); 182 << ui::GetX11ErrorString(display, ret);
184 return false; 183 return false;
185 } 184 }
186 185
187 return true; 186 return true;
188 } 187 }
189 188
189 Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
190 // Creates an invisible, InputOnly toplevel window. This window will receive
191 // all mouse movement for drags. It turns out that normal windows doing a
192 // grab doesn't redirect pointer motion events if the pointer isn't over the
193 // grabbing window. But InputOnly windows are able to grab everything. This
194 // is what GTK+ does, and I found a patch to KDE that did something similar.
195 unsigned long attribute_mask = CWEventMask | CWOverrideRedirect;
196 XSetWindowAttributes swa;
197 memset(&swa, 0, sizeof(swa));
198 swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
199 StructureNotifyMask;
200 swa.override_redirect = True;
201 Window window = XCreateWindow(display,
202 DefaultRootWindow(display),
203 -100, -100, 10, 10,
204 0, CopyFromParent, InputOnly, CopyFromParent,
205 attribute_mask, &swa);
206 XMapRaised(display, window);
207 base::MessagePumpX11::Current()->BlockUntilWindowMapped(window);
208 return window;
209 }
210
211 void X11WholeScreenMoveLoop::CreateDragImageWindow() {
212 Widget* widget = new Widget;
213 Widget::InitParams params(Widget::InitParams::TYPE_DRAG);
214 params.opacity = Widget::InitParams::OPAQUE_WINDOW;
215 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
216 params.accept_events = false;
217
218 gfx::Point location = gfx::ToFlooredPoint(
219 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint() - drag_offset_);
220 params.bounds = gfx::Rect(location, drag_image_.size());
221 widget->set_focus_on_creation(false);
222 widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE);
223 widget->Init(params);
224 widget->GetNativeWindow()->SetName("DragWindow");
225
226 ImageView* image = new ImageView();
227 image->SetImage(drag_image_);
228 image->SetBounds(0, 0, drag_image_.width(), drag_image_.height());
229 widget->SetContentsView(image);
230
231 widget->Show();
232 widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false);
233
234 drag_widget_.reset(widget);
235 }
236
190 } // namespace views 237 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h ('k') | ui/views/widget/widget.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698