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); |
+} |
+ |
} // 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 |