[wayland] Implement size and position window rules

Test Plan: The new tests pass.

Reviewers: #kwin

Subscribers: kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D19413
This commit is contained in:
Vlad Zagorodniy 2019-07-09 20:28:05 +03:00
parent 4d41e877c3
commit bbe898243a
3 changed files with 1038 additions and 8 deletions

File diff suppressed because it is too large Load diff

View file

@ -355,9 +355,17 @@ void ShellClient::finishInit() {
updateWindowMargins(); updateWindowMargins();
bool needsPlacement = !isInitialPositionSet();
if (supportsWindowRules()) { if (supportsWindowRules()) {
setupWindowRules(false); setupWindowRules(false);
const QRect originalGeometry = QRect(pos(), sizeForClientSize(clientSize()));
const QRect ruledGeometry = rules()->checkGeometry(originalGeometry, true);
if (originalGeometry != ruledGeometry) {
setGeometry(ruledGeometry);
}
setDesktop(rules()->checkDesktop(desktop(), true)); setDesktop(rules()->checkDesktop(desktop(), true));
setDesktopFileName(rules()->checkDesktopFile(desktopFileName(), true).toUtf8()); setDesktopFileName(rules()->checkDesktopFile(desktopFileName(), true).toUtf8());
if (rules()->checkMinimize(isMinimized(), true)) { if (rules()->checkMinimize(isMinimized(), true)) {
@ -371,12 +379,17 @@ void ShellClient::finishInit() {
setShortcut(rules()->checkShortcut(shortcut().toString(), true)); setShortcut(rules()->checkShortcut(shortcut().toString(), true));
updateColorScheme(); updateColorScheme();
// Don't place the client if its position is set by a rule.
if (rules()->checkPosition(invalidPoint, true) != invalidPoint) {
needsPlacement = false;
}
discardTemporaryRules(); discardTemporaryRules();
RuleBook::self()->discardUsed(this, false); // Remove Apply Now rules. RuleBook::self()->discardUsed(this, false); // Remove Apply Now rules.
updateWindowRules(Rules::All); updateWindowRules(Rules::All);
} }
if (!isInitialPositionSet()) { if (needsPlacement) {
QRect area = workspace()->clientArea(PlacementArea, Screens::self()->current(), desktop()); QRect area = workspace()->clientArea(PlacementArea, Screens::self()->current(), desktop());
placeIn(area); placeIn(area);
} }
@ -624,10 +637,12 @@ void ShellClient::updateDecoration(bool check_workspace_pos, bool force)
void ShellClient::setGeometry(int x, int y, int w, int h, ForceGeometry_t force) void ShellClient::setGeometry(int x, int y, int w, int h, ForceGeometry_t force)
{ {
const QRect newGeometry = rules()->checkGeometry(QRect(x, y, w, h));
if (areGeometryUpdatesBlocked()) { if (areGeometryUpdatesBlocked()) {
// when the GeometryUpdateBlocker exits the current geom is passed to setGeometry // when the GeometryUpdateBlocker exits the current geom is passed to setGeometry
// thus we need to set it here. // thus we need to set it here.
geom = QRect(x, y, w, h); geom = newGeometry;
if (pendingGeometryUpdate() == PendingGeometryForced) if (pendingGeometryUpdate() == PendingGeometryForced)
{} // maximum, nothing needed {} // maximum, nothing needed
else if (force == ForceGeometrySet) else if (force == ForceGeometrySet)
@ -640,17 +655,17 @@ void ShellClient::setGeometry(int x, int y, int w, int h, ForceGeometry_t force)
// reset geometry to the one before blocking, so that we can compare properly // reset geometry to the one before blocking, so that we can compare properly
geom = geometryBeforeUpdateBlocking(); geom = geometryBeforeUpdateBlocking();
} }
const QSize requestedClientSize = QSize(w, h) - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()); const QSize requestedClientSize = newGeometry.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom());
const QSize requestedWindowGeometrySize = toWindowGeometry(QSize(w, h)); const QSize requestedWindowGeometrySize = toWindowGeometry(newGeometry.size());
if (requestedClientSize == m_clientSize && !isWaitingForMoveResizeSync() && if (requestedClientSize == m_clientSize && !isWaitingForMoveResizeSync() &&
(m_requestedClientSize.isEmpty() || requestedWindowGeometrySize == m_requestedClientSize)) { (m_requestedClientSize.isEmpty() || requestedWindowGeometrySize == m_requestedClientSize)) {
// size didn't change, and we don't need to explicitly request a new size // size didn't change, and we don't need to explicitly request a new size
doSetGeometry(QRect(x, y, w, h)); doSetGeometry(newGeometry);
updateMaximizeMode(m_requestedMaximizeMode); updateMaximizeMode(m_requestedMaximizeMode);
} else { } else {
// size did change, Client needs to provide a new buffer // size did change, Client needs to provide a new buffer
requestGeometry(QRect(x, y, w, h)); requestGeometry(newGeometry);
} }
} }
@ -662,7 +677,9 @@ void ShellClient::doSetGeometry(const QRect &rect)
if (!m_unmapped) { if (!m_unmapped) {
addWorkspaceRepaint(visibleRect()); addWorkspaceRepaint(visibleRect());
} }
geom = rect; geom = rect;
updateWindowRules(Rules::Position | Rules::Size);
if (m_unmapped && m_geomMaximizeRestore.isEmpty() && !geom.isEmpty()) { if (m_unmapped && m_geomMaximizeRestore.isEmpty() && !geom.isEmpty()) {
// use first valid geometry as restore geometry // use first valid geometry as restore geometry
@ -757,6 +774,9 @@ bool ShellClient::isFullScreen() const
bool ShellClient::isMaximizable() const bool ShellClient::isMaximizable() const
{ {
if (!isResizable()) {
return false;
}
return true; return true;
} }
@ -770,6 +790,9 @@ bool ShellClient::isMinimizable() const
bool ShellClient::isMovable() const bool ShellClient::isMovable() const
{ {
if (rules()->checkPosition(invalidPoint) != invalidPoint) {
return false;
}
if (m_plasmaShellSurface) { if (m_plasmaShellSurface) {
return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal; return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal;
} }
@ -781,6 +804,9 @@ bool ShellClient::isMovable() const
bool ShellClient::isMovableAcrossScreens() const bool ShellClient::isMovableAcrossScreens() const
{ {
if (rules()->checkPosition(invalidPoint) != invalidPoint) {
return false;
}
if (m_plasmaShellSurface) { if (m_plasmaShellSurface) {
return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal; return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal;
} }
@ -792,6 +818,9 @@ bool ShellClient::isMovableAcrossScreens() const
bool ShellClient::isResizable() const bool ShellClient::isResizable() const
{ {
if (rules()->checkSize(QSize()).isValid()) {
return false;
}
if (m_plasmaShellSurface) { if (m_plasmaShellSurface) {
return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal; return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal;
} }
@ -840,8 +869,6 @@ void ShellClient::changeMaximize(bool horizontal, bool vertical, bool adjust)
const MaximizeMode oldMode = m_requestedMaximizeMode; const MaximizeMode oldMode = m_requestedMaximizeMode;
const QRect oldGeometry = geometry(); const QRect oldGeometry = geometry();
StackingUpdatesBlocker blocker(workspace());
RequestGeometryBlocker geometryBlocker(this);
// 'adjust == true' means to update the size only, e.g. after changing workspace size // 'adjust == true' means to update the size only, e.g. after changing workspace size
if (!adjust) { if (!adjust) {
if (vertical) if (vertical)
@ -855,6 +882,9 @@ void ShellClient::changeMaximize(bool horizontal, bool vertical, bool adjust)
return; return;
} }
StackingUpdatesBlocker blocker(workspace());
RequestGeometryBlocker geometryBlocker(this);
// call into decoration update borders // call into decoration update borders
if (isDecorated() && decoration()->client() && !(options->borderlessMaximizedWindows() && m_requestedMaximizeMode == KWin::MaximizeFull)) { if (isDecorated() && decoration()->client() && !(options->borderlessMaximizedWindows() && m_requestedMaximizeMode == KWin::MaximizeFull)) {
changeMaximizeRecursion = true; changeMaximizeRecursion = true;

View file

@ -301,6 +301,9 @@ void Workspace::init()
if (c->isFullScreen()) { if (c->isFullScreen()) {
placementDone = true; placementDone = true;
} }
if (c->rules()->checkPosition(invalidPoint, true) != invalidPoint) {
placementDone = true;
}
if (!placementDone) { if (!placementDone) {
c->placeIn(area); c->placeIn(area);
} }