1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <vector>
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <X11/extensions/shape.h>
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <X11/Xlib.h>
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Get rid of X11 macros which conflict with gtest.
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#undef Bool
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#undef None
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/aura/window.h"
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/aura/window_tree_host.h"
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/base/hit_test.h"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/base/x/x11_util.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/events/platform/x11/x11_event_source.h"
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/path.h"
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/point.h"
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/rect.h"
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/x/x11_atom_cache.h"
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/views/test/views_test_base.h"
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/views/test/x11_property_change_waiter.h"
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/views/widget/widget_delegate.h"
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/views/window/non_client_view.h"
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace views {
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace {
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Blocks till the window state hint, |hint|, is set or unset.
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class WMStateWaiter : public X11PropertyChangeWaiter {
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public:
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  WMStateWaiter(XID window,
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                const char* hint,
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                bool wait_till_set)
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      : X11PropertyChangeWaiter(window, "_NET_WM_STATE"),
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        hint_(hint),
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        wait_till_set_(wait_till_set) {
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const char* kAtomsToCache[] = {
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        hint,
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        NULL
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    };
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    atom_cache_.reset(new ui::X11AtomCache(gfx::GetXDisplay(), kAtomsToCache));
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual ~WMStateWaiter() {
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private:
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // X11PropertyChangeWaiter:
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) OVERRIDE {
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<Atom> hints;
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &hints)) {
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      std::vector<Atom>::iterator it = std::find(
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          hints.begin(),
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          hints.end(),
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          atom_cache_->GetAtom(hint_));
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      bool hint_set = (it != hints.end());
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return hint_set != wait_till_set_;
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<ui::X11AtomCache> atom_cache_;
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // The name of the hint to wait to get set or unset.
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const char* hint_;
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Whether we are waiting for |hint| to be set or unset.
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool wait_till_set_;
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(WMStateWaiter);
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// A NonClientFrameView with a window mask with the bottom right corner cut out.
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class ShapedNonClientFrameView : public NonClientFrameView {
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public:
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  explicit ShapedNonClientFrameView() {
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual ~ShapedNonClientFrameView() {
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // NonClientFrameView:
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return bounds();
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual gfx::Rect GetWindowBoundsForClientBounds(
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const gfx::Rect& client_bounds) const OVERRIDE {
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return client_bounds;
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return HTNOWHERE;
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void GetWindowMask(const gfx::Size& size,
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             gfx::Path* window_mask) OVERRIDE {
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int right = size.width();
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int bottom = size.height();
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    window_mask->moveTo(0, 0);
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    window_mask->lineTo(0, bottom);
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    window_mask->lineTo(right, bottom);
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    window_mask->lineTo(right, 10);
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    window_mask->lineTo(right - 10, 10);
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    window_mask->lineTo(right - 10, 0);
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    window_mask->close();
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void ResetWindowControls() OVERRIDE {
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void UpdateWindowIcon() OVERRIDE {
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void UpdateWindowTitle() OVERRIDE {
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual void SizeConstraintsChanged() OVERRIDE {
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private:
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShapedNonClientFrameView);
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class ShapedWidgetDelegate : public WidgetDelegateView {
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public:
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ShapedWidgetDelegate() {
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual ~ShapedWidgetDelegate() {
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // WidgetDelegateView:
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual NonClientFrameView* CreateNonClientFrameView(
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      Widget* widget) OVERRIDE {
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return new ShapedNonClientFrameView;
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private:
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShapedWidgetDelegate);
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Creates a widget of size 100x100.
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_ptr<Widget> CreateWidget(WidgetDelegate* delegate) {
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<Widget> widget(new Widget);
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.delegate = delegate;
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.remove_standard_frame = true;
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.native_widget = new DesktopNativeWidgetAura(widget.get());
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.bounds = gfx::Rect(100, 100, 100, 100);
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  widget->Init(params);
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return widget.Pass();
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Returns the list of rectangles which describe |xid|'s bounding region via the
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// X shape extension.
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)std::vector<gfx::Rect> GetShapeRects(XID xid) {
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int dummy;
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int shape_rects_size;
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  XRectangle* shape_rects = XShapeGetRectangles(gfx::GetXDisplay(),
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                xid,
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                ShapeBounding,
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                &shape_rects_size,
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                &dummy);
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<gfx::Rect> shape_vector;
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (int i = 0; i < shape_rects_size; ++i) {
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    shape_vector.push_back(gfx::Rect(
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        shape_rects[i].x,
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        shape_rects[i].y,
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        shape_rects[i].width,
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        shape_rects[i].height));
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  XFree(shape_rects);
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return shape_vector;
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Returns true if one of |rects| contains point (x,y).
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool ShapeRectContainsPoint(const std::vector<gfx::Rect>& shape_rects,
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            int x,
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            int y) {
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  gfx::Point point(x, y);
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (size_t i = 0; i < shape_rects.size(); ++i) {
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (shape_rects[i].Contains(point))
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return true;
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return false;
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class DesktopWindowTreeHostX11Test : public ViewsTestBase {
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public:
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DesktopWindowTreeHostX11Test() {
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual ~DesktopWindowTreeHostX11Test() {
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void SetUp() OVERRIDE {
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ViewsTestBase::SetUp();
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Make X11 synchronous for our display connection. This does not force the
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // window manager to behave synchronously.
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    XSynchronize(gfx::GetXDisplay(), True);
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void TearDown() OVERRIDE {
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    XSynchronize(gfx::GetXDisplay(), False);
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ViewsTestBase::TearDown();
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private:
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11Test);
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Tests that the shape is properly set on the x window.
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST_F(DesktopWindowTreeHostX11Test, Shape) {
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!ui::IsShapeExtensionAvailable())
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // 1) Test setting the window shape via the NonClientFrameView. This technique
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // is used to get rounded corners on Chrome windows when not using the native
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // window frame.
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<Widget> widget1 = CreateWidget(new ShapedWidgetDelegate());
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  widget1->Show();
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui::X11EventSource::GetInstance()->DispatchXEvents();
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<gfx::Rect> shape_rects = GetShapeRects(xid1);
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_FALSE(shape_rects.empty());
23346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
23446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // The widget was supposed to be 100x100, but the WM might have ignored this
23546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // suggestion.
23646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  int widget_width = widget1->GetWindowBoundsInScreen().width();
23746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, widget_width - 15, 5));
23846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, widget_width - 5, 5));
23946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, widget_width - 5, 15));
24046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, widget_width + 5, 15));
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Changing widget's size should update the shape.
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  widget1->SetBounds(gfx::Rect(100, 100, 200, 200));
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui::X11EventSource::GetInstance()->DispatchXEvents();
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
24646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (widget1->GetWindowBoundsInScreen().width() == 200) {
24746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    shape_rects = GetShapeRects(xid1);
24846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ASSERT_FALSE(shape_rects.empty());
24946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 85, 5));
25046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 5));
25146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 185, 5));
25246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 195, 5));
25346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 195, 15));
25446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 205, 15));
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
25746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (ui::WmSupportsHint(ui::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"))) {
25846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // The shape should be changed to a rectangle which fills the entire screen
25946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // when |widget1| is maximized.
26046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    {
261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      WMStateWaiter waiter(xid1, "_NET_WM_STATE_MAXIMIZED_VERT", true);
26246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      widget1->Maximize();
26346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      waiter.Wait();
26446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
26546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
26646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // xvfb does not support Xrandr so we cannot check the maximized window's
26746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // bounds.
26846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    gfx::Rect maximized_bounds;
26946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ui::GetWindowRect(xid1, &maximized_bounds);
27046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
27146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    shape_rects = GetShapeRects(xid1);
27246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ASSERT_FALSE(shape_rects.empty());
27346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    EXPECT_TRUE(ShapeRectContainsPoint(shape_rects,
27446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                       maximized_bounds.width() - 1,
27546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                       5));
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    EXPECT_TRUE(ShapeRectContainsPoint(shape_rects,
27746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                       maximized_bounds.width() - 1,
27846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                       15));
27946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // 2) Test setting the window shape via Widget::SetShape().
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  gfx::Path shape2;
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  shape2.moveTo(10, 0);
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  shape2.lineTo(10, 10);
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  shape2.lineTo(0, 10);
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  shape2.lineTo(0, 100);
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  shape2.lineTo(100, 100);
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  shape2.lineTo(100, 0);
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  shape2.close();
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<Widget> widget2(CreateWidget(NULL));
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  widget2->Show();
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  widget2->SetShape(shape2.CreateNativeRegion());
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui::X11EventSource::GetInstance()->DispatchXEvents();
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  XID xid2 = widget2->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  shape_rects = GetShapeRects(xid2);
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_FALSE(shape_rects.empty());
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 5, 5));
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 15, 5));
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 15));
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 105, 15));
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Changing the widget's size should not affect the shape.
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  widget2->SetBounds(gfx::Rect(100, 100, 200, 200));
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  shape_rects = GetShapeRects(xid2);
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_FALSE(shape_rects.empty());
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 5, 5));
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 15, 5));
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 15));
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 105, 15));
3126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Setting the shape to NULL resets the shape back to the entire
3146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // window bounds.
3156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  widget2->SetShape(NULL);
3166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  shape_rects = GetShapeRects(xid2);
3176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ASSERT_FALSE(shape_rects.empty());
3186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 5, 5));
3196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 15, 5));
3206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 15));
3216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 105, 15));
3226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 500, 500));
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Test that the widget ignores changes in fullscreen state initiated by the
326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// window manager (e.g. via a window manager accelerator key).
327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)TEST_F(DesktopWindowTreeHostX11Test, WindowManagerTogglesFullscreen) {
328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!ui::WmSupportsHint(ui::GetAtom("_NET_WM_STATE_FULLSCREEN")))
329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate());
332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xid = widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  widget->Show();
334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ui::X11EventSource::GetInstance()->DispatchXEvents();
335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gfx::Rect initial_bounds = widget->GetWindowBoundsInScreen();
337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  {
338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    WMStateWaiter waiter(xid, "_NET_WM_STATE_FULLSCREEN", true);
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    widget->SetFullscreen(true);
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    waiter.Wait();
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_TRUE(widget->IsFullscreen());
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Emulate the window manager exiting fullscreen via a window manager
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // accelerator key. It should not affect the widget's fullscreen state.
346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  {
347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const char* kAtomsToCache[] = {
348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        "_NET_WM_STATE",
349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        "_NET_WM_STATE_FULLSCREEN",
350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        NULL
351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    };
352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    Display* display = gfx::GetXDisplay();
353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ui::X11AtomCache atom_cache(display, kAtomsToCache);
354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XEvent xclient;
356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    memset(&xclient, 0, sizeof(xclient));
357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    xclient.type = ClientMessage;
358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    xclient.xclient.window = xid;
359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    xclient.xclient.message_type = atom_cache.GetAtom("_NET_WM_STATE");
360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    xclient.xclient.format = 32;
361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    xclient.xclient.data.l[0] = 0;
362f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    xclient.xclient.data.l[1] = atom_cache.GetAtom("_NET_WM_STATE_FULLSCREEN");
363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    xclient.xclient.data.l[2] = 0;
364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    xclient.xclient.data.l[3] = 1;
365f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    xclient.xclient.data.l[4] = 0;
366f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XSendEvent(display, DefaultRootWindow(display), False,
367f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)               SubstructureRedirectMask | SubstructureNotifyMask,
368f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)               &xclient);
369f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
370f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    WMStateWaiter waiter(xid, "_NET_WM_STATE_FULLSCREEN", false);
371f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    waiter.Wait();
372f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
373f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_TRUE(widget->IsFullscreen());
374f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Calling Widget::SetFullscreen(false) should clear the widget's fullscreen
376f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // state and clean things up.
377f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  widget->SetFullscreen(false);
378f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_FALSE(widget->IsFullscreen());
379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(initial_bounds.ToString(),
380f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            widget->GetWindowBoundsInScreen().ToString());
381f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
382f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
3836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Tests that the minimization information is propagated to the content window.
3846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)TEST_F(DesktopWindowTreeHostX11Test, ToggleMinimizePropogateToContentWindow) {
3856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  Widget widget;
3866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
3876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  params.native_widget = new DesktopNativeWidgetAura(&widget);
3896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  widget.Init(params);
3906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  widget.Show();
3916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ui::X11EventSource::GetInstance()->DispatchXEvents();
3926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  XID xid = widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget();
3946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  Display* display = gfx::GetXDisplay();
3956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Minimize by sending _NET_WM_STATE_HIDDEN
3976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  {
3986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const char* kAtomsToCache[] = {
3996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        "_NET_WM_STATE",
4006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        "_NET_WM_STATE_HIDDEN",
4016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        NULL
4026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    };
4036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ui::X11AtomCache atom_cache(display, kAtomsToCache);
4056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    std::vector< ::Atom> atom_list;
4076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    atom_list.push_back(atom_cache.GetAtom("_NET_WM_STATE_HIDDEN"));
4086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ui::SetAtomArrayProperty(xid, "_NET_WM_STATE", "ATOM", atom_list);
4096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    XEvent xevent;
4116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    memset(&xevent, 0, sizeof(xevent));
4126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.type = PropertyNotify;
4136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.type = PropertyNotify;
4146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.send_event = 1;
4156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.display = display;
4166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.window = xid;
4176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.atom = atom_cache.GetAtom("_NET_WM_STATE");
4186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.state = 0;
4196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    XSendEvent(display, DefaultRootWindow(display), False,
4206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        SubstructureRedirectMask | SubstructureNotifyMask,
4216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        &xevent);
4226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    WMStateWaiter waiter(xid, "_NET_WM_STATE_HIDDEN", true);
4246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    waiter.Wait();
4256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
4266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  EXPECT_FALSE(widget.GetNativeWindow()->IsVisible());
4276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Show from minimized by sending _NET_WM_STATE_FOCUSED
4296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  {
4306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const char* kAtomsToCache[] = {
4316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        "_NET_WM_STATE",
4326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        "_NET_WM_STATE_FOCUSED",
4336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        NULL
4346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    };
4356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ui::X11AtomCache atom_cache(display, kAtomsToCache);
4376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    std::vector< ::Atom> atom_list;
4396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    atom_list.push_back(atom_cache.GetAtom("_NET_WM_STATE_FOCUSED"));
4406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ui::SetAtomArrayProperty(xid, "_NET_WM_STATE", "ATOM", atom_list);
4416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    XEvent xevent;
4436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    memset(&xevent, 0, sizeof(xevent));
4446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.type = PropertyNotify;
4456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.type = PropertyNotify;
4466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.send_event = 1;
4476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.display = display;
4486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.window = xid;
4496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.atom = atom_cache.GetAtom("_NET_WM_STATE");
4506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    xevent.xproperty.state = 0;
4516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    XSendEvent(display, DefaultRootWindow(display), False,
4526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        SubstructureRedirectMask | SubstructureNotifyMask,
4536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        &xevent);
4546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    WMStateWaiter waiter(xid, "_NET_WM_STATE_FOCUSED", true);
4566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    waiter.Wait();
4576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
4586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  EXPECT_TRUE(widget.GetNativeWindow()->IsVisible());
4596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
4606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
461cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace views
462