window and border snapping during resize operations.

Patch contributed by Christopher Suleski (linux from tildewave com): http://bugs.kde.org/show_bug.cgi?id=45805
Many thanks, Christopher.
Code inspected by Lubos Lunak.
Reviewed, slightly adapted and tested by me.
CCMAIL: 45805-done@bugs.kde.org

svn path=/trunk/kdebase/kwin/; revision=317353
This commit is contained in:
Cristian Tibirna 2004-06-03 12:36:57 +00:00
parent 32580f2f51
commit 05c003dd28
2 changed files with 213 additions and 13 deletions

View file

@ -270,19 +270,19 @@ QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
//aleXXX 02Nov2000 added second snapping mode
if (options->windowSnapZone || options->borderSnapZone )
{
bool sOWO=options->snapOnlyWhenOverlapping;
QRect maxRect = clientArea(MovementArea, pos+c->rect().center(), c->desktop());
int xmin = maxRect.left();
int xmax = maxRect.right()+1; //desk size
int ymin = maxRect.top();
int ymax = maxRect.bottom()+1;
const bool sOWO=options->snapOnlyWhenOverlapping;
const QRect maxRect = clientArea(MovementArea, pos+c->rect().center(), c->desktop());
const int xmin = maxRect.left();
const int xmax = maxRect.right()+1; //desk size
const int ymin = maxRect.top();
const int ymax = maxRect.bottom()+1;
int cx(pos.x());
int cy(pos.y());
int cw(c->width());
int ch(c->height());
int rx(cx+cw);
int ry(cy+ch); //these don't change
const int cx(pos.x());
const int cy(pos.y());
const int cw(c->width());
const int ch(c->height());
const int rx(cx+cw);
const int ry(cy+ch); //these don't change
int nx(cx), ny(cy); //buffers
int deltaX(xmax);
@ -373,6 +373,202 @@ QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
return pos;
}
QRect Workspace::adjustClientSize( Client* c, QRect moveResizeGeom, int mode )
{
//adapted from adjustClientPosition on 29May2004
//this function is called when resizing a window and will modify
//the new dimensions to snap to other windows/borders if appropriate
if ( options->windowSnapZone || options->borderSnapZone )
{
const bool sOWO=options->snapOnlyWhenOverlapping;
const QRect maxRect = clientArea(MovementArea, c->rect().center(), c->desktop());
const int xmin = maxRect.left();
const int xmax = maxRect.right()+1; //desk size
const int ymin = maxRect.top();
const int ymax = maxRect.bottom()+1;
const int cx(moveResizeGeom.left());
const int cy(moveResizeGeom.top());
const int rx(moveResizeGeom.right());
const int ry(moveResizeGeom.bottom());
int newcx(cx), newcy(cy); //buffers
int newrx(rx), newry(ry);
int deltaX(xmax);
int deltaY(ymax); //minimum distance to other clients
int lx, ly, lrx, lry; //coords and size for the comparison client, l
// border snap
int snap = options->borderSnapZone; //snap trigger
if (snap)
{
deltaX = int(snap);
deltaY = int(snap);
#define SNAP_BORDER_TOP \
if ((sOWO?(newcy<ymin):true) && (QABS(ymin-newcy)<deltaY)) \
{ \
deltaY = QABS(ymin-newcy); \
newcy = ymin; \
}
#define SNAP_BORDER_BOTTOM \
if ((sOWO?(newry>ymax):true) && (QABS(ymax-newry)<deltaY)) \
{ \
deltaY = QABS(ymax-newcy); \
newry = ymax; \
}
#define SNAP_BORDER_LEFT \
if ((sOWO?(newcx<xmin):true) && (QABS(xmin-newcx)<deltaX)) \
{ \
deltaX = QABS(xmin-newcx); \
newcx = xmin; \
}
#define SNAP_BORDER_RIGHT \
if ((sOWO?(newrx>xmax):true) && (QABS(xmax-newrx)<deltaX)) \
{ \
deltaX = QABS(xmax-newrx); \
newrx = xmax; \
}
switch ( mode )
{
case PositionBottomRight:
SNAP_BORDER_BOTTOM
SNAP_BORDER_RIGHT
break;
case PositionRight:
SNAP_BORDER_RIGHT
break;
case PositionBottom:
SNAP_BORDER_BOTTOM
break;
case PositionTopLeft:
SNAP_BORDER_TOP
SNAP_BORDER_LEFT
break;
case PositionLeft:
SNAP_BORDER_LEFT
break;
case PositionTop:
SNAP_BORDER_TOP
break;
case PositionTopRight:
SNAP_BORDER_TOP
SNAP_BORDER_RIGHT
break;
case PositionBottomLeft:
SNAP_BORDER_BOTTOM
SNAP_BORDER_LEFT
break;
default:
assert( false );
break;
}
}
// windows snap
snap = options->windowSnapZone;
if (snap)
{
deltaX = int(snap);
deltaY = int(snap);
QValueList<Client *>::ConstIterator l;
for (l = clients.begin();l != clients.end();++l )
{
if ((*l)->isOnDesktop(currentDesktop()) &&
!(*l)->isMinimized()
&& (*l) != c )
{
lx = (*l)->x();
ly = (*l)->y();
lrx = lx + (*l)->width();
lry = ly + (*l)->height();
#define WITHIN_HEIGHT ((( newcy <= lry ) && ( newcy >= ly )) || \
(( newry >= ly ) && ( newry <= lry )) || \
(( newcy <= ly ) && ( newry >= lry )) )
#define WITHIN_WIDTH ( (( cx <= lrx ) && ( cx >= lx )) || \
(( rx >= lx ) && ( rx <= lrx )) || \
(( cx <= lx ) && ( rx >= lrx )) )
#define SNAP_WINDOW_TOP if ( (sOWO?(newcy<lry):true) \
&& WITHIN_WIDTH \
&& (QABS( lry - newcy ) < deltaY) ) { \
deltaY = QABS( lry - newcy ); \
newcy=lry; \
}
#define SNAP_WINDOW_BOTTOM if ( (sOWO?(newry>ly):true) \
&& WITHIN_WIDTH \
&& (QABS( ly - newry ) < deltaY) ) { \
deltaY = QABS( ly - newry ); \
newry=ly; \
}
#define SNAP_WINDOW_LEFT if ( (sOWO?(newcx<lrx):true) \
&& WITHIN_HEIGHT \
&& (QABS( lrx - newcx ) < deltaX)) { \
deltaX = QABS( lrx - newcx ); \
newcx=lrx; \
}
#define SNAP_WINDOW_RIGHT if ( (sOWO?(newrx>lx):true) \
&& WITHIN_HEIGHT \
&& (QABS( lx - newrx ) < deltaX)) \
{ \
deltaX = QABS( lx - newrx ); \
newrx=lx; \
}
switch ( mode )
{
case PositionBottomRight:
SNAP_WINDOW_BOTTOM
SNAP_WINDOW_RIGHT
break;
case PositionRight:
SNAP_WINDOW_RIGHT
break;
case PositionBottom:
SNAP_WINDOW_BOTTOM
break;
case PositionTopLeft:
SNAP_WINDOW_TOP
SNAP_WINDOW_LEFT
break;
case PositionLeft:
SNAP_WINDOW_LEFT
break;
case PositionTop:
SNAP_WINDOW_TOP
break;
case PositionTopRight:
SNAP_WINDOW_TOP
SNAP_WINDOW_RIGHT
break;
case PositionBottomLeft:
SNAP_WINDOW_BOTTOM
SNAP_WINDOW_LEFT
break;
default:
assert( false );
break;
}
}
}
}
moveResizeGeom = QRect(QPoint(newcx, newcy), QPoint(newrx, newry));
}
return moveResizeGeom;
}
/*!
Marks the client as being moved around by the user.
*/
@ -1968,7 +2164,10 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
assert( false );
break;
}
// TODO snap
// 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 );

View file

@ -131,6 +131,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
void placeSmart( Client* c, const QRect& area );
QPoint adjustClientPosition( Client* c, QPoint pos );
QRect adjustClientSize( Client* c, QRect moveResizeGeom, int mode );
void raiseClient( Client* c );
void lowerClient( Client* c );
void raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp );