Fix Xinerama placement. Thanks to Malte S. Stretz for help with debugging

and testing.

svn path=/trunk/kdebase/kwin/; revision=278437
icc-effect-5.14.5
Luboš Luňák 2004-01-10 15:13:23 +00:00
parent 9fbfe0a925
commit 24cae23c66
6 changed files with 95 additions and 77 deletions

View File

@ -206,6 +206,7 @@ class Client : public QObject, public KDecorationDefines
// plainResize() simply resizes // plainResize() simply resizes
void plainResize( int w, int h, ForceGeometry_t force = NormalGeometrySet ); void plainResize( int w, int h, ForceGeometry_t force = NormalGeometrySet );
void plainResize( const QSize& s, ForceGeometry_t force = NormalGeometrySet ); void plainResize( const QSize& s, ForceGeometry_t force = NormalGeometrySet );
void keepInArea( const QRect& area );
void growHorizontal(); void growHorizontal();
void shrinkHorizontal(); void shrinkHorizontal();

View File

@ -312,6 +312,7 @@ void Workspace::setClientIsMoving( Client *c )
*/ */
void Workspace::cascadeDesktop() void Workspace::cascadeDesktop()
{ {
// TODO XINERAMA this probably is not right for xinerama
Q_ASSERT( block_stacking_updates == 0 ); Q_ASSERT( block_stacking_updates == 0 );
ClientList::ConstIterator it(stackingOrder().begin()); ClientList::ConstIterator it(stackingOrder().begin());
bool re_init_cascade_at_first_client = true; bool re_init_cascade_at_first_client = true;
@ -322,7 +323,7 @@ void Workspace::cascadeDesktop()
((*it)->isOnAllDesktops()) || ((*it)->isOnAllDesktops()) ||
(!(*it)->isMovable()) ) (!(*it)->isMovable()) )
continue; continue;
initPositioning->placeCascaded(*it, re_init_cascade_at_first_client); initPositioning->placeCascaded(*it, QRect(), re_init_cascade_at_first_client);
//CT is an if faster than an attribution?? //CT is an if faster than an attribution??
if (re_init_cascade_at_first_client) if (re_init_cascade_at_first_client)
re_init_cascade_at_first_client = false; re_init_cascade_at_first_client = false;
@ -343,7 +344,7 @@ void Workspace::unclutterDesktop()
((*it)->isOnAllDesktops()) || ((*it)->isOnAllDesktops()) ||
(!(*it)->isMovable()) ) (!(*it)->isMovable()) )
continue; continue;
initPositioning->placeSmart(*it); initPositioning->placeSmart(*it, QRect());
} }
} }
@ -387,6 +388,24 @@ void Workspace::updateTopMenuGeometry( Client* c )
//******************************************** //********************************************
void Client::keepInArea( const QRect& area )
{
if ( geometry().right() > area.right() && width() < area.width() )
move( area.right() - width(), y() );
if ( geometry().bottom() > area.bottom() && height() < area.height() )
move( x(), area.bottom() - height() );
if( !area.contains( geometry().topLeft() ))
{
int tx = x();
int ty = y();
if ( tx < area.x() )
tx = area.x();
if ( ty < area.y() )
ty = area.y();
move( tx, ty );
}
}
/*! /*!
Returns \a area with the client's strut taken into account. Returns \a area with the client's strut taken into account.
@ -1271,7 +1290,7 @@ void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
if( geom_restore.width() == 0 ) if( geom_restore.width() == 0 )
{ // needs placement { // needs placement
plainResize( adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH )); plainResize( adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH ));
workspace()->placeSmart( this ); workspace()->placeSmart( this, clientArea );
} }
else else
setGeometry( QRect(QPoint( geom_restore.x(), clientArea.top()), setGeometry( QRect(QPoint( geom_restore.x(), clientArea.top()),
@ -1291,7 +1310,7 @@ void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
if( geom_restore.height() == 0 ) if( geom_restore.height() == 0 )
{ // needs placement { // needs placement
plainResize( adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW )); plainResize( adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW ));
workspace()->placeSmart( this ); workspace()->placeSmart( this, clientArea );
} }
else else
setGeometry( QRect( QPoint(clientArea.left(), geom_restore.y()), setGeometry( QRect( QPoint(clientArea.left(), geom_restore.y()),
@ -1326,7 +1345,7 @@ void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
if( geom_restore.height() > 0 ) if( geom_restore.height() > 0 )
s.setHeight( geom_restore.height()); s.setHeight( geom_restore.height());
plainResize( adjustedSize( s )); plainResize( adjustedSize( s ));
workspace()->placeSmart( this ); workspace()->placeSmart( this, clientArea );
restore = geometry(); restore = geometry();
if( geom_restore.width() > 0 ) if( geom_restore.width() > 0 )
restore.moveLeft( geom_restore.x()); restore.moveLeft( geom_restore.x());

View File

@ -182,7 +182,9 @@ bool Client::manage( Window w, bool isMapped )
geom = session->geometry; geom = session->geometry;
QRect area; QRect area;
if( !isMapped && options->xineramaPlacementEnabled ) if( isMapped )
area = workspace()->clientArea( WorkArea, geom.center(), desktop());
else if( options->xineramaPlacementEnabled )
area = workspace()->clientArea( PlacementArea, QCursor::pos(), desktop()); area = workspace()->clientArea( PlacementArea, QCursor::pos(), desktop());
else else
area = workspace()->clientArea( PlacementArea, geom.center(), desktop()); area = workspace()->clientArea( PlacementArea, geom.center(), desktop());
@ -263,27 +265,12 @@ bool Client::manage( Window w, bool isMapped )
if( !placementDone ) if( !placementDone )
{ // placement needs to be after setting size { // placement needs to be after setting size
workspace()->place( this ); workspace()->place( this, area );
placementDone = TRUE; placementDone = TRUE;
} }
if (( !isSpecialWindow() || isToolbar()) && isMovable()) if (( !isSpecialWindow() || isToolbar()) && isMovable())
{ keepInArea( area );
if ( geometry().right() > area.right() && width() < area.width() )
move( area.right() - width(), y() );
if ( geometry().bottom() > area.bottom() && height() < area.height() )
move( x(), area.bottom() - height() );
if( !area.contains( geometry().topLeft() ))
{
int tx = x();
int ty = y();
if ( tx < area.x() )
tx = area.x();
if ( ty < area.y() )
ty = area.y();
move( tx, ty );
}
}
XShapeSelectInput( qt_xdisplay(), window(), ShapeNotifyMask ); XShapeSelectInput( qt_xdisplay(), window(), ShapeNotifyMask );
if ( (is_shape = Shape::hasShape( window())) ) if ( (is_shape = Shape::hasShape( window())) )

View File

@ -40,38 +40,38 @@ Placement::Placement(Workspace* w)
/*! /*!
Places the client \a c according to the workspace's layout policy Places the client \a c according to the workspace's layout policy
*/ */
void Placement::place(Client* c) void Placement::place(Client* c, QRect& area )
{ {
if( c->isUtility()) if( c->isUtility())
placeUtility(c); placeUtility(c, area);
else if( c->isDialog()) else if( c->isDialog())
placeDialog(c); placeDialog(c, area);
else if( c->isSplash()) else if( c->isSplash())
placeOnMainWindow( c ); // on mainwindow, if any, otherwise centered placeOnMainWindow( c, area ); // on mainwindow, if any, otherwise centered
else else
placeInternal(c); placeInternal(c, area);
} }
void Placement::placeInternal(Client* c) void Placement::placeInternal(Client* c, const QRect& area )
{ {
if (options->placement == Options::Random) placeAtRandom(c); if (options->placement == Options::Random) placeAtRandom(c, area);
else if (options->placement == Options::Cascade) placeCascaded(c); else if (options->placement == Options::Cascade) placeCascaded(c, area);
else if (options->placement == Options::Centered) placeCentered(c); else if (options->placement == Options::Centered) placeCentered(c, area);
else if (options->placement == Options::ZeroCornered) placeZeroCornered(c); else if (options->placement == Options::ZeroCornered) placeZeroCornered(c, area);
else placeSmart(c); else placeSmart(c, area);
} }
/*! /*!
Place the client \a c according to a simply "random" placement algorithm. Place the client \a c according to a simply "random" placement algorithm.
*/ */
void Placement::placeAtRandom(Client* c) void Placement::placeAtRandom(Client* c, const QRect& area )
{ {
const int step = 24; const int step = 24;
static int px = step; static int px = step;
static int py = 2 * step; static int py = 2 * step;
int tx,ty; int tx,ty;
const QRect maxRect = m_WorkspacePtr->clientArea( PlacementArea, c ); const QRect maxRect = checkArea( c, area );
if (px < maxRect.x()) if (px < maxRect.x())
px = maxRect.x(); px = maxRect.x();
@ -107,7 +107,7 @@ void Placement::placeAtRandom(Client* c)
/*! /*!
Place the client \a c according to a really smart placement algorithm :-) Place the client \a c according to a really smart placement algorithm :-)
*/ */
void Placement::placeSmart(Client* c) void Placement::placeSmart(Client* c, const QRect& area )
{ {
/* /*
* SmartPlacement by Cristian Tibirna (tibirna@kde.org) * SmartPlacement by Cristian Tibirna (tibirna@kde.org)
@ -129,7 +129,7 @@ void Placement::placeSmart(Client* c)
int basket; //temp holder int basket; //temp holder
// get the maximum allowed windows space // get the maximum allowed windows space
const QRect maxRect = m_WorkspacePtr->clientArea( PlacementArea, c ); const QRect maxRect = checkArea( c, area );
int x = maxRect.left(), y = maxRect.top(); int x = maxRect.left(), y = maxRect.top();
x_optimal = x; y_optimal = y; x_optimal = x; y_optimal = y;
@ -278,7 +278,7 @@ void Placement::placeSmart(Client* c)
/*! /*!
Place windows in a cascading order, remembering positions for each desktop Place windows in a cascading order, remembering positions for each desktop
*/ */
void Placement::placeCascaded (Client* c, bool re_init) void Placement::placeCascaded (Client* c, const QRect& area, bool re_init)
{ {
/* cascadePlacement by Cristian Tibirna (tibirna@kde.org) (30Jan98) /* cascadePlacement by Cristian Tibirna (tibirna@kde.org) (30Jan98)
*/ */
@ -292,8 +292,7 @@ void Placement::placeCascaded (Client* c, bool re_init)
const int dn = c->desktop() == 0 || c->isOnAllDesktops() ? (m_WorkspacePtr->currentDesktop() - 1) : (c->desktop() - 1); const int dn = c->desktop() == 0 || c->isOnAllDesktops() ? (m_WorkspacePtr->currentDesktop() - 1) : (c->desktop() - 1);
// get the maximum allowed windows space and desk's origin // get the maximum allowed windows space and desk's origin
// (CT 20Nov1999 - is this common to all desktops?) QRect maxRect = checkArea( c, area );
QRect maxRect = m_WorkspacePtr->clientArea( PlacementArea, c );
// initialize often used vars: width and height of c; we gain speed // initialize often used vars: width and height of c; we gain speed
const int ch = c->height(); const int ch = c->height();
@ -320,7 +319,7 @@ void Placement::placeCascaded (Client* c, bool re_init)
if ((xp + cw) > W) if ((xp + cw) > W)
if (!yp) if (!yp)
{ {
placeSmart(c); placeSmart(c,area);
return; return;
} }
else xp = X; else xp = X;
@ -349,7 +348,7 @@ void Placement::placeCascaded (Client* c, bool re_init)
// last resort: if still doesn't fit, smart place it // last resort: if still doesn't fit, smart place it
if (((xp + cw) > W - X) || ((yp + ch) > H - Y)) if (((xp + cw) > W - X) || ((yp + ch) > H - Y))
{ {
placeSmart(c); placeSmart(c,area);
return; return;
} }
} }
@ -364,12 +363,11 @@ void Placement::placeCascaded (Client* c, bool re_init)
/*! /*!
Place windows centered, on top of all others Place windows centered, on top of all others
*/ */
void Placement::placeCentered (Client* c) void Placement::placeCentered (Client* c, const QRect& area )
{ {
// get the maximum allowed windows space and desk's origin // get the maximum allowed windows space and desk's origin
// (CT 20Nov1999 - is this common to all desktops?) const QRect maxRect = checkArea( c, area );
const QRect maxRect = m_WorkspacePtr->clientArea( PlacementArea, c );
const int xp = maxRect.left() + (maxRect.width() - c->width()) / 2; const int xp = maxRect.left() + (maxRect.width() - c->width()) / 2;
const int yp = maxRect.top() + (maxRect.height() - c->height()) / 2; const int yp = maxRect.top() + (maxRect.height() - c->height()) / 2;
@ -381,69 +379,73 @@ void Placement::placeCentered (Client* c)
/*! /*!
Place windows in the (0,0) corner, on top of all others Place windows in the (0,0) corner, on top of all others
*/ */
void Placement::placeZeroCornered(Client* c) void Placement::placeZeroCornered(Client* c, const QRect& area )
{ {
// get the maximum allowed windows space and desk's origin // get the maximum allowed windows space and desk's origin
// (CT 20Nov1999 - is this common to all desktops?) const QRect maxRect = checkArea( c, area );
const QRect maxRect = m_WorkspacePtr->clientArea( PlacementArea, c );
// place the window // place the window
c->move(QPoint(maxRect.left(), maxRect.top())); c->move(QPoint(maxRect.left(), maxRect.top()));
} }
void Placement::placeUtility(Client* c) void Placement::placeUtility(Client* c, QRect& area )
{ {
// TODO kwin should try to place utility windows next to their mainwindow, // TODO kwin should try to place utility windows next to their mainwindow,
// preferably at the right edge, and going down if there are more of them // preferably at the right edge, and going down if there are more of them
// if there's not enough place outside the mainwindow, it should prefer // if there's not enough place outside the mainwindow, it should prefer
// top-right corner // top-right corner
// use the default placement for now // use the default placement for now
placeInternal( c ); placeInternal( c, area );
} }
void Placement::placeDialog(Client* c) void Placement::placeDialog(Client* c, QRect& area )
{ {
// if the dialog is actually non-NETWM transient window, don't apply placement to it, // if the dialog is actually non-NETWM transient window, don't apply placement to it,
// it breaks with too many things (xmms, display) // it breaks with too many things (xmms, display)
if( !c->hasNETSupport()) if( !c->hasNETSupport())
return; return;
placeOnMainWindow( c ); placeOnMainWindow( c, area );
} }
void Placement::placeUnderMouse(Client* c) void Placement::placeUnderMouse(Client* c, QRect& area )
{ {
area = checkArea( c, area );
QRect geom = c->geometry(); QRect geom = c->geometry();
geom.moveCenter( QCursor::pos()); geom.moveCenter( QCursor::pos());
c->move( geom.topLeft()); c->move( geom.topLeft());
c->keepInArea( area ); // make sure it's kept inside workarea
} }
void Placement::placeOnMainWindow(Client* c) void Placement::placeOnMainWindow(Client* c, QRect& area )
{ {
area = checkArea( c, area );
ClientList mainwindows = c->mainClients(); ClientList mainwindows = c->mainClients();
Client* place_on = NULL; Client* place_on = NULL;
int mains_count = 0;
for( ClientList::ConstIterator it = mainwindows.begin(); for( ClientList::ConstIterator it = mainwindows.begin();
it != mainwindows.end(); it != mainwindows.end();
++it ) ++it )
{ {
if( (*it)->isSpecialWindow() && !(*it)->isOverride()) if( (*it)->isSpecialWindow() && !(*it)->isOverride())
continue; // don't consider toolbars etc when placing continue; // don't consider toolbars etc when placing
++mains_count;
if( (*it)->isOnCurrentDesktop()) if( (*it)->isOnCurrentDesktop())
{ {
if( place_on == NULL ) if( place_on == NULL )
place_on = *it; place_on = *it;
else else
{ // two or more on current desktop -> center { // two or more on current desktop -> center
placeCentered( c ); placeCentered( c, area );
return; return;
} }
} }
} }
if( place_on == NULL ) if( place_on == NULL )
{ { // 'mains_count' is used because it doesn't include ignored mainwindows
if( mainwindows.count() != 1 ) if( mains_count != 1 )
{ {
placeCentered( c ); placeCentered( c, area );
return; return;
} }
place_on = mainwindows.first(); place_on = mainwindows.first();
@ -451,6 +453,15 @@ void Placement::placeOnMainWindow(Client* c)
QRect geom = c->geometry(); QRect geom = c->geometry();
geom.moveCenter( place_on->geometry().center()); geom.moveCenter( place_on->geometry().center());
c->move( geom.topLeft()); c->move( geom.topLeft());
// get area again, because the mainwindow may be on different xinerama screen
area = checkArea( c, QRect());
}
QRect Placement::checkArea( const Client* c, const QRect& area )
{
if( area.isNull())
return m_WorkspacePtr->clientArea( PlacementArea, c->geometry().center(), c->desktop());
return area;
} }
// ******************** // ********************
@ -666,15 +677,14 @@ int Workspace::packPositionDown( const Client* cl, int oldy, bool bottom_edge )
/*! /*!
Asks the internal positioning object to place a client Asks the internal positioning object to place a client
*/ */
void Workspace::place(Client* c) void Workspace::place(Client* c, QRect& area)
{ {
initPositioning->place(c); initPositioning->place( c, area );
} }
void Workspace::placeSmart(Client* c) void Workspace::placeSmart(Client* c, const QRect& area)
{ {
initPositioning->placeSmart(c); initPositioning->placeSmart( c, area );
} }
} // namespace } // namespace

View File

@ -28,21 +28,22 @@ class Placement
Placement(Workspace* w); Placement(Workspace* w);
void place(Client* c); void place(Client* c, QRect& area );
void placeAtRandom (Client* c); void placeAtRandom (Client* c, const QRect& area );
void placeCascaded (Client* c, bool re_init = false); void placeCascaded (Client* c, const QRect& area, bool re_init = false);
void placeSmart (Client* c); void placeSmart (Client* c, const QRect& area );
void placeCentered (Client* c); void placeCentered (Client* c, const QRect& area );
void placeZeroCornered(Client* c); void placeZeroCornered(Client* c, const QRect& area );
void placeDialog (Client* c); void placeDialog (Client* c, QRect& area );
void placeUtility (Client* c); void placeUtility (Client* c, QRect& area );
private: private:
void placeInternal(Client* c); void placeInternal(Client* c, const QRect& area );
void placeUnderMouse(Client* c); void placeUnderMouse(Client* c, QRect& area );
void placeOnMainWindow(Client* c); void placeOnMainWindow(Client* c, QRect& area );
QRect checkArea( const Client*c, const QRect& area );
Placement(); Placement();

View File

@ -126,8 +126,8 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
*/ */
void setClientIsMoving( Client *c ); void setClientIsMoving( Client *c );
void place(Client *c); void place( Client *c, QRect& area );
void placeSmart( Client* c ); void placeSmart( Client* c, const QRect& area );
QPoint adjustClientPosition( Client* c, QPoint pos ); QPoint adjustClientPosition( Client* c, QPoint pos );
void raiseClient( Client* c ); void raiseClient( Client* c );