diff --git a/effects.cpp b/effects.cpp index 9eca6d30ca..fa59878734 100644 --- a/effects.cpp +++ b/effects.cpp @@ -96,6 +96,18 @@ void Effect::windowGeometryShapeChanged( EffectWindow*, const QRect& ) { } +void Effect::tabBoxAdded( int ) + { + } + +void Effect::tabBoxClosed() + { + } + +void Effect::tabBoxUpdated() + { + } + void Effect::prePaintScreen( int* mask, QRegion* region, int time ) { effects->prePaintScreen( mask, region, time ); @@ -259,6 +271,8 @@ void EffectsHandler::desktopChanged( int old ) void EffectsHandler::windowDamaged( EffectWindow* w, const QRect& r ) { + if( w == NULL ) + return; foreach( EffectPair ep, loaded_effects ) ep.second->windowDamaged( w, r ); } @@ -271,6 +285,24 @@ void EffectsHandler::windowGeometryShapeChanged( EffectWindow* w, const QRect& o ep.second->windowGeometryShapeChanged( w, old ); } +void EffectsHandler::tabBoxAdded( int mode ) + { + foreach( EffectPair ep, loaded_effects ) + ep.second->tabBoxAdded( mode ); + } + +void EffectsHandler::tabBoxClosed() + { + foreach( EffectPair ep, loaded_effects ) + ep.second->tabBoxClosed(); + } + +void EffectsHandler::tabBoxUpdated() + { + foreach( EffectPair ep, loaded_effects ) + ep.second->tabBoxUpdated(); + } + // start another painting pass void EffectsHandler::startPaint() { diff --git a/effects.h b/effects.h index 3b3bb3a50d..a6f20f376d 100644 --- a/effects.h +++ b/effects.h @@ -88,6 +88,9 @@ class Effect virtual void desktopChanged( int old ); virtual void windowDamaged( EffectWindow* w, const QRect& r ); virtual void windowGeometryShapeChanged( EffectWindow* w, const QRect& old ); + virtual void tabBoxAdded( int mode ); + virtual void tabBoxClosed(); + virtual void tabBoxUpdated(); // Interpolates between x and y static float interpolate(float x, float y, float a) @@ -161,6 +164,9 @@ class EffectsHandler void desktopChanged( int old ); void windowDamaged( EffectWindow* w, const QRect& r ); void windowGeometryShapeChanged( EffectWindow* w, const QRect& old ); + void tabBoxAdded( int mode ); + void tabBoxClosed(); + void tabBoxUpdated(); void registerEffect( const QString& name, EffectFactory* factory ); void loadEffect( const QString& name ); diff --git a/tabbox.cpp b/tabbox.cpp index a9ca1b3e49..f9e97d9539 100644 --- a/tabbox.cpp +++ b/tabbox.cpp @@ -12,6 +12,7 @@ License. See the file "COPYING" for the exact licensing terms. //#define QT_CLEAN_NAMESPACE #include "tabbox.h" #include "workspace.h" +#include "effects.h" #include "client.h" #include #include @@ -46,6 +47,7 @@ TabBox::TabBox( Workspace *ws ) : QFrame( 0, Qt::X11BypassWindowManagerHint ) , client(0) , wspace(ws) + , display_refcount( 0 ) { setFrameStyle(QFrame::StyledPanel | QFrame::Plain); setLineWidth(2); @@ -156,16 +158,18 @@ void TabBox::reset( bool partial_reset ) // get all clients to show createClientList(clients, options_traverse_all ? -1 : workspace()->currentDesktop(), starting_client, true); + displayed_clients = clients; + // calculate maximum caption width cw = fontMetrics().width(no_tasks)+20; - for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) + for (ClientList::ConstIterator it = displayed_clients.begin(); it != displayed_clients.end(); ++it) { cw = fontMetrics().width( (*it)->caption() ); if ( cw > wmax ) wmax = cw; } // calculate height for the popup - if ( clients.count() == 0 ) // height for the "not tasks" text + if ( displayed_clients.count() == 0 ) // height for the "not tasks" text { QFont f = font(); f.setBold( true ); @@ -176,7 +180,7 @@ void TabBox::reset( bool partial_reset ) else { showMiniIcon = false; - h = clients.count() * lineHeight; + h = displayed_clients.count() * lineHeight; if ( h > (r.height()-(2*frameWidth())) ) // if too high, use mini icons { @@ -184,16 +188,16 @@ void TabBox::reset( bool partial_reset ) // fontheight + 1 pixel above + 1 pixel below, or 16x16 icon + 1 pixel above + below lineHeight = qMax(fontMetrics().height() + 2, 16 + 2); - h = clients.count() * lineHeight; + h = displayed_clients.count() * lineHeight; if ( h > (r.height()-(2*frameWidth())) ) // if still too high, remove some clients { // how many clients to remove int howMany = (h - (r.height()-(2*frameWidth())))/lineHeight; for (; howMany; howMany--) - clients.removeAll(clients.last()); + displayed_clients.removeAll(displayed_clients.last()); - h = clients.count() * lineHeight; + h = displayed_clients.count() * lineHeight; } } } @@ -221,6 +225,9 @@ void TabBox::reset( bool partial_reset ) setGeometry( (r.width()-w)/2 + r.x(), (r.height()-h)/2+ r.y(), w, h ); + + if( effects ) + effects->tabBoxUpdated(); } @@ -275,6 +282,8 @@ void TabBox::nextPrev( bool next) } } + if( effects ) + effects->tabBoxUpdated(); update(); } @@ -293,6 +302,19 @@ Client* TabBox::currentClient() return client; } +/*! + Returns the list of clients potentially displayed ( only works in + WindowsMode ). + Returns an empty list if no clients are available. + */ +ClientList TabBox::currentClientList() + { + if( mode() != WindowsMode ) + return ClientList(); + return clients; + } + + /*! Returns the currently displayed virtual desktop ( only works in DesktopListMode ) @@ -352,7 +374,7 @@ void TabBox::paintEvent( QPaintEvent* e ) } else { - for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) + for (ClientList::ConstIterator it = displayed_clients.begin(); it != displayed_clients.end(); ++it) { if ( workspace()->hasClient( *it ) ) // safety { @@ -508,6 +530,17 @@ void TabBox::paintEvent( QPaintEvent* e ) } } +void TabBox::show() + { + if( display_refcount > 0 ) + return; + display_refcount = 0; + if( effects ) + effects->tabBoxAdded( mode()); + if( display_refcount == 0 ) // no effects have claimed TabBox + QWidget::show(); + } + void TabBox::hide() { delayedShowTimer.stop(); @@ -519,6 +552,16 @@ void TabBox::hide() } +/*! + Reduce the reference count, eventually closing the tabbox. + */ +void TabBox::unrefTabBox() + { + if( --display_refcount > 0 ) + return; + workspace()->closeTabBox(); + } + void TabBox::reconfigure() { KSharedConfigPtr c(KGlobal::config()); @@ -564,12 +607,18 @@ void TabBox::delayedShow() void TabBox::handleMouseEvent( XEvent* e ) { XAllowEvents( display(), AsyncPointer, xTime() ); + if( display_refcount > 0 ) // tabbox has been replaced, check effects + { + if( effects && !effects->checkInputWindowEvent( e ) && e->type == ButtonPress ) + unrefTabBox(); + return; + } if( e->type != ButtonPress ) return; QPoint pos( e->xbutton.x_root, e->xbutton.y_root ); if( !geometry().contains( pos )) { - workspace()->closeTabBox(); // click outside closes tab + unrefTabBox(); // click outside closes tab return; } pos.rx() -= x(); // pos is now inside tabbox @@ -578,8 +627,8 @@ void TabBox::handleMouseEvent( XEvent* e ) if( mode() == WindowsMode ) { - for( ClientList::ConstIterator it = clients.begin(); - it != clients.end(); + for( ClientList::ConstIterator it = displayed_clients.begin(); + it != displayed_clients.end(); ++it) { if( workspace()->hasClient( *it ) && (num == 0) ) // safety @@ -1048,15 +1097,29 @@ void Workspace::tabBoxKeyPress( int keyQt ) if ( ((keyQt & ~Qt::KeyboardModifierMask) == Qt::Key_Escape) && !(forward || backward) ) { // if Escape is part of the shortcut, don't cancel - closeTabBox(); + unrefTabBox(); } } } +void Workspace::refTabBox() + { + if( tab_box ) + tab_box->refTabBox(); + } + +void Workspace::unrefTabBox() + { + if( tab_box ) + tab_box->unrefTabBox(); + } + void Workspace::closeTabBox() { removeTabBoxGrab(); tab_box->hide(); + if( effects ) + effects->tabBoxClosed(); keys->setEnabled( true ); disable_shortcuts_keys->setEnabled( true ); client_keys->setEnabled( true ); @@ -1104,12 +1167,9 @@ void Workspace::tabBoxKeyRelease( const XKeyEvent& ev ) return; if (tab_grab) { - removeTabBoxGrab(); - tab_box->hide(); - keys->setEnabled( true ); - disable_shortcuts_keys->setEnabled( true ); - client_keys->setEnabled( true ); - tab_grab = false; + bool old_control_grab = control_grab; + unrefTabBox(); + control_grab = old_control_grab; if( Client* c = tab_box->currentClient()) { activateClient( c ); @@ -1119,12 +1179,9 @@ void Workspace::tabBoxKeyRelease( const XKeyEvent& ev ) } if (control_grab) { - removeTabBoxGrab(); - tab_box->hide(); - keys->setEnabled( true ); - disable_shortcuts_keys->setEnabled( true ); - client_keys->setEnabled( true ); - control_grab = False; + bool old_tab_grab = tab_grab; + unrefTabBox(); + tab_grab = old_tab_grab; if ( tab_box->currentDesktop() != -1 ) { setCurrentDesktop( tab_box->currentDesktop() ); @@ -1222,6 +1279,27 @@ Client* Workspace::previousStaticClient( Client* c ) const return clients[ pos ]; } +Client* Workspace::currentTabBoxClient() const + { + if( !tab_box ) + return 0; + return tab_box->currentClient(); + } + +ClientList Workspace::currentTabBoxClientList() const + { + if( !tab_box ) + return ClientList(); + return tab_box->currentClientList(); + } + +int Workspace::currentTabBoxDesktop() const + { + if( !tab_box ) + return -1; + return tab_box->currentDesktop(); + } + bool Workspace::establishTabBoxGrab() { if( XGrabKeyboard( display(), root, false, diff --git a/tabbox.h b/tabbox.h index f79374d881..8e78540632 100644 --- a/tabbox.h +++ b/tabbox.h @@ -32,6 +32,7 @@ class TabBox : public QFrame ~TabBox(); Client* currentClient(); + ClientList currentClientList(); int currentDesktop(); // DesktopMode and WindowsMode are based on the order in which the desktop @@ -47,6 +48,9 @@ class TabBox : public QFrame void delayedShow(); void hide(); + void refTabBox(); + void unrefTabBox(); + void handleMouseEvent( XEvent* ); Workspace* workspace() const; @@ -54,6 +58,9 @@ class TabBox : public QFrame void reconfigure(); void updateKeyMapping(); + public slots: + void show(); + protected: void showEvent( QShowEvent* ); void hideEvent( QHideEvent* ); @@ -66,13 +73,14 @@ class TabBox : public QFrame Client* client; Mode m; Workspace* wspace; - ClientList clients; + ClientList clients, displayed_clients; int desk; int lineHeight; bool showMiniIcon; QTimer delayedShowTimer; QString no_tasks; bool options_traverse_all; + int display_refcount; }; @@ -94,6 +102,14 @@ inline TabBox::Mode TabBox::mode() const return m; } +/*! + Increase the reference count, preventing the default tabbox from showing. + */ +inline void TabBox::refTabBox() + { + ++display_refcount; + } + } // namespace #endif diff --git a/workspace.h b/workspace.h index d52e3f2116..31fe48290e 100644 --- a/workspace.h +++ b/workspace.h @@ -18,6 +18,8 @@ License. See the file "COPYING" for the exact licensing terms. #include #include #include +#include +#include #include "utils.h" #include "kdecoration.h" @@ -77,7 +79,7 @@ class Workspace : public QObject, public KDecorationDefines virtual ~Workspace(); static Workspace * self() { return _self; } - + bool workspaceEvent( XEvent * ); KDecoration* createDecoration( KDecorationBridge* bridge ); @@ -87,6 +89,9 @@ class Workspace : public QObject, public KDecorationDefines template< typename T > Client* findClient( T predicate ); template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate ); template< typename T > void forEachClient( T procedure ); + template< typename T > Unmanaged* findUnmanaged( T predicate ); + template< typename T1, typename T2 > void forEachUnmanaged( T1 procedure, T2 predicate ); + template< typename T > void forEachUnmanaged( T procedure ); QRect clientArea( clientAreaOption, const QPoint& p, int desktop ) const; QRect clientArea( clientAreaOption, const Client* c ) const; @@ -165,12 +170,17 @@ class Workspace : public QObject, public KDecorationDefines QWidget* desktopWidget(); // for TabBox + Client* currentTabBoxClient() const; + ClientList currentTabBoxClientList() const; + int currentTabBoxDesktop() const; Client* nextFocusChainClient(Client*) const; Client* previousFocusChainClient(Client*) const; Client* nextStaticClient(Client*) const; Client* previousStaticClient(Client*) const; int nextDesktopFocusChain( int iDesktop ) const; int previousDesktopFocusChain( int iDesktop ) const; + void refTabBox(); + void unrefTabBox(); void closeTabBox(); /** @@ -181,7 +191,7 @@ class Workspace : public QObject, public KDecorationDefines ClientList ensureStackingOrder( const ClientList& clients ) const; - Client* topClientOnDesktop( int desktop, bool unconstrained = false, bool only_normal = true ) const; + Client* topClientOnDesktop( int desktop, bool unconstrained = false ) const; Client* findDesktop( bool topmost, int desktop ) const; void sendClientToDesktop( Client* c, int desktop, bool dont_activate ); void windowToPreviousDesktop( Client* c ); @@ -190,6 +200,10 @@ class Workspace : public QObject, public KDecorationDefines // KDE4 remove me - and it's also in the DCOP interface :( void showWindowMenuAt( unsigned long id, int x, int y ); + void loadEffect( const QString& name ); + + void unloadEffect( const QString& name ); + /** * Shows the menu operations menu for the client and makes it active if * it's not already. @@ -224,7 +238,7 @@ class Workspace : public QObject, public KDecorationDefines void circulateDesktopApplications(); QString desktopName( int desk ) const; - void setDesktopLayout(NET::Orientation o, int x, int y, NET::DesktopLayoutCorner c); + void setDesktopLayout(int o, int x, int y); void setShowingDesktop( bool showing ); void resetShowingDesktop( bool keep_hidden ); bool showingDesktop() const; @@ -234,14 +248,17 @@ class Workspace : public QObject, public KDecorationDefines void sendPingToWindow( Window w, Time timestamp ); // called from Client::pingWindow() void sendTakeActivity( Client* c, Time timestamp, long flags ); // called from Client::takeActivity() - // only called from Client::destroyClient() or Client::releaseWindow() - void removeClient( Client*, allowed_t ); + void removeClient( Client*, allowed_t ); // only called from Client::destroyClient() or Client::releaseWindow() void setActiveClient( Client*, allowed_t ); Group* findGroup( Window leader ) const; void addGroup( Group* group, allowed_t ); void removeGroup( Group* group, allowed_t ); Group* findClientLeaderGroup( const Client* c ) const; + void removeUnmanaged( Unmanaged*, allowed_t ); // only called from Unmanaged::release() + void removeDeleted( Deleted*, allowed_t ); + void addDeleted( Deleted*, allowed_t ); + bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data ); void focusToNull(); // SELI public? @@ -276,6 +293,17 @@ class Workspace : public QObject, public KDecorationDefines void requestDelayFocus( Client* ); void toggleTopDockShadows(bool on); + + void addRepaint( const QRect& r ); + void addRepaint( int x, int y, int w, int h ); + void addRepaintFull(); + // creates XComposite overlay window, call initOverlay() afterwards + bool createOverlay(); + // init overlay and the destination window in it + void setupOverlay( Window window ); + // destroys XComposite overlay window + void destroyOverlay(); + Window overlayWindow(); public slots: void refresh(); @@ -406,15 +434,14 @@ class Workspace : public QObject, public KDecorationDefines void cleanupTemporaryRules(); void writeWindowRules(); void slotBlockShortcuts(int data); - void slotReloadConfig(); - // kompmgr - void setPopupClientOpacity(int v); - void resetClientOpacity(); - void setTransButtonText(int value); - // end + void setPopupClientOpacity( QAction* action ); + void setupCompositing(); + void performCompositing(); + void lostCMSelection(); protected: bool keyPressMouseEmulation( XKeyEvent& ev ); + bool netCheck( XEvent* e ); private: void init(); @@ -458,6 +485,8 @@ class Workspace : public QObject, public KDecorationDefines // this is the right way to create a new client Client* createClient( Window w, bool is_mapped ); void addClient( Client* c, allowed_t ); + Unmanaged* createUnmanaged( Window w ); + void addUnmanaged( Unmanaged* c, allowed_t ); Window findSpecialEventWindow( XEvent* e ); @@ -499,6 +528,9 @@ class Workspace : public QObject, public KDecorationDefines void closeActivePopup(); void updateClientArea( bool force ); + + void finishCompositing(); + bool windowRepaintsPending() const; SystemTrayWindowList systemTrayWins; @@ -535,10 +567,12 @@ class Workspace : public QObject, public KDecorationDefines ClientList clients; ClientList desktops; + UnmanagedList unmanaged; + DeletedList deleted; - ClientList unconstrained_stacking_order; // topmost last - ClientList stacking_order; // topmost last - QVector< ClientList > focus_chain; // currently ative last + ClientList unconstrained_stacking_order; + ClientList stacking_order; + QVector< ClientList > focus_chain; ClientList global_focus_chain; // this one is only for things like tabbox's MRU ClientList should_get_focus; // last is most recent ClientList attention_chain; @@ -572,6 +606,7 @@ class Workspace : public QObject, public KDecorationDefines QMenu *popup; QMenu *advanced_popup; + QMenu *trans_popup; QMenu *desk_popup; int desk_popup_index; @@ -655,12 +690,14 @@ class Workspace : public QObject, public KDecorationDefines bool forced_global_mouse_grab; friend class StackingUpdatesBlocker; - //kompmgr + KSelectionOwner* cm_selection; + QTimer compositeTimer; + QTime lastCompositePaint; + int compositeRate; + QRegion repaints_region; + Window overlay; // XComposite overlay window QSlider *transSlider; QPushButton *transButton; - - private: - friend bool performTransiencyCheck(); }; // helper for Workspace::blockStackingUpdates() being called in pairs (true/false) @@ -803,6 +840,11 @@ inline bool Workspace::globalShortcutsDisabled() const return global_shortcuts_disabled || global_shortcuts_disabled_for_client; } +inline Window Workspace::overlayWindow() + { + return overlay; + } + template< typename T > inline Client* Workspace::findClient( T predicate ) { @@ -830,7 +872,27 @@ inline void Workspace::forEachClient( T procedure ) return forEachClient( procedure, TruePredicate()); } -KWIN_COMPARE_PREDICATE( ClientMatchPredicate, const Client*, cl == value ); +template< typename T > +inline Unmanaged* Workspace::findUnmanaged( T predicate ) + { + return findUnmanagedInList( unmanaged, predicate ); + } + +template< typename T1, typename T2 > +inline void Workspace::forEachUnmanaged( T1 procedure, T2 predicate ) + { + for ( UnmanagedList::ConstIterator it = unmanaged.begin(); it != unmanaged.end(); ++it) + if ( predicate( const_cast< const Unmanaged* >( *it))) + procedure( *it ); + } + +template< typename T > +inline void Workspace::forEachUnmanaged( T procedure ) + { + return forEachUnmanaged( procedure, TruePredicate()); + } + +KWIN_COMPARE_PREDICATE( ClientMatchPredicate, Client, const Client*, cl == value ); inline bool Workspace::hasClient( const Client* c ) { return findClient( ClientMatchPredicate( c ));