1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee>
6 Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
22 #include "presentwindows.h"
24 #include <kactioncollection.h>
27 #include <kcolorscheme.h>
28 #include <kconfiggroup.h>
31 #include <QMouseEvent>
41 KWIN_EFFECT( presentwindows
, PresentWindowsEffect
)
43 PresentWindowsEffect::PresentWindowsEffect()
44 : m_borderActivate( ElectricNone
)
45 , m_borderActivateAll( ElectricNone
)
46 , m_activated( false )
47 , m_allDesktops( false )
48 , m_ignoreMinimized( false )
49 , m_decalOpacity( 0.0 )
51 , m_hasKeyboardGrab( false )
52 , m_tabBoxEnabled( false )
55 , m_highlightedWindow( NULL
)
58 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
59 , m_filterTexture( NULL
)
60 //, m_filterTextureRect()
61 //, m_filterFrameRect()
64 KActionCollection
* actionCollection
= new KActionCollection( this );
65 KAction
* a
= ( KAction
* )actionCollection
->addAction( "Expose" );
66 a
->setText( i18n( "Toggle Present Windows (Current desktop)" ));
67 a
->setGlobalShortcut( KShortcut( Qt::CTRL
+ Qt::Key_F9
));
68 connect( a
, SIGNAL( triggered(bool) ), this, SLOT( toggleActive() ));
69 KAction
* b
= ( KAction
* )actionCollection
->addAction( "ExposeAll" );
70 b
->setText( i18n( "Toggle Present Windows (All desktops)" ));
71 b
->setGlobalShortcut( KShortcut( Qt::CTRL
+ Qt::Key_F10
));
72 connect( b
, SIGNAL( triggered(bool) ), this, SLOT( toggleActiveAllDesktops() ));
73 reconfigure( ReconfigureAll
);
76 PresentWindowsEffect::~PresentWindowsEffect()
78 effects
->unreserveElectricBorder( m_borderActivate
);
79 effects
->unreserveElectricBorder( m_borderActivateAll
);
80 discardFilterTexture();
83 void PresentWindowsEffect::reconfigure( ReconfigureFlags
)
85 KConfigGroup conf
= effects
->effectConfig("PresentWindows");
86 effects
->unreserveElectricBorder( m_borderActivate
);
87 effects
->unreserveElectricBorder( m_borderActivateAll
);
88 m_borderActivate
= ElectricBorder( conf
.readEntry( "BorderActivate", int( ElectricNone
)));
89 m_borderActivateAll
= ElectricBorder( conf
.readEntry( "BorderActivateAll", int( ElectricTopLeft
)));
90 effects
->reserveElectricBorder( m_borderActivate
);
91 effects
->reserveElectricBorder( m_borderActivateAll
);
92 m_layoutMode
= conf
.readEntry( "LayoutMode", int( LayoutNatural
));
93 m_showCaptions
= conf
.readEntry( "DrawWindowCaptions", true );
94 m_showIcons
= conf
.readEntry( "DrawWindowIcons", true );
95 m_tabBoxAllowed
= conf
.readEntry( "TabBox", false );
96 m_ignoreMinimized
= conf
.readEntry( "IgnoreMinimized", false );
97 m_accuracy
= conf
.readEntry( "Accuracy", 1 ) * 20;
98 m_fillGaps
= conf
.readEntry( "FillGaps", true );
99 m_fadeDuration
= double( animationTime( 150 ));
100 m_showPanel
= conf
.readEntry( "ShowPanel", false );
103 //-----------------------------------------------------------------------------
106 void PresentWindowsEffect::prePaintScreen( ScreenPrePaintData
&data
, int time
)
108 m_motionManager
.calculate( time
);
110 // We need to mark the screen as having been transformed otherwise there will be no repainting
111 if( m_activated
|| m_motionManager
.managingWindows() )
112 data
.mask
|= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS
;
115 m_decalOpacity
= qMin( 1.0, m_decalOpacity
+ time
/ m_fadeDuration
);
117 m_decalOpacity
= qMax( 0.0, m_decalOpacity
- time
/ m_fadeDuration
);
119 effects
->prePaintScreen( data
, time
);
122 void PresentWindowsEffect::paintScreen( int mask
, QRegion region
, ScreenPaintData
&data
)
124 effects
->paintScreen( mask
, region
, data
);
126 // Display the filter box
127 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
128 if( m_filterTexture
&& region
.intersects( m_filterFrameRect
))
130 glPushAttrib( GL_CURRENT_BIT
| GL_ENABLE_BIT
);
131 glEnable( GL_BLEND
);
132 glBlendFunc( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
134 // First render the frame
135 QColor color
= QPalette().color( QPalette::Active
, QPalette::Highlight
);
136 glColor4f( color
.redF(), color
.greenF(), color
.blueF(), 0.75f
);
137 renderRoundBoxWithEdge( m_filterFrameRect
);
139 // Then the text on top of it
140 m_filterTexture
->bind();
141 m_filterTexture
->render( region
, m_filterTextureRect
);
142 m_filterTexture
->unbind();
148 void PresentWindowsEffect::postPaintScreen()
150 if( m_motionManager
.areWindowsMoving() )
151 effects
->addRepaintFull();
152 else if( !m_activated
&& m_motionManager
.managingWindows() )
153 { // We have finished moving them back, stop processing
154 m_motionManager
.unmanageAll();
155 m_windowData
.clear();
156 effects
->setActiveFullScreenEffect( NULL
);
159 // Update windows that are changing brightness or opacity
160 foreach( EffectWindow
*w
, m_windowData
.keys() )
162 if( m_windowData
[w
].opacity
> 0.0 && m_windowData
[w
].opacity
< 1.0 )
164 if( m_windowData
[w
].highlight
> 0.0 && m_windowData
[w
].highlight
< 1.0 )
168 effects
->postPaintScreen();
171 //-----------------------------------------------------------------------------
174 void PresentWindowsEffect::prePaintWindow( EffectWindow
*w
, WindowPrePaintData
&data
, int time
)
176 // TODO: We should also check to see if any windows are fading just in case fading takes longer
177 // than moving the windows when the effect is deactivated.
178 if( m_activated
|| m_motionManager
.areWindowsMoving() )
180 w
->enablePainting( EffectWindow::PAINT_DISABLED_BY_MINIMIZE
); // Display always
181 w
->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP
);
183 // Calculate window's opacity
184 // TODO: Minimized windows or windows not on the current desktop are only 75% visible?
185 if( m_windowData
[w
].visible
)
186 m_windowData
[w
].opacity
= qMin(/*( w->isMinimized() || !w->isOnCurrentDesktop() ) ? 0.75 :*/ 1.0,
187 m_windowData
[w
].opacity
+ time
/ m_fadeDuration
);
189 m_windowData
[w
].opacity
= qMax( 0.0, m_windowData
[w
].opacity
- time
/ m_fadeDuration
);
190 if( m_windowData
[w
].opacity
== 0.0 )
192 // don't disable painting for panels if show panel is set
193 if( !w
->isDock() || ( w
->isDock() && !m_showPanel
))
194 w
->disablePainting( EffectWindow::PAINT_DISABLED
);
196 else if( m_windowData
[w
].opacity
!= 1.0 )
197 data
.setTranslucent();
199 // Calculate window's brightness
200 if( w
== m_highlightedWindow
|| !m_activated
)
201 m_windowData
[w
].highlight
= qMin( 1.0, m_windowData
[w
].highlight
+ time
/ m_fadeDuration
);
203 m_windowData
[w
].highlight
= qMax( 0.0, m_windowData
[w
].highlight
- time
/ m_fadeDuration
);
205 if( m_motionManager
.isManaging( w
))
206 data
.setTransformed(); // We will be moving this window
208 effects
->prePaintWindow( w
, data
, time
);
211 void PresentWindowsEffect::paintWindow( EffectWindow
*w
, int mask
, QRegion region
, WindowPaintData
&data
)
213 if( m_activated
|| m_motionManager
.areWindowsMoving() )
215 if( w
->isDock() && m_showPanel
)
217 // in case the panel should be shown just display it without any changes
218 effects
->paintWindow( w
, mask
, region
, data
);
221 // Apply opacity and brightness
222 data
.opacity
*= m_windowData
[w
].opacity
;
223 data
.brightness
*= interpolate( 0.7, 1.0, m_windowData
[w
].highlight
);
225 if( m_motionManager
.isManaging( w
))
227 m_motionManager
.apply( w
, data
);
229 effects
->paintWindow( w
, mask
, region
, data
);
231 const WindowData
&wData
= m_windowData
[w
];
233 paintWindowIcon( w
, data
);
236 QString text
= w
->caption();
237 QRect
textArea( w
->x() + data
.xTranslate
, w
->y() + data
.yTranslate
,
238 w
->width() * data
.xScale
, w
->height() * data
.yScale
);
239 textArea
.adjust( 10, 10, -10, -10 );
240 double opacity
= (0.7 + 0.2 * wData
.highlight
) * data
.opacity
* m_decalOpacity
;
241 QColor
textcolor( 255, 255, 255, int( 255 * opacity
));
242 QColor
bgcolor( 0, 0, 0, int( 255 * opacity
));
245 f
.setPointSize( 12 );
246 effects
->paintTextWithBackground( text
, textArea
, textcolor
, bgcolor
, f
);
250 effects
->paintWindow( w
, mask
, region
, data
);
253 effects
->paintWindow( w
, mask
, region
, data
);
256 //-----------------------------------------------------------------------------
259 void PresentWindowsEffect::windowAdded( EffectWindow
*w
)
261 m_windowData
[w
].visible
= isVisibleWindow( w
);
262 m_windowData
[w
].opacity
= 0.0;
263 m_windowData
[w
].highlight
= 0.0;
264 if( isSelectableWindow( w
))
266 m_motionManager
.manage( w
);
271 void PresentWindowsEffect::windowClosed( EffectWindow
*w
)
273 if( m_highlightedWindow
== w
)
274 setHighlightedWindow( findFirstWindow() );
275 m_windowData
[w
].visible
= false; // TODO: Fix this so they do actually fade out
279 void PresentWindowsEffect::windowDeleted( EffectWindow
*w
)
281 m_windowData
.remove( w
);
282 m_motionManager
.unmanage( w
);
285 bool PresentWindowsEffect::borderActivated( ElectricBorder border
)
287 if( effects
->activeFullScreenEffect() && effects
->activeFullScreenEffect() != this )
289 if( border
== m_borderActivate
&& !m_activated
)
294 if( border
== m_borderActivateAll
&& !m_activated
)
296 toggleActiveAllDesktops();
302 void PresentWindowsEffect::windowInputMouseEvent( Window w
, QEvent
*e
)
304 assert( w
== m_input
);
306 // Which window are we hovering over? Always trigger as we don't always get move events before clicking
307 // We cannot use m_motionManager.windowAtPoint() as the window might not be visible
308 EffectWindowList windows
= m_motionManager
.managedWindows();
309 for( int i
= 0; i
< windows
.size(); i
++ )
311 if( m_motionManager
.transformedGeometry( windows
.at( i
)).contains( cursorPos() ) &&
312 m_windowData
[windows
.at( i
)].visible
)
314 if( windows
.at( i
) && m_highlightedWindow
!= windows
.at( i
))
315 setHighlightedWindow( windows
.at( i
));
320 if( e
->type() != QEvent::MouseButtonPress
)
323 QMouseEvent
* me
= static_cast<QMouseEvent
*>( e
);
324 if( me
->button() == Qt::LeftButton
)
326 if( m_highlightedWindow
)
327 effects
->activateWindow( m_highlightedWindow
);
330 // TODO: User mouse actions. E.g. right-click stickies and middle-click brings to current desktop
333 void PresentWindowsEffect::grabbedKeyboardEvent( QKeyEvent
*e
)
335 if( e
->type() == QEvent::KeyPress
)
338 { // Wrap only if not auto-repeating
340 setHighlightedWindow( relativeWindow( m_highlightedWindow
, -1, 0, !e
->isAutoRepeat() ));
343 setHighlightedWindow( relativeWindow( m_highlightedWindow
, 1, 0, !e
->isAutoRepeat() ));
346 setHighlightedWindow( relativeWindow( m_highlightedWindow
, 0, -1, !e
->isAutoRepeat() ));
349 setHighlightedWindow( relativeWindow( m_highlightedWindow
, 0, 1, !e
->isAutoRepeat() ));
352 setHighlightedWindow( relativeWindow( m_highlightedWindow
, -1000, 0, false ));
355 setHighlightedWindow( relativeWindow( m_highlightedWindow
, 1000, 0, false ));
358 setHighlightedWindow( relativeWindow( m_highlightedWindow
, 0, -1000, false ));
360 case Qt::Key_PageDown
:
361 setHighlightedWindow( relativeWindow( m_highlightedWindow
, 0, 1000, false ));
363 case Qt::Key_Backspace
:
364 if( !m_windowFilter
.isEmpty() )
366 m_windowFilter
.remove( m_windowFilter
.length() - 1, 1 );
367 updateFilterTexture();
376 if( m_highlightedWindow
)
377 effects
->activateWindow( m_highlightedWindow
);
381 return; // Nothing at the moment
383 if( !m_windowFilter
.isEmpty() )
385 m_windowFilter
.clear();
386 updateFilterTexture();
391 return; // HACK: Workaround for Qt bug on unbound keys (#178547)
393 if( !e
->text().isEmpty() )
395 m_windowFilter
.append( e
->text() );
396 updateFilterTexture();
405 //-----------------------------------------------------------------------------
408 void PresentWindowsEffect::tabBoxAdded( int mode
)
410 if( effects
->activeFullScreenEffect() && effects
->activeFullScreenEffect() != this )
414 if( !m_tabBoxAllowed
)
416 if( mode
== TabBoxWindowsMode
&& effects
->currentTabBoxWindowList().count() > 0 )
418 m_tabBoxEnabled
= true;
421 effects
->refTabBox();
425 void PresentWindowsEffect::tabBoxClosed()
429 effects
->unrefTabBox();
430 setActive( false, true );
431 m_tabBoxEnabled
= false;
435 void PresentWindowsEffect::tabBoxUpdated()
438 setHighlightedWindow( effects
->currentTabBoxWindow() );
441 //-----------------------------------------------------------------------------
442 // Window rearranging
444 void PresentWindowsEffect::rearrangeWindows()
449 effects
->addRepaintFull(); // Trigger the first repaint
451 // Work out which windows are on which screens
452 EffectWindowList windowlist
;
453 QList
<EffectWindowList
> windowlists
;
454 for( int i
= 0; i
< effects
->numScreens(); i
++ )
455 windowlists
.append( EffectWindowList() );
457 if( m_windowFilter
.isEmpty() )
459 if( m_tabBoxEnabled
)
460 // Assume we correctly set things up, should be identical to
461 // m_motionManager except just in a slightly different order.
462 windowlist
= effects
->currentTabBoxWindowList();
464 windowlist
= m_motionManager
.managedWindows();
465 foreach( EffectWindow
*w
, m_motionManager
.managedWindows() )
467 windowlists
[w
->screen()].append( w
);
468 m_windowData
[w
].visible
= true;
472 { // Can we move this filtering somewhere else?
473 foreach( EffectWindow
*w
, m_motionManager
.managedWindows() )
475 if( w
->caption().contains( m_windowFilter
, Qt::CaseInsensitive
) ||
476 w
->windowClass().contains( m_windowFilter
, Qt::CaseInsensitive
) ||
477 w
->windowRole().contains( m_windowFilter
, Qt::CaseInsensitive
))
479 windowlist
.append( w
);
480 windowlists
[w
->screen()].append( w
);
481 m_windowData
[w
].visible
= true;
484 m_windowData
[w
].visible
= false;
487 if( windowlist
.isEmpty() )
489 setHighlightedWindow( NULL
); // TODO: Having a NULL highlighted window isn't really safe
493 // We filtered out the highlighted window
494 if( m_highlightedWindow
)
496 if( m_windowData
[m_highlightedWindow
].visible
== false )
497 setHighlightedWindow( findFirstWindow() );
500 setHighlightedWindow( findFirstWindow() );
502 int screens
= m_tabBoxEnabled
? 1 : effects
->numScreens();
503 for( int screen
= 0; screen
< screens
; screen
++ )
505 EffectWindowList windows
;
506 if( m_tabBoxEnabled
)
507 { // Kind of cheating here
508 screen
= effects
->activeScreen();
509 windows
= windowlist
;
512 windows
= windowlists
[screen
];
514 // Don't rearrange if the grid is the same size as what it was before to prevent
515 // windows moving to a better spot if one was filtered out.
516 if( m_layoutMode
== LayoutRegularGrid
&&
517 m_gridSizes
[screen
].columns
* m_gridSizes
[screen
].rows
&&
518 windows
.size() < m_gridSizes
[screen
].columns
* m_gridSizes
[screen
].rows
&&
519 windows
.size() > ( m_gridSizes
[screen
].columns
- 1) * m_gridSizes
[screen
].rows
&&
520 windows
.size() > m_gridSizes
[screen
].columns
* ( m_gridSizes
[screen
].rows
- 1 ))
523 // No point continuing if there is no windows to process
524 if( !windows
.count() )
527 if( m_layoutMode
== LayoutRegularGrid
|| m_tabBoxEnabled
) // Force the grid for window switching
528 calculateWindowTransformationsClosest( windows
, screen
);
529 else if( m_layoutMode
== LayoutFlexibleGrid
)
530 calculateWindowTransformationsKompose( windows
, screen
);
532 calculateWindowTransformationsNatural( windows
, screen
);
536 void PresentWindowsEffect::calculateWindowTransformationsClosest( EffectWindowList windowlist
, int screen
)
538 QRect area
= effects
->clientArea( ScreenArea
, screen
, effects
->currentDesktop() );
539 if( m_showPanel
) // reserve space for the panel
540 area
= effects
->clientArea( MaximizeArea
, screen
, effects
->currentDesktop() );
541 int columns
= int( ceil( sqrt( double( windowlist
.count() ))));
542 int rows
= int( ceil( windowlist
.count() / double( columns
)));
544 // Remember the size for later
545 m_gridSizes
[screen
].columns
= columns
;
546 m_gridSizes
[screen
].rows
= rows
;
549 foreach( EffectWindow
*w
, windowlist
)
550 m_windowData
[w
].slot
= -1;
551 if( m_tabBoxEnabled
)
552 { // Rearrange in the correct order. As rearrangeWindows() is only ever
553 // called once so we can use effects->currentTabBoxWindow() here.
554 int selectedWindow
= qMax( 0, windowlist
.indexOf( effects
->currentTabBoxWindow() ));
556 for( int i
= selectedWindow
; i
< windowlist
.count(); i
++ )
557 m_windowData
[windowlist
[i
]].slot
= slot
++;
558 for( int i
= selectedWindow
- 1; i
>= 0; i
-- )
559 m_windowData
[windowlist
[i
]].slot
= slot
++;
565 // Assign each window to the closest available slot
566 assignSlots( windowlist
, area
, columns
, rows
);
567 // Leave only the closest window in each slot, remove further conflicts
568 getBestAssignments( windowlist
);
569 bool allAssigned
= true;
570 foreach( EffectWindow
*w
, windowlist
)
571 if( m_windowData
[w
].slot
== -1 )
581 int slotWidth
= area
.width() / columns
;
582 int slotHeight
= area
.height() / rows
;
583 foreach( EffectWindow
*w
, windowlist
)
585 assert( m_windowData
[w
].slot
!= -1 );
587 // Work out where the slot is
589 area
.x() + ( m_windowData
[w
].slot
% columns
) * slotWidth
,
590 area
.y() + ( m_windowData
[w
].slot
/ columns
) * slotHeight
,
591 slotWidth
, slotHeight
);
592 target
.adjust( 10, 10, -10, -10 ); // Borders
594 if( target
.width() / double( w
->width() ) < target
.height() / double( w
->height() ))
595 { // Center vertically
596 scale
= target
.width() / double( w
->width() );
597 target
.moveTop( target
.top() + ( target
.height() - int( w
->height() * scale
)) / 2 );
598 target
.setHeight( int( w
->height() * scale
));
601 { // Center horizontally
602 scale
= target
.height() / double( w
->height() );
603 target
.moveLeft( target
.left() + ( target
.width() - int( w
->width() * scale
)) / 2 );
604 target
.setWidth( int( w
->width() * scale
));
606 // Don't scale the windows too much
607 if( scale
> 2.0 || ( scale
> 1.0 && ( w
->width() > 300 || w
->height() > 300 )))
609 scale
= ( w
->width() > 300 || w
->height() > 300 ) ? 1.0 : 2.0;
611 target
.center().x() - int( w
->width() * scale
) / 2,
612 target
.center().y() - int( w
->height() * scale
) / 2,
613 scale
* w
->width(), scale
* w
->height() );
615 m_motionManager
.moveWindow( w
, target
);
619 void PresentWindowsEffect::calculateWindowTransformationsKompose( EffectWindowList windowlist
, int screen
)
621 QRect availRect
= effects
->clientArea( ScreenArea
, screen
, effects
->currentDesktop() );
622 if( m_showPanel
) // reserve space for the panel
623 availRect
= effects
->clientArea( MaximizeArea
, screen
, effects
->currentDesktop() );
624 qSort( windowlist
); // The location of the windows should not depend on the stacking order
626 // Following code is taken from Kompose 0.5.4, src/komposelayout.cpp
630 double parentRatio
= availRect
.width() / (double)availRect
.height();
631 // Use more columns than rows when parent's width > parent's height
632 if ( parentRatio
> 1 )
634 columns
= (int)ceil( sqrt((double)windowlist
.count()) );
635 rows
= (int)ceil( (double)windowlist
.count() / (double)columns
);
639 rows
= (int)ceil( sqrt((double)windowlist
.count()) );
640 columns
= (int)ceil( (double)windowlist
.count() / (double)rows
);
642 //kDebug(1212) << "Using " << rows << " rows & " << columns << " columns for " << windowlist.count() << " clients";
644 // Calculate width & height
645 int w
= (availRect
.width() - (columns
+1) * spacing
) / columns
;
646 int h
= (availRect
.height() - (rows
+1) * spacing
) / rows
;
648 EffectWindowList::iterator
it( windowlist
.begin() );
649 QList
<QRect
> geometryRects
;
650 QList
<int> maxRowHeights
;
652 for ( int i
=0; i
<rows
; ++i
)
654 int xOffsetFromLastCol
= 0;
655 int maxHeightInRow
= 0;
657 for ( int j
=0; j
<columns
; ++j
)
659 EffectWindow
* window
;
661 // Check for end of List
662 if ( it
== windowlist
.end() )
666 // Calculate width and height of widget
667 double ratio
= aspectRatio( window
);
674 // use width of two boxes if there is no right neighbour
675 if (window
== windowlist
.last() && j
!= columns
-1)
679 ++it
; // We need access to the neighbour in the following
680 // expand if right neighbour has ratio < 1
681 if (j
!= columns
-1 && it
!= windowlist
.end() && aspectRatio(*it
) < 1)
683 int addW
= w
- widthForHeight(*it
, h
);
697 double widthByHeight
= widthForHeight( window
, usableH
);
698 double heightByWidth
= heightForWidth( window
, usableW
);
699 if ( (ratio
>= 1.0 && heightByWidth
<= usableH
) ||
700 (ratio
< 1.0 && widthByHeight
> usableW
) )
703 widgeth
= (int)heightByWidth
;
705 else if ( (ratio
< 1.0 && widthByHeight
<= usableW
) ||
706 (ratio
>= 1.0 && heightByWidth
> usableH
) )
709 widgetw
= (int)widthByHeight
;
711 // Don't upscale large-ish windows
712 if( widgetw
> window
->width() && ( window
->width() > 300 || window
->height() > 300 ))
714 widgetw
= window
->width();
715 widgeth
= window
->height();
719 // Set the Widget's size
721 int alignmentXoffset
= 0;
722 int alignmentYoffset
= 0;
723 if ( i
==0 && h
> widgeth
)
724 alignmentYoffset
= h
- widgeth
;
725 if ( j
==0 && w
> widgetw
)
726 alignmentXoffset
= w
- widgetw
;
727 QRect
geom( availRect
.x() + j
* (w
+ spacing
) + spacing
+ alignmentXoffset
+ xOffsetFromLastCol
,
728 availRect
.y() + i
* (h
+ spacing
) + spacing
+ alignmentYoffset
,
730 geometryRects
.append(geom
);
732 // Set the x offset for the next column
733 if (alignmentXoffset
==0)
734 xOffsetFromLastCol
+= widgetw
-w
;
735 if (maxHeightInRow
< widgeth
)
736 maxHeightInRow
= widgeth
;
738 maxRowHeights
.append(maxHeightInRow
);
742 for( int i
= 0; i
< rows
; i
++ )
744 for( int j
= 0; j
< columns
; j
++ )
746 int pos
= i
*columns
+ j
;
747 if(pos
>= windowlist
.count())
750 EffectWindow
* window
= windowlist
[pos
];
751 QRect target
= geometryRects
[pos
];
752 target
.setY( target
.y() + topOffset
);
753 m_windowData
[window
].slot
= pos
;
754 m_motionManager
.moveWindow( window
, target
);
756 //kDebug(1212) << "Window '" << window->caption() << "' gets moved to (" <<
757 // mWindowData[window].area.left() << "; " << mWindowData[window].area.right() <<
758 // "), scale: " << mWindowData[window].scale << endl;
760 if ( maxRowHeights
[i
]-h
> 0 )
761 topOffset
+= maxRowHeights
[i
]-h
;
765 void PresentWindowsEffect::calculateWindowTransformationsNatural( EffectWindowList windowlist
, int screen
)
767 // If windows do not overlap they scale into nothingness, fix by resetting. To reproduce
768 // just have a single window on a Xinerama screen or have two windows that do not touch.
769 // TODO: Work out why this happens, is most likely a bug in the manager.
770 foreach( EffectWindow
*w
, windowlist
)
771 if( m_motionManager
.transformedGeometry( w
) == w
->geometry() )
772 m_motionManager
.reset( w
);
774 if( windowlist
.count() == 1 )
776 // Just move the window to its original location to save time
777 m_motionManager
.moveWindow( windowlist
[0], windowlist
[0]->geometry() );
781 // As we are using pseudo-random movement (See "slot") we need to make sure the list
782 // is always sorted the same way no matter which window is currently active.
785 QRect area
= effects
->clientArea( ScreenArea
, screen
, effects
->currentDesktop() );
786 if( m_showPanel
) // reserve space for the panel
787 area
= effects
->clientArea( MaximizeArea
, screen
, effects
->currentDesktop() );
790 QHash
<EffectWindow
*, QRect
> targets
;
791 foreach( EffectWindow
*w
, windowlist
)
793 bounds
= bounds
.united( w
->geometry() );
794 targets
[w
] = w
->geometry();
795 // Reuse the unused "slot" as a preferred direction attribute. This is used when the window
796 // is on the edge of the screen to try to use as much screen real estate as possible.
797 m_windowData
[w
].slot
= direction
;
803 // Iterate over all windows, if two overlap push them apart _slightly_ as we try to
804 // brute-force the most optimal positions over many iterations.
809 foreach( EffectWindow
*w
, windowlist
)
811 foreach( EffectWindow
*e
, windowlist
)
813 if( w
!= e
&& targets
[w
].adjusted( -5, -5, 5, 5 ).intersects(
814 targets
[e
].adjusted( -5, -5, 5, 5 )))
818 // Determine pushing direction
819 QPoint
diff( targets
[e
].center() - targets
[w
].center() );
820 // Prevent dividing by zero and non-movement
821 if( diff
.x() == 0 && diff
.y() == 0 )
823 // Try to keep screen aspect ratio
824 //if( bounds.height() / bounds.width() > area.height() / area.width() )
825 // diff.setY( diff.y() / 2 );
827 // diff.setX( diff.x() / 2 );
828 // Approximate a vector of between 10px and 20px in magnitude in the same direction
829 diff
*= m_accuracy
/ double( diff
.manhattanLength() );
830 // Move both windows apart
831 targets
[w
].translate( -diff
);
832 targets
[e
].translate( diff
);
834 // Try to keep the bounding rect the same aspect as the screen so that more
835 // screen real estate is utilised. We do this by splitting the screen into nine
836 // equal sections, if the window center is in any of the corner sections pull the
837 // window towards the outer corner. If it is in any of the other edge sections
838 // alternate between each corner on that edge. We don't want to determine it
839 // randomly as it will not produce consistant locations when using the filter.
840 // Only move one window so we don't cause large amounts of unnecessary zooming
841 // in some situations. We need to do this even when expanding later just in case
842 // all windows are the same size.
843 // (We are using an old bounding rect for this, hopefully it doesn't matter)
844 int xSection
= ( targets
[w
].x() - bounds
.x() ) / ( bounds
.width() / 3 );
845 int ySection
= ( targets
[w
].y() - bounds
.y() ) / ( bounds
.height() / 3 );
846 diff
= QPoint( 0, 0 );
847 if( xSection
!= 1 || ySection
!= 1 ) // Remove this if you want the center to pull as well
850 xSection
= ( m_windowData
[w
].slot
/ 2 ? 2 : 0 );
852 ySection
= ( m_windowData
[w
].slot
% 2 ? 2 : 0 );
854 if( xSection
== 0 && ySection
== 0 )
855 diff
= QPoint( bounds
.topLeft() - targets
[w
].center() );
856 if( xSection
== 2 && ySection
== 0 )
857 diff
= QPoint( bounds
.topRight() - targets
[w
].center() );
858 if( xSection
== 2 && ySection
== 2 )
859 diff
= QPoint( bounds
.bottomRight() - targets
[w
].center() );
860 if( xSection
== 0 && ySection
== 2 )
861 diff
= QPoint( bounds
.bottomLeft() - targets
[w
].center() );
862 if( diff
.x() != 0 || diff
.y() != 0 )
864 diff
*= m_accuracy
/ double( diff
.manhattanLength() );
865 targets
[w
].translate( diff
);
868 // Update bounding rect
869 bounds
= bounds
.united( targets
[w
] );
870 bounds
= bounds
.united( targets
[e
] );
876 // Work out scaling by getting the most top-left and most bottom-right window coords.
877 // The 20's and 10's are so that the windows don't touch the edge of the screen.
880 scale
= 1.0; // Don't add borders to the screen
881 else if( area
.width() / double( bounds
.width() ) < area
.height() / double( bounds
.height() ))
882 scale
= ( area
.width() - 20 ) / double( bounds
.width() );
884 scale
= ( area
.height() - 20 ) / double( bounds
.height() );
885 // Make bounding rect fill the screen size for later steps
887 bounds
.x() - ( area
.width() - 20 - bounds
.width() * scale
) / 2 - 10 / scale
,
888 bounds
.y() - ( area
.height() - 20 - bounds
.height() * scale
) / 2 - 10 / scale
,
889 area
.width() / scale
,
890 area
.height() / scale
893 // Move all windows back onto the screen and set their scale
894 foreach( EffectWindow
*w
, windowlist
)
896 ( targets
[w
].x() - bounds
.x() ) * scale
+ area
.x(),
897 ( targets
[w
].y() - bounds
.y() ) * scale
+ area
.y(),
898 targets
[w
].width() * scale
,
899 targets
[w
].height() * scale
902 // Try to fill the gaps by enlarging windows if they have the space
905 // Don't expand onto or over the border
906 QRegion
borderRegion( area
.adjusted( -200, -200, 200, 200 ));
907 borderRegion
^= area
.adjusted( 10 / scale
, 10 / scale
, -10 / scale
, -10 / scale
);
913 foreach( EffectWindow
*w
, windowlist
)
916 // This may cause some slight distortion if the windows are enlarged a large amount
917 int widthDiff
= m_accuracy
;
918 int heightDiff
= heightForWidth( w
, targets
[w
].width() + widthDiff
) - targets
[w
].height();
919 int xDiff
= widthDiff
/ 2; // Also move a bit in the direction of the enlarge, allows the
920 int yDiff
= heightDiff
/ 2; // center windows to be enlarged if there is gaps on the side.
922 // Attempt enlarging to the top-right
923 oldRect
= targets
[w
];
925 targets
[w
].x() + xDiff
,
926 targets
[w
].y() - yDiff
- heightDiff
,
927 targets
[w
].width() + widthDiff
,
928 targets
[w
].height() + heightDiff
930 if( isOverlappingAny( w
, targets
, borderRegion
))
931 targets
[w
] = oldRect
;
935 // Attempt enlarging to the bottom-right
936 oldRect
= targets
[w
];
938 targets
[w
].x() + xDiff
,
939 targets
[w
].y() + yDiff
,
940 targets
[w
].width() + widthDiff
,
941 targets
[w
].height() + heightDiff
943 if( isOverlappingAny( w
, targets
, borderRegion
))
944 targets
[w
] = oldRect
;
948 // Attempt enlarging to the bottom-left
949 oldRect
= targets
[w
];
951 targets
[w
].x() - xDiff
- widthDiff
,
952 targets
[w
].y() + yDiff
,
953 targets
[w
].width() + widthDiff
,
954 targets
[w
].height() + heightDiff
956 if( isOverlappingAny( w
, targets
, borderRegion
))
957 targets
[w
] = oldRect
;
961 // Attempt enlarging to the top-left
962 oldRect
= targets
[w
];
964 targets
[w
].x() - xDiff
- widthDiff
,
965 targets
[w
].y() - yDiff
- heightDiff
,
966 targets
[w
].width() + widthDiff
,
967 targets
[w
].height() + heightDiff
969 if( isOverlappingAny( w
, targets
, borderRegion
))
970 targets
[w
] = oldRect
;
976 // The expanding code above can actually enlarge windows over 1.0/2.0 scale, we don't like this
977 // We can't add this to the loop above as it would cause a never-ending loop so we have to make
978 // do with the less-than-optimal space usage with using this method.
979 foreach( EffectWindow
*w
, windowlist
)
981 double scale
= targets
[w
].width() / double( w
->width() );
982 if( scale
> 2.0 || ( scale
> 1.0 && ( w
->width() > 300 || w
->height() > 300 )))
984 scale
= ( w
->width() > 300 || w
->height() > 300 ) ? 1.0 : 2.0;
986 targets
[w
].center().x() - int( w
->width() * scale
) / 2,
987 targets
[w
].center().y() - int( w
->height() * scale
) / 2,
989 w
->height() * scale
);
994 // Notify the motion manager of the targets
995 foreach( EffectWindow
*w
, windowlist
)
996 m_motionManager
.moveWindow( w
, targets
[w
] );
999 //-----------------------------------------------------------------------------
1000 // Helper functions for window rearranging
1002 void PresentWindowsEffect::assignSlots( EffectWindowList windowlist
, const QRect
&area
, int columns
, int rows
)
1004 QVector
< bool > taken
;
1005 taken
.fill( false, columns
* rows
);
1006 foreach( EffectWindow
* w
, windowlist
)
1007 if( m_windowData
[w
].slot
!= -1 )
1008 taken
[ m_windowData
[w
].slot
] = true;
1009 int slotWidth
= area
.width() / columns
;
1010 int slotHeight
= area
.height() / rows
;
1011 if( m_tabBoxEnabled
)
1013 for( int i
= 0; i
< windowlist
.count(); i
++ )
1015 EffectWindow
*w
= windowlist
[i
];
1016 WindowData
*wData
= &m_windowData
[w
];
1017 if( wData
->slot
!= -1 )
1018 continue; // It's already has a slot
1019 int x
= i
% columns
;
1020 int y
= i
/ columns
;
1021 QPoint pos
= w
->geometry().center();
1022 if( pos
.x() < area
.left() )
1023 pos
.setX( area
.left() );
1024 if( pos
.x() > area
.right() )
1025 pos
.setX( area
.right() );
1026 if( pos
.y() < area
.top() )
1027 pos
.setY( area
.top() );
1028 if( pos
.y() > area
.bottom() )
1029 pos
.setY( area
.bottom() );
1030 int xdiff
= pos
.x() - ( area
.x() + slotWidth
* x
+ slotWidth
/ 2 );
1031 int ydiff
= pos
.y() - ( area
.y() + slotHeight
* y
+ slotHeight
/ 2 );
1032 int dist
= int( sqrt( double( xdiff
* xdiff
+ ydiff
* ydiff
)));
1034 wData
->slot_distance
= dist
;
1039 foreach( EffectWindow
*w
, windowlist
)
1041 WindowData
*wData
= &m_windowData
[w
];
1042 if( wData
->slot
!= -1 )
1043 continue; // it already has a slot
1044 QPoint pos
= w
->geometry().center();
1045 if( pos
.x() < area
.left() )
1046 pos
.setX( area
.left() );
1047 if( pos
.x() > area
.right() )
1048 pos
.setX( area
.right() );
1049 if( pos
.y() < area
.top() )
1050 pos
.setY( area
.top() );
1051 if( pos
.y() > area
.bottom() )
1052 pos
.setY( area
.bottom() );
1053 int distance
= INT_MAX
;
1054 for( int x
= 0; x
< columns
; x
++ )
1055 for( int y
= 0; y
< rows
; y
++ )
1057 int slot
= x
+ y
* columns
;
1060 int xdiff
= pos
.x() - ( area
.x() + slotWidth
* x
+ slotWidth
/ 2 );
1061 int ydiff
= pos
.y() - ( area
.y() + slotHeight
* y
+ slotHeight
/ 2 );
1062 int dist
= int( sqrt( double( xdiff
* xdiff
+ ydiff
* ydiff
)));
1063 if( dist
< distance
)
1067 wData
->slot_distance
= distance
;
1074 void PresentWindowsEffect::getBestAssignments( EffectWindowList windowlist
)
1076 foreach( EffectWindow
* w1
, windowlist
)
1078 WindowData
*windowData1
= &m_windowData
[w1
];
1079 foreach( EffectWindow
* w2
, windowlist
)
1081 WindowData
*windowData2
= &m_windowData
[w2
];
1082 if( w1
!= w2
&& windowData1
->slot
== windowData2
->slot
&&
1083 windowData1
->slot_distance
>= windowData2
->slot_distance
)
1084 windowData1
->slot
= -1;
1089 bool PresentWindowsEffect::isOverlappingAny( EffectWindow
*w
, const QHash
<EffectWindow
*, QRect
> &targets
, const QRegion
&border
)
1091 if( border
.intersects( targets
[w
] ))
1093 // Is there a better way to do this?
1094 foreach( EffectWindow
*e
, targets
.keys() )
1098 if( targets
[w
].adjusted( -5, -5, 5, 5 ).intersects(
1099 targets
[e
].adjusted( -5, -5, 5, 5 )))
1105 //-----------------------------------------------------------------------------
1108 void PresentWindowsEffect::setActive( bool active
, bool closingTab
)
1110 if( effects
->activeFullScreenEffect() && effects
->activeFullScreenEffect() != this )
1112 if( m_activated
== active
)
1114 if( m_activated
&& m_tabBoxEnabled
&& !closingTab
)
1116 effects
->closeTabBox();
1119 m_activated
= active
;
1122 m_decalOpacity
= 0.0;
1123 m_windowFilter
.clear();
1125 // Add every single window to m_windowData (Just calling [w] creates it)
1126 foreach( EffectWindow
*w
, effects
->stackingOrder() )
1128 m_windowData
[w
].visible
= isVisibleWindow( w
);
1129 m_windowData
[w
].opacity
= 0.0;
1130 if( w
->isOnCurrentDesktop() && !w
->isMinimized() )
1131 m_windowData
[w
].opacity
= 1.0;
1132 m_windowData
[w
].highlight
= 1.0;
1135 if( m_tabBoxEnabled
)
1137 foreach( EffectWindow
*w
, effects
->currentTabBoxWindowList() )
1139 m_motionManager
.manage( w
);
1140 m_windowData
[w
].visible
= effects
->currentTabBoxWindowList().contains( w
);
1142 // Hide windows not in the list
1143 foreach( EffectWindow
*w
, effects
->stackingOrder() )
1144 m_windowData
[w
].visible
= isVisibleWindow( w
) &&
1145 (!isSelectableWindow( w
) || effects
->currentTabBoxWindowList().contains( w
));
1149 // Filter out special windows such as panels and taskbars
1150 foreach( EffectWindow
*w
, effects
->stackingOrder() )
1151 if( isSelectableWindow( w
))
1152 m_motionManager
.manage( w
);
1154 if( m_motionManager
.managedWindows().isEmpty() ||
1155 (( m_motionManager
.managedWindows().count() == 1 ) && m_motionManager
.managedWindows().first()->isOnCurrentDesktop() ))
1156 { // No point triggering if there is nothing to do
1157 m_activated
= false;
1158 m_windowData
.clear();
1159 m_motionManager
.unmanageAll();
1163 // Create temporary input window to catch mouse events
1164 m_input
= effects
->createFullScreenInputWindow( this, Qt::PointingHandCursor
);
1165 m_hasKeyboardGrab
= effects
->grabKeyboard( this );
1166 effects
->setActiveFullScreenEffect( this );
1168 m_gridSizes
.clear();
1169 for( int i
= 0; i
< effects
->numScreens(); i
++ )
1170 m_gridSizes
.append( GridSize() );
1173 if( m_tabBoxEnabled
)
1174 setHighlightedWindow( effects
->currentTabBoxWindow() );
1176 setHighlightedWindow( effects
->activeWindow() );
1180 // Fade in/out all windows
1181 foreach( EffectWindow
*w
, effects
->stackingOrder() )
1183 EffectWindow
*activeWindow
= effects
->activeWindow();
1184 if( m_tabBoxEnabled
)
1185 activeWindow
= effects
->currentTabBoxWindow();
1187 m_windowData
[w
].visible
= ( w
->desktop() == activeWindow
->desktop() || w
->isOnAllDesktops() ) && !w
->isMinimized();
1188 else // Deactivating to an empty desktop
1189 m_windowData
[w
].visible
= ( w
->isOnCurrentDesktop() || w
->isOnAllDesktops() ) && !w
->isMinimized();
1190 if( m_tabBoxEnabled
&& w
== effects
->currentTabBoxWindow() )
1191 m_windowData
[w
].visible
= true;
1194 // Move all windows back to their original position
1195 foreach( EffectWindow
*w
, m_motionManager
.managedWindows() )
1196 m_motionManager
.moveWindow( w
, w
->geometry() );
1197 discardFilterTexture();
1198 m_windowFilter
.clear();
1200 effects
->destroyInputWindow( m_input
);
1201 if( m_hasKeyboardGrab
)
1202 effects
->ungrabKeyboard();
1203 m_hasKeyboardGrab
= false;
1205 effects
->addRepaintFull(); // Trigger the first repaint
1208 //-----------------------------------------------------------------------------
1211 void PresentWindowsEffect::discardFilterTexture()
1213 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
1214 delete m_filterTexture
;
1215 m_filterTexture
= NULL
;
1219 void PresentWindowsEffect::updateFilterTexture()
1221 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
1222 discardFilterTexture();
1223 if( m_windowFilter
.isEmpty())
1225 effects
->addRepaint( m_filterTextureRect
);
1228 // Create font for filter text
1230 font
.setPointSize( font
.pointSize() * 2 );
1231 font
.setBold( true );
1232 // Get size of the rect containing filter text
1233 QFontMetrics
fm( font
);
1235 QString translatedString
= i18n( "Filter:\n%1", m_windowFilter
);
1236 rect
.setSize( fm
.size( 0, translatedString
));
1237 QRect area
= effects
->clientArea( PlacementArea
, effects
->activeScreen(), effects
->currentDesktop() );
1239 QImage
im( rect
.width(), rect
.height(), QImage::Format_ARGB32
);
1240 im
.fill( Qt::transparent
);
1241 // Paint the filter text to it
1244 p
.setPen( QPalette().color( QPalette::Active
, QPalette::HighlightedText
));
1245 p
.drawText( rect
, Qt::AlignCenter
, translatedString
);
1247 // Create GL texture
1248 m_filterTexture
= new GLTexture( im
);
1249 // Get position for filter text and it's frame
1250 m_filterTextureRect
= QRect(
1251 area
.x() + ( area
.width() - rect
.width() ) / 2,
1252 area
.y() + ( area
.height() - rect
.height() ) / 2,
1253 rect
.width(), rect
.height() );
1254 m_filterFrameRect
= m_filterTextureRect
.adjusted( -20, -10, 20, 10 );
1256 effects
->addRepaint( m_filterTextureRect
);
1260 //-----------------------------------------------------------------------------
1263 bool PresentWindowsEffect::isSelectableWindow( EffectWindow
*w
)
1265 if( w
->isSpecialWindow() || w
->isUtility() )
1267 if( w
->isDeleted() )
1269 if( !m_allDesktops
&& !w
->isOnCurrentDesktop() )
1271 if( !m_tabBoxEnabled
&& m_ignoreMinimized
&& w
->isMinimized() )
1276 bool PresentWindowsEffect::isVisibleWindow( EffectWindow
*w
)
1278 if( w
->isDesktop() )
1280 return isSelectableWindow( w
);
1283 void PresentWindowsEffect::setHighlightedWindow( EffectWindow
*w
)
1285 if( w
== m_highlightedWindow
|| ( w
!= NULL
&& !m_motionManager
.isManaging( w
)))
1288 if( m_highlightedWindow
)
1289 m_highlightedWindow
->addRepaintFull(); // Trigger the first repaint
1290 m_highlightedWindow
= w
;
1291 if( m_highlightedWindow
)
1292 m_highlightedWindow
->addRepaintFull(); // Trigger the first repaint
1294 if( m_tabBoxEnabled
&& m_highlightedWindow
)
1295 effects
->setTabBoxWindow( w
);
1298 EffectWindow
* PresentWindowsEffect::relativeWindow( EffectWindow
*w
, int xdiff
, int ydiff
, bool wrap
) const
1299 { // TODO: Is it possible to select hidden windows?
1301 QRect area
= effects
->clientArea( FullArea
, 0, effects
->currentDesktop() );
1304 // Detect across the width of the desktop
1309 for( int i
= 0; i
< xdiff
; i
++ )
1311 QRectF wArea
= m_motionManager
.transformedGeometry( w
);
1312 detectRect
= QRect( 0, wArea
.y(), area
.width(), wArea
.height() );
1314 foreach( EffectWindow
* e
, m_motionManager
.managedWindows() )
1316 if( !m_windowData
[e
].visible
)
1318 QRectF eArea
= m_motionManager
.transformedGeometry( e
);
1319 if( eArea
.intersects( detectRect
) &&
1320 eArea
.x() > wArea
.x() )
1326 QRectF nArea
= m_motionManager
.transformedGeometry( next
);
1327 if( eArea
.x() < nArea
.x() )
1334 if( wrap
) // We are at the right-most window, now get the left-most one to wrap
1335 return relativeWindow( w
, -1000, 0, false );
1336 break; // No more windows to the right
1344 for( int i
= 0; i
< -xdiff
; i
++ )
1346 QRectF wArea
= m_motionManager
.transformedGeometry( w
);
1347 detectRect
= QRect( 0, wArea
.y(), area
.width(), wArea
.height() );
1349 foreach( EffectWindow
* e
, m_motionManager
.managedWindows() )
1351 if( !m_windowData
[e
].visible
)
1353 QRectF eArea
= m_motionManager
.transformedGeometry( e
);
1354 if( eArea
.intersects( detectRect
) &&
1355 eArea
.x() + eArea
.width() < wArea
.x() + wArea
.width() )
1361 QRectF nArea
= m_motionManager
.transformedGeometry( next
);
1362 if( eArea
.x() + eArea
.width() > nArea
.x() + nArea
.width() )
1369 if( wrap
) // We are at the left-most window, now get the right-most one to wrap
1370 return relativeWindow( w
, 1000, 0, false );
1371 break; // No more windows to the left
1379 // Detect across the height of the desktop
1384 for( int i
= 0; i
< ydiff
; i
++ )
1386 QRectF wArea
= m_motionManager
.transformedGeometry( w
);
1387 detectRect
= QRect( wArea
.x(), 0, wArea
.width(), area
.height() );
1389 foreach( EffectWindow
* e
, m_motionManager
.managedWindows() )
1391 if( !m_windowData
[e
].visible
)
1393 QRectF eArea
= m_motionManager
.transformedGeometry( e
);
1394 if( eArea
.intersects( detectRect
) &&
1395 eArea
.y() > wArea
.y() )
1401 QRectF nArea
= m_motionManager
.transformedGeometry( next
);
1402 if( eArea
.y() < nArea
.y() )
1409 if( wrap
) // We are at the bottom-most window, now get the top-most one to wrap
1410 return relativeWindow( w
, 0, -1000, false );
1411 break; // No more windows to the bottom
1419 for( int i
= 0; i
< -ydiff
; i
++ )
1421 QRectF wArea
= m_motionManager
.transformedGeometry( w
);
1422 detectRect
= QRect( wArea
.x(), 0, wArea
.width(), area
.height() );
1424 foreach( EffectWindow
* e
, m_motionManager
.managedWindows() )
1426 if( !m_windowData
[e
].visible
)
1428 QRectF eArea
= m_motionManager
.transformedGeometry( e
);
1429 if( eArea
.intersects( detectRect
) &&
1430 eArea
.y() + eArea
.height() < wArea
.y() + wArea
.height() )
1436 QRectF nArea
= m_motionManager
.transformedGeometry( next
);
1437 if( eArea
.y() + eArea
.height() > nArea
.y() + nArea
.height() )
1444 if( wrap
) // We are at the top-most window, now get the bottom-most one to wrap
1445 return relativeWindow( w
, 0, 1000, false );
1446 break; // No more windows to the top
1454 abort(); // Should never get here
1457 EffectWindow
* PresentWindowsEffect::findFirstWindow() const
1459 EffectWindow
*topLeft
= NULL
;
1460 QRectF topLeftGeometry
;
1461 foreach( EffectWindow
*w
, m_motionManager
.managedWindows() )
1463 QRectF geometry
= m_motionManager
.transformedGeometry( w
);
1464 if( m_windowData
[w
].visible
== false )
1465 continue; // Not visible
1466 if( topLeft
== NULL
)
1469 topLeftGeometry
= geometry
;
1471 else if( geometry
.x() < topLeftGeometry
.x() || geometry
.y() < topLeftGeometry
.y() )
1474 topLeftGeometry
= geometry
;
1480 void PresentWindowsEffect::paintWindowIcon( EffectWindow
*w
, WindowPaintData
&data
)
1482 // Don't bother if we don't even have an icon
1483 if( w
->icon().isNull() )
1486 WindowData
&wData
= m_windowData
[w
];
1487 if( wData
.icon
.cacheKey() != w
->icon().cacheKey())
1488 { // Make sure data.icon is the right QPixmap, and rebind
1489 wData
.icon
= w
->icon();
1490 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
1491 if( effects
->compositingType() == OpenGLCompositing
)
1493 wData
.iconTexture
= new GLTexture( wData
.icon
);
1494 wData
.iconTexture
->setFilter( GL_LINEAR
);
1497 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
1498 if( effects
->compositingType() == XRenderCompositing
)
1499 wData
.iconPicture
= XRenderPicture( wData
.icon
);
1502 int icon_margin
= 8;
1503 int width
= wData
.icon
.width();
1504 int height
= wData
.icon
.height();
1505 int x
= w
->x() + data
.xTranslate
+ w
->width() * data
.xScale
* 0.95 - width
- icon_margin
;
1506 int y
= w
->y() + data
.yTranslate
+ w
->height() * data
.yScale
* 0.95 - height
- icon_margin
;
1507 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
1508 if( effects
->compositingType() == OpenGLCompositing
)
1510 glPushAttrib( GL_CURRENT_BIT
| GL_ENABLE_BIT
| GL_TEXTURE_BIT
);
1511 glEnable( GL_BLEND
);
1512 glBlendFunc( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1513 // Render some background
1514 glColor4f( 0, 0, 0, 0.5 * wData
.opacity
* m_decalOpacity
);
1515 renderRoundBox( QRect( x
-3, y
-3, width
+6, height
+6 ), 3 );
1517 glColor4f( 1, 1, 1, 1 * wData
.opacity
* m_decalOpacity
);
1518 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
1519 wData
.iconTexture
->bind();
1520 wData
.iconTexture
->render( infiniteRegion(), QRect( x
, y
, width
, height
));
1521 wData
.iconTexture
->unbind();
1525 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
1526 if( effects
->compositingType() == XRenderCompositing
)
1528 XRenderComposite( display(),
1529 wData
.icon
.depth() == 32 ? PictOpOver
: PictOpSrc
,
1530 wData
.iconPicture
, None
,
1531 effects
->xrenderBufferPicture(),
1532 0, 0, 0, 0, x
, y
, width
, height
);
1539 #include "presentwindows.moc"