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 // Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. | |
9 #undef RootWindow | |
10 | 8 |
11 #include "base/bind.h" | 9 #include "base/bind.h" |
12 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
13 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
14 #include "third_party/skia/include/core/SkBitmap.h" | |
15 #include "ui/aura/env.h" | 12 #include "ui/aura/env.h" |
16 #include "ui/aura/window.h" | 13 #include "ui/aura/window.h" |
17 #include "ui/aura/window_event_dispatcher.h" | 14 #include "ui/aura/window_event_dispatcher.h" |
18 #include "ui/aura/window_tree_host.h" | 15 #include "ui/aura/window_tree_host.h" |
19 #include "ui/base/x/x11_util.h" | 16 #include "ui/base/x/x11_util.h" |
20 #include "ui/events/event.h" | 17 #include "ui/events/event.h" |
21 #include "ui/events/event_utils.h" | 18 #include "ui/events/event_utils.h" |
22 #include "ui/events/keycodes/keyboard_code_conversion_x.h" | 19 #include "ui/events/keycodes/keyboard_code_conversion_x.h" |
23 #include "ui/events/platform/scoped_event_dispatcher.h" | 20 #include "ui/events/platform/scoped_event_dispatcher.h" |
24 #include "ui/events/platform/x11/x11_event_source.h" | 21 #include "ui/events/platform/x11/x11_event_source.h" |
25 #include "ui/gfx/point_conversions.h" | 22 #include "ui/gfx/point_conversions.h" |
26 #include "ui/gfx/screen.h" | |
27 #include "ui/views/controls/image_view.h" | |
28 #include "ui/views/widget/widget.h" | |
29 | 23 |
30 namespace views { | 24 namespace views { |
31 | 25 |
32 namespace { | 26 namespace { |
33 | 27 |
34 // The minimum alpha before we declare a pixel transparent when searching in | |
35 // our source image. | |
36 const uint32 kMinAlpha = 32; | |
37 const unsigned char kDragWidgetOpacity = 0xc0; | |
38 | |
39 class ScopedCapturer { | 28 class ScopedCapturer { |
40 public: | 29 public: |
41 explicit ScopedCapturer(aura::WindowTreeHost* host) | 30 explicit ScopedCapturer(aura::WindowTreeHost* host) |
42 : host_(host) { | 31 : host_(host) { |
43 host_->SetCapture(); | 32 host_->SetCapture(); |
44 } | 33 } |
45 | 34 |
46 ~ScopedCapturer() { | 35 ~ScopedCapturer() { |
47 host_->ReleaseCapture(); | 36 host_->ReleaseCapture(); |
48 } | 37 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 // event that should have stopped the drag even if that mouse release happened | 82 // event that should have stopped the drag even if that mouse release happened |
94 // before the grab was granted. | 83 // before the grab was granted. |
95 if (!in_move_loop_) | 84 if (!in_move_loop_) |
96 return ui::POST_DISPATCH_PERFORM_DEFAULT; | 85 return ui::POST_DISPATCH_PERFORM_DEFAULT; |
97 XEvent* xev = event; | 86 XEvent* xev = event; |
98 | 87 |
99 // Note: the escape key is handled in the tab drag controller, which has | 88 // Note: the escape key is handled in the tab drag controller, which has |
100 // keyboard focus even though we took pointer grab. | 89 // keyboard focus even though we took pointer grab. |
101 switch (xev->type) { | 90 switch (xev->type) { |
102 case MotionNotify: { | 91 case MotionNotify: { |
103 if (drag_widget_.get()) { | |
104 gfx::Screen* screen = gfx::Screen::GetNativeScreen(); | |
105 gfx::Point location = gfx::ToFlooredPoint( | |
106 screen->GetCursorScreenPoint() - drag_offset_); | |
107 drag_widget_->SetBounds(gfx::Rect(location, drag_image_.size())); | |
108 drag_widget_->StackAtTop(); | |
109 } | |
110 last_xmotion_ = xev->xmotion; | 92 last_xmotion_ = xev->xmotion; |
111 if (!weak_factory_.HasWeakPtrs()) { | 93 if (!weak_factory_.HasWeakPtrs()) { |
112 // Post a task to dispatch mouse movement event when control returns to | 94 // Post a task to dispatch mouse movement event when control returns to |
113 // the message loop. This allows smoother dragging since the events are | 95 // the message loop. This allows smoother dragging since the events are |
114 // dispatched without waiting for the drag widget updates. | 96 // dispatched without waiting for the drag widget updates. |
115 base::MessageLoopForUI::current()->PostTask( | 97 base::MessageLoopForUI::current()->PostTask( |
116 FROM_HERE, | 98 FROM_HERE, |
117 base::Bind(&X11WholeScreenMoveLoop::DispatchMouseMovement, | 99 base::Bind(&X11WholeScreenMoveLoop::DispatchMouseMovement, |
118 weak_factory_.GetWeakPtr())); | 100 weak_factory_.GetWeakPtr())); |
119 } | 101 } |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 // ScopedCapturer to avoid possibility of logically keeping multiple grabs. | 181 // ScopedCapturer to avoid possibility of logically keeping multiple grabs. |
200 if (!GrabPointerAndKeyboard(cursor)) { | 182 if (!GrabPointerAndKeyboard(cursor)) { |
201 XDestroyWindow(gfx::GetXDisplay(), grab_input_window_); | 183 XDestroyWindow(gfx::GetXDisplay(), grab_input_window_); |
202 return false; | 184 return false; |
203 } | 185 } |
204 | 186 |
205 scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher = | 187 scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher = |
206 nested_dispatcher_.Pass(); | 188 nested_dispatcher_.Pass(); |
207 nested_dispatcher_ = | 189 nested_dispatcher_ = |
208 ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this); | 190 ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this); |
209 if (!drag_image_.isNull() && CheckIfIconValid()) | |
210 CreateDragImageWindow(); | |
211 | 191 |
212 // We are handling a mouse drag outside of the aura::RootWindow system. We | 192 // We are handling a mouse drag outside of the aura::RootWindow system. We |
213 // must manually make aura think that the mouse button is pressed so that we | 193 // must manually make aura think that the mouse button is pressed so that we |
214 // don't draw extraneous tooltips. | 194 // don't draw extraneous tooltips. |
215 aura::Env* env = aura::Env::GetInstance(); | 195 aura::Env* env = aura::Env::GetInstance(); |
216 if (!env->IsMouseButtonDown()) { | 196 if (!env->IsMouseButtonDown()) { |
217 env->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON); | 197 env->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON); |
218 should_reset_mouse_flags_ = true; | 198 should_reset_mouse_flags_ = true; |
219 } | 199 } |
220 | 200 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 // Ungrab before we let go of the window. | 239 // Ungrab before we let go of the window. |
260 XDisplay* display = gfx::GetXDisplay(); | 240 XDisplay* display = gfx::GetXDisplay(); |
261 // Only ungrab pointer if capture was not switched to another window. | 241 // Only ungrab pointer if capture was not switched to another window. |
262 if (has_grab_) { | 242 if (has_grab_) { |
263 XUngrabPointer(display, CurrentTime); | 243 XUngrabPointer(display, CurrentTime); |
264 XUngrabKeyboard(display, CurrentTime); | 244 XUngrabKeyboard(display, CurrentTime); |
265 } | 245 } |
266 | 246 |
267 // Restore the previous dispatcher. | 247 // Restore the previous dispatcher. |
268 nested_dispatcher_.reset(); | 248 nested_dispatcher_.reset(); |
269 drag_widget_.reset(); | |
270 delegate_->OnMoveLoopEnded(); | 249 delegate_->OnMoveLoopEnded(); |
271 XDestroyWindow(display, grab_input_window_); | 250 XDestroyWindow(display, grab_input_window_); |
272 grab_input_window_ = None; | 251 grab_input_window_ = None; |
273 | 252 |
274 in_move_loop_ = false; | 253 in_move_loop_ = false; |
275 quit_closure_.Run(); | 254 quit_closure_.Run(); |
276 } | 255 } |
277 | 256 |
278 void X11WholeScreenMoveLoop::SetDragImage(const gfx::ImageSkia& image, | |
279 const gfx::Vector2dF& offset) { | |
280 drag_image_ = image; | |
281 drag_offset_ = offset; | |
282 } | |
283 | |
284 bool X11WholeScreenMoveLoop::GrabPointerAndKeyboard(gfx::NativeCursor cursor) { | 257 bool X11WholeScreenMoveLoop::GrabPointerAndKeyboard(gfx::NativeCursor cursor) { |
285 XDisplay* display = gfx::GetXDisplay(); | 258 XDisplay* display = gfx::GetXDisplay(); |
286 XGrabServer(display); | 259 XGrabServer(display); |
287 | 260 |
288 XUngrabPointer(display, CurrentTime); | 261 XUngrabPointer(display, CurrentTime); |
289 int ret = XGrabPointer( | 262 int ret = XGrabPointer( |
290 display, | 263 display, |
291 grab_input_window_, | 264 grab_input_window_, |
292 False, | 265 False, |
293 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, | 266 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 Window window = XCreateWindow(display, | 308 Window window = XCreateWindow(display, |
336 DefaultRootWindow(display), | 309 DefaultRootWindow(display), |
337 -100, -100, 10, 10, | 310 -100, -100, 10, 10, |
338 0, CopyFromParent, InputOnly, CopyFromParent, | 311 0, CopyFromParent, InputOnly, CopyFromParent, |
339 attribute_mask, &swa); | 312 attribute_mask, &swa); |
340 XMapRaised(display, window); | 313 XMapRaised(display, window); |
341 ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(window); | 314 ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(window); |
342 return window; | 315 return window; |
343 } | 316 } |
344 | 317 |
345 void X11WholeScreenMoveLoop::CreateDragImageWindow() { | |
346 Widget* widget = new Widget; | |
347 Widget::InitParams params(Widget::InitParams::TYPE_DRAG); | |
348 params.opacity = Widget::InitParams::OPAQUE_WINDOW; | |
349 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
350 params.accept_events = false; | |
351 | |
352 gfx::Point location = gfx::ToFlooredPoint( | |
353 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint() - drag_offset_); | |
354 params.bounds = gfx::Rect(location, drag_image_.size()); | |
355 widget->set_focus_on_creation(false); | |
356 widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE); | |
357 widget->Init(params); | |
358 widget->SetOpacity(kDragWidgetOpacity); | |
359 widget->GetNativeWindow()->SetName("DragWindow"); | |
360 | |
361 ImageView* image = new ImageView(); | |
362 image->SetImage(drag_image_); | |
363 image->SetBounds(0, 0, drag_image_.width(), drag_image_.height()); | |
364 widget->SetContentsView(image); | |
365 widget->Show(); | |
366 widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false); | |
367 | |
368 drag_widget_.reset(widget); | |
369 } | |
370 | |
371 bool X11WholeScreenMoveLoop::CheckIfIconValid() { | |
372 // Because we need a GL context per window, we do a quick check so that we | |
373 // don't make another context if the window would just be displaying a mostly | |
374 // transparent image. | |
375 const SkBitmap* in_bitmap = drag_image_.bitmap(); | |
376 SkAutoLockPixels in_lock(*in_bitmap); | |
377 for (int y = 0; y < in_bitmap->height(); ++y) { | |
378 uint32* in_row = in_bitmap->getAddr32(0, y); | |
379 | |
380 for (int x = 0; x < in_bitmap->width(); ++x) { | |
381 if (SkColorGetA(in_row[x]) > kMinAlpha) | |
382 return true; | |
383 } | |
384 } | |
385 | |
386 return false; | |
387 } | |
388 | |
389 } // namespace views | 318 } // namespace views |
OLD | NEW |