| 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 |