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

Side by Side Diff: ui/aura/hostwm/host_window_manager_x11.cc

Issue 10789018: aura: Add X11 host window management. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Keep ash switches alphabetized. Created 8 years, 5 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 | Annotate | Revision Log
OLDNEW
(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/aura/hostwm/host_window_manager_x11.h"
6
7 #include <X11/Xutil.h>
8 #include <X11/cursorfont.h>
9 #include <X11/extensions/Xcomposite.h>
10 #include <X11/extensions/Xdamage.h>
11
12 #include "base/bind.h"
13 #include "base/message_pump_aurax11.h"
14 #include "ui/aura/client/window_types.h"
15 #include "ui/aura/dispatcher_linux.h"
16 #include "ui/aura/env.h"
17 #include "ui/aura/event.h"
18 #include "ui/aura/focus_manager.h"
19 #include "ui/aura/hostwm/host_window_manager_client.h"
20 #include "ui/aura/root_window.h"
21 #include "ui/aura/root_window_host_linux.h"
22 #include "ui/aura/window.h"
23 #include "ui/base/touch/touch_factory.h"
24 #include "ui/base/x/x11_util.h"
25
26 namespace {
27
28 class ScopedPtrXFree {
29 public:
30 void operator()(void* x) const {
31 ::XFree(x);
32 }
33 };
34
35 int ExistingWMX11ErrorHandler(Display* d, XErrorEvent* e) {
36 LOG(FATAL)
37 << "X Error detected: "
38 << "serial " << e->serial << ", "
39 << "error_code " << static_cast<int>(e->error_code) << ", "
40 << "request_code " << static_cast<int>(e->request_code) << ", "
41 << "minor_code " << static_cast<int>(e->minor_code);
42 return 0;
43 }
44
45 std::queue<unsigned long> xerror_ignore_queue;
46
47 int FilteredX11ErrorHandler(Display* d, XErrorEvent* e) {
48 while (!xerror_ignore_queue.empty()) {
49 if ((e->serial - xerror_ignore_queue.front()) > 0) {
50 xerror_ignore_queue.pop();
51 continue;
52 }
53
54 break;
55 }
56
57 if (!xerror_ignore_queue.empty() && xerror_ignore_queue.front() == e->serial)
58 return 0;
59
60 return aura::CallBaseX11ErrorHandler(d, e);
61 }
62
63 unsigned InitWindowChanges(const gfx::Rect& bounds,
64 ::Window siblingToStackAbove,
65 XWindowChanges& wc) {
66 wc.x = bounds.x();
67 wc.y = bounds.y();
68 wc.width = bounds.width();
69 wc.height = bounds.height();
70 if (!siblingToStackAbove) {
71 wc.stack_mode = Below;
72 return CWX | CWY | CWWidth | CWHeight | CWStackMode;
73 }
74
75 wc.sibling = siblingToStackAbove;
76 wc.stack_mode = Above;
77 return CWX | CWY | CWWidth | CWHeight | CWStackMode | CWSibling;
78 }
79
80 aura::Window* FindLowestCommonAncestor(
81 aura::Window* root, aura::Window* p, aura::Window* q) {
82 // Root is the LCA.
83 if (root == p || root == q)
84 return root;
85
86 aura::Window* prev = NULL;
87 const aura::Window::Windows& children = root->children();
88 for (size_t i = 0; i < children.size(); ++i) {
89
90 // Try to find LCA of p and q in subtree.
91 aura::Window* next = FindLowestCommonAncestor(children[i], p, q);
92 if (next) {
93
94 // If a LCA was previously found, p and q must be in different subtrees.
95 if (prev)
96 return root;
97
98 prev = next;
99 }
100 }
101
102 return prev;
103 }
104
105 gfx::Point GetTargetOriginInRootWindow(aura::Window* window) {
106 gfx::Point origin;
107
108 const aura::Window* p = window;
109 for (; p != window->GetRootWindow(); p = p->parent())
110 origin = origin.Add(p->GetTargetBounds().origin());
111
112 return origin;
113 }
114
115 gfx::Rect GetTargetBoundsInRootWindow(aura::Window* window) {
116 return gfx::Rect(
117 GetTargetOriginInRootWindow(window),
118 window->GetTargetBounds().size());
119 }
120
121 const char* kAtomsToCache[] = {
122 "WM_DELETE_WINDOW",
123 "WM_PROTOCOLS",
124 NULL
125 };
126
127 }
128
129 namespace aura {
130
131 XErrorHandler base_xerror_handler_ = 0;
132
133 void SetBaseX11ErrorHandler(XErrorHandler error_handler) {
134 DCHECK(!base_xerror_handler_);
135 base_xerror_handler_ = error_handler;
136 }
137
138 int CallBaseX11ErrorHandler(Display* d, XErrorEvent* e) {
139 DCHECK(base_xerror_handler_);
140 return base_xerror_handler_(d, e);
141 }
142
143 HostWindowManagerX11WindowObserver::HostWindowManagerX11WindowObserver(
144 HostWindowManagerX11* manager)
145 : host_window_manager_(manager) {
146 }
147
148 void HostWindowManagerX11WindowObserver::OnWindowInitialized(Window* window) {
149 window->AddObserver(this);
150 }
151
152 void HostWindowManagerX11WindowObserver::OnWillRemoveWindow(Window* window) {
153 HostWindowManagerX11* wm = host_window_manager_;
154
155 if (wm->configure_window_ == window)
156 wm->configure_window_ = window->parent();
157 }
158
159 void HostWindowManagerX11WindowObserver::OnWindowDestroyed(Window* window) {
160 HostWindowManagerX11* wm = host_window_manager_;
161
162 if (wm->input_host_windows_.find(window) != wm->input_host_windows_.end()) {
163 scoped_refptr<HostWindowX11> top_level = wm->input_host_windows_[window];
164 wm->native_windows_.erase(top_level->xid());
165 wm->input_host_windows_.erase(window);
166 top_level->CloseWindow();
167 }
168
169 // This should only happend at close down.
170 if (wm->host_windows_.find(window) != wm->host_windows_.end()) {
171 wm->native_windows_.erase(wm->host_windows_[window]);
172 wm->host_windows_.erase(window);
173 }
174 }
175
176 void HostWindowManagerX11WindowObserver::OnWindowStackingChanged(
177 Window* window) {
178 HostWindowManagerX11* wm = host_window_manager_;
179 wm->HostWindowNeedsConfigure(window->parent());
180 }
181
182 void HostWindowManagerX11WindowObserver::OnWindowVisibilityChanged(
183 Window* window, bool visible) {
184 HostWindowManagerX11* wm = host_window_manager_;
185 // Window can be parent-less when being destroyed.
186 if (window->parent())
187 wm->HostWindowNeedsConfigure(window);
188 }
189
190 void HostWindowManagerX11WindowObserver::OnWindowBoundsChanged(
191 Window* window, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) {
192 HostWindowManagerX11* wm = host_window_manager_;
193 wm->HostWindowNeedsConfigure(window);
194 }
195
196 HostWindowX11::HostWindowX11(::XID xwindow, unsigned state)
197 : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
198 xwindow_(xwindow),
199 state_(state) {
200 }
201
202 HostWindowX11::~HostWindowX11() {
203 }
204
205 bool HostWindowX11::CanResize() {
206 return false;
207 }
208
209 bool HostWindowX11::CanConfigure() {
210 return false;
211 }
212
213 bool HostWindowX11::CanActivate() {
214 return false;
215 }
216
217 InputHostWindowX11::InputHostWindowX11(::XID xwindow)
218 : HostWindowX11(xwindow, WithdrawnState) {
219 }
220
221 InputHostWindowX11::~InputHostWindowX11() {
222 }
223
224 void InputHostWindowX11::CloseWindow() {
225 XDestroyWindow(xdisplay_, xwindow_);
226 }
227
228 bool InputHostWindowX11::CanResize() {
229 return true;
230 }
231
232 bool InputHostWindowX11::CanConfigure() {
233 return true;
234 }
235
236 bool InputHostWindowX11::CanActivate() {
237 return false;
238 }
239
240 RedirectedHostWindowX11::RedirectedHostWindowX11(
241 HostWindowManagerX11* manager,
242 ::Window xwindow,
243 const gfx::Size& size)
244 : HostWindowX11(xwindow, WithdrawnState),
245 host_window_manager_(manager),
246 size_(size),
247 visible_(false) {
248 // Ignore possible X error as we can't guarantee that host window exists
249 // and is of InputOutput type.
250 xerror_ignore_queue.push(NextRequest(xdisplay_));
251 // Damage resource is automatically freed when the window is destroyed or
252 // we close our connection to the X server.
253 XDamageCreate(xdisplay_, xwindow_, XDamageReportRawRectangles);
254 static_cast<DispatcherLinux*>(
255 Env::GetInstance()->GetDispatcher())->
256 AddDispatcherForWindow(this, xwindow_);
257 }
258
259 RedirectedHostWindowX11::~RedirectedHostWindowX11() {
260 static_cast<DispatcherLinux*>(
261 Env::GetInstance()->GetDispatcher())->
262 RemoveDispatcherForWindow(xwindow_);
263 }
264
265 void RedirectedHostWindowX11::OnMapNotify() {
266 HostWindowManagerX11* wm = host_window_manager_;
267 client::HostWindowManagerClient* client = wm->client_;
268
269 if (wm->native_windows_.find(xwindow_) != wm->native_windows_.end())
270 client->OnHostWindowVisibilityChanged(wm->native_windows_[xwindow_], true);
271
272 SetVisible(true);
273 }
274
275 void RedirectedHostWindowX11::OnUnmapNotify() {
276 HostWindowManagerX11* wm = host_window_manager_;
277 client::HostWindowManagerClient* client = wm->client_;
278
279 if (wm->native_windows_.find(xwindow_) != wm->native_windows_.end())
280 client->OnHostWindowVisibilityChanged(
281 wm->native_windows_[xwindow_], false);
282
283 SetVisible(false);
284 }
285
286 void RedirectedHostWindowX11::OnConfigureNotify(
287 gfx::Rect bounds, ::Window above) {
288 HostWindowManagerX11* wm = host_window_manager_;
289 client::HostWindowManagerClient* client = wm->client_;
290
291 if (wm->native_windows_.find(xwindow_) != wm->native_windows_.end())
292 client->OnHostWindowMovedOrResized(wm->native_windows_[xwindow_], bounds);
293
294 SetSize(bounds.size());
295
296 // TODO(reveman): Respect stacking properties.
297 }
298
299 bool RedirectedHostWindowX11::Dispatch(const base::NativeEvent& event) {
300 HostWindowManagerX11* wm = host_window_manager_;
301 client::HostWindowManagerClient* client = wm->client_;
302
303 if (event->type == wm->damage_event_base() + XDamageNotify) {
304 UpdateExternalTexture();
305 return true;
306 }
307
308 switch (event->type) {
309 case ButtonPress: {
310 XEvent x_button_event = *event;
311 x_button_event.xbutton.x = event->xbutton.x_root;
312 x_button_event.xbutton.y = event->xbutton.y_root;
313 client->GetRootWindow()->DispatchNativeEvent(&x_button_event);
314 // We generate a ButtonRelease event here as we won't get a real release
315 // event when we replay event on the host window.
316 x_button_event.type = ButtonRelease;
317 client->GetRootWindow()->DispatchNativeEvent(&x_button_event);
318 XAllowEvents(xdisplay_, ReplayPointer, event->xbutton.time);
319 break;
320 }
321 case ButtonRelease:
322 NOTREACHED();
323 break;
324 case KeyPress:
325 case KeyRelease:
326 // TODO(reveman): Implement key grabs.
327 NOTREACHED();
328 break;
329 }
330 return true;
331 }
332
333 void RedirectedHostWindowX11::UpdateExternalTexture() {
334 // TODO(reveman): Get backing pixmap for window and bind to ui::Texture.
335 }
336
337 void RedirectedHostWindowX11::SetSize(const gfx::Size& size) {
338 if (size == size_)
339 return;
340
341 size_ = size;
342
343 // External texture will be updated as a result of receiving damage events.
344 }
345
346 void RedirectedHostWindowX11::SetVisible(bool visible) {
347 if (visible == visible_)
348 return;
349
350 visible_ = visible;
351 }
352
353 bool RedirectedHostWindowX11::CanResize() {
354 return false;
355 }
356
357 bool RedirectedHostWindowX11::CanConfigure() {
358 return false;
359 }
360
361 bool RedirectedHostWindowX11::CanActivate() {
362 return false;
363 }
364
365 ManagedRedirectedHostWindowX11::ManagedRedirectedHostWindowX11(
366 HostWindowManagerX11* manager, ::Window xwindow, const gfx::Size& size)
367 : RedirectedHostWindowX11(manager, xwindow, size) {
368 }
369
370 ManagedRedirectedHostWindowX11::~ManagedRedirectedHostWindowX11() {
371 }
372
373 void ManagedRedirectedHostWindowX11::CloseWindow() {
374 HostWindowManagerX11* wm = host_window_manager_;
375 XEvent xevent;
376 xevent.type = ClientMessage;
377 xevent.xclient.window = xwindow_;
378 xevent.xclient.message_type = wm->atom_cache_.GetAtom("WM_PROTOCOLS");
379 xevent.xclient.format = 32;
380 xevent.xclient.data.l[0] = wm->atom_cache_.GetAtom("WM_DELETE_WINDOW");
381 xevent.xclient.data.l[1] = CurrentTime;
382 xevent.xclient.data.l[2] = 0;
383 xevent.xclient.data.l[3] = 0;
384 xevent.xclient.data.l[4] = 0;
385 // Ignore possible X error as we can't guarantee that host window exists.
386 xerror_ignore_queue.push(NextRequest(xdisplay_));
387 XSendEvent(xdisplay_, xwindow_, false, NoEventMask, &xevent);
388 }
389
390 bool ManagedRedirectedHostWindowX11::CanResize() {
391 // TODO(reveman): Use hints to determine if host window can be resized.
392 return true;
393 }
394
395 void ManagedRedirectedHostWindowX11::OnMapNotify() {
396 SetVisible(true);
397 }
398
399 void ManagedRedirectedHostWindowX11::OnUnmapNotify() {
400 HostWindowManagerX11* wm = host_window_manager_;
401 client::HostWindowManagerClient* client = wm->client_;
402
403 // The client unmapped the window, we should transition to withdrawn state.
404 if (state_ == NormalState) {
405 if (wm->native_windows_.find(xwindow_) != wm->native_windows_.end())
406 client->OnHostWindowVisibilityChanged(
407 wm->native_windows_[xwindow_], false);
408
409 state_ = WithdrawnState;
410 }
411
412 SetVisible(false);
413 }
414
415 void ManagedRedirectedHostWindowX11::OnConfigureNotify(
416 gfx::Rect bounds, ::Window above) {
417 SetSize(bounds.size());
418 }
419
420 bool ManagedRedirectedHostWindowX11::CanConfigure() {
421 return true;
422 }
423
424 bool ManagedRedirectedHostWindowX11::CanActivate() {
425 return true;
426 }
427
428 HostWindowManagerX11RootEventObserver::HostWindowManagerX11RootEventObserver(
429 HostWindowManagerX11* manager)
430 : host_window_manager_(manager),
431 xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()) {
432 }
433
434 bool HostWindowManagerX11RootEventObserver::ProcessHostWindowUpdate(
435 const base::NativeEvent& event) {
436 HostWindowManagerX11* wm = host_window_manager_;
437 client::HostWindowManagerClient* client = wm->client_;
438
439 ::Window xwindow = 0;
440 switch (event->type) {
441 case CreateNotify: {
442 int border_size = event->xcreatewindow.border_width * 2;
443 gfx::Rect bounds(event->xcreatewindow.x,
444 event->xcreatewindow.y,
445 event->xcreatewindow.width + border_size,
446 event->xcreatewindow.height + border_size);
447 wm->RegisterNewTopLevel(event->xcreatewindow.window, bounds,
448 !event->xcreatewindow.override_redirect);
449 xwindow = event->xcreatewindow.window;
450 } break;
451 case ReparentNotify:
452 if (event->xreparent.parent == wm->x_root_window_)
453 wm->RegisterNewTopLevel(event->xreparent.window);
454 xwindow = event->xreparent.window;
455 break;
456 case MapNotify:
457 xwindow = event->xmap.window;
458 break;
459 case UnmapNotify:
460 xwindow = event->xunmap.window;
461 break;
462 case DestroyNotify:
463 xwindow = event->xdestroywindow.window;
464 break;
465 case ConfigureNotify:
466 xwindow = event->xconfigure.window;
467 break;
468 default:
469 return false;
470 }
471
472 scoped_refptr<HostWindowX11> top_level = wm->top_level_windows_[xwindow];
473
474 DCHECK(top_level);
475
476 switch (event->type) {
477 case CreateNotify:
478 wm->HostWindowNeedsConfigure(client->GetRootWindow());
479 break;
480 case MapNotify:
481 top_level->OnMapNotify();
482 break;
483 case UnmapNotify:
484 top_level->OnUnmapNotify();
485 break;
486 case ReparentNotify:
487 if (event->xreparent.parent == wm->x_root_window_) {
488 wm->HostWindowNeedsConfigure(client->GetRootWindow());
489 break;
490 }
491
492 XUngrabButton(xdisplay_, AnyButton, AnyModifier, xwindow);
493
494 // TODO(danakj): grab keys on the window so we can use shortcuts
495 //XUngrabKey(xdisplay_, AnyKey, AnyModifier, xwindow);
496
497 // Fallthrough.
498 case DestroyNotify: {
499 if (wm->native_windows_.find(xwindow) != wm->native_windows_.end()) {
500 Window* window = wm->native_windows_[xwindow];
501
502 DCHECK(wm->input_host_windows_.find(window) ==
503 wm->input_host_windows_.end());
504
505 if (wm->host_windows_.find(window) != wm->host_windows_.end()) {
506 // Reset delegate before calling OnHostWindowDestroyed to make sure
507 // we're not preventing widget from being closed.
508 SetHostWindowDelegate(window, 0);
509 client->OnHostWindowDestroyed(window);
510 wm->host_windows_.erase(window);
511 }
512
513 wm->native_windows_.erase(xwindow);
514 }
515 wm->top_level_windows_.erase(xwindow);
516
517 // Window destruction could have caused a previous configure request to
518 // fail.
519 wm->HostWindowNeedsConfigure(client->GetRootWindow());
520 } break;
521 case ConfigureNotify: {
522 int bw = event->xconfigure.border_width * 2;
523 gfx::Rect bounds(event->xconfigure.x,
524 event->xconfigure.y,
525 event->xconfigure.width + bw,
526 event->xconfigure.height + bw);
527 top_level->OnConfigureNotify(bounds, event->xconfigure.above);
528 } break;
529 }
530
531 return true;
532 }
533
534 bool HostWindowManagerX11RootEventObserver::ProcessHostWindowRequest(
535 const base::NativeEvent& event) {
536 HostWindowManagerX11* wm = host_window_manager_;
537 client::HostWindowManagerClient* client = wm->client_;
538
539 ::Window xwindow = 0;
540 switch (event->type) {
541 case MapRequest:
542 xwindow = event->xmaprequest.window;
543 break;
544 case ConfigureRequest:
545 xwindow = event->xconfigurerequest.window;
546 break;
547 case CirculateRequest:
548 xwindow = event->xcirculaterequest.window;
549 break;
550 default:
551 return false;
552 }
553
554 scoped_refptr<HostWindowX11> top_level = wm->top_level_windows_[xwindow];
555
556 DCHECK(top_level);
557 DCHECK(top_level->CanConfigure());
558
559 if (wm->native_windows_.find(xwindow) == wm->native_windows_.end())
560 return true;
561
562 Window* window = wm->native_windows_[xwindow];
563
564 switch (event->type) {
565 case MapRequest:
566 client->OnHostWindowMovedOrResizedConstrained(
567 window, GetTargetBoundsInRootWindow(window));
568 client->OnHostWindowVisibilityChanged(window, true);
569 break;
570 case ConfigureRequest: {
571 gfx::Rect bounds(GetTargetBoundsInRootWindow(window));
572 if (event->xconfigurerequest.value_mask & CWX)
573 bounds.set_x(event->xconfigurerequest.x);
574 if (event->xconfigurerequest.value_mask & CWY)
575 bounds.set_y(event->xconfigurerequest.y);
576 if (event->xconfigurerequest.value_mask & CWWidth)
577 bounds.set_width(event->xconfigurerequest.width);
578 if (event->xconfigurerequest.value_mask & CWHeight)
579 bounds.set_height(event->xconfigurerequest.height);
580 client->OnHostWindowMovedOrResizedConstrained(window, bounds);
581 // TODO(reveman): Respect stacking properties.
582 } break;
583 case CirculateRequest:
584 // TODO(reveman): Respect stacking properties.
585 break;
586 }
587
588 return true;
589 }
590
591 bool HostWindowManagerX11RootEventObserver::Dispatch(
592 const base::NativeEvent& event) {
593 if (ProcessHostWindowRequest(event))
594 return true;
595 if (ProcessHostWindowUpdate(event))
596 return true;
597
598 HostWindowManagerX11* wm = host_window_manager_;
599 client::HostWindowManagerClient* client = wm->client_;
600 // Let root window host handle all input events.
601 return client->GetRootWindow()->DispatchNativeEvent(event);
602 }
603
604 void HostWindowManagerX11RootEventObserver::OnWindowFocused(Window* window) {
605 HostWindowManagerX11* wm = host_window_manager_;
606 client::HostWindowManagerClient* client = wm->client_;
607 // We need to configure all windows when changing focus.
608 wm->HostWindowNeedsConfigure(client->GetRootWindow());
609 }
610
611 void HostWindowManagerX11RootEventObserver::OnCursorChanged(
612 const RootWindow* root, ui::PlatformCursor cursor) {
613 HostWindowManagerX11* wm = host_window_manager_;
614
615 // Set cursor for all input windows.
616 std::map<gfx::NativeWindow, scoped_refptr<InputHostWindowX11> >::iterator it;
617 for (it = wm->input_host_windows_.begin();
618 it != wm->input_host_windows_.end(); it++) {
619 scoped_refptr<HostWindowX11> input_window = (*it).second;
620 XDefineCursor(xdisplay_, input_window->xid(), cursor);
621 }
622 }
623
624 HostWindowManagerX11::HostWindowManagerX11(
625 client::HostWindowManagerClient* client)
626 : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
627 x_root_window_(DefaultRootWindow(xdisplay_)),
628 configure_window_(0),
629 damage_event_base_(0),
630 window_observer_(new HostWindowManagerX11WindowObserver(this)),
631 event_observer_(new HostWindowManagerX11RootEventObserver(this)),
632 atom_cache_(xdisplay_, kAtomsToCache),
633 client_(client) {
634 // TODO(reveman): Check that damage extension is present.
635 int error_base_ignored;
636 XDamageQueryExtension(xdisplay_, &damage_event_base_, &error_base_ignored);
637 }
638
639 HostWindowManagerX11::~HostWindowManagerX11() {
640 XCompositeUnredirectSubwindows(xdisplay_, x_root_window_,
641 CompositeRedirectManual);
642
643 std::map< ::Window, gfx::NativeWindow>::iterator it;
644 for (it = native_windows_.begin(); it != native_windows_.end(); it++) {
645 if ((*it).second) {
646 Window* window = (*it).second;
647 SetHostWindowDelegate(window, 0);
648 client_->OnHostWindowDestroyed(window);
649 window->RemoveObserver(window_observer_.get());
650 }
651 }
652
653 top_level_windows_.clear();
654 native_windows_.clear();
655 host_windows_.clear();
656 input_host_windows_.clear();
657
658 Env::GetInstance()->RemoveObserver(window_observer_.get());
659 static_cast<DispatcherLinux*>(
660 Env::GetInstance()->GetDispatcher())->
661 RemoveDispatcherForRootWindow(event_observer_.get());
662 if (client_->GetRootWindow()) {
663 client_->GetRootWindow()->RemoveRootWindowObserver(event_observer_.get());
664 client_->GetRootWindow()->GetFocusManager()->RemoveObserver(
665 event_observer_.get());
666 }
667 }
668
669 ::Window HostWindowManagerX11::GetTopHostWindow(Window* window) {
670 // children is ordered back to front, so walk through it in reverse.
671 const Window::Windows& children = window->children();
672 for (size_t i = children.size(); i; --i) {
673 ::Window top = GetTopHostWindow(children[i - 1]);
674 if (top)
675 return top;
676 }
677
678 if (host_windows_.find(window) != host_windows_.end()) {
679 ::Window host_window = host_windows_[window];
680 scoped_refptr<HostWindowX11> top_level = top_level_windows_[host_window];
681
682 DCHECK(top_level);
683 // Ignore windows that we're not allowed to configure.
684 if (top_level->CanConfigure())
685 return host_window;
686 }
687
688 if (input_host_windows_.find(window) != input_host_windows_.end())
689 return input_host_windows_[window]->xid();
690
691 return 0;
692 }
693
694 ::Window HostWindowManagerX11::FindHostWindowToStackAbove(Window* window) {
695 Window* parent = window->parent();
696 if (!parent)
697 return 0;
698
699 ::Window above = 0;
700
701 const Window::Windows& children = parent->children();
702 for (size_t i = 0; i < children.size(); ++i) {
703 if (children[i] == window)
704 break;
705
706 ::Window top = GetTopHostWindow(children[i]);
707 if (top)
708 above = top;
709 }
710
711 if (!above)
712 above = FindHostWindowToStackAbove(parent);
713
714 return above;
715 }
716
717 void HostWindowManagerX11::CreateHostInputWindowIfNeeded(Window* window) {
718 // Ignore root window.
719 if (window == window->GetRootWindow())
720 return;
721
722 // Don't create host input window when there's already host window.
723 if (host_windows_.find(window) != host_windows_.end())
724 return;
725
726 // Avoid windows without delegates.
727 if (!window->delegate())
728 return;
729
730 // Delay creation until window is visible.
731 if (!window->IsVisible())
732 return;
733
734 // Host input window already exists.
735 if (input_host_windows_.find(window) != input_host_windows_.end())
736 return;
737
738 scoped_refptr<InputHostWindowX11> delegate = new InputHostWindowX11(
739 XCreateWindow(xdisplay_, x_root_window_, -100, -100, 1, 1,
740 0, CopyFromParent, InputOnly, CopyFromParent, 0, 0));
741 SetHostWindowDelegate(window, delegate);
742 native_windows_[delegate->xid()] = window;
743 input_host_windows_[window] = delegate;
744 }
745
746 void HostWindowManagerX11::RecursiveConfigureHostWindow(
747 Window* window,
748 gfx::Point origin,
749 ::Window& sibling_to_stack_above,
750 ::Window& focus_window,
751 bool has_focus) {
752 RootWindow* root_window = window->GetRootWindow();
753
754 // Lazy creation of input only windows.
755 CreateHostInputWindowIfNeeded(window);
756
757 // Special case to ensure that root window is stacked properly.
758 if (window == root_window) {
759 XWindowChanges wc;
760 unsigned mask = InitWindowChanges(gfx::Rect(), sibling_to_stack_above, wc);
761 ::Window root_host_window =
762 root_window->GetAcceleratedWidgetUsedForEvents();
763 DCHECK(window->IsVisible());
764 XConfigureWindow(xdisplay_, root_host_window,
765 mask & (CWSibling | CWStackMode),
766 &wc);
767
768 sibling_to_stack_above = root_host_window;
769 }
770
771 // We never move focus to our internal input host windows.
772 if (input_host_windows_.find(window) != input_host_windows_.end()) {
773 scoped_refptr<HostWindowX11> input_window = input_host_windows_[window];
774 gfx::Rect host_bounds(origin, window->GetTargetBounds().size());
775 host_bounds.Inset(window->hit_test_bounds_override_outer());
776 gfx::Rect non_empty_bounds(
777 host_bounds.Union(gfx::Rect(host_bounds.origin(), gfx::Size(1, 1))));
778
779 if (!window->IsVisible()) {
780 if (input_window->state() == NormalState) {
781 XUnmapWindow(xdisplay_, input_window->xid());
782 input_window->set_state(IconicState);
783 }
784 }
785
786 XWindowChanges wc;
787 unsigned mask = InitWindowChanges(
788 non_empty_bounds, sibling_to_stack_above, wc);
789 // Ignore possible X error as we can't guarantee that host window exists.
790 if (mask & CWSibling)
791 xerror_ignore_queue.push(NextRequest(xdisplay_));
792 XConfigureWindow(xdisplay_, input_window->xid(), mask, &wc);
793
794 sibling_to_stack_above = input_window->xid();
795
796 if (window->IsVisible()) {
797 if (input_window->state() != NormalState) {
798 XMapWindow(xdisplay_, input_window->xid());
799 input_window->set_state(NormalState);
800 }
801 }
802 }
803
804 if (host_windows_.find(window) != host_windows_.end()) {
805 ::Window host_window = host_windows_[window];
806 scoped_refptr<HostWindowX11> top_level = top_level_windows_[host_window];
807
808 DCHECK(top_level);
809 if (top_level->CanConfigure()) {
810 gfx::Rect host_bounds(origin, window->GetTargetBounds().size());
811 gfx::Rect non_empty_bounds(
812 host_bounds.Union(gfx::Rect(host_bounds.origin(), gfx::Size(1, 1))));
813
814 if (!window->IsVisible()) {
815 if (top_level->state() == NormalState) {
816 // Ignore possible X error as we can't guarantee that host window
817 // exists.
818 xerror_ignore_queue.push(NextRequest(xdisplay_));
819 XUnmapWindow(xdisplay_, host_window);
820
821 top_level->set_state(IconicState);
822 }
823 }
824
825 XWindowChanges wc;
826 unsigned mask = InitWindowChanges(
827 non_empty_bounds, sibling_to_stack_above, wc);
828 // Get rid of any borders.
829 wc.border_width = 0;
830 mask |= CWBorderWidth;
831 // Ignore possible X error as we can't guarantee that host window exists.
832 xerror_ignore_queue.push(NextRequest(xdisplay_));
833 XConfigureWindow(xdisplay_, host_window, mask, &wc);
834
835 sibling_to_stack_above = host_window;
836
837 if (window->IsVisible()) {
838 if (top_level->state() != NormalState) {
839 // Ignore possible X error as we can't guarantee that host window
840 // exists.
841 xerror_ignore_queue.push(NextRequest(xdisplay_));
842 XMapWindow(xdisplay_, host_window);
843
844 // Grab buttons so that window can be activated when a click is
845 // received in the client area.
846 xerror_ignore_queue.push(NextRequest(xdisplay_));
847 XGrabButton(xdisplay_, AnyButton, AnyModifier, host_window, false,
848 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
849 GrabModeSync, GrabModeAsync, 0, 0);
850
851 // TODO(danakj): grab keys on the window so we can use shortcuts
852 //XGrabKey(xdisplay_, AnyKey, AnyModifier, event->xmaprequest.window,
853 // true, GrabModeAsync, GrabModeSync);
854
855 top_level->set_state(NormalState);
856 }
857
858 // Set |focus_window| to host window if aura sub-tree has focus.
859 if (has_focus)
860 focus_window = host_window;
861 }
862 }
863 }
864
865 const Window::Windows& children = window->children();
866 for (size_t i = 0; i < children.size(); ++i)
867 RecursiveConfigureHostWindow(
868 children[i],
869 origin.Add(children[i]->GetTargetBounds().origin()),
870 sibling_to_stack_above,
871 focus_window,
872 has_focus || window->HasFocus());
873 }
874
875 void HostWindowManagerX11::ConfigureHostWindows() {
876 if (!configure_window_)
877 return;
878
879 ::Window focus_window = 0;
880 ::Window sibling_to_stack_above =
881 FindHostWindowToStackAbove(configure_window_);
882 RecursiveConfigureHostWindow(
883 configure_window_,
884 GetTargetOriginInRootWindow(configure_window_),
885 sibling_to_stack_above,
886 focus_window,
887 configure_window_->HasFocus());
888
889 // Only set focus when we configure the root window.
890 if (configure_window_ == client_->GetRootWindow()) {
891 if (focus_window) {
892 // Ignore possible X error as we can't guarantee that host window exists.
893 xerror_ignore_queue.push(NextRequest(xdisplay_));
894 XSetInputFocus(xdisplay_, focus_window, 0, CurrentTime);
895 } else
896 XSetInputFocus(
897 xdisplay_,
898 client_->GetRootWindow()->GetAcceleratedWidgetUsedForEvents(),
899 0, CurrentTime);
900 }
901
902 configure_window_ = 0;
903 }
904
905 void HostWindowManagerX11::HostWindowNeedsConfigure(Window* window) {
906 DCHECK(window->GetRootWindow() == client_->GetRootWindow());
907 if (!configure_window_) {
908 configure_window_ = window;
909 MessageLoop::current()->PostTask(
910 FROM_HERE,
911 base::Bind(&HostWindowManagerX11::ConfigureHostWindows, AsWeakPtr()));
912 } else {
913 configure_window_ = FindLowestCommonAncestor(
914 window->GetRootWindow(), configure_window_, window);
915 }
916 }
917
918 void HostWindowManagerX11::Init() {
919 Env::GetInstance()->AddObserver(window_observer_.get());
920 static_cast<DispatcherLinux*>(
921 Env::GetInstance()->GetDispatcher())->
922 AddDispatcherForRootWindow(event_observer_.get());
923
924 // TODO(danakj): When env manages root windows, get it from there, and watch
925 // for monitor changes.
926 client_->GetRootWindow()->AddRootWindowObserver(event_observer_.get());
927 client_->GetRootWindow()->GetFocusManager()->AddObserver(
928 event_observer_.get());
929
930 if (client_->GetRootWindow()->GetAcceleratedWidget() ==
931 client_->GetRootWindow()->GetAcceleratedWidgetUsedForEvents())
932 LOG(FATAL) << "Overlay window must be used as output. Try using "
933 "--aura-host-window-use-fullscreen.";
934
935 int root_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
936 EnterWindowMask | LeaveWindowMask | SubstructureRedirectMask |
937 SubstructureNotifyMask;
938
939 XGrabServer(xdisplay_);
940
941 ::Window root, parent, *children = 0;
942 unsigned int nchildren;
943 XQueryTree(xdisplay_, x_root_window_, &root, &parent, &children, &nchildren);
944 scoped_ptr_malloc< ::Window, ScopedPtrXFree> xwindows(children);
945
946 XErrorHandler error_handler = XSetErrorHandler(ExistingWMX11ErrorHandler);
947 XWindowAttributes attr;
948 XGetWindowAttributes(xdisplay_, x_root_window_, &attr);
949 XSelectInput(xdisplay_, x_root_window_, attr.your_event_mask | root_mask);
950 // Redirect top-level windows to offscreen buffers.
951 XCompositeRedirectSubwindows(xdisplay_, x_root_window_,
952 CompositeRedirectManual);
953 XSync(xdisplay_, 0);
954 XSetErrorHandler(error_handler);
955
956 // Install filtered error handler.
957 SetBaseX11ErrorHandler(XSetErrorHandler(FilteredX11ErrorHandler));
958
959 XUngrabServer(xdisplay_);
960
961 // Set root window cursor. Host windows that don't define their own cursor
962 // will inherit the default cursor defined here.
963 XDefineCursor(xdisplay_, x_root_window_, ui::GetXCursor(XC_left_ptr));
964
965 for (size_t i = 0; i < nchildren; ++i)
966 RegisterNewTopLevel(xwindows.get()[i]);
967
968 HostWindowNeedsConfigure(client_->GetRootWindow());
969 }
970
971 void HostWindowManagerX11::RegisterNewTopLevel(::Window xwindow) {
972 gfx::Rect bounds(gfx::Point(-100, -100), gfx::Size(1, 1));
973 bool visible = false;
974 bool managed = false;
975
976 XWindowAttributes attributes;
977 // Ignore possible X error as we can't guarantee that host window exists.
978 xerror_ignore_queue.push(NextRequest(xdisplay_));
979 if (XGetWindowAttributes(xdisplay_, xwindow, &attributes)) {
980 int border_size = attributes.border_width * 2;
981 bounds = gfx::Rect(attributes.x,
982 attributes.y,
983 attributes.width + border_size,
984 attributes.height + border_size);
985 visible = attributes.map_state == IsViewable;
986 managed = !attributes.override_redirect;
987 }
988
989 RegisterNewTopLevel(xwindow, bounds, managed);
990
991 if (visible) {
992 Window* window = native_windows_[xwindow];
993 DCHECK(window);
994 client_->OnHostWindowMovedOrResizedConstrained(
995 window, GetTargetBoundsInRootWindow(window));
996 client_->OnHostWindowVisibilityChanged(window, true);
997 }
998 }
999
1000 void HostWindowManagerX11::RegisterNewTopLevel(
1001 ::Window xwindow, const gfx::Rect bounds, bool managed) {
1002 client::HostWindowManagerClient* client = client_;
1003
1004 // Add a HostWindowX11 for the root input window.
1005 RootWindow* root_window = client->GetRootWindow();
1006 if (xwindow == root_window->GetAcceleratedWidgetUsedForEvents()) {
1007 top_level_windows_[xwindow] = new HostWindowX11(xwindow, NormalState);
1008 return;
1009 }
1010
1011 // Container input windows will already have a native mapping.
1012 if (native_windows_.find(xwindow) != native_windows_.end()) {
1013 Window* window = native_windows_[xwindow];
1014
1015 if (input_host_windows_.find(window) != input_host_windows_.end()) {
1016 top_level_windows_[xwindow] = input_host_windows_[window];
1017 return;
1018 }
1019 }
1020
1021 // This is foreign host window.
1022 scoped_refptr<HostWindowX11> top_level;
1023 bool decorated = false;
1024
1025 if (managed) {
1026 top_level = new ManagedRedirectedHostWindowX11(
1027 this, xwindow, bounds.size());
1028 decorated = true;
1029 } else {
1030 top_level = new RedirectedHostWindowX11(this, xwindow, bounds.size());
1031 }
1032
1033 // Create a native window.
1034 Window* window = client->OnHostWindowCreated(bounds, decorated);
1035 SetHostWindowDelegate(window, top_level);
1036 top_level_windows_[xwindow] = top_level;
1037
1038 native_windows_[xwindow] = window;
1039 host_windows_[window] = xwindow;
1040 }
1041
1042 } // namespace aura
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698