From 1e91a66fd292667cd28bf9d57a82249167cb4e4b Mon Sep 17 00:00:00 2001 From: Lucas Murray Date: Sun, 22 Feb 2009 13:04:16 +0000 Subject: [PATCH] Added support for unstyled and frameless EffectFrames. Converted all effects that display text or boxes to use the class. Minor speed increase in XRender mode for those effects and a massive increase in OpenGL mode (Double framerate in present windows in my case). svn path=/trunk/KDE/kdebase/workspace/; revision=929951 --- effects/boxswitch/boxswitch.cpp | 21 ++- effects/boxswitch/boxswitch.h | 1 - effects/coverswitch/coverswitch.cpp | 4 +- effects/cube/cube.cpp | 2 +- effects/desktopgrid/desktopgrid.cpp | 46 +++++- effects/desktopgrid/desktopgrid.h | 4 +- effects/presentwindows/presentwindows.cpp | 134 ++++++++-------- effects/presentwindows/presentwindows.h | 12 +- lib/kwineffects.cpp | 185 +++++++++++++++++----- lib/kwineffects.h | 61 ++++++- lib/kwinglutils.h | 7 + 11 files changed, 324 insertions(+), 153 deletions(-) diff --git a/effects/boxswitch/boxswitch.cpp b/effects/boxswitch/boxswitch.cpp index 1c46385db5..c1e38b6aa7 100644 --- a/effects/boxswitch/boxswitch.cpp +++ b/effects/boxswitch/boxswitch.cpp @@ -41,12 +41,16 @@ KWIN_EFFECT( boxswitch, BoxSwitchEffect ) BoxSwitchEffect::BoxSwitchEffect() : mActivated( 0 ) , mMode( 0 ) - , thumbnailFrame( true ) + , thumbnailFrame( EffectFrame::Styled ) , selected_window( 0 ) , painting_desktop( 0 ) , animation( false ) , highlight_is_set( false ) { + text_font.setBold( true ); + text_font.setPointSize( 12 ); + thumbnailFrame.setFont( text_font ); + thumbnailFrame.setAlignment( Qt::AlignBottom | Qt::AlignHCenter ); highlight_margin = 10; reconfigure( ReconfigureAll ); @@ -147,7 +151,6 @@ void BoxSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& da paintWindowIcon( w ); } } - paintText( selected_window->caption() ); } else { @@ -164,7 +167,6 @@ void BoxSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& da paintDesktopThumbnail( painting_desktop ); } - paintText( effects->desktopName( selected_desktop )); painting_desktop = 0; } } @@ -401,11 +403,12 @@ void BoxSwitchEffect::tabBoxUpdated() effects->addRepaint( text_area ); original_windows = effects->currentTabBoxWindowList(); } - else + else if( mMode != TabBoxWindowsMode ) { // DesktopMode if( desktops.contains( selected_desktop )) effects->addRepaint( desktops.value( selected_desktop )->area ); selected_desktop = effects->currentTabBoxDesktop(); + thumbnailFrame.setText( effects->desktopName( selected_desktop )); if( desktops.contains( selected_desktop )) effects->addRepaint( desktops.value( selected_desktop )->area ); effects->addRepaint( text_area ); @@ -438,6 +441,7 @@ void BoxSwitchEffect::setActive() { original_desktops = effects->currentTabBoxDesktopList(); selected_desktop = effects->currentTabBoxDesktop(); + thumbnailFrame.setText( effects->desktopName( selected_desktop )); } calculateFrameSize(); calculateItemSizes(); @@ -491,6 +495,7 @@ void BoxSwitchEffect::setSelectedWindow( EffectWindow* w ) effects->setElevatedWindow( selected_window, false ); } selected_window = w; + thumbnailFrame.setText( selected_window->caption() ); if( elevate_window && w ) { effects->setElevatedWindow( selected_window, true ); @@ -528,8 +533,6 @@ void BoxSwitchEffect::calculateFrameSize() item_max_size.setHeight( 200 ); } // How much height to reserve for a one-line text label - text_font.setBold( true ); - text_font.setPointSize( 12 ); text_area.setHeight( QFontMetrics( text_font ).height() * 1.2 ); // Separator space between items and text const int separator_height = 6; @@ -1053,10 +1056,4 @@ void BoxSwitchEffect::paintWindowIcon( EffectWindow* w ) #endif } -void BoxSwitchEffect::paintText( const QString& text ) -{ - int maxwidth = text_area.width(); - effects->paintText( text, text_area.center(), maxwidth, EffectFrame::textColor(), text_font ); -} - } // namespace diff --git a/effects/boxswitch/boxswitch.h b/effects/boxswitch/boxswitch.h index b479fc17fe..9021e51f59 100644 --- a/effects/boxswitch/boxswitch.h +++ b/effects/boxswitch/boxswitch.h @@ -70,7 +70,6 @@ class BoxSwitchEffect void paintWindowThumbnail( EffectWindow* w ); void paintDesktopThumbnail( int iDesktop ); void paintWindowIcon( EffectWindow* w ); - void paintText( const QString& text ); bool mActivated; Window mInput; diff --git a/effects/coverswitch/coverswitch.cpp b/effects/coverswitch/coverswitch.cpp index bf59158538..f2c689166e 100644 --- a/effects/coverswitch/coverswitch.cpp +++ b/effects/coverswitch/coverswitch.cpp @@ -52,8 +52,8 @@ CoverSwitchEffect::CoverSwitchEffect() , scaleFactor( 0.0 ) , direction( Left ) , selected_window( 0 ) - , captionFrame( true ) - , thumbnailFrame( true ) + , captionFrame( EffectFrame::Styled ) + , thumbnailFrame( EffectFrame::Styled ) { reconfigure( ReconfigureAll ); diff --git a/effects/cube/cube.cpp b/effects/cube/cube.cpp index 88d38c5927..18554b83f0 100644 --- a/effects/cube/cube.cpp +++ b/effects/cube/cube.cpp @@ -57,7 +57,7 @@ CubeEffect::CubeEffect() , cubeOpacity( 1.0 ) , opacityDesktopOnly( true ) , displayDesktopName( false ) - , desktopNameFrame( true ) + , desktopNameFrame( EffectFrame::Styled ) , reflection( true ) , rotating( false ) , desktopChangedWhileRotating( false ) diff --git a/effects/desktopgrid/desktopgrid.cpp b/effects/desktopgrid/desktopgrid.cpp index 027b1f066e..784f04231b 100644 --- a/effects/desktopgrid/desktopgrid.cpp +++ b/effects/desktopgrid/desktopgrid.cpp @@ -135,12 +135,6 @@ void DesktopGridEffect::paintScreen( int mask, QRegion region, ScreenPaintData& if( desktopNameAlignment ) { - double progress = timeline.value(); - QColor textColor( 255, 255, 255, 255 * progress ); - QColor bgColor( 0, 0, 0, 178 * progress ); // 70% - QFont f; - f.setBold( true ); - f.setPointSize( 12 ); for( int screen = 0; screen < effects->numScreens(); screen++ ) { QRect screenGeom = effects->clientArea( ScreenArea, screen, 0 ); @@ -152,8 +146,21 @@ void DesktopGridEffect::paintScreen( int mask, QRegion region, ScreenPaintData& QRect textArea( posTL.x(), posTL.y(), posBR.x() - posTL.x(), posBR.y() - posTL.y() ); textArea.adjust( textArea.width() / 10, textArea.height() / 10, -textArea.width() / 10, -textArea.height() / 10 ); - effects->paintTextWithBackground( effects->desktopName( desktop ), - textArea, textColor, bgColor, f, desktopNameAlignment ); + int x, y; + if( desktopNameAlignment & Qt::AlignLeft ) + x = textArea.x(); + else if( desktopNameAlignment & Qt::AlignRight ) + x = textArea.right(); + else + x = textArea.center().x(); + if( desktopNameAlignment & Qt::AlignTop ) + y = textArea.y(); + else if( desktopNameAlignment & Qt::AlignBottom ) + y = textArea.bottom(); + else + y = textArea.center().y(); + desktopNames[desktop-1]->setPosition( QPoint( x, y )); + desktopNames[desktop-1]->render( region, timeline.value(), 0.7 ); } } } @@ -750,6 +757,22 @@ void DesktopGridEffect::setup() } hoverTimeline[effects->currentDesktop() - 1].setProgress( 1.0 ); + // Create desktop name textures if enabled + if( desktopNameAlignment ) + { + desktopNames = new EffectFrame*[effects->numberOfDesktops()]; + QFont font; + font.setBold( true ); + font.setPointSize( 12 ); + for( int i = 0; i < effects->numberOfDesktops(); i++ ) + { + desktopNames[i] = new EffectFrame( EffectFrame::Unstyled, false ); + desktopNames[i]->setFont( font ); + desktopNames[i]->setText( effects->desktopName( i+1 )); + desktopNames[i]->setAlignment( desktopNameAlignment ); + } + } + // We need these variables for every paint so lets cache them int x, y; int numDesktops = effects->numberOfDesktops(); @@ -806,6 +829,13 @@ void DesktopGridEffect::setup() void DesktopGridEffect::finish() { + if( desktopNameAlignment ) + { + for( int i = 0; i < effects->numberOfDesktops(); i++ ) + delete desktopNames[i]; + delete[] desktopNames; + } + if( keyboardGrab ) effects->ungrabKeyboard(); keyboardGrab = false; diff --git a/effects/desktopgrid/desktopgrid.h b/effects/desktopgrid/desktopgrid.h index 0e68115491..56de2a16a6 100644 --- a/effects/desktopgrid/desktopgrid.h +++ b/effects/desktopgrid/desktopgrid.h @@ -85,7 +85,9 @@ class DesktopGridEffect // Soft highlighting QList hoverTimeline; - + + EffectFrame** desktopNames; + QSize gridSize; Qt::Orientation orientation; QPoint activeCell; diff --git a/effects/presentwindows/presentwindows.cpp b/effects/presentwindows/presentwindows.cpp index 88bc36ef6d..fe769c4bc8 100644 --- a/effects/presentwindows/presentwindows.cpp +++ b/effects/presentwindows/presentwindows.cpp @@ -51,7 +51,7 @@ PresentWindowsEffect::PresentWindowsEffect() , m_hasKeyboardGrab( false ) , m_tabBoxEnabled( false ) , m_highlightedWindow( NULL ) - , m_filterFrame( false ) + , m_filterFrame( EffectFrame::Styled, false ) { QFont font; font.setPointSize( font.pointSize() * 2 ); @@ -136,7 +136,16 @@ void PresentWindowsEffect::postPaintScreen() else if( !m_activated && m_motionManager.managingWindows() ) { // We have finished moving them back, stop processing m_motionManager.unmanageAll(); + + DataHash::iterator i = m_windowData.begin(); + while( i != m_windowData.end() ) + { + delete i.value().textFrame; + delete i.value().iconFrame; + i++; + } m_windowData.clear(); + effects->setActiveFullScreenEffect( NULL ); } @@ -211,23 +220,21 @@ void PresentWindowsEffect::paintWindow( EffectWindow *w, int mask, QRegion regio m_motionManager.apply( w, data ); effects->paintWindow( w, mask, region, data ); - - const WindowData &wData = m_windowData[w]; + + QRect rect = m_motionManager.transformedGeometry( w ).toRect(); if( m_showIcons ) - paintWindowIcon( w, data ); + { + QPoint point( rect.x() + rect.width() * 0.95, + rect.y() + rect.height() * 0.95 ); + m_windowData[w].iconFrame->setPosition( point ); + m_windowData[w].iconFrame->render( region, 0.9 * data.opacity * m_decalOpacity, 0.75 ); + } if( m_showCaptions ) { - QString text = w->caption(); - QRect textArea( w->x() + data.xTranslate, w->y() + data.yTranslate, - w->width() * data.xScale, w->height() * data.yScale ); - textArea.adjust( 10, 10, -10, -10 ); - double opacity = (0.7 + 0.2 * wData.highlight) * data.opacity * m_decalOpacity; - QColor textcolor( 255, 255, 255, int( 255 * opacity )); - QColor bgcolor( 0, 0, 0, int( 255 * opacity )); - QFont f; - f.setBold( true ); - f.setPointSize( 12 ); - effects->paintTextWithBackground( text, textArea, textcolor, bgcolor, f ); + QPoint point( rect.x() + rect.width() / 2, + rect.y() + rect.height() / 2 ); + m_windowData[w].textFrame->setPosition( point ); + m_windowData[w].textFrame->render( region, 0.9 * data.opacity * m_decalOpacity, 0.75 ); } } else @@ -245,6 +252,14 @@ void PresentWindowsEffect::windowAdded( EffectWindow *w ) m_windowData[w].visible = isVisibleWindow( w ); m_windowData[w].opacity = 0.0; m_windowData[w].highlight = 0.0; + m_windowData[w].textFrame = new EffectFrame( EffectFrame::Unstyled, false ); + QFont font; + font.setBold( true ); + font.setPointSize( 12 ); + m_windowData[w].textFrame->setFont( font ); + m_windowData[w].iconFrame = new EffectFrame( EffectFrame::Unstyled, false ); + m_windowData[w].iconFrame->setAlignment( Qt::AlignRight | Qt::AlignBottom ); + m_windowData[w].iconFrame->setIcon( w->icon() ); if( isSelectableWindow( w )) { m_motionManager.manage( w ); @@ -262,6 +277,8 @@ void PresentWindowsEffect::windowClosed( EffectWindow *w ) void PresentWindowsEffect::windowDeleted( EffectWindow *w ) { + delete m_windowData[w].textFrame; + delete m_windowData[w].iconFrame; m_windowData.remove( w ); m_motionManager.unmanage( w ); } @@ -511,6 +528,19 @@ void PresentWindowsEffect::rearrangeWindows() else calculateWindowTransformationsNatural( windows, screen ); } + + // Resize text frames if required + QFontMetrics* metrics = NULL; // All fonts are the same + foreach( EffectWindow *w, m_motionManager.managedWindows() ) + { + if( !metrics ) + metrics = new QFontMetrics( m_windowData[w].textFrame->font() ); + QRect geom = m_motionManager.targetGeometry( w ).toRect(); + QString string = metrics->elidedText( w->caption(), Qt::ElideRight, geom.width() * 0.9 ); + if( string != m_windowData[w].textFrame->text() ) + m_windowData[w].textFrame->setText( string ); + } + delete metrics; } void PresentWindowsEffect::calculateWindowTransformationsClosest( EffectWindowList windowlist, int screen ) @@ -1110,6 +1140,14 @@ void PresentWindowsEffect::setActive( bool active, bool closingTab ) if( w->isOnCurrentDesktop() && !w->isMinimized() ) m_windowData[w].opacity = 1.0; m_windowData[w].highlight = 1.0; + m_windowData[w].textFrame = new EffectFrame( EffectFrame::Unstyled, false ); + QFont font; + font.setBold( true ); + font.setPointSize( 12 ); + m_windowData[w].textFrame->setFont( font ); + m_windowData[w].iconFrame = new EffectFrame( EffectFrame::Unstyled, false ); + m_windowData[w].iconFrame->setAlignment( Qt::AlignRight | Qt::AlignBottom ); + m_windowData[w].iconFrame->setIcon( w->icon() ); } if( m_tabBoxEnabled ) @@ -1135,7 +1173,16 @@ void PresentWindowsEffect::setActive( bool active, bool closingTab ) (( m_motionManager.managedWindows().count() == 1 ) && m_motionManager.managedWindows().first()->isOnCurrentDesktop() )) { // No point triggering if there is nothing to do m_activated = false; + + DataHash::iterator i = m_windowData.begin(); + while( i != m_windowData.end() ) + { + delete i.value().textFrame; + delete i.value().iconFrame; + i++; + } m_windowData.clear(); + m_motionManager.unmanageAll(); return; } @@ -1417,63 +1464,6 @@ EffectWindow* PresentWindowsEffect::findFirstWindow() const return topLeft; } -void PresentWindowsEffect::paintWindowIcon( EffectWindow *w, WindowPaintData &data ) - { - // Don't bother if we don't even have an icon - if( w->icon().isNull() ) - return; - - WindowData &wData = m_windowData[w]; - if( wData.icon.cacheKey() != w->icon().cacheKey()) - { // Make sure data.icon is the right QPixmap, and rebind - wData.icon = w->icon(); -#ifdef KWIN_HAVE_OPENGL_COMPOSITING - if( effects->compositingType() == OpenGLCompositing ) - { - wData.iconTexture = new GLTexture( wData.icon ); - wData.iconTexture->setFilter( GL_LINEAR ); - } -#endif -#ifdef KWIN_HAVE_XRENDER_COMPOSITING - if( effects->compositingType() == XRenderCompositing ) - wData.iconPicture = XRenderPicture( wData.icon ); -#endif - } - int icon_margin = 8; - int width = wData.icon.width(); - int height = wData.icon.height(); - int x = w->x() + data.xTranslate + w->width() * data.xScale * 0.95 - width - icon_margin; - int y = w->y() + data.yTranslate + w->height() * data.yScale * 0.95 - height - icon_margin; -#ifdef KWIN_HAVE_OPENGL_COMPOSITING - 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 * wData.opacity * m_decalOpacity ); - renderRoundBox( QRect( x-3, y-3, width+6, height+6 ), 3 ); - // Render the icon - glColor4f( 1, 1, 1, 1 * wData.opacity * m_decalOpacity ); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - wData.iconTexture->bind(); - wData.iconTexture->render( infiniteRegion(), QRect( x, y, width, height )); - wData.iconTexture->unbind(); - glPopAttrib(); - } -#endif -#ifdef KWIN_HAVE_XRENDER_COMPOSITING - if( effects->compositingType() == XRenderCompositing ) - { - XRenderComposite( display(), - wData.icon.depth() == 32 ? PictOpOver : PictOpSrc, - wData.iconPicture, None, - effects->xrenderBufferPicture(), - 0, 0, 0, 0, x, y, width, height ); - } -#endif - } - } // namespace #include "presentwindows.moc" diff --git a/effects/presentwindows/presentwindows.h b/effects/presentwindows/presentwindows.h index 3abbc8f5e2..f96be819cd 100644 --- a/effects/presentwindows/presentwindows.h +++ b/effects/presentwindows/presentwindows.h @@ -24,10 +24,7 @@ along with this program. If not, see . #include "presentwindows_proxy.h" -// Include with base class for effects. #include -#include -#include #include @@ -52,12 +49,8 @@ class PresentWindowsEffect int slot; int slot_distance; QPixmap icon; -#ifdef KWIN_HAVE_OPENGL_COMPOSITING - KSharedPtr< GLTexture > iconTexture; -#endif -#ifdef KWIN_HAVE_XRENDER_COMPOSITING - XRenderPicture iconPicture; -#endif + EffectFrame* textFrame; + EffectFrame* iconFrame; }; typedef QHash DataHash; struct GridSize @@ -129,7 +122,6 @@ class PresentWindowsEffect void setHighlightedWindow( EffectWindow *w ); EffectWindow* relativeWindow( EffectWindow *w, int xdiff, int ydiff, bool wrap ) const; EffectWindow* findFirstWindow() const; - void paintWindowIcon( EffectWindow *w, WindowPaintData &data ); // TODO: Do we need this? private: PresentWindowsEffectProxy m_proxy; diff --git a/lib/kwineffects.cpp b/lib/kwineffects.cpp index 766b49d63d..1754472aa1 100644 --- a/lib/kwineffects.cpp +++ b/lib/kwineffects.cpp @@ -34,6 +34,7 @@ along with this program. If not, see . #include #include +#include #include #include @@ -1297,6 +1298,18 @@ QRectF WindowMotionManager::transformedGeometry( EffectWindow *w ) const return geometry; } +QRectF WindowMotionManager::targetGeometry( EffectWindow *w ) const + { + QRectF geometry( w->geometry() ); + + // TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid) + geometry.moveTo( m_managedWindows[ w ].translation.target() ); + geometry.setWidth( geometry.width() * m_managedWindows[ w ].scale.target().x() ); + geometry.setHeight( geometry.height() * m_managedWindows[ w ].scale.target().y() ); + + return geometry; + } + EffectWindow* WindowMotionManager::windowAtPoint( QPoint point, bool useStackingOrder ) const { // TODO: Stacking order uses EffectsHandler::stackingOrder() then filters by m_managedWindows @@ -1313,8 +1326,11 @@ EffectWindow* WindowMotionManager::windowAtPoint( QPoint point, bool useStacking EffectFrame ***************************************************************/ -EffectFrame::EffectFrame( bool staticSize, QPoint position, Qt::Alignment alignment ) +GLTexture* EffectFrame::m_unstyledTexture = NULL; + +EffectFrame::EffectFrame( Style style, bool staticSize, QPoint position, Qt::Alignment alignment ) : QObject() + , m_style( style ) , m_static( staticSize ) , m_point( position ) , m_alignment( alignment ) @@ -1328,10 +1344,19 @@ EffectFrame::EffectFrame( bool staticSize, QPoint position, Qt::Alignment alignm m_textPicture = NULL; #endif - m_frame.setImagePath( "widgets/background" ); - m_frame.setCacheAllRenderedFrames( true ); - - connect( Plasma::Theme::defaultTheme(), SIGNAL( themeChanged() ), this, SLOT( plasmaThemeChanged() )); + if( m_style == Unstyled ) + { +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + if( effects->compositingType() == OpenGLCompositing && !m_unstyledTexture ) + updateUnstyledTexture(); +#endif + } + else if( m_style == Styled ) + { + m_frame.setImagePath( "widgets/background" ); + m_frame.setCacheAllRenderedFrames( true ); + connect( Plasma::Theme::defaultTheme(), SIGNAL( themeChanged() ), this, SLOT( plasmaThemeChanged() )); + } } EffectFrame::~EffectFrame() @@ -1362,32 +1387,94 @@ void EffectFrame::free() #endif } -void EffectFrame::render( QRegion region, double opacity ) +void EffectFrame::render( QRegion region, double opacity, double frameOpacity ) { + if( m_geometry.isEmpty() ) + return; // Nothing to display + region = infiniteRegion(); // TODO: Old region doesn't seem to work with OpenGL #ifdef KWIN_HAVE_OPENGL_COMPOSITING if( effects->compositingType() == OpenGLCompositing ) { - if( !m_texture ) // Lazy creation - updateTexture(); - if( !m_texture || m_geometry.isEmpty() ) - return; - glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - glColor4f( 1.0, 1.0, 1.0, opacity ); glPushMatrix(); // Render the actual frame - m_texture->bind(); - qreal left, top, right, bottom; - m_frame.getMargins( left, top, right, bottom ); // m_geometry is the inner geometry - m_texture->render( region, m_geometry.adjusted( -left, -top, right, bottom )); - m_texture->unbind(); + if( m_style == Unstyled ) + { + const QRect& area = m_geometry.adjusted( -5, -5, 5, 5 ); + const int roundness = 5; + QVector verts, texCoords; + verts.reserve( 80 ); + texCoords.reserve( 80 ); + + // Center + addQuadVertices( verts, area.left() + roundness, area.top() + roundness, + area.right() - roundness, area.bottom() - roundness ); + addQuadVertices( texCoords, 0.5, 0.5, 0.5, 0.5 ); + + // Left + addQuadVertices( verts, area.left(), area.top() + roundness, + area.left() + roundness, area.bottom() - roundness ); + addQuadVertices( texCoords, 0.0, 0.5, 0.5, 0.5 ); + // Top + addQuadVertices( verts, area.left() + roundness, area.top(), + area.right() - roundness, area.top() + roundness ); + addQuadVertices( texCoords, 0.5, 0.0, 0.5, 0.5 ); + // Right + addQuadVertices( verts, area.right() - roundness, area.top() + roundness, + area.right(), area.bottom() - roundness ); + addQuadVertices( texCoords, 0.5, 0.5, 1.0, 0.5 ); + // Bottom + addQuadVertices( verts, area.left() + roundness, area.bottom() - roundness, + area.right() - roundness, area.bottom() ); + addQuadVertices( texCoords, 0.5, 0.5, 0.5, 1.0 ); + + // Top-left + addQuadVertices( verts, area.left(), area.top(), + area.left() + roundness, area.top() + roundness ); + addQuadVertices( texCoords, 0.0, 0.0, 0.5, 0.5 ); + // Top-right + addQuadVertices( verts, area.right() - roundness, area.top(), + area.right(), area.top() + roundness ); + addQuadVertices( texCoords, 0.5, 0.0, 1.0, 0.5 ); + // Bottom-left + addQuadVertices( verts, area.left(), area.bottom() - roundness, + area.left() + roundness, area.bottom() ); + addQuadVertices( texCoords, 0.0, 0.5, 0.5, 1.0 ); + // Bottom-right + addQuadVertices( verts, area.right() - roundness, area.bottom() - roundness, + area.right(), area.bottom() ); + addQuadVertices( texCoords, 0.5, 0.5, 1.0, 1.0 ); + + glColor4f( 0.0, 0.0, 0.0, opacity * frameOpacity ); + + m_unstyledTexture->bind(); + m_unstyledTexture->enableNormalizedTexCoords(); + renderGLGeometry( verts.count() / 2, verts.data(), texCoords.data() ); + m_unstyledTexture->disableNormalizedTexCoords(); + m_unstyledTexture->unbind(); + } + else if( m_style == Styled ) + { + if( !m_texture ) // Lazy creation + updateTexture(); + + glColor4f( 1.0, 1.0, 1.0, opacity * frameOpacity ); + + m_texture->bind(); + qreal left, top, right, bottom; + m_frame.getMargins( left, top, right, bottom ); // m_geometry is the inner geometry + m_texture->render( region, m_geometry.adjusted( -left, -top, right, bottom )); + m_texture->unbind(); + } + + glColor4f( 1.0, 1.0, 1.0, opacity ); // Render icon if( !m_icon.isNull() && !m_iconSize.isEmpty() ) @@ -1418,19 +1505,23 @@ void EffectFrame::render( QRegion region, double opacity ) #ifdef KWIN_HAVE_XRENDER_COMPOSITING if( effects->compositingType() == XRenderCompositing ) { - if( !m_picture ) // Lazy creation - updatePicture(); - if( !m_picture || m_geometry.isEmpty() ) - return; - - // TODO: Opacity - // Render the actual frame - qreal left, top, right, bottom; - m_frame.getMargins( left, top, right, bottom ); // m_geometry is the inner geometry - QRect geom = m_geometry.adjusted( -left, -top, right, bottom ); - XRenderComposite( display(), PictOpOver, *m_picture, None, effects->xrenderBufferPicture(), - 0, 0, 0, 0, geom.x(), geom.y(), geom.width(), geom.height() ); + if( m_style == Unstyled ) + xRenderRoundBox( effects->xrenderBufferPicture(), m_geometry.adjusted( -5, -5, 5, 5 ), + 5, QColor( 0, 0, 0, int( opacity * frameOpacity * 255 ))); + else if( m_style == Styled ) + { + if( !m_picture ) // Lazy creation + updatePicture(); + qreal left, top, right, bottom; + m_frame.getMargins( left, top, right, bottom ); // m_geometry is the inner geometry + QRect geom = m_geometry.adjusted( -left, -top, right, bottom ); + XRenderComposite( display(), PictOpOver, *m_picture, None, effects->xrenderBufferPicture(), + 0, 0, 0, 0, geom.x(), geom.y(), geom.width(), geom.height() ); + } + + // Opacity, TODO: Can we further optimize this? + XRenderPicture fill = xRenderFill( QColor( 255, 255, 255, int( opacity * 255 ))); // Render icon if( !m_icon.isNull() && !m_iconSize.isEmpty() ) @@ -1438,8 +1529,8 @@ void EffectFrame::render( QRegion region, double opacity ) QPoint topLeft( m_geometry.x(), m_geometry.center().y() - m_iconSize.height() / 2 ); XRenderPicture* icon = new XRenderPicture( m_icon ); // TODO: Cache - geom = QRect( topLeft, m_iconSize ); - XRenderComposite( display(), PictOpOver, *icon, None, effects->xrenderBufferPicture(), + QRect geom = QRect( topLeft, m_iconSize ); + XRenderComposite( display(), PictOpOver, *icon, fill, effects->xrenderBufferPicture(), 0, 0, 0, 0, geom.x(), geom.y(), geom.width(), geom.height() ); delete icon; } @@ -1449,7 +1540,7 @@ void EffectFrame::render( QRegion region, double opacity ) { if( !m_textPicture ) // Lazy creation updateTextPicture(); - XRenderComposite( display(), PictOpOver, *m_textPicture, None, effects->xrenderBufferPicture(), + XRenderComposite( display(), PictOpOver, *m_textPicture, fill, effects->xrenderBufferPicture(), 0, 0, 0, 0, m_geometry.x(), m_geometry.y(), m_geometry.width(), m_geometry.height() ); } } @@ -1459,6 +1550,7 @@ void EffectFrame::render( QRegion region, double opacity ) void EffectFrame::setPosition( const QPoint& point ) { m_point = point; + autoResize(); } void EffectFrame::setGeometry( const QRect& geometry, bool force ) @@ -1471,9 +1563,13 @@ void EffectFrame::setGeometry( const QRect& geometry, bool force ) effects->addRepaint( m_geometry ); if( !newSize && !force ) return; - qreal left, top, right, bottom; - m_frame.getMargins( left, top, right, bottom ); // m_geometry is the inner geometry - m_frame.resizeFrame( m_geometry.adjusted( -left, -top, right, bottom ).size() ); + + if( m_style == Styled ) + { + qreal left, top, right, bottom; + m_frame.getMargins( left, top, right, bottom ); // m_geometry is the inner geometry + m_frame.resizeFrame( m_geometry.adjusted( -left, -top, right, bottom ).size() ); + } #ifdef KWIN_HAVE_OPENGL_COMPOSITING if( effects->compositingType() == OpenGLCompositing ) @@ -1625,7 +1721,8 @@ void EffectFrame::updateTexture() { #ifdef KWIN_HAVE_OPENGL_COMPOSITING delete m_texture; - m_texture = new GLTexture( m_frame.framePixmap() ); + if( m_style == Styled ) + m_texture = new GLTexture( m_frame.framePixmap() ); #endif } @@ -1656,7 +1753,7 @@ void EffectFrame::updateTextTexture() QPainter p( &pixmap ); p.setFont( m_font ); p.setPen( textColor() ); - p.drawText( rect, Qt::AlignCenter, text ); + p.drawText( rect, m_alignment, text ); p.end(); m_textTexture = new GLTexture( pixmap ); #endif @@ -1666,7 +1763,8 @@ void EffectFrame::updatePicture() { #ifdef KWIN_HAVE_XRENDER_COMPOSITING delete m_picture; - m_picture = new XRenderPicture( m_frame.framePixmap() ); + if( m_style == Styled ) + m_picture = new XRenderPicture( m_frame.framePixmap() ); #endif } @@ -1696,10 +1794,19 @@ void EffectFrame::updateTextPicture() QPainter p( &pixmap ); p.setFont( m_font ); p.setPen( textColor() ); - p.drawText( rect, Qt::AlignCenter, text ); + p.drawText( rect, m_alignment, text ); p.end(); m_textPicture = new XRenderPicture( pixmap ); #endif } +void EffectFrame::updateUnstyledTexture() + { +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + delete m_unstyledTexture; + QString filename = KGlobal::dirs()->findResource( "data", "kwin/circle.png" ); + m_unstyledTexture = new GLTexture( filename ); +#endif + } + } // namespace diff --git a/lib/kwineffects.h b/lib/kwineffects.h index 661d57a602..4f8b5228c7 100644 --- a/lib/kwineffects.h +++ b/lib/kwineffects.h @@ -714,6 +714,8 @@ class KWIN_EXPORT EffectsHandler virtual int shadowTextureList( ShadowType type ) const = 0; /** + * @deprecated + * @see EffectFrame * Paints given text onto screen, possibly in elided form * @param text * @param center center point of the painted text @@ -723,11 +725,23 @@ class KWIN_EXPORT EffectsHandler **/ bool paintText( const QString& text, const QPoint& center, int maxwidth, const QColor& color, const QFont& font = QFont() ); + /** + * @deprecated + * @see EffectFrame + */ bool paintText( const QString& text, const QRect& rect, const QColor& color, const QFont& font = QFont(), const Qt::Alignment& alignment = Qt::AlignCenter ); + /** + * @deprecated + * @see EffectFrame + */ bool paintTextWithBackground( const QString& text, const QPoint& center, int maxwidth, const QColor& color, const QColor& bgcolor, const QFont& font = QFont() ); + /** + * @deprecated + * @see EffectFrame + */ bool paintTextWithBackground( const QString& text, const QRect& rect, const QColor& color, const QColor& bgcolor, const QFont& font = QFont(), const Qt::Alignment& alignment = Qt::AlignCenter ); @@ -1551,6 +1565,11 @@ class KWIN_EXPORT WindowMotionManager * window. */ QRectF transformedGeometry( EffectWindow *w ) const; + /** + * Retrieve the current target geometry of a registered + * window. + */ + QRectF targetGeometry( EffectWindow *w ) const; /** * Return the window that has it's transformed geometry under * the specified point. It is recommended to use the stacking @@ -1592,22 +1611,32 @@ class KWIN_EXPORT WindowMotionManager }; /** - * @short Helper class for painting themed boxes. + * @short Helper class for displaying text and icons in frames. * - * Paints a box using the default Plasma theme. + * Paints text and/or and icon with an optional frame around them. The + * available frames includes one that follows the default Plasma theme and + * another that doesn't. + * It is recommended to use this class whenever displaying text. */ class KWIN_EXPORT EffectFrame : public QObject { Q_OBJECT public: + enum Style + { + None, ///< Displays no frame around the contents. + Unstyled, ///< Displays a basic box around the contents. + Styled ///< Displays a Plasma-styled frame around the contents. + }; + /** * Creates a new frame object. If the frame does not have a static size * then it will be located at @a position with @a alignment. A * non-static frame will automatically adjust its size to fit the * contents. */ - EffectFrame( bool staticSize = false, QPoint position = QPoint( -1, -1 ), + EffectFrame( Style style, bool staticSize = true, QPoint position = QPoint( -1, -1 ), Qt::Alignment alignment = Qt::AlignCenter ); ~EffectFrame(); @@ -1620,22 +1649,34 @@ class KWIN_EXPORT EffectFrame : public QObject /** * Render the frame. */ - void render( QRegion region = infiniteRegion(), double opacity = 1.0 ); + void render( QRegion region = infiniteRegion(), double opacity = 1.0, double frameOpacity = 1.0 ); void setPosition( const QPoint& point ); + /** + * Set the text alignment for static frames and the position alignment + * for non-static. + */ inline void setAlignment( Qt::Alignment alignment ) { m_alignment = alignment; }; // Doesn't change geometry void setGeometry( const QRect& geometry, bool force = false ); - QRect geometry() const // Inner/contents geometry + inline QRect geometry() const // Inner/contents geometry { return m_geometry; }; void setText( const QString& text ); + inline QString text() const + { return m_text; }; void setFont( const QFont& font ); + inline QFont font() const + { return m_font; }; /** * Set the icon that will appear on the left-hand size of the frame. */ void setIcon( const QPixmap& icon ); + inline QPixmap icon() const + { return m_icon; }; void setIconSize( const QSize& size ); + inline QSize iconSize() const + { return m_iconSize; }; /** * The foreground text color as specified by the default Plasma theme. @@ -1646,12 +1687,15 @@ class KWIN_EXPORT EffectFrame : public QObject void plasmaThemeChanged(); private: + Q_DISABLE_COPY( EffectFrame ) // As we need to use Qt slots we cannot copy this class + void autoResize(); // Auto-resize if not a static size - void updateTexture(); // Update OpenGL frame texture + void updateTexture(); // Update OpenGL styled frame texture void updateTextTexture(); // Update OpenGL text texture - void updatePicture(); // Update XRender frame picture + void updatePicture(); // Update XRender styled frame picture void updateTextPicture(); // Update XRender text picture + Style m_style; Plasma::FrameSvg m_frame; GLTexture* m_texture; GLTexture* m_textTexture; @@ -1669,6 +1713,9 @@ class KWIN_EXPORT EffectFrame : public QObject QFont m_font; QPixmap m_icon; QSize m_iconSize; + + static GLTexture* m_unstyledTexture; + static void updateUnstyledTexture(); // Update OpenGL unstyled frame texture }; /** diff --git a/lib/kwinglutils.h b/lib/kwinglutils.h index 3a7f6c8f40..82d09e904e 100644 --- a/lib/kwinglutils.h +++ b/lib/kwinglutils.h @@ -101,6 +101,13 @@ KWIN_EXPORT void renderGLGeometryImmediate( int count, int dim = 2, int stride = 0 ); +KWIN_EXPORT void addQuadVertices( QVector& verts, float x1, float y1, float x2, float y2 ); + + +/** + * @deprecated + * @see EffectFrame + */ KWIN_EXPORT void renderRoundBox( const QRect& area, float roundness = 10.0f, GLTexture* texture = 0 ); /** * @deprecated