summaryrefslogtreecommitdiff
path: root/chromium/ui/base/x/x11_window.h
blob: 4078ea5dc7be28d090950cbc99dbc56751e20ad7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
// Copyright 2019 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.

#ifndef UI_BASE_X_X11_WINDOW_H_
#define UI_BASE_X_X11_WINDOW_H_

#include <array>
#include <memory>
#include <string>
#include <vector>

#include "base/cancelable_callback.h"
#include "base/component_export.h"
#include "base/containers/flat_set.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "ui/base/x/x11_cursor.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/sync.h"
#include "ui/gfx/x/xfixes.h"
#include "ui/gfx/x/xproto.h"

class SkPath;

namespace gfx {
class ImageSkia;
class Transform;
}  // namespace gfx

namespace ui {

class Event;
class XScopedEventSelector;
class X11Cursor;

////////////////////////////////////////////////////////////////////////////////
// XWindow class
//
// Base class that encapsulates a full featured Xlib-based X11 Window, meant
// to be used mainly in Linux desktop. Abstracts away most of X11 API
// interaction and assumes event handling and some required getters are
// implemented in subclasses.
//
// |XWindow::Configuration| holds parameters used in window initialization.
// Fields are equivalent and a sub-set of Widget::InitParams.
//
// All bounds and size values are assumed to be expressed in pixels.
class COMPONENT_EXPORT(UI_BASE_X) XWindow {
 public:
  using NativeShapeRects = std::vector<gfx::Rect>;

  enum class WindowType {
    kWindow,
    kPopup,
    kMenu,
    kTooltip,
    kDrag,
    kBubble,
  };

  enum class WindowOpacity {
    kInferOpacity,
    kOpaqueWindow,
    kTranslucentWindow,
  };

  struct Configuration final {
    Configuration();
    Configuration(const Configuration& config);
    ~Configuration();

    WindowType type;
    WindowOpacity opacity;
    gfx::Rect bounds;
    gfx::ImageSkia* icon;
    base::Optional<int> background_color;
    bool activatable;
    bool force_show_in_taskbar;
    bool keep_on_top;
    bool visible_on_all_workspaces;
    bool remove_standard_frame;
    bool prefer_dark_theme;
    bool override_redirect;
    std::string workspace;
    std::string wm_class_name;
    std::string wm_class_class;
    std::string wm_role_name;
  };

  XWindow();
  XWindow(const XWindow&) = delete;
  XWindow& operator=(const XWindow&) = delete;
  virtual ~XWindow();

  void Init(const Configuration& config);
  void Map(bool inactive = false);
  void Close();
  void Maximize();
  void Minimize();
  void Unmaximize();
  bool Hide();
  void Unhide();
  void SetFullscreen(bool fullscreen);
  void Activate();
  void Deactivate();
  bool IsActive() const;
  void GrabPointer();
  void ReleasePointerGrab();
  void StackXWindowAbove(x11::Window window);
  void StackXWindowAtTop();
  bool IsTargetedBy(const x11::Event& xev) const;
  bool IsTransientWindowTargetedBy(const x11::Event& x11_event) const;
  void SetTransientWindow(x11::Window window);
  void WmMoveResize(int hittest, const gfx::Point& location) const;
  void ProcessEvent(x11::Event* xev);

  void SetSize(const gfx::Size& size_in_pixels);
  void SetBounds(const gfx::Rect& requested_bounds);
  bool IsXWindowVisible() const;
  bool IsMinimized() const;
  bool IsMaximized() const;
  bool IsFullscreen() const;
  gfx::Rect GetOuterBounds() const;

  void SetCursor(scoped_refptr<X11Cursor> cursor);
  bool SetTitle(base::string16 title);
  void SetXWindowOpacity(float opacity);
  void SetXWindowAspectRatio(const gfx::SizeF& aspect_ratio);
  void SetXWindowIcons(const gfx::ImageSkia& window_icon,
                       const gfx::ImageSkia& app_icon);
  void SetXWindowVisibleOnAllWorkspaces(bool visible);
  bool IsXWindowVisibleOnAllWorkspaces() const;
  void MoveCursorTo(const gfx::Point& location);
  void SetAlwaysOnTop(bool always_on_top);
  void SetFlashFrameHint(bool flash_frame);
  void UpdateMinAndMaxSize();
  void SetUseNativeFrame(bool use_native_frame);
  void DispatchResize();
  void CancelResize();
  void NotifySwapAfterResize();
  void ConfineCursorTo(const gfx::Rect& bounds);
  void LowerWindow();
  void SetOverrideRedirect(bool override_redirect);

  // Returns if the point is within XWindow shape. If shape is not set, always
  // returns true.
  bool ContainsPointInRegion(const gfx::Point& point) const;

  void SetXWindowShape(std::unique_ptr<NativeShapeRects> native_shape,
                       const gfx::Transform& transform);

  // Resets the window region for the current window bounds if necessary.
  void ResetWindowRegion();

