Chromium Code Reviews| Index: wm/host/root_window_host_linux.cc |
| diff --git a/ui/aura/root_window_host_linux.cc b/wm/host/root_window_host_linux.cc |
| similarity index 71% |
| copy from ui/aura/root_window_host_linux.cc |
| copy to wm/host/root_window_host_linux.cc |
| index ab08c4fccdd5f4593debcc8f8dd926550c88a256..91c44eca24f33887496a1936378880739d143ca9 100644 |
| --- a/ui/aura/root_window_host_linux.cc |
| +++ b/wm/host/root_window_host_linux.cc |
| @@ -1,17 +1,19 @@ |
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Copyright (c) 2013 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/root_window_host_linux.h" |
| +#include "wm/host/root_window_host_linux.h" |
| -#include <strings.h> |
| -#include <X11/cursorfont.h> |
| -#include <X11/extensions/Xfixes.h> |
| -#include <X11/extensions/XInput2.h> |
| -#include <X11/extensions/Xrandr.h> |
| #include <X11/Xatom.h> |
| #include <X11/Xcursor/Xcursor.h> |
| #include <X11/Xlib.h> |
| +#include <X11/cursorfont.h> |
| +#include <X11/extensions/XInput2.h> |
| +#include <X11/extensions/Xcomposite.h> |
| +#include <X11/extensions/Xfixes.h> |
| +#include <X11/extensions/Xrandr.h> |
| +#include <X11/extensions/shape.h> |
| +#include <strings.h> |
| #include <algorithm> |
| #include <limits> |
| @@ -45,6 +47,8 @@ |
| #include "ui/compositor/layer.h" |
| #include "ui/gfx/codec/png_codec.h" |
| #include "ui/gfx/screen.h" |
| +#include "wm/foreign_window.h" |
| +#include "wm/foreign_window_widget.h" |
| #if defined(OS_CHROMEOS) |
| #include "base/chromeos/chromeos_version.h" |
| @@ -53,7 +57,7 @@ |
| using std::max; |
| using std::min; |
| -namespace aura { |
| +namespace wm { |
| namespace { |
| @@ -169,6 +173,61 @@ bool ShouldSendCharEventForKeyboardCode(ui::KeyboardCode keycode) { |
| } |
| } |
| +unsigned InitWindowChanges(const gfx::Rect& bounds, |
| + ::Window sibling_to_stack_above, |
| + XWindowChanges& wc) { |
| + wc.x = bounds.x(); |
| + wc.y = bounds.y(); |
| + wc.width = bounds.width(); |
| + wc.height = bounds.height(); |
| + if (!sibling_to_stack_above) { |
| + wc.stack_mode = Below; |
| + return CWX | CWY | CWWidth | CWHeight | CWStackMode; |
| + } |
| + |
| + wc.sibling = sibling_to_stack_above; |
| + wc.stack_mode = Above; |
| + return CWX | CWY | CWWidth | CWHeight | CWStackMode | CWSibling; |
| +} |
| + |
| +aura::Window* FindLowestCommonAncestor( |
| + aura::Window* root, const aura::Window* p, const 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::Vector2d GetTargetOffsetInRootWindow(const aura::Window* window) { |
| + gfx::Vector2d offset; |
| + |
| + const aura::Window* p = window; |
| + for (; p != window->GetRootWindow(); p = p->parent()) |
| + offset += p->GetTargetBounds().OffsetFromOrigin(); |
| + |
| + return offset; |
| +} |
| + |
| +gfx::Rect GetTargetBoundsInRootWindow(const aura::Window* window) { |
| + return gfx::Rect(window->GetTargetBounds().size()) + |
| + GetTargetOffsetInRootWindow(window); |
|
danakj
2013/02/22 21:42:59
Yep looks good!
|
| +} |
| + |
| } // namespace |
| namespace internal { |
| @@ -266,7 +325,10 @@ RootWindowHostLinux::RootWindowHostLinux(const gfx::Rect& bounds) |
| focus_when_shown_(false), |
| touch_calibrate_(new internal::TouchEventCalibrate), |
| mouse_move_filter_(new MouseMoveFilter), |
| - atom_cache_(xdisplay_, kAtomsToCache) { |
| + atom_cache_(xdisplay_, kAtomsToCache), |
| + configure_window_(NULL), |
| + x_input_window_(0), |
| + need_to_set_default_cursor_(true) { |
| XSetWindowAttributes swa; |
| memset(&swa, 0, sizeof(swa)); |
| swa.background_pixmap = None; |
| @@ -279,6 +341,18 @@ RootWindowHostLinux::RootWindowHostLinux(const gfx::Rect& bounds) |
| CopyFromParent, // visual |
| CWBackPixmap, |
| &swa); |
| + x_input_window_ = XCreateWindow( |
| + xdisplay_, xwindow_, |
| + -100, -100, 1, 1, |
| + 0, // border width |
| + CopyFromParent, // depth |
| + InputOnly, |
| + CopyFromParent, // visual |
| + 0, |
| + NULL); |
| + XMapWindow(xdisplay_, x_input_window_); |
| + XCompositeRedirectSubwindows(xdisplay_, xwindow_, CompositeRedirectManual); |
| + |
| base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_); |
| base::MessagePumpAuraX11::Current()->AddDispatcherForRootWindow(this); |
| @@ -287,7 +361,8 @@ RootWindowHostLinux::RootWindowHostLinux(const gfx::Rect& bounds) |
| EnterWindowMask | LeaveWindowMask | |
| ExposureMask | VisibilityChangeMask | |
| StructureNotifyMask | PropertyChangeMask | |
| - PointerMotionMask; |
| + PointerMotionMask | |
| + SubstructureNotifyMask | SubstructureRedirectMask; |
| XSelectInput(xdisplay_, xwindow_, event_mask); |
| XFlush(xdisplay_); |
| @@ -340,6 +415,8 @@ RootWindowHostLinux::~RootWindowHostLinux() { |
| UnConfineCursor(); |
| + GetRootWindow()->RemoveObserver(this); |
| + XDestroyWindow(xdisplay_, x_input_window_); |
| XDestroyWindow(xdisplay_, xwindow_); |
| } |
| @@ -350,6 +427,105 @@ bool RootWindowHostLinux::Dispatch(const base::NativeEvent& event) { |
| return DispatchEventForRootWindow(event); |
| switch (xev->type) { |
| + case ConfigureNotify: { |
| + if (event->xconfigure.window == x_input_window_) |
| + return true; |
| + |
| + ForeignWindowMap::iterator it = foreign_windows_.find( |
| + event->xconfigure.window); |
| + if (it != foreign_windows_.end()) { |
| + ForeignWindow* window = it->second; |
| + |
| + int border_size = event->xconfigure.border_width * 2; |
| + gfx::Size size(event->xconfigure.width + border_size, |
| + event->xconfigure.height + border_size); |
| + window->OnWindowSizeChanged(size); |
| + return true; |
| + } |
| + break; |
| + } |
| + case MapNotify: { |
| + ForeignWindowMap::iterator it = foreign_windows_.find( |
| + event->xmap.window); |
| + if (it != foreign_windows_.end()) { |
| + ForeignWindow* window = it->second; |
| + |
| + window->OnWindowVisibilityChanged(true); |
| + return true; |
| + } |
| + break; |
| + } |
| + case UnmapNotify: { |
| + ForeignWindowMap::iterator it = foreign_windows_.find( |
| + event->xunmap.window); |
| + if (it != foreign_windows_.end()) { |
| + ForeignWindow* window = it->second; |
| + |
| + // Hide top level widget. |
| + views::Widget* widget = window->GetWidget(); |
| + widget->Hide(); |
| + |
| + window->OnWindowVisibilityChanged(false); |
| + return true; |
| + } |
| + break; |
| + } |
| + case CreateNotify: { |
| + int border_size = event->xcreatewindow.border_width * 2; |
| + gfx::Size size(event->xcreatewindow.width + border_size, |
| + event->xcreatewindow.height + border_size); |
| + |
| + // Create a foreign window for this X window. |
| + ForeignWindow::CreateParams params(event->xcreatewindow.window, size); |
| + scoped_refptr<ForeignWindow> window(new ForeignWindow(params)); |
| + |
| + // Create top level window widget. |
| + ForeignWindowWidget::CreateWindow(window.get()); |
| + |
| + // Add foreign window to map. |
| + foreign_windows_[event->xcreatewindow.window] = window.get(); |
| + return true; |
| + } |
| + case DestroyNotify: { |
| + ForeignWindowMap::iterator it = foreign_windows_.find( |
| + event->xdestroywindow.window); |
| + if (it != foreign_windows_.end()) { |
| + ForeignWindow* window = it->second; |
| + |
| + // Tell foreign window that X window has been destroyed. |
| + window->OnWindowDestroyed(); |
| + |
| + // Close top level widget. |
| + views::Widget* widget = window->GetWidget(); |
| + widget->Close(); |
| + |
| + foreign_windows_.erase(it); |
| + } |
| + return true; |
| + } |
| + case MapRequest: { |
| + ForeignWindowMap::iterator it = foreign_windows_.find( |
| + event->xmaprequest.window); |
| + if (it != foreign_windows_.end()) { |
| + ForeignWindow* window = it->second; |
| + |
| + // Show top level widget. |
| + views::Widget* widget = window->GetWidget(); |
| + widget->Show(); |
| + } |
| + return true; |
| + } |
| + case ConfigureRequest: { |
| + // TODO(reveman): Respect ConfigureRequest events. |
| + return true; |
| + } |
| + case CirculateRequest: { |
| + // TODO(reveman): Respect CirculateRequest events. |
| + return true; |
| + } |
| + } |
| + |
| + switch (xev->type) { |
| case EnterNotify: { |
| ui::MouseEvent mouseenter_event(xev); |
| TranslateAndDispatchMouseEvent(&mouseenter_event); |
| @@ -371,13 +547,13 @@ bool RootWindowHostLinux::Dispatch(const base::NativeEvent& event) { |
| case ButtonPress: { |
| if (static_cast<int>(xev->xbutton.button) == kBackMouseButton || |
| static_cast<int>(xev->xbutton.button) == kForwardMouseButton) { |
| - client::UserActionClient* gesture_client = |
| - client::GetUserActionClient(delegate_->AsRootWindow()); |
| + aura::client::UserActionClient* gesture_client = |
| + aura::client::GetUserActionClient(delegate_->AsRootWindow()); |
| if (gesture_client) { |
| gesture_client->OnUserAction( |
| static_cast<int>(xev->xbutton.button) == kBackMouseButton ? |
| - client::UserActionClient::BACK : |
| - client::UserActionClient::FORWARD); |
| + aura::client::UserActionClient::BACK : |
| + aura::client::UserActionClient::FORWARD); |
| } |
| break; |
| } |
| @@ -483,11 +659,235 @@ bool RootWindowHostLinux::Dispatch(const base::NativeEvent& event) { |
| return true; |
| } |
| -void RootWindowHostLinux::SetDelegate(RootWindowHostDelegate* delegate) { |
| +void RootWindowHostLinux::OnWindowAdded(aura::Window* window) { |
| + window->AddObserver(this); |
| +} |
| + |
| +void RootWindowHostLinux::OnWillRemoveWindow(aura::Window* window) { |
| + if (configure_window_ == window) |
| + configure_window_ = window->parent(); |
| + |
| + window->RemoveObserver(this); |
| +} |
| + |
| +void RootWindowHostLinux::OnWindowStackingChanged(aura::Window* window) { |
| + ScheduleConfigure(GetRootWindow()); |
| +} |
| + |
| +void RootWindowHostLinux::OnWindowVisibilityChanged( |
| + aura::Window* window, bool visible) { |
| + ScheduleConfigure(GetRootWindow()); |
| +} |
| + |
| +void RootWindowHostLinux::OnWindowBoundsChanged( |
| + aura::Window* window, |
| + const gfx::Rect& old_bounds, |
| + const gfx::Rect& new_bounds) { |
| + ScheduleConfigure(GetRootWindow()); |
| +} |
| + |
| +void RootWindowHostLinux::OnWindowDestroying(aura::Window* window) { |
| + window->RemoveObserver(this); |
| +} |
| + |
| +::Window RootWindowHostLinux::GetTopForeignWindow(const aura::Window* window) { |
| + // children are ordered back to front, so walk through it in reverse. |
| + const aura::Window::Windows& children = window->children(); |
| + for (size_t i = children.size(); i; --i) { |
| + ::Window top = GetTopForeignWindow(children[i - 1]); |
| + if (top) |
| + return top; |
| + } |
| + |
| + ForeignWindow* foreign_window = ForeignWindow::GetForeignWindowForNativeView( |
| + const_cast<gfx::NativeView>(window)); |
| + if (foreign_window) { |
| + // Ignore windows that we're not allowed to configure. |
| + if (foreign_window->IsManaged()) |
| + return foreign_window->GetWindowHandle(); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +::Window RootWindowHostLinux::FindForeignWindowToStackAbove( |
| + const aura::Window* window) { |
| + const aura::Window* parent = window->parent(); |
| + if (!parent) |
| + return 0; |
| + |
| + ::Window above = 0; |
| + |
| + const aura::Window::Windows& children = parent->children(); |
| + for (size_t i = 0; i < children.size(); ++i) { |
| + if (children[i] == window) |
| + break; |
| + |
| + ::Window top = GetTopForeignWindow(children[i]); |
| + if (top) |
| + above = top; |
| + } |
| + |
| + if (!above) |
| + above = FindForeignWindowToStackAbove(parent); |
| + |
| + return above; |
| +} |
| + |
| +void RootWindowHostLinux::MapWindowIfNeeded(ForeignWindow* window) { |
| + ForeignWindow::DisplayState current_display_state = |
| + window->GetDisplayState(); |
| + |
| + if (current_display_state != ForeignWindow::DISPLAY_NORMAL) { |
| + // TODO(reveman): Ignore possible X error. |
| + XMapWindow(xdisplay_, window->GetWindowHandle()); |
| + |
| + window->SetDisplayState(ForeignWindow::DISPLAY_NORMAL); |
| + } |
| +} |
| + |
| +void RootWindowHostLinux::UnmapWindowIfNeeded(ForeignWindow* window) { |
| + ForeignWindow::DisplayState current_display_state = |
| + window->GetDisplayState(); |
| + |
| + if (current_display_state == ForeignWindow::DISPLAY_NORMAL) { |
| + // TODO(reveman): Ignore possible X error. |
| + XUnmapWindow(xdisplay_, window->GetWindowHandle()); |
| + |
| + window->SetDisplayState(ForeignWindow::DISPLAY_ICONIC); |
| + } |
| +} |
| + |
| +void RootWindowHostLinux::RecursiveConfigure( |
| + aura::Window* window, |
| + gfx::Vector2d offset, |
| + ::Window* sibling_to_stack_above, |
| + SkRegion* input_region) { |
| + gfx::Rect bounds(gfx::Rect(window->GetTargetBounds().size()) + offset); |
| + SkRegion::Op input_region_op; |
| + |
| + ForeignWindow* foreign_window = ForeignWindow::GetForeignWindowForNativeView( |
| + const_cast<gfx::NativeView>(window)); |
| + if (foreign_window) { |
| + DCHECK(!bounds.IsEmpty()); |
| + |
| + // We should only be adjusting attributes of managed windows. |
| + if (foreign_window->IsManaged()) { |
| + if (!window->IsVisible()) |
| + UnmapWindowIfNeeded(foreign_window); |
| + |
| + XWindowChanges wc; |
| + unsigned mask = InitWindowChanges(bounds, *sibling_to_stack_above, wc); |
| + // Get rid of any borders. |
| + wc.border_width = 0; |
| + mask |= CWBorderWidth; |
| + // TODO(reveman): Ignore possible X error. |
| + XConfigureWindow(xdisplay_, |
| + foreign_window->GetWindowHandle(), |
| + mask, |
| + &wc); |
| + |
| + *sibling_to_stack_above = foreign_window->GetWindowHandle(); |
| + |
| + if (window->IsVisible()) |
| + MapWindowIfNeeded(foreign_window); |
| + } |
| + |
| + // Remove foreign window bounds from input region. |
| + bounds.Inset(window->hit_test_bounds_override_inner()); |
| + input_region_op = SkRegion::kDifference_Op; |
| + } else { |
| + // Add window bounds to output region. |
| + bounds.Inset(window->hit_test_bounds_override_outer_mouse()); |
| + input_region_op = SkRegion::kUnion_Op; |
| + } |
| + |
| + if (window->delegate() && window->IsVisible()) { |
| + input_region->op(bounds.x(), |
| + bounds.y(), |
| + bounds.right(), |
| + bounds.bottom(), |
| + input_region_op); |
| + } |
| + |
| + const aura::Window::Windows& children = window->children(); |
| + for (size_t i = 0; i < children.size(); ++i) { |
| + RecursiveConfigure( |
| + children[i], |
| + offset + children[i]->GetTargetBounds().OffsetFromOrigin(), |
| + sibling_to_stack_above, |
| + input_region); |
| + } |
| +} |
| + |
| +void RootWindowHostLinux::Configure() { |
| + if (!configure_window_) |
| + return; |
| + |
| + SkRegion input_region; |
| + ::Window sibling_to_stack_above = |
| + FindForeignWindowToStackAbove(configure_window_); |
| + RecursiveConfigure(configure_window_, |
| + GetTargetOffsetInRootWindow(configure_window_), |
| + &sibling_to_stack_above, |
| + &input_region); |
| + |
| + // Update input window and set focus when we configure the root window. |
| + if (configure_window_ == GetRootWindow()) { |
| + // Configure input window above all other windows. |
| + XWindowChanges wc; |
| + gfx::Rect bounds(gfx::Point(0, 0), bounds_.size()); |
| + unsigned mask = InitWindowChanges(bounds, sibling_to_stack_above, wc); |
| + XConfigureWindow(xdisplay_, x_input_window_, mask, &wc); |
| + |
| + // Update input window shape. |
| + std::vector<XRectangle> rectangles; |
| + for (SkRegion::Iterator iter(input_region); !iter.done(); iter.next()) { |
| + const SkIRect& sk_rect = iter.rect(); |
| + XRectangle x_rect; |
| + x_rect.x = sk_rect.x(); |
| + x_rect.y = sk_rect.y(); |
| + x_rect.width = sk_rect.width(); |
| + x_rect.height = sk_rect.height(); |
| + rectangles.push_back(x_rect); |
| + } |
| + |
| + XShapeCombineRectangles(xdisplay_, |
| + x_input_window_, |
| + ShapeInput, |
| + 0, |
| + 0, |
| + &rectangles.front(), |
| + rectangles.size(), |
| + ShapeSet, |
| + Unsorted); |
| + } |
| + |
| + XFlush(xdisplay_); |
| + configure_window_ = NULL; |
| +} |
| + |
| +void RootWindowHostLinux::ScheduleConfigure(aura::Window* window) { |
| + if (!configure_window_) { |
| + configure_window_ = window; |
| + MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&RootWindowHostLinux::Configure, AsWeakPtr())); |
| + } else { |
| + configure_window_ = FindLowestCommonAncestor( |
| + GetRootWindow(), configure_window_, window); |
| + } |
| +} |
| + |
| +void RootWindowHostLinux::SetDelegate(aura::RootWindowHostDelegate* delegate) { |
| + DCHECK(!delegate_); |
| delegate_ = delegate; |
| + DCHECK(delegate_); |
| + delegate_->AsRootWindow()->AddObserver(this); |
| + ScheduleConfigure(delegate_->AsRootWindow()); |
| } |
| -RootWindow* RootWindowHostLinux::GetRootWindow() { |
| +aura::RootWindow* RootWindowHostLinux::GetRootWindow() { |
| return delegate_->AsRootWindow(); |
| } |
| @@ -594,8 +994,8 @@ void RootWindowHostLinux::SetCursor(gfx::NativeCursor cursor) { |
| } |
| bool RootWindowHostLinux::QueryMouseLocation(gfx::Point* location_return) { |
| - client::CursorClient* cursor_client = |
| - client::GetCursorClient(GetRootWindow()); |
| + aura::client::CursorClient* cursor_client = |
| + aura::client::GetCursorClient(GetRootWindow()); |
| if (cursor_client && !cursor_client->IsMouseEventsEnabled()) { |
| *location_return = gfx::Point(0, 0); |
| return false; |
| @@ -917,16 +1317,16 @@ void RootWindowHostLinux::DispatchXI2Event(const base::NativeEvent& event) { |
| if (button == kBackMouseButton || button == kForwardMouseButton) { |
| if (type == ui::ET_MOUSE_RELEASED) |
| break; |
| - client::UserActionClient* gesture_client = |
| - client::GetUserActionClient(delegate_->AsRootWindow()); |
| + aura::client::UserActionClient* gesture_client = |
| + aura::client::GetUserActionClient(delegate_->AsRootWindow()); |
| if (gesture_client) { |
| bool reverse_direction = |
| ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled(); |
| gesture_client->OnUserAction( |
| (button == kBackMouseButton && !reverse_direction) || |
| (button == kForwardMouseButton && reverse_direction) ? |
| - client::UserActionClient::BACK : |
| - client::UserActionClient::FORWARD); |
| + aura::client::UserActionClient::BACK : |
| + aura::client::UserActionClient::FORWARD); |
| } |
| break; |
| } |
| @@ -966,13 +1366,19 @@ bool RootWindowHostLinux::IsWindowManagerPresent() { |
| } |
| void RootWindowHostLinux::SetCursorInternal(gfx::NativeCursor cursor) { |
| - XDefineCursor(xdisplay_, xwindow_, cursor.platform()); |
| + XDefineCursor(xdisplay_, x_input_window_, cursor.platform()); |
| + |
| + // Set default native window cursor. |
| + if (need_to_set_default_cursor_ && cursor.native_type() == ui::kCursorNull) { |
| + XDefineCursor(xdisplay_, xwindow_, cursor.platform()); |
| + need_to_set_default_cursor_ = false; |
| + } |
| } |
| void RootWindowHostLinux::TranslateAndDispatchMouseEvent( |
| ui::MouseEvent* event) { |
| - RootWindow* root = GetRootWindow(); |
| - client::ScreenPositionClient* screen_position_client = |
| + aura::RootWindow* root = GetRootWindow(); |
| + aura::client::ScreenPositionClient* screen_position_client = |
| GetScreenPositionClient(root); |
| if (screen_position_client && !bounds_.Contains(event->location())) { |
| gfx::Point location(event->location()); |
| @@ -1001,15 +1407,4 @@ scoped_ptr<ui::XScopedImage> RootWindowHostLinux::GetXImage( |
| return image.Pass(); |
| } |
| -// static |
| -RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) { |
| - return new RootWindowHostLinux(bounds); |
| -} |
| - |
| -// static |
| -gfx::Size RootWindowHost::GetNativeScreenSize() { |
| - ::Display* xdisplay = base::MessagePumpAuraX11::GetDefaultXDisplay(); |
| - return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0)); |
| -} |
| - |
| -} // namespace aura |
| +} // namespace wm |