diff --git a/client.cpp b/client.cpp index ef863af592..5cc8acc4f3 100644 --- a/client.cpp +++ b/client.cpp @@ -858,6 +858,8 @@ void Client::updateVisibility() rawHide(); show = false; } + if( show ) + info->setState( 0, NET::Hidden ); if( !isOnCurrentDesktop()) { setMappingState( IconicState ); @@ -866,7 +868,8 @@ void Client::updateVisibility() } if( show ) { - info->setState( 0, NET::Hidden ); + if( workspace()->showingDesktop()) + workspace()->resetShowingDesktop( true ); if( isShade()) setMappingState( IconicState ); else diff --git a/events.cpp b/events.cpp index 77e72ac6ab..62a899639c 100644 --- a/events.cpp +++ b/events.cpp @@ -90,7 +90,7 @@ void WinInfo::changeState( unsigned long state, unsigned long mask ) // **************************************** RootInfo::RootInfo( Workspace* ws, Display *dpy, Window w, const char *name, unsigned long pr[], int pr_num, int scr ) - : NETRootInfo3( dpy, w, name, pr, pr_num, scr ) + : NETRootInfo4( dpy, w, name, pr, pr_num, scr ) { workspace = ws; } @@ -180,6 +180,11 @@ void RootInfo::gotPing( Window w, Time timestamp ) c->gotPing( timestamp ); } +void RootInfo::changeShowingDesktop( bool showing ) + { + workspace->setShowingDesktop( showing ); + } + // **************************************** // Workspace // **************************************** diff --git a/manage.cpp b/manage.cpp index c742d9b1d6..08d36d3baf 100644 --- a/manage.cpp +++ b/manage.cpp @@ -443,6 +443,9 @@ bool Client::manage( Window w, bool isMapped ) if( !isOnCurrentDesktop() && !isMapped && !session && ( allow || workspace()->sessionSaving())) workspace()->setCurrentDesktop( desktop()); + if( workspace()->showingDesktop()) + workspace()->resetShowingDesktop( false ); + if( isOnCurrentDesktop() && !isMapped && !allow ) workspace()->restackClientUnderActive( this ); else diff --git a/workspace.cpp b/workspace.cpp index 22167d661f..5e5e524090 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -79,6 +79,8 @@ Workspace::Workspace( bool restore ) movingClient(0), pending_take_activity ( NULL ), delayfocus_client (0), + showing_desktop( false ), + block_showing_desktop( 0 ), was_user_interaction (false), session_saving (false), control_grab (false), @@ -281,6 +283,7 @@ void Workspace::init() NET::WM2MoveResizeWindow | NET::WM2ExtendedStrut | NET::WM2KDETemporaryRules | + NET::WM2ShowingDesktop | 0 , NET::ActionMove | @@ -389,6 +392,7 @@ void Workspace::init() desktop_geometry.height = geom.height(); // TODO update also after gaining XRANDR support rootInfo->setDesktopGeometry( -1, desktop_geometry ); + setShowingDesktop( false ); } // end updates blocker block @@ -1082,6 +1086,7 @@ bool Workspace::setCurrentDesktop( int new_desktop ) int old_desktop = current_desktop; if (new_desktop != current_desktop) { + ++block_showing_desktop; /* optimized Desktop switching: unmapping done from back to front mapping done from front to back => less exposure events @@ -1108,6 +1113,10 @@ bool Workspace::setCurrentDesktop( int new_desktop ) for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) if ( (*it)->isOnDesktop( new_desktop ) ) (*it)->updateVisibility(); + + --block_showing_desktop; + if( showingDesktop()) // do this only after desktop change to avoid flicker + resetShowingDesktop( false ); } // restore the focus on this desktop @@ -2482,7 +2491,71 @@ void Workspace::setUnshadowed(unsigned long winId) return; } } - + +void Workspace::setShowingDesktop( bool showing ) + { + rootInfo->setShowingDesktop( showing ); + showing_desktop = showing; + ++block_showing_desktop; + if( showing_desktop ) + { + showing_desktop_clients.clear(); + ++block_focus; + ClientList cls = stackingOrder(); + // find them first, then minimize, otherwise transients may get minimized with the window + // they're transient for + for( ClientList::ConstIterator it = cls.begin(); + it != cls.end(); + ++it ) + { + if( (*it)->isOnCurrentDesktop() && (*it)->isShown( true ) && !(*it)->isSpecialWindow()) + showing_desktop_clients.prepend( *it ); // topmost first to reduce flicker + } + for( ClientList::ConstIterator it = showing_desktop_clients.begin(); + it != showing_desktop_clients.end(); + ++it ) + (*it)->minimize(); + --block_focus; + if( Client* desk = findDesktop( true, currentDesktop())) + requestFocus( desk ); + } + else + { + for( ClientList::ConstIterator it = showing_desktop_clients.begin(); + it != showing_desktop_clients.end(); + ++it ) + (*it)->unminimize(); + if( showing_desktop_clients.count() > 0 ) + requestFocus( showing_desktop_clients.first()); + showing_desktop_clients.clear(); + } + --block_showing_desktop; + } + +// Following Kicker's behavior: +// Changing a virtual desktop resets the state and shows the windows again. +// Unminimizing a window resets the state but keeps the windows hidden (except +// the one that was unminimized). +// A new window resets the state and shows the windows again, with the new window +// being active. +void Workspace::resetShowingDesktop( bool keep_hidden ) + { + if( block_showing_desktop > 0 ) + return; + rootInfo->setShowingDesktop( false ); + showing_desktop = false; + ++block_showing_desktop; + if( !keep_hidden ) + { + for( ClientList::ConstIterator it = showing_desktop_clients.begin(); + it != showing_desktop_clients.end(); + ++it ) + (*it)->unminimize(); + } + showing_desktop_clients.clear(); + --block_showing_desktop; + } + } // namespace #include "workspace.moc" diff --git a/workspace.h b/workspace.h index b436ea59b3..31cb936ec2 100644 --- a/workspace.h +++ b/workspace.h @@ -223,6 +223,9 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine QString desktopName( int desk ) const; void setDesktopLayout(int o, int x, int y); + void setShowingDesktop( bool showing ); + void resetShowingDesktop( bool keep_hidden ); + bool showingDesktop() const; bool isNotManaged( const QString& title ); // ### setter or getter ? @@ -501,6 +504,10 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine ClientList focus_chain; ClientList should_get_focus; // last is most recent ClientList attention_chain; + + bool showing_desktop; + ClientList showing_desktop_clients; + int block_showing_desktop; GroupList groups; @@ -624,7 +631,7 @@ class StackingUpdatesBlocker }; // NET WM Protocol handler class -class RootInfo : public NETRootInfo3 +class RootInfo : public NETRootInfo4 { private: typedef KWinInternal::Client Client; // because of NET::Client @@ -641,6 +648,7 @@ class RootInfo : public NETRootInfo3 virtual void gotPing(Window w, Time timestamp); virtual void restackWindow(Window w, RequestSource source, Window above, int detail, Time timestamp); virtual void gotTakeActivity(Window w, Time timestamp, long flags ); + virtual void changeShowingDesktop( bool showing ); private: Workspace* workspace; }; @@ -740,6 +748,11 @@ inline bool Workspace::forcedGlobalMouseGrab() const return forced_global_mouse_grab; } +inline bool Workspace::showingDesktop() const + { + return showing_desktop; + } + template< typename T > inline Client* Workspace::findClient( T predicate ) {