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 |