  gfx::Rect bounds() const { return bounds_in_pixels_; }
  gfx::Rect previous_bounds() const { return previous_bounds_in_pixels_; }
  void set_bounds(gfx::Rect new_bounds) { bounds_in_pixels_ = new_bounds; }

  bool mapped_in_client() const { return window_mapped_in_client_; }
  bool is_always_on_top() const { return is_always_on_top_; }
  bool use_native_frame() const { return use_native_frame_; }
  bool use_custom_shape() const { return custom_window_shape_; }
  bool was_minimized() const { return was_minimized_; }
  bool has_alpha() const { return visual_has_alpha_; }
  base::Optional<int> workspace() const { return workspace_; }

  x11::Connection* connection() const { return connection_; }
  x11::Window window() const { return xwindow_; }
  x11::Window root_window() const { return x_root_window_; }
  std::vector<x11::Rectangle>* shape() const { return window_shape_.get(); }
  x11::Sync::Counter update_counter() const { return update_counter_; }
  x11::Sync::Counter extended_update_counter() const {
    return extended_update_counter_;
  }
  scoped_refptr<X11Cursor> last_cursor() const { return last_cursor_; }

 protected:
  // Updates |xwindow_|'s _NET_WM_USER_TIME if |xwindow_| is active.
  void UpdateWMUserTime(ui::Event* event);

 private:
  // Called on an XFocusInEvent, XFocusOutEvent, XIFocusInEvent, or an
  // XIFocusOutEvent.
  void OnFocusEvent(bool focus_in,
                    x11::NotifyMode mode,
                    x11::NotifyDetail detail);

  // Called on an XEnterWindowEvent, XLeaveWindowEvent, XIEnterEvent, or an
  // XILeaveEvent.
  void OnCrossingEvent(bool enter,
                       bool focus_in_window_or_ancestor,
                       x11::NotifyMode mode,
                       x11::NotifyDetail detail);

  // Called when |xwindow_|'s _NET_WM_STATE property is updated.
  void OnWMStateUpdated();

  // Called when |xwindow_|'s _NET_FRAME_EXTENTS property is updated.
  void OnFrameExtentsUpdated();

  void OnConfigureEvent(const x11::ConfigureNotifyEvent& event);

  void OnWorkspaceUpdated();

  void OnWindowMapped();

  // Record the activation state.
  void BeforeActivationStateChanged();

  // Handle the state change since BeforeActivationStateChanged().
  void AfterActivationStateChanged();

  void DelayedResize(const gfx::Rect& bounds_in_pixels);

  // If mapped, sends a message to the window manager to enable or disable the
  // states |state1| and |state2|.  Otherwise, the states will be enabled or
  // disabled on the next map.  It's the caller's responsibility to make sure
  // atoms are set and unset in the appropriate pairs.  For example, if a caller
  // sets (_NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MAXIMIZED_HORZ), it would
  // be invalid to unset the maximized state by making two calls like
  // (_NET_WM_STATE_MAXIMIZED_VERT, x11::None), (_NET_WM_STATE_MAXIMIZED_HORZ,
  // x11::None).
  void SetWMSpecState(bool enabled, x11::Atom state1, x11::Atom state2);

  // Updates |window_properties_| with |new_window_properties|.
  void UpdateWindowProperties(
      const base::flat_set<x11::Atom>& new_window_properties);

  void UnconfineCursor();

  void UpdateWindowRegion(std::unique_ptr<std::vector<x11::Rectangle>> region);

  void NotifyBoundsChanged(const gfx::Rect& new_bounds_in_px);

  // Initializes as a status icon window.
  bool InitializeAsStatusIcon();

  // Interface that must be used by a class that inherits the XWindow to receive
  // different messages from X Server.
  virtual void OnXWindowCreated() = 0;
  virtual void OnXWindowStateChanged() = 0;
  virtual void OnXWindowDamageEvent(const gfx::Rect& damage_rect) = 0;
  virtual void OnXWindowBoundsChanged(const gfx::Rect& size) = 0;
  virtual void OnXWindowCloseRequested() = 0;
  virtual void OnXWindowIsActiveChanged(bool active) = 0;
  virtual void OnXWindowWorkspaceChanged() = 0;
  virtual void OnXWindowLostPointerGrab() = 0;
  virtual void OnXWindowLostCapture() = 0;
  virtual void OnXWindowSelectionEvent(x11::Event* xev) = 0;
  virtual void OnXWindowDragDropEvent(x11::Event* xev) = 0;
  virtual base::Optional<gfx::Size> GetMinimumSizeForXWindow() = 0;
  virtual base::Optional<gfx::Size> GetMaximumSizeForXWindow() = 0;
  virtual void GetWindowMaskForXWindow(const gfx::Size& size,
                                       SkPath* window_mask) = 0;

  // The display and the native X window hosting the root window.
  x11::Connection* const connection_;
  x11::Window xwindow_ = x11::Window::None;
  x11::Window x_root_window_ = x11::Window::None;

  // Any native, modal dialog hanging from this window.
  x11::Window transient_window_ = x11::Window::None;

  // Events selected on |xwindow_|.
  std::unique_ptr<ui::XScopedEventSelector> xwindow_events_;

  // The window manager state bits.
  base::flat_set<x11::Atom> window_properties_;

  // Is this window able to receive focus?
  bool activatable_ = true;

  // Was this window initialized with the override_redirect window attribute?
  bool override_redirect_ = false;

  base::string16 window_title_;

  // Whether the window is visible with respect to Aura.
  bool window_mapped_in_client_ = false;

  // Whether the window is mapped with respect to the X server.
  bool window_mapped_in_server_ = false;

  // The bounds of |xwindow_|.
  gfx::Rect bounds_in_pixels_;

  x11::VisualId visual_id_{};

  // Whether we used an ARGB visual for our window.
  bool visual_has_alpha_ = false;

  // The workspace containing |xwindow_|.  This will be base::nullopt when
  // _NET_WM_DESKTOP is unset.
  base::Optional<int> workspace_;

  // True if the window should stay on top of most other windows.
  bool is_always_on_top_ = false;

  // Does |xwindow_| have the pointer grab (XI2 or normal)?
  bool has_pointer_grab_ = false;

  // The focus-tracking state variables are as described in
  // gtk/docs/focus_tracking.txt
  //
  // |xwindow_| is active iff:
  //     (|has_window_focus_| || |has_pointer_focus_|) &&
  //     !|ignore_keyboard_input_|

  // Is the pointer in |xwindow_| or one of its children?
  bool has_pointer_ = false;

  // Is |xwindow_| or one of its children focused?
  bool has_window_focus_ = false;

  // (An ancestor window or the PointerRoot is focused) && |has_pointer_|.
  // |has_pointer_focus_| == true is the odd case where we will receive keyboard
  // input when |has_window_focus_| == false.  |has_window_focus_| and
  // |has_pointer_focus_| are mutually exclusive.
  bool has_pointer_focus_ = false;

  // X11 does not support defocusing windows; you can only focus a different
  // window.  If we would like to be defocused, we just ignore keyboard input we
  // no longer care about.
  bool ignore_keyboard_input_ = false;

  // Used for tracking activation state in {Before|After}ActivationStateChanged.
  bool was_active_ = false;
  bool had_pointer_ = false;
  bool had_pointer_grab_ = false;
  bool had_window_focus_ = false;

  bool was_minimized_ = false;

  // Used for synchronizing between |xwindow_| and desktop compositor during
  // resizing.
  x11::Sync::Counter update_counter_{};
  x11::Sync::Counter extended_update_counter_{};

  // Whenever the bounds are set, we keep the previous set of bounds around so
  // we can have a better chance of getting the real
  // |restored_bounds_in_pixels_|. Window managers tend to send a Configure
  // message with the maximized bounds, and then set the window maximized
  // property. (We don't rely on this for when we request that the window be
  // maximized, only when we detect that some other process has requested that
  // we become the maximized window.)
  gfx::Rect previous_bounds_in_pixels_;

  // True if a Maximize() call should be done after mapping the window.
  bool should_maximize_after_map_ = false;

  // Whether we currently are flashing our frame. This feature is implemented
  // by setting the urgency hint with the window manager, which can draw
  // attention to the window or completely ignore the hint. We stop flashing
  // the frame when |xwindow_| gains focus or handles a mouse button event.
  bool urgency_hint_set_ = false;

  // |xwindow_|'s minimum size.
  gfx::Size min_size_in_pixels_;

  // |xwindow_|'s maximum size.
  gfx::Size max_size_in_pixels_;

  // The window shape if the window is non-rectangular.
  std::unique_ptr<std::vector<x11::Rectangle>> window_shape_;

  // Whether |window_shape_| was set via SetShape().
  bool custom_window_shape_ = false;

  // True if the window has title-bar / borders provided by the window manager.
  bool use_native_frame_ = false;

  // The size of the window manager provided borders (if any).
  gfx::Insets native_window_frame_borders_in_pixels_;

  // Used for synchronizing between |xwindow_| between desktop compositor during
  // resizing.
  int64_t pending_counter_value_ = 0;
  int64_t configure_counter_value_ = 0;
  int64_t current_counter_value_ = 0;
  bool pending_counter_value_is_extended_ = false;
  bool configure_counter_value_is_extended_ = false;

  base::CancelableOnceClosure delayed_resize_task_;

  // Keep track of barriers to confine cursor.
  bool has_pointer_barriers_ = false;
  std::array<x11::XFixes::Barrier, 4> pointer_barriers_;

  scoped_refptr<X11Cursor> last_cursor_;

  base::CancelableOnceCallback<void(x11::Cursor)> on_cursor_loaded_;
};

}  // namespace ui

#endif  // UI_BASE_X_X11_WINDOW_H_