/******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2007 Philip Falkner This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "boxswitch.h" #include #include #include #include #include #include #ifdef KWIN_HAVE_OPENGL_COMPOSITING #include #endif namespace KWin { KWIN_EFFECT( boxswitch, BoxSwitchEffect ) BoxSwitchEffect::BoxSwitchEffect() : mActivated( 0 ) , mMode( 0 ) , thumbnailFrame( EffectFrame::Styled ) , selected_window( 0 ) , painting_desktop( 0 ) , animation( false ) , highlight_is_set( false ) , primaryTabBox( true ) , secondaryTabBox( false ) , mProxy( this ) , mProxyActivated( 0 ) , mProxyAnimateSwitch( 0 ) , mProxyShowText( 0 ) , mPositioningFactor( 0.5f ) { text_font.setBold( true ); text_font.setPointSize( 12 ); thumbnailFrame.setFont( text_font ); thumbnailFrame.setAlignment( Qt::AlignBottom | Qt::AlignHCenter ); highlight_margin = 10; reconfigure( ReconfigureAll ); } BoxSwitchEffect::~BoxSwitchEffect() { } void BoxSwitchEffect::reconfigure( ReconfigureFlags ) { color_frame = KColorScheme( QPalette::Active, KColorScheme::Window ).background().color(); color_frame.setAlphaF( 0.9 ); color_highlight = KColorScheme( QPalette::Active, KColorScheme::Selection ).background().color(); color_highlight.setAlphaF( 0.9 ); activeTimeLine.setDuration( animationTime( 250 )); activeTimeLine.setCurveShape( TimeLine::EaseInOutCurve ); timeLine.setDuration( animationTime( 150 )); timeLine.setCurveShape( TimeLine::EaseInOutCurve ); KConfigGroup conf = effects->effectConfig( "BoxSwitch" ); bg_opacity = conf.readEntry( "BackgroundOpacity", 25 ) / 100.0; elevate_window = conf.readEntry( "ElevateSelected", true ); mAnimateSwitch = conf.readEntry( "AnimateSwitch", false ); primaryTabBox = conf.readEntry( "TabBox", true ); secondaryTabBox = conf.readEntry( "TabBoxAlternative", false ); } void BoxSwitchEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ) { if( activeTimeLine.value() != 0.0 && !mProxyActivated ) { if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode ) { if( windows.contains( w )) { if( w == selected_window ) w->enablePainting( EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP ); else data.setTranslucent(); w->enablePainting( EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP ); } } else { if( painting_desktop ) { if( w->isOnDesktop( painting_desktop )) w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); else w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); } } } effects->prePaintWindow( w, data, time ); } void BoxSwitchEffect::prePaintScreen( ScreenPrePaintData& data, int time ) { if( mActivated ) activeTimeLine.addTime( time ); else { activeTimeLine.removeTime( time ); if( activeTimeLine.value() == 0.0 ) { // No longer need the window data qDeleteAll( windows ); windows.clear(); } } if( mActivated && animation ) { timeLine.addTime( time ); calculateItemSizes(); } effects->prePaintScreen( data, time ); } void BoxSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) { effects->paintScreen( mask, region, data ); if( mActivated && !mProxyActivated ) { if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode ) { paintWindowsBox(region); } else { if( !painting_desktop ) { thumbnailFrame.render( region ); QHash< int, ItemInfo* >::const_iterator i; for( i = desktops.constBegin(); i != desktops.constEnd(); ++i ) { painting_desktop = i.key(); if( painting_desktop == selected_desktop ) paintHighlight( desktops[ painting_desktop ]->area ); //effects->desktopName( painting_desktop ) paintDesktopThumbnail( painting_desktop ); } painting_desktop = 0; } } } } void BoxSwitchEffect::paintWindowsBox(const QRegion& region) { thumbnailFrame.render( region ); if( (mAnimateSwitch && !mProxyActivated) || (mProxyActivated && mProxyAnimateSwitch) ) { // HACK: PaintClipper is used because window split is somehow wrong if the height is greater than width PaintClipper::push( frame_area ); paintHighlight( highlight_area ); QHash< EffectWindow*, ItemInfo* >::const_iterator i; for( i = windows.constBegin(); i != windows.constEnd(); ++i ) { paintWindowThumbnail( i.key() ); paintWindowIcon( i.key() ); } PaintClipper::pop( frame_area ); } else { QHash< EffectWindow*, ItemInfo* >::const_iterator i; for( i = windows.constBegin(); i != windows.constEnd(); ++i ) { if( i.key() == selected_window ) paintHighlight( i.value()->area ); paintWindowThumbnail( i.key() ); paintWindowIcon( i.key() ); } } } void BoxSwitchEffect::postPaintScreen() { if( mActivated && activeTimeLine.value() != 1.0 ) effects->addRepaintFull(); if( !mActivated && activeTimeLine.value() != 0.0 ) effects->addRepaintFull(); if( mActivated && animation ) { if( timeLine.value() == 1.0 ) { timeLine.setProgress( 0.0 ); animation = false; if( !scheduled_directions.isEmpty() ) { direction = scheduled_directions.dequeue(); animation = true; } } QRect repaint = QRect( frame_area.x() - item_max_size.width()*0.5, frame_area.y(), frame_area.width() + item_max_size.width(), frame_area.height() ); effects->addRepaint( repaint ); } effects->postPaintScreen(); } void BoxSwitchEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) { if((( mActivated && (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) ) || ( !mActivated && activeTimeLine.value() != 0.0 )) && !mProxyActivated) { if( windows.contains( w ) && w != selected_window ) { if( w->isMinimized() || !w->isOnCurrentDesktop() ) // TODO: When deactivating minimized windows are not painted at all data.opacity *= activeTimeLine.value() * bg_opacity; else data.opacity *= 1.0 - activeTimeLine.value() * ( 1.0 - bg_opacity ); } } effects->paintWindow( w, mask, region, data ); } void BoxSwitchEffect::windowInputMouseEvent( Window w, QEvent* e ) { assert( w == mInput ); Q_UNUSED( w ); if( e->type() != QEvent::MouseButtonPress ) return; QPoint pos = static_cast< QMouseEvent* >( e )->pos(); pos += frame_area.topLeft(); // determine which item was clicked if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode ) { QHash< EffectWindow*, ItemInfo* >::const_iterator i; for( i = windows.constBegin(); i != windows.constEnd(); ++i ) { if( i.value()->clickable.contains( pos )) { effects->setTabBoxWindow( i.key() ); break; } } // special handling for second half of window in case of animation and even number of windows if( mAnimateSwitch && ( windows.size() % 2 == 0 ) ) { QRect additionalRect = QRect( frame_area.x(), frame_area.y(), item_max_size.width()*0.5, item_max_size.height()); if( additionalRect.contains( pos )) { effects->setTabBoxWindow( right_window ); } } } else { QHash< int, ItemInfo* >::const_iterator i; for( i = desktops.constBegin(); i != desktops.constEnd(); ++i ) { if( i.value()->clickable.contains( pos )) effects->setTabBoxDesktop( i.key() ); } } } void BoxSwitchEffect::windowDamaged( EffectWindow* w, const QRect& damage ) { Q_UNUSED( damage ); if( mActivated ) { if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode ) { if( windows.contains( w )) { effects->addRepaint( frame_area ); } } else { if( w->isOnAllDesktops()) { foreach( ItemInfo* info, desktops ) effects->addRepaint( info->area ); } else { effects->addRepaint( desktops[ w->desktop() ]->area ); } } } } void BoxSwitchEffect::windowGeometryShapeChanged( EffectWindow* w, const QRect& old ) { if( mActivated ) { if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode ) { if( windows.contains( w ) && w->size() != old.size()) { effects->addRepaint( windows[ w ]->area ); } } else { if( w->isOnAllDesktops()) { foreach( ItemInfo* info, desktops ) effects->addRepaint( info->area ); } else { effects->addRepaint( desktops[ w->desktop() ]->area ); } } } } void BoxSwitchEffect::tabBoxAdded( int mode ) { if( !mActivated ) { if( ( mode == TabBoxWindowsMode && primaryTabBox ) || ( mode == TabBoxWindowsAlternativeMode && secondaryTabBox) ) { if( effects->currentTabBoxWindowList().count() > 0 ) { mMode = mode; effects->refTabBox(); highlight_is_set = false; animation = false; scheduled_directions.clear(); right_window = 0; setActive(); } } else if( mode == TabBoxDesktopListMode || mode == TabBoxDesktopMode ) { // DesktopMode if( effects->currentTabBoxDesktopList().count() > 0 ) { mMode = mode; painting_desktop = 0; effects->refTabBox(); setActive(); } } } } void BoxSwitchEffect::tabBoxClosed() { if( mActivated ) setInactive(); } void BoxSwitchEffect::tabBoxUpdated() { if( mActivated ) { if( (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) && selected_window != effects->currentTabBoxWindow() ) { if( selected_window != NULL ) { if( (mAnimateSwitch && !mProxyActivated) || (mProxyActivated && mProxyAnimateSwitch) ) { int old_index = effects->currentTabBoxWindowList().indexOf( selected_window ); int new_index = effects->currentTabBoxWindowList().indexOf( effects->currentTabBoxWindow() ); Direction new_direction; int distance = new_index - old_index; if( distance > 0 ) new_direction = Left; if( distance < 0 ) new_direction = Right; if( distance != 0 ) { distance = abs( distance ); int tempDistance = effects->currentTabBoxWindowList().count() - distance; if( tempDistance < abs( distance ) ) { distance = tempDistance; if( new_direction == Left ) new_direction = Right; else new_direction = Left; } if( !animation ) { animation = true; direction = new_direction; distance--; } for( int i=0; icurrentTabBoxWindowList().count() ) scheduled_directions.clear(); } } } if( windows.contains( selected_window )) effects->addRepaint( windows.value( selected_window )->area ); selected_window->addRepaintFull(); } setSelectedWindow( effects->currentTabBoxWindow()); if( windows.contains( selected_window )) effects->addRepaint( windows.value( selected_window )->area ); selected_window->addRepaintFull(); effects->addRepaint( text_area ); } else if( mMode != TabBoxWindowsMode && mMode != TabBoxWindowsAlternativeMode ) { // DesktopMode if( desktops.contains( selected_desktop )) effects->addRepaint( desktops.value( selected_desktop )->area ); selected_desktop = effects->currentTabBoxDesktop(); if( !mProxyActivated || mProxyShowText ) thumbnailFrame.setText( effects->desktopName( selected_desktop )); if( desktops.contains( selected_desktop )) effects->addRepaint( desktops.value( selected_desktop )->area ); effects->addRepaint( text_area ); if( effects->currentTabBoxDesktopList() == original_desktops ) return; original_desktops = effects->currentTabBoxDesktopList(); } // for safety copy list each time tabbox is updated original_windows = effects->currentTabBoxWindowList(); effects->addRepaint( frame_area ); calculateFrameSize(); calculateItemSizes(); moveResizeInputWindow( frame_area.x(), frame_area.y(), frame_area.width(), frame_area.height()); effects->addRepaint( frame_area ); } } void BoxSwitchEffect::setActive() { mActivated = true; // Just in case we are activated again before the deactivation animation finished qDeleteAll( windows ); windows.clear(); if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode ) { original_windows = effects->currentTabBoxWindowList(); setSelectedWindow( effects->currentTabBoxWindow()); } else { original_desktops = effects->currentTabBoxDesktopList(); selected_desktop = effects->currentTabBoxDesktop(); if( !mProxyActivated || mProxyShowText ) thumbnailFrame.setText( effects->desktopName( selected_desktop )); } calculateFrameSize(); calculateItemSizes(); if( !mProxyActivated ) { // only create the input window when effect is not activated via the proxy mInput = effects->createInputWindow( this, frame_area.x(), frame_area.y(), frame_area.width(), frame_area.height(), Qt::ArrowCursor ); } effects->addRepaint( frame_area ); if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode ) { QHash< EffectWindow*, ItemInfo* >::const_iterator i; for( i = windows.constBegin(); i != windows.constEnd(); ++i ) { i.key()->addRepaintFull(); } } } void BoxSwitchEffect::setInactive() { mActivated = false; effects->unrefTabBox(); if( !mProxyActivated && mInput != None ) { effects->destroyInputWindow( mInput ); mInput = None; } mProxyActivated = false; mPositioningFactor = 0.5f; if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode ) { QHash< EffectWindow*, ItemInfo* >::const_iterator i; for( i = windows.constBegin(); i != windows.constEnd(); ++i ) { if( i.key() != selected_window ) i.key()->addRepaintFull(); } // We don't unset the selected window so we have correct fading // But we do need to remove elevation status if( elevate_window && selected_window ) effects->setElevatedWindow( selected_window, false ); foreach( EffectWindow* w, referrencedWindows ) { w->unrefWindow(); } referrencedWindows.clear(); } else { // DesktopMode qDeleteAll( windows ); desktops.clear(); } thumbnailFrame.free(); effects->addRepaint( frame_area ); frame_area = QRect(); } void BoxSwitchEffect::setSelectedWindow( EffectWindow* w ) { if( elevate_window && selected_window ) { effects->setElevatedWindow( selected_window, false ); } selected_window = w; if( selected_window && ( !mProxyActivated || mProxyShowText ) ) thumbnailFrame.setText( selected_window->caption() ); if( elevate_window && w ) { effects->setElevatedWindow( selected_window, true ); } } void BoxSwitchEffect::windowClosed( EffectWindow* w ) { if( w == selected_window ) { setSelectedWindow( 0 ); } if( windows.contains( w ) ) { w->refWindow(); referrencedWindows.append( w ); original_windows.removeAll( w ); delete windows[ w ]; windows.remove( w ); effects->addRepaintFull(); } } void BoxSwitchEffect::moveResizeInputWindow( int x, int y, int width, int height ) { XMoveWindow( display(), mInput, x, y ); XResizeWindow( display(), mInput, width, height ); } void BoxSwitchEffect::calculateFrameSize() { int itemcount; if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode ) { itemcount = original_windows.count(); item_max_size.setWidth( 200 ); item_max_size.setHeight( 200 ); } else { itemcount = original_desktops.count(); item_max_size.setWidth( 200 ); item_max_size.setHeight( 200 ); } // How much height to reserve for a one-line text label text_area.setHeight( QFontMetrics( text_font ).height() * 1.2 ); // Separator space between items and text const int separator_height = 6; // Shrink the size until all windows/desktops can fit onscreen frame_area.setWidth( itemcount * item_max_size.width()); QRect screenr = effects->clientArea( PlacementArea, effects->activeScreen(), effects->currentDesktop()); while( frame_area.width() > screenr.width()) { item_max_size /= 2; frame_area.setWidth( itemcount * item_max_size.width()); } frame_area.setHeight( item_max_size.height() + separator_height + text_area.height()); if( mProxyActivated && !mProxyShowText ) frame_area.setHeight( item_max_size.height() ); text_area.setWidth( frame_area.width() ); frame_area.moveTo( screenr.x() + ( screenr.width() - frame_area.width()) / 2, screenr.y() + ( screenr.height() - frame_area.height()) / 2 * mPositioningFactor * 2 ); text_area.moveTo( frame_area.x(), frame_area.y() + item_max_size.height() + separator_height); thumbnailFrame.setGeometry( frame_area ); } void BoxSwitchEffect::calculateItemSizes() { if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode ) { qDeleteAll( windows ); windows.clear(); if( (mAnimateSwitch && !mProxyActivated) || (mProxyActivated && mProxyAnimateSwitch) ) { int index = original_windows.indexOf( effects->currentTabBoxWindow() ); int leftIndex = index; int rightIndex = index + 1; if( rightIndex == original_windows.count() ) rightIndex = 0; EffectWindowList ordered_windows; int leftWindowCount = original_windows.count()/2; int rightWindowCount = leftWindowCount; if( original_windows.count()%2 == 1 ) leftWindowCount++; for( int i=0; i < leftWindowCount; i++ ) { int tempIndex = ( leftIndex - i ); if( tempIndex < 0 ) tempIndex = original_windows.count() + tempIndex; ordered_windows.prepend( original_windows[ tempIndex ] ); } for( int i=0; i < rightWindowCount; i++ ) { int tempIndex = ( rightIndex + i ) % original_windows.count(); ordered_windows.append( original_windows[ tempIndex ] ); } // move items cause of schedule for( int i=0; i < scheduled_directions.count(); i++ ) { Direction actual = scheduled_directions[ i ]; if( actual == Left ) { EffectWindow* w = ordered_windows.takeLast(); ordered_windows.prepend( w ); } else { EffectWindow* w = ordered_windows.takeFirst(); ordered_windows.append( w ); } } if( animation && timeLine.value() < 0.5 ) { if( direction == Left ) { EffectWindow* w = ordered_windows.takeLast(); edge_window = w; ordered_windows.prepend( w ); } else { EffectWindow* w = ordered_windows.takeFirst(); edge_window = w; ordered_windows.append( w ); } } else if( animation && timeLine.value() >= 0.5 ) { if( animation && direction == Left ) edge_window = ordered_windows.last(); if( animation && direction == Right ) edge_window = ordered_windows.first(); } int offset = 0; if( animation ) { if( direction == Left ) offset = (float)item_max_size.width()*(1.0-timeLine.value()); else offset = -(float)item_max_size.width()*(1.0-timeLine.value()); } for( int i = 0; i < ordered_windows.count(); i++ ) { if( !ordered_windows.at( i ) ) continue; EffectWindow* w = ordered_windows.at( i ); windows[ w ] = new ItemInfo(); windows[ w ]->iconFrame = new EffectFrame( EffectFrame::Unstyled, false ); windows[ w ]->iconFrame->setAlignment( Qt::AlignTop | Qt::AlignLeft ); windows[ w ]->iconFrame->setIcon( w->icon() ); float moveIndex = i; if( animation && timeLine.value() < 0.5 ) { if( direction == Left ) moveIndex--; else moveIndex++; } if( ordered_windows.count()%2 == 0 ) moveIndex += 0.5; windows[ w ]->area = QRect( frame_area.x() + moveIndex * item_max_size.width() + offset, frame_area.y(), item_max_size.width(), item_max_size.height()); windows[ w ]->clickable = windows[ w ]->area; } if( ordered_windows.count()%2 == 0 ) { right_window = ordered_windows.last(); } if( !highlight_is_set ) { highlight_area = windows[ selected_window ]->area; highlight_is_set = true; } } else { for( int i = 0; i < original_windows.count(); i++ ) { if( !original_windows.at( i ) ) continue; EffectWindow* w = original_windows.at( i ); windows[ w ] = new ItemInfo(); windows[ w ]->iconFrame = new EffectFrame( EffectFrame::Unstyled, false ); windows[ w ]->iconFrame->setAlignment( Qt::AlignTop | Qt::AlignLeft ); windows[ w ]->iconFrame->setIcon( w->icon() ); windows[ w ]->area = QRect( frame_area.x() + i * item_max_size.width(), frame_area.y(), item_max_size.width(), item_max_size.height()); windows[ w ]->clickable = windows[ w ]->area; } } } else { desktops.clear(); for( int i = 0; i < original_desktops.count(); i++ ) { int it = original_desktops.at( i ); desktops[ it ] = new ItemInfo(); desktops[ it ]->area = QRect( frame_area.x() + i * item_max_size.width(), frame_area.y(), item_max_size.width(), item_max_size.height()); desktops[ it ]->clickable = desktops[ it ]->area; } } } void BoxSwitchEffect::paintHighlight( QRect area ) { #ifdef KWIN_HAVE_OPENGL_COMPOSITING if( effects->compositingType() == OpenGLCompositing ) { glPushAttrib( GL_CURRENT_BIT ); glColor4f( color_highlight.redF(), color_highlight.greenF(), color_highlight.blueF(), color_highlight.alphaF()); renderRoundBox( area, 6 ); glPopAttrib(); } #endif #ifdef KWIN_HAVE_XRENDER_COMPOSITING if( effects->compositingType() == XRenderCompositing ) { Pixmap pixmap = XCreatePixmap( display(), rootWindow(), area.width(), area.height(), 32 ); XRenderPicture pic( pixmap, 32 ); XFreePixmap( display(), pixmap ); XRenderColor col; col.alpha = int( color_highlight.alphaF() * 0xffff ); col.red = int( color_highlight.redF() * color_highlight.alphaF() * 0xffff ); col.green = int( color_highlight.greenF() * color_highlight.alphaF() * 0xffff ); col.blue = int( color_highlight.blueF() * color_highlight.alphaF() * 0xffff ); XRenderFillRectangle( display(), PictOpSrc, pic, &col, 0, 0, area.width(), area.height()); XRenderComposite( display(), color_highlight.alphaF() != 1.0 ? PictOpOver : PictOpSrc, pic, None, effects->xrenderBufferPicture(), 0, 0, 0, 0, area.x(), area.y(), area.width(), area.height()); } #endif } void BoxSwitchEffect::paintWindowThumbnail( EffectWindow* w ) { if( !windows.contains( w )) return; WindowPaintData data( w ); setPositionTransformations( data, windows[ w ]->thumbnail, w, windows[ w ]->area.adjusted( highlight_margin, highlight_margin, -highlight_margin, -highlight_margin ), Qt::KeepAspectRatio ); if( animation && ( w == edge_window ) && ( windows.size() % 2 == 1 ) ) { // in case of animation: // the window which has to change the side will be split and painted on both sides of the edge double splitPoint = 0.0; if( direction == Left ) { splitPoint = w->geometry().width()*timeLine.value(); } else { splitPoint = w->geometry().width() - w->geometry().width()*timeLine.value(); } data.quads = data.quads.splitAtX( splitPoint ); WindowQuadList left_quads; WindowQuadList right_quads; foreach( const WindowQuad &quad, data.quads ) { if( quad.left() >= splitPoint ) left_quads << quad; if( quad.right() <= splitPoint ) right_quads << quad; } // the base position of the window is changed after half of the animation if( timeLine.value() < 0.5 ) { if( direction == Left ) data.quads = left_quads; else data.quads = right_quads; } else { if( direction == Left ) data.quads = right_quads; else data.quads = left_quads; } // paint one part of the thumbnail effects->paintWindow( w, PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED, windows[ w ]->thumbnail, data ); QRect secondThumbnail; // paint the second part of the thumbnail: // the other window quads are needed and a new rect for transformation has to be calculated if( direction == Left ) { if( timeLine.value() < 0.5 ) { data.quads = right_quads; secondThumbnail = QRect( frame_area.x() + frame_area.width() - (float)item_max_size.width()*timeLine.value(), frame_area.y(), item_max_size.width(), item_max_size.height()); } else { data.quads = left_quads; secondThumbnail = QRect( frame_area.x() - (float)item_max_size.width()*timeLine.value(), frame_area.y(), item_max_size.width(), item_max_size.height()); if( right_window ) secondThumbnail = QRect( frame_area.x() - (float)item_max_size.width()*(timeLine.value()-0.5), frame_area.y(), item_max_size.width(), item_max_size.height()); } } else { if( timeLine.value() < 0.5 ) { data.quads = left_quads; secondThumbnail = QRect( frame_area.x() - (float)item_max_size.width()*(1.0 - timeLine.value()), frame_area.y(), item_max_size.width(), item_max_size.height()); } else { data.quads = right_quads; secondThumbnail = QRect( frame_area.x() + frame_area.width() - (float)item_max_size.width()*(1.0 - timeLine.value()), frame_area.y(), item_max_size.width(), item_max_size.height()); } } setPositionTransformations( data, windows[ w ]->thumbnail, w, secondThumbnail.adjusted( highlight_margin, highlight_margin, -highlight_margin, -highlight_margin ), Qt::KeepAspectRatio ); effects->paintWindow( w, PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED, windows[ w ]->thumbnail, data ); } else if( ( windows.size() % 2 == 0 ) && ( w == right_window ) ) { // in case of even number of thumbnails: // the window on the right is painted one half on left and on half on the right side float animationOffset = 0.0f; double splitPoint = w->geometry().width()*0.5; if( animation && timeLine.value() <= 0.5 ) { // in case of animation the right window has only to be split during first half of animation if( direction == Left ) { splitPoint += w->geometry().width()*timeLine.value(); animationOffset = -(float)item_max_size.width()*timeLine.value(); } else { splitPoint -= w->geometry().width()*timeLine.value(); animationOffset = (float)item_max_size.width()*timeLine.value(); } } if( animation && timeLine.value() > 0.5 ) { // at half of animation a different window has become the right window // we have to adjust the splitting again if( direction == Left ) { splitPoint -= w->geometry().width()*(1.0-timeLine.value()); animationOffset = (float)item_max_size.width()*(1.0-timeLine.value()); } else { splitPoint += w->geometry().width()*(1.0-timeLine.value()); animationOffset = -(float)item_max_size.width()*(1.0-timeLine.value()); } } data.quads = data.quads.splitAtX( splitPoint ); WindowQuadList rightQuads; WindowQuadList leftQuads; foreach( const WindowQuad &quad, data.quads ) { if( quad.right() <= splitPoint ) leftQuads << quad; else rightQuads << quad; } // left quads are painted on right side of frame data.quads = leftQuads; effects->drawWindow( w, PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED, windows[ w ]->thumbnail, data ); // right quads are painted on left side of frame data.quads = rightQuads; QRect secondThumbnail; secondThumbnail = QRect( frame_area.x() - (float)item_max_size.width()*0.5 + animationOffset, frame_area.y(), item_max_size.width(), item_max_size.height()); setPositionTransformations( data, windows[ w ]->thumbnail, w, secondThumbnail.adjusted( highlight_margin, highlight_margin, -highlight_margin, -highlight_margin ), Qt::KeepAspectRatio ); effects->drawWindow( w, PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED, windows[ w ]->thumbnail, data ); } else { effects->drawWindow( w, PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED, windows[ w ]->thumbnail, data ); } } void BoxSwitchEffect::paintDesktopThumbnail( int iDesktop ) { if( !desktops.contains( iDesktop )) return; ScreenPaintData data; QRect region; QRect r = desktops[ iDesktop ]->area.adjusted( highlight_margin, highlight_margin, -highlight_margin, -highlight_margin ); QSize size = QSize( displayWidth(), displayHeight()); size.scale( r.size(), Qt::KeepAspectRatio ); data.xScale = size.width() / double( displayWidth()); data.yScale = size.height() / double( displayHeight()); int width = int( displayWidth() * data.xScale ); int height = int( displayHeight() * data.yScale ); int x = r.x() + ( r.width() - width ) / 2; int y = r.y() + ( r.height() - height ) / 2; region = QRect( x, y, width, height ); data.xTranslate = x; data.yTranslate = y; effects->paintScreen( PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST, region, data ); } void BoxSwitchEffect::paintWindowIcon( EffectWindow* w ) { if( !windows.contains( w )) return; // Don't render null icons if( w->icon().isNull() ) { return; } int width = w->icon().width(); int height = w->icon().height(); int x = windows[ w ]->area.x() + windows[ w ]->area.width() - width - highlight_margin; int y = windows[ w ]->area.y() + windows[ w ]->area.height() - height - highlight_margin; if( ( windows.size() % 2 == 0 ) ) { if( w == right_window ) { // in case of right window the icon has to be painted on the left side of the frame x = frame_area.x() + windows[ w ]->area.width()*0.5 - width - highlight_margin; if( animation ) { if( timeLine.value() <= 0.5 ) { if( direction == Left ) { x -= windows[ w ]->area.width()*timeLine.value(); x = qMax( x, frame_area.x() ); } else x += windows[ w ]->area.width()*timeLine.value(); } else { if( direction == Left ) x += windows[ w ]->area.width()*(1.0-timeLine.value()); else { x -= windows[ w ]->area.width()*(1.0-timeLine.value()); x = qMax( x, frame_area.x() ); } } } } } else { // during animation the icon of the edge window has to change position if( animation && w == edge_window ) { if( timeLine.value() < 0.5 ) { if( direction == Left ) x += windows[ w ]->area.width()*timeLine.value(); else x -= windows[ w ]->area.width()*timeLine.value(); } else { if( direction == Left ) x -= windows[ w ]->area.width()*(1.0 - timeLine.value()); else x += windows[ w ]->area.width()*(1.0 - timeLine.value()); } } } windows[ w ]->iconFrame->setPosition( QPoint( x, y )); windows[ w ]->iconFrame->render( infiniteRegion(), 1.0, 0.75 ); } void* BoxSwitchEffect::proxy() { return &mProxy; } void BoxSwitchEffect::activateFromProxy( int mode, bool animate, bool showText, float positioningFactor ) { if( !mActivated ) { mProxyActivated = true; mProxyAnimateSwitch = animate; mProxyShowText = showText; mPositioningFactor = positioningFactor; thumbnailFrame.setText(" "); if( ( mode == TabBoxWindowsMode ) || ( mode == TabBoxWindowsAlternativeMode ) ) { if( effects->currentTabBoxWindowList().count() > 0 ) { mMode = mode; effects->refTabBox(); highlight_is_set = false; animation = false; scheduled_directions.clear(); right_window = 0; setActive(); } } else if( mode == TabBoxDesktopListMode || mode == TabBoxDesktopMode ) { // DesktopMode if( effects->currentTabBoxDesktopList().count() > 0 ) { mMode = mode; painting_desktop = 0; effects->refTabBox(); setActive(); } } if( !mActivated ) mProxyActivated = false; } } BoxSwitchEffect::ItemInfo::ItemInfo() : iconFrame( NULL ) { } BoxSwitchEffect::ItemInfo::~ItemInfo() { delete iconFrame; } } // namespace