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/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 |
OLD | NEW |