diff --git a/effects/presentwindows/presentwindows.cpp b/effects/presentwindows/presentwindows.cpp index 2de31028a..d79ea307c 100644 --- a/effects/presentwindows/presentwindows.cpp +++ b/effects/presentwindows/presentwindows.cpp @@ -1,2105 +1,2108 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2007 Rivo Laks Copyright (C) 2008 Lucas Murray 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 "presentwindows.h" #include #include #include #include #include #include #ifdef KWIN_HAVE_OPENGL_COMPOSITING #include #endif #include #include #include #include #include #include #include #include #include namespace KWin { KWIN_EFFECT( presentwindows, PresentWindowsEffect ) PresentWindowsEffect::PresentWindowsEffect() : m_proxy( this ) , m_activated( false ) , m_ignoreMinimized( false ) , m_decalOpacity( 0.0 ) , m_hasKeyboardGrab( false ) , m_tabBoxEnabled( false ) , m_mode( ModeCurrentDesktop ) , m_managerWindow( NULL ) , m_highlightedWindow( NULL ) , m_filterFrame( effects->effectFrame( EffectFrameStyled, false ) ) , m_closeView( NULL ) { m_atomDesktop = XInternAtom( display(), "_KDE_PRESENT_WINDOWS_DESKTOP", False ); m_atomWindows = XInternAtom( display(), "_KDE_PRESENT_WINDOWS_GROUP", False ); effects->registerPropertyType( m_atomDesktop, true ); effects->registerPropertyType( m_atomWindows, true ); // Announce support by creating a dummy version on the root window unsigned char dummy = 0; XChangeProperty( display(), rootWindow(), m_atomDesktop, m_atomDesktop, 8, PropModeReplace, &dummy, 1 ); XChangeProperty( display(), rootWindow(), m_atomWindows, m_atomWindows, 8, PropModeReplace, &dummy, 1 ); QFont font; font.setPointSize( font.pointSize() * 2 ); font.setBold( true ); m_filterFrame->setFont( font ); KActionCollection* actionCollection = new KActionCollection( this ); KAction* a = ( KAction* )actionCollection->addAction( "Expose" ); a->setText( i18n( "Toggle Present Windows (Current desktop)" )); a->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F9 )); shortcut = a->globalShortcut(); connect( a, SIGNAL( triggered(bool) ), this, SLOT( toggleActive() )); connect( a, SIGNAL( globalShortcutChanged(QKeySequence) ), this, SLOT( globalShortcutChanged(QKeySequence))); KAction* b = ( KAction* )actionCollection->addAction( "ExposeAll" ); b->setText( i18n( "Toggle Present Windows (All desktops)" )); b->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F10 )); shortcutAll = b->globalShortcut(); connect( b, SIGNAL( triggered(bool) ), this, SLOT( toggleActiveAllDesktops() )); connect( b, SIGNAL( globalShortcutChanged(QKeySequence) ), this, SLOT( globalShortcutChangedAll(QKeySequence))); KAction* c = ( KAction* )actionCollection->addAction( "ExposeClass" ); c->setText( i18n( "Toggle Present Windows (Window class)" )); c->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F7 )); connect( c, SIGNAL( triggered(bool) ), this, SLOT( toggleActiveClass() )); connect( c, SIGNAL( globalShortcutChanged(QKeySequence) ), this, SLOT( globalShortcutChangedClass(QKeySequence))); shortcutClass = c->globalShortcut(); reconfigure( ReconfigureAll ); } PresentWindowsEffect::~PresentWindowsEffect() { XDeleteProperty( display(), rootWindow(), m_atomDesktop ); effects->registerPropertyType( m_atomDesktop, false ); XDeleteProperty( display(), rootWindow(), m_atomWindows ); effects->registerPropertyType( m_atomWindows, false ); foreach( ElectricBorder border, m_borderActivate ) { effects->unreserveElectricBorder( border ); } foreach( ElectricBorder border, m_borderActivateAll ) { effects->unreserveElectricBorder( border ); } delete m_filterFrame; delete m_closeView; } void PresentWindowsEffect::reconfigure( ReconfigureFlags ) { KConfigGroup conf = effects->effectConfig("PresentWindows"); foreach( ElectricBorder border, m_borderActivate ) { effects->unreserveElectricBorder( border ); } foreach( ElectricBorder border, m_borderActivateAll ) { effects->unreserveElectricBorder( border ); } m_borderActivate.clear(); m_borderActivateAll.clear(); QList borderList = QList(); borderList.append( int( ElectricNone ) ); borderList = conf.readEntry( "BorderActivate", borderList ); foreach( int i, borderList ) { m_borderActivate.append( ElectricBorder( i ) ); effects->reserveElectricBorder( ElectricBorder( i ) ); } borderList.clear(); borderList.append( int( ElectricTopLeft ) ); borderList = conf.readEntry( "BorderActivateAll", borderList ); foreach( int i, borderList ) { m_borderActivateAll.append( ElectricBorder( i ) ); effects->reserveElectricBorder( ElectricBorder( i ) ); } m_layoutMode = conf.readEntry( "LayoutMode", int( LayoutNatural )); m_showCaptions = conf.readEntry( "DrawWindowCaptions", true ); m_showIcons = conf.readEntry( "DrawWindowIcons", true ); + m_doNotCloseWindows = !conf.readEntry( "AllowClosingWindows", true ); m_tabBoxAllowed = conf.readEntry( "TabBox", false ); m_tabBoxAlternativeAllowed = conf.readEntry( "TabBoxAlternative", false ); m_ignoreMinimized = conf.readEntry( "IgnoreMinimized", false ); m_accuracy = conf.readEntry( "Accuracy", 1 ) * 20; m_fillGaps = conf.readEntry( "FillGaps", true ); m_fadeDuration = double( animationTime( 150 )); m_showPanel = conf.readEntry( "ShowPanel", false ); m_leftButtonWindow = (WindowMouseAction)conf.readEntry( "LeftButtonWindow", (int)WindowActivateAction ); m_middleButtonWindow = (WindowMouseAction)conf.readEntry( "MiddleButtonWindow", (int)WindowNoAction ); m_rightButtonWindow = (WindowMouseAction)conf.readEntry( "RightButtonWindow", (int)WindowExitAction ); m_leftButtonDesktop = (DesktopMouseAction)conf.readEntry( "LeftButtonDesktop", (int)DesktopExitAction ); m_middleButtonDesktop = (DesktopMouseAction)conf.readEntry( "MiddleButtonDesktop", (int)DesktopNoAction ); m_rightButtonDesktop = (DesktopMouseAction)conf.readEntry( "RightButtonDesktop", (int)DesktopNoAction ); } void* PresentWindowsEffect::proxy() { return &m_proxy; } void PresentWindowsEffect::toggleActiveClass() { if( !m_activated ) { if( !effects->activeWindow() ) return; m_mode = ModeWindowClass; m_class = effects->activeWindow()->windowClass(); } setActive( !m_activated ); } //----------------------------------------------------------------------------- // Screen painting void PresentWindowsEffect::prePaintScreen( ScreenPrePaintData &data, int time ) { m_motionManager.calculate( time ); // We need to mark the screen as having been transformed otherwise there will be no repainting if( m_activated || m_motionManager.managingWindows() ) data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; if( m_activated ) m_decalOpacity = qMin( 1.0, m_decalOpacity + time / m_fadeDuration ); else m_decalOpacity = qMax( 0.0, m_decalOpacity - time / m_fadeDuration ); effects->prePaintScreen( data, time ); } void PresentWindowsEffect::paintScreen( int mask, QRegion region, ScreenPaintData &data ) { effects->paintScreen( mask, region, data ); // Display the filter box if( !m_windowFilter.isEmpty() ) m_filterFrame->render( region ); } void PresentWindowsEffect::postPaintScreen() { if( m_motionManager.areWindowsMoving() ) effects->addRepaintFull(); 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(); foreach( EffectWindow *w, effects->stackingOrder() ) { if( w->isDock() ) { w->setData( WindowForceBlurRole, QVariant( false ) ); } } effects->setActiveFullScreenEffect( NULL ); } // Update windows that are changing brightness or opacity DataHash::const_iterator i; for( i = m_windowData.constBegin(); i != m_windowData.constEnd(); ++i ) { if( i.value().opacity > 0.0 && i.value().opacity < 1.0 ) i.key()->addRepaintFull(); if( i.value().highlight > 0.0 && i.value().highlight < 1.0 ) i.key()->addRepaintFull(); } effects->postPaintScreen(); } //----------------------------------------------------------------------------- // Window painting void PresentWindowsEffect::prePaintWindow( EffectWindow *w, WindowPrePaintData &data, int time ) { // TODO: We should also check to see if any windows are fading just in case fading takes longer // than moving the windows when the effect is deactivated. if(( m_activated || m_motionManager.areWindowsMoving() ) && m_windowData.contains( w )) { w->enablePainting( EffectWindow::PAINT_DISABLED_BY_MINIMIZE ); // Display always w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); if( m_windowData[w].visible ) w->enablePainting( EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP ); // Calculate window's opacity // TODO: Minimized windows or windows not on the current desktop are only 75% visible? if( m_windowData[w].visible ) { if( m_windowData[w].deleted ) m_windowData[w].opacity = qMax( 0.0, m_windowData[w].opacity - time / m_fadeDuration ); else m_windowData[w].opacity = qMin(/*( w->isMinimized() || !w->isOnCurrentDesktop() ) ? 0.75 :*/ 1.0, m_windowData[w].opacity + time / m_fadeDuration ); } else m_windowData[w].opacity = qMax( 0.0, m_windowData[w].opacity - time / m_fadeDuration ); if( m_windowData[w].opacity == 0.0 ) { // don't disable painting for panels if show panel is set if( !w->isDock() || ( w->isDock() && !m_showPanel )) w->disablePainting( EffectWindow::PAINT_DISABLED ); } else if( m_windowData[w].opacity != 1.0 ) data.setTranslucent(); // Calculate window's brightness if( w == m_highlightedWindow || w == m_closeWindow || !m_activated ) m_windowData[w].highlight = qMin( 1.0, m_windowData[w].highlight + time / m_fadeDuration ); else m_windowData[w].highlight = qMax( 0.0, m_windowData[w].highlight - time / m_fadeDuration ); // Closed windows if( m_windowData[w].deleted ) { data.setTranslucent(); if( m_windowData[w].opacity <= 0.0 && m_windowData[w].referenced ) { // it's possible that another effect has referenced the window // we have to keep the window in the list to prevent flickering m_windowData[w].referenced = false; w->unrefWindow(); } else w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DELETE ); } // desktop windows on other desktops (Plasma activity per desktop) should not be painted if( w->isDesktop() && !w->isOnCurrentDesktop() ) w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); if( m_motionManager.isManaging( w )) data.setTransformed(); // We will be moving this window } effects->prePaintWindow( w, data, time ); } void PresentWindowsEffect::paintWindow( EffectWindow *w, int mask, QRegion region, WindowPaintData &data ) { if(( m_activated || m_motionManager.areWindowsMoving() ) && m_windowData.contains( w )) { if( w->isDock() && m_showPanel ) { // in case the panel should be shown just display it without any changes effects->paintWindow( w, mask, region, data ); return; } // Apply opacity and brightness data.opacity *= m_windowData[w].opacity; data.brightness *= interpolate( 0.7, 1.0, m_windowData[w].highlight ); if( m_motionManager.isManaging( w )) { m_motionManager.apply( w, data ); if( !m_motionManager.areWindowsMoving() ) { mask |= PAINT_WINDOW_LANCZOS; } effects->paintWindow( w, mask, region, data ); QRect rect = m_motionManager.transformedGeometry( w ).toRect(); if( m_showIcons ) { QPoint point( rect.x() + rect.width() * 0.95, rect.y() + rect.height() * 0.95 ); m_windowData[w].iconFrame->setPosition( point ); #ifdef KWIN_HAVE_OPENGL_COMPOSITING if( effects->compositingType() == KWin::OpenGLCompositing && data.shader ) { data.shader->setUniform( "textureWidth", 1.0f ); data.shader->setUniform( "textureHeight", 1.0f ); data.shader->setUniform( "opacity", (float)(0.9 * data.opacity * m_decalOpacity * 0.75) ); } #endif m_windowData[w].iconFrame->render( region, 0.9 * data.opacity * m_decalOpacity, 0.75 ); } if( m_showCaptions ) { QPoint point( rect.x() + rect.width() / 2, rect.y() + rect.height() / 2 ); m_windowData[w].textFrame->setPosition( point ); #ifdef KWIN_HAVE_OPENGL_COMPOSITING if( effects->compositingType() == KWin::OpenGLCompositing && data.shader ) { data.shader->setUniform( "textureWidth", 1.0f ); data.shader->setUniform( "textureHeight", 1.0f ); data.shader->setUniform( "opacity", (float)(0.9 * data.opacity * m_decalOpacity * 0.75) ); } #endif m_windowData[w].textFrame->render( region, 0.9 * data.opacity * m_decalOpacity, 0.75 ); } } else effects->paintWindow( w, mask, region, data ); } else effects->paintWindow( w, mask, region, data ); } //----------------------------------------------------------------------------- // User interaction void PresentWindowsEffect::windowAdded( EffectWindow *w ) { if( !m_activated ) return; m_windowData[w].visible = isVisibleWindow( w ); m_windowData[w].opacity = 0.0; m_windowData[w].highlight = 0.0; m_windowData[w].textFrame = effects->effectFrame( EffectFrameUnstyled, false ); QFont font; font.setBold( true ); font.setPointSize( 12 ); m_windowData[w].textFrame->setFont( font ); m_windowData[w].iconFrame = effects->effectFrame( EffectFrameUnstyled, false ); m_windowData[w].iconFrame->setAlignment( Qt::AlignRight | Qt::AlignBottom ); m_windowData[w].iconFrame->setIcon( w->icon() ); if( isSelectableWindow( w )) { m_motionManager.manage( w ); rearrangeWindows(); } if( w == effects->findWindow( m_closeView->winId() ) ) { m_windowData[w].visible = true; m_windowData[w].highlight = 1.0; m_closeWindow = w; w->setData( WindowForceBlurRole, QVariant( true ) ); } } void PresentWindowsEffect::windowClosed( EffectWindow *w ) { if( m_managerWindow == w ) m_managerWindow = NULL; if( !m_windowData.contains( w )) return; m_windowData[w].deleted = true; m_windowData[w].referenced = true; w->refWindow(); if( m_highlightedWindow == w ) setHighlightedWindow( findFirstWindow() ); if( m_closeWindow == w ) { m_closeWindow = 0; return; // don't rearrange } rearrangeWindows(); } void PresentWindowsEffect::windowDeleted( EffectWindow *w ) { if( !m_windowData.contains( w )) return; delete m_windowData[w].textFrame; delete m_windowData[w].iconFrame; m_windowData.remove( w ); m_motionManager.unmanage( w ); } void PresentWindowsEffect::windowGeometryShapeChanged( EffectWindow* w, const QRect& old ) { Q_UNUSED( old ) if( !m_activated ) return; if( !m_windowData.contains( w )) return; rearrangeWindows(); } bool PresentWindowsEffect::borderActivated( ElectricBorder border ) { if( !m_borderActivate.contains( border ) && !m_borderActivateAll.contains( border ) ) return false; if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) return true; if( m_borderActivate.contains( border ) ) toggleActive(); else toggleActiveAllDesktops(); return true; } void PresentWindowsEffect::windowInputMouseEvent( Window w, QEvent *e ) { assert( w == m_input ); Q_UNUSED( w ); QMouseEvent* me = static_cast< QMouseEvent* >( e ); if( m_closeView->geometry().contains( me->pos() ) ) { if( !m_closeView->isVisible() ) { updateCloseWindow(); } if( m_closeView->isVisible() ) { const QPoint widgetPos = m_closeView->mapFromGlobal( me->pos() ); const QPointF scenePos = m_closeView->mapToScene( widgetPos ); QMouseEvent event( me->type(), widgetPos, me->pos(), me->button(), me->buttons(), me->modifiers() ); m_closeView->windowInputMouseEvent( &event ); return; } } // Which window are we hovering over? Always trigger as we don't always get move events before clicking // We cannot use m_motionManager.windowAtPoint() as the window might not be visible EffectWindowList windows = m_motionManager.managedWindows(); bool hovering = false; for( int i = 0; i < windows.size(); i++ ) { assert( m_windowData.contains( windows.at( i ))); if( m_motionManager.transformedGeometry( windows.at( i )).contains( cursorPos() ) && m_windowData[windows.at( i )].visible && !m_windowData[windows.at( i )].deleted ) { hovering = true; if( windows.at( i ) && m_highlightedWindow != windows.at( i )) setHighlightedWindow( windows.at( i )); break; } } if( m_highlightedWindow && m_motionManager.transformedGeometry( m_highlightedWindow ).contains( me->pos() ) ) updateCloseWindow(); else m_closeView->hide(); if( e->type() != QEvent::MouseButtonPress ) return; if( me->button() == Qt::LeftButton ) { if( hovering ) { // mouse is hovering above a window - use MouseActionsWindow mouseActionWindow( m_leftButtonWindow ); } else { // mouse is hovering above desktop - use MouseActionsDesktop mouseActionDesktop( m_leftButtonDesktop ); } } if( me->button() == Qt::MidButton ) { if( hovering ) { // mouse is hovering above a window - use MouseActionsWindow mouseActionWindow( m_middleButtonWindow ); } else { // mouse is hovering above desktop - use MouseActionsDesktop mouseActionDesktop( m_middleButtonDesktop ); } } if( me->button() == Qt::RightButton ) { if( hovering ) { // mouse is hovering above a window - use MouseActionsWindow mouseActionWindow( m_rightButtonWindow ); } else { // mouse is hovering above desktop - use MouseActionsDesktop mouseActionDesktop( m_rightButtonDesktop ); } } } void PresentWindowsEffect::mouseActionWindow( WindowMouseAction& action ) { switch( action ) { case WindowActivateAction: if( m_highlightedWindow ) effects->activateWindow( m_highlightedWindow ); setActive( false ); break; case WindowExitAction: setActive( false ); break; case WindowToCurrentDesktopAction: if( m_highlightedWindow ) effects->windowToDesktop( m_highlightedWindow, effects->currentDesktop() ); break; case WindowToAllDesktopsAction: if( m_highlightedWindow ) { if( m_highlightedWindow->isOnAllDesktops() ) effects->windowToDesktop( m_highlightedWindow, effects->currentDesktop() ); else effects->windowToDesktop( m_highlightedWindow, NET::OnAllDesktops ); } break; case WindowMinimizeAction: if( m_highlightedWindow ) { if( m_highlightedWindow->isMinimized() ) m_highlightedWindow->unminimize(); else m_highlightedWindow->minimize(); } break; case WindowCloseAction: if( m_highlightedWindow ) { m_highlightedWindow->closeWindow(); } break; default: break; } } void PresentWindowsEffect::mouseActionDesktop( DesktopMouseAction& action ) { switch( action ) { case DesktopActivateAction: if( m_highlightedWindow ) effects->activateWindow( m_highlightedWindow ); setActive( false ); break; case DesktopExitAction: setActive( false ); break; case DesktopShowDesktopAction: effects->setShowingDesktop( true ); setActive( false ); default: break; } } void PresentWindowsEffect::grabbedKeyboardEvent( QKeyEvent *e ) { if( e->type() == QEvent::KeyPress ) { // check for global shortcuts // HACK: keyboard grab disables the global shortcuts so we have to check for global shortcut (bug 156155) if( m_mode == ModeCurrentDesktop && shortcut.contains( e->key() + e->modifiers() ) ) { toggleActive(); return; } if( m_mode == ModeAllDesktops && shortcutAll.contains( e->key() + e->modifiers() ) ) { toggleActiveAllDesktops(); return; } if( m_mode == ModeWindowClass && shortcutClass.contains( e->key() + e->modifiers() ) ) { toggleActiveClass(); return; } switch( e->key() ) { // Wrap only if not auto-repeating case Qt::Key_Left: if( m_highlightedWindow ) setHighlightedWindow( relativeWindow( m_highlightedWindow, -1, 0, !e->isAutoRepeat() )); break; case Qt::Key_Right: if( m_highlightedWindow ) setHighlightedWindow( relativeWindow( m_highlightedWindow, 1, 0, !e->isAutoRepeat() )); break; case Qt::Key_Up: if( m_highlightedWindow ) setHighlightedWindow( relativeWindow( m_highlightedWindow, 0, -1, !e->isAutoRepeat() )); break; case Qt::Key_Down: if( m_highlightedWindow ) setHighlightedWindow( relativeWindow( m_highlightedWindow, 0, 1, !e->isAutoRepeat() )); break; case Qt::Key_Home: if( m_highlightedWindow ) setHighlightedWindow( relativeWindow( m_highlightedWindow, -1000, 0, false )); break; case Qt::Key_End: if( m_highlightedWindow ) setHighlightedWindow( relativeWindow( m_highlightedWindow, 1000, 0, false )); break; case Qt::Key_PageUp: if( m_highlightedWindow ) setHighlightedWindow( relativeWindow( m_highlightedWindow, 0, -1000, false )); break; case Qt::Key_PageDown: if( m_highlightedWindow ) setHighlightedWindow( relativeWindow( m_highlightedWindow, 0, 1000, false )); break; case Qt::Key_Backspace: if( !m_windowFilter.isEmpty() ) { m_windowFilter.remove( m_windowFilter.length() - 1, 1 ); updateFilterFrame(); rearrangeWindows(); } return; case Qt::Key_Escape: setActive( false ); return; case Qt::Key_Return: case Qt::Key_Enter: if( m_highlightedWindow ) effects->activateWindow( m_highlightedWindow ); setActive( false ); return; case Qt::Key_Tab: return; // Nothing at the moment case Qt::Key_Delete: if( !m_windowFilter.isEmpty() ) { m_windowFilter.clear(); updateFilterFrame(); rearrangeWindows(); } break; case 0: return; // HACK: Workaround for Qt bug on unbound keys (#178547) default: if( !e->text().isEmpty() ) { m_windowFilter.append( e->text() ); updateFilterFrame(); rearrangeWindows(); return; } break; } } } //----------------------------------------------------------------------------- // Tab box void PresentWindowsEffect::tabBoxAdded( int mode ) { if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) return; if( m_activated ) return; if( (( mode == TabBoxWindowsMode && m_tabBoxAllowed ) || ( mode == TabBoxWindowsAlternativeMode && m_tabBoxAlternativeAllowed )) && effects->currentTabBoxWindowList().count() > 0 ) { m_tabBoxEnabled = true; setActive( true ); if( m_activated ) effects->refTabBox(); else m_tabBoxEnabled = false; } } void PresentWindowsEffect::tabBoxClosed() { if( m_activated ) { effects->unrefTabBox(); setActive( false, true ); m_tabBoxEnabled = false; } } void PresentWindowsEffect::tabBoxUpdated() { if( m_activated ) setHighlightedWindow( effects->currentTabBoxWindow() ); } void PresentWindowsEffect::tabBoxKeyEvent( QKeyEvent* event ) { if( !m_activated ) return; // not using the "normal" grabbedKeyboardEvent as we don't want to filter in tabbox if( event->type() == QEvent::KeyPress ) { switch( event->key() ) { // Wrap only if not auto-repeating case Qt::Key_Left: setHighlightedWindow( relativeWindow( m_highlightedWindow, -1, 0, !event->isAutoRepeat() )); break; case Qt::Key_Right: setHighlightedWindow( relativeWindow( m_highlightedWindow, 1, 0, !event->isAutoRepeat() )); break; case Qt::Key_Up: setHighlightedWindow( relativeWindow( m_highlightedWindow, 0, -1, !event->isAutoRepeat() )); break; case Qt::Key_Down: setHighlightedWindow( relativeWindow( m_highlightedWindow, 0, 1, !event->isAutoRepeat() )); break; case Qt::Key_Home: setHighlightedWindow( relativeWindow( m_highlightedWindow, -1000, 0, false )); break; case Qt::Key_End: setHighlightedWindow( relativeWindow( m_highlightedWindow, 1000, 0, false )); break; case Qt::Key_PageUp: setHighlightedWindow( relativeWindow( m_highlightedWindow, 0, -1000, false )); break; case Qt::Key_PageDown: setHighlightedWindow( relativeWindow( m_highlightedWindow, 0, 1000, false )); break; default: // nothing break; } } } //----------------------------------------------------------------------------- // Atom handling void PresentWindowsEffect::propertyNotify( EffectWindow* w, long a ) { if( !w || ( a != m_atomDesktop && a != m_atomWindows )) return; // Not our atom if( a == m_atomDesktop ) { QByteArray byteData = w->readProperty( m_atomDesktop, m_atomDesktop, 32 ); if( byteData.length() < 1 ) { // Property was removed, end present windows setActive( false ); return; } long* data = reinterpret_cast( byteData.data() ); if( !data[0] ) { // Purposely ending present windows by issuing a NULL target setActive( false ); return; } // present windows is active so don't do anything if( m_activated ) return; int desktop = data[0]; if( desktop > effects->numberOfDesktops() ) return; if( desktop == -1 ) toggleActiveAllDesktops(); else { m_mode = ModeSelectedDesktop; m_desktop = desktop; m_managerWindow = w; setActive( true ); } } else if( a == m_atomWindows ) { QByteArray byteData = w->readProperty( m_atomWindows, m_atomWindows, 32 ); if( byteData.length() < 1 ) { // Property was removed, end present windows setActive( false ); return; } long* data = reinterpret_cast( byteData.data() ); if( !data[0] ) { // Purposely ending present windows by issuing a NULL target setActive( false ); return; } // present windows is active so don't do anything if( m_activated ) return; // for security clear selected windows m_selectedWindows.clear(); int length = byteData.length() / sizeof( data[0] ); for( int i=0; ifindWindow( data[i] ); if( !foundWin ) { kDebug(1212) << "Invalid window targetted for present windows. Requested:" << data[i]; continue; } m_selectedWindows.append( foundWin ); } m_mode = ModeWindowGroup; m_managerWindow = w; setActive( true ); } } //----------------------------------------------------------------------------- // Window rearranging void PresentWindowsEffect::rearrangeWindows() { if( !m_activated ) return; effects->addRepaintFull(); // Trigger the first repaint m_closeView->hide(); // Work out which windows are on which screens EffectWindowList windowlist; QList windowlists; for( int i = 0; i < effects->numScreens(); i++ ) windowlists.append( EffectWindowList() ); if( m_windowFilter.isEmpty() ) { if( m_tabBoxEnabled ) // Assume we correctly set things up, should be identical to // m_motionManager except just in a slightly different order. windowlist = effects->currentTabBoxWindowList(); else windowlist = m_motionManager.managedWindows(); foreach( EffectWindow *w, m_motionManager.managedWindows() ) { if( m_windowData[w].deleted ) continue; // don't include closed windows windowlists[w->screen()].append( w ); assert( m_windowData.contains( w )); m_windowData[w].visible = true; } } else { // Can we move this filtering somewhere else? foreach( EffectWindow *w, m_motionManager.managedWindows() ) { assert( m_windowData.contains( w )); if( m_windowData[w].deleted ) continue; // don't include closed windows if( w->caption().contains( m_windowFilter, Qt::CaseInsensitive ) || w->windowClass().contains( m_windowFilter, Qt::CaseInsensitive ) || w->windowRole().contains( m_windowFilter, Qt::CaseInsensitive )) { windowlist.append( w ); windowlists[w->screen()].append( w ); m_windowData[w].visible = true; } else m_windowData[w].visible = false; } } if( windowlist.isEmpty() ) { setHighlightedWindow( NULL ); // TODO: Having a NULL highlighted window isn't really safe return; } // We filtered out the highlighted window if( m_highlightedWindow ) { assert( m_windowData.contains( m_highlightedWindow )); if( m_windowData[m_highlightedWindow].visible == false ) setHighlightedWindow( findFirstWindow() ); } else if( m_tabBoxEnabled ) setHighlightedWindow( effects->currentTabBoxWindow() ); else setHighlightedWindow( findFirstWindow() ); int screens = m_tabBoxEnabled ? 1 : effects->numScreens(); for( int screen = 0; screen < screens; screen++ ) { EffectWindowList windows; if( m_tabBoxEnabled ) { // Kind of cheating here screen = effects->activeScreen(); windows = windowlist; } else windows = windowlists[screen]; // Don't rearrange if the grid is the same size as what it was before to prevent // windows moving to a better spot if one was filtered out. if( m_layoutMode == LayoutRegularGrid && m_gridSizes[screen].columns * m_gridSizes[screen].rows && windows.size() < m_gridSizes[screen].columns * m_gridSizes[screen].rows && windows.size() > ( m_gridSizes[screen].columns - 1) * m_gridSizes[screen].rows && windows.size() > m_gridSizes[screen].columns * ( m_gridSizes[screen].rows - 1 ) && !m_tabBoxEnabled ) continue; // No point continuing if there is no windows to process if( !windows.count() ) continue; calculateWindowTransformations( windows, screen, m_motionManager ); } // 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::calculateWindowTransformations( EffectWindowList windowlist, int screen, WindowMotionManager& motionManager, bool external ) { if( m_layoutMode == LayoutRegularGrid || m_tabBoxEnabled ) // Force the grid for window switching calculateWindowTransformationsClosest( windowlist, screen, motionManager ); else if( m_layoutMode == LayoutFlexibleGrid ) calculateWindowTransformationsKompose( windowlist, screen, motionManager ); else calculateWindowTransformationsNatural( windowlist, screen, motionManager ); // If called externally we don't need to remember this data if( external ) m_windowData.clear(); } void PresentWindowsEffect::calculateWindowTransformationsClosest( EffectWindowList windowlist, int screen, WindowMotionManager& motionManager ) { // This layout mode requires at least one window visible if( windowlist.count() == 0 ) return; QRect area = effects->clientArea( ScreenArea, screen, effects->currentDesktop() ); if( m_showPanel ) // reserve space for the panel area = effects->clientArea( MaximizeArea, screen, effects->currentDesktop() ); int columns = int( ceil( sqrt( double( windowlist.count() )))); int rows = int( ceil( windowlist.count() / double( columns ))); // Remember the size for later // If we are using this layout externally we don't need to remember m_gridSizes. if( m_gridSizes.size() != 0 ) { m_gridSizes[screen].columns = columns; m_gridSizes[screen].rows = rows; } // Assign slots foreach( EffectWindow *w, windowlist ) m_windowData[w].slot = -1; if( m_tabBoxEnabled ) { // Rearrange in the correct order. As rearrangeWindows() is only ever // called once so we can use effects->currentTabBoxWindow() here. int selectedWindow = qMax( 0, windowlist.indexOf( effects->currentTabBoxWindow() )); int slot = 0; for( int i = selectedWindow; i < windowlist.count(); i++ ) m_windowData[windowlist[i]].slot = slot++; for( int i = selectedWindow - 1; i >= 0; i-- ) m_windowData[windowlist[i]].slot = slot++; } else { for(;;) { // Assign each window to the closest available slot assignSlots( windowlist, area, columns, rows ); // Leave only the closest window in each slot, remove further conflicts getBestAssignments( windowlist ); bool allAssigned = true; foreach( EffectWindow *w, windowlist ) if( m_windowData[w].slot == -1 ) { allAssigned = false; break; } if( allAssigned ) break; } } int slotWidth = area.width() / columns; int slotHeight = area.height() / rows; foreach( EffectWindow *w, windowlist ) { assert( m_windowData[w].slot != -1 ); // Work out where the slot is QRect target( area.x() + ( m_windowData[w].slot % columns ) * slotWidth, area.y() + ( m_windowData[w].slot / columns ) * slotHeight, slotWidth, slotHeight ); target.adjust( 10, 10, -10, -10 ); // Borders double scale; if( target.width() / double( w->width() ) < target.height() / double( w->height() )) { // Center vertically scale = target.width() / double( w->width() ); target.moveTop( target.top() + ( target.height() - int( w->height() * scale )) / 2 ); target.setHeight( int( w->height() * scale )); } else { // Center horizontally scale = target.height() / double( w->height() ); target.moveLeft( target.left() + ( target.width() - int( w->width() * scale )) / 2 ); target.setWidth( int( w->width() * scale )); } // Don't scale the windows too much if( scale > 2.0 || ( scale > 1.0 && ( w->width() > 300 || w->height() > 300 ))) { scale = ( w->width() > 300 || w->height() > 300 ) ? 1.0 : 2.0; target = QRect( target.center().x() - int( w->width() * scale ) / 2, target.center().y() - int( w->height() * scale ) / 2, scale * w->width(), scale * w->height() ); } motionManager.moveWindow( w, target ); } } void PresentWindowsEffect::calculateWindowTransformationsKompose( EffectWindowList windowlist, int screen, WindowMotionManager& motionManager ) { // This layout mode requires at least one window visible if( windowlist.count() == 0 ) return; QRect availRect = effects->clientArea( ScreenArea, screen, effects->currentDesktop() ); if( m_showPanel ) // reserve space for the panel availRect = effects->clientArea( MaximizeArea, screen, effects->currentDesktop() ); qSort( windowlist ); // The location of the windows should not depend on the stacking order // Following code is taken from Kompose 0.5.4, src/komposelayout.cpp int spacing = 10; int rows, columns; double parentRatio = availRect.width() / (double)availRect.height(); // Use more columns than rows when parent's width > parent's height if ( parentRatio > 1 ) { columns = (int)ceil( sqrt((double)windowlist.count()) ); rows = (int)ceil( (double)windowlist.count() / (double)columns ); } else { rows = (int)ceil( sqrt((double)windowlist.count()) ); columns = (int)ceil( (double)windowlist.count() / (double)rows ); } //kDebug(1212) << "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 geometryRects; QList maxRowHeights; // Process rows for ( int i=0; i 0 ) { usableW = w + addW; } } if ( ratio == -1 ) { widgetw = w; widgeth = h; } else { double widthByHeight = widthForHeight( window, usableH ); double heightByWidth = heightForWidth( window, usableW ); if ( (ratio >= 1.0 && heightByWidth <= usableH) || (ratio < 1.0 && widthByHeight > usableW) ) { widgetw = usableW; widgeth = (int)heightByWidth; } else if ( (ratio < 1.0 && widthByHeight <= usableW) || (ratio >= 1.0 && heightByWidth > usableH) ) { widgeth = usableH; widgetw = (int)widthByHeight; } // Don't upscale large-ish windows if( widgetw > window->width() && ( window->width() > 300 || window->height() > 300 )) { widgetw = window->width(); widgeth = window->height(); } } // 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 target = geometryRects[pos]; target.setY( target.y() + topOffset ); m_windowData[window].slot = pos; motionManager.moveWindow( window, target ); //kDebug(1212) << "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::calculateWindowTransformationsNatural( EffectWindowList windowlist, int screen, WindowMotionManager& motionManager ) { // If windows do not overlap they scale into nothingness, fix by resetting. To reproduce // just have a single window on a Xinerama screen or have two windows that do not touch. // TODO: Work out why this happens, is most likely a bug in the manager. foreach( EffectWindow *w, windowlist ) if( motionManager.transformedGeometry( w ) == w->geometry() ) motionManager.reset( w ); if( windowlist.count() == 1 ) { // Just move the window to its original location to save time if( effects->clientArea( FullScreenArea, windowlist[0] ).contains( windowlist[0]->geometry() ) ) { motionManager.moveWindow( windowlist[0], windowlist[0]->geometry() ); return; } } // As we are using pseudo-random movement (See "slot") we need to make sure the list // is always sorted the same way no matter which window is currently active. qSort( windowlist ); QRect area = effects->clientArea( ScreenArea, screen, effects->currentDesktop() ); if( m_showPanel ) // reserve space for the panel area = effects->clientArea( MaximizeArea, screen, effects->currentDesktop() ); QRect bounds = area; int direction = 0; QHash targets; QHash directions; foreach( EffectWindow *w, windowlist ) { bounds = bounds.united( w->geometry() ); targets[w] = w->geometry(); // Reuse the unused "slot" as a preferred direction attribute. This is used when the window // is on the edge of the screen to try to use as much screen real estate as possible. directions[w] = direction; direction++; if( direction == 4 ) direction = 0; } // Iterate over all windows, if two overlap push them apart _slightly_ as we try to // brute-force the most optimal positions over many iterations. bool overlap; do { overlap = false; foreach( EffectWindow *w, windowlist ) { foreach( EffectWindow *e, windowlist ) { if( w != e && targets[w].adjusted( -5, -5, 5, 5 ).intersects( targets[e].adjusted( -5, -5, 5, 5 ))) { overlap = true; // Determine pushing direction QPoint diff( targets[e].center() - targets[w].center() ); // Prevent dividing by zero and non-movement if( diff.x() == 0 && diff.y() == 0 ) diff.setX( 1 ); // Try to keep screen aspect ratio //if( bounds.height() / bounds.width() > area.height() / area.width() ) // diff.setY( diff.y() / 2 ); //else // diff.setX( diff.x() / 2 ); // Approximate a vector of between 10px and 20px in magnitude in the same direction diff *= m_accuracy / double( diff.manhattanLength() ); // Move both windows apart targets[w].translate( -diff ); targets[e].translate( diff ); // Try to keep the bounding rect the same aspect as the screen so that more // screen real estate is utilised. We do this by splitting the screen into nine // equal sections, if the window center is in any of the corner sections pull the // window towards the outer corner. If it is in any of the other edge sections // alternate between each corner on that edge. We don't want to determine it // randomly as it will not produce consistant locations when using the filter. // Only move one window so we don't cause large amounts of unnecessary zooming // in some situations. We need to do this even when expanding later just in case // all windows are the same size. // (We are using an old bounding rect for this, hopefully it doesn't matter) int xSection = ( targets[w].x() - bounds.x() ) / ( bounds.width() / 3 ); int ySection = ( targets[w].y() - bounds.y() ) / ( bounds.height() / 3 ); diff = QPoint( 0, 0 ); if( xSection != 1 || ySection != 1 ) // Remove this if you want the center to pull as well { if( xSection == 1 ) xSection = ( directions[w] / 2 ? 2 : 0 ); if( ySection == 1 ) ySection = ( directions[w] % 2 ? 2 : 0 ); } if( xSection == 0 && ySection == 0 ) diff = QPoint( bounds.topLeft() - targets[w].center() ); if( xSection == 2 && ySection == 0 ) diff = QPoint( bounds.topRight() - targets[w].center() ); if( xSection == 2 && ySection == 2 ) diff = QPoint( bounds.bottomRight() - targets[w].center() ); if( xSection == 0 && ySection == 2 ) diff = QPoint( bounds.bottomLeft() - targets[w].center() ); if( diff.x() != 0 || diff.y() != 0 ) { diff *= m_accuracy / double( diff.manhattanLength() ); targets[w].translate( diff ); } // Update bounding rect bounds = bounds.united( targets[w] ); bounds = bounds.united( targets[e] ); } } } } while( overlap ); // Work out scaling by getting the most top-left and most bottom-right window coords. // The 20's and 10's are so that the windows don't touch the edge of the screen. double scale; if( bounds == area ) scale = 1.0; // Don't add borders to the screen else if( area.width() / double( bounds.width() ) < area.height() / double( bounds.height() )) scale = ( area.width() - 20 ) / double( bounds.width() ); else scale = ( area.height() - 20 ) / double( bounds.height() ); // Make bounding rect fill the screen size for later steps bounds = QRect( bounds.x() - ( area.width() - 20 - bounds.width() * scale ) / 2 - 10 / scale, bounds.y() - ( area.height() - 20 - bounds.height() * scale ) / 2 - 10 / scale, area.width() / scale, area.height() / scale ); // Move all windows back onto the screen and set their scale foreach( EffectWindow *w, windowlist ) targets[w] = QRect( ( targets[w].x() - bounds.x() ) * scale + area.x(), ( targets[w].y() - bounds.y() ) * scale + area.y(), targets[w].width() * scale, targets[w].height() * scale ); // Try to fill the gaps by enlarging windows if they have the space if( m_fillGaps ) { // Don't expand onto or over the border QRegion borderRegion( area.adjusted( -200, -200, 200, 200 )); borderRegion ^= area.adjusted( 10 / scale, 10 / scale, -10 / scale, -10 / scale ); bool moved; do { moved = false; foreach( EffectWindow *w, windowlist ) { QRect oldRect; // This may cause some slight distortion if the windows are enlarged a large amount int widthDiff = m_accuracy; int heightDiff = heightForWidth( w, targets[w].width() + widthDiff ) - targets[w].height(); int xDiff = widthDiff / 2; // Also move a bit in the direction of the enlarge, allows the int yDiff = heightDiff / 2; // center windows to be enlarged if there is gaps on the side. // Attempt enlarging to the top-right oldRect = targets[w]; targets[w] = QRect( targets[w].x() + xDiff, targets[w].y() - yDiff - heightDiff, targets[w].width() + widthDiff, targets[w].height() + heightDiff ); if( isOverlappingAny( w, targets, borderRegion )) targets[w] = oldRect; else moved = true; // Attempt enlarging to the bottom-right oldRect = targets[w]; targets[w] = QRect( targets[w].x() + xDiff, targets[w].y() + yDiff, targets[w].width() + widthDiff, targets[w].height() + heightDiff ); if( isOverlappingAny( w, targets, borderRegion )) targets[w] = oldRect; else moved = true; // Attempt enlarging to the bottom-left oldRect = targets[w]; targets[w] = QRect( targets[w].x() - xDiff - widthDiff, targets[w].y() + yDiff, targets[w].width() + widthDiff, targets[w].height() + heightDiff ); if( isOverlappingAny( w, targets, borderRegion )) targets[w] = oldRect; else moved = true; // Attempt enlarging to the top-left oldRect = targets[w]; targets[w] = QRect( targets[w].x() - xDiff - widthDiff, targets[w].y() - yDiff - heightDiff, targets[w].width() + widthDiff, targets[w].height() + heightDiff ); if( isOverlappingAny( w, targets, borderRegion )) targets[w] = oldRect; else moved = true; } } while( moved ); // The expanding code above can actually enlarge windows over 1.0/2.0 scale, we don't like this // We can't add this to the loop above as it would cause a never-ending loop so we have to make // do with the less-than-optimal space usage with using this method. foreach( EffectWindow *w, windowlist ) { double scale = targets[w].width() / double( w->width() ); if( scale > 2.0 || ( scale > 1.0 && ( w->width() > 300 || w->height() > 300 ))) { scale = ( w->width() > 300 || w->height() > 300 ) ? 1.0 : 2.0; targets[w] = QRect( targets[w].center().x() - int( w->width() * scale ) / 2, targets[w].center().y() - int( w->height() * scale ) / 2, w->width() * scale, w->height() * scale ); } } } // Notify the motion manager of the targets foreach( EffectWindow *w, windowlist ) motionManager.moveWindow( w, targets[w] ); } //----------------------------------------------------------------------------- // Helper functions for window rearranging void PresentWindowsEffect::assignSlots( EffectWindowList windowlist, const QRect &area, int columns, int rows ) { QVector< bool > taken; taken.fill( false, columns * rows ); foreach( EffectWindow* w, windowlist ) if( m_windowData[w].slot != -1 ) taken[ m_windowData[w].slot ] = true; int slotWidth = area.width() / columns; int slotHeight = area.height() / rows; foreach( EffectWindow *w, windowlist ) { WindowData *wData = &m_windowData[w]; if( wData->slot != -1 ) continue; // it already has a slot QPoint pos = w->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 ); int ydiff = pos.y() - ( area.y() + slotHeight * y + slotHeight / 2 ); int dist = int( sqrt( double( xdiff * xdiff + ydiff * ydiff ))); if( dist < distance ) { distance = dist; wData->slot = slot; wData->slot_distance = distance; } } } } void PresentWindowsEffect::getBestAssignments( EffectWindowList windowlist ) { foreach( EffectWindow* w1, windowlist ) { WindowData *windowData1 = &m_windowData[w1]; foreach( EffectWindow* w2, windowlist ) { WindowData *windowData2 = &m_windowData[w2]; if( w1 != w2 && windowData1->slot == windowData2->slot && windowData1->slot_distance >= windowData2->slot_distance ) windowData1->slot = -1; } } } bool PresentWindowsEffect::isOverlappingAny( EffectWindow *w, const QHash &targets, const QRegion &border ) { if( border.intersects( targets[w] )) return true; // Is there a better way to do this? QHash::const_iterator i; for( i = targets.constBegin(); i != targets.constEnd(); ++i ) { if( w == i.key() ) continue; if( targets[w].adjusted( -5, -5, 5, 5 ).intersects( i.value().adjusted( -5, -5, 5, 5 ))) return true; } return false; } //----------------------------------------------------------------------------- // Activation void PresentWindowsEffect::setActive( bool active, bool closingTab ) { if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) return; if( m_activated == active ) return; if( m_activated && m_tabBoxEnabled && !closingTab ) { effects->closeTabBox(); return; } m_activated = active; if( m_activated ) { m_decalOpacity = 0.0; m_highlightedWindow = NULL; m_windowFilter.clear(); m_closeView = new CloseWindowView(); connect( m_closeView, SIGNAL(close()), SLOT(closeWindow()) ); // Add every single window to m_windowData (Just calling [w] creates it) foreach( EffectWindow *w, effects->stackingOrder() ) { if( m_windowData.contains( w )) // Happens if we reactivate before the ending animation finishes continue; m_windowData[w].visible = isVisibleWindow( w ); m_windowData[w].deleted = false; m_windowData[w].referenced = false; m_windowData[w].opacity = 0.0; if( w->isOnCurrentDesktop() && !w->isMinimized() ) m_windowData[w].opacity = 1.0; m_windowData[w].highlight = 1.0; m_windowData[w].textFrame = effects->effectFrame( EffectFrameUnstyled, false ); QFont font; font.setBold( true ); font.setPointSize( 12 ); m_windowData[w].textFrame->setFont( font ); m_windowData[w].iconFrame = effects->effectFrame( EffectFrameUnstyled, false ); m_windowData[w].iconFrame->setAlignment( Qt::AlignRight | Qt::AlignBottom ); m_windowData[w].iconFrame->setIcon( w->icon() ); } if( m_tabBoxEnabled ) { foreach( EffectWindow *w, effects->currentTabBoxWindowList() ) { if( !w ) continue; m_motionManager.manage( w ); assert( m_windowData.contains( w )); m_windowData[w].visible = effects->currentTabBoxWindowList().contains( w ); } // Hide windows not in the list foreach( EffectWindow *w, effects->stackingOrder() ) m_windowData[w].visible = isVisibleWindow( w ) && (!isSelectableWindow( w ) || effects->currentTabBoxWindowList().contains( w )); } else { // Filter out special windows such as panels and taskbars foreach( EffectWindow *w, effects->stackingOrder() ) if( isSelectableWindow( w )) m_motionManager.manage( w ); } if( m_motionManager.managedWindows().isEmpty() || (( m_motionManager.managedWindows().count() == 1 ) && m_motionManager.managedWindows().first()->isOnCurrentDesktop() && ( m_ignoreMinimized || !m_motionManager.managedWindows().first()->isMinimized() ) )) { // 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; } // Create temporary input window to catch mouse events m_input = effects->createFullScreenInputWindow( this, Qt::PointingHandCursor ); m_hasKeyboardGrab = effects->grabKeyboard( this ); effects->setActiveFullScreenEffect( this ); m_gridSizes.clear(); for( int i = 0; i < effects->numScreens(); i++ ) m_gridSizes.append( GridSize() ); rearrangeWindows(); if( m_tabBoxEnabled ) setHighlightedWindow( effects->currentTabBoxWindow() ); else setHighlightedWindow( effects->activeWindow() ); foreach( EffectWindow *w, effects->stackingOrder() ) { if( w->isDock() ) { w->setData( WindowForceBlurRole, QVariant( true ) ); } } } else { // Fade in/out all windows EffectWindow *activeWindow = effects->activeWindow(); if( m_tabBoxEnabled ) activeWindow = effects->currentTabBoxWindow(); int desktop = effects->currentDesktop(); if( activeWindow && !activeWindow->isOnAllDesktops() ) desktop = activeWindow->desktop(); foreach( EffectWindow *w, effects->stackingOrder() ) { assert( m_windowData.contains( w )); m_windowData[w].visible = ( w->isOnDesktop( desktop ) || w->isOnAllDesktops() ) && !w->isMinimized() && ( w->visibleInClientGroup() || m_windowData[w].visible ); } delete m_closeView; m_closeView = 0; // Move all windows back to their original position foreach( EffectWindow *w, m_motionManager.managedWindows() ) m_motionManager.moveWindow( w, w->geometry() ); m_filterFrame->free(); m_windowFilter.clear(); m_selectedWindows.clear(); effects->destroyInputWindow( m_input ); if( m_hasKeyboardGrab ) effects->ungrabKeyboard(); m_hasKeyboardGrab = false; // destroy atom on manager window if( m_managerWindow ) { if( m_mode == ModeSelectedDesktop ) m_managerWindow->deleteProperty( m_atomDesktop ); else if( m_mode == ModeWindowGroup ) m_managerWindow->deleteProperty( m_atomWindows ); m_managerWindow = NULL; } } effects->addRepaintFull(); // Trigger the first repaint } //----------------------------------------------------------------------------- // Filter box void PresentWindowsEffect::updateFilterFrame() { QRect area = effects->clientArea( ScreenArea, effects->activeScreen(), effects->currentDesktop() ); m_filterFrame->setPosition( QPoint( area.x() + area.width() / 2, area.y() + area.height() / 2 )); m_filterFrame->setText( i18n( "Filter:\n%1", m_windowFilter )); } //----------------------------------------------------------------------------- // Helper functions bool PresentWindowsEffect::isSelectableWindow( EffectWindow *w ) { if( w->isSpecialWindow() || w->isUtility() ) return false; if( w->isDeleted() ) return false; if( !w->acceptsFocus() ) return false; if( !w->visibleInClientGroup() ) return false; if( w->isSkipSwitcher() ) return false; if( w == effects->findWindow( m_closeView->winId() ) ) return false; switch( m_mode ) { case ModeAllDesktops: break; case ModeCurrentDesktop: return w->isOnCurrentDesktop(); case ModeSelectedDesktop: return w->isOnDesktop( m_desktop ); case ModeWindowGroup: return m_selectedWindows.contains( w ); case ModeWindowClass: return m_class == w->windowClass(); } if( !m_tabBoxEnabled && m_ignoreMinimized && w->isMinimized() ) return false; return true; } bool PresentWindowsEffect::isVisibleWindow( EffectWindow *w ) { if( w->isDesktop() ) return true; return isSelectableWindow( w ); } void PresentWindowsEffect::setHighlightedWindow( EffectWindow *w ) { if( w == m_highlightedWindow || ( w != NULL && !m_motionManager.isManaging( w ))) return; m_closeView->hide(); if( m_highlightedWindow ) m_highlightedWindow->addRepaintFull(); // Trigger the first repaint m_highlightedWindow = w; if( m_highlightedWindow ) m_highlightedWindow->addRepaintFull(); // Trigger the first repaint if( m_tabBoxEnabled && m_highlightedWindow ) effects->setTabBoxWindow( w ); updateCloseWindow(); } void PresentWindowsEffect::updateCloseWindow() { + if ( m_doNotCloseWindows ) + return; if( m_closeView->isVisible() ) return; if( !m_highlightedWindow ) { m_closeView->hide(); return; } const QRectF rect = m_motionManager.targetGeometry( m_highlightedWindow ); m_closeView->setGeometry( rect.x() + rect.width() - m_closeView->sceneRect().width(), rect.y(), m_closeView->sceneRect().width(), m_closeView->sceneRect().height() ); if( rect.contains( effects->cursorPos() ) ) m_closeView->delayedShow(); else m_closeView->hide(); } void PresentWindowsEffect::closeWindow() { if( m_highlightedWindow ) m_highlightedWindow->closeWindow(); } EffectWindow* PresentWindowsEffect::relativeWindow( EffectWindow *w, int xdiff, int ydiff, bool wrap ) const { // TODO: Is it possible to select hidden windows? EffectWindow* next; QRect area = effects->clientArea( FullArea, 0, effects->currentDesktop() ); QRect detectRect; // Detect across the width of the desktop if( xdiff != 0 ) { if( xdiff > 0 ) { // Detect right for( int i = 0; i < xdiff; i++ ) { QRectF wArea = m_motionManager.transformedGeometry( w ); detectRect = QRect( 0, wArea.y(), area.width(), wArea.height() ); next = NULL; foreach( EffectWindow* e, m_motionManager.managedWindows() ) { if( !m_windowData[e].visible ) continue; QRectF eArea = m_motionManager.transformedGeometry( e ); if( eArea.intersects( detectRect ) && eArea.x() > wArea.x() ) { if( next == NULL ) next = e; else { QRectF nArea = m_motionManager.transformedGeometry( next ); if( eArea.x() < nArea.x() ) next = e; } } } if( next == NULL ) { if( wrap ) // We are at the right-most window, now get the left-most one to wrap return relativeWindow( w, -1000, 0, false ); break; // No more windows to the right } w = next; } return w; } else { // Detect left for( int i = 0; i < -xdiff; i++ ) { QRectF wArea = m_motionManager.transformedGeometry( w ); detectRect = QRect( 0, wArea.y(), area.width(), wArea.height() ); next = NULL; foreach( EffectWindow* e, m_motionManager.managedWindows() ) { if( !m_windowData[e].visible ) continue; QRectF eArea = m_motionManager.transformedGeometry( e ); if( eArea.intersects( detectRect ) && eArea.x() + eArea.width() < wArea.x() + wArea.width() ) { if( next == NULL ) next = e; else { QRectF nArea = m_motionManager.transformedGeometry( next ); if( eArea.x() + eArea.width() > nArea.x() + nArea.width() ) next = e; } } } if( next == NULL ) { if( wrap ) // We are at the left-most window, now get the right-most one to wrap return relativeWindow( w, 1000, 0, false ); break; // No more windows to the left } w = next; } return w; } } // Detect across the height of the desktop if( ydiff != 0 ) { if( ydiff > 0 ) { // Detect down for( int i = 0; i < ydiff; i++ ) { QRectF wArea = m_motionManager.transformedGeometry( w ); detectRect = QRect( wArea.x(), 0, wArea.width(), area.height() ); next = NULL; foreach( EffectWindow* e, m_motionManager.managedWindows() ) { if( !m_windowData[e].visible ) continue; QRectF eArea = m_motionManager.transformedGeometry( e ); if( eArea.intersects( detectRect ) && eArea.y() > wArea.y() ) { if( next == NULL ) next = e; else { QRectF nArea = m_motionManager.transformedGeometry( next ); if( eArea.y() < nArea.y() ) next = e; } } } if( next == NULL ) { if( wrap ) // We are at the bottom-most window, now get the top-most one to wrap return relativeWindow( w, 0, -1000, false ); break; // No more windows to the bottom } w = next; } return w; } else { // Detect up for( int i = 0; i < -ydiff; i++ ) { QRectF wArea = m_motionManager.transformedGeometry( w ); detectRect = QRect( wArea.x(), 0, wArea.width(), area.height() ); next = NULL; foreach( EffectWindow* e, m_motionManager.managedWindows() ) { if( !m_windowData[e].visible ) continue; QRectF eArea = m_motionManager.transformedGeometry( e ); if( eArea.intersects( detectRect ) && eArea.y() + eArea.height() < wArea.y() + wArea.height() ) { if( next == NULL ) next = e; else { QRectF nArea = m_motionManager.transformedGeometry( next ); if( eArea.y() + eArea.height() > nArea.y() + nArea.height() ) next = e; } } } if( next == NULL ) { if( wrap ) // We are at the top-most window, now get the bottom-most one to wrap return relativeWindow( w, 0, 1000, false ); break; // No more windows to the top } w = next; } return w; } } abort(); // Should never get here } EffectWindow* PresentWindowsEffect::findFirstWindow() const { EffectWindow *topLeft = NULL; QRectF topLeftGeometry; foreach( EffectWindow *w, m_motionManager.managedWindows() ) { QRectF geometry = m_motionManager.transformedGeometry( w ); if( m_windowData[w].visible == false ) continue; // Not visible if( m_windowData[w].deleted ) continue; // Window has been closed if( topLeft == NULL ) { topLeft = w; topLeftGeometry = geometry; } else if( geometry.x() < topLeftGeometry.x() || geometry.y() < topLeftGeometry.y() ) { topLeft = w; topLeftGeometry = geometry; } } return topLeft; } void PresentWindowsEffect::globalShortcutChanged( const QKeySequence& seq ) { shortcut = KShortcut( seq ); } void PresentWindowsEffect::globalShortcutChangedAll( const QKeySequence& seq ) { shortcutAll = KShortcut( seq ); } void PresentWindowsEffect::globalShortcutChangedClass( const QKeySequence& seq ) { shortcutClass = KShortcut( seq ); } /************************************************ * CloseWindowView ************************************************/ CloseWindowView::CloseWindowView( QWidget* parent ) : QGraphicsView(parent) , m_delayedShowTimer( new QTimer( this )) { setWindowFlags( Qt::X11BypassWindowManagerHint ); setAttribute( Qt::WA_TranslucentBackground ); setFrameShape( QFrame::NoFrame ); QPalette pal = palette(); pal.setColor( backgroundRole(), Qt::transparent ); setPalette( pal ); setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); // setup the scene QGraphicsScene* scene = new QGraphicsScene( this ); m_closeButton = new Plasma::PushButton(); m_closeButton->setIcon( KIcon( "window-close" ) ); scene->addItem( m_closeButton ); connect( m_closeButton, SIGNAL(clicked()), SIGNAL(close())); QGraphicsLinearLayout *layout = new QGraphicsLinearLayout; layout->addItem( m_closeButton ); QGraphicsWidget *form = new QGraphicsWidget; form->setLayout( layout ); form->setGeometry(0, 0, 32, 32); scene->addItem( form ); m_frame = new Plasma::FrameSvg( this ); m_frame->setImagePath( "dialogs/background" ); m_frame->setCacheAllRenderedFrames( true ); m_frame->setEnabledBorders( Plasma::FrameSvg::AllBorders ); qreal left, top, right, bottom; m_frame->getMargins( left, top, right, bottom ); qreal width = form->size().width() + left + right; qreal height = form->size().height() + top + bottom; m_frame->resizeFrame( QSizeF( width, height ) ); Plasma::WindowEffects::enableBlurBehind( winId(), true, m_frame->mask() ); Plasma::WindowEffects::overrideShadow( winId(), true ); form->setPos( left, top ); scene->setSceneRect( QRectF( QPointF( 0, 0 ), QSizeF( width, height ) ) ); setScene( scene ); // setup the timer m_delayedShowTimer->setSingleShot( true ); m_delayedShowTimer->setInterval( 500 ); connect( m_delayedShowTimer, SIGNAL(timeout()), SLOT(show())); } void CloseWindowView::windowInputMouseEvent( QMouseEvent* e ) { if( m_delayedShowTimer->isActive() ) return; if( e->type() == QEvent::MouseMove ) { mouseMoveEvent( e ); } else if( e->type() == QEvent::MouseButtonPress ) { mousePressEvent( e ); } else if( e->type() == QEvent::MouseButtonDblClick ) { mouseDoubleClickEvent( e ); } else if( e->type() == QEvent::MouseButtonRelease ) { mouseReleaseEvent( e ); } } void CloseWindowView::drawBackground( QPainter* painter, const QRectF& rect ) { Q_UNUSED( rect ) painter->setRenderHint( QPainter::Antialiasing ); m_frame->paintFrame( painter ); } void CloseWindowView::hide() { m_delayedShowTimer->stop(); QWidget::hide(); } void CloseWindowView::delayedShow() { if( isVisible() || m_delayedShowTimer->isActive() ) return; m_delayedShowTimer->start(); } } // namespace #include "presentwindows.moc" diff --git a/effects/presentwindows/presentwindows.h b/effects/presentwindows/presentwindows.h index 43ff179b7..43151bd3d 100644 --- a/effects/presentwindows/presentwindows.h +++ b/effects/presentwindows/presentwindows.h @@ -1,271 +1,272 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2007 Rivo Laks Copyright (C) 2008 Lucas Murray 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 . *********************************************************************/ #ifndef KWIN_PRESENTWINDOWS_H #define KWIN_PRESENTWINDOWS_H #include "presentwindows_proxy.h" #include #include #include class QTimer; namespace Plasma { class PushButton; } namespace KWin { class CloseWindowView : public QGraphicsView { Q_OBJECT public: CloseWindowView( QWidget* parent = 0 ); void windowInputMouseEvent( QMouseEvent* e ); virtual void drawBackground( QPainter* painter, const QRectF& rect ); void delayedShow(); void hide(); Q_SIGNALS: void close(); private: Plasma::PushButton* m_closeButton; Plasma::FrameSvg* m_frame; QTimer* m_delayedShowTimer; }; /** * Expose-like effect which shows all windows on current desktop side-by-side, * letting the user select active window. **/ class PresentWindowsEffect : public QObject, public Effect { Q_OBJECT private: // Structures struct WindowData { bool visible; bool deleted; bool referenced; double opacity; double highlight; int slot; int slot_distance; EffectFrame* textFrame; EffectFrame* iconFrame; }; typedef QHash DataHash; struct GridSize { int columns; int rows; }; public: PresentWindowsEffect(); virtual ~PresentWindowsEffect(); virtual void reconfigure( ReconfigureFlags ); virtual void* proxy(); // Screen painting virtual void prePaintScreen( ScreenPrePaintData &data, int time ); virtual void paintScreen( int mask, QRegion region, ScreenPaintData &data ); virtual void postPaintScreen(); // Window painting virtual void prePaintWindow( EffectWindow *w, WindowPrePaintData &data, int time ); virtual void paintWindow( EffectWindow *w, int mask, QRegion region, WindowPaintData &data ); // User interaction virtual void windowAdded( EffectWindow *w ); virtual void windowClosed( EffectWindow *w ); virtual void windowDeleted( EffectWindow *w ); virtual void windowGeometryShapeChanged( EffectWindow* w, const QRect& old ); virtual bool borderActivated( ElectricBorder border ); virtual void windowInputMouseEvent( Window w, QEvent *e ); virtual void grabbedKeyboardEvent( QKeyEvent *e ); // Tab box virtual void tabBoxAdded( int mode ); virtual void tabBoxClosed(); virtual void tabBoxUpdated(); virtual void tabBoxKeyEvent( QKeyEvent* event ); // atoms virtual void propertyNotify( EffectWindow* w, long atom ); enum { LayoutNatural, LayoutRegularGrid, LayoutFlexibleGrid }; // Layout modes enum PresentWindowsMode { ModeAllDesktops, // Shows windows of all desktops ModeCurrentDesktop, // Shows windows on current desktop ModeSelectedDesktop, // Shows windows of selected desktop via property (m_desktop) ModeWindowGroup, // Shows windows selected via property ModeWindowClass // Shows all windows of same class as selected class }; enum WindowMouseAction { WindowNoAction = 0, // Nothing WindowActivateAction = 1, // Activates the window and deactivates the effect WindowExitAction = 2, // Deactivates the effect without activating new window WindowToCurrentDesktopAction = 3, // Brings window to current desktop WindowToAllDesktopsAction = 4, // Brings window to all desktops WindowMinimizeAction = 5, // Minimize the window WindowCloseAction = 6 // Closes the window }; enum DesktopMouseAction { DesktopNoAction = 0, // nothing DesktopActivateAction = 1, // Activates the window and deactivates the effect DesktopExitAction = 2, // Deactivates the effect without activating new window DesktopShowDesktopAction = 3 // Minimizes all windows }; public slots: void setActive( bool active, bool closingTab = false ); // HACK: closingTab shouldn't be needed void toggleActive() { m_mode = ModeCurrentDesktop; setActive( !m_activated ); } void toggleActiveAllDesktops() { m_mode = ModeAllDesktops; setActive( !m_activated ); } void toggleActiveClass(); // slots for global shortcut changed // needed to toggle the effect void globalShortcutChanged( const QKeySequence& seq ); void globalShortcutChangedAll( const QKeySequence& seq ); void globalShortcutChangedClass( const QKeySequence& seq ); private slots: void closeWindow(); protected: // Window rearranging void rearrangeWindows(); void calculateWindowTransformations( EffectWindowList windowlist, int screen, WindowMotionManager& motionManager, bool external = false ); void calculateWindowTransformationsClosest( EffectWindowList windowlist, int screen, WindowMotionManager& motionManager ); void calculateWindowTransformationsKompose( EffectWindowList windowlist, int screen, WindowMotionManager& motionManager ); void calculateWindowTransformationsNatural( EffectWindowList windowlist, int screen, WindowMotionManager& motionManager ); // Helper functions for window rearranging inline double aspectRatio( EffectWindow *w ) { return w->width() / double( w->height() ); } inline int widthForHeight( EffectWindow *w, int height ) { return int(( height / double( w->height() )) * w->width() ); } inline int heightForWidth( EffectWindow *w, int width ) { return int(( width / double( w->width() )) * w->height() ); } void assignSlots( EffectWindowList windowlist, const QRect &area, int columns, int rows ); void getBestAssignments( EffectWindowList windowlist ); bool isOverlappingAny( EffectWindow *w, const QHash &targets, const QRegion &border ); // Filter box void updateFilterFrame(); // Helper functions bool isSelectableWindow( EffectWindow *w ); bool isVisibleWindow( EffectWindow *w ); void setHighlightedWindow( EffectWindow *w ); EffectWindow* relativeWindow( EffectWindow *w, int xdiff, int ydiff, bool wrap ) const; EffectWindow* findFirstWindow() const; void updateCloseWindow(); // Helper functions for mouse actions void mouseActionWindow( WindowMouseAction& action ); void mouseActionDesktop( DesktopMouseAction& action ); private: PresentWindowsEffectProxy m_proxy; friend class PresentWindowsEffectProxy; // User configuration settings QList m_borderActivate; QList m_borderActivateAll; int m_layoutMode; bool m_showCaptions; bool m_showIcons; + bool m_doNotCloseWindows; bool m_tabBoxAllowed; bool m_tabBoxAlternativeAllowed; int m_accuracy; bool m_fillGaps; double m_fadeDuration; bool m_showPanel; // Activation bool m_activated; bool m_ignoreMinimized; double m_decalOpacity; Window m_input; bool m_hasKeyboardGrab; bool m_tabBoxEnabled; PresentWindowsMode m_mode; int m_desktop; EffectWindowList m_selectedWindows; EffectWindow *m_managerWindow; QString m_class; // Window data WindowMotionManager m_motionManager; DataHash m_windowData; EffectWindow *m_highlightedWindow; // Grid layout info QList m_gridSizes; // Filter box EffectFrame* m_filterFrame; QString m_windowFilter; // Shortcut - needed to toggle the effect KShortcut shortcut; KShortcut shortcutAll; KShortcut shortcutClass; // Atoms // Present windows for all windows of given desktop // -1 for all desktops long m_atomDesktop; // Present windows for group of window ids long m_atomWindows; // Mouse Actions WindowMouseAction m_leftButtonWindow; WindowMouseAction m_middleButtonWindow; WindowMouseAction m_rightButtonWindow; DesktopMouseAction m_leftButtonDesktop; DesktopMouseAction m_middleButtonDesktop; DesktopMouseAction m_rightButtonDesktop; CloseWindowView* m_closeView; EffectWindow* m_closeWindow; }; } // namespace #endif diff --git a/effects/presentwindows/presentwindows_config.cpp b/effects/presentwindows/presentwindows_config.cpp index 58e117725..1197f9699 100644 --- a/effects/presentwindows/presentwindows_config.cpp +++ b/effects/presentwindows/presentwindows_config.cpp @@ -1,209 +1,209 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2007 Rivo Laks Copyright (C) 2008 Lucas Murray 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 "presentwindows_config.h" #include #include #include #include #include namespace KWin { KWIN_EFFECT_CONFIG_FACTORY PresentWindowsEffectConfigForm::PresentWindowsEffectConfigForm(QWidget* parent) : QWidget(parent) { setupUi(this); } PresentWindowsEffectConfig::PresentWindowsEffectConfig(QWidget* parent, const QVariantList& args) : KCModule( EffectFactory::componentData(), parent, args ) { m_ui = new PresentWindowsEffectConfigForm( this ); QVBoxLayout* layout = new QVBoxLayout( this ); layout->addWidget( m_ui ); // Shortcut config. The shortcut belongs to the component "kwin"! m_actionCollection = new KActionCollection( this, KComponentData("kwin") ); m_actionCollection->setConfigGroup( "PresentWindows" ); m_actionCollection->setConfigGlobal( true ); KAction* a = (KAction*) m_actionCollection->addAction( "ExposeAll" ); a->setText( i18n( "Toggle Present Windows (All desktops)" )); a->setProperty( "isConfigurationAction", true ); a->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F10 )); KAction* b = (KAction*) m_actionCollection->addAction( "Expose" ); b->setText( i18n( "Toggle Present Windows (Current desktop)" )); b->setProperty( "isConfigurationAction", true ); b->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F9 )); KAction* c = ( KAction* )m_actionCollection->addAction( "ExposeClass" ); c->setText( i18n( "Toggle Present Windows (Window class)" )); c->setProperty( "isConfigurationAction", true ); c->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F7 )); m_ui->shortcutEditor->addCollection( m_actionCollection ); connect( m_ui->layoutCombo, SIGNAL( currentIndexChanged( int )), this, SLOT( changed() )); connect( m_ui->displayTitleBox, SIGNAL( stateChanged( int )), this, SLOT( changed() )); connect( m_ui->displayIconBox, SIGNAL( stateChanged( int )), this, SLOT( changed() )); - connect( m_ui->switchingBox, SIGNAL( stateChanged( int )), this, SLOT( changed() )); + connect( m_ui->allowClosing, SIGNAL( stateChanged( int )), this, SLOT( changed() )); connect( m_ui->ignoreMinimizedBox, SIGNAL( stateChanged( int )), this, SLOT( changed() )); connect( m_ui->showPanelBox, SIGNAL( stateChanged( int )), this, SLOT( changed() )); connect( m_ui->accuracySlider, SIGNAL( valueChanged( int )), this, SLOT( changed() )); connect( m_ui->fillGapsBox, SIGNAL( stateChanged( int )), this, SLOT( changed() )); connect( m_ui->shortcutEditor, SIGNAL( keyChange() ), this, SLOT( changed() )); connect( m_ui->leftButtonWindowCombo, SIGNAL( currentIndexChanged( int )), this, SLOT( changed() )); connect( m_ui->middleButtonWindowCombo, SIGNAL( currentIndexChanged( int )), this, SLOT( changed() )); connect( m_ui->rightButtonWindowCombo, SIGNAL( currentIndexChanged( int )), this, SLOT( changed() )); connect( m_ui->leftButtonDesktopCombo, SIGNAL( currentIndexChanged( int )), this, SLOT( changed() )); connect( m_ui->middleButtonDesktopCombo, SIGNAL( currentIndexChanged( int )), this, SLOT( changed() )); connect( m_ui->rightButtonDesktopCombo, SIGNAL( currentIndexChanged( int )), this, SLOT( changed() )); load(); } PresentWindowsEffectConfig::~PresentWindowsEffectConfig() { // If save() is called undoChanges() has no effect m_ui->shortcutEditor->undoChanges(); } void PresentWindowsEffectConfig::load() { KCModule::load(); KConfigGroup conf = EffectsHandler::effectConfig( "PresentWindows" ); int layoutMode = conf.readEntry( "LayoutMode", int( PresentWindowsEffect::LayoutNatural )); m_ui->layoutCombo->setCurrentIndex( layoutMode ); bool displayTitle = conf.readEntry( "DrawWindowCaptions", true ); m_ui->displayTitleBox->setChecked( displayTitle ); bool displayIcon = conf.readEntry( "DrawWindowIcons", true ); m_ui->displayIconBox->setChecked( displayIcon ); - bool switching = conf.readEntry( "TabBox", false ); - m_ui->switchingBox->setChecked( switching ); + bool allowClosing = conf.readEntry( "AllowClosingWindows", true ); + m_ui->allowClosing->setChecked( allowClosing ); bool ignoreMinimized = conf.readEntry( "IgnoreMinimized", false ); m_ui->ignoreMinimizedBox->setChecked( ignoreMinimized ); bool showPanel = conf.readEntry( "ShowPanel", false ); m_ui->showPanelBox->setChecked( showPanel ); int accuracy = conf.readEntry( "Accuracy", 1 ); m_ui->accuracySlider->setSliderPosition( accuracy ); bool fillGaps = conf.readEntry( "FillGaps", true ); m_ui->fillGapsBox->setChecked( fillGaps ); int leftButtonWindow = conf.readEntry( "LeftButtonWindow", int( PresentWindowsEffect::WindowActivateAction )); m_ui->leftButtonWindowCombo->setCurrentIndex( leftButtonWindow ); int middleButtonWindow = conf.readEntry( "MiddleButtonWindow", int( PresentWindowsEffect::WindowNoAction )); m_ui->middleButtonWindowCombo->setCurrentIndex( middleButtonWindow ); int rightButtonWindow = conf.readEntry( "RightButtonWindow", int( PresentWindowsEffect::WindowExitAction )); m_ui->rightButtonWindowCombo->setCurrentIndex( rightButtonWindow ); int leftButtonDesktop = conf.readEntry( "LeftButtonDesktop", int( PresentWindowsEffect::DesktopExitAction )); m_ui->leftButtonDesktopCombo->setCurrentIndex( leftButtonDesktop ); int middleButtonDesktop = conf.readEntry( "MiddleButtonDesktop", int( PresentWindowsEffect::DesktopNoAction )); m_ui->middleButtonDesktopCombo->setCurrentIndex( middleButtonDesktop ); int rightButtonDesktop = conf.readEntry( "RightButtonDesktop", int( PresentWindowsEffect::DesktopNoAction )); m_ui->rightButtonDesktopCombo->setCurrentIndex( rightButtonDesktop ); emit changed(false); } void PresentWindowsEffectConfig::save() { KCModule::save(); KConfigGroup conf = EffectsHandler::effectConfig( "PresentWindows" ); int layoutMode = m_ui->layoutCombo->currentIndex(); conf.writeEntry( "LayoutMode", layoutMode ); conf.writeEntry( "DrawWindowCaptions", m_ui->displayTitleBox->isChecked() ); conf.writeEntry( "DrawWindowIcons", m_ui->displayIconBox->isChecked() ); - conf.writeEntry( "TabBox", m_ui->switchingBox->isChecked() ); + conf.writeEntry( "AllowClosingWindows", m_ui->allowClosing->isChecked() ); conf.writeEntry( "IgnoreMinimized", m_ui->ignoreMinimizedBox->isChecked() ); conf.writeEntry( "ShowPanel", m_ui->showPanelBox->isChecked() ); int accuracy = m_ui->accuracySlider->value(); conf.writeEntry( "Accuracy", accuracy ); conf.writeEntry( "FillGaps", m_ui->fillGapsBox->isChecked() ); int leftButtonWindow = m_ui->leftButtonWindowCombo->currentIndex(); conf.writeEntry( "LeftButtonWindow", leftButtonWindow ); int middleButtonWindow = m_ui->middleButtonWindowCombo->currentIndex(); conf.writeEntry( "MiddleButtonWindow", middleButtonWindow ); int rightButtonWindow = m_ui->rightButtonWindowCombo->currentIndex(); conf.writeEntry( "RightButtonWindow", rightButtonWindow ); int leftButtonDesktop = m_ui->leftButtonDesktopCombo->currentIndex(); conf.writeEntry( "LeftButtonDesktop", leftButtonDesktop ); int middleButtonDesktop = m_ui->middleButtonDesktopCombo->currentIndex(); conf.writeEntry( "MiddleButtonDesktop", middleButtonDesktop ); int rightButtonDesktop = m_ui->rightButtonDesktopCombo->currentIndex(); conf.writeEntry( "RightButtonDesktop", rightButtonDesktop ); m_ui->shortcutEditor->save(); conf.sync(); emit changed(false); EffectsHandler::sendReloadMessage( "presentwindows" ); } void PresentWindowsEffectConfig::defaults() { m_ui->layoutCombo->setCurrentIndex( int( PresentWindowsEffect::LayoutNatural )); m_ui->displayTitleBox->setChecked( true ); m_ui->displayIconBox->setChecked( true ); - m_ui->switchingBox->setChecked( false ); + m_ui->allowClosing->setChecked( true ); m_ui->ignoreMinimizedBox->setChecked( false ); m_ui->showPanelBox->setChecked( false ); m_ui->accuracySlider->setSliderPosition( 1 ); m_ui->fillGapsBox->setChecked( true ); m_ui->shortcutEditor->allDefault(); m_ui->leftButtonWindowCombo->setCurrentIndex( int( PresentWindowsEffect::WindowActivateAction )); m_ui->middleButtonWindowCombo->setCurrentIndex( int( PresentWindowsEffect::WindowNoAction )); m_ui->rightButtonWindowCombo->setCurrentIndex( int( PresentWindowsEffect::WindowExitAction )); m_ui->leftButtonDesktopCombo->setCurrentIndex( int( PresentWindowsEffect::DesktopExitAction )); m_ui->middleButtonDesktopCombo->setCurrentIndex( int( PresentWindowsEffect::DesktopNoAction )); m_ui->rightButtonDesktopCombo->setCurrentIndex( int( PresentWindowsEffect::DesktopNoAction )); emit changed(true); } } // namespace #include "presentwindows_config.moc" diff --git a/effects/presentwindows/presentwindows_config.ui b/effects/presentwindows/presentwindows_config.ui index c30619efa..d1e027c48 100644 --- a/effects/presentwindows/presentwindows_config.ui +++ b/effects/presentwindows/presentwindows_config.ui @@ -1,494 +1,494 @@ KWin::PresentWindowsEffectConfigForm 0 0 595 441 Activation 0 0 Natural Layout Settings Fill &gaps Qt::Vertical 20 40 Faster 130 0 1 8 1 1 1 true Qt::Horizontal true false QSlider::TicksBelow Nicer Windows Left button: leftButtonWindowCombo No action Activate window End effect Bring window to current desktop Send window to all desktops (Un-)Minimize window Close window Middle button: middleButtonWindowCombo No action Activate window End effect Bring window to current desktop Send window to all desktops (Un-)Minimize window Close window Right button: rightButtonWindowCombo No action Activate window End effect Bring window to current desktop Send window to all desktops (Un-)Minimize window Close window Desktop QFormLayout::ExpandingFieldsGrow Left button: leftButtonDesktopCombo No action Activate window End effect Show desktop Middle button: middleButtonDesktopCombo No action Activate window End effect Show desktop Right button: rightButtonDesktopCombo No action Activate window End effect Show desktop Appearance Layout mode: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter layoutCombo Display window &titles Display window &icons - - - - Use for window &switching - - - Ignore &minimized windows Show &panels 0 0 Natural Regular Grid Flexible Grid + + + + Provide buttons to close the windows + + + + + KComboBox + QComboBox +
kcombobox.h
+
KWin::GlobalShortcutsEditor QWidget
kwineffects.h
1
- - KComboBox - QComboBox -
kcombobox.h
-
layoutCombo displayTitleBox displayIconBox - switchingBox + allowClosing ignoreMinimizedBox accuracySlider fillGapsBox