From 3d389961ffc6ad7dec481288a9e22e690b87106f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=BCbking?= Date: Sun, 17 Nov 2013 17:37:46 +0100 Subject: [PATCH] preserve offsets when sending client to screen for that purpose, move sendToScreen and updateLayer functions from Workspace to Client, keep wrappers BUG: 327361 FIXED-IN: 4.11.6 REVIEW: 114078 --- client.h | 3 +++ geometry.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ layers.cpp | 23 +++++++++++-------- workspace.cpp | 36 +---------------------------- 4 files changed, 80 insertions(+), 45 deletions(-) diff --git a/client.h b/client.h index 064e82fb9e..c9236993c1 100644 --- a/client.h +++ b/client.h @@ -346,6 +346,8 @@ public: void setDesktop(int); void setOnAllDesktops(bool set); + void sendToScreen(int screen); + virtual QStringList activities() const; void setOnActivity(const QString &activity, bool enable); void setOnAllActivities(bool set); @@ -405,6 +407,7 @@ public: virtual Layer layer() const; Layer belongsToLayer() const; void invalidateLayer(); + void updateLayer(); int sessionStackingOrder() const; void setModal(bool modal); diff --git a/geometry.cpp b/geometry.cpp index d090a57956..aa1c99ddf6 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -3266,4 +3266,67 @@ void Client::setQuickTileMode(QuickTileMode mode, bool keyboard) } } +void Client::sendToScreen(int newScreen) +{ + newScreen = rules()->checkScreen(newScreen); + if (isActive()) { + screens()->setCurrent(newScreen); + // might impact the layer of a fullscreen window + foreach (Client *cc, workspace()->clientList()) { + if (cc->isFullScreen() && cc->screen() == newScreen) { + cc->updateLayer(); + } + } + } + if (screen() == newScreen) // Don't use isOnScreen(), that's true even when only partially + return; + + GeometryUpdatesBlocker blocker(this); + + // operating on the maximized / quicktiled window would leave the old geom_restore behind, + // so we clear the state first + MaximizeMode maxMode = maximizeMode(); + QuickTileMode qtMode = (QuickTileMode)quick_tile_mode; + maximize(MaximizeRestore); + setQuickTileMode(QuickTileNone); + + QRect oldScreenArea = workspace()->clientArea(MaximizeArea, this); + QRect screenArea = workspace()->clientArea(MaximizeArea, newScreen, desktop()); + QRect oldGeom = geometry(); + QRect newGeom = oldGeom; + // move the window to have the same relative position to the center of the screen + // (i.e. one near the middle of the right edge will also end up near the middle of the right edge) + QPoint center = newGeom.center() - oldScreenArea.center(); + center.setX(center.x() * screenArea.width() / oldScreenArea.width()); + center.setY(center.y() * screenArea.height() / oldScreenArea.height()); + center += screenArea.center(); + newGeom.moveCenter(center); + setGeometry(newGeom); + // align geom_restore - checkWorkspacePosition operates on it + geom_restore = newGeom; + + // If the window was inside the old screen area, explicitly make sure its inside also the new screen area. + // Calling checkWorkspacePosition() should ensure that, but when moving to a small screen the window could + // be big enough to overlap outside of the new screen area, making struts from other screens come into effect, + // which could alter the resulting geometry. + if (oldScreenArea.contains(oldGeom)) + keepInArea(screenArea); + checkWorkspacePosition(oldGeom); + + // re-align geom_restore to contrained geometry + geom_restore = geometry(); + + // finally reset special states + // NOTICE that MaximizeRestore/QuickTileNone checks are required. + // eg. setting QuickTileNone would break maximization + if (maxMode != MaximizeRestore) + maximize(maxMode); + if (qtMode != QuickTileNone) + setQuickTileMode(qtMode); + + ClientList tso = workspace()->ensureStackingOrder(transients()); + for (ClientList::ConstIterator it = tso.constBegin(), end = tso.constEnd(); it != end; ++it) + (*it)->sendToScreen(newScreen); +} + } // namespace diff --git a/layers.cpp b/layers.cpp index 9ac899274c..ed373b89ac 100644 --- a/layers.cpp +++ b/layers.cpp @@ -103,16 +103,8 @@ namespace KWin void Workspace::updateClientLayer(Client* c) { - if (c == NULL) - return; - if (c->layer() == c->belongsToLayer()) - return; - StackingUpdatesBlocker blocker(this); - c->invalidateLayer(); // invalidate, will be updated when doing restacking - for (ClientList::ConstIterator it = c->transients().constBegin(); - it != c->transients().constEnd(); - ++it) - updateClientLayer(*it); + if (c) + c->updateLayer(); } void Workspace::updateStackingOrder(bool propagate_new_clients) @@ -851,6 +843,17 @@ Layer Client::belongsToLayer() const return NormalLayer; } +void Client::updateLayer() +{ + if (layer() == belongsToLayer()) + return; + StackingUpdatesBlocker blocker(workspace()); + invalidateLayer(); // invalidate, will be updated when doing restacking + for (ClientList::ConstIterator it = transients().constBegin(), + end = transients().constEnd(); it != end; ++it) + (*it)->updateLayer(); +} + bool rec_checkTransientOnTop(const ClientList &transients, const Client *topmost) { foreach (const Client *transient, transients) { diff --git a/workspace.cpp b/workspace.cpp index e7f103f99c..82a7567c96 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -1217,41 +1217,7 @@ bool Workspace::isOnCurrentHead() void Workspace::sendClientToScreen(Client* c, int screen) { - screen = c->rules()->checkScreen(screen); - if (c->isActive()) { - screens()->setCurrent(screen); - // might impact the layer of a fullscreen window - foreach (Client *cc, clientList()) { - if (cc->isFullScreen() && cc->screen() == screen) { - updateClientLayer(cc); - } - } - } - if (c->screen() == screen) // Don't use isOnScreen(), that's true even when only partially - return; - GeometryUpdatesBlocker blocker(c); - QRect old_sarea = clientArea(MaximizeArea, c); - QRect sarea = clientArea(MaximizeArea, screen, c->desktop()); - QRect oldgeom = c->geometry(); - QRect geom = c->geometry(); - // move the window to have the same relative position to the center of the screen - // (i.e. one near the middle of the right edge will also end up near the middle of the right edge) - geom.moveCenter( - QPoint(( geom.center().x() - old_sarea.center().x()) * sarea.width() / old_sarea.width() + sarea.center().x(), - ( geom.center().y() - old_sarea.center().y()) * sarea.height() / old_sarea.height() + sarea.center().y())); - c->setGeometry( geom ); - // If the window was inside the old screen area, explicitly make sure its inside also the new screen area. - // Calling checkWorkspacePosition() should ensure that, but when moving to a small screen the window could - // be big enough to overlap outside of the new screen area, making struts from other screens come into effect, - // which could alter the resulting geometry. - if( old_sarea.contains( oldgeom )) - c->keepInArea( sarea ); - c->checkWorkspacePosition( oldgeom ); - ClientList transients_stacking_order = ensureStackingOrder(c->transients()); - for (ClientList::ConstIterator it = transients_stacking_order.constBegin(); - it != transients_stacking_order.constEnd(); - ++it) - sendClientToScreen(*it, screen); + c->sendToScreen(screen); } void Workspace::sendPingToWindow(xcb_window_t window, xcb_timestamp_t timestamp)