OLD | NEW |
---|---|
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 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
11 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
12 #include "ui/aura/client/capture_client.h" | |
12 #include "ui/aura/env.h" | 13 #include "ui/aura/env.h" |
13 #include "ui/aura/window.h" | 14 #include "ui/aura/window.h" |
14 #include "ui/aura/window_event_dispatcher.h" | 15 #include "ui/aura/window_event_dispatcher.h" |
15 #include "ui/aura/window_tree_host.h" | 16 #include "ui/aura/window_tree_host.h" |
16 #include "ui/base/x/x11_util.h" | 17 #include "ui/base/x/x11_util.h" |
17 #include "ui/events/event.h" | 18 #include "ui/events/event.h" |
18 #include "ui/events/event_utils.h" | 19 #include "ui/events/event_utils.h" |
19 #include "ui/events/keycodes/keyboard_code_conversion_x.h" | 20 #include "ui/events/keycodes/keyboard_code_conversion_x.h" |
20 #include "ui/events/platform/scoped_event_dispatcher.h" | 21 #include "ui/events/platform/scoped_event_dispatcher.h" |
21 #include "ui/events/platform/x11/x11_event_source.h" | 22 #include "ui/events/platform/x11/x11_event_source.h" |
22 #include "ui/gfx/point_conversions.h" | |
23 | 23 |
24 namespace views { | 24 namespace views { |
25 | 25 |
26 namespace { | |
27 | |
28 class ScopedCapturer { | |
29 public: | |
30 explicit ScopedCapturer(aura::WindowTreeHost* host) | |
31 : host_(host) { | |
32 host_->SetCapture(); | |
33 } | |
34 | |
35 ~ScopedCapturer() { | |
36 host_->ReleaseCapture(); | |
37 } | |
38 | |
39 private: | |
40 aura::WindowTreeHost* host_; | |
41 | |
42 DISALLOW_COPY_AND_ASSIGN(ScopedCapturer); | |
43 }; | |
44 | |
45 } // namespace | |
46 | |
47 X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(X11MoveLoopDelegate* delegate) | 26 X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(X11MoveLoopDelegate* delegate) |
48 : delegate_(delegate), | 27 : delegate_(delegate), |
49 in_move_loop_(false), | 28 in_move_loop_(false), |
29 initial_cursor_(ui::kCursorNull), | |
50 should_reset_mouse_flags_(false), | 30 should_reset_mouse_flags_(false), |
51 grab_input_window_(None), | 31 grab_input_window_(None), |
32 grabbed_pointer_(false), | |
52 canceled_(false), | 33 canceled_(false), |
53 has_grab_(false), | |
54 weak_factory_(this) { | 34 weak_factory_(this) { |
55 last_xmotion_.type = LASTEvent; | 35 last_xmotion_.type = LASTEvent; |
56 } | 36 } |
57 | 37 |
58 X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {} | 38 X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {} |
59 | 39 |
60 void X11WholeScreenMoveLoop::DispatchMouseMovement() { | 40 void X11WholeScreenMoveLoop::DispatchMouseMovement() { |
61 if (!weak_factory_.HasWeakPtrs()) | 41 if (!weak_factory_.HasWeakPtrs()) |
62 return; | 42 return; |
63 weak_factory_.InvalidateWeakPtrs(); | 43 weak_factory_.InvalidateWeakPtrs(); |
64 DCHECK_EQ(MotionNotify, last_xmotion_.type); | 44 DCHECK_EQ(MotionNotify, last_xmotion_.type); |
65 delegate_->OnMouseMovement(&last_xmotion_); | 45 delegate_->OnMouseMovement(&last_xmotion_); |
66 last_xmotion_.type = LASTEvent; | 46 last_xmotion_.type = LASTEvent; |
67 } | 47 } |
68 | 48 |
69 //////////////////////////////////////////////////////////////////////////////// | 49 //////////////////////////////////////////////////////////////////////////////// |
70 // DesktopWindowTreeHostLinux, ui::PlatformEventDispatcher implementation: | 50 // DesktopWindowTreeHostLinux, ui::PlatformEventDispatcher implementation: |
71 | 51 |
72 bool X11WholeScreenMoveLoop::CanDispatchEvent(const ui::PlatformEvent& event) { | 52 bool X11WholeScreenMoveLoop::CanDispatchEvent(const ui::PlatformEvent& event) { |
73 return in_move_loop_; | 53 return in_move_loop_; |
74 } | 54 } |
75 | 55 |
76 uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) { | 56 uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) { |
77 // This method processes all events for the grab_input_window_ as well as | 57 // This method processes all events while the move loop is active. |
78 // mouse events for all windows while the move loop is active - even before | |
79 // the grab is granted by X. This allows mouse notification events that were | |
80 // sent after the capture was requested but before the capture was granted | |
81 // to be dispatched. It is especially important to process the mouse release | |
82 // event that should have stopped the drag even if that mouse release happened | |
83 // before the grab was granted. | |
84 if (!in_move_loop_) | 58 if (!in_move_loop_) |
85 return ui::POST_DISPATCH_PERFORM_DEFAULT; | 59 return ui::POST_DISPATCH_PERFORM_DEFAULT; |
60 | |
86 XEvent* xev = event; | 61 XEvent* xev = event; |
87 | |
88 // Note: the escape key is handled in the tab drag controller, which has | |
89 // keyboard focus even though we took pointer grab. | |
90 switch (xev->type) { | 62 switch (xev->type) { |
91 case MotionNotify: { | 63 case MotionNotify: { |
92 last_xmotion_ = xev->xmotion; | 64 last_xmotion_ = xev->xmotion; |
93 if (!weak_factory_.HasWeakPtrs()) { | 65 if (!weak_factory_.HasWeakPtrs()) { |
94 // Post a task to dispatch mouse movement event when control returns to | 66 // Post a task to dispatch mouse movement event when control returns to |
95 // the message loop. This allows smoother dragging since the events are | 67 // the message loop. This allows smoother dragging since the events are |
96 // dispatched without waiting for the drag widget updates. | 68 // dispatched without waiting for the drag widget updates. |
97 base::MessageLoopForUI::current()->PostTask( | 69 base::MessageLoopForUI::current()->PostTask( |
98 FROM_HERE, | 70 FROM_HERE, |
99 base::Bind(&X11WholeScreenMoveLoop::DispatchMouseMovement, | 71 base::Bind(&X11WholeScreenMoveLoop::DispatchMouseMovement, |
100 weak_factory_.GetWeakPtr())); | 72 weak_factory_.GetWeakPtr())); |
101 } | 73 } |
102 return ui::POST_DISPATCH_NONE; | 74 return ui::POST_DISPATCH_NONE; |
103 } | 75 } |
104 case ButtonRelease: { | 76 case ButtonRelease: { |
105 if (xev->xbutton.button == Button1) { | 77 if (xev->xbutton.button == Button1) { |
106 // Assume that drags are being done with the left mouse button. Only | 78 // Assume that drags are being done with the left mouse button. Only |
107 // break the drag if the left mouse button was released. | 79 // break the drag if the left mouse button was released. |
108 DispatchMouseMovement(); | 80 DispatchMouseMovement(); |
109 delegate_->OnMouseReleased(); | 81 delegate_->OnMouseReleased(); |
82 | |
83 if (!grabbed_pointer_) { | |
84 // If the source widget had capture prior to the move loop starting, | |
85 // it may be relying on views::Widget getting the mouse release and | |
86 // releasing capture in Widget::OnMouseEvent(). | |
87 return ui::POST_DISPATCH_PERFORM_DEFAULT; | |
pkotwicz
2014/08/10 18:58:49
I want to look into whether we can stop the propag
| |
88 } | |
110 } | 89 } |
111 return ui::POST_DISPATCH_NONE; | 90 return ui::POST_DISPATCH_NONE; |
112 } | 91 } |
113 case KeyPress: { | 92 case KeyPress: { |
114 if (ui::KeyboardCodeFromXKeyEvent(xev) == ui::VKEY_ESCAPE) { | 93 if (ui::KeyboardCodeFromXKeyEvent(xev) == ui::VKEY_ESCAPE) { |
115 canceled_ = true; | 94 canceled_ = true; |
116 EndMoveLoop(); | 95 EndMoveLoop(); |
117 return ui::POST_DISPATCH_NONE; | 96 return ui::POST_DISPATCH_NONE; |
118 } | 97 } |
119 break; | 98 break; |
120 } | 99 } |
121 case FocusOut: { | |
122 if (xev->xfocus.mode != NotifyGrab) | |
123 has_grab_ = false; | |
124 break; | |
125 } | |
126 case GenericEvent: { | 100 case GenericEvent: { |
127 ui::EventType type = ui::EventTypeFromNative(xev); | 101 ui::EventType type = ui::EventTypeFromNative(xev); |
128 switch (type) { | 102 switch (type) { |
129 case ui::ET_MOUSE_MOVED: | 103 case ui::ET_MOUSE_MOVED: |
130 case ui::ET_MOUSE_DRAGGED: | 104 case ui::ET_MOUSE_DRAGGED: |
131 case ui::ET_MOUSE_RELEASED: { | 105 case ui::ET_MOUSE_RELEASED: { |
132 XEvent xevent = {0}; | 106 XEvent xevent = {0}; |
133 if (type == ui::ET_MOUSE_RELEASED) { | 107 if (type == ui::ET_MOUSE_RELEASED) { |
134 xevent.type = ButtonRelease; | 108 xevent.type = ButtonRelease; |
135 xevent.xbutton.button = ui::EventButtonFromNative(xev); | 109 xevent.xbutton.button = ui::EventButtonFromNative(xev); |
136 } else { | 110 } else { |
137 xevent.type = MotionNotify; | 111 xevent.type = MotionNotify; |
138 } | 112 } |
139 xevent.xany.display = xev->xgeneric.display; | 113 xevent.xany.display = xev->xgeneric.display; |
140 xevent.xany.window = grab_input_window_; | 114 xevent.xany.window = grab_input_window_; |
141 // The fields used below are in the same place for all of events | 115 // The fields used below are in the same place for all of events |
142 // above. Using xmotion from XEvent's unions to avoid repeating | 116 // above. Using xmotion from XEvent's unions to avoid repeating |
143 // the code. | 117 // the code. |
144 xevent.xmotion.root = DefaultRootWindow(xev->xgeneric.display); | 118 xevent.xmotion.root = DefaultRootWindow(xev->xgeneric.display); |
145 xevent.xmotion.time = ui::EventTimeFromNative(xev).InMilliseconds(); | 119 xevent.xmotion.time = ui::EventTimeFromNative(xev).InMilliseconds(); |
146 gfx::Point point(ui::EventSystemLocationFromNative(xev)); | 120 gfx::Point point(ui::EventSystemLocationFromNative(xev)); |
147 xevent.xmotion.x_root = point.x(); | 121 xevent.xmotion.x_root = point.x(); |
148 xevent.xmotion.y_root = point.y(); | 122 xevent.xmotion.y_root = point.y(); |
149 DispatchEvent(&xevent); | 123 return DispatchEvent(&xevent); |
150 return ui::POST_DISPATCH_NONE; | |
151 } | 124 } |
152 default: | 125 default: |
153 break; | 126 break; |
154 } | 127 } |
155 } | 128 } |
156 } | 129 } |
157 | 130 |
158 return (event->xany.window == grab_input_window_) ? | 131 return ui::POST_DISPATCH_PERFORM_DEFAULT; |
159 ui::POST_DISPATCH_NONE : ui::POST_DISPATCH_PERFORM_DEFAULT; | |
160 } | 132 } |
161 | 133 |
162 bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source, | 134 bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source, |
163 gfx::NativeCursor cursor) { | 135 gfx::NativeCursor cursor) { |
164 DCHECK(!in_move_loop_); // Can only handle one nested loop at a time. | 136 DCHECK(!in_move_loop_); // Can only handle one nested loop at a time. |
165 | 137 |
166 // Start a capture on the host, so that it continues to receive events during | 138 // Query the mouse cursor prior to the move loop starting so that it can be |
167 // the drag. This may be second time we are capturing the mouse events - the | 139 // restored when the move loop finishes. |
168 // first being when a mouse is first pressed. That first capture needs to be | 140 initial_cursor_ = source->GetHost()->last_cursor(); |
169 // released before the call to GrabPointerAndKeyboard below, otherwise it may | |
170 // get released while we still need the pointer grab, which is why we restrict | |
171 // the scope here. | |
172 { | |
173 ScopedCapturer capturer(source->GetHost()); | |
174 | 141 |
175 grab_input_window_ = CreateDragInputWindow(gfx::GetXDisplay()); | 142 grab_input_window_ = CreateDragInputWindow(gfx::GetXDisplay()); |
176 // Releasing ScopedCapturer ensures that any other instance of | 143 |
177 // X11ScopedCapture will not prematurely release grab that will be acquired | 144 // Only grab mouse capture of |grab_input_window_| if |source| does not have |
178 // below. | 145 // capture. |
146 // - The caller may intend to transfer capture to a different aura::Window | |
147 // when the move loop ends and not release capture. | |
148 // - Releasing capture and X window destruction are both asynchronous. We drop | |
149 // events targeted at |grab_input_window_| in the time between the move | |
150 // loop ends and |grab_input_window_| loses capture. | |
151 grabbed_pointer_ = false; | |
152 if (!source->HasCapture()) { | |
153 aura::client::CaptureClient* capture_client = | |
154 aura::client::GetCaptureClient(source->GetRootWindow()); | |
155 CHECK(capture_client->GetGlobalCaptureWindow() == NULL); | |
156 grabbed_pointer_ = GrabPointer(cursor); | |
157 if (!grabbed_pointer_) { | |
158 XDestroyWindow(gfx::GetXDisplay(), grab_input_window_); | |
159 return false; | |
160 } | |
179 } | 161 } |
180 // TODO(varkha): Consider integrating GrabPointerAndKeyboard with | 162 |
181 // ScopedCapturer to avoid possibility of logically keeping multiple grabs. | 163 if (!GrabKeyboard()) { |
182 if (!GrabPointerAndKeyboard(cursor)) { | |
183 XDestroyWindow(gfx::GetXDisplay(), grab_input_window_); | 164 XDestroyWindow(gfx::GetXDisplay(), grab_input_window_); |
184 return false; | 165 return false; |
185 } | 166 } |
186 | 167 |
187 scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher = | 168 scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher = |
188 nested_dispatcher_.Pass(); | 169 nested_dispatcher_.Pass(); |
189 nested_dispatcher_ = | 170 nested_dispatcher_ = |
190 ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this); | 171 ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this); |
191 | 172 |
192 // We are handling a mouse drag outside of the aura::RootWindow system. We | 173 // We are handling a mouse drag outside of the aura::Window system. We must |
193 // must manually make aura think that the mouse button is pressed so that we | 174 // manually make aura think that the mouse button is pressed so that we don't |
194 // don't draw extraneous tooltips. | 175 // draw extraneous tooltips. |
195 aura::Env* env = aura::Env::GetInstance(); | 176 aura::Env* env = aura::Env::GetInstance(); |
196 if (!env->IsMouseButtonDown()) { | 177 if (!env->IsMouseButtonDown()) { |
197 env->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON); | 178 env->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON); |
198 should_reset_mouse_flags_ = true; | 179 should_reset_mouse_flags_ = true; |
199 } | 180 } |
200 | 181 |
201 in_move_loop_ = true; | 182 in_move_loop_ = true; |
202 canceled_ = false; | 183 canceled_ = false; |
203 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); | 184 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); |
204 base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop); | 185 base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop); |
205 base::RunLoop run_loop; | 186 base::RunLoop run_loop; |
206 quit_closure_ = run_loop.QuitClosure(); | 187 quit_closure_ = run_loop.QuitClosure(); |
207 run_loop.Run(); | 188 run_loop.Run(); |
208 nested_dispatcher_ = old_dispatcher.Pass(); | 189 nested_dispatcher_ = old_dispatcher.Pass(); |
209 return !canceled_; | 190 return !canceled_; |
210 } | 191 } |
211 | 192 |
212 void X11WholeScreenMoveLoop::UpdateCursor(gfx::NativeCursor cursor) { | 193 void X11WholeScreenMoveLoop::UpdateCursor(gfx::NativeCursor cursor) { |
213 if (in_move_loop_) { | 194 if (in_move_loop_) { |
214 // If we're still in the move loop, regrab the pointer with the updated | 195 // We cannot call GrabPointer() because we do not want to change the |
215 // cursor. Note: we can be called from handling an XdndStatus message after | 196 // "owner_events" property of the active pointer grab. |
216 // EndMoveLoop() was called, but before we return from the nested RunLoop. | 197 XChangeActivePointerGrab( |
217 GrabPointerAndKeyboard(cursor); | 198 gfx::GetXDisplay(), |
pkotwicz
2014/08/10 18:58:49
This comment sounds like a description of the "own
| |
199 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, | |
200 cursor.platform(), | |
201 CurrentTime); | |
218 } | 202 } |
219 } | 203 } |
220 | 204 |
221 void X11WholeScreenMoveLoop::EndMoveLoop() { | 205 void X11WholeScreenMoveLoop::EndMoveLoop() { |
222 if (!in_move_loop_) | 206 if (!in_move_loop_) |
223 return; | 207 return; |
224 | 208 |
225 // Prevent DispatchMouseMovement from dispatching any posted motion event. | 209 // Prevent DispatchMouseMovement from dispatching any posted motion event. |
226 weak_factory_.InvalidateWeakPtrs(); | 210 weak_factory_.InvalidateWeakPtrs(); |
227 last_xmotion_.type = LASTEvent; | 211 last_xmotion_.type = LASTEvent; |
228 | 212 |
229 // We undo our emulated mouse click from RunMoveLoop(); | 213 // We undo our emulated mouse click from RunMoveLoop(); |
230 if (should_reset_mouse_flags_) { | 214 if (should_reset_mouse_flags_) { |
231 aura::Env::GetInstance()->set_mouse_button_flags(0); | 215 aura::Env::GetInstance()->set_mouse_button_flags(0); |
232 should_reset_mouse_flags_ = false; | 216 should_reset_mouse_flags_ = false; |
233 } | 217 } |
234 | 218 |
235 // TODO(erg): Is this ungrab the cause of having to click to give input focus | 219 // TODO(erg): Is this ungrab the cause of having to click to give input focus |
236 // on drawn out windows? Not ungrabbing here screws the X server until I kill | 220 // on drawn out windows? Not ungrabbing here screws the X server until I kill |
237 // the chrome process. | 221 // the chrome process. |
238 | 222 |
239 // Ungrab before we let go of the window. | 223 // Ungrab before we let go of the window. |
240 XDisplay* display = gfx::GetXDisplay(); | 224 XDisplay* display = gfx::GetXDisplay(); |
241 // Only ungrab pointer if capture was not switched to another window. | 225 if (grabbed_pointer_) |
242 if (has_grab_) { | |
243 XUngrabPointer(display, CurrentTime); | 226 XUngrabPointer(display, CurrentTime); |
244 XUngrabKeyboard(display, CurrentTime); | 227 else |
245 } | 228 UpdateCursor(initial_cursor_); |
229 | |
230 XUngrabKeyboard(display, CurrentTime); | |
246 | 231 |
247 // Restore the previous dispatcher. | 232 // Restore the previous dispatcher. |
248 nested_dispatcher_.reset(); | 233 nested_dispatcher_.reset(); |
249 delegate_->OnMoveLoopEnded(); | 234 delegate_->OnMoveLoopEnded(); |
250 XDestroyWindow(display, grab_input_window_); | 235 XDestroyWindow(display, grab_input_window_); |
251 grab_input_window_ = None; | 236 grab_input_window_ = None; |
252 | 237 |
253 in_move_loop_ = false; | 238 in_move_loop_ = false; |
254 quit_closure_.Run(); | 239 quit_closure_.Run(); |
255 } | 240 } |
256 | 241 |
257 bool X11WholeScreenMoveLoop::GrabPointerAndKeyboard(gfx::NativeCursor cursor) { | 242 bool X11WholeScreenMoveLoop::GrabPointer(gfx::NativeCursor cursor) { |
258 XDisplay* display = gfx::GetXDisplay(); | 243 XDisplay* display = gfx::GetXDisplay(); |
259 XGrabServer(display); | 244 XGrabServer(display); |
260 | 245 |
261 XUngrabPointer(display, CurrentTime); | 246 // Pass "owner_events" as false so that X sends all mouse events to |
247 // |grab_input_window_|. | |
262 int ret = XGrabPointer( | 248 int ret = XGrabPointer( |
263 display, | 249 display, |
264 grab_input_window_, | 250 grab_input_window_, |
265 False, | 251 False, // owner_events |
266 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, | 252 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, |
267 GrabModeAsync, | 253 GrabModeAsync, |
268 GrabModeAsync, | 254 GrabModeAsync, |
269 None, | 255 None, |
270 cursor.platform(), | 256 cursor.platform(), |
271 CurrentTime); | 257 CurrentTime); |
272 if (ret != GrabSuccess) { | 258 if (ret != GrabSuccess) { |
273 DLOG(ERROR) << "Grabbing pointer for dragging failed: " | 259 DLOG(ERROR) << "Grabbing pointer for dragging failed: " |
274 << ui::GetX11ErrorString(display, ret); | 260 << ui::GetX11ErrorString(display, ret); |
275 } else { | |
276 has_grab_ = true; | |
277 XUngrabKeyboard(display, CurrentTime); | |
278 ret = XGrabKeyboard( | |
279 display, | |
280 grab_input_window_, | |
281 False, | |
282 GrabModeAsync, | |
283 GrabModeAsync, | |
284 CurrentTime); | |
285 if (ret != GrabSuccess) { | |
286 DLOG(ERROR) << "Grabbing keyboard for dragging failed: " | |
287 << ui::GetX11ErrorString(display, ret); | |
288 } | |
289 } | 261 } |
290 | |
291 XUngrabServer(display); | 262 XUngrabServer(display); |
292 XFlush(display); | 263 XFlush(display); |
293 return ret == GrabSuccess; | 264 return ret == GrabSuccess; |
294 } | 265 } |
295 | 266 |
267 bool X11WholeScreenMoveLoop::GrabKeyboard() { | |
268 XDisplay* display = gfx::GetXDisplay(); | |
269 int ret = XGrabKeyboard(display, | |
270 grab_input_window_, | |
271 False, | |
272 GrabModeAsync, | |
273 GrabModeAsync, | |
274 CurrentTime); | |
275 if (ret != GrabSuccess) { | |
276 DLOG(ERROR) << "Grabbing keyboard for dragging failed: " | |
277 << ui::GetX11ErrorString(display, ret); | |
278 return false; | |
279 } | |
280 return true; | |
281 } | |
282 | |
296 Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) { | 283 Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) { |
297 // Creates an invisible, InputOnly toplevel window. This window will receive | |
298 // all mouse movement for drags. It turns out that normal windows doing a | |
299 // grab doesn't redirect pointer motion events if the pointer isn't over the | |
300 // grabbing window. But InputOnly windows are able to grab everything. This | |
301 // is what GTK+ does, and I found a patch to KDE that did something similar. | |
pkotwicz
2014/08/10 18:58:49
This comment sounds like a description of the "own
| |
302 unsigned long attribute_mask = CWEventMask | CWOverrideRedirect; | 284 unsigned long attribute_mask = CWEventMask | CWOverrideRedirect; |
303 XSetWindowAttributes swa; | 285 XSetWindowAttributes swa; |
304 memset(&swa, 0, sizeof(swa)); | 286 memset(&swa, 0, sizeof(swa)); |
305 swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | | 287 swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | |
306 KeyPressMask | KeyReleaseMask | StructureNotifyMask; | 288 KeyPressMask | KeyReleaseMask | StructureNotifyMask; |
307 swa.override_redirect = True; | 289 swa.override_redirect = True; |
308 Window window = XCreateWindow(display, | 290 Window window = XCreateWindow(display, |
309 DefaultRootWindow(display), | 291 DefaultRootWindow(display), |
310 -100, -100, 10, 10, | 292 -100, -100, 10, 10, |
311 0, CopyFromParent, InputOnly, CopyFromParent, | 293 0, CopyFromParent, InputOnly, CopyFromParent, |
312 attribute_mask, &swa); | 294 attribute_mask, &swa); |
313 XMapRaised(display, window); | 295 XMapRaised(display, window); |
314 ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(window); | 296 ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(window); |
315 return window; | 297 return window; |
316 } | 298 } |
317 | 299 |
318 } // namespace views | 300 } // namespace views |
OLD | NEW |