summaryrefslogtreecommitdiff
path: root/chromium/ui/platform_window/x11/x11_window.h
blob: 3a78032d8467ccb1de5cc277dcd7a579a8f4cf96 (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
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
// Copyright 2014 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_PLATFORM_WINDOW_X11_X11_WINDOW_H_
#define UI_PLATFORM_WINDOW_X11_X11_WINDOW_H_

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

#include "base/cancelable_callback.h"
#include "base/macros.h"
#include "ui/base/x/x11_desktop_window_move_client.h"
#include "ui/base/x/x11_drag_drop_client.h"
#include "ui/base/x/x11_move_loop_delegate.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/geometry/insets.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"
#include "ui/platform_window/extensions/workspace_extension.h"
#include "ui/platform_window/extensions/x11_extension.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_init_properties.h"
#include "ui/platform_window/wm/wm_drag_handler.h"
#include "ui/platform_window/wm/wm_move_loop_handler.h"
#include "ui/platform_window/wm/wm_move_resize_handler.h"
#include "ui/platform_window/x11/x11_window_export.h"

class SkPath;

namespace ui {

class PlatformWindowDelegate;
class X11ExtensionDelegate;
class X11MoveLoop;
class LocatedEvent;
class WorkspaceExtensionDelegate;

// PlatformWindow implementation for X11.
class X11_WINDOW_EXPORT X11Window
    : public PlatformWindow,
      public WmMoveResizeHandler,
      public PlatformEventDispatcher,
      public x11::EventObserver,
      public WorkspaceExtension,
      public X11Extension,
      public WmDragHandler,
      public XDragDropClient::Delegate,
      public X11MoveLoopDelegate,
      public WmMoveLoopHandler,
      public X11DesktopWindowMoveClient::Delegate {
 public:
  explicit X11Window(PlatformWindowDelegate* platform_window_delegate);
  ~X11Window() override;

  virtual void Initialize(PlatformWindowInitProperties properties);

  // X11WindowManager calls this.
  // XWindow override:
  void OnXWindowLostCapture();

  void OnMouseEnter();

  gfx::AcceleratedWidget GetWidget() const;
  gfx::Rect GetOuterBounds() const;
  void SetTransientWindow(x11::Window window);

  // PlatformWindow:
  void Show(bool inactive) override;
  void Hide() override;
  void Close() override;
  bool IsVisible() const override;
  void PrepareForShutdown() override;
  void SetBounds(const gfx::Rect& bounds) override;
  gfx::Rect GetBounds() const override;
  void SetTitle(const std::u16string& title) override;
  void SetCapture() override;
  void ReleaseCapture() override;
  bool HasCapture() const override;
  void ToggleFullscreen() override;
  void Maximize() override;
  void Minimize() override;
  void Restore() override;
  PlatformWindowState GetPlatformWindowState() const override;
  void Activate() override;
  void Deactivate() override;
  void SetUseNativeFrame(bool use_native_frame) override;
  bool ShouldUseNativeFrame() const override;
  void SetCursor(PlatformCursor cursor) override;
  void MoveCursorTo(const gfx::Point& location) override;
  void ConfineCursorToBounds(const gfx::Rect& bounds) override;
  void SetRestoredBoundsInPixels(const gfx::Rect& bounds) override;
  gfx::Rect GetRestoredBoundsInPixels() const override;
  bool ShouldWindowContentsBeTransparent() const override;
  void SetZOrderLevel(ZOrderLevel order) override;
  ZOrderLevel GetZOrderLevel() const override;
  void StackAbove(gfx::AcceleratedWidget widget) override;
  void StackAtTop() override;
  void FlashFrame(bool flash_frame) override;
  void SetShape(std::unique_ptr<ShapeRects> native_shape,
                const gfx::Transform& transform) override;
  void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
  void SetWindowIcons(const gfx::ImageSkia& window_icon,
                      const gfx::ImageSkia& app_icon) override;
  void SizeConstraintsChanged() override;
  bool IsTranslucentWindowOpacitySupported() const override;
  void SetOpacity(float opacity) override;

  // WorkspaceExtension:
  std::string GetWorkspace() const override;
  void SetVisibleOnAllWorkspaces(bool always_visible) override;
  bool IsVisibleOnAllWorkspaces() const override;
  void SetWorkspaceExtensionDelegate(
      WorkspaceExtensionDelegate* delegate) override;

  // X11Extension:
  bool IsSyncExtensionAvailable() const override;
  bool IsWmTiling() const override;
  void OnCompleteSwapAfterResize() override;
  gfx::Rect GetXRootWindowOuterBounds() const override;
  bool ContainsPointInXRegion(const gfx::Point& point) const override;
  void LowerXWindow() override;
  void SetOverrideRedirect(bool override_redirect) override;
  void SetX11ExtensionDelegate(X11ExtensionDelegate* delegate) override;

  // x11::EventObserver:
  void OnEvent(const x11::Event& event) override;

 protected:
  PlatformWindowDelegate* platform_window_delegate() const {
    return platform_window_delegate_;
  }

  void OnXWindowStateChanged();
  void OnXWindowDamageEvent(const gfx::Rect& damage_rect);
  void OnXWindowBoundsChanged(const gfx::Rect& size);
  void OnXWindowCloseRequested();
  void OnXWindowIsActiveChanged(bool active);
  void OnXWindowWorkspaceChanged();
  void OnXWindowLostPointerGrab();
  void OnXWindowSelectionEvent(const x11::SelectionNotifyEvent& xev);
  void OnXWindowDragDropEvent(const x11::ClientMessageEvent& xev);
  base::Optional<gfx::Size> GetMinimumSizeForXWindow();
  base::Optional<gfx::Size> GetMaximumSizeForXWindow();
  SkPath GetWindowMaskForXWindow();

 private:
  FRIEND_TEST_ALL_PREFIXES(X11WindowTest, Shape);
  FRIEND_TEST_ALL_PREFIXES(X11WindowTest, WindowManagerTogglesFullscreen);
  FRIEND_TEST_ALL_PREFIXES(X11WindowTest,
                           ToggleMinimizePropogateToPlatformWindowDelegate);

  // PlatformEventDispatcher:
  bool CanDispatchEvent(const PlatformEvent& event) override;
  uint32_t DispatchEvent(const PlatformEvent& event) override;

  void DispatchUiEvent(ui::Event* event, const x11::Event& xev);

  // WmMoveResizeHandler
  void DispatchHostWindowDragMovement(
      int hittest,
      const gfx::Point& pointer_location_in_px) override;

  // WmMoveLoopHandler:
  bool RunMoveLoop(const gfx::Vector2d& drag_offset) override;
  void EndMoveLoop() override;

  // WmDragHandler
  bool StartDrag(const OSExchangeData& data,
                 int operation,
                 gfx::NativeCursor cursor,
                 bool can_grab_pointer,
                 WmDragHandler::Delegate* delegate) override;
  void CancelDrag() override;

  // XDragDropClient::Delegate
  std::unique_ptr<XTopmostWindowFinder> CreateWindowFinder() override;
  int UpdateDrag(const gfx::Point& screen_point) override;
  void UpdateCursor(DragDropTypes::DragOperation negotiated_operation) override;
  void OnBeginForeignDrag(x11::Window window) override;
  void OnEndForeignDrag() override;
  void OnBeforeDragLeave() override;
  int PerformDrop() override;
  void EndDragLoop() override;

  // X11MoveLoopDelegate
  void OnMouseMovement(const gfx::Point& screen_point,
                       int flags,
                       base::TimeTicks event_time) override;
  void OnMouseReleased() override;
  void OnMoveLoopEnded() override;

  // X11DesktopWindowMoveClient::Delegate:
  void SetBoundsOnMove(const gfx::Rect& requested_bounds) override;
  scoped_refptr<X11Cursor> GetLastCursor() override;
  gfx::Size GetSize() override;

  void QuitDragLoop();

  // Handles |xevent| as a Atk Key Event
  bool HandleAsAtkEvent(const x11::Event& xevent, bool transient);

  // Adjusts |requested_size_in_pixels| to avoid the WM "feature" where setting
  // the window size to the monitor size causes the WM to set the EWMH for
  // fullscreen.
  gfx::Size AdjustSizeForDisplay(const gfx::Size& requested_size_in_pixels);

  // Converts the location of the |located_event| from the
  // |current_window_bounds| to the |target_window_bounds|.
  void ConvertEventLocationToTargetLocation(
      const gfx::Rect& target_window_bounds,
      const gfx::Rect& current_window_bounds,
      ui::LocatedEvent* located_event);

  // Creates the X window with the given properties.
  // Depending on presence of the compositing manager and window type, may
  // change the opacity, in which case returns the final opacity type through
  // |opacity|.
  void CreateXWindow(const PlatformWindowInitProperties& properties,
                     PlatformWindowOpacity& opacity);
  void CloseXWindow();
  void Map(bool inactive = false);
  void SetFullscreen(bool fullscreen);
  bool IsActive() const;
  bool IsTargetedBy(const x11::Event& xev) const;
  void HandleEvent(const x11::Event& xev);

  bool IsMinimized() const;
  bool IsMaximized() const;
  bool IsFullscreen() const;

  void SetFlashFrameHint(bool flash_frame);
  void UpdateMinAndMaxSize();
  void DispatchResize();
  void CancelResize();

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

  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(); }

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

  // 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();

  // Stores current state of this window.
  PlatformWindowState state_ = PlatformWindowState::kUnknown;

  PlatformWindowDelegate* const platform_window_delegate_;

  WorkspaceExtensionDelegate* workspace_extension_delegate_ = nullptr;

  X11ExtensionDelegate* x11_extension_delegate_ = nullptr;

  // Tells if the window got a ::Close call.
  bool is_shutting_down_ = false;

  // The z-order level of the window; the window exhibits "always on top"
  // behavior if > 0.
  ui::ZOrderLevel z_order_ = ui::ZOrderLevel::kNormal;

  // The bounds of our window before the window was maximized.
  gfx::Rect restored_bounds_in_pixels_;

  std::unique_ptr<X11DesktopWindowMoveClient> x11_window_move_client_;

  // Whether the drop handler has notified that the drag has entered.
  bool notified_enter_ = false;
  // Keeps the last negotiated operation returned by the drop handler.
  int drag_operation_ = 0;

  // Handles XDND events going through this window.
  std::unique_ptr<XDragDropClient> drag_drop_client_;
  WmDragHandler::Delegate* drag_handler_delegate_ = nullptr;

  // Run loop used while dragging from this window.
  std::unique_ptr<X11MoveLoop> drag_loop_;

  // Events that we have selected on the source window of the incoming drag.
  std::unique_ptr<x11::XScopedEventSelector> source_window_events_;

  // 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<x11::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;

  std::u16string 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_;

  base::WeakPtrFactory<X11Window> weak_ptr_factory_{this};

  DISALLOW_COPY_AND_ASSIGN(X11Window);
};

}  // namespace ui

#endif  // UI_PLATFORM_WINDOW_X11_X11_WINDOW_H_