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
|
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_X_X11_CRTC_RESIZER_H_
#define UI_GFX_X_X11_CRTC_RESIZER_H_
#include <vector>
#include "base/component_export.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/x/randr.h"
namespace x11 {
// Helper class for DesktopResizerX11 which handles much of the logic
// for arranging and resizing a set of active CRTCs.
class COMPONENT_EXPORT(X11) X11CrtcResizer {
public:
X11CrtcResizer(x11::RandR::GetScreenResourcesCurrentReply* resources,
x11::Connection* connection);
X11CrtcResizer(const X11CrtcResizer&) = delete;
X11CrtcResizer& operator=(const X11CrtcResizer&) = delete;
~X11CrtcResizer();
// Queries the server for all active CRTCs and stores them in |active_crtcs_|.
void FetchActiveCrtcs();
// Searches |active_crts_| to find the one for the given output. If none is
// found, this returns kDisabledCrtc. Since the information on all CRTCs is
// already fetched, this method avoids a server round-trip from using
// RRGetOutputInfo.
x11::RandR::Crtc GetCrtcForOutput(x11::RandR::Output output) const;
// Disables a CRTC. A disabled CRTC no longer has a mode selected (allowing
// the CRD mode to be removed). It also no longer occupies space in the root
// window, which may allow the root window to be resized. This does not
// modify |active_crtcs_|, so the stored information can be used to enable
// the CRTC again.
void DisableCrtc(x11::RandR::Crtc crtc);
// This operates only on |active_crtcs_| without making any X server calls.
// It sets the new mode and width/height for the given CRTC. And it changes
// any xy-offsets as needed, to avoid overlaps between CRTCs.
// This method calls NormalizeCrtcs() so you don't need to call it manually.
void UpdateActiveCrtcs(x11::RandR::Crtc crtc,
x11::RandR::Mode mode,
const gfx::Size& new_size);
// This operates only on |active_crtcs_| without making any X server calls.
// It sets the new mode, offsets and width/height for the given CRTC. Unlike
// UpdateActiveCrtcs, this method does not change any xy-offsets to avoid
// overlaps.
void UpdateActiveCrtc(x11::RandR::Crtc crtc,
x11::RandR::Mode mode,
const gfx::Rect& new_rect);
// Adds a new CRTC to |active_crtcs_|. This method does not make any X server
// calls, and it does not change xy-offsets of any existing CRTCs.
void AddActiveCrtc(x11::RandR::Crtc crtc,
x11::RandR::Mode mode,
const std::vector<x11::RandR::Output>& outputs,
const gfx::Rect& new_rect);
// Removes a CRTC from |active_crtcs_|. This method does not make any X server
// calls.
void RemoveActiveCrtc(x11::RandR::Crtc crtc);
// Disables any CRTCs whose offsets are being changed. The caller is
// responsible for disabling the CRTC being resized, so there is no need to
// do it here.
void DisableChangedCrtcs();
// Computes the bounding-box of the CRTCs after active CRTCs have been
// modified. If the bounding-box is not aligned at the origin, all the CRTC
// offsets are shifted the same amount so that the new bounding-box's top-left
// corner is at (0, 0).
void NormalizeCrtcs();
// This should be called after a new layout is computed and normalized, just
// before applying the changes to the X server. This moves any visible
// windows, to try to keep them in the same relative positions to any moved
// CRTCs.
void MoveApplicationWindows();
// Returns the bounding box of |active_crtcs_| from their current xy-offsets
// and sizes.
// NormalizeCrtcs() needs to be called first if (Update|Add|Remove)ActiveCrtc
// has been called (not including UpdateActiveCrtcs which takes a DesktopSize
// instead of DesktopRect).
gfx::Size GetBoundingBox() const;
// Applies any changed CRTCs back to the X server. This will re-enable any
// outputs/CRTCs that were disabled.
void ApplyActiveCrtcs();
// Updates the root window using the bounding box of the CRTCs, then
// re-activate all CRTCs.
void UpdateRootWindow(x11::Window root);
// Initializes the active CRTCs from a list of fake X11 replies. As the
// replies don't include the CRTC IDs, these will be created sequentially
// as 1, 2, ...
void SetCrtcsForTest(std::vector<x11::RandR::GetCrtcInfoReply> crtcs);
// Returns the stored CRTCs as a list of rectangles.
std::vector<gfx::Rect> GetCrtcsForTest() const;
private:
// Information for an active CRTC, from RRGetCrtcInfo response. When
// modifying a CRTC, the information here can reconstruct the original
// properties that should not be changed.
struct CrtcInfo {
CrtcInfo();
CrtcInfo(x11::RandR::Crtc crtc,
int16_t x,
int16_t y,
uint16_t width,
uint16_t height,
x11::RandR::Mode mode,
x11::RandR::Rotation rotation,
const std::vector<x11::RandR::Output>& outputs);
CrtcInfo(const CrtcInfo&);
CrtcInfo(CrtcInfo&&);
CrtcInfo& operator=(const CrtcInfo&);
CrtcInfo& operator=(CrtcInfo&&);
~CrtcInfo();
// Returns whether {x, y} are different from the original values.
bool OffsetsChanged() const;
x11::RandR::Crtc crtc;
int16_t old_x;
int16_t x;
int16_t old_y;
int16_t y;
uint16_t width;
uint16_t height;
x11::RandR::Mode mode;
x11::RandR::Rotation rotation;
std::vector<x11::RandR::Output> outputs;
};
// Adds a new active CRTC from a reply to RRGetCrtcInfo.
void AddCrtcFromReply(x11::RandR::Crtc crtc,
const x11::RandR::GetCrtcInfoReply& reply);
// Adjusts CRTC offsets to accommodate the new size of the CRTC. This should
// position the CRTCs such that they do not overlap after the CRTC is given
// its new size. The implementation may set negative xy-coordinates, or it
// may leave a gap between all CRTCs and the top (or left) desktop edge.
// NormalizeCrtcs() will be called afterwards to fix both these issues.
// The implementation may also re-order |active_crtcs_|, for example, a
// stacking-algorithm may want to sort the list first.
// |crtc_to_resize| points to the CRTC being resized.
// |new_size| is the new size of |crtc_to_resize|. This method is responsible
// for setting the new width/height values of the CRTC.
void RelayoutCrtcs(x11::RandR::Crtc crtc_to_resize,
const gfx::Size& new_size);
// Returns true if the CRTCs appear to be roughly laid out vertically.
bool LayoutIsVertical() const;
// Stacks the CRTCs vertically without gaps. The CRTC being resized should
// have the old width/height, so that right-alignment can be detected and
// preserved. If they are not all right-aligned, this will position the
// monitors against the left edge of the desktop.
// On return, the CRTC being resized will have the new width/height.
void PackVertically(const gfx::Size& new_size, x11::RandR::Crtc resized_crtc);
// Behaves similarly, but stacks the CRTCs horizontally.
void PackHorizontally(const gfx::Size& new_size,
x11::RandR::Crtc resized_crtc);
// Transposes all the CRTCs by swapping x and y coordinates. This allows
// the vertical layout code to be re-used for horizontal layout.
void Transpose();
// Moves an application window. This tries to account for any re-parenting
// done by a window-manager.
// |window| is the top-level window to move (a child of the root window),
// which is possibly a window-manager frame.
// |attributes| is the response from GetWindowAttributes(window...). It is
// used here to avoid fetching the attributes again inside this method,
// as the caller already has them.
// |top_left| is the requested top-left corner of the new window position.
void MoveWindow(x11::Window window,
const x11::GetWindowAttributesReply& attributes,
gfx::Point top_left);
// Helper method to locate an application window which was re-parented by the
// window-manager. It looks at |window| and its children recursively, in
// stacking order, and returns a viewable window which has the "WM_STATE"
// property. If not found, this returns x11::Window::None.
x11::Window FindAppWindow(x11::Window window,
const x11::GetWindowAttributesReply& attributes);
x11::RandR::GetScreenResourcesCurrentReply resources_;
raw_ptr<x11::Connection> connection_;
raw_ptr<x11::RandR> randr_;
// Information on all CRTCs that are currently enabled (including the CRTC
// being resized). This is only used during a resize operation, while the X
// server is grabbed. Some of these xy-positions may be adjusted. At the end,
// the root window size will be set to the bounding rectangle of all these
// CRTCs. If a CRTC needs to be disabled temporarily, the list entry will be
// preserved so that the CRTC can be re-enabled with the original and new
// properties.
std::vector<CrtcInfo> active_crtcs_;
// Stores the CRTCs being updated. This is needed so that ApplyActiveCrtcs()
// will set the CRTCs' new sizes in the X server, even if their xy-offsets are
// unchanged.
base::flat_set<x11::RandR::Crtc> updated_crtcs_;
// Bounding-box size computed by NormalizeCrtcs().
gfx::Size bounding_box_size_;
x11::Atom wm_state_atom_;
};
} // namespace x11
#endif // UI_GFX_X_X11_CRTC_RESIZER_H_
|