| Index: ui/aura/hostwm/host_window_manager_x11.cc
|
| diff --git a/ui/aura/hostwm/host_window_manager_x11.cc b/ui/aura/hostwm/host_window_manager_x11.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..03e6bfc797ac887a437c2ca9aa682e2ba3b3bccc
|
| --- /dev/null
|
| +++ b/ui/aura/hostwm/host_window_manager_x11.cc
|
| @@ -0,0 +1,1042 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "ui/aura/hostwm/host_window_manager_x11.h"
|
| +
|
| +#include <X11/Xutil.h>
|
| +#include <X11/cursorfont.h>
|
| +#include <X11/extensions/Xcomposite.h>
|
| +#include <X11/extensions/Xdamage.h>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/message_pump_aurax11.h"
|
| +#include "ui/aura/client/window_types.h"
|
| +#include "ui/aura/dispatcher_linux.h"
|
| +#include "ui/aura/env.h"
|
| +#include "ui/aura/event.h"
|
| +#include "ui/aura/focus_manager.h"
|
| +#include "ui/aura/hostwm/host_window_manager_client.h"
|
| +#include "ui/aura/root_window.h"
|
| +#include "ui/aura/root_window_host_linux.h"
|
| +#include "ui/aura/window.h"
|
| +#include "ui/base/touch/touch_factory.h"
|
| +#include "ui/base/x/x11_util.h"
|
| +
|
| +namespace {
|
| +
|
| +class ScopedPtrXFree {
|
| + public:
|
| + void operator()(void* x) const {
|
| + ::XFree(x);
|
| + }
|
| +};
|
| +
|
| +int ExistingWMX11ErrorHandler(Display* d, XErrorEvent* e) {
|
| + LOG(FATAL)
|
| + << "X Error detected: "
|
| + << "serial " << e->serial << ", "
|
| + << "error_code " << static_cast<int>(e->error_code) << ", "
|
| + << "request_code " << static_cast<int>(e->request_code) << ", "
|
| + << "minor_code " << static_cast<int>(e->minor_code);
|
| + return 0;
|
| +}
|
| +
|
| +std::queue<unsigned long> xerror_ignore_queue;
|
| +
|
| +int FilteredX11ErrorHandler(Display* d, XErrorEvent* e) {
|
| + while (!xerror_ignore_queue.empty()) {
|
| + if ((e->serial - xerror_ignore_queue.front()) > 0) {
|
| + xerror_ignore_queue.pop();
|
| + continue;
|
| + }
|
| +
|
| + break;
|
| + }
|
| +
|
| + if (!xerror_ignore_queue.empty() && xerror_ignore_queue.front() == e->serial)
|
| + return 0;
|
| +
|
| + return aura::CallBaseX11ErrorHandler(d, e);
|
| +}
|
| +
|
| +unsigned InitWindowChanges(const gfx::Rect& bounds,
|
| + ::Window siblingToStackAbove,
|
| + XWindowChanges& wc) {
|
| + wc.x = bounds.x();
|
| + wc.y = bounds.y();
|
| + wc.width = bounds.width();
|
| + wc.height = bounds.height();
|
| + if (!siblingToStackAbove) {
|
| + wc.stack_mode = Below;
|
| + return CWX | CWY | CWWidth | CWHeight | CWStackMode;
|
| + }
|
| +
|
| + wc.sibling = siblingToStackAbove;
|
| + wc.stack_mode = Above;
|
| + return CWX | CWY | CWWidth | CWHeight | CWStackMode | CWSibling;
|
| +}
|
| +
|
| +aura::Window* FindLowestCommonAncestor(
|
| + aura::Window* root, aura::Window* p, aura::Window* q) {
|
| + // Root is the LCA.
|
| + if (root == p || root == q)
|
| + return root;
|
| +
|
| + aura::Window* prev = NULL;
|
| + const aura::Window::Windows& children = root->children();
|
| + for (size_t i = 0; i < children.size(); ++i) {
|
| +
|
| + // Try to find LCA of p and q in subtree.
|
| + aura::Window* next = FindLowestCommonAncestor(children[i], p, q);
|
| + if (next) {
|
| +
|
| + // If a LCA was previously found, p and q must be in different subtrees.
|
| + if (prev)
|
| + return root;
|
| +
|
| + prev = next;
|
| + }
|
| + }
|
| +
|
| + return prev;
|
| +}
|
| +
|
| +gfx::Point GetTargetOriginInRootWindow(aura::Window* window) {
|
| + gfx::Point origin;
|
| +
|
| + const aura::Window* p = window;
|
| + for (; p != window->GetRootWindow(); p = p->parent())
|
| + origin = origin.Add(p->GetTargetBounds().origin());
|
| +
|
| + return origin;
|
| +}
|
| +
|
| +gfx::Rect GetTargetBoundsInRootWindow(aura::Window* window) {
|
| + return gfx::Rect(
|
| + GetTargetOriginInRootWindow(window),
|
| + window->GetTargetBounds().size());
|
| +}
|
| +
|
| +const char* kAtomsToCache[] = {
|
| + "WM_DELETE_WINDOW",
|
| + "WM_PROTOCOLS",
|
| + NULL
|
| +};
|
| +
|
| +}
|
| +
|
| +namespace aura {
|
| +
|
| +XErrorHandler base_xerror_handler_ = 0;
|
| +
|
| +void SetBaseX11ErrorHandler(XErrorHandler error_handler) {
|
| + DCHECK(!base_xerror_handler_);
|
| + base_xerror_handler_ = error_handler;
|
| +}
|
| +
|
| +int CallBaseX11ErrorHandler(Display* d, XErrorEvent* e) {
|
| + DCHECK(base_xerror_handler_);
|
| + return base_xerror_handler_(d, e);
|
| +}
|
| +
|
| +HostWindowManagerX11WindowObserver::HostWindowManagerX11WindowObserver(
|
| + HostWindowManagerX11* manager)
|
| + : host_window_manager_(manager) {
|
| +}
|
| +
|
| +void HostWindowManagerX11WindowObserver::OnWindowInitialized(Window* window) {
|
| + window->AddObserver(this);
|
| +}
|
| +
|
| +void HostWindowManagerX11WindowObserver::OnWillRemoveWindow(Window* window) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| +
|
| + if (wm->configure_window_ == window)
|
| + wm->configure_window_ = window->parent();
|
| +}
|
| +
|
| +void HostWindowManagerX11WindowObserver::OnWindowDestroyed(Window* window) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| +
|
| + if (wm->input_host_windows_.find(window) != wm->input_host_windows_.end()) {
|
| + scoped_refptr<HostWindowX11> top_level = wm->input_host_windows_[window];
|
| + wm->native_windows_.erase(top_level->xid());
|
| + wm->input_host_windows_.erase(window);
|
| + top_level->CloseWindow();
|
| + }
|
| +
|
| + // This should only happend at close down.
|
| + if (wm->host_windows_.find(window) != wm->host_windows_.end()) {
|
| + wm->native_windows_.erase(wm->host_windows_[window]);
|
| + wm->host_windows_.erase(window);
|
| + }
|
| +}
|
| +
|
| +void HostWindowManagerX11WindowObserver::OnWindowStackingChanged(
|
| + Window* window) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + wm->HostWindowNeedsConfigure(window->parent());
|
| +}
|
| +
|
| +void HostWindowManagerX11WindowObserver::OnWindowVisibilityChanged(
|
| + Window* window, bool visible) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + // Window can be parent-less when being destroyed.
|
| + if (window->parent())
|
| + wm->HostWindowNeedsConfigure(window);
|
| +}
|
| +
|
| +void HostWindowManagerX11WindowObserver::OnWindowBoundsChanged(
|
| + Window* window, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + wm->HostWindowNeedsConfigure(window);
|
| +}
|
| +
|
| +HostWindowX11::HostWindowX11(::XID xwindow, unsigned state)
|
| + : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
|
| + xwindow_(xwindow),
|
| + state_(state) {
|
| +}
|
| +
|
| +HostWindowX11::~HostWindowX11() {
|
| +}
|
| +
|
| +bool HostWindowX11::CanResize() {
|
| + return false;
|
| +}
|
| +
|
| +bool HostWindowX11::CanConfigure() {
|
| + return false;
|
| +}
|
| +
|
| +bool HostWindowX11::CanActivate() {
|
| + return false;
|
| +}
|
| +
|
| +InputHostWindowX11::InputHostWindowX11(::XID xwindow)
|
| + : HostWindowX11(xwindow, WithdrawnState) {
|
| +}
|
| +
|
| +InputHostWindowX11::~InputHostWindowX11() {
|
| +}
|
| +
|
| +void InputHostWindowX11::CloseWindow() {
|
| + XDestroyWindow(xdisplay_, xwindow_);
|
| +}
|
| +
|
| +bool InputHostWindowX11::CanResize() {
|
| + return true;
|
| +}
|
| +
|
| +bool InputHostWindowX11::CanConfigure() {
|
| + return true;
|
| +}
|
| +
|
| +bool InputHostWindowX11::CanActivate() {
|
| + return false;
|
| +}
|
| +
|
| +RedirectedHostWindowX11::RedirectedHostWindowX11(
|
| + HostWindowManagerX11* manager,
|
| + ::Window xwindow,
|
| + const gfx::Size& size)
|
| + : HostWindowX11(xwindow, WithdrawnState),
|
| + host_window_manager_(manager),
|
| + size_(size),
|
| + visible_(false) {
|
| + // Ignore possible X error as we can't guarantee that host window exists
|
| + // and is of InputOutput type.
|
| + xerror_ignore_queue.push(NextRequest(xdisplay_));
|
| + // Damage resource is automatically freed when the window is destroyed or
|
| + // we close our connection to the X server.
|
| + XDamageCreate(xdisplay_, xwindow_, XDamageReportRawRectangles);
|
| + static_cast<DispatcherLinux*>(
|
| + Env::GetInstance()->GetDispatcher())->
|
| + AddDispatcherForWindow(this, xwindow_);
|
| +}
|
| +
|
| +RedirectedHostWindowX11::~RedirectedHostWindowX11() {
|
| + static_cast<DispatcherLinux*>(
|
| + Env::GetInstance()->GetDispatcher())->
|
| + RemoveDispatcherForWindow(xwindow_);
|
| +}
|
| +
|
| +void RedirectedHostWindowX11::OnMapNotify() {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + client::HostWindowManagerClient* client = wm->client_;
|
| +
|
| + if (wm->native_windows_.find(xwindow_) != wm->native_windows_.end())
|
| + client->OnHostWindowVisibilityChanged(wm->native_windows_[xwindow_], true);
|
| +
|
| + SetVisible(true);
|
| +}
|
| +
|
| +void RedirectedHostWindowX11::OnUnmapNotify() {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + client::HostWindowManagerClient* client = wm->client_;
|
| +
|
| + if (wm->native_windows_.find(xwindow_) != wm->native_windows_.end())
|
| + client->OnHostWindowVisibilityChanged(
|
| + wm->native_windows_[xwindow_], false);
|
| +
|
| + SetVisible(false);
|
| +}
|
| +
|
| +void RedirectedHostWindowX11::OnConfigureNotify(
|
| + gfx::Rect bounds, ::Window above) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + client::HostWindowManagerClient* client = wm->client_;
|
| +
|
| + if (wm->native_windows_.find(xwindow_) != wm->native_windows_.end())
|
| + client->OnHostWindowMovedOrResized(wm->native_windows_[xwindow_], bounds);
|
| +
|
| + SetSize(bounds.size());
|
| +
|
| + // TODO(reveman): Respect stacking properties.
|
| +}
|
| +
|
| +bool RedirectedHostWindowX11::Dispatch(const base::NativeEvent& event) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + client::HostWindowManagerClient* client = wm->client_;
|
| +
|
| + if (event->type == wm->damage_event_base() + XDamageNotify) {
|
| + UpdateExternalTexture();
|
| + return true;
|
| + }
|
| +
|
| + switch (event->type) {
|
| + case ButtonPress: {
|
| + XEvent x_button_event = *event;
|
| + x_button_event.xbutton.x = event->xbutton.x_root;
|
| + x_button_event.xbutton.y = event->xbutton.y_root;
|
| + client->GetRootWindow()->DispatchNativeEvent(&x_button_event);
|
| + // We generate a ButtonRelease event here as we won't get a real release
|
| + // event when we replay event on the host window.
|
| + x_button_event.type = ButtonRelease;
|
| + client->GetRootWindow()->DispatchNativeEvent(&x_button_event);
|
| + XAllowEvents(xdisplay_, ReplayPointer, event->xbutton.time);
|
| + break;
|
| + }
|
| + case ButtonRelease:
|
| + NOTREACHED();
|
| + break;
|
| + case KeyPress:
|
| + case KeyRelease:
|
| + // TODO(reveman): Implement key grabs.
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void RedirectedHostWindowX11::UpdateExternalTexture() {
|
| + // TODO(reveman): Get backing pixmap for window and bind to ui::Texture.
|
| +}
|
| +
|
| +void RedirectedHostWindowX11::SetSize(const gfx::Size& size) {
|
| + if (size == size_)
|
| + return;
|
| +
|
| + size_ = size;
|
| +
|
| + // External texture will be updated as a result of receiving damage events.
|
| +}
|
| +
|
| +void RedirectedHostWindowX11::SetVisible(bool visible) {
|
| + if (visible == visible_)
|
| + return;
|
| +
|
| + visible_ = visible;
|
| +}
|
| +
|
| +bool RedirectedHostWindowX11::CanResize() {
|
| + return false;
|
| +}
|
| +
|
| +bool RedirectedHostWindowX11::CanConfigure() {
|
| + return false;
|
| +}
|
| +
|
| +bool RedirectedHostWindowX11::CanActivate() {
|
| + return false;
|
| +}
|
| +
|
| +ManagedRedirectedHostWindowX11::ManagedRedirectedHostWindowX11(
|
| + HostWindowManagerX11* manager, ::Window xwindow, const gfx::Size& size)
|
| + : RedirectedHostWindowX11(manager, xwindow, size) {
|
| +}
|
| +
|
| +ManagedRedirectedHostWindowX11::~ManagedRedirectedHostWindowX11() {
|
| +}
|
| +
|
| +void ManagedRedirectedHostWindowX11::CloseWindow() {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + XEvent xevent;
|
| + xevent.type = ClientMessage;
|
| + xevent.xclient.window = xwindow_;
|
| + xevent.xclient.message_type = wm->atom_cache_.GetAtom("WM_PROTOCOLS");
|
| + xevent.xclient.format = 32;
|
| + xevent.xclient.data.l[0] = wm->atom_cache_.GetAtom("WM_DELETE_WINDOW");
|
| + xevent.xclient.data.l[1] = CurrentTime;
|
| + xevent.xclient.data.l[2] = 0;
|
| + xevent.xclient.data.l[3] = 0;
|
| + xevent.xclient.data.l[4] = 0;
|
| + // Ignore possible X error as we can't guarantee that host window exists.
|
| + xerror_ignore_queue.push(NextRequest(xdisplay_));
|
| + XSendEvent(xdisplay_, xwindow_, false, NoEventMask, &xevent);
|
| +}
|
| +
|
| +bool ManagedRedirectedHostWindowX11::CanResize() {
|
| + // TODO(reveman): Use hints to determine if host window can be resized.
|
| + return true;
|
| +}
|
| +
|
| +void ManagedRedirectedHostWindowX11::OnMapNotify() {
|
| + SetVisible(true);
|
| +}
|
| +
|
| +void ManagedRedirectedHostWindowX11::OnUnmapNotify() {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + client::HostWindowManagerClient* client = wm->client_;
|
| +
|
| + // The client unmapped the window, we should transition to withdrawn state.
|
| + if (state_ == NormalState) {
|
| + if (wm->native_windows_.find(xwindow_) != wm->native_windows_.end())
|
| + client->OnHostWindowVisibilityChanged(
|
| + wm->native_windows_[xwindow_], false);
|
| +
|
| + state_ = WithdrawnState;
|
| + }
|
| +
|
| + SetVisible(false);
|
| +}
|
| +
|
| +void ManagedRedirectedHostWindowX11::OnConfigureNotify(
|
| + gfx::Rect bounds, ::Window above) {
|
| + SetSize(bounds.size());
|
| +}
|
| +
|
| +bool ManagedRedirectedHostWindowX11::CanConfigure() {
|
| + return true;
|
| +}
|
| +
|
| +bool ManagedRedirectedHostWindowX11::CanActivate() {
|
| + return true;
|
| +}
|
| +
|
| +HostWindowManagerX11RootEventObserver::HostWindowManagerX11RootEventObserver(
|
| + HostWindowManagerX11* manager)
|
| + : host_window_manager_(manager),
|
| + xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()) {
|
| +}
|
| +
|
| +bool HostWindowManagerX11RootEventObserver::ProcessHostWindowUpdate(
|
| + const base::NativeEvent& event) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + client::HostWindowManagerClient* client = wm->client_;
|
| +
|
| + ::Window xwindow = 0;
|
| + switch (event->type) {
|
| + case CreateNotify: {
|
| + int border_size = event->xcreatewindow.border_width * 2;
|
| + gfx::Rect bounds(event->xcreatewindow.x,
|
| + event->xcreatewindow.y,
|
| + event->xcreatewindow.width + border_size,
|
| + event->xcreatewindow.height + border_size);
|
| + wm->RegisterNewTopLevel(event->xcreatewindow.window, bounds,
|
| + !event->xcreatewindow.override_redirect);
|
| + xwindow = event->xcreatewindow.window;
|
| + } break;
|
| + case ReparentNotify:
|
| + if (event->xreparent.parent == wm->x_root_window_)
|
| + wm->RegisterNewTopLevel(event->xreparent.window);
|
| + xwindow = event->xreparent.window;
|
| + break;
|
| + case MapNotify:
|
| + xwindow = event->xmap.window;
|
| + break;
|
| + case UnmapNotify:
|
| + xwindow = event->xunmap.window;
|
| + break;
|
| + case DestroyNotify:
|
| + xwindow = event->xdestroywindow.window;
|
| + break;
|
| + case ConfigureNotify:
|
| + xwindow = event->xconfigure.window;
|
| + break;
|
| + default:
|
| + return false;
|
| + }
|
| +
|
| + scoped_refptr<HostWindowX11> top_level = wm->top_level_windows_[xwindow];
|
| +
|
| + DCHECK(top_level);
|
| +
|
| + switch (event->type) {
|
| + case CreateNotify:
|
| + wm->HostWindowNeedsConfigure(client->GetRootWindow());
|
| + break;
|
| + case MapNotify:
|
| + top_level->OnMapNotify();
|
| + break;
|
| + case UnmapNotify:
|
| + top_level->OnUnmapNotify();
|
| + break;
|
| + case ReparentNotify:
|
| + if (event->xreparent.parent == wm->x_root_window_) {
|
| + wm->HostWindowNeedsConfigure(client->GetRootWindow());
|
| + break;
|
| + }
|
| +
|
| + XUngrabButton(xdisplay_, AnyButton, AnyModifier, xwindow);
|
| +
|
| + // TODO(danakj): grab keys on the window so we can use shortcuts
|
| + //XUngrabKey(xdisplay_, AnyKey, AnyModifier, xwindow);
|
| +
|
| + // Fallthrough.
|
| + case DestroyNotify: {
|
| + if (wm->native_windows_.find(xwindow) != wm->native_windows_.end()) {
|
| + Window* window = wm->native_windows_[xwindow];
|
| +
|
| + DCHECK(wm->input_host_windows_.find(window) ==
|
| + wm->input_host_windows_.end());
|
| +
|
| + if (wm->host_windows_.find(window) != wm->host_windows_.end()) {
|
| + // Reset delegate before calling OnHostWindowDestroyed to make sure
|
| + // we're not preventing widget from being closed.
|
| + SetHostWindowDelegate(window, 0);
|
| + client->OnHostWindowDestroyed(window);
|
| + wm->host_windows_.erase(window);
|
| + }
|
| +
|
| + wm->native_windows_.erase(xwindow);
|
| + }
|
| + wm->top_level_windows_.erase(xwindow);
|
| +
|
| + // Window destruction could have caused a previous configure request to
|
| + // fail.
|
| + wm->HostWindowNeedsConfigure(client->GetRootWindow());
|
| + } break;
|
| + case ConfigureNotify: {
|
| + int bw = event->xconfigure.border_width * 2;
|
| + gfx::Rect bounds(event->xconfigure.x,
|
| + event->xconfigure.y,
|
| + event->xconfigure.width + bw,
|
| + event->xconfigure.height + bw);
|
| + top_level->OnConfigureNotify(bounds, event->xconfigure.above);
|
| + } break;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool HostWindowManagerX11RootEventObserver::ProcessHostWindowRequest(
|
| + const base::NativeEvent& event) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + client::HostWindowManagerClient* client = wm->client_;
|
| +
|
| + ::Window xwindow = 0;
|
| + switch (event->type) {
|
| + case MapRequest:
|
| + xwindow = event->xmaprequest.window;
|
| + break;
|
| + case ConfigureRequest:
|
| + xwindow = event->xconfigurerequest.window;
|
| + break;
|
| + case CirculateRequest:
|
| + xwindow = event->xcirculaterequest.window;
|
| + break;
|
| + default:
|
| + return false;
|
| + }
|
| +
|
| + scoped_refptr<HostWindowX11> top_level = wm->top_level_windows_[xwindow];
|
| +
|
| + DCHECK(top_level);
|
| + DCHECK(top_level->CanConfigure());
|
| +
|
| + if (wm->native_windows_.find(xwindow) == wm->native_windows_.end())
|
| + return true;
|
| +
|
| + Window* window = wm->native_windows_[xwindow];
|
| +
|
| + switch (event->type) {
|
| + case MapRequest:
|
| + client->OnHostWindowMovedOrResizedConstrained(
|
| + window, GetTargetBoundsInRootWindow(window));
|
| + client->OnHostWindowVisibilityChanged(window, true);
|
| + break;
|
| + case ConfigureRequest: {
|
| + gfx::Rect bounds(GetTargetBoundsInRootWindow(window));
|
| + if (event->xconfigurerequest.value_mask & CWX)
|
| + bounds.set_x(event->xconfigurerequest.x);
|
| + if (event->xconfigurerequest.value_mask & CWY)
|
| + bounds.set_y(event->xconfigurerequest.y);
|
| + if (event->xconfigurerequest.value_mask & CWWidth)
|
| + bounds.set_width(event->xconfigurerequest.width);
|
| + if (event->xconfigurerequest.value_mask & CWHeight)
|
| + bounds.set_height(event->xconfigurerequest.height);
|
| + client->OnHostWindowMovedOrResizedConstrained(window, bounds);
|
| + // TODO(reveman): Respect stacking properties.
|
| + } break;
|
| + case CirculateRequest:
|
| + // TODO(reveman): Respect stacking properties.
|
| + break;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool HostWindowManagerX11RootEventObserver::Dispatch(
|
| + const base::NativeEvent& event) {
|
| + if (ProcessHostWindowRequest(event))
|
| + return true;
|
| + if (ProcessHostWindowUpdate(event))
|
| + return true;
|
| +
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + client::HostWindowManagerClient* client = wm->client_;
|
| + // Let root window host handle all input events.
|
| + return client->GetRootWindow()->DispatchNativeEvent(event);
|
| +}
|
| +
|
| +void HostWindowManagerX11RootEventObserver::OnWindowFocused(Window* window) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| + client::HostWindowManagerClient* client = wm->client_;
|
| + // We need to configure all windows when changing focus.
|
| + wm->HostWindowNeedsConfigure(client->GetRootWindow());
|
| +}
|
| +
|
| +void HostWindowManagerX11RootEventObserver::OnCursorChanged(
|
| + const RootWindow* root, ui::PlatformCursor cursor) {
|
| + HostWindowManagerX11* wm = host_window_manager_;
|
| +
|
| + // Set cursor for all input windows.
|
| + std::map<gfx::NativeWindow, scoped_refptr<InputHostWindowX11> >::iterator it;
|
| + for (it = wm->input_host_windows_.begin();
|
| + it != wm->input_host_windows_.end(); it++) {
|
| + scoped_refptr<HostWindowX11> input_window = (*it).second;
|
| + XDefineCursor(xdisplay_, input_window->xid(), cursor);
|
| + }
|
| +}
|
| +
|
| +HostWindowManagerX11::HostWindowManagerX11(
|
| + client::HostWindowManagerClient* client)
|
| + : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
|
| + x_root_window_(DefaultRootWindow(xdisplay_)),
|
| + configure_window_(0),
|
| + damage_event_base_(0),
|
| + window_observer_(new HostWindowManagerX11WindowObserver(this)),
|
| + event_observer_(new HostWindowManagerX11RootEventObserver(this)),
|
| + atom_cache_(xdisplay_, kAtomsToCache),
|
| + client_(client) {
|
| + // TODO(reveman): Check that damage extension is present.
|
| + int error_base_ignored;
|
| + XDamageQueryExtension(xdisplay_, &damage_event_base_, &error_base_ignored);
|
| +}
|
| +
|
| +HostWindowManagerX11::~HostWindowManagerX11() {
|
| + XCompositeUnredirectSubwindows(xdisplay_, x_root_window_,
|
| + CompositeRedirectManual);
|
| +
|
| + std::map< ::Window, gfx::NativeWindow>::iterator it;
|
| + for (it = native_windows_.begin(); it != native_windows_.end(); it++) {
|
| + if ((*it).second) {
|
| + Window* window = (*it).second;
|
| + SetHostWindowDelegate(window, 0);
|
| + client_->OnHostWindowDestroyed(window);
|
| + window->RemoveObserver(window_observer_.get());
|
| + }
|
| + }
|
| +
|
| + top_level_windows_.clear();
|
| + native_windows_.clear();
|
| + host_windows_.clear();
|
| + input_host_windows_.clear();
|
| +
|
| + Env::GetInstance()->RemoveObserver(window_observer_.get());
|
| + static_cast<DispatcherLinux*>(
|
| + Env::GetInstance()->GetDispatcher())->
|
| + RemoveDispatcherForRootWindow(event_observer_.get());
|
| + if (client_->GetRootWindow()) {
|
| + client_->GetRootWindow()->RemoveRootWindowObserver(event_observer_.get());
|
| + client_->GetRootWindow()->GetFocusManager()->RemoveObserver(
|
| + event_observer_.get());
|
| + }
|
| +}
|
| +
|
| +::Window HostWindowManagerX11::GetTopHostWindow(Window* window) {
|
| + // children is ordered back to front, so walk through it in reverse.
|
| + const Window::Windows& children = window->children();
|
| + for (size_t i = children.size(); i; --i) {
|
| + ::Window top = GetTopHostWindow(children[i - 1]);
|
| + if (top)
|
| + return top;
|
| + }
|
| +
|
| + if (host_windows_.find(window) != host_windows_.end()) {
|
| + ::Window host_window = host_windows_[window];
|
| + scoped_refptr<HostWindowX11> top_level = top_level_windows_[host_window];
|
| +
|
| + DCHECK(top_level);
|
| + // Ignore windows that we're not allowed to configure.
|
| + if (top_level->CanConfigure())
|
| + return host_window;
|
| + }
|
| +
|
| + if (input_host_windows_.find(window) != input_host_windows_.end())
|
| + return input_host_windows_[window]->xid();
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +::Window HostWindowManagerX11::FindHostWindowToStackAbove(Window* window) {
|
| + Window* parent = window->parent();
|
| + if (!parent)
|
| + return 0;
|
| +
|
| + ::Window above = 0;
|
| +
|
| + const Window::Windows& children = parent->children();
|
| + for (size_t i = 0; i < children.size(); ++i) {
|
| + if (children[i] == window)
|
| + break;
|
| +
|
| + ::Window top = GetTopHostWindow(children[i]);
|
| + if (top)
|
| + above = top;
|
| + }
|
| +
|
| + if (!above)
|
| + above = FindHostWindowToStackAbove(parent);
|
| +
|
| + return above;
|
| +}
|
| +
|
| +void HostWindowManagerX11::CreateHostInputWindowIfNeeded(Window* window) {
|
| + // Ignore root window.
|
| + if (window == window->GetRootWindow())
|
| + return;
|
| +
|
| + // Don't create host input window when there's already host window.
|
| + if (host_windows_.find(window) != host_windows_.end())
|
| + return;
|
| +
|
| + // Avoid windows without delegates.
|
| + if (!window->delegate())
|
| + return;
|
| +
|
| + // Delay creation until window is visible.
|
| + if (!window->IsVisible())
|
| + return;
|
| +
|
| + // Host input window already exists.
|
| + if (input_host_windows_.find(window) != input_host_windows_.end())
|
| + return;
|
| +
|
| + scoped_refptr<InputHostWindowX11> delegate = new InputHostWindowX11(
|
| + XCreateWindow(xdisplay_, x_root_window_, -100, -100, 1, 1,
|
| + 0, CopyFromParent, InputOnly, CopyFromParent, 0, 0));
|
| + SetHostWindowDelegate(window, delegate);
|
| + native_windows_[delegate->xid()] = window;
|
| + input_host_windows_[window] = delegate;
|
| +}
|
| +
|
| +void HostWindowManagerX11::RecursiveConfigureHostWindow(
|
| + Window* window,
|
| + gfx::Point origin,
|
| + ::Window& sibling_to_stack_above,
|
| + ::Window& focus_window,
|
| + bool has_focus) {
|
| + RootWindow* root_window = window->GetRootWindow();
|
| +
|
| + // Lazy creation of input only windows.
|
| + CreateHostInputWindowIfNeeded(window);
|
| +
|
| + // Special case to ensure that root window is stacked properly.
|
| + if (window == root_window) {
|
| + XWindowChanges wc;
|
| + unsigned mask = InitWindowChanges(gfx::Rect(), sibling_to_stack_above, wc);
|
| + ::Window root_host_window =
|
| + root_window->GetAcceleratedWidgetUsedForEvents();
|
| + DCHECK(window->IsVisible());
|
| + XConfigureWindow(xdisplay_, root_host_window,
|
| + mask & (CWSibling | CWStackMode),
|
| + &wc);
|
| +
|
| + sibling_to_stack_above = root_host_window;
|
| + }
|
| +
|
| + // We never move focus to our internal input host windows.
|
| + if (input_host_windows_.find(window) != input_host_windows_.end()) {
|
| + scoped_refptr<HostWindowX11> input_window = input_host_windows_[window];
|
| + gfx::Rect host_bounds(origin, window->GetTargetBounds().size());
|
| + host_bounds.Inset(window->hit_test_bounds_override_outer());
|
| + gfx::Rect non_empty_bounds(
|
| + host_bounds.Union(gfx::Rect(host_bounds.origin(), gfx::Size(1, 1))));
|
| +
|
| + if (!window->IsVisible()) {
|
| + if (input_window->state() == NormalState) {
|
| + XUnmapWindow(xdisplay_, input_window->xid());
|
| + input_window->set_state(IconicState);
|
| + }
|
| + }
|
| +
|
| + XWindowChanges wc;
|
| + unsigned mask = InitWindowChanges(
|
| + non_empty_bounds, sibling_to_stack_above, wc);
|
| + // Ignore possible X error as we can't guarantee that host window exists.
|
| + if (mask & CWSibling)
|
| + xerror_ignore_queue.push(NextRequest(xdisplay_));
|
| + XConfigureWindow(xdisplay_, input_window->xid(), mask, &wc);
|
| +
|
| + sibling_to_stack_above = input_window->xid();
|
| +
|
| + if (window->IsVisible()) {
|
| + if (input_window->state() != NormalState) {
|
| + XMapWindow(xdisplay_, input_window->xid());
|
| + input_window->set_state(NormalState);
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (host_windows_.find(window) != host_windows_.end()) {
|
| + ::Window host_window = host_windows_[window];
|
| + scoped_refptr<HostWindowX11> top_level = top_level_windows_[host_window];
|
| +
|
| + DCHECK(top_level);
|
| + if (top_level->CanConfigure()) {
|
| + gfx::Rect host_bounds(origin, window->GetTargetBounds().size());
|
| + gfx::Rect non_empty_bounds(
|
| + host_bounds.Union(gfx::Rect(host_bounds.origin(), gfx::Size(1, 1))));
|
| +
|
| + if (!window->IsVisible()) {
|
| + if (top_level->state() == NormalState) {
|
| + // Ignore possible X error as we can't guarantee that host window
|
| + // exists.
|
| + xerror_ignore_queue.push(NextRequest(xdisplay_));
|
| + XUnmapWindow(xdisplay_, host_window);
|
| +
|
| + top_level->set_state(IconicState);
|
| + }
|
| + }
|
| +
|
| + XWindowChanges wc;
|
| + unsigned mask = InitWindowChanges(
|
| + non_empty_bounds, sibling_to_stack_above, wc);
|
| + // Get rid of any borders.
|
| + wc.border_width = 0;
|
| + mask |= CWBorderWidth;
|
| + // Ignore possible X error as we can't guarantee that host window exists.
|
| + xerror_ignore_queue.push(NextRequest(xdisplay_));
|
| + XConfigureWindow(xdisplay_, host_window, mask, &wc);
|
| +
|
| + sibling_to_stack_above = host_window;
|
| +
|
| + if (window->IsVisible()) {
|
| + if (top_level->state() != NormalState) {
|
| + // Ignore possible X error as we can't guarantee that host window
|
| + // exists.
|
| + xerror_ignore_queue.push(NextRequest(xdisplay_));
|
| + XMapWindow(xdisplay_, host_window);
|
| +
|
| + // Grab buttons so that window can be activated when a click is
|
| + // received in the client area.
|
| + xerror_ignore_queue.push(NextRequest(xdisplay_));
|
| + XGrabButton(xdisplay_, AnyButton, AnyModifier, host_window, false,
|
| + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
|
| + GrabModeSync, GrabModeAsync, 0, 0);
|
| +
|
| + // TODO(danakj): grab keys on the window so we can use shortcuts
|
| + //XGrabKey(xdisplay_, AnyKey, AnyModifier, event->xmaprequest.window,
|
| + // true, GrabModeAsync, GrabModeSync);
|
| +
|
| + top_level->set_state(NormalState);
|
| + }
|
| +
|
| + // Set |focus_window| to host window if aura sub-tree has focus.
|
| + if (has_focus)
|
| + focus_window = host_window;
|
| + }
|
| + }
|
| + }
|
| +
|
| + const Window::Windows& children = window->children();
|
| + for (size_t i = 0; i < children.size(); ++i)
|
| + RecursiveConfigureHostWindow(
|
| + children[i],
|
| + origin.Add(children[i]->GetTargetBounds().origin()),
|
| + sibling_to_stack_above,
|
| + focus_window,
|
| + has_focus || window->HasFocus());
|
| +}
|
| +
|
| +void HostWindowManagerX11::ConfigureHostWindows() {
|
| + if (!configure_window_)
|
| + return;
|
| +
|
| + ::Window focus_window = 0;
|
| + ::Window sibling_to_stack_above =
|
| + FindHostWindowToStackAbove(configure_window_);
|
| + RecursiveConfigureHostWindow(
|
| + configure_window_,
|
| + GetTargetOriginInRootWindow(configure_window_),
|
| + sibling_to_stack_above,
|
| + focus_window,
|
| + configure_window_->HasFocus());
|
| +
|
| + // Only set focus when we configure the root window.
|
| + if (configure_window_ == client_->GetRootWindow()) {
|
| + if (focus_window) {
|
| + // Ignore possible X error as we can't guarantee that host window exists.
|
| + xerror_ignore_queue.push(NextRequest(xdisplay_));
|
| + XSetInputFocus(xdisplay_, focus_window, 0, CurrentTime);
|
| + } else
|
| + XSetInputFocus(
|
| + xdisplay_,
|
| + client_->GetRootWindow()->GetAcceleratedWidgetUsedForEvents(),
|
| + 0, CurrentTime);
|
| + }
|
| +
|
| + configure_window_ = 0;
|
| +}
|
| +
|
| +void HostWindowManagerX11::HostWindowNeedsConfigure(Window* window) {
|
| + DCHECK(window->GetRootWindow() == client_->GetRootWindow());
|
| + if (!configure_window_) {
|
| + configure_window_ = window;
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&HostWindowManagerX11::ConfigureHostWindows, AsWeakPtr()));
|
| + } else {
|
| + configure_window_ = FindLowestCommonAncestor(
|
| + window->GetRootWindow(), configure_window_, window);
|
| + }
|
| +}
|
| +
|
| +void HostWindowManagerX11::Init() {
|
| + Env::GetInstance()->AddObserver(window_observer_.get());
|
| + static_cast<DispatcherLinux*>(
|
| + Env::GetInstance()->GetDispatcher())->
|
| + AddDispatcherForRootWindow(event_observer_.get());
|
| +
|
| + // TODO(danakj): When env manages root windows, get it from there, and watch
|
| + // for monitor changes.
|
| + client_->GetRootWindow()->AddRootWindowObserver(event_observer_.get());
|
| + client_->GetRootWindow()->GetFocusManager()->AddObserver(
|
| + event_observer_.get());
|
| +
|
| + if (client_->GetRootWindow()->GetAcceleratedWidget() ==
|
| + client_->GetRootWindow()->GetAcceleratedWidgetUsedForEvents())
|
| + LOG(FATAL) << "Overlay window must be used as output. Try using "
|
| + "--aura-host-window-use-fullscreen.";
|
| +
|
| + int root_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
|
| + EnterWindowMask | LeaveWindowMask | SubstructureRedirectMask |
|
| + SubstructureNotifyMask;
|
| +
|
| + XGrabServer(xdisplay_);
|
| +
|
| + ::Window root, parent, *children = 0;
|
| + unsigned int nchildren;
|
| + XQueryTree(xdisplay_, x_root_window_, &root, &parent, &children, &nchildren);
|
| + scoped_ptr_malloc< ::Window, ScopedPtrXFree> xwindows(children);
|
| +
|
| + XErrorHandler error_handler = XSetErrorHandler(ExistingWMX11ErrorHandler);
|
| + XWindowAttributes attr;
|
| + XGetWindowAttributes(xdisplay_, x_root_window_, &attr);
|
| + XSelectInput(xdisplay_, x_root_window_, attr.your_event_mask | root_mask);
|
| + // Redirect top-level windows to offscreen buffers.
|
| + XCompositeRedirectSubwindows(xdisplay_, x_root_window_,
|
| + CompositeRedirectManual);
|
| + XSync(xdisplay_, 0);
|
| + XSetErrorHandler(error_handler);
|
| +
|
| + // Install filtered error handler.
|
| + SetBaseX11ErrorHandler(XSetErrorHandler(FilteredX11ErrorHandler));
|
| +
|
| + XUngrabServer(xdisplay_);
|
| +
|
| + // Set root window cursor. Host windows that don't define their own cursor
|
| + // will inherit the default cursor defined here.
|
| + XDefineCursor(xdisplay_, x_root_window_, ui::GetXCursor(XC_left_ptr));
|
| +
|
| + for (size_t i = 0; i < nchildren; ++i)
|
| + RegisterNewTopLevel(xwindows.get()[i]);
|
| +
|
| + HostWindowNeedsConfigure(client_->GetRootWindow());
|
| +}
|
| +
|
| +void HostWindowManagerX11::RegisterNewTopLevel(::Window xwindow) {
|
| + gfx::Rect bounds(gfx::Point(-100, -100), gfx::Size(1, 1));
|
| + bool visible = false;
|
| + bool managed = false;
|
| +
|
| + XWindowAttributes attributes;
|
| + // Ignore possible X error as we can't guarantee that host window exists.
|
| + xerror_ignore_queue.push(NextRequest(xdisplay_));
|
| + if (XGetWindowAttributes(xdisplay_, xwindow, &attributes)) {
|
| + int border_size = attributes.border_width * 2;
|
| + bounds = gfx::Rect(attributes.x,
|
| + attributes.y,
|
| + attributes.width + border_size,
|
| + attributes.height + border_size);
|
| + visible = attributes.map_state == IsViewable;
|
| + managed = !attributes.override_redirect;
|
| + }
|
| +
|
| + RegisterNewTopLevel(xwindow, bounds, managed);
|
| +
|
| + if (visible) {
|
| + Window* window = native_windows_[xwindow];
|
| + DCHECK(window);
|
| + client_->OnHostWindowMovedOrResizedConstrained(
|
| + window, GetTargetBoundsInRootWindow(window));
|
| + client_->OnHostWindowVisibilityChanged(window, true);
|
| + }
|
| +}
|
| +
|
| +void HostWindowManagerX11::RegisterNewTopLevel(
|
| + ::Window xwindow, const gfx::Rect bounds, bool managed) {
|
| + client::HostWindowManagerClient* client = client_;
|
| +
|
| + // Add a HostWindowX11 for the root input window.
|
| + RootWindow* root_window = client->GetRootWindow();
|
| + if (xwindow == root_window->GetAcceleratedWidgetUsedForEvents()) {
|
| + top_level_windows_[xwindow] = new HostWindowX11(xwindow, NormalState);
|
| + return;
|
| + }
|
| +
|
| + // Container input windows will already have a native mapping.
|
| + if (native_windows_.find(xwindow) != native_windows_.end()) {
|
| + Window* window = native_windows_[xwindow];
|
| +
|
| + if (input_host_windows_.find(window) != input_host_windows_.end()) {
|
| + top_level_windows_[xwindow] = input_host_windows_[window];
|
| + return;
|
| + }
|
| + }
|
| +
|
| + // This is foreign host window.
|
| + scoped_refptr<HostWindowX11> top_level;
|
| + bool decorated = false;
|
| +
|
| + if (managed) {
|
| + top_level = new ManagedRedirectedHostWindowX11(
|
| + this, xwindow, bounds.size());
|
| + decorated = true;
|
| + } else {
|
| + top_level = new RedirectedHostWindowX11(this, xwindow, bounds.size());
|
| + }
|
| +
|
| + // Create a native window.
|
| + Window* window = client->OnHostWindowCreated(bounds, decorated);
|
| + SetHostWindowDelegate(window, top_level);
|
| + top_level_windows_[xwindow] = top_level;
|
| +
|
| + native_windows_[xwindow] = window;
|
| + host_windows_[window] = xwindow;
|
| +}
|
| +
|
| +} // namespace aura
|
|
|