Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / kwin / effects / boxswitch.cpp
blob58a5141883160a5f4af78f0cfe8ccfa67cce59ad
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"
25 #include <QCursor>
26 #include <QMouseEvent>
27 #include <QPainter>
28 #include <QSize>
30 #include <kapplication.h>
31 #include <kcolorscheme.h>
33 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
34 #include <GL/gl.h>
35 #endif
37 namespace KWin
40 KWIN_EFFECT( boxswitch, BoxSwitchEffect )
42 BoxSwitchEffect::BoxSwitchEffect()
43 : mActivated( 0 )
44 , mMode( 0 )
45 , selected_window( 0 )
46 , painting_desktop( 0 )
48 frame_margin = 10;
49 highlight_margin = 5;
50 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
51 alphaFormat = XRenderFindStandardFormat( display(), PictStandardARGB32 );
52 #endif
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 )
66 if( mActivated )
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 );
77 else
79 if( painting_desktop )
81 if( w->isOnDesktop( painting_desktop ))
82 w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
83 else
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 );
94 if( mActivated )
96 if( mMode == TabBoxWindowsMode )
98 paintFrame();
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() );
111 else
113 if( !painting_desktop )
115 paintFrame();
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 )
135 if( mActivated )
137 if( mMode == TabBoxWindowsMode )
139 if( windows.contains( w ) && w != selected_window )
141 data.opacity *= 0.2;
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 )
152 return;
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 );
167 else
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 )
181 if( mActivated )
183 if( mMode == TabBoxWindowsMode )
185 if( windows.contains( w ))
187 effects->addRepaint( windows[ w ]->area );
190 else
192 if( w->isOnAllDesktops())
194 foreach( ItemInfo* info, desktops )
195 effects->addRepaint( info->area );
197 else
199 effects->addRepaint( desktops[ w->desktop() ]->area );
205 void BoxSwitchEffect::windowGeometryShapeChanged( EffectWindow* w, const QRect& old )
207 if( mActivated )
209 if( mMode == TabBoxWindowsMode )
211 if( windows.contains( w ) && w->size() != old.size())
213 effects->addRepaint( windows[ w ]->area );
216 else
218 if( w->isOnAllDesktops())
220 foreach( ItemInfo* info, desktops )
221 effects->addRepaint( info->area );
223 else
225 effects->addRepaint( desktops[ w->desktop() ]->area );
231 void BoxSwitchEffect::tabBoxAdded( int mode )
233 if( !mActivated )
235 if( mode == TabBoxWindowsMode )
237 if( effects->currentTabBoxWindowList().count() > 0 )
239 mMode = mode;
240 effects->refTabBox();
241 setActive();
244 else
245 { // DesktopMode
246 if( effects->currentTabBoxDesktopList().count() > 0 )
248 mMode = mode;
249 painting_desktop = 0;
250 effects->refTabBox();
251 setActive();
257 void BoxSwitchEffect::tabBoxClosed()
259 if( mActivated )
260 setInactive();
263 void BoxSwitchEffect::tabBoxUpdated()
265 if( mActivated )
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 )
281 return;
282 original_windows = effects->currentTabBoxWindowList();
284 else
285 { // DesktopMode
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 )
293 return;
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()
306 mActivated = true;
307 if( mMode == TabBoxWindowsMode )
309 original_windows = effects->currentTabBoxWindowList();
310 setSelectedWindow( effects->currentTabBoxWindow());
312 else
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())
326 w->addRepaintFull();
331 void BoxSwitchEffect::setInactive()
333 mActivated = false;
334 effects->unrefTabBox();
335 if( mInput != None )
337 effects->destroyInputWindow( mInput );
338 mInput = None;
340 if( mMode == TabBoxWindowsMode )
342 foreach( EffectWindow* w, windows.keys())
344 if( w != selected_window )
345 w->addRepaintFull();
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;
356 #endif
357 delete i;
359 windows.clear();
360 setSelectedWindow( 0 );
362 else
363 { // DesktopMode
364 foreach( ItemInfo* i, desktops )
365 delete i;
366 desktops.clear();
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 );
378 selected_window = w;
379 if( w )
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()
401 int itemcount;
403 if( mMode == TabBoxWindowsMode )
405 itemcount = original_windows.count();
406 item_max_size.setWidth( 200 );
407 item_max_size.setHeight( 200 );
409 else
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())
426 item_max_size /= 2;
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 )
443 windows.clear();
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;
456 else
458 desktops.clear();
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 );
481 glPopAttrib();
483 #endif
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 );
491 XRenderColor col;
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 );
503 #endif
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 );
514 glPopAttrib();
516 #endif
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 );
524 XRenderColor col;
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 );
536 #endif
539 void BoxSwitchEffect::paintWindowThumbnail( EffectWindow* w )
541 if( !windows.contains( w ))
542 return;
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 ))
558 return;
560 ScreenPaintData data;
561 QRect region;
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 );
574 data.xTranslate = x;
575 data.yTranslate = y;
577 effects->paintScreen( PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST,
578 region, data );
581 void BoxSwitchEffect::paintWindowIcon( EffectWindow* w )
583 if( !windows.contains( w ))
584 return;
585 // Don't render null icons
586 if( w->icon().isNull() )
588 return;
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 );
600 #endif
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 );
609 #endif
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 );
624 // Render the icon
625 glColor4f( 1, 1, 1, 1 );
626 windows[ w ]->iconTexture.bind();
627 const float verts[ 4 * 2 ] =
629 x, y,
630 x, y + height,
631 x + width, y + height,
632 x + width, y
634 const float texcoords[ 4 * 2 ] =
636 0, 1,
637 0, 0,
638 1, 0,
639 1, 1
641 renderGLGeometry( 4, verts, texcoords );
642 windows[ w ]->iconTexture.unbind();
643 glPopAttrib();
645 #endif
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 );
655 #endif
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 );
664 } // namespace