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

Unified Diff: wm/host/root_window_host_linux.cc

Issue 11485006: Add window manager component. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Push gfx::AcceleratedWidget usage into platform specific code. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « wm/host/root_window_host_linux.h ('k') | wm/shell/content_client/DEPS » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « wm/host/root_window_host_linux.h ('k') | wm/shell/content_client/DEPS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698