Lay out windows on all monitors in Xinerama, from "Lucas Murray" <admin@undefinedfire.com>
BUG: 157952 svn path=/trunk/KDE/kdebase/workspace/; revision=819104
This commit is contained in:
parent
e2f835e142
commit
aff5b2c2c5
2 changed files with 108 additions and 71 deletions
|
@ -343,6 +343,11 @@ void PresentWindowsEffect::effectActivated()
|
|||
hasKeyboardGrab = effects->grabKeyboard( this );
|
||||
effects->setActiveFullScreenEffect( this );
|
||||
setHighlightedWindow( effects->activeWindow());
|
||||
|
||||
screenGridSizes.clear();
|
||||
for( int i = 0; i < effects->numScreens(); i++ )
|
||||
screenGridSizes.append( GridSize() );
|
||||
numOfWindows.fill( 0, effects->numScreens() );
|
||||
}
|
||||
|
||||
void PresentWindowsEffect::effectTerminated()
|
||||
|
@ -363,8 +368,16 @@ void PresentWindowsEffect::rearrangeWindows()
|
|||
return;
|
||||
|
||||
EffectWindowList windowlist;
|
||||
QVector<EffectWindowList> windowlists;
|
||||
for( int i = 0; i < effects->numScreens(); i++ )
|
||||
windowlists.append( EffectWindowList() );
|
||||
|
||||
if( windowFilter.isEmpty())
|
||||
{
|
||||
windowlist = mWindowsToPresent;
|
||||
foreach( EffectWindow* w, mWindowsToPresent )
|
||||
windowlists[ w->screen() ].append( w );
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( EffectWindow* w, mWindowsToPresent )
|
||||
|
@ -372,7 +385,10 @@ void PresentWindowsEffect::rearrangeWindows()
|
|||
if( w->caption().contains( windowFilter, Qt::CaseInsensitive )
|
||||
|| w->windowClass().contains( windowFilter, Qt::CaseInsensitive )
|
||||
|| w->windowRole().contains( windowFilter, Qt::CaseInsensitive ))
|
||||
{
|
||||
windowlist.append( w );
|
||||
windowlists[ w->screen() ].append( w );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( windowlist.isEmpty())
|
||||
|
@ -383,11 +399,11 @@ void PresentWindowsEffect::rearrangeWindows()
|
|||
return;
|
||||
}
|
||||
|
||||
if( !mWindowData.isEmpty()) // this is not the first arranging
|
||||
// Check for changes if not the first arranging
|
||||
bool firstTime = false;
|
||||
if( !mWindowData.isEmpty())
|
||||
{
|
||||
bool rearrange = canRearrangeClosest( windowlist ); // called before manipulating mWindowData
|
||||
DataHash newdata;
|
||||
int oldcount = mWindowData.count();
|
||||
for( DataHash::ConstIterator it = mWindowData.begin();
|
||||
it != mWindowData.end();
|
||||
++it )
|
||||
|
@ -400,28 +416,42 @@ void PresentWindowsEffect::rearrangeWindows()
|
|||
{
|
||||
mWindowData[ w ].highlight = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
firstTime = true;
|
||||
|
||||
bool rearranging = false;
|
||||
QVector<int> newNumOfWindows( effects->numScreens(), 0 );
|
||||
QVector<GridSize> newScreenGridSizes( effects->numScreens() );
|
||||
for( int i = 0; i < effects->numScreens(); i++ )
|
||||
{
|
||||
newScreenGridSizes.append( GridSize() );
|
||||
|
||||
// Do not rearrange if filtering only removed windows, so that the remaining ones don't possibly
|
||||
// jump into the freed slots if they'd be a better match.
|
||||
// This can probably still lead to such things when removing the filter again, but that'd need
|
||||
// more complex remembering of window positions.
|
||||
if( !rearrange && oldcount >= mWindowData.count())
|
||||
return;
|
||||
if( mHighlightedWindow != NULL && !mWindowData.contains( mHighlightedWindow ))
|
||||
setHighlightedWindow( NULL );
|
||||
for( DataHash::Iterator it = mWindowData.begin();
|
||||
it != mWindowData.end();
|
||||
++it )
|
||||
newNumOfWindows[i] = windowlists[i].count();
|
||||
newScreenGridSizes[i].columns = int( ceil( sqrt( (double)windowlists[i].count())));
|
||||
newScreenGridSizes[i].rows = int( ceil( windowlists[i].count() / double( newScreenGridSizes[i].columns )));
|
||||
if( newNumOfWindows[i] && ( firstTime || newNumOfWindows[i] > numOfWindows[i] ||
|
||||
( newNumOfWindows[i] < numOfWindows[i] && ( newScreenGridSizes[i].rows != screenGridSizes[i].rows ||
|
||||
newScreenGridSizes[i].columns != screenGridSizes[i].columns ))))
|
||||
{
|
||||
(*it).old_area = (*it).area;
|
||||
(*it).old_scale = (*it).scale;
|
||||
if( !firstTime && !rearranging )
|
||||
{
|
||||
rearranging = true;
|
||||
prepareToRearrange();
|
||||
}
|
||||
// Calculate new positions and scales for windows
|
||||
// calculateWindowTransformationsDumb( windowlist ); // Haven't added screen support to these yet
|
||||
// calculateWindowTransformationsKompose( windowlist );
|
||||
calculateWindowTransformationsClosest( windowlists[i], i );
|
||||
}
|
||||
mRearranging = 0; // start animation again
|
||||
}
|
||||
|
||||
// Calculate new positions and scales for windows
|
||||
// calculateWindowTransformationsDumb( windowlist );
|
||||
// calculateWindowTransformationsKompose( windowlist );
|
||||
calculateWindowTransformationsClosest( windowlist );
|
||||
numOfWindows = newNumOfWindows;
|
||||
screenGridSizes = newScreenGridSizes;
|
||||
|
||||
if( !mWindowData.isEmpty() && mHighlightedWindow == NULL )
|
||||
setHighlightedWindow( findFirstWindow());
|
||||
|
@ -430,6 +460,20 @@ void PresentWindowsEffect::rearrangeWindows()
|
|||
effects->addRepaintFull();
|
||||
}
|
||||
|
||||
void PresentWindowsEffect::prepareToRearrange()
|
||||
{
|
||||
if( mHighlightedWindow != NULL && !mWindowData.contains( mHighlightedWindow ))
|
||||
setHighlightedWindow( NULL );
|
||||
for( DataHash::Iterator it = mWindowData.begin();
|
||||
it != mWindowData.end();
|
||||
++it )
|
||||
{
|
||||
(*it).old_area = (*it).area;
|
||||
(*it).old_scale = (*it).scale;
|
||||
}
|
||||
mRearranging = 0; // start animation again
|
||||
}
|
||||
|
||||
void PresentWindowsEffect::calculateWindowTransformationsDumb(EffectWindowList windowlist)
|
||||
{
|
||||
// Calculate number of rows/cols
|
||||
|
@ -440,7 +484,7 @@ void PresentWindowsEffect::calculateWindowTransformationsDumb(EffectWindowList w
|
|||
// Size of one cell
|
||||
int cellwidth = placementRect.width() / cols;
|
||||
int cellheight = placementRect.height() / rows;
|
||||
kDebug() << "Got " << windowlist.count() << " clients, using " << rows << "x" << cols << " grid";
|
||||
kDebug(1212) << "Got " << windowlist.count() << " clients, using " << rows << "x" << cols << " grid";
|
||||
|
||||
// Calculate position and scale factor for each window
|
||||
int i = 0;
|
||||
|
@ -460,7 +504,7 @@ void PresentWindowsEffect::calculateWindowTransformationsDumb(EffectWindowList w
|
|||
mWindowData[window].area.setWidth((int)(window->width() * mWindowData[window].scale));
|
||||
mWindowData[window].area.setHeight((int)(window->height() * mWindowData[window].scale));
|
||||
|
||||
kDebug() << "Window '" << window->caption() << "' gets moved to (" <<
|
||||
kDebug(1212) << "Window '" << window->caption() << "' gets moved to (" <<
|
||||
mWindowData[window].area.left() << "; " << mWindowData[window].area.right() <<
|
||||
"), scale: " << mWindowData[window].scale << endl;
|
||||
i++;
|
||||
|
@ -503,7 +547,7 @@ void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowLis
|
|||
rows = (int)ceil( sqrt((double)windowlist.count()) );
|
||||
columns = (int)ceil( (double)windowlist.count() / (double)rows );
|
||||
}
|
||||
kDebug() << "Using " << rows << " rows & " << columns << " columns for " << windowlist.count() << " clients";
|
||||
kDebug(1212) << "Using " << rows << " rows & " << columns << " columns for " << windowlist.count() << " clients";
|
||||
|
||||
// Calculate width & height
|
||||
int w = (availRect.width() - (columns+1) * spacing ) / columns;
|
||||
|
@ -615,7 +659,7 @@ void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowLis
|
|||
mWindowData[window].scale = geom.width() / (double)window->width();
|
||||
mWindowData[window].highlight = 0.0f;
|
||||
|
||||
kDebug() << "Window '" << window->caption() << "' gets moved to (" <<
|
||||
kDebug(1212) << "Window '" << window->caption() << "' gets moved to (" <<
|
||||
mWindowData[window].area.left() << "; " << mWindowData[window].area.right() <<
|
||||
"), scale: " << mWindowData[window].scale << endl;
|
||||
}
|
||||
|
@ -624,9 +668,9 @@ void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowLis
|
|||
}
|
||||
}
|
||||
|
||||
void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowList windowlist)
|
||||
void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowList windowlist, int screen)
|
||||
{
|
||||
QRect area = effects->clientArea( PlacementArea, effects->activeScreen(), effects->currentDesktop());
|
||||
QRect area = effects->clientArea( PlacementArea, screen, effects->currentDesktop());
|
||||
int columns = int( ceil( sqrt( (double)windowlist.count())));
|
||||
int rows = int( ceil( windowlist.count() / double( columns )));
|
||||
foreach( EffectWindow* w, windowlist )
|
||||
|
@ -634,9 +678,9 @@ void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowLis
|
|||
for(;;)
|
||||
{
|
||||
// Assign each window to the closest available slot
|
||||
assignSlots( area, columns, rows );
|
||||
assignSlots( windowlist, area, columns, rows );
|
||||
// Leave only the closest window in each slot, remove further conflicts
|
||||
getBestAssignments();
|
||||
getBestAssignments( windowlist );
|
||||
bool all_assigned = true;
|
||||
foreach( EffectWindow* w, windowlist )
|
||||
if( mWindowData[ w ].slot == -1 )
|
||||
|
@ -649,16 +693,14 @@ void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowLis
|
|||
}
|
||||
int slotwidth = area.width() / columns;
|
||||
int slotheight = area.height() / rows;
|
||||
for( DataHash::Iterator it = mWindowData.begin();
|
||||
it != mWindowData.end();
|
||||
++it )
|
||||
foreach( EffectWindow* w, windowlist )
|
||||
{
|
||||
QRect geom( area.x() + ((*it).slot % columns ) * slotwidth,
|
||||
area.y() + ((*it).slot / columns ) * slotheight,
|
||||
WindowData *windowData = &mWindowData[ w ];
|
||||
QRect geom( area.x() + (windowData->slot % columns ) * slotwidth,
|
||||
area.y() + (windowData->slot / columns ) * slotheight,
|
||||
slotwidth, slotheight );
|
||||
geom.adjust( 10, 10, -10, -10 ); // borders
|
||||
double scale;
|
||||
EffectWindow* w = it.key();
|
||||
if( geom.width() / double( w->width()) < geom.height() / double( w->height()))
|
||||
{ // center vertically
|
||||
scale = geom.width() / double( w->width());
|
||||
|
@ -679,29 +721,28 @@ void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowLis
|
|||
geom = QRect( geom.center().x() - w->width(), geom.center().y() - w->height(),
|
||||
2 * w->width(), 2 * w->height() );
|
||||
}
|
||||
(*it).area = geom;
|
||||
(*it).scale = scale;
|
||||
windowData->area = geom;
|
||||
windowData->scale = scale;
|
||||
}
|
||||
}
|
||||
|
||||
void PresentWindowsEffect::assignSlots( const QRect& area, int columns, int rows )
|
||||
void PresentWindowsEffect::assignSlots( EffectWindowList windowlist, const QRect& area, int columns, int rows )
|
||||
{
|
||||
QVector< bool > taken;
|
||||
taken.fill( false, columns * rows );
|
||||
foreach( const WindowData& d, mWindowData )
|
||||
foreach( EffectWindow* w, windowlist )
|
||||
{
|
||||
if( d.slot != -1 )
|
||||
taken[ d.slot ] = true;
|
||||
if( mWindowData[ w ].slot != -1 )
|
||||
taken[ mWindowData[ w ].slot ] = true;
|
||||
}
|
||||
int slotwidth = area.width() / columns;
|
||||
int slotheight = area.height() / rows;
|
||||
for( DataHash::Iterator it = mWindowData.begin();
|
||||
it != mWindowData.end();
|
||||
++it )
|
||||
foreach( EffectWindow* w, windowlist )
|
||||
{
|
||||
if( (*it).slot != -1 )
|
||||
WindowData *windowData = &mWindowData[ w ];
|
||||
if( windowData->slot != -1 )
|
||||
continue; // it already has a slot
|
||||
QPoint pos = it.key()->geometry().center();
|
||||
QPoint pos = w->geometry().center();
|
||||
if( pos.x() < area.left())
|
||||
pos.setX( area.left());
|
||||
if( pos.x() > area.right())
|
||||
|
@ -727,44 +768,32 @@ void PresentWindowsEffect::assignSlots( const QRect& area, int columns, int rows
|
|||
if( dist < distance )
|
||||
{
|
||||
distance = dist;
|
||||
(*it).slot = slot;
|
||||
(*it).x = x;
|
||||
(*it).y = y;
|
||||
(*it).slot_distance = distance;
|
||||
windowData->slot = slot;
|
||||
windowData->x = x;
|
||||
windowData->y = y;
|
||||
windowData->slot_distance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PresentWindowsEffect::getBestAssignments()
|
||||
void PresentWindowsEffect::getBestAssignments( EffectWindowList windowlist )
|
||||
{
|
||||
for( DataHash::Iterator it1 = mWindowData.begin();
|
||||
it1 != mWindowData.end();
|
||||
++it1 )
|
||||
foreach( EffectWindow* w1, windowlist )
|
||||
{
|
||||
for( DataHash::ConstIterator it2 = mWindowData.begin();
|
||||
it2 != mWindowData.end();
|
||||
++it2 )
|
||||
WindowData *windowData1 = &mWindowData[ w1 ];
|
||||
foreach( EffectWindow* w2, windowlist )
|
||||
{
|
||||
if( it1.key() != it2.key() && (*it1).slot == (*it2).slot
|
||||
&& (*it1).slot_distance >= (*it2).slot_distance )
|
||||
WindowData *windowData2 = &mWindowData[ w2 ];
|
||||
if( w1 != w2 && windowData1->slot == windowData2->slot
|
||||
&& windowData1->slot_distance >= windowData2->slot_distance )
|
||||
{
|
||||
(*it1).slot = -1;
|
||||
windowData1->slot = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PresentWindowsEffect::canRearrangeClosest(EffectWindowList windowlist)
|
||||
{
|
||||
QRect area = effects->clientArea( PlacementArea, effects->activeScreen(), effects->currentDesktop());
|
||||
int columns = int( ceil( sqrt( (double)windowlist.count())));
|
||||
int rows = int( ceil( windowlist.count() / double( columns )));
|
||||
int old_columns = int( ceil( sqrt( (double)mWindowData.count())));
|
||||
int old_rows = int( ceil( mWindowData.count() / double( columns )));
|
||||
return old_columns != columns || old_rows != rows;
|
||||
}
|
||||
|
||||
bool PresentWindowsEffect::borderActivated( ElectricBorder border )
|
||||
{
|
||||
if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this )
|
||||
|
|
|
@ -62,18 +62,18 @@ class PresentWindowsEffect
|
|||
protected:
|
||||
// Updates window tranformations, i.e. destination pos and scale of the window
|
||||
void rearrangeWindows();
|
||||
void prepareToRearrange();
|
||||
void calculateWindowTransformationsDumb(EffectWindowList windowlist);
|
||||
void calculateWindowTransformationsKompose(EffectWindowList windowlist);
|
||||
void calculateWindowTransformationsClosest(EffectWindowList windowlist);
|
||||
bool canRearrangeClosest(EffectWindowList windowlist);
|
||||
void calculateWindowTransformationsClosest(EffectWindowList windowlist, int screen);
|
||||
|
||||
// Helper methods for layout calculation
|
||||
double windowAspectRatio(EffectWindow* c);
|
||||
int windowWidthForHeight(EffectWindow* c, int h);
|
||||
int windowHeightForWidth(EffectWindow* c, int w);
|
||||
|
||||
void assignSlots( const QRect& area, int columns, int rows );
|
||||
void getBestAssignments();
|
||||
void assignSlots( EffectWindowList windowlist, const QRect& area, int columns, int rows );
|
||||
void getBestAssignments( EffectWindowList windowlist );
|
||||
|
||||
void updateFilterTexture();
|
||||
void discardFilterTexture();
|
||||
|
@ -124,7 +124,15 @@ class PresentWindowsEffect
|
|||
typedef QHash<EffectWindow*, WindowData> DataHash;
|
||||
DataHash mWindowData;
|
||||
EffectWindow* mHighlightedWindow;
|
||||
|
||||
// Grid and window remembering
|
||||
struct GridSize
|
||||
{
|
||||
int columns;
|
||||
int rows;
|
||||
};
|
||||
QVector<GridSize> screenGridSizes;
|
||||
QVector<int> numOfWindows;
|
||||
|
||||
QString windowFilter;
|
||||
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
|
||||
GLTexture* filterTexture;
|
||||
|
|
Loading…
Reference in a new issue