Improved window movement around struts. Windows can be moved anywhere
where the titlebar is still clickable even if it is outside the normal work area. When struts are added or removed only move the windows that cover the same area, leave all others untouched. If a strut is removed on a xinerama screen that is not on the edge of the full desktop area prevent the windows from being moved offscreen. Prevent struts/panels from interfering with the movement of windows on other xinerama screens. BUG: 74559 BUG: 90833 BUG: 160068 svn path=/trunk/KDE/kdebase/workspace/; revision=927466
This commit is contained in:
parent
7243d7132e
commit
ca901dae30
8 changed files with 360 additions and 155 deletions
|
@ -318,12 +318,8 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
|
|||
XReparentWindow( display(), decoration->widget()->winId(), frameId(), 0, 0 );
|
||||
decoration->widget()->lower();
|
||||
decoration->borders( border_left, border_right, border_top, border_bottom );
|
||||
int save_workarea_diff_x = workarea_diff_x;
|
||||
int save_workarea_diff_y = workarea_diff_y;
|
||||
move( calculateGravitation( false ));
|
||||
plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
|
||||
workarea_diff_x = save_workarea_diff_x;
|
||||
workarea_diff_y = save_workarea_diff_y;
|
||||
do_show = true;
|
||||
if( compositing() )
|
||||
discardWindowPixmap();
|
||||
|
@ -352,12 +348,8 @@ void Client::destroyDecoration()
|
|||
QPoint grav = calculateGravitation( true );
|
||||
border_left = border_right = border_top = border_bottom = 0;
|
||||
setMask( QRegion()); // Reset shape mask
|
||||
int save_workarea_diff_x = workarea_diff_x;
|
||||
int save_workarea_diff_y = workarea_diff_y;
|
||||
plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
|
||||
move( grav );
|
||||
workarea_diff_x = save_workarea_diff_x;
|
||||
workarea_diff_y = save_workarea_diff_y;
|
||||
if( compositing() )
|
||||
discardWindowPixmap();
|
||||
if( scene != NULL && !deleting )
|
||||
|
|
5
client.h
5
client.h
|
@ -280,6 +280,8 @@ class Client
|
|||
void cancelShadeHoverTimer();
|
||||
void cancelAutoRaise();
|
||||
void checkActiveModal();
|
||||
StrutRect strutRect( StrutArea area ) const;
|
||||
StrutRects strutRects() const;
|
||||
bool hasStrut() const;
|
||||
/**
|
||||
* Whether or not the window has a strut that expands through the invisible area of
|
||||
|
@ -378,9 +380,7 @@ class Client
|
|||
void finishWindowRules();
|
||||
void setShortcutInternal( const KShortcut& cut );
|
||||
|
||||
void updateWorkareaDiffs();
|
||||
void checkDirection( int new_diff, int old_diff, QRect& rect, const QRect& area );
|
||||
static int computeWorkareaDiff( int left, int right, int a_left, int a_right );
|
||||
void configureRequest( int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool );
|
||||
NETExtendedStrut strut() const;
|
||||
int checkShadeGeometry( int w, int h );
|
||||
|
@ -510,7 +510,6 @@ class Client
|
|||
QRect geom_restore;
|
||||
QRect geom_fs_restore;
|
||||
MaximizeMode maxmode_restore;
|
||||
int workarea_diff_x, workarea_diff_y;
|
||||
QTimer* autoRaiseTimer;
|
||||
QTimer* shadeHoverTimer;
|
||||
QTimer* delayedMoveResizeTimer;
|
||||
|
|
443
geometry.cpp
443
geometry.cpp
|
@ -4,6 +4,7 @@
|
|||
|
||||
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
|
||||
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -85,6 +86,7 @@ void Workspace::updateClientArea( bool force )
|
|||
int nscreens = Kephal::ScreenUtils::numScreens();
|
||||
kDebug(1212) << "screens: " << nscreens << "desktops: " << numberOfDesktops();
|
||||
QVector< QRect > new_wareas( numberOfDesktops() + 1 );
|
||||
QVector< StrutRects > new_rmoveareas( numberOfDesktops() + 1 );
|
||||
QVector< QVector< QRect > > new_sareas( numberOfDesktops() + 1 );
|
||||
QVector< QRect > screens( nscreens );
|
||||
QRect desktopArea = Kephal::ScreenUtils::desktopGeometry();
|
||||
|
@ -110,6 +112,7 @@ void Workspace::updateClientArea( bool force )
|
|||
if( !(*it)->hasStrut())
|
||||
continue;
|
||||
QRect r = (*it)->adjustedClientArea( desktopArea, desktopArea );
|
||||
StrutRects strutRegion = (*it)->strutRects();
|
||||
|
||||
// Ignore offscreen xinerama struts. These interfere with the larger monitors on the setup
|
||||
// and should be ignored so that applications that use the work area to work out where
|
||||
|
@ -127,6 +130,7 @@ void Workspace::updateClientArea( bool force )
|
|||
{
|
||||
if( !hasOffscreenXineramaStrut )
|
||||
new_wareas[ i ] = new_wareas[ i ].intersected( r );
|
||||
new_rmoveareas[ i ] += strutRegion;
|
||||
for( int iS = 0;
|
||||
iS < nscreens;
|
||||
iS ++ )
|
||||
|
@ -140,6 +144,7 @@ void Workspace::updateClientArea( bool force )
|
|||
{
|
||||
if( !hasOffscreenXineramaStrut )
|
||||
new_wareas[ (*it)->desktop() ] = new_wareas[ (*it)->desktop() ].intersected( r );
|
||||
new_rmoveareas[ (*it)->desktop() ] += strutRegion;
|
||||
for( int iS = 0;
|
||||
iS < nscreens;
|
||||
iS ++ )
|
||||
|
@ -170,7 +175,10 @@ void Workspace::updateClientArea( bool force )
|
|||
for( int i = 1;
|
||||
i <= numberOfDesktops();
|
||||
++i )
|
||||
{
|
||||
new_wareas[ i ] = new_wareas[ i ].intersected( topmenu_area );
|
||||
new_rmoveareas[ i ] += topmenu_area;
|
||||
}
|
||||
}
|
||||
|
||||
bool changed = force;
|
||||
|
@ -184,6 +192,8 @@ void Workspace::updateClientArea( bool force )
|
|||
{
|
||||
if( workarea[ i ] != new_wareas[ i ] )
|
||||
changed = true;
|
||||
if( restrictedmovearea[ i ] != new_rmoveareas[ i ] )
|
||||
changed = true;
|
||||
if( screenarea[ i ].size() != new_sareas[ i ].size())
|
||||
changed = true;
|
||||
for( int iS = 0;
|
||||
|
@ -196,6 +206,8 @@ void Workspace::updateClientArea( bool force )
|
|||
if ( changed )
|
||||
{
|
||||
workarea = new_wareas;
|
||||
oldrestrictedmovearea = restrictedmovearea;
|
||||
restrictedmovearea = new_rmoveareas;
|
||||
screenarea = new_sareas;
|
||||
NETRect r;
|
||||
for( int i = 1; i <= numberOfDesktops(); i++)
|
||||
|
@ -296,6 +308,27 @@ QRect Workspace::clientArea( clientAreaOption opt, const Client* c ) const
|
|||
return clientArea( opt, c->geometry().center(), c->desktop());
|
||||
}
|
||||
|
||||
QRegion Workspace::restrictedMoveArea( int desktop, StrutAreas areas ) const
|
||||
{
|
||||
if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 )
|
||||
desktop = currentDesktop();
|
||||
QRegion region;
|
||||
foreach( const StrutRect& rect, restrictedmovearea[desktop] )
|
||||
if( areas & rect.area() )
|
||||
region += rect;
|
||||
return region;
|
||||
}
|
||||
|
||||
QRegion Workspace::previousRestrictedMoveArea( int desktop, StrutAreas areas ) const
|
||||
{
|
||||
if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 )
|
||||
desktop = currentDesktop();
|
||||
QRegion region;
|
||||
foreach( const StrutRect& rect, oldrestrictedmovearea[desktop] )
|
||||
if( areas & rect.area() )
|
||||
region += rect;
|
||||
return region;
|
||||
}
|
||||
|
||||
/*!
|
||||
Client \a c is moved around to position \a pos. This gives the
|
||||
|
@ -964,6 +997,56 @@ NETExtendedStrut Client::strut() const
|
|||
return ext;
|
||||
}
|
||||
|
||||
StrutRect Client::strutRect( StrutArea area ) const
|
||||
{
|
||||
assert( area != StrutAreaAll ); // Not valid
|
||||
NETExtendedStrut strutArea = strut();
|
||||
switch( area )
|
||||
{
|
||||
case StrutAreaTop:
|
||||
if( strutArea.top_width != 0 )
|
||||
return StrutRect( QRect(
|
||||
strutArea.top_start, 0,
|
||||
strutArea.top_end - strutArea.top_start, strutArea.top_width
|
||||
), StrutAreaTop );
|
||||
break;
|
||||
case StrutAreaRight:
|
||||
if( strutArea.right_width != 0 )
|
||||
return StrutRect( QRect(
|
||||
displayWidth() - strutArea.right_width, strutArea.right_start,
|
||||
strutArea.right_width, strutArea.right_end - strutArea.right_start
|
||||
), StrutAreaRight );
|
||||
break;
|
||||
case StrutAreaBottom:
|
||||
if( strutArea.bottom_width != 0 )
|
||||
return StrutRect( QRect(
|
||||
strutArea.bottom_start, displayHeight() - strutArea.bottom_width,
|
||||
strutArea.bottom_end - strutArea.bottom_start, strutArea.bottom_width
|
||||
), StrutAreaBottom );
|
||||
break;
|
||||
case StrutAreaLeft:
|
||||
if( strutArea.left_width != 0 )
|
||||
return StrutRect( QRect(
|
||||
0, strutArea.left_start,
|
||||
strutArea.left_width, strutArea.left_end - strutArea.left_start
|
||||
), StrutAreaLeft );
|
||||
break;
|
||||
default:
|
||||
abort(); // Not valid
|
||||
}
|
||||
return StrutRect(); // Null rect
|
||||
}
|
||||
|
||||
StrutRects Client::strutRects() const
|
||||
{
|
||||
StrutRects region;
|
||||
region += strutRect( StrutAreaTop );
|
||||
region += strutRect( StrutAreaRight );
|
||||
region += strutRect( StrutAreaBottom );
|
||||
region += strutRect( StrutAreaLeft );
|
||||
return region;
|
||||
}
|
||||
|
||||
bool Client::hasStrut() const
|
||||
{
|
||||
NETExtendedStrut ext = strut();
|
||||
|
@ -974,72 +1057,20 @@ bool Client::hasStrut() const
|
|||
|
||||
bool Client::hasOffscreenXineramaStrut() const
|
||||
{
|
||||
// Convert strut to a QRegion
|
||||
NETExtendedStrut strutArea = strut();
|
||||
QRegion strutRegion;
|
||||
if( strutArea.left_width != 0 )
|
||||
strutRegion += QRect(
|
||||
0, strutArea.left_start,
|
||||
strutArea.left_width, strutArea.left_end - strutArea.left_start
|
||||
);
|
||||
if( strutArea.right_width != 0 )
|
||||
strutRegion += QRect(
|
||||
displayWidth() - strutArea.right_width, strutArea.right_start,
|
||||
strutArea.right_width, strutArea.right_end - strutArea.right_start
|
||||
);
|
||||
if( strutArea.top_width != 0 )
|
||||
strutRegion += QRect(
|
||||
strutArea.top_start, 0,
|
||||
strutArea.top_end - strutArea.top_start, strutArea.top_width
|
||||
);
|
||||
if( strutArea.bottom_width != 0 )
|
||||
strutRegion += QRect(
|
||||
strutArea.bottom_start, displayHeight() - strutArea.bottom_width,
|
||||
strutArea.bottom_end - strutArea.bottom_start, strutArea.bottom_width
|
||||
);
|
||||
// Get strut as a QRegion
|
||||
QRegion region;
|
||||
region += strutRect( StrutAreaTop );
|
||||
region += strutRect( StrutAreaRight );
|
||||
region += strutRect( StrutAreaBottom );
|
||||
region += strutRect( StrutAreaLeft );
|
||||
|
||||
// Remove all visible areas so that only the invisible remain
|
||||
int numScreens = Kephal::ScreenUtils::numScreens();
|
||||
for( int i = 0; i < numScreens; i ++ )
|
||||
strutRegion -= Kephal::ScreenUtils::screenGeometry( i );
|
||||
region -= Kephal::ScreenUtils::screenGeometry( i );
|
||||
|
||||
// If there's anything left then we have an offscreen strut
|
||||
return !strutRegion.isEmpty();
|
||||
}
|
||||
|
||||
// updates differences to workarea edges for all directions
|
||||
void Client::updateWorkareaDiffs()
|
||||
{
|
||||
QRect area = workspace()->clientArea( WorkArea, this );
|
||||
QRect geom = geometry();
|
||||
workarea_diff_x = computeWorkareaDiff( geom.left(), geom.right(), area.left(), area.right());
|
||||
workarea_diff_y = computeWorkareaDiff( geom.top(), geom.bottom(), area.top(), area.bottom());
|
||||
}
|
||||
|
||||
// If the client was inside workarea in the x direction, and if it was close to the left/right
|
||||
// edge, return the distance from the left/right edge (negative for left, positive for right)
|
||||
// INT_MIN means 'not inside workarea', INT_MAX means 'not near edge'.
|
||||
// In order to recognize 'at the left workarea edge' from 'at the right workarea edge'
|
||||
// (i.e. negative vs positive zero), the distances are one larger in absolute value than they
|
||||
// really are (i.e. 5 pixels from the left edge is -6, not -5). A bit hacky, but I'm lazy
|
||||
// to rewrite it just to make it nicer. If this will ever get touched again, perhaps then.
|
||||
// the y direction is done the same, just the values will be rotated: top->left, bottom->right
|
||||
int Client::computeWorkareaDiff( int left, int right, int a_left, int a_right )
|
||||
{
|
||||
int left_diff = left - a_left;
|
||||
int right_diff = a_right - right;
|
||||
if( left_diff < 0 || right_diff < 0 )
|
||||
return INT_MIN;
|
||||
else // fully inside workarea in this direction direction
|
||||
{
|
||||
// max distance from edge where it's still considered to be close and is kept at that distance
|
||||
int max_diff = ( a_right - a_left ) / 10;
|
||||
if( left_diff < right_diff )
|
||||
return left_diff < max_diff ? -left_diff - 1 : INT_MAX;
|
||||
else if( left_diff > right_diff )
|
||||
return right_diff < max_diff ? right_diff + 1 : INT_MAX;
|
||||
return INT_MAX; // not close to workarea edge
|
||||
}
|
||||
return !region.isEmpty();
|
||||
}
|
||||
|
||||
void Client::checkWorkspacePosition()
|
||||
|
@ -1078,10 +1109,6 @@ void Client::checkWorkspacePosition()
|
|||
|
||||
if( !isShade()) // TODO
|
||||
{
|
||||
int old_diff_x = workarea_diff_x;
|
||||
int old_diff_y = workarea_diff_y;
|
||||
updateWorkareaDiffs();
|
||||
|
||||
// this can be true only if this window was mapped before KWin
|
||||
// was started - in such case, don't adjust position to workarea,
|
||||
// because the window already had its position, and if a window
|
||||
|
@ -1090,27 +1117,125 @@ void Client::checkWorkspacePosition()
|
|||
if( workspace()->initializing())
|
||||
return;
|
||||
|
||||
QRect area = workspace()->clientArea( WorkArea, this );
|
||||
QRect new_geom = geometry();
|
||||
QRect tmp_rect_x( new_geom.left(), 0, new_geom.width(), 0 );
|
||||
QRect tmp_area_x( area.left(), 0, area.width(), 0 );
|
||||
checkDirection( workarea_diff_x, old_diff_x, tmp_rect_x, tmp_area_x );
|
||||
// the x<->y swapping
|
||||
QRect tmp_rect_y( new_geom.top(), 0, new_geom.height(), 0 );
|
||||
QRect tmp_area_y( area.top(), 0, area.height(), 0 );
|
||||
checkDirection( workarea_diff_y, old_diff_y, tmp_rect_y, tmp_area_y );
|
||||
new_geom = QRect( tmp_rect_x.left(), tmp_rect_y.left(), tmp_rect_x.width(), tmp_rect_y.width());
|
||||
QRect final_geom( new_geom.topLeft(), adjustedSize( new_geom.size()));
|
||||
if( final_geom != new_geom ) // size increments, or size restrictions
|
||||
{ // adjusted size differing matters only for right and bottom edge
|
||||
if( old_diff_x != INT_MAX && old_diff_x > 0 )
|
||||
final_geom.moveRight( area.right() - ( old_diff_x - 1 ));
|
||||
if( old_diff_y != INT_MAX && old_diff_y > 0 )
|
||||
final_geom.moveBottom( area.bottom() - ( old_diff_y - 1 ));
|
||||
// If the window was touching an edge before but not now move it so it is again.
|
||||
// Old and new maximums have different starting values so windows on the screen
|
||||
// edge will move when a new strut is placed on the edge.
|
||||
const QRect& screenArea = workspace()->clientArea( ScreenArea, this );
|
||||
int oldTopMax = screenArea.y();
|
||||
int oldRightMax = screenArea.x() + screenArea.width();
|
||||
int oldBottomMax = screenArea.y() + screenArea.height();
|
||||
int oldLeftMax = screenArea.x();
|
||||
int topMax = INT_MIN, rightMax = INT_MAX, bottomMax = INT_MAX, leftMax = INT_MIN;
|
||||
QRect newGeom = geometry();
|
||||
const QRect& newGeomTall = QRect( newGeom.x(), 0, newGeom.width(), displayHeight() ); // Full screen height
|
||||
const QRect& newGeomWide = QRect( 0, newGeom.y(), displayWidth(), newGeom.height() ); // Full screen width
|
||||
|
||||
// Get the max strut point for each side where the window is (E.g. Highest point for
|
||||
// the bottom struts bounded by the window's left and right sides).
|
||||
foreach( QRect rect, workspace()->previousRestrictedMoveArea( desktop(), StrutAreaTop ).rects() )
|
||||
{
|
||||
rect &= newGeomTall;
|
||||
if( !rect.isEmpty() )
|
||||
oldTopMax = qMax( oldTopMax, rect.y() + rect.height() );
|
||||
}
|
||||
if( final_geom != geometry() )
|
||||
setGeometry( final_geom );
|
||||
// updateWorkareaDiffs(); done already by setGeometry()
|
||||
foreach( QRect rect, workspace()->previousRestrictedMoveArea( desktop(), StrutAreaRight ).rects() )
|
||||
{
|
||||
rect &= newGeomWide;
|
||||
if( !rect.isEmpty() )
|
||||
oldRightMax = qMin( oldRightMax, rect.x() );
|
||||
}
|
||||
foreach( QRect rect, workspace()->previousRestrictedMoveArea( desktop(), StrutAreaBottom ).rects() )
|
||||
{
|
||||
rect &= newGeomTall;
|
||||
if( !rect.isEmpty() )
|
||||
oldBottomMax = qMin( oldBottomMax, rect.y() );
|
||||
}
|
||||
foreach( QRect rect, workspace()->previousRestrictedMoveArea( desktop(), StrutAreaLeft ).rects() )
|
||||
{
|
||||
rect &= newGeomWide;
|
||||
if( !rect.isEmpty() )
|
||||
oldLeftMax = qMax( oldLeftMax, rect.x() + rect.width() );
|
||||
}
|
||||
foreach( QRect rect, workspace()->restrictedMoveArea( desktop(), StrutAreaTop ).rects() )
|
||||
{
|
||||
rect &= newGeomTall;
|
||||
if( !rect.isEmpty() )
|
||||
topMax = qMax( topMax, rect.y() + rect.height() );
|
||||
}
|
||||
foreach( QRect rect, workspace()->restrictedMoveArea( desktop(), StrutAreaRight ).rects() )
|
||||
{
|
||||
rect &= newGeomWide;
|
||||
if( !rect.isEmpty() )
|
||||
rightMax = qMin( rightMax, rect.x() );
|
||||
}
|
||||
foreach( QRect rect, workspace()->restrictedMoveArea( desktop(), StrutAreaBottom ).rects() )
|
||||
{
|
||||
rect &= newGeomTall;
|
||||
if( !rect.isEmpty() )
|
||||
bottomMax = qMin( bottomMax, rect.y() );
|
||||
}
|
||||
foreach( QRect rect, workspace()->restrictedMoveArea( desktop(), StrutAreaLeft ).rects() )
|
||||
{
|
||||
rect &= newGeomWide;
|
||||
if( !rect.isEmpty() )
|
||||
leftMax = qMax( leftMax, rect.x() + rect.width() );
|
||||
}
|
||||
|
||||
// Check if the sides were touching before but are no longer
|
||||
if( newGeom.y() == oldTopMax &&
|
||||
newGeom.y() != topMax )
|
||||
{ // Top was touching before but isn't anymore
|
||||
// If the other side was touching make sure it still is afterwards
|
||||
if( newGeom.y() + newGeom.height() == oldBottomMax )
|
||||
newGeom.setTop( qMax( topMax, screenArea.y() ));
|
||||
else
|
||||
newGeom.moveTop( qMax( topMax, screenArea.y() ));
|
||||
// Make sure it doesn't go off the other side of the screen/under an opposite strut
|
||||
newGeom.setBottom( qMin( qMin( bottomMax - 1, screenArea.bottom() ),
|
||||
newGeom.y() + newGeom.height() - 1 ));
|
||||
}
|
||||
if( newGeom.x() + newGeom.width() == oldRightMax &&
|
||||
newGeom.x() + newGeom.width() != rightMax )
|
||||
{ // Right was touching before but isn't anymore
|
||||
// If the other side was touching make sure it still is afterwards
|
||||
if( newGeom.x() == oldLeftMax )
|
||||
newGeom.setRight( qMin( rightMax - 1, screenArea.right() ));
|
||||
else
|
||||
newGeom.moveRight( qMin( rightMax - 1, screenArea.right() ));
|
||||
// Make sure it doesn't go off the other side of the screen/under an opposite strut
|
||||
newGeom.setLeft( qMax( qMax( leftMax, screenArea.x() ),
|
||||
newGeom.x() ));
|
||||
}
|
||||
if( newGeom.y() + newGeom.height() == oldBottomMax &&
|
||||
newGeom.y() + newGeom.height() != bottomMax )
|
||||
{ // Bottom was touching before but isn't anymore
|
||||
// If the other side was touching make sure it still is afterwards
|
||||
if( newGeom.y() == oldTopMax )
|
||||
newGeom.setBottom( qMin( bottomMax - 1, screenArea.bottom() ));
|
||||
else
|
||||
newGeom.moveBottom( qMin( bottomMax - 1, screenArea.bottom() ));
|
||||
// Make sure it doesn't go off the other side of the screen/under an opposite strut
|
||||
newGeom.setTop( qMax( qMax( topMax, screenArea.y() ),
|
||||
newGeom.y() ));
|
||||
}
|
||||
if( newGeom.x() == oldLeftMax &&
|
||||
newGeom.x() != leftMax )
|
||||
{ // Left was touching before but isn't anymore
|
||||
// If the other side was touching make sure it still is afterwards
|
||||
if( newGeom.y() == newGeom.x() + newGeom.width() == oldRightMax )
|
||||
newGeom.setLeft( qMax( leftMax, screenArea.x() ));
|
||||
else
|
||||
newGeom.moveLeft( qMax( leftMax, screenArea.x() ));
|
||||
// Make sure it doesn't go off the other side of the screen/under an opposite strut
|
||||
newGeom.setRight( qMin( qMin( rightMax - 1, screenArea.right() ),
|
||||
newGeom.x() + newGeom.width() - 1 ));
|
||||
}
|
||||
|
||||
// Obey size hints. TODO: We really should make sure it stays in the right place
|
||||
newGeom.setSize( adjustedSize( newGeom.size() ));
|
||||
|
||||
if( newGeom != geometry() )
|
||||
setGeometry( newGeom );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1710,24 +1835,6 @@ void Client::resizeWithChecks( int w, int h, ForceGeometry_t force )
|
|||
newy = newy + height() - h;
|
||||
break;
|
||||
}
|
||||
// if it would be moved outside of workarea, keep it inside,
|
||||
// see also Client::computeWorkareaDiff()
|
||||
if( workarea_diff_x != INT_MIN && w <= area.width()) // was inside and can still fit
|
||||
{
|
||||
if( newx < area.left())
|
||||
newx = area.left();
|
||||
if( newx + w > area.right() + 1 )
|
||||
newx = area.right() + 1 - w;
|
||||
assert( newx >= area.left() && newx + w <= area.right() + 1 ); // width was checked above
|
||||
}
|
||||
if( workarea_diff_y != INT_MIN && h <= area.height()) // was inside and can still fit
|
||||
{
|
||||
if( newy < area.top())
|
||||
newy = area.top();
|
||||
if( newy + h > area.bottom() + 1 )
|
||||
newy = area.bottom() + 1 - h;
|
||||
assert( newy >= area.top() && newy + h <= area.bottom() + 1 ); // height was checked above
|
||||
}
|
||||
setGeometry( newx, newy, w, h, force );
|
||||
}
|
||||
|
||||
|
@ -1869,7 +1976,6 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
|
|||
if( force == NormalGeometrySet && geom == g && pending_geometry_update == PendingGeometryNone )
|
||||
return;
|
||||
geom = g;
|
||||
updateWorkareaDiffs();
|
||||
if( block_geometry_updates != 0 )
|
||||
{
|
||||
if( pending_geometry_update == PendingGeometryForced )
|
||||
|
@ -1949,7 +2055,6 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
|
|||
if( force == NormalGeometrySet && geom.size() == s )
|
||||
return;
|
||||
geom.setSize( s );
|
||||
updateWorkareaDiffs();
|
||||
if( block_geometry_updates != 0 )
|
||||
{
|
||||
if( pending_geometry_update == PendingGeometryForced )
|
||||
|
@ -2003,7 +2108,6 @@ void Client::move( int x, int y, ForceGeometry_t force )
|
|||
if( force == NormalGeometrySet && geom.topLeft() == p )
|
||||
return;
|
||||
geom.moveTopLeft( p );
|
||||
updateWorkareaDiffs();
|
||||
if( block_geometry_updates != 0 )
|
||||
{
|
||||
if( pending_geometry_update == PendingGeometryForced )
|
||||
|
@ -2761,22 +2865,14 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
|
|||
if( workspace()->screenNumber( globalPos ) == -1 )
|
||||
return;
|
||||
|
||||
// compute bounds
|
||||
// NOTE: This is duped in checkUnrestrictedMoveResize().
|
||||
QRect desktopArea = workspace()->clientArea( WorkArea, globalPos, desktop());
|
||||
int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
|
||||
if( unrestrictedMoveResize ) // unrestricted, just don't let it go out completely
|
||||
left_marge = right_marge = top_marge = bottom_marge = titlebar_marge = 5;
|
||||
else // restricted move/resize - keep at least part of the titlebar always visible
|
||||
{
|
||||
// how much must remain visible when moved away in that direction
|
||||
left_marge = qMin( 100 + border_right, moveResizeGeom.width());
|
||||
right_marge = qMin( 100 + border_left, moveResizeGeom.width());
|
||||
// width/height change with opaque resizing, use the initial ones
|
||||
titlebar_marge = initialMoveResizeGeom.height();
|
||||
top_marge = border_bottom;
|
||||
bottom_marge = border_top;
|
||||
}
|
||||
// When doing a restricted move we must always keep 100px of the titlebar
|
||||
// visible to allow the user to be able to move it again.
|
||||
int frameLeft, frameRight, frameTop, frameBottom;
|
||||
if( decoration )
|
||||
decoration->borders( frameLeft, frameRight, frameTop, frameBottom );
|
||||
else
|
||||
frameTop = 10;
|
||||
int titlebarArea = qMin( frameTop * 100, moveResizeGeom.width() * moveResizeGeom.height() );
|
||||
|
||||
bool update = false;
|
||||
if( isResize())
|
||||
|
@ -2823,17 +2919,63 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
|
|||
// adjust new size to snap to other windows/borders
|
||||
moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode );
|
||||
|
||||
// NOTE: This is duped in checkUnrestrictedMoveResize().
|
||||
if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
|
||||
moveResizeGeom.setBottom( desktopArea.top() + top_marge );
|
||||
if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
|
||||
moveResizeGeom.setTop( desktopArea.bottom() - bottom_marge );
|
||||
if( moveResizeGeom.right() < desktopArea.left() + left_marge )
|
||||
moveResizeGeom.setRight( desktopArea.left() + left_marge );
|
||||
if( moveResizeGeom.left() > desktopArea.right() - right_marge )
|
||||
moveResizeGeom.setLeft(desktopArea.right() - right_marge );
|
||||
if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() ) // titlebar mustn't go out
|
||||
moveResizeGeom.setTop( desktopArea.top());
|
||||
// Make sure the titlebar isn't behind a restricted area. We don't need to restrict
|
||||
// the other directions. If not visible enough, move the window to the closest valid
|
||||
// point. We bruteforce this by slowly moving the window back to its previous position.
|
||||
for(;;)
|
||||
{
|
||||
QRegion titlebarRegion( moveResizeGeom.left(), moveResizeGeom.top(),
|
||||
moveResizeGeom.width(), frameTop );
|
||||
titlebarRegion &= workspace()->clientArea( FullArea, -1, 0 ); // On the screen
|
||||
titlebarRegion -= workspace()->restrictedMoveArea( desktop() ); // Strut areas
|
||||
// Now we have a region of all the visible areas of the titlebar
|
||||
// Count the visible pixels and check to see if it's enough
|
||||
int visiblePixels = 0;
|
||||
foreach( const QRect& rect, titlebarRegion.rects() )
|
||||
if( rect.height() >= frameTop ) // Only the full height regions, prevents long slim areas
|
||||
visiblePixels += rect.width() * rect.height();
|
||||
if( visiblePixels >= titlebarArea )
|
||||
break; // We have reached a valid position
|
||||
|
||||
// Not visible enough, move the window to the closest valid point. We bruteforce
|
||||
// this by slowly moving the window back to its previous position.
|
||||
if( previousMoveResizeGeom.y() != moveResizeGeom.y() )
|
||||
{
|
||||
if( previousMoveResizeGeom.y() > moveResizeGeom.y() )
|
||||
moveResizeGeom.setTop( moveResizeGeom.y() + 1 );
|
||||
else
|
||||
moveResizeGeom.setTop( moveResizeGeom.y() - 1 );
|
||||
}
|
||||
else // Our heights match but we still don't have a valid area, maybe
|
||||
{ // we are trying to resize in from the side?
|
||||
bool breakLoop = false;
|
||||
switch( mode )
|
||||
{
|
||||
case PositionTopLeft:
|
||||
case PositionLeft:
|
||||
if( previousMoveResizeGeom.x() >= moveResizeGeom.x() )
|
||||
{
|
||||
breakLoop = true;
|
||||
break;
|
||||
}
|
||||
moveResizeGeom.setLeft( moveResizeGeom.x() - 1 );
|
||||
break;
|
||||
case PositionTopRight:
|
||||
case PositionRight:
|
||||
if( previousMoveResizeGeom.right() <= moveResizeGeom.right() )
|
||||
{
|
||||
breakLoop = true;
|
||||
break;
|
||||
}
|
||||
moveResizeGeom.setRight( moveResizeGeom.x() + moveResizeGeom.width() );
|
||||
break;
|
||||
default:
|
||||
breakLoop = true;
|
||||
}
|
||||
if( breakLoop )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QSize size = adjustedSize( moveResizeGeom.size(), sizemode );
|
||||
// the new topleft and bottomright corners (after checking size constrains), if they'll be needed
|
||||
|
@ -2891,16 +3033,33 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
|
|||
moveResizeGeom.moveTopLeft( topleft );
|
||||
moveResizeGeom.moveTopLeft( workspace()->adjustClientPosition( this, moveResizeGeom.topLeft(),
|
||||
unrestrictedMoveResize ));
|
||||
// NOTE: This is duped in checkUnrestrictedMoveResize().
|
||||
if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 ) // titlebar mustn't go out
|
||||
moveResizeGeom.moveBottom( desktopArea.top() + titlebar_marge - 1 );
|
||||
// no need to check top_marge, titlebar_marge already handles it
|
||||
if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
|
||||
moveResizeGeom.moveTop( desktopArea.bottom() - bottom_marge );
|
||||
if( moveResizeGeom.right() < desktopArea.left() + left_marge )
|
||||
moveResizeGeom.moveRight( desktopArea.left() + left_marge );
|
||||
if( moveResizeGeom.left() > desktopArea.right() - right_marge )
|
||||
moveResizeGeom.moveLeft(desktopArea.right() - right_marge );
|
||||
|
||||
// Make sure the titlebar isn't behind a restricted area.
|
||||
for(;;)
|
||||
{
|
||||
QRegion titlebarRegion( moveResizeGeom.left(), moveResizeGeom.top(),
|
||||
moveResizeGeom.width(), frameTop );
|
||||
titlebarRegion &= workspace()->clientArea( FullArea, -1, 0 ); // On the screen
|
||||
titlebarRegion -= workspace()->restrictedMoveArea( desktop() ); // Strut areas
|
||||
// Now we have a region of all the visible areas of the titlebar
|
||||
// Count the visible pixels and check to see if it's enough
|
||||
int visiblePixels = 0;
|
||||
foreach( const QRect& rect, titlebarRegion.rects() )
|
||||
if( rect.height() >= frameTop ) // Only the full height regions, prevents long slim areas
|
||||
visiblePixels += rect.width() * rect.height();
|
||||
if( visiblePixels >= titlebarArea )
|
||||
break; // We have reached a valid position
|
||||
|
||||
// Move it (Favour vertically)
|
||||
if( previousMoveResizeGeom.y() != moveResizeGeom.y() )
|
||||
moveResizeGeom.translate( 0,
|
||||
previousMoveResizeGeom.y() > moveResizeGeom.y() ? 1 : -1 );
|
||||
else
|
||||
moveResizeGeom.translate( previousMoveResizeGeom.x() > moveResizeGeom.x() ? 1 : -1,
|
||||
0 );
|
||||
if( moveResizeGeom == previousMoveResizeGeom )
|
||||
break; // Prevent lockup
|
||||
}
|
||||
}
|
||||
if( moveResizeGeom.topLeft() != previousMoveResizeGeom.topLeft())
|
||||
update = true;
|
||||
|
|
|
@ -524,8 +524,6 @@ bool Client::manage( Window w, bool isMapped )
|
|||
user_time = xTime() - 1000000 + 10;
|
||||
}
|
||||
|
||||
updateWorkareaDiffs();
|
||||
|
||||
//sendSyntheticConfigureNotify(); // Done when setting mapping state
|
||||
|
||||
delete session;
|
||||
|
|
20
utils.cpp
20
utils.cpp
|
@ -57,6 +57,26 @@ namespace KWin
|
|||
|
||||
#ifndef KCMRULES
|
||||
|
||||
//************************************
|
||||
// StrutRect
|
||||
//************************************
|
||||
|
||||
StrutRect::StrutRect( QRect rect, StrutArea area )
|
||||
: QRect( rect )
|
||||
, m_area( area )
|
||||
{
|
||||
}
|
||||
|
||||
StrutRect::StrutRect( const StrutRect& other )
|
||||
: QRect( other )
|
||||
, m_area( other.area() )
|
||||
{
|
||||
}
|
||||
|
||||
//************************************
|
||||
// Motif
|
||||
//************************************
|
||||
|
||||
void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move,
|
||||
bool& minimize, bool& maximize, bool& close )
|
||||
{
|
||||
|
|
26
utils.h
26
utils.h
|
@ -127,6 +127,29 @@ enum ActivityFlags
|
|||
ActivityRaise = 1 << 2 // raise the window
|
||||
};
|
||||
|
||||
enum StrutArea
|
||||
{
|
||||
StrutAreaInvalid = 0, // Null
|
||||
StrutAreaTop = 1 << 0,
|
||||
StrutAreaRight = 1 << 1,
|
||||
StrutAreaBottom = 1 << 2,
|
||||
StrutAreaLeft = 1 << 3,
|
||||
StrutAreaAll = StrutAreaTop | StrutAreaRight | StrutAreaBottom | StrutAreaLeft
|
||||
};
|
||||
Q_DECLARE_FLAGS( StrutAreas, StrutArea )
|
||||
|
||||
class StrutRect : public QRect
|
||||
{
|
||||
public:
|
||||
StrutRect( QRect rect = QRect(), StrutArea area = StrutAreaInvalid );
|
||||
StrutRect( const StrutRect& other );
|
||||
inline StrutArea area() const
|
||||
{ return m_area; };
|
||||
private:
|
||||
StrutArea m_area;
|
||||
};
|
||||
typedef QVector<StrutRect> StrutRects;
|
||||
|
||||
// Some KWin classes, mainly Client and Workspace, are very tighly coupled,
|
||||
// and some of the methods of one class may be called only from speficic places.
|
||||
// Those methods have additional allowed_t argument. If you pass Allowed
|
||||
|
@ -342,4 +365,7 @@ class ShortcutDialog
|
|||
|
||||
} // namespace
|
||||
|
||||
// Must be outside namespace
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( KWin::StrutAreas )
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1132,6 +1132,10 @@ void Workspace::loadDesktopSettings()
|
|||
desktopCount_ = n;
|
||||
workarea.clear();
|
||||
workarea.resize( n + 1 );
|
||||
restrictedmovearea.clear();
|
||||
restrictedmovearea.resize( n + 1 );
|
||||
oldrestrictedmovearea.clear();
|
||||
oldrestrictedmovearea.resize( n + 1 );
|
||||
screenarea.clear();
|
||||
rootInfo->setNumberOfDesktops( n );
|
||||
desktop_focus_chain.resize( n );
|
||||
|
|
|
@ -90,6 +90,9 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
QRect clientArea( clientAreaOption, const Client* c ) const;
|
||||
QRect clientArea( clientAreaOption, int screen, int desktop ) const;
|
||||
|
||||
QRegion restrictedMoveArea( int desktop, StrutAreas areas = StrutAreaAll ) const;
|
||||
QRegion previousRestrictedMoveArea( int desktop, StrutAreas areas = StrutAreaAll ) const;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -853,6 +856,10 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
Placement* initPositioning;
|
||||
|
||||
QVector<QRect> workarea; // Array of workareas for virtual desktops
|
||||
// Array of restricted areas that window cannot be moved into
|
||||
QVector<StrutRects> restrictedmovearea;
|
||||
// Array of the previous restricted areas that window cannot be moved into
|
||||
QVector<StrutRects> oldrestrictedmovearea;
|
||||
QVector< QVector<QRect> > screenarea; // Array of workareas per xinerama screen for all virtual desktops
|
||||
|
||||
bool managing_topmenus;
|
||||
|
|
Loading…
Reference in a new issue