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
This commit is contained in:
Thomas Lübking 2013-11-17 17:37:46 +01:00
parent c4d014eb8c
commit 3d389961ff
4 changed files with 80 additions and 45 deletions

View file

@ -346,6 +346,8 @@ public:
void setDesktop(int); void setDesktop(int);
void setOnAllDesktops(bool set); void setOnAllDesktops(bool set);
void sendToScreen(int screen);
virtual QStringList activities() const; virtual QStringList activities() const;
void setOnActivity(const QString &activity, bool enable); void setOnActivity(const QString &activity, bool enable);
void setOnAllActivities(bool set); void setOnAllActivities(bool set);
@ -405,6 +407,7 @@ public:
virtual Layer layer() const; virtual Layer layer() const;
Layer belongsToLayer() const; Layer belongsToLayer() const;
void invalidateLayer(); void invalidateLayer();
void updateLayer();
int sessionStackingOrder() const; int sessionStackingOrder() const;
void setModal(bool modal); void setModal(bool modal);

View file

@ -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 } // namespace

View file

@ -103,16 +103,8 @@ namespace KWin
void Workspace::updateClientLayer(Client* c) void Workspace::updateClientLayer(Client* c)
{ {
if (c == NULL) if (c)
return; c->updateLayer();
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);
} }
void Workspace::updateStackingOrder(bool propagate_new_clients) void Workspace::updateStackingOrder(bool propagate_new_clients)
@ -851,6 +843,17 @@ Layer Client::belongsToLayer() const
return NormalLayer; 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) bool rec_checkTransientOnTop(const ClientList &transients, const Client *topmost)
{ {
foreach (const Client *transient, transients) { foreach (const Client *transient, transients) {

View file

@ -1217,41 +1217,7 @@ bool Workspace::isOnCurrentHead()
void Workspace::sendClientToScreen(Client* c, int screen) void Workspace::sendClientToScreen(Client* c, int screen)
{ {
screen = c->rules()->checkScreen(screen); c->sendToScreen(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);
} }
void Workspace::sendPingToWindow(xcb_window_t window, xcb_timestamp_t timestamp) void Workspace::sendPingToWindow(xcb_window_t window, xcb_timestamp_t timestamp)