| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ui/views/widget/x11_desktop_window_move_client.h" | |
| 6 | |
| 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 | |
| 11 #include "base/debug/stack_trace.h" | |
| 12 #include "base/message_loop.h" | |
| 13 #include "base/message_pump_aurax11.h" | |
| 14 #include "base/run_loop.h" | |
| 15 #include "ui/aura/env.h" | |
| 16 #include "ui/aura/root_window.h" | |
| 17 #include "ui/base/events/event.h" | |
| 18 #include "ui/base/x/x11_util.h" | |
| 19 #include "ui/gfx/screen.h" | |
| 20 | |
| 21 namespace views { | |
| 22 | |
| 23 X11DesktopWindowMoveClient::X11DesktopWindowMoveClient() | |
| 24 : in_move_loop_(false), | |
| 25 grab_input_window_(None), | |
| 26 root_window_(NULL) { | |
| 27 } | |
| 28 | |
| 29 X11DesktopWindowMoveClient::~X11DesktopWindowMoveClient() {} | |
| 30 | |
| 31 //////////////////////////////////////////////////////////////////////////////// | |
| 32 // DesktopRootWindowHostLinux, MessageLoop::Dispatcher implementation: | |
| 33 | |
| 34 bool X11DesktopWindowMoveClient::Dispatch(const base::NativeEvent& event) { | |
| 35 XEvent* xev = event; | |
| 36 | |
| 37 // Note: the escape key is handled in the tab drag controller, which has | |
| 38 // keyboard focus even though we took pointer grab. | |
| 39 switch (xev->type) { | |
| 40 case MotionNotify: { | |
| 41 gfx::Point cursor_point(xev->xmotion.x_root, xev->xmotion.y_root); | |
| 42 gfx::Point system_loc = cursor_point - window_offset_; | |
| 43 root_window_->SetHostBounds(gfx::Rect( | |
| 44 system_loc, root_window_->GetHostSize())); | |
| 45 break; | |
| 46 } | |
| 47 case ButtonPress: | |
| 48 case ButtonRelease: { | |
| 49 EndMoveLoop(); | |
| 50 break; | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 return true; | |
| 55 } | |
| 56 | |
| 57 //////////////////////////////////////////////////////////////////////////////// | |
| 58 // DesktopRootWindowHostLinux, aura::client::WindowMoveClient implementation: | |
| 59 | |
| 60 aura::client::WindowMoveResult X11DesktopWindowMoveClient::RunMoveLoop( | |
| 61 aura::Window* source, | |
| 62 const gfx::Vector2d& drag_offset) { | |
| 63 DCHECK(!in_move_loop_); // Can only handle one nested loop at a time. | |
| 64 in_move_loop_ = true; | |
| 65 window_offset_ = drag_offset; | |
| 66 | |
| 67 root_window_ = source->GetRootWindow(); | |
| 68 | |
| 69 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); | |
| 70 | |
| 71 // Creates an invisible, InputOnly toplevel window. This window will receive | |
| 72 // all mouse movement for drags. It turns out that normal windows doing a | |
| 73 // grab doesn't redirect pointer motion events if the pointer isn't over the | |
| 74 // grabbing window. But InputOnly windows are able to grab everything. This | |
| 75 // is what GTK+ does, and I found a patch to KDE that did something similar. | |
| 76 unsigned long attribute_mask = CWEventMask | CWOverrideRedirect; | |
| 77 XSetWindowAttributes swa; | |
| 78 memset(&swa, 0, sizeof(swa)); | |
| 79 swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | | |
| 80 StructureNotifyMask; | |
| 81 swa.override_redirect = True; | |
| 82 grab_input_window_ = XCreateWindow( | |
| 83 display, | |
| 84 DefaultRootWindow(display), | |
| 85 -100, -100, 10, 10, | |
| 86 0, 0, InputOnly, CopyFromParent, | |
| 87 attribute_mask, &swa); | |
| 88 base::MessagePumpAuraX11::Current()->AddDispatcherForWindow( | |
| 89 this, grab_input_window_); | |
| 90 | |
| 91 // Wait for the window to be mapped. If we don't, XGrabPointer fails. | |
| 92 XMapRaised(display, grab_input_window_); | |
| 93 base::MessagePumpAuraX11::Current()->BlockUntilWindowMapped( | |
| 94 grab_input_window_); | |
| 95 | |
| 96 XGrabServer(display); | |
| 97 XUngrabPointer(display, CurrentTime); | |
| 98 int ret = XGrabPointer( | |
| 99 display, | |
| 100 grab_input_window_, | |
| 101 False, | |
| 102 ButtonPressMask | ButtonReleaseMask | PointerMotionMask, | |
| 103 GrabModeAsync, | |
| 104 GrabModeAsync, | |
| 105 None, | |
| 106 None, | |
| 107 CurrentTime); | |
| 108 XUngrabServer(display); | |
| 109 if (ret != GrabSuccess) { | |
| 110 DLOG(ERROR) << "Grabbing new tab for dragging failed: " | |
| 111 << ui::GetX11ErrorString(display, ret); | |
| 112 return aura::client::MOVE_CANCELED; | |
| 113 } | |
| 114 | |
| 115 MessageLoopForUI* loop = MessageLoopForUI::current(); | |
| 116 MessageLoop::ScopedNestableTaskAllower allow_nested(loop); | |
| 117 base::RunLoop run_loop(aura::Env::GetInstance()->GetDispatcher()); | |
| 118 quit_closure_ = run_loop.QuitClosure(); | |
| 119 run_loop.Run(); | |
| 120 return aura::client::MOVE_SUCCESSFUL; | |
| 121 } | |
| 122 | |
| 123 void X11DesktopWindowMoveClient::EndMoveLoop() { | |
| 124 if (!in_move_loop_) | |
| 125 return; | |
| 126 | |
| 127 // TODO(erg): Is this ungrab the cause of having to click to give input focus | |
| 128 // on drawn out windows? Not ungrabbing here screws the X server until I kill | |
| 129 // the chrome process. | |
| 130 | |
| 131 // Ungrab before we let go of the window. | |
| 132 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); | |
| 133 XUngrabPointer(display, CurrentTime); | |
| 134 | |
| 135 base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow( | |
| 136 grab_input_window_); | |
| 137 root_window_ = NULL; | |
| 138 XDestroyWindow(display, grab_input_window_); | |
| 139 | |
| 140 in_move_loop_ = false; | |
| 141 quit_closure_.Run(); | |
| 142 } | |
| 143 | |
| 144 } // namespace views | |
| OLD | NEW |