Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(346)

Side by Side Diff: ui/views/widget/desktop_aura/x11_desktop_handler.cc

Issue 2165083002: Linux: Refactor X11DesktopHandler (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase to ToT Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/views/widget/desktop_aura/x11_desktop_handler.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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_desktop_handler.h" 5 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
6 6
7 #include <X11/Xatom.h> 7 #include <X11/Xatom.h>
8 #include <X11/Xlib.h> 8 #include <X11/Xlib.h>
9 9
10 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_number_conversions.h"
12 #include "ui/aura/env.h" 12 #include "ui/aura/env.h"
13 #include "ui/aura/window_event_dispatcher.h" 13 #include "ui/aura/window_event_dispatcher.h"
14 #include "ui/base/x/x11_foreign_window_manager.h" 14 #include "ui/base/x/x11_foreign_window_manager.h"
15 #include "ui/base/x/x11_menu_list.h" 15 #include "ui/base/x/x11_menu_list.h"
16 #include "ui/base/x/x11_util.h" 16 #include "ui/base/x/x11_util.h"
17 #include "ui/events/platform/platform_event_source.h" 17 #include "ui/events/platform/platform_event_source.h"
18 #include "ui/gfx/x/x11_error_tracker.h" 18 #include "ui/gfx/x/x11_error_tracker.h"
19 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" 19 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
20 20
21 namespace { 21 namespace {
22 22
23 const char* const kAtomsToCache[] = { 23 const char* const kAtomsToCache[] = {
24 "_NET_ACTIVE_WINDOW",
25 "_NET_CURRENT_DESKTOP", 24 "_NET_CURRENT_DESKTOP",
26 nullptr 25 nullptr
27 }; 26 };
28 27
29 // Our global instance. Deleted when our Env() is deleted. 28 // Our global instance. Deleted when our Env() is deleted.
30 views::X11DesktopHandler* g_handler = NULL; 29 views::X11DesktopHandler* g_handler = NULL;
31 30
32 } // namespace 31 } // namespace
33 32
34 namespace views { 33 namespace views {
35 34
36 // static 35 // static
37 X11DesktopHandler* X11DesktopHandler::get() { 36 X11DesktopHandler* X11DesktopHandler::get() {
38 if (!g_handler) 37 if (!g_handler)
39 g_handler = new X11DesktopHandler; 38 g_handler = new X11DesktopHandler;
40 39
41 return g_handler; 40 return g_handler;
42 } 41 }
43 42
44 X11DesktopHandler::X11DesktopHandler() 43 X11DesktopHandler::X11DesktopHandler()
45 : xdisplay_(gfx::GetXDisplay()), 44 : xdisplay_(gfx::GetXDisplay()),
46 x_root_window_(DefaultRootWindow(xdisplay_)), 45 x_root_window_(DefaultRootWindow(xdisplay_)),
47 x_active_window_(None), 46 atom_cache_(xdisplay_, kAtomsToCache) {
48 wm_user_time_ms_(CurrentTime),
49 current_window_(None),
50 current_window_active_state_(NOT_ACTIVE),
51 atom_cache_(xdisplay_, kAtomsToCache),
52 wm_supports_active_window_(false) {
53 if (ui::PlatformEventSource::GetInstance()) 47 if (ui::PlatformEventSource::GetInstance())
54 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); 48 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
55 aura::Env::GetInstance()->AddObserver(this); 49 aura::Env::GetInstance()->AddObserver(this);
56 50
57 XWindowAttributes attr; 51 XWindowAttributes attr;
58 XGetWindowAttributes(xdisplay_, x_root_window_, &attr); 52 XGetWindowAttributes(xdisplay_, x_root_window_, &attr);
59 XSelectInput(xdisplay_, x_root_window_, 53 XSelectInput(xdisplay_, x_root_window_,
60 attr.your_event_mask | PropertyChangeMask | 54 attr.your_event_mask | PropertyChangeMask |
61 StructureNotifyMask | SubstructureNotifyMask); 55 StructureNotifyMask | SubstructureNotifyMask);
62
63 if (ui::GuessWindowManager() == ui::WM_WMII) {
64 // wmii says that it supports _NET_ACTIVE_WINDOW but does not.
65 // https://code.google.com/p/wmii/issues/detail?id=266
66 wm_supports_active_window_ = false;
67 } else {
68 wm_supports_active_window_ =
69 ui::WmSupportsHint(atom_cache_.GetAtom("_NET_ACTIVE_WINDOW"));
70 }
71 } 56 }
72 57
73 X11DesktopHandler::~X11DesktopHandler() { 58 X11DesktopHandler::~X11DesktopHandler() {
74 aura::Env::GetInstance()->RemoveObserver(this); 59 aura::Env::GetInstance()->RemoveObserver(this);
75 if (ui::PlatformEventSource::GetInstance()) 60 if (ui::PlatformEventSource::GetInstance())
76 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); 61 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
77 } 62 }
78 63
79 void X11DesktopHandler::ActivateWindow(::Window window) {
80 if ((current_window_ == None || current_window_ == window) &&
81 current_window_active_state_ == NOT_ACTIVE) {
82 // |window| is most likely still active wrt to the X server. Undo the
83 // changes made in DeactivateWindow().
84 OnActiveWindowChanged(window, ACTIVE);
85
86 // Go through the regular activation path such that calling
87 // DeactivateWindow() and ActivateWindow() immediately afterwards results
88 // in an active X window.
89 }
90
91 if (wm_supports_active_window_) {
92 DCHECK_EQ(gfx::GetXDisplay(), xdisplay_);
93
94 // If the window is not already active, send a hint to activate it
95 if (x_active_window_ != window) {
96 if (wm_user_time_ms_ == CurrentTime) {
97 set_wm_user_time_ms(
98 ui::X11EventSource::GetInstance()->UpdateLastSeenServerTime());
99 }
100 XEvent xclient;
101 memset(&xclient, 0, sizeof(xclient));
102 xclient.type = ClientMessage;
103 xclient.xclient.window = window;
104 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
105 xclient.xclient.format = 32;
106 xclient.xclient.data.l[0] = 1; // Specified we are an app.
107 xclient.xclient.data.l[1] = wm_user_time_ms_;
108 xclient.xclient.data.l[2] = None;
109 xclient.xclient.data.l[3] = 0;
110 xclient.xclient.data.l[4] = 0;
111
112 XSendEvent(xdisplay_, x_root_window_, False,
113 SubstructureRedirectMask | SubstructureNotifyMask,
114 &xclient);
115 } else {
116 OnActiveWindowChanged(window, ACTIVE);
117 }
118 } else {
119 XRaiseWindow(xdisplay_, window);
120 // Directly ask the X server to give focus to the window. Note
121 // that the call will raise an X error if the window is not
122 // mapped.
123 XSetInputFocus(xdisplay_, window, RevertToParent, CurrentTime);
124
125 OnActiveWindowChanged(window, ACTIVE);
126 }
127 }
128
129 void X11DesktopHandler::AddObserver(X11DesktopHandlerObserver* observer) { 64 void X11DesktopHandler::AddObserver(X11DesktopHandlerObserver* observer) {
130 observers_.AddObserver(observer); 65 observers_.AddObserver(observer);
131 } 66 }
132 67
133 void X11DesktopHandler::RemoveObserver(X11DesktopHandlerObserver* observer) { 68 void X11DesktopHandler::RemoveObserver(X11DesktopHandlerObserver* observer) {
134 observers_.RemoveObserver(observer); 69 observers_.RemoveObserver(observer);
135 } 70 }
136 71
137 std::string X11DesktopHandler::GetWorkspace() { 72 std::string X11DesktopHandler::GetWorkspace() {
138 if (workspace_.empty()) 73 if (workspace_.empty())
139 UpdateWorkspace(); 74 UpdateWorkspace();
140 return workspace_; 75 return workspace_;
141 } 76 }
142 77
143 bool X11DesktopHandler::UpdateWorkspace() { 78 bool X11DesktopHandler::UpdateWorkspace() {
144 int desktop; 79 int desktop;
145 if (ui::GetCurrentDesktop(&desktop)) { 80 if (ui::GetCurrentDesktop(&desktop)) {
146 workspace_ = base::IntToString(desktop); 81 workspace_ = base::IntToString(desktop);
147 return true; 82 return true;
148 } 83 }
149 return false; 84 return false;
150 } 85 }
151 86
152 void X11DesktopHandler::set_wm_user_time_ms(Time time_ms) {
153 if (time_ms != CurrentTime) {
154 int64_t event_time_64 = time_ms;
155 int64_t time_difference = wm_user_time_ms_ - event_time_64;
156 // Ignore timestamps that go backwards. However, X server time is a 32-bit
157 // millisecond counter, so if the time goes backwards by more than half the
158 // range of the 32-bit counter, treat it as a rollover.
159 if (time_difference < 0 || time_difference > (UINT32_MAX >> 1))
160 wm_user_time_ms_ = time_ms;
161 }
162 }
163
164 void X11DesktopHandler::DeactivateWindow(::Window window) {
165 if (!IsActiveWindow(window))
166 return;
167
168 XLowerWindow(xdisplay_, window);
169
170 // Per ICCCM: http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7
171 // "Clients should not give up the input focus of their own volition.
172 // They should ignore input that they receive instead."
173 //
174 // There is nothing else that we can do. Pretend that we have been
175 // deactivated and ignore keyboard input in DesktopWindowTreeHostX11.
176 OnActiveWindowChanged(window, NOT_ACTIVE);
177 }
178
179 bool X11DesktopHandler::IsActiveWindow(::Window window) const {
180 return window == current_window_ && current_window_active_state_ == ACTIVE;
181 }
182
183 void X11DesktopHandler::ProcessXEvent(XEvent* event) {
184 // Ignore focus events that are being sent only because the pointer is over
185 // our window, even if the input focus is in a different window.
186 if (event->xfocus.detail == NotifyPointer)
187 return;
188
189 switch (event->type) {
190 case FocusIn:
191 if (current_window_ != event->xfocus.window)
192 OnActiveWindowChanged(event->xfocus.window, ACTIVE);
193 break;
194 case FocusOut:
195 if (current_window_ == event->xfocus.window)
196 OnActiveWindowChanged(None, NOT_ACTIVE);
197 break;
198 default:
199 NOTREACHED();
200 }
201 }
202
203 bool X11DesktopHandler::CanDispatchEvent(const ui::PlatformEvent& event) { 87 bool X11DesktopHandler::CanDispatchEvent(const ui::PlatformEvent& event) {
204 return event->type == CreateNotify || event->type == DestroyNotify || 88 return event->type == CreateNotify || event->type == DestroyNotify ||
205 (event->type == PropertyNotify && 89 (event->type == PropertyNotify &&
206 event->xproperty.window == x_root_window_); 90 event->xproperty.window == x_root_window_);
207 } 91 }
208 92
209 uint32_t X11DesktopHandler::DispatchEvent(const ui::PlatformEvent& event) { 93 uint32_t X11DesktopHandler::DispatchEvent(const ui::PlatformEvent& event) {
210 switch (event->type) { 94 switch (event->type) {
211 case PropertyNotify: { 95 case PropertyNotify: {
212 if (event->xproperty.atom == atom_cache_.GetAtom("_NET_ACTIVE_WINDOW")) { 96 if (event->xproperty.atom ==
213 ::Window window; 97 atom_cache_.GetAtom("_NET_CURRENT_DESKTOP")) {
214 if (ui::GetXIDProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &window) &&
215 window) {
216 x_active_window_ = window;
217 OnActiveWindowChanged(window, ACTIVE);
218 } else {
219 x_active_window_ = None;
220 }
221 } else if (event->xproperty.atom ==
222 atom_cache_.GetAtom("_NET_CURRENT_DESKTOP")) {
223 if (UpdateWorkspace()) { 98 if (UpdateWorkspace()) {
224 FOR_EACH_OBSERVER(views::X11DesktopHandlerObserver, observers_, 99 FOR_EACH_OBSERVER(views::X11DesktopHandlerObserver, observers_,
225 OnWorkspaceChanged(workspace_)); 100 OnWorkspaceChanged(workspace_));
226 } 101 }
227 } 102 }
228 break; 103 break;
229 } 104 }
230 case CreateNotify: 105 case CreateNotify:
231 OnWindowCreatedOrDestroyed(event->type, event->xcreatewindow.window); 106 OnWindowCreatedOrDestroyed(event->type, event->xcreatewindow.window);
232 break; 107 break;
233 case DestroyNotify: 108 case DestroyNotify:
234 OnWindowCreatedOrDestroyed(event->type, event->xdestroywindow.window); 109 OnWindowCreatedOrDestroyed(event->type, event->xdestroywindow.window);
235 // If the current active window is being destroyed, reset our tracker.
236 if (x_active_window_ == event->xdestroywindow.window) {
237 x_active_window_ = None;
238 }
239 break; 110 break;
240 default: 111 default:
241 NOTREACHED(); 112 NOTREACHED();
242 } 113 }
243 114
244 return ui::POST_DISPATCH_NONE; 115 return ui::POST_DISPATCH_NONE;
245 } 116 }
246 117
247 void X11DesktopHandler::OnWindowInitialized(aura::Window* window) { 118 void X11DesktopHandler::OnWindowInitialized(aura::Window* window) {
248 } 119 }
249 120
250 void X11DesktopHandler::OnWillDestroyEnv() { 121 void X11DesktopHandler::OnWillDestroyEnv() {
251 g_handler = NULL; 122 g_handler = NULL;
252 delete this; 123 delete this;
253 } 124 }
254 125
255 void X11DesktopHandler::OnActiveWindowChanged(::Window xid,
256 ActiveState active_state) {
257 if (current_window_ == xid && current_window_active_state_ == active_state)
258 return;
259
260 if (current_window_active_state_ == ACTIVE) {
261 DesktopWindowTreeHostX11* old_host =
262 views::DesktopWindowTreeHostX11::GetHostForXID(current_window_);
263 if (old_host)
264 old_host->HandleNativeWidgetActivationChanged(false);
265 }
266
267 // Update the current window ID to effectively change the active widget.
268 current_window_ = xid;
269 current_window_active_state_ = active_state;
270
271 if (active_state == ACTIVE) {
272 DesktopWindowTreeHostX11* new_host =
273 views::DesktopWindowTreeHostX11::GetHostForXID(xid);
274 if (new_host)
275 new_host->HandleNativeWidgetActivationChanged(true);
276 }
277 }
278
279 void X11DesktopHandler::OnWindowCreatedOrDestroyed(int event_type, 126 void X11DesktopHandler::OnWindowCreatedOrDestroyed(int event_type,
280 XID window) { 127 XID window) {
281 // Menus created by Chrome can be drag and drop targets. Since they are 128 // Menus created by Chrome can be drag and drop targets. Since they are
282 // direct children of the screen root window and have override_redirect 129 // direct children of the screen root window and have override_redirect
283 // we cannot use regular _NET_CLIENT_LIST_STACKING property to find them 130 // we cannot use regular _NET_CLIENT_LIST_STACKING property to find them
284 // and use a separate cache to keep track of them. 131 // and use a separate cache to keep track of them.
285 // TODO(varkha): Implement caching of all top level X windows and their 132 // TODO(varkha): Implement caching of all top level X windows and their
286 // coordinates and stacking order to eliminate repeated calls to the X server 133 // coordinates and stacking order to eliminate repeated calls to the X server
287 // during mouse movement, drag and shaping events. 134 // during mouse movement, drag and shaping events.
288 if (event_type == CreateNotify) { 135 if (event_type == CreateNotify) {
289 // The window might be destroyed if the message pump did not get a chance to 136 // The window might be destroyed if the message pump did not get a chance to
290 // run but we can safely ignore the X error. 137 // run but we can safely ignore the X error.
291 gfx::X11ErrorTracker error_tracker; 138 gfx::X11ErrorTracker error_tracker;
292 ui::XMenuList::GetInstance()->MaybeRegisterMenu(window); 139 ui::XMenuList::GetInstance()->MaybeRegisterMenu(window);
293 } else { 140 } else {
294 ui::XMenuList::GetInstance()->MaybeUnregisterMenu(window); 141 ui::XMenuList::GetInstance()->MaybeUnregisterMenu(window);
295 } 142 }
296 143
297 if (event_type == DestroyNotify) { 144 if (event_type == DestroyNotify) {
298 // Notify the XForeignWindowManager that |window| has been destroyed. 145 // Notify the XForeignWindowManager that |window| has been destroyed.
299 ui::XForeignWindowManager::GetInstance()->OnWindowDestroyed(window); 146 ui::XForeignWindowManager::GetInstance()->OnWindowDestroyed(window);
300 } 147 }
301 } 148 }
302 149
303 } // namespace views 150 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/widget/desktop_aura/x11_desktop_handler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698