gracefully handle more than one desktop client application (which

happens triggered by a kdesktop bug on David Faure's machine).

You can now launch additional desktop applications with

     kstart --type Desktop konqueror
or
     kstart --type Desktop konsole

and toggle between them with

    dcop kwin default circulateDesktopApplications

svn path=/trunk/kdebase/kwin/; revision=140330
This commit is contained in:
Matthias Ettrich 2002-03-02 21:03:49 +00:00
parent f10a38655b
commit 83f58ed248
6 changed files with 115 additions and 112 deletions

View file

@ -21,6 +21,7 @@ class KWinInterface : virtual public DCOPObject
virtual int currentDesktop() const = 0;
virtual void nextDesktop() = 0;
virtual void previousDesktop() = 0;
virtual void circulateDesktopApplications() = 0;
};
#endif

View file

@ -494,8 +494,7 @@ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags
NET::WMWindowType |
NET::WMStrut |
NET::WMName |
NET::WMIconGeometry |
NET::WMPid
NET::WMIconGeometry
;
info = new WinInfo( this, qt_xdisplay(), win, qt_xrootwin(), properties );
@ -635,6 +634,13 @@ bool Client::manage( bool isMapped, bool doNotShow, bool isInitial )
may_move = FALSE; // don't let fullscreen windows be moved around
}
if ( isDesktop() ) {
// desktops are treated slightly special
geom = workspace()->geometry();
may_move = FALSE;
isMapped = TRUE;
}
if ( isMapped || session || isTransient() ) {
placementDone = TRUE;
} else {
@ -1117,10 +1123,9 @@ void Client::withdraw()
Events::raise( isTransient() ? Events::TransDelete : Events::Delete );
// remove early from client list
workspace()->removeClient( this );
setMappingState( WithdrawnState );
info->setDesktop( 0 );
desk = 0;
releaseWindow();
releaseWindow(TRUE);
workspace()->destroyClient( this );
}
@ -1132,6 +1137,12 @@ bool Client::configureRequest( XConfigureRequestEvent& e )
if ( isResize() )
return TRUE; // we have better things to do right now
if ( isDesktop() ) {
setGeometry( workspace()->geometry() );
sendSyntheticConfigureNotify();
return TRUE;
}
if ( isShade() )
setShade( FALSE );
@ -1833,12 +1844,19 @@ void Client::paintEvent( QPaintEvent * )
/*!
Releases the window. The client has done its job and the window is still existing.
If withdraw is TRUE, the function also sets the mapping state of the
window to WithdrawnState
*/
void Client::releaseWindow()
void Client::releaseWindow( bool withdraw )
{
if ( win ) {
move(gravitate(TRUE));
if ( withdraw )
XUnmapWindow( qt_xdisplay(), win );
windowWrapper()->releaseWindow();
if ( withdraw )
setMappingState( WithdrawnState );
win = 0;
}
}

View file

@ -80,7 +80,7 @@ public:
WId window() const;
WindowWrapper* windowWrapper() const;
Workspace* workspace() const;
void releaseWindow();
void releaseWindow( bool withdraw = FALSE );
void invalidateWindow();
WId transientFor() const;
bool isTransient() const;

View file

@ -260,7 +260,7 @@ int kdemain( int argc, char * argv[] )
signal(SIGHUP, SIG_IGN);
Application a;
KCrash::setCrashHandler(crashHandler); // Try to restart on crash
// KCrash::setCrashHandler(crashHandler); // Try to restart on crash
fcntl(ConnectionNumber(qt_xdisplay()), F_SETFD, 1);
QCString appname;

View file

@ -225,7 +225,6 @@ Client* Workspace::clientFactory( WId w )
XLowerWindow( qt_xdisplay(), w );
Client * c = new NoBorderClient( this, w);
c->setSticky( TRUE );
setDesktopClient( c );
return c;
}
@ -268,7 +267,6 @@ Workspace::Workspace( bool restore )
current_desktop (0),
number_of_desktops(0),
desktop_widget (0),
desktop_client (0),
active_client (0),
last_active_client (0),
should_get_focus (0),
@ -436,15 +434,9 @@ void Workspace::init()
if ( addSystemTrayWin( wins[i] ) )
continue;
Client* c = clientFactory( wins[i] );
if ( c != desktop_client ) {
clients.append( c );
stacking_order.append( c );
}
if ( c->wantsTabFocus() )
focus_chain.append( c );
addClient( c );
c->manage( TRUE );
if ( c == desktop_client )
setDesktopClient( c );
if ( root != qt_xrootwin() ) {
// TODO may use QWidget:.create
XReparentWindow( qt_xdisplay(), c->winId(), root, 0, 0 );
@ -471,9 +463,9 @@ void Workspace::init()
Workspace::~Workspace()
{
if ( desktop_client ) {
WId win = desktop_client->window();
delete desktop_client;
for ( ClientList::ConstIterator it = desktops.fromLast(); it != desktops.end(); --it) {
WId win = (*it)->window();
delete (*it);
XMapWindow( qt_xdisplay(), win );
XLowerWindow( qt_xdisplay(), win );
}
@ -591,7 +583,7 @@ bool Workspace::workspaceEvent( XEvent * e )
checkStartOnDesktop( e->xmaprequest.window );
c = findClient( e->xmaprequest.window );
if ( !c ) {
if ( e->xmaprequest.parent ) { // == root ) { //###TODO store rpeviously destroyed client ids
if ( e->xmaprequest.parent ) { // == root ) { //###TODO store previously destroyed client ids
if ( addSystemTrayWin( e->xmaprequest.window ) )
return TRUE;
c = clientFactory( e->xmaprequest.window );
@ -599,19 +591,11 @@ bool Workspace::workspaceEvent( XEvent * e )
// TODO may use QWidget:.create
XReparentWindow( qt_xdisplay(), c->winId(), root, 0, 0 );
}
if ( c != desktop_client ) {
if ( c->wantsTabFocus() )
focus_chain.append( c );
clients.append( c );
stacking_order.append( c );
}
addClient( c );
}
}
if ( c ) {
bool result = c->windowEvent( e );
if ( c == desktop_client )
setDesktopClient( c );
return result;
return c->windowEvent( e );
}
break;
case EnterNotify:
@ -702,8 +686,10 @@ Client* Workspace::findClient( WId w ) const
if ( (*it)->window() == w )
return *it;
}
if ( desktop_client && w == desktop_client->window() )
return desktop_client;
for ( ClientList::ConstIterator it = desktops.begin(); it != desktops.end(); ++it) {
if ( (*it)->window() == w )
return *it;
}
return 0;
}
@ -763,8 +749,8 @@ bool Workspace::destroyClient( Client* c)
c->invalidateWindow();
clientHidden( c );
if ( c == desktop_client )
desktop_client = 0;
if ( desktops.contains(c) )
desktops.remove(c);
if ( c == most_recently_raised )
most_recently_raised = 0;
if ( c == should_get_focus )
@ -1225,6 +1211,45 @@ int Workspace::previousDesktop( int iDesktop ) const
return numberOfDesktops();
}
void Workspace::circulateDesktopApplications()
{
if ( desktops.count() <= 1 )
return;
Client* first = desktops.first();
desktops.remove( first );
desktops.append( first );
Window* new_stack = new Window[ desktops.count() + 1 ];
int i = 0;
for ( ClientList::ConstIterator it = desktops.fromLast(); it != desktops.end(); --it)
new_stack[i++] = (*it)->winId();
XRestackWindows(qt_xdisplay(), new_stack, i);
delete [] new_stack;
}
void Workspace::addClient( Client* c )
{
if ( c->isDesktop() ) {
if ( !desktops.isEmpty() ) {
Client* first = desktops.first();
Window stack[2];
stack[0] = first->winId();
stack[1] = c->winId();
XRestackWindows( qt_xdisplay(), stack, 2 );
desktops.prepend( c );
circulateDesktopApplications();
} else {
c->lower();
desktops.append( c );
}
} else {
if ( c->wantsTabFocus() )
focus_chain.append( c );
clients.append( c );
stacking_order.append( c );
}
}
/*!
auxiliary functions to travers all clients according the focus
order. Useful for kwm´s Alt-tab feature.
@ -1356,9 +1381,9 @@ void Workspace::setActiveClient( Client* c )
break;
}
}
if ( !menubar && desktop_client ) {
if ( !menubar && !desktops.isEmpty() ) {
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
if ( (*it)->isMenu() && (*it)->mainClient() == desktop_client ) {
if ( (*it)->isMenu() && (*it)->mainClient()->isDesktop() ) {
menubar = *it;
break;
}
@ -1542,14 +1567,15 @@ void Workspace::clientHidden( Client* c )
}
}
}
if ( desktop_client )
requestFocus( desktop_client );
else
focusToNull();
} // if blocking focus, move focus to desktop_client later if needed
// in order to avoid flickering
else
focusToNull();
if ( !c->isDesktop() && !desktops.isEmpty() )
requestFocus( desktops.last() );
else
focusToNull();
} else {
// if blocking focus, move focus to the desktop later if needed
// in order to avoid flickering
focusToNull();
}
}
@ -1759,7 +1785,7 @@ void Workspace::smartPlacement(Client* c){
cyt = y; cyb = y + ch;
QValueList<Client*>::ConstIterator l;
for(l = clients.begin(); l != clients.end() ; ++l ) {
if((*l)->isOnDesktop(desktop) && (*l) != desktop_client &&
if((*l)->isOnDesktop(desktop) &&
!(*l)->isIconified() && (*l) != c ) {
xl = (*l)->x(); yt = (*l)->y();
@ -1807,7 +1833,7 @@ void Workspace::smartPlacement(Client* c){
QValueList<Client*>::ConstIterator l;
for(l = clients.begin(); l != clients.end() ; ++l) {
if ( (*l)->isOnDesktop(desktop) && (*l) != desktop_client &&
if ( (*l)->isOnDesktop(desktop) &&
!(*l)->isIconified() && (*l) != c ) {
xl = (*l)->x(); yt = (*l)->y();
@ -1837,7 +1863,7 @@ void Workspace::smartPlacement(Client* c){
//test the position of each window on the desk
QValueList<Client*>::ConstIterator l;
for( l = clients.begin(); l != clients.end() ; ++l ) {
if( (*l)->isOnDesktop(desktop) && (*l) != desktop_client &&
if( (*l)->isOnDesktop(desktop) &&
(*l) != c && !c->isIconified() ) {
xl = (*l)->x(); yt = (*l)->y();
@ -2052,7 +2078,7 @@ void Workspace::lowerClient( Client* c )
if ( !c )
return;
if ( c == desktop_client )
if ( c->isDesktop() )
return; // deny
ClientList saveset;
@ -2070,7 +2096,7 @@ void Workspace::lowerClient( Client* c )
saveset.append( t );
t = tmp;
}
if ( t && !saveset.contains( t ) && t != desktop_client ) {
if ( t && !saveset.contains( t ) ) {
lowerClient( t );
return;
}
@ -2085,9 +2111,8 @@ void Workspace::lowerClient( Client* c )
stacking_order = constrainedStackingOrder( stacking_order );
Window* new_stack = new Window[ stacking_order.count() + 1 ];
int i = 0;
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
new_stack[i++] = (*it)->winId();
}
XRestackWindows(qt_xdisplay(), new_stack, i);
delete [] new_stack;
@ -2110,7 +2135,7 @@ void Workspace::raiseClient( Client* c )
ClientList saveset;
if ( c == desktop_client ) {
if ( c->isDesktop() ) {
saveset.clear();
saveset.append( c );
raiseTransientsOf(saveset, c );
@ -2133,7 +2158,7 @@ void Workspace::raiseClient( Client* c )
saveset.append( t );
t = tmp;
}
if ( t && !saveset.contains( t ) && t != desktop_client ) {
if ( t && !saveset.contains( t ) ) {
raiseClient( t );
most_recently_raised = c;
return;
@ -2171,9 +2196,8 @@ void Workspace::raiseClient( Client* c )
Window* new_stack = new Window[ stacking_order.count() + 1 ];
int i = 0;
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
new_stack[i++] = (*it)->winId();
}
XRestackWindows(qt_xdisplay(), new_stack, i);
delete [] new_stack;
@ -2300,43 +2324,15 @@ void Workspace::focusToNull(){
}
/*!
Declares client \a c to be the desktop.
*/
void Workspace::setDesktopClient( Client* c)
{
desktop_client = c;
if ( desktop_client ) {
desktop_client->lower();
desktop_client->setGeometry( geometry() );
}
}
/*!
Refreshes all the client windows
*/
void Workspace::refresh() {
/* This idea/code is borrowed from FVWM 2.x */
XSetWindowAttributes attributes;
unsigned long valuemask = CWOverrideRedirect|
CWBackingStore|
CWSaveUnder|
CWBackPixmap;
attributes.background_pixmap = None;
attributes.save_under = False;
attributes.override_redirect = True;
attributes.backing_store = NotUseful;
WId rw = XCreateWindow(qt_xdisplay(), root, 0, 0,
desktop_client->width(),
desktop_client->height(),
0,
CopyFromParent, CopyFromParent,
CopyFromParent, valuemask,
&attributes);
XMapWindow(qt_xdisplay(), rw);
XDestroyWindow(qt_xdisplay(), rw);
XFlush(qt_xdisplay());
QWidget w( 0, 0, WX11BypassWM );
w.setGeometry( QApplication::desktop()->geometry() );
w.show();
w.hide();
QApplication::flushX();
}
/*!
@ -2517,12 +2513,12 @@ void Workspace::setCurrentDesktop( int new_desktop ){
} else {
focusToNull();
}
if( desktop_client ) {
if( !desktops.isEmpty() ) {
Window w_tmp;
int i_tmp;
XGetInputFocus( qt_xdisplay(), &w_tmp, &i_tmp );
if( w_tmp == null_focus_window )
requestFocus( desktop_client );
requestFocus( desktops.last() );
}
// Update focus chain:
@ -2882,19 +2878,6 @@ void Workspace::slotSwitchToDesktop( int i )
setCurrentDesktop( i );
}
/*void Workspace::slotSwitchToWindow( int i )
{
int n = 0;
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
if( (*it)->isOnDesktop( currentDesktop() ) ) {
if( n == i ) {
activateClient( (*it) );
break;
}
n++;
}
}
}*/
void Workspace::slotWindowToDesktop( int i )
{
@ -3297,7 +3280,7 @@ QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
QValueList<Client *>::ConstIterator l;
for (l = clients.begin();l != clients.end();++l )
{
if ((*l)->isOnDesktop(currentDesktop()) && (*l) != desktop_client &&
if ((*l)->isOnDesktop(currentDesktop()) &&
!(*l)->isIconified()
#if 0
&& (*l)->transientFor() == None
@ -3596,8 +3579,8 @@ void Workspace::slotResetAllClients()
block_focus = FALSE;
if ( active )
requestFocus( active );
else if( desktop_client )
requestFocus( desktop_client );
else if( !desktops.isEmpty() )
requestFocus( desktops.last() );
else
focusToNull();

View file

@ -206,8 +206,6 @@ public:
QPopupMenu* clientPopup( Client* );
void showWindowMenuAt( unsigned long id, int x, int y );
void setDesktopClient( Client* );
void iconifyOrDeiconifyTransientsOf( Client* );
void setStickyTransientsOf( Client*, bool sticky );
@ -229,8 +227,9 @@ public:
void unclutterDesktop();
void doNotManage(QString);
void setCurrentDesktop( int new_desktop );
void nextDesktop();
void previousDesktop();
void nextDesktop();
void previousDesktop();
void circulateDesktopApplications();
QString desktopName( int desk );
void setDesktopLayout(int o, int x, int y);
@ -389,13 +388,13 @@ private:
void writeFakeSessionInfo();
QValueList<CascadingInfo> cci;
Client* desktop_client;
Client* active_client;
Client* last_active_client;
Client* should_get_focus;
Client* most_recently_raised;
ClientList clients;
ClientList desktops;
ClientList stacking_order;
ClientList focus_chain;
@ -449,6 +448,8 @@ private:
XineramaScreenInfo *xineramaInfo;
XineramaScreenInfo dummy_xineramaInfo;
#endif
void addClient( Client* c );
};
inline WId Workspace::rootWin() const