/***************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee> You can Freely distribute this program under the GNU General Public License. See the file "COPYING" for the exact licensing terms. ******************************************************************/ #include "presentwindows.h" #include <kactioncollection.h> #include <kaction.h> #include <klocale.h> #include <QMouseEvent> #include <qpainter.h> #include <math.h> #include <assert.h> #include <limits.h> namespace KWin { KWIN_EFFECT( presentwindows, PresentWindowsEffect ) PresentWindowsEffect::PresentWindowsEffect() : mShowWindowsFromAllDesktops ( false ) , mActivated( false ) , mActiveness( 0.0 ) , mRearranging( 1.0 ) , hasKeyboardGrab( false ) , mHoverWindow( NULL ) #ifdef HAVE_OPENGL , filterTexture( NULL ) #endif { KConfigGroup conf = effects->effectConfig("PresentWindows"); KActionCollection* actionCollection = new KActionCollection( this ); KAction* a = (KAction*)actionCollection->addAction( "Expose" ); a->setText( i18n("Toggle Expose effect" )); a->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F10)); connect(a, SIGNAL(triggered(bool)), this, SLOT(toggleActive())); KAction* b = (KAction*)actionCollection->addAction( "ExposeAll" ); b->setText( i18n("Toggle Expose effect (incl other desktops)" )); b->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F11)); connect(b, SIGNAL(triggered(bool)), this, SLOT(toggleActiveAllDesktops())); borderActivate = (ElectricBorder)conf.readEntry("BorderActivate", (int)ElectricTopRight); borderActivateAll = (ElectricBorder)conf.readEntry("BorderActivateAll", (int)ElectricNone); effects->reserveElectricBorder( borderActivate ); effects->reserveElectricBorder( borderActivateAll ); #ifdef HAVE_XRENDER alphaFormat = XRenderFindStandardFormat( display(), PictStandardARGB32 ); #endif } PresentWindowsEffect::~PresentWindowsEffect() { effects->unreserveElectricBorder( borderActivate ); effects->unreserveElectricBorder( borderActivateAll ); discardFilterTexture(); } void PresentWindowsEffect::prePaintScreen( ScreenPrePaintData& data, int time ) { // How long does it take for the effect to get it's full strength (in ms) const float changeTime = 300; if(mActivated) { mActiveness = qMin(1.0f, mActiveness + time/changeTime); if( mRearranging < 1 ) mRearranging = qMin(1.0f, mRearranging + time/changeTime); } else if(mActiveness > 0.0f) { mActiveness = qMax(0.0f, mActiveness - time/changeTime); if(mActiveness <= 0.0f) effectTerminated(); } // We need to mark the screen windows as transformed. Otherwise the whole // screen won't be repainted, resulting in artefacts if( mActiveness > 0.0f ) data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; effects->prePaintScreen(data, time); } void PresentWindowsEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ) { if( mActiveness > 0.0f ) { if( mWindowData.contains(w) ) { // This window will be transformed by the effect data.setTransformed(); w->enablePainting( EffectWindow::PAINT_DISABLED_BY_MINIMIZE ); w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); // If it's minimized window or on another desktop and effect is not // fully active, then apply some transparency if( mActiveness < 1.0f && (w->isMinimized() || !w->isOnCurrentDesktop() )) data.setTranslucent(); // Change window's hover according to cursor pos WindowData& windata = mWindowData[w]; const float hoverchangetime = 200; if( windata.area.contains(cursorPos()) ) windata.hover = qMin(1.0f, windata.hover + time / hoverchangetime); else windata.hover = qMax(0.0f, windata.hover - time / hoverchangetime); } else if( !w->isDesktop()) w->disablePainting( EffectWindow::PAINT_DISABLED ); } effects->prePaintWindow( w, data, time ); } void PresentWindowsEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) { effects->paintScreen( mask, region, data ); #ifdef HAVE_OPENGL if( filterTexture && region.intersects( filterFrameRect )) { glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // First render the frame QColor color = QPalette().color( QPalette::Highlight ); glColor4f( color.redF(), color.greenF(), color.blueF(), 0.75f ); renderRoundBoxWithEdge( filterFrameRect ); // And then the text on top of it filterTexture->bind(); filterTexture->render( mask, region, filterTextureRect ); filterTexture->unbind(); glPopAttrib(); } #endif } void PresentWindowsEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) { if(mActiveness > 0.0f && mWindowData.contains(w)) { // Change window's position and scale const WindowData& windata = mWindowData[w]; if( mRearranging < 1 ) // rearranging { if( windata.old_area.isEmpty()) // no old position { data.xScale = windata.scale; data.yScale = windata.scale; data.xTranslate = windata.area.left() - w->x(); data.yTranslate = windata.area.top() - w->y(); data.opacity *= interpolate(0.0, 1.0, mRearranging); } else { data.xScale = interpolate(windata.old_scale, windata.scale, mRearranging); data.yScale = interpolate(windata.old_scale, windata.scale, mRearranging); data.xTranslate = (int)interpolate(windata.old_area.left() - w->x(), windata.area.left() - w->x(), mRearranging); data.yTranslate = (int)interpolate(windata.old_area.top() - w->y(), windata.area.top() - w->y(), mRearranging); } } else { data.xScale = interpolate(data.xScale, windata.scale, mActiveness); data.yScale = interpolate(data.xScale, windata.scale, mActiveness); data.xTranslate = (int)interpolate(data.xTranslate, windata.area.left() - w->x(), mActiveness); data.yTranslate = (int)interpolate(data.yTranslate, windata.area.top() - w->y(), mActiveness); } // Darken all windows except for the one under the cursor data.brightness *= interpolate(1.0, 0.7, mActiveness * (1.0f - windata.hover)); // If it's minimized window or on another desktop and effect is not // fully active, then apply some transparency if( mActiveness < 1.0f && (w->isMinimized() || !w->isOnCurrentDesktop() )) data.opacity *= interpolate(0.0, 1.0, mActiveness); } // Call the next effect. effects->paintWindow( w, mask, region, data ); if(mActiveness > 0.0f && mWindowData.contains(w)) { paintWindowIcon( w, data ); } } void PresentWindowsEffect::postPaintScreen() { if( mActivated && mActiveness < 1.0 ) // activating effect effects->addRepaintFull(); if( mActivated && mRearranging < 1.0 ) // rearranging effects->addRepaintFull(); if( !mActivated && mActiveness > 0.0 ) // deactivating effect effects->addRepaintFull(); foreach( const WindowData& d, mWindowData ) { if( d.hover > 0 && d.hover < 1 ) // changing highlight effects->addRepaintFull(); } // Call the next effect. effects->postPaintScreen(); } void PresentWindowsEffect::windowInputMouseEvent( Window w, QEvent* e ) { assert( w == mInput ); if( e->type() == QEvent::MouseMove ) { // Repaint if the hovered-over window changed. // (No need to use cursorMoved(), this takes care of it as well) for( DataHash::ConstIterator it = mWindowData.begin(); it != mWindowData.end(); ++it ) { if( (*it).area.contains( cursorPos())) { if( mHoverWindow != it.key()) { mHoverWindow = it.key(); effects->addRepaintFull(); // screen is transformed, so paint all } return; } } return; } if( e->type() != QEvent::MouseButtonPress ) return; if( static_cast< QMouseEvent* >( e )->button() != Qt::LeftButton ) { setActive( false ); return; } // Find out which window (if any) was clicked and activate it QPoint pos = static_cast< QMouseEvent* >( e )->pos(); for( DataHash::iterator it = mWindowData.begin(); it != mWindowData.end(); ++it ) { if( it.value().area.contains(pos) ) { effects->activateWindow( it.key() ); // mWindowData gets cleared and rebuilt when a window is // activated, so it's dangerous (and unnecessary) to continue break; } } // Deactivate effect, no matter if any window was actually activated setActive(false); } void PresentWindowsEffect::windowClosed( EffectWindow* w ) { if( mHoverWindow == w ) mHoverWindow = NULL; mWindowsToPresent.remove( w ); rearrangeWindows(); } void PresentWindowsEffect::setActive(bool active) { if( mActivated == active ) return; mActivated = active; mHoverWindow = NULL; if( mActivated ) { mWindowData.clear(); effectActivated(); mActiveness = 0; windowFilter.clear(); mWindowsToPresent.clear(); const EffectWindowList& originalwindowlist = effects->stackingOrder(); // Filter out special windows such as panels and taskbars foreach( EffectWindow* window, originalwindowlist ) { if( window->isSpecialWindow() ) continue; if( window->isDeleted()) continue; if( !mShowWindowsFromAllDesktops && !window->isOnCurrentDesktop() ) continue; mWindowsToPresent.append(window); } rearrangeWindows(); } else { mWindowsToPresent.clear(); mRearranging = 1; // turn off mActiveness = 1; // go back from arranged position discardFilterTexture(); } effects->addRepaintFull(); // trigger next animation repaint } void PresentWindowsEffect::effectActivated() { // Create temporary input window to catch mouse events mInput = effects->createFullScreenInputWindow( this, Qt::PointingHandCursor ); hasKeyboardGrab = effects->grabKeyboard( this ); } void PresentWindowsEffect::effectTerminated() { // Destroy the temporary input window effects->destroyInputWindow( mInput ); if( hasKeyboardGrab ) effects->ungrabKeyboard(); hasKeyboardGrab = false; } void PresentWindowsEffect::rearrangeWindows() { if( !mActivated ) return; EffectWindowList windowlist; if( windowFilter.isEmpty()) windowlist = mWindowsToPresent; else { foreach( EffectWindow* w, mWindowsToPresent ) { if( w->caption().contains( windowFilter, Qt::CaseInsensitive ) || w->windowClass().contains( windowFilter, Qt::CaseInsensitive )) windowlist.append( w ); } } if( windowlist.isEmpty()) { mWindowData.clear(); effects->addRepaintFull(); return; } if( !mWindowData.isEmpty()) // this is not the first arranging { bool rearrange = canRearrangeClosest( windowlist ); // called before manipulating mWindowData DataHash newdata; EffectWindowList newlist = windowlist; EffectWindowList oldlist = mWindowData.keys(); qSort( newlist ); qSort( oldlist ); for( DataHash::ConstIterator it = mWindowData.begin(); it != mWindowData.end(); ++it ) if( windowlist.contains( it.key())) // remove windows that are not in the window list newdata[ it.key() ] = *it; mWindowData = newdata; if( !rearrange && newlist == oldlist ) return; for( DataHash::Iterator it = mWindowData.begin(); it != mWindowData.end(); ++it ) { (*it).old_area = (*it).area; (*it).old_scale = (*it).scale; } // Initialize new entries foreach( EffectWindow* w, windowlist ) if( !mWindowData.contains( w )) { mWindowData[ w ].hover = 0; } mRearranging = 0; // start animation again } // Calculate new positions and scales for windows // calculateWindowTransformationsDumb( windowlist ); // calculateWindowTransformationsKompose( windowlist ); calculateWindowTransformationsClosest( windowlist ); // Schedule entire desktop to be repainted effects->addRepaintFull(); } void PresentWindowsEffect::calculateWindowTransformationsDumb(EffectWindowList windowlist) { // Calculate number of rows/cols int rows = windowlist.count() / 4 + 1; int cols = windowlist.count() / rows + windowlist.count() % rows; // Get rect which we can use on current desktop. This excludes e.g. panels QRect placementRect = effects->clientArea( PlacementArea, QPoint( 0, 0 ), 0 ); // Size of one cell int cellwidth = placementRect.width() / cols; int cellheight = placementRect.height() / rows; kDebug() << "Got " << windowlist.count() << " clients, using " << rows << "x" << cols << " grid"; // Calculate position and scale factor for each window int i = 0; foreach( EffectWindow* window, windowlist ) { // Row/Col of this window int r = i / cols; int c = i % cols; mWindowData[window].hover = 0.0f; mWindowData[window].scale = qMin(cellwidth / (float)window->width(), cellheight / (float)window->height()); mWindowData[window].area.setLeft(placementRect.left() + cellwidth * c); mWindowData[window].area.setTop(placementRect.top() + cellheight * r); mWindowData[window].area.setWidth((int)(window->width() * mWindowData[window].scale)); mWindowData[window].area.setHeight((int)(window->height() * mWindowData[window].scale)); kDebug() << "Window '" << window->caption() << "' gets moved to (" << mWindowData[window].area.left() << "; " << mWindowData[window].area.right() << "), scale: " << mWindowData[window].scale << endl; i++; } } float PresentWindowsEffect::windowAspectRatio(EffectWindow* c) { return c->width() / (float)c->height(); } int PresentWindowsEffect::windowWidthForHeight(EffectWindow* c, int h) { return (int)((h / (float)c->height()) * c->width()); } int PresentWindowsEffect::windowHeightForWidth(EffectWindow* c, int w) { return (int)((w / (float)c->width()) * c->height()); } void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowList windowlist) { // Get rect which we can use on current desktop. This excludes e.g. panels QRect availRect = effects->clientArea( PlacementArea, QPoint( 0, 0 ), effects->currentDesktop()); // Following code is taken from Kompose 0.5.4, src/komposelayout.cpp int spacing = 10; int rows, columns; float parentRatio = availRect.width() / (float)availRect.height(); // Use more columns than rows when parent's width > parent's height if ( parentRatio > 1 ) { columns = (int)ceil( sqrt(windowlist.count()) ); rows = (int)ceil( (float)windowlist.count() / (float)columns ); } else { rows = (int)ceil( sqrt(windowlist.count()) ); columns = (int)ceil( (float)windowlist.count() / (float)rows ); } kDebug() << "Using " << rows << " rows & " << columns << " columns for " << windowlist.count() << " clients"; // Calculate width & height int w = (availRect.width() - (columns+1) * spacing ) / columns; int h = (availRect.height() - (rows+1) * spacing ) / rows; EffectWindowList::iterator it( windowlist.begin() ); QList<QRect> geometryRects; QList<int> maxRowHeights; // Process rows for ( int i=0; i<rows; ++i ) { int xOffsetFromLastCol = 0; int maxHeightInRow = 0; // Process columns for ( int j=0; j<columns; ++j ) { EffectWindow* window; // Check for end of List if ( it == windowlist.end() ) break; window = *it; // Calculate width and height of widget float ratio = windowAspectRatio(window); int widgetw = 100; int widgeth = 100; int usableW = w; int usableH = h; // use width of two boxes if there is no right neighbour if (window == windowlist.last() && j != columns-1) { usableW = 2*w; } ++it; // We need access to the neighbour in the following // expand if right neighbour has ratio < 1 if (j != columns-1 && it != windowlist.end() && windowAspectRatio(*it) < 1) { int addW = w - windowWidthForHeight(*it, h); if ( addW > 0 ) { usableW = w + addW; } } if ( ratio == -1 ) { widgetw = w; widgeth = h; } else { float widthForHeight = windowWidthForHeight(window, usableH); float heightForWidth = windowHeightForWidth(window, usableW); if ( (ratio >= 1.0 && heightForWidth <= usableH) || (ratio < 1.0 && widthForHeight > usableW) ) { widgetw = usableW; widgeth = (int)heightForWidth; } else if ( (ratio < 1.0 && widthForHeight <= usableW) || (ratio >= 1.0 && heightForWidth > usableH) ) { widgeth = usableH; widgetw = (int)widthForHeight; } } // Set the Widget's size int alignmentXoffset = 0; int alignmentYoffset = 0; if ( i==0 && h > widgeth ) alignmentYoffset = h - widgeth; if ( j==0 && w > widgetw ) alignmentXoffset = w - widgetw; QRect geom( availRect.x() + j * (w + spacing) + spacing + alignmentXoffset + xOffsetFromLastCol, availRect.y() + i * (h + spacing) + spacing + alignmentYoffset, widgetw, widgeth ); geometryRects.append(geom); // Set the x offset for the next column if (alignmentXoffset==0) xOffsetFromLastCol += widgetw-w; if (maxHeightInRow < widgeth) maxHeightInRow = widgeth; } maxRowHeights.append(maxHeightInRow); } int topOffset = 0; for( int i = 0; i < rows; i++ ) { for( int j = 0; j < columns; j++ ) { int pos = i*columns + j; if(pos >= windowlist.count()) break; EffectWindow* window = windowlist[pos]; QRect geom = geometryRects[pos]; geom.setY( geom.y() + topOffset ); mWindowData[window].area = geom; mWindowData[window].scale = geom.width() / (float)window->width(); mWindowData[window].hover = 0.0f; kDebug() << "Window '" << window->caption() << "' gets moved to (" << mWindowData[window].area.left() << "; " << mWindowData[window].area.right() << "), scale: " << mWindowData[window].scale << endl; } if ( maxRowHeights[i]-h > 0 ) topOffset += maxRowHeights[i]-h; } } void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowList windowlist) { QRect area = effects->clientArea( PlacementArea, QPoint( 0, 0 ), effects->currentDesktop()); int columns = int( ceil( sqrt( windowlist.count()))); int rows = int( ceil( windowlist.count() / float( columns ))); foreach( EffectWindow* w, windowlist ) mWindowData[ w ].slot = -1; for(;;) { // Assign each window to the closest available slot assignSlots( area, columns, rows ); // Leave only the closest window in each slot, remove further conflicts getBestAssignments(); bool all_assigned = true; foreach( EffectWindow* w, windowlist ) if( mWindowData[ w ].slot == -1 ) { all_assigned = false; break; } if( all_assigned ) break; // ok } int slotwidth = area.width() / columns; int slotheight = area.height() / rows; for( DataHash::Iterator it = mWindowData.begin(); it != mWindowData.end(); ++it ) { QRect geom( area.x() + ((*it).slot % columns ) * slotwidth, area.y() + ((*it).slot / columns ) * slotheight, slotwidth, slotheight ); geom.adjust( 10, 10, -10, -10 ); // borders float scale; EffectWindow* w = it.key(); if( geom.width() / float( w->width()) < geom.height() / float( w->height())) { // center vertically scale = geom.width() / float( w->width()); geom.moveTop( geom.top() + ( geom.height() - int( w->height() * scale )) / 2 ); geom.setHeight( int( w->height() * scale )); } else { // center horizontally scale = geom.height() / float( w->height()); geom.moveLeft( geom.left() + ( geom.width() - int( w->width() * scale )) / 2 ); geom.setWidth( int( w->width() * scale )); } (*it).area = geom; (*it).scale = scale; } } void PresentWindowsEffect::assignSlots( const QRect& area, int columns, int rows ) { QVector< bool > taken; taken.fill( false, columns * rows ); foreach( const WindowData& d, mWindowData ) { if( d.slot != -1 ) taken[ d.slot ] = true; } int slotwidth = area.width() / columns; int slotheight = area.height() / rows; for( DataHash::Iterator it = mWindowData.begin(); it != mWindowData.end(); ++it ) { if( (*it).slot != -1 ) continue; // it already has a slot QPoint pos = it.key()->geometry().center(); if( pos.x() < area.left()) pos.setX( area.left()); if( pos.x() > area.right()) pos.setX( area.right()); if( pos.y() < area.top()) pos.setY( area.top()); if( pos.y() > area.bottom()) pos.setY( area.bottom()); int distance = INT_MAX; for( int x = 0; x < columns; ++x ) for( int y = 0; y < rows; ++y ) { int slot = x + y * columns; if( taken[ slot ] ) continue; int xdiff = pos.x() - ( area.x() + slotwidth * x + slotwidth / 2 ); // slotwidth/2 for center int ydiff = pos.y() - ( area.y() + slotheight * y + slotheight / 2 ); int dist = int( sqrt( xdiff * xdiff + ydiff * ydiff )); if( dist < distance ) { distance = dist; (*it).slot = slot; (*it).slot_distance = distance; } } } } void PresentWindowsEffect::getBestAssignments() { for( DataHash::Iterator it1 = mWindowData.begin(); it1 != mWindowData.end(); ++it1 ) { for( DataHash::ConstIterator it2 = mWindowData.begin(); it2 != mWindowData.end(); ++it2 ) { if( it1.key() != it2.key() && (*it1).slot == (*it2).slot && (*it1).slot_distance >= (*it2).slot_distance ) { (*it1).slot = -1; } } } } bool PresentWindowsEffect::canRearrangeClosest(EffectWindowList windowlist) { QRect area = effects->clientArea( PlacementArea, QPoint( 0, 0 ), effects->currentDesktop()); int columns = int( ceil( sqrt( windowlist.count()))); int rows = int( ceil( windowlist.count() / float( columns ))); int old_columns = int( ceil( sqrt( mWindowData.count()))); int old_rows = int( ceil( mWindowData.count() / float( columns ))); return old_columns != columns || old_rows != rows; } bool PresentWindowsEffect::borderActivated( ElectricBorder border ) { if( border == borderActivate && !mActivated ) { toggleActive(); return true; } if( border == borderActivateAll && !mActivated ) { toggleActiveAllDesktops(); return true; } return false; } void PresentWindowsEffect::grabbedKeyboardEvent( QKeyEvent* e ) { if( e->type() != QEvent::KeyPress ) return; if( e->key() == Qt::Key_Escape ) { setActive( false ); return; } if( e->key() == Qt::Key_Backspace ) { if( !windowFilter.isEmpty()) { windowFilter.remove( windowFilter.length() - 1, 1 ); updateFilterTexture(); rearrangeWindows(); } return; } if( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter ) { if( mHoverWindow != NULL ) { effects->activateWindow( mHoverWindow ); setActive( false ); return; } if( mWindowData.count() == 1 ) // only one window shown { effects->activateWindow( mWindowData.begin().key()); setActive( false ); } return; } if( !e->text().isEmpty()) { windowFilter.append( e->text()); updateFilterTexture(); rearrangeWindows(); return; } } void PresentWindowsEffect::discardFilterTexture() { #ifdef HAVE_OPENGL delete filterTexture; filterTexture = NULL; #endif } void PresentWindowsEffect::updateFilterTexture() { #ifdef HAVE_OPENGL discardFilterTexture(); if( windowFilter.isEmpty()) return; // Create font for filter text QFont font; font.setPointSize( font.pointSize() * 2 ); font.setBold( true ); // Get size of the rect containing filter text QFontMetrics fm( font ); QRect rect; QString translatedString = i18n( "Filter:\n%1", windowFilter ); rect.setSize( fm.size( 0, translatedString )); QRect area = effects->clientArea( PlacementArea, QPoint( 0, 0 ), effects->currentDesktop()); // Create image QImage im( rect.width(), rect.height(), QImage::Format_ARGB32 ); im.fill( Qt::transparent ); // Paint the filter text to it QPainter p( &im ); p.setFont( font ); p.setPen( QPalette().color( QPalette::HighlightedText ) ); p.drawText( rect, Qt::AlignCenter, translatedString ); p.end(); // Create GL texture filterTexture = new GLTexture( im ); // Get position for filter text and it's frame filterTextureRect = QRect( area.x() + ( area.width() - rect.width()) / 2, area.y() + ( area.height() - rect.height()) / 2, rect.width(), rect.height()); const int borderh = 10; const int borderw = 20; filterFrameRect = filterTextureRect.adjusted( -borderw, -borderh, borderw, borderh ); // Schedule repaint effects->addRepaint( filterTextureRect ); #endif } void PresentWindowsEffect::paintWindowIcon( EffectWindow* w, WindowPaintData& paintdata ) { // Don't render null icons if( w->icon().isNull() ) { return; } WindowData& data = mWindowData[ w ]; if( data.icon.serialNumber() != w->icon().serialNumber()) { // make sure data.icon is the right QPixmap, and rebind data.icon = w->icon(); #ifdef HAVE_OPENGL if( effects->compositingType() == OpenGLCompositing ) { data.iconTexture.load( data.icon ); data.iconTexture.setFilter( GL_LINEAR ); } #endif #ifdef HAVE_XRENDER if( effects->compositingType() == XRenderCompositing ) { if( data.iconPicture != None ) XRenderFreePicture( display(), data.iconPicture ); data.iconPicture = XRenderCreatePicture( display(), data.icon.handle(), alphaFormat, 0, NULL ); } #endif } int icon_margin = 8; int width = data.icon.width(); int height = data.icon.height(); int x = w->x() + paintdata.xTranslate + w->width() * paintdata.xScale * 0.95 - width - icon_margin; int y = w->y() + paintdata.yTranslate + w->height() * paintdata.yScale * 0.95 - height - icon_margin; #ifdef HAVE_OPENGL if( effects->compositingType() == OpenGLCompositing ) { glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // Render some background glColor4f( 0, 0, 0, 0.5 * mActiveness ); renderRoundBox( QRect( x-3, y-3, width+6, height+6 ), 3 ); // Render the icon glColor4f( 1, 1, 1, 1 * mActiveness ); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); data.iconTexture.bind(); const float verts[ 4 * 2 ] = { x, y, x, y + height, x + width, y + height, x + width, y }; const float texcoords[ 4 * 2 ] = { 0, 1, 0, 0, 1, 0, 1, 1 }; renderGLGeometry( 4, verts, texcoords ); data.iconTexture.unbind(); glPopAttrib(); } #endif #ifdef HAVE_XRENDER if( effects->compositingType() == XRenderCompositing ) { XRenderComposite( display(), data.icon.depth() == 32 ? PictOpOver : PictOpSrc, data.iconPicture, None, effects->xrenderBufferPicture(), 0, 0, 0, 0, x, y, width, height ); } #endif } } // namespace #include "presentwindows.moc"