1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2007 Philip Falkner <philip.falkner@gmail.com>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
21 #include <kwinconfig.h>
23 #include "boxswitch.h"
26 #include <QMouseEvent>
30 #include <kapplication.h>
31 #include <kcolorscheme.h>
33 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
40 KWIN_EFFECT( boxswitch
, BoxSwitchEffect
)
42 BoxSwitchEffect::BoxSwitchEffect()
45 , selected_window( 0 )
46 , painting_desktop( 0 )
50 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
51 alphaFormat
= XRenderFindStandardFormat( display(), PictStandardARGB32
);
53 color_frame
= KColorScheme( QPalette::Active
, KColorScheme::Window
).background().color();
54 color_frame
.setAlphaF( 0.9 );
55 color_highlight
= KColorScheme( QPalette::Active
, KColorScheme::Selection
).background().color();
56 color_highlight
.setAlphaF( 0.9 );
57 color_text
= KColorScheme( QPalette::Active
, KColorScheme::Window
).foreground().color();
60 BoxSwitchEffect::~BoxSwitchEffect()
64 void BoxSwitchEffect::prePaintWindow( EffectWindow
* w
, WindowPrePaintData
& data
, int time
)
68 if( mMode
== TabBoxWindowsMode
)
70 if( windows
.contains( w
))
72 if( w
!= selected_window
)
73 data
.setTranslucent();
74 w
->enablePainting( EffectWindow::PAINT_DISABLED_BY_MINIMIZE
);
79 if( painting_desktop
)
81 if( w
->isOnDesktop( painting_desktop
))
82 w
->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP
);
84 w
->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP
);
88 effects
->prePaintWindow( w
, data
, time
);
91 void BoxSwitchEffect::paintScreen( int mask
, QRegion region
, ScreenPaintData
& data
)
93 effects
->paintScreen( mask
, region
, data
);
96 if( mMode
== TabBoxWindowsMode
)
100 foreach( EffectWindow
* w
, windows
.keys())
102 if( w
== selected_window
)
104 paintHighlight( windows
[ w
]->area
);
106 paintWindowThumbnail( w
);
107 paintWindowIcon( w
);
109 paintText( selected_window
->caption() );
113 if( !painting_desktop
)
117 foreach( painting_desktop
, desktops
.keys())
119 if( painting_desktop
== selected_desktop
)
121 paintHighlight( desktops
[ painting_desktop
]->area
); //effects->desktopName( painting_desktop )
124 paintDesktopThumbnail( painting_desktop
);
126 paintText( effects
->desktopName( selected_desktop
));
127 painting_desktop
= 0;
133 void BoxSwitchEffect::paintWindow( EffectWindow
* w
, int mask
, QRegion region
, WindowPaintData
& data
)
137 if( mMode
== TabBoxWindowsMode
)
139 if( windows
.contains( w
) && w
!= selected_window
)
145 effects
->paintWindow( w
, mask
, region
, data
);
148 void BoxSwitchEffect::windowInputMouseEvent( Window w
, QEvent
* e
)
150 assert( w
== mInput
);
151 if( e
->type() != QEvent::MouseButtonPress
)
153 QPoint pos
= static_cast< QMouseEvent
* >( e
)->pos();
154 pos
+= frame_area
.topLeft();
156 // determine which item was clicked
157 if( mMode
== TabBoxWindowsMode
)
159 foreach( EffectWindow
* w
, windows
.keys())
161 if( windows
[ w
]->clickable
.contains( pos
))
163 effects
->setTabBoxWindow( w
);
169 foreach( int i
, desktops
.keys())
171 if( desktops
[ i
]->clickable
.contains( pos
))
173 effects
->setTabBoxDesktop( i
);
179 void BoxSwitchEffect::windowDamaged( EffectWindow
* w
, const QRect
& damage
)
183 if( mMode
== TabBoxWindowsMode
)
185 if( windows
.contains( w
))
187 effects
->addRepaint( windows
[ w
]->area
);
192 if( w
->isOnAllDesktops())
194 foreach( ItemInfo
* info
, desktops
)
195 effects
->addRepaint( info
->area
);
199 effects
->addRepaint( desktops
[ w
->desktop() ]->area
);
205 void BoxSwitchEffect::windowGeometryShapeChanged( EffectWindow
* w
, const QRect
& old
)
209 if( mMode
== TabBoxWindowsMode
)
211 if( windows
.contains( w
) && w
->size() != old
.size())
213 effects
->addRepaint( windows
[ w
]->area
);
218 if( w
->isOnAllDesktops())
220 foreach( ItemInfo
* info
, desktops
)
221 effects
->addRepaint( info
->area
);
225 effects
->addRepaint( desktops
[ w
->desktop() ]->area
);
231 void BoxSwitchEffect::tabBoxAdded( int mode
)
235 if( mode
== TabBoxWindowsMode
)
237 if( effects
->currentTabBoxWindowList().count() > 0 )
240 effects
->refTabBox();
246 if( effects
->currentTabBoxDesktopList().count() > 0 )
249 painting_desktop
= 0;
250 effects
->refTabBox();
257 void BoxSwitchEffect::tabBoxClosed()
263 void BoxSwitchEffect::tabBoxUpdated()
267 if( mMode
== TabBoxWindowsMode
)
269 if( selected_window
!= NULL
)
271 if( windows
.contains( selected_window
))
272 effects
->addRepaint( windows
.value( selected_window
)->area
);
273 selected_window
->addRepaintFull();
275 setSelectedWindow( effects
->currentTabBoxWindow());
276 if( windows
.contains( selected_window
))
277 effects
->addRepaint( windows
.value( selected_window
)->area
);
278 selected_window
->addRepaintFull();
279 effects
->addRepaint( text_area
);
280 if( effects
->currentTabBoxWindowList() == original_windows
)
282 original_windows
= effects
->currentTabBoxWindowList();
286 if( desktops
.contains( selected_desktop
))
287 effects
->addRepaint( desktops
.value( selected_desktop
)->area
);
288 selected_desktop
= effects
->currentTabBoxDesktop();
289 if( desktops
.contains( selected_desktop
))
290 effects
->addRepaint( desktops
.value( selected_desktop
)->area
);
291 effects
->addRepaint( text_area
);
292 if( effects
->currentTabBoxDesktopList() == original_desktops
)
294 original_desktops
= effects
->currentTabBoxDesktopList();
296 effects
->addRepaint( frame_area
);
297 calculateFrameSize();
298 calculateItemSizes();
299 moveResizeInputWindow( frame_area
.x(), frame_area
.y(), frame_area
.width(), frame_area
.height());
300 effects
->addRepaint( frame_area
);
304 void BoxSwitchEffect::setActive()
307 if( mMode
== TabBoxWindowsMode
)
309 original_windows
= effects
->currentTabBoxWindowList();
310 setSelectedWindow( effects
->currentTabBoxWindow());
314 original_desktops
= effects
->currentTabBoxDesktopList();
315 selected_desktop
= effects
->currentTabBoxDesktop();
317 calculateFrameSize();
318 calculateItemSizes();
319 mInput
= effects
->createInputWindow( this, frame_area
.x(), frame_area
.y(),
320 frame_area
.width(), frame_area
.height(), Qt::ArrowCursor
);
321 effects
->addRepaint( frame_area
);
322 if( mMode
== TabBoxWindowsMode
)
324 foreach( EffectWindow
* w
, windows
.keys())
331 void BoxSwitchEffect::setInactive()
334 effects
->unrefTabBox();
337 effects
->destroyInputWindow( mInput
);
340 if( mMode
== TabBoxWindowsMode
)
342 foreach( EffectWindow
* w
, windows
.keys())
344 if( w
!= selected_window
)
347 foreach( ItemInfo
* i
, windows
)
349 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
350 if( effects
->compositingType() == XRenderCompositing
)
352 if( i
->iconPicture
!= None
)
353 XRenderFreePicture( display(), i
->iconPicture
);
354 i
->iconPicture
= None
;
360 setSelectedWindow( 0 );
364 foreach( ItemInfo
* i
, desktops
)
368 effects
->addRepaint( frame_area
);
369 frame_area
= QRect();
372 void BoxSwitchEffect::setSelectedWindow( EffectWindow
* w
)
374 if( selected_window
)
376 effects
->setElevatedWindow( selected_window
, false );
381 effects
->setElevatedWindow( selected_window
, true );
385 void BoxSwitchEffect::windowClosed( EffectWindow
* w
)
387 if( w
== selected_window
)
389 setSelectedWindow( 0 );
393 void BoxSwitchEffect::moveResizeInputWindow( int x
, int y
, int width
, int height
)
395 XMoveWindow( display(), mInput
, x
, y
);
396 XResizeWindow( display(), mInput
, width
, height
);
399 void BoxSwitchEffect::calculateFrameSize()
403 if( mMode
== TabBoxWindowsMode
)
405 itemcount
= original_windows
.count();
406 item_max_size
.setWidth( 200 );
407 item_max_size
.setHeight( 200 );
411 itemcount
= original_desktops
.count();
412 item_max_size
.setWidth( 200 );
413 item_max_size
.setHeight( 200 );
415 // How much height to reserve for a one-line text label
416 text_font
.setBold( true );
417 text_font
.setPointSize( 12 );
418 text_area
.setHeight( QFontMetrics( text_font
).height() * 1.2 );
419 // Separator space between items and text
420 const int separator_height
= 6;
421 // Shrink the size until all windows/desktops can fit onscreen
422 frame_area
.setWidth( frame_margin
* 2 + itemcount
* item_max_size
.width());
423 QRect screenr
= effects
->clientArea( PlacementArea
, effects
->activeScreen(), effects
->currentDesktop());
424 while( frame_area
.width() > screenr
.width())
427 frame_area
.setWidth( frame_margin
* 2 + itemcount
* item_max_size
.width());
429 frame_area
.setHeight( frame_margin
* 2 + item_max_size
.height() +
430 separator_height
+ text_area
.height());
431 text_area
.setWidth( frame_area
.width() - frame_margin
* 2 );
433 frame_area
.moveTo( screenr
.x() + ( screenr
.width() - frame_area
.width()) / 2,
434 screenr
.y() + ( screenr
.height() - frame_area
.height()) / 2 );
435 text_area
.moveTo( frame_area
.x() + frame_margin
,
436 frame_area
.y() + frame_margin
+ item_max_size
.height() + separator_height
);
439 void BoxSwitchEffect::calculateItemSizes()
441 if( mMode
== TabBoxWindowsMode
)
444 for( int i
= 0; i
< original_windows
.count(); i
++ )
446 EffectWindow
* w
= original_windows
.at( i
);
447 windows
[ w
] = new ItemInfo();
449 windows
[ w
]->area
= QRect( frame_area
.x() + frame_margin
450 + i
* item_max_size
.width(),
451 frame_area
.y() + frame_margin
,
452 item_max_size
.width(), item_max_size
.height());
453 windows
[ w
]->clickable
= windows
[ w
]->area
;
459 for( int i
= 0; i
< original_desktops
.count(); i
++ )
461 int it
= original_desktops
.at( i
);
462 desktops
[ it
] = new ItemInfo();
464 desktops
[ it
]->area
= QRect( frame_area
.x() + frame_margin
465 + i
* item_max_size
.width(),
466 frame_area
.y() + frame_margin
,
467 item_max_size
.width(), item_max_size
.height());
468 desktops
[ it
]->clickable
= desktops
[ it
]->area
;
473 void BoxSwitchEffect::paintFrame()
475 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
476 if( effects
->compositingType() == OpenGLCompositing
)
478 glPushAttrib( GL_CURRENT_BIT
);
479 glColor4f( color_frame
.redF(), color_frame
.greenF(), color_frame
.blueF(), color_frame
.alphaF());
480 renderRoundBoxWithEdge( frame_area
);
484 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
485 if( effects
->compositingType() == XRenderCompositing
)
487 Pixmap pixmap
= XCreatePixmap( display(), rootWindow(),
488 frame_area
.width(), frame_area
.height(), 32 );
489 Picture pic
= XRenderCreatePicture( display(), pixmap
, alphaFormat
, 0, NULL
);
490 XFreePixmap( display(), pixmap
);
492 col
.alpha
= int( color_frame
.alphaF() * 0xffff );
493 col
.red
= int( color_frame
.redF() * color_frame
.alphaF() * 0xffff );
494 col
.green
= int( color_frame
.greenF() * color_frame
.alphaF() * 0xffff );
495 col
.blue
= int( color_frame
.blueF() * color_frame
.alphaF() * 0xffff );
496 XRenderFillRectangle( display(), PictOpSrc
, pic
, &col
, 0, 0,
497 frame_area
.width(), frame_area
.height());
498 XRenderComposite( display(), color_frame
.alphaF() != 1.0 ? PictOpOver
: PictOpSrc
,
499 pic
, None
, effects
->xrenderBufferPicture(),
500 0, 0, 0, 0, frame_area
.x(), frame_area
.y(), frame_area
.width(), frame_area
.height());
501 XRenderFreePicture( display(), pic
);
506 void BoxSwitchEffect::paintHighlight( QRect area
)
508 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
509 if( effects
->compositingType() == OpenGLCompositing
)
511 glPushAttrib( GL_CURRENT_BIT
);
512 glColor4f( color_highlight
.redF(), color_highlight
.greenF(), color_highlight
.blueF(), color_highlight
.alphaF());
513 renderRoundBox( area
, 6 );
517 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
518 if( effects
->compositingType() == XRenderCompositing
)
520 Pixmap pixmap
= XCreatePixmap( display(), rootWindow(),
521 area
.width(), area
.height(), 32 );
522 Picture pic
= XRenderCreatePicture( display(), pixmap
, alphaFormat
, 0, NULL
);
523 XFreePixmap( display(), pixmap
);
525 col
.alpha
= int( color_highlight
.alphaF() * 0xffff );
526 col
.red
= int( color_highlight
.redF() * color_highlight
.alphaF() * 0xffff );
527 col
.green
= int( color_highlight
.greenF() * color_highlight
.alphaF() * 0xffff );
528 col
.blue
= int( color_highlight
.blueF() * color_highlight
.alphaF() * 0xffff );
529 XRenderFillRectangle( display(), PictOpSrc
, pic
, &col
, 0, 0,
530 area
.width(), area
.height());
531 XRenderComposite( display(), color_highlight
.alphaF() != 1.0 ? PictOpOver
: PictOpSrc
,
532 pic
, None
, effects
->xrenderBufferPicture(),
533 0, 0, 0, 0, area
.x(), area
.y(), area
.width(), area
.height());
534 XRenderFreePicture( display(), pic
);
539 void BoxSwitchEffect::paintWindowThumbnail( EffectWindow
* w
)
541 if( !windows
.contains( w
))
543 WindowPaintData
data( w
);
545 setPositionTransformations( data
,
546 windows
[ w
]->thumbnail
, w
,
547 windows
[ w
]->area
.adjusted( highlight_margin
, highlight_margin
, -highlight_margin
, -highlight_margin
),
548 Qt::KeepAspectRatio
);
550 effects
->drawWindow( w
,
551 PAINT_WINDOW_OPAQUE
| PAINT_WINDOW_TRANSFORMED
,
552 windows
[ w
]->thumbnail
, data
);
555 void BoxSwitchEffect::paintDesktopThumbnail( int iDesktop
)
557 if( !desktops
.contains( iDesktop
))
560 ScreenPaintData data
;
562 QRect r
= desktops
[ iDesktop
]->area
.adjusted( highlight_margin
, highlight_margin
,
563 -highlight_margin
, -highlight_margin
);
564 QSize size
= QSize( displayWidth(), displayHeight());
566 size
.scale( r
.size(), Qt::KeepAspectRatio
);
567 data
.xScale
= size
.width() / double( displayWidth());
568 data
.yScale
= size
.height() / double( displayHeight());
569 int width
= int( displayWidth() * data
.xScale
);
570 int height
= int( displayHeight() * data
.yScale
);
571 int x
= r
.x() + ( r
.width() - width
) / 2;
572 int y
= r
.y() + ( r
.height() - height
) / 2;
573 region
= QRect( x
, y
, width
, height
);
577 effects
->paintScreen( PAINT_SCREEN_TRANSFORMED
| PAINT_SCREEN_BACKGROUND_FIRST
,
581 void BoxSwitchEffect::paintWindowIcon( EffectWindow
* w
)
583 if( !windows
.contains( w
))
585 // Don't render null icons
586 if( w
->icon().isNull() )
591 if( windows
[ w
]->icon
.cacheKey() != w
->icon().cacheKey())
592 { // make sure windows[ w ]->icon is the right QPixmap, and rebind
593 windows
[ w
]->icon
= w
->icon();
594 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
595 if( effects
->compositingType() == OpenGLCompositing
)
597 windows
[ w
]->iconTexture
.load( windows
[ w
]->icon
);
598 windows
[ w
]->iconTexture
.setFilter( GL_LINEAR
);
601 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
602 if( effects
->compositingType() == XRenderCompositing
)
604 if( windows
[ w
]->iconPicture
!= None
)
605 XRenderFreePicture( display(), windows
[ w
]->iconPicture
);
606 windows
[ w
]->iconPicture
= XRenderCreatePicture( display(),
607 windows
[ w
]->icon
.handle(), alphaFormat
, 0, NULL
);
611 int width
= windows
[ w
]->icon
.width();
612 int height
= windows
[ w
]->icon
.height();
613 int x
= windows
[ w
]->area
.x() + windows
[ w
]->area
.width() - width
- highlight_margin
;
614 int y
= windows
[ w
]->area
.y() + windows
[ w
]->area
.height() - height
- highlight_margin
;
615 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
616 if( effects
->compositingType() == OpenGLCompositing
)
618 glPushAttrib( GL_CURRENT_BIT
| GL_ENABLE_BIT
);
619 glEnable( GL_BLEND
);
620 glBlendFunc( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
621 // Render some background
622 glColor4f( 0, 0, 0, 0.5 );
623 renderRoundBox( QRect( x
-3, y
-3, width
+6, height
+6 ), 3 );
625 glColor4f( 1, 1, 1, 1 );
626 windows
[ w
]->iconTexture
.bind();
627 const float verts
[ 4 * 2 ] =
631 x
+ width
, y
+ height
,
634 const float texcoords
[ 4 * 2 ] =
641 renderGLGeometry( 4, verts
, texcoords
);
642 windows
[ w
]->iconTexture
.unbind();
646 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
647 if( effects
->compositingType() == XRenderCompositing
)
649 XRenderComposite( display(),
650 windows
[ w
]->icon
.depth() == 32 ? PictOpOver
: PictOpSrc
,
651 windows
[ w
]->iconPicture
, None
,
652 effects
->xrenderBufferPicture(),
653 0, 0, 0, 0, x
, y
, width
, height
);
658 void BoxSwitchEffect::paintText( const QString
& text
)
660 int maxwidth
= text_area
.width();
661 effects
->paintText( text
, text_area
.center(), maxwidth
, color_text
, text_font
);