[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-bugs-dist
Subject:    Bug#9394: PATCH] legacy session management in kwin
From:       Leon Bottou <leonb () research ! att ! com>
Date:       2001-03-12 20:05:05
[Download RAW message or body]

Attached are my updated patches.
I believe that these make a good candidate for 
insertion into the CVS.

- Leon Bottou


FYI: Updated list of changes / cvs
> [atoms.h, atoms.cpp]
>   * inserted new atom names.
> [client.h, client.cpp]
>   * implemented staticPROPERTYNAME() static methods
>     for accession props in any window.
>   * re-implemented the PROPERTYNAME() methods to use the above.
>   * added support for cached WM_CLIENT_LEADER property.
>   * added support for WM_CLIENT_MACHINE property.
>   * if sessionId, wmCommand, wmClientMachine is not found
>       also look into the leader window
> [workspace.cpp, workspace,h]
>   * rewrote code to match window geometry takeSessionInfo().
>   * function storeSession() saves more fields
>   * session config file now has a new section [LegacySession]
>     containing the commands to restart legacy applications.
>   * added function restoreLegacySession()
>   * added function storeLegacySession()

Compared to my last set of patches, this version
- has a restoreLegacySession() function
- has a better implementation of takeSessionInfo()
- uses more robust stuff in storeLegacySession() 
	i.e.  QTime instead of gettimeofday()
	      ::select located with a method similar to QT's

I did not move the staticPROPERTYNAME() methods into atoms.cpp
because there was too little overlap between these methods
and the atoms defined by atoms.cpp.  Such a change does not
make sense unless we make it a lot more pervasive.


- Leon Bottou
["2001-03-12.diff" (text/plain)]

? 2001-03-12.diff
? 2001-03-10.diff
Index: atoms.cpp
===================================================================
RCS file: /home/kde/kdebase/kwin/atoms.cpp,v
retrieving revision 1.13
diff -u -3 -p -r1.13 atoms.cpp
--- atoms.cpp	2000/06/24 17:58:10	1.13
+++ atoms.cpp	2001/03/12 17:14:37
@@ -30,6 +30,12 @@ Atoms::Atoms()
     atoms[n] = &wm_change_state;
     names[n++] = (char *) "WM_CHANGE_STATE";
 
+    atoms[n] = &wm_client_leader;
+    names[n++] = (char *) "WM_CLIENT_LEADER";
+
+    atoms[n] = &wm_save_yourself;
+    names[n++] = (char *) "WM_SAVE_YOURSELF";
+
     atoms[n] = &motif_wm_hints;
     names[n++] = (char *) "_MOTIF_WM_HINTS";
 
Index: atoms.h
===================================================================
RCS file: /home/kde/kdebase/kwin/atoms.h,v
retrieving revision 1.13
diff -u -3 -p -r1.13 atoms.h
--- atoms.h	2000/06/24 17:58:10	1.13
+++ atoms.h	2001/03/12 17:14:37
@@ -17,6 +17,8 @@ public:
     Atom wm_delete_window;
     Atom wm_take_focus;
     Atom wm_change_state;
+    Atom wm_client_leader;
+    Atom wm_save_yourself;
 
     Atom motif_wm_hints;
     Atom net_wm_context_help;
Index: client.cpp
===================================================================
RCS file: /home/kde/kdebase/kwin/client.cpp,v
retrieving revision 1.226
diff -u -3 -p -r1.226 client.cpp
--- client.cpp	2001/03/06 09:17:43	1.226
+++ client.cpp	2001/03/12 17:14:37
@@ -516,6 +516,7 @@ Client::Client( Workspace *ws, WId w, QW
     getWMHints();
     getWindowProtocols();
     getWmNormalHints(); // get xSizeHint
+    getWmClientLeader();
     fetchName();
 
     if ( mainClient()->isSticky() )
@@ -1145,6 +1146,8 @@ bool Client::propertyNotify( XPropertyEv
     default:
 	if ( e.atom == atoms->wm_protocols )
 	    getWindowProtocols();
+        else if (e.atom == atoms->wm_client_leader )
+            getWmClientLeader();
 	break;
     }
     return TRUE;
@@ -2589,79 +2592,172 @@ void Client::keyPressEvent( QKeyEvent * 
     QCursor::setPos( pos );
 }
 
-
-QCString Client::windowRole()
+static QCString getStringProperty(WId w, Atom prop, char separator=0)
 {
     Atom type;
     int format;
-    unsigned long length, after;
-    unsigned char *data;
-    QCString result;
-    if ( XGetWindowProperty( qt_xdisplay(), win, qt_window_role, 0, 1024,
+    unsigned long nitems = 0;
+    unsigned long extra = 0;
+    unsigned char *data = 0;
+    QCString result = "";
+    if ( XGetWindowProperty( qt_xdisplay(), w, prop, 0, 10000,
 			     FALSE, XA_STRING, &type, &format,
-			     &length, &after, &data ) == Success ) {
-	if ( data )
-	    result = (const char*) data;
-	XFree( data );
+			     &nitems, &extra, &data ) == Success ) {
+        if (data && separator) {
+            for (int i=0; i<(int)nitems; i++)
+                if (!data[i] && i+1<(int)nitems)
+                    data[i] = separator;
+        }
+        if (data)
+          result = (const char*) data;
+        XFree(data);
     }
     return result;
 }
 
-QCString Client::sessionId()
+/*!
+  Returns WINDOW_ROLE property for a given window.
+ */
+QCString Client::staticWindowRole(WId w)
+{
+    return getStringProperty(w, qt_window_role);
+}
+
+/*!
+  Returns SM_CLIENT_ID property for a given window.
+ */
+QCString Client::staticSessionId(WId w)
+{
+    return getStringProperty(w, qt_sm_client_id);
+}
+
+/*!
+  Returns WM_COMMAND property for a given window.
+ */
+QCString Client::staticWmCommand(WId w)
+{
+    return getStringProperty(w, XA_WM_COMMAND, ' ');
+}
+
+/*!
+  Returns WM_CLIENT_MACHINE property for a given window.
+  Local machine is always returned as "localhost".
+ */
+QCString Client::staticWmClientMachine(WId w)
+{
+    QCString result = getStringProperty(w, XA_WM_CLIENT_MACHINE);
+    if (result.isEmpty()) {
+        result = "localhost";
+    } else {
+        // special name for the local machine (localhost)
+        char hostnamebuf[80];
+        if (gethostname (hostnamebuf, sizeof hostnamebuf) >= 0) {
+            hostnamebuf[sizeof(hostnamebuf)-1] = 0;
+            if (result == hostnamebuf)
+                result = "localhost";
+            char *dot = strchr(hostnamebuf, '.');
+            if (dot && !(*dot = 0) && result == hostnamebuf) 
+                result = "localhost";
+        }
+    }
+    return result;
+}
+
+/*!
+  Returns WM_CLIENT_LEADER property for a given window.
+ */
+Window Client::staticWmClientLeader(WId w)
 {
     Atom type;
     int format;
-    unsigned long length, after;
-    unsigned char *data;
-    QCString result;
-    if ( XGetWindowProperty( qt_xdisplay(), win, qt_sm_client_id, 0, 1024,
-			     FALSE, XA_STRING, &type, &format,
-			     &length, &after, &data ) == Success ) {
-	if ( data )
-	    result = (const char*) data;
-	XFree( data );
+    unsigned long nitems = 0;
+    unsigned long extra = 0;
+    unsigned char *data = 0;
+    Window result = w;
+    if ( XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
+			     FALSE, XA_WINDOW, &type, &format,
+			     &nitems, &extra, &data ) == Success ) {
+        if (data && nitems > 0)
+            result = *((Window*) data);
+        XFree(data);
     }
     return result;
 }
-
 
-static int getprop(Window w, Atom a, Atom type, long len, unsigned char **p)
+void Client::getWmClientLeader()
 {
-    Atom real_type;
-    int format;
-    unsigned long n, extra;
-    int status;
+    wmClientLeaderWin = staticWmClientLeader(win);
+}
 
-    status = XGetWindowProperty(qt_xdisplay(), w, a, 0L, len, False, type, \
                &real_type, &format, &n, &extra, p);
-    if (status != Success || *p == 0)
-	return -1;
-    if (n == 0)
-	XFree((void*) *p);
-    return n;
+/*!
+  Returns WINDOW_ROLE for this client
+ */
+QCString Client::windowRole()
+{
+    return staticWindowRole(win);
 }
 
-QCString Client::wmCommand()
+/*!
+  Returns sessionId for this client, 
+  taken either from its window or from the leader window.
+ */
+QCString Client::sessionId()
 {
-  QCString result;
-  char *p;
-  int i,n;
-  if ((n = getprop(win, XA_WM_COMMAND, XA_STRING, 100L, (unsigned char **)&p)) > 0){
-    result = p;
-    for ( i = 0; (i += strlen(p+i)+1) < n; result.append(p+i) )
-	result.append(" ");
-    XFree((char *) p);
-  }
-  return result;
+    QCString result = staticSessionId(win);
+    if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=win)
+        result = staticSessionId(wmClientLeaderWin);
+    return result;
 }
 
+/*!
+  Returns the classhint resource name for this client, 
+ */
 QCString Client::resourceName()
 {
     return resource_name;
 }
 
+/*!
+  Returns the classhint resource class for this client, 
+ */
 QCString Client::resourceClass()
 {
     return resource_class;
+}
+
+/*!
+  Returns command property for this client, 
+  taken either from its window or from the leader window.
+ */
+QCString Client::wmCommand()
+{
+    QCString result = staticWmCommand(win);
+    if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=win)
+        result = staticWmCommand(wmClientLeaderWin);
+    return result;
+}
+
+/*!
+  Returns client machine for this client, 
+  taken either from its window or from the leader window.
+*/
+QCString Client::wmClientMachine()
+{
+    QCString result = staticWmClientMachine(win);
+    if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=win)
+        result = staticWmClientMachine(wmClientLeaderWin);
+    return result;
+}
+
+/*! 
+  Returns client leader window for this client.
+  Returns the client window itself if no leader window is defined.
+*/
+Window Client::wmClientLeader()
+{
+    if (wmClientLeaderWin)
+        return wmClientLeaderWin;
+    return win;
 }
 
 
Index: client.h
===================================================================
RCS file: /home/kde/kdebase/kwin/client.h,v
retrieving revision 1.64
diff -u -3 -p -r1.64 client.h
--- client.h	2001/02/20 01:20:36	1.64
+++ client.h	2001/03/12 17:14:37
@@ -178,9 +178,11 @@ public:
 
     QCString windowRole();
     QCString sessionId();
-    QCString wmCommand();
     QCString resourceName();
     QCString resourceClass();
+    QCString wmCommand();
+    QCString wmClientMachine();
+    Window   wmClientLeader();
 
     QRect adjustedClientArea( const QRect& area ) const;
 
@@ -314,6 +316,16 @@ private:
     void verifyTransientFor();
     friend class WindowWrapper;
     QString cap;
+    WId wmClientLeaderWin;
+    void getWmClientLeader();
+
+ public:
+    static QCString staticWindowRole(WId);
+    static QCString staticSessionId(WId);
+    static QCString staticWmCommand(WId);
+    static QCString staticWmClientMachine(WId);
+    static Window   staticWmClientLeader(WId);
+    
 };
 
 inline WId Client::window() const
Index: workspace.cpp
===================================================================
RCS file: /home/kde/kdebase/kwin/workspace.cpp,v
retrieving revision 1.217
diff -u -3 -p -r1.217 workspace.cpp
--- workspace.cpp	2001/03/02 10:35:25	1.217
+++ workspace.cpp	2001/03/12 17:14:38
@@ -3,7 +3,10 @@ kwin - the KDE window manager
 
 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
 ******************************************************************/
+
 //#define QT_CLEAN_NAMESPACE
+#define select kwin_hide_select
+
 #include <kconfig.h>
 #include <kglobal.h>
 #include <kglobalsettings.h>
@@ -42,6 +45,15 @@ const int XIconicState = IconicState;
 #include <kwin.h>
 #include <kdebug.h>
 
+// Possible protoypes for select() were hidden as `kwin_hide_select.
+// Undo the hiding definition and defines an acceptable prototype.
+// This is how QT does this. It should work where QT works.
+#ifdef HAVE_SYS_SELECT_H 
+#include <sys/select.h>
+#endif
+#undef select
+extern "C" int select(int,void*,void*,void*,struct timeval*);
+
 namespace KWinInternal {
 
 // NET WM Protocol handler class
@@ -280,15 +292,8 @@ Workspace::Workspace( bool restore )
 
     init();
 
-    if ( restore ) { // pseudo session management with wmCommand
-        for (SessionInfo* info = session.first(); info; info = session.next() ) {
-            if ( info->sessionId.isEmpty() && !info->wmCommand.isEmpty() ) {
-                KShellProcess proc;
-                proc << QString::fromLatin1( info->wmCommand );
-                proc.start(KShellProcess::DontCare);
-            }
-        }
-    }
+    if ( restore ) 
+        restoreLegacySession(kapp->sessionConfig());
 }
 
 void Workspace::init()
@@ -2888,35 +2893,220 @@ void Workspace::slotResetAllClients()
         requestFocus( active );
 }
 
+
+/* 
+ * Legacy session management
+ */
+
+#ifndef NO_LEGACY_SESSION_MANAGEMENT
+
+#define WM_SAVE_YOURSELF_TIMEOUT 2000 
+
+enum WinState { W_INVALID, W_VALID, W_SAVE_YOURSELF, W_SAVE_YOURSELF_OK };
+typedef QMap<WId,WinState> WinMap;
+
+static WinMap *winsPtr = 0;
+
+static int winsErrorHandler(Display *, XErrorEvent *ev)
+{
+    if (winsPtr) {
+        WinMap::Iterator it = winsPtr->find(ev->resourceid);
+        if (it != winsPtr->end())
+            it.data() = W_INVALID;
+    }
+    return 0;
+}
+
 /*!
+  Stores legacy session management data
+*/
+void Workspace::storeLegacySession( KConfig* config )
+{
+    // Compute set of leader windows that 
+    // might require legacy session management
+    WinMap wins;
+    for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it) {
+        Client* c = (*it);
+        WId leader = c->wmClientLeader();
+        if (!wins.contains(leader) && c->sessionId().isEmpty())
+            wins.insert(leader, W_VALID);
+    }
+    
+    // Open a new display for safely doing the WM_SAVE_YOURSELF protocol
+    XSync(qt_xdisplay(), False);
+    Display *newdisplay = XOpenDisplay(DisplayString(qt_xdisplay()));
+    if (!newdisplay) return;
+    WId root = DefaultRootWindow(newdisplay);
+    XGrabKeyboard(newdisplay, root, False, 
+                  GrabModeAsync, GrabModeAsync, CurrentTime);
+    XGrabPointer(newdisplay, root, False, Button1Mask|Button2Mask|Button3Mask,
+                 GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
+    winsPtr = &wins;
+    XErrorHandler oldHandler = XSetErrorHandler(winsErrorHandler);
+    
+    // Send WM_SAVE_YOURSELF messages to relevant windows
+    XEvent ev;
+    int awaiting_replies = 0;
+    for (WinMap::Iterator it = wins.begin(); it != wins.end(); ++it) {
+        if ( atoms->wm_protocols == None || atoms->wm_save_yourself == None)
+            break;
+        if ( it.data() == W_VALID ) {
+            WId w = it.key();
+            Atom *protocols = 0;
+            int nprotocols = 0;
+            XGetWMProtocols(newdisplay, w, &protocols, &nprotocols);
+            for (int i=0; i<nprotocols; i++)
+              if (protocols[i] == atoms->wm_save_yourself) {
+                it.data() = W_SAVE_YOURSELF;
+                break;
+              }
+            XFree((void*) protocols);
+        }
+        if ( it.data() == W_SAVE_YOURSELF ) {
+            WId w = it.key();
+            awaiting_replies += 1;
+            memset(&ev, 0, sizeof(ev));
+            ev.xclient.type = ClientMessage;
+            ev.xclient.window = w;
+            ev.xclient.message_type = atoms->wm_protocols;
+            ev.xclient.format = 32;
+            ev.xclient.data.l[0] = atoms->wm_save_yourself;
+            ev.xclient.data.l[1] = CurrentTime;
+            XSelectInput(newdisplay, w, PropertyChangeMask|StructureNotifyMask);
+            XSendEvent(newdisplay, w, False, 0, &ev);
+        }
+    }
+    
+    // Wait for change in WM_COMMAND (with timeout)
+    XFlush(newdisplay);
+    QTime start = QTime::currentTime();
+    while (awaiting_replies > 0) {
+        if (XPending(newdisplay)) {
+            /* Process pending event */
+            XNextEvent(newdisplay, &ev);
+            WinMap::Iterator it = wins.find( ev.xany.window );
+            if (it == wins.end() || it.data() == W_SAVE_YOURSELF_OK)
+                continue;
+            if ( ev.type == UnmapNotify ||
+                 ( ev.xany.type == PropertyNotify 
+                   && ev.xproperty.atom == XA_WM_COMMAND ) ) {
+                awaiting_replies -= 1;
+                it.data() = W_SAVE_YOURSELF_OK;
+            }
+        } else {
+            /* Check timeout */
+            int msecs = start.elapsed();
+            if (msecs >= WM_SAVE_YOURSELF_TIMEOUT)
+                break;
+            /* Wait for more events */
+            struct timeval tmwait;
+            int fd = ConnectionNumber(newdisplay);
+            fd_set fds;
+            FD_ZERO(&fds);
+            FD_SET(fd, &fds);
+            tmwait.tv_sec = (WM_SAVE_YOURSELF_TIMEOUT - msecs) / 1000;
+            tmwait.tv_usec = ((WM_SAVE_YOURSELF_TIMEOUT - msecs) % 1000) * 1000;
+            ::select(fd+1, &fds, NULL, &fds, &tmwait);
+        }
+    }
+
+    // Terminate work in new display
+    XAllowEvents(newdisplay, ReplayPointer, CurrentTime);
+    XAllowEvents(newdisplay, ReplayKeyboard, CurrentTime);
+    XSync(newdisplay, False);
+    XCloseDisplay(newdisplay);
+    
+    // Write LegacySession data
+    config->setGroup("LegacySession" );
+    int count = 0;
+    for (WinMap::Iterator it = wins.begin(); it != wins.end(); ++it) {
+      if (it.data() != W_INVALID) {
+        WId w = it.key();
+        QCString wmCommand = Client::staticWmCommand(w);
+        QCString wmClientMachine = Client::staticWmClientMachine(w);
+        if ( !wmCommand.isEmpty() && !wmClientMachine.isEmpty() ) {
+          count++;
+          QString n = QString::number(count);
+          config->writeEntry( QString("command")+n, wmCommand.data() );
+          config->writeEntry( QString("clientMachine")+n, wmClientMachine.data() );
+        }
+      }
+    }
+    config->writeEntry( "count", count );
+    
+    // Restore old error handler
+    XSync(qt_xdisplay(), False);
+    XSetErrorHandler(oldHandler);
+    
+    // Process a few events to update the client list.
+    // All events should be there because of the XSync above.
+    kapp->processEvents(10);
+}
+#endif
+
+/*!
+  Restores legacy session management data (i.e. restart applications)
+*/
+void Workspace::restoreLegacySession( KConfig* config )
+{
+    if (config) {
+        config->setGroup("LegacySession" );
+        int count =  config->readNumEntry( "count" );
+        for ( int i = 1; i <= count; i++ ) {
+            QString n = QString::number(i);
+            QCString wmCommand = config->readEntry( QString("command")+n ).latin1();
+            QCString wmClientMachine = config->readEntry( QString("clientMachine")+n \
).latin1(); +            if ( !wmCommand.isEmpty() && !wmClientMachine.isEmpty() ) {
+                KShellProcess proc;
+                if ( wmClientMachine != "localhost" )
+                    proc << "xon" << wmClientMachine;
+                proc << QString::fromLatin1( wmCommand );
+                proc.start(KShellProcess::DontCare);
+            }
+        }
+    }
+}
+
+/*!
   Stores the current session in the config file
 
   \sa loadSessionInfo()
  */
 void Workspace::storeSession( KConfig* config )
 {
+#ifndef NO_LEGACY_SESSION_MANAGEMENT
+    storeLegacySession(config);
+#endif
     config->setGroup("Session" );
     int count =  0;
     for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it) {
         Client* c = (*it);
         QCString sessionId = c->sessionId();
-        QCString windowRole = c->windowRole();
         QCString wmCommand = c->wmCommand();
-        if ( !sessionId.isEmpty() || !wmCommand.isEmpty() ) {
-            count++;
-            QString n = QString::number(count);
-            config->writeEntry( QString("sessionId")+n, sessionId.data() );
-            config->writeEntry( QString("windowRole")+n, windowRole.data() );
-            config->writeEntry( QString("wmCommand")+n, wmCommand.data() );
-            config->writeEntry( QString("geometry")+n,  QRect( c->pos(), \
                c->windowWrapper()->size() ) );
-            config->writeEntry( QString("restore")+n, c->geometryRestore() );
-            config->writeEntry( QString("maximize")+n, (int) c->maximizeMode() );
-            config->writeEntry( QString("desktop")+n, c->desktop() );
-            config->writeEntry( QString("iconified")+n, c->isIconified() );
-            config->writeEntry( QString("sticky")+n, c->isSticky() );
-            config->writeEntry( QString("shaded")+n, c->isShade() );
-            config->writeEntry( QString("staysOnTop")+n, c->staysOnTop() );
-        }
+        if ( sessionId.isEmpty() )
+#ifndef NO_LEGACY_SESSION_MANAGEMENT
+            // This is the only connection between the determination of legacy
+            // session managed applications (storeLegacySession) and the
+            // recollection of the window geometries (this function).
+            if ( wmCommand.isEmpty() )
+#endif 
+                continue;
+        count++;
+        QString n = QString::number(count);
+        config->writeEntry( QString("sessionId")+n, sessionId.data() );
+        config->writeEntry( QString("windowRole")+n, c->windowRole().data() );
+        config->writeEntry( QString("wmCommand")+n, wmCommand.data() );
+        config->writeEntry( QString("wmClientMachine")+n, \
c->wmClientMachine().data() ); +        config->writeEntry( \
QString("resourceName")+n, c->resourceName().data() ); +        config->writeEntry( \
QString("resourceClass")+n, c->resourceClass().data() ); +        config->writeEntry( \
QString("geometry")+n,  QRect( c->pos(), c->windowWrapper()->size() ) ); +        \
config->writeEntry( QString("restore")+n, c->geometryRestore() ); +        \
config->writeEntry( QString("maximize")+n, (int) c->maximizeMode() ); +        \
config->writeEntry( QString("desktop")+n, c->desktop() ); +        \
config->writeEntry( QString("iconified")+n, c->isIconified() ); +        \
config->writeEntry( QString("sticky")+n, c->isSticky() ); +        \
config->writeEntry( QString("shaded")+n, c->isShade() ); +        config->writeEntry( \
QString("staysOnTop")+n, c->staysOnTop() );  }
     config->writeEntry( "count", count );
 }
@@ -2940,6 +3130,9 @@ void Workspace::loadSessionInfo()
         info->sessionId = config->readEntry( QString("sessionId")+n ).latin1();
         info->windowRole = config->readEntry( QString("windowRole")+n ).latin1();
         info->wmCommand = config->readEntry( QString("wmCommand")+n ).latin1();
+        info->wmClientMachine = config->readEntry( QString("wmClientMachine")+n \
).latin1(); +        info->resourceName = config->readEntry( \
QString("resourceName")+n ).latin1(); +        info->resourceClass = \
config->readEntry( QString("resourceClass")+n ).latin1();  info->geometry = \
config->readRectEntry( QString("geometry")+n );  info->restore = \
                config->readRectEntry( QString("restore")+n );
         info->maximize = config->readNumEntry( QString("maximize")+n, 0 );
@@ -2963,6 +3156,7 @@ void Workspace::loadFakeSessionInfo()
         fakeSession.append( info );
         info->resourceName = config->readEntry( QString("resourceName")+n \
                ).latin1();
         info->resourceClass = config->readEntry( QString("resourceClass")+n \
).latin1(); +        info->wmClientMachine = config->readEntry( \
QString("clientMachine")+n ).latin1();  info->geometry = config->readRectEntry( \
QString("geometry")+n );  info->restore = config->readRectEntry( QString("restore")+n \
                );
         info->maximize = config->readNumEntry( QString("maximize")+n, 0 );
@@ -2982,6 +3176,7 @@ void Workspace::storeFakeSessionInfo( Cl
     fakeSession.append( info );
     info->resourceName = c->resourceName();
     info->resourceClass = c->resourceClass();
+    info->wmClientMachine = c->wmClientMachine();
     info->geometry = QRect( c->pos(), c->windowWrapper()->size() ) ;
     info->restore = c->geometryRestore();
     info->maximize = (int)c->maximizeMode();
@@ -3002,6 +3197,7 @@ void Workspace::writeFakeSessionInfo()
         QString n = QString::number(count);
         config->writeEntry( QString("resourceName")+n, info->resourceName.data() );
         config->writeEntry( QString("resourceClass")+n, info->resourceClass.data() \
); +        config->writeEntry( QString("clientMachine")+n, \
info->wmClientMachine.data() );  config->writeEntry( QString("geometry")+n,  \
info->geometry );  config->writeEntry( QString("restore")+n, info->restore );
         config->writeEntry( QString("maximize")+n, info->maximize );
@@ -3015,47 +3211,68 @@ void Workspace::writeFakeSessionInfo()
 }
 
 /*!
-  Returns the SessionInfo for client \a c. The returned session
+  Returns a SessionInfo for client \a c. The returned session
   info is removed from the storage. It's up to the caller to delete it.
 
+  This function is called when a new window is mapped and must be managed.
+  We try to find a matching entry in the session.  We also try to find
+  a matching entry in the fakeSession to see if the user had seclected the
+  ``store settings'' menu entry.  
+
   May return 0 if there's no session info for the client.
  */
 SessionInfo* Workspace::takeSessionInfo( Client* c )
 {
-
-    if ( !session.isEmpty() ) {
-        QCString sessionId = c->sessionId();
-        QCString windowRole = c->windowRole();
-        QCString wmCommand = c->wmCommand();
-
-        for (SessionInfo* info = session.first(); info; info = session.next() ) {
-
-            // a real session managed client
-            if ( info->sessionId == sessionId &&
-                 ( ( info->windowRole.isEmpty() && windowRole.isEmpty() )
-                   || (info->windowRole == windowRole ) ) )
-                return session.take();
-
-            // pseudo session management
-            if ( info->sessionId.isEmpty() && !info->wmCommand.isEmpty() &&
-                 info->wmCommand == wmCommand &&
-                 ( ( info->windowRole.isEmpty() && windowRole.isEmpty() )
-                   || (info->windowRole == windowRole ) ) )
-                return session.take();
-        }
-    }
-
-     // fakeSession, the "Store Settings" option in the window operation popup menu
-    if ( !fakeSession.isEmpty() ) {
-        QCString resourceName = c->resourceName();
-        QCString resourceClass = c->resourceClass();
-        for (SessionInfo* info = fakeSession.first(); info; info = \
                fakeSession.next() ) {
-            if (  info->resourceName == resourceName && info->resourceClass == \
                resourceClass ) {
-                c->setStoreSettings( TRUE );
-                return fakeSession.take();
+    SessionInfo *realInfo = 0;
+    SessionInfo *fakeInfo = 0;
+    QCString sessionId = c->sessionId();
+    QCString windowRole = c->windowRole();
+    QCString wmCommand = c->wmCommand();
+    QCString wmClientMachine = c->wmClientMachine();
+    QCString resourceName = c->resourceName();
+    QCString resourceClass = c->resourceClass();
+    
+    // First search ``session''
+    if (! sessionId.isEmpty() ) {
+        // look for a real session managed client (algorithm suggested by ICCCM)
+        for (SessionInfo* info = session.first(); info && !realInfo; info = \
session.next() )  +            if ( info->sessionId == sessionId ) {
+                if ( ! windowRole.isEmpty() ) {
+                    if ( info->windowRole == windowRole )
+                        realInfo = session.take();
+                } else {
+                    if ( info->windowRole.isEmpty() && 
+                         info->resourceName == resourceName && 
+                         info->resourceClass == resourceClass )
+                        realInfo = session.take();
+                }
             }
-        }
-    }
+    } else {
+        // look for a sessioninfo with matching features.
+        for (SessionInfo* info = session.first(); info && !realInfo; info = \
session.next() )  +            if ( info->resourceName == resourceName && 
+                 info->resourceClass == resourceClass &&
+                 info->wmClientMachine == wmClientMachine )
+                if ( wmCommand.isEmpty() || info->wmCommand == wmCommand )
+                    realInfo = session.take();
+    }
+    
+    // Now search ``fakeSession''
+    for (SessionInfo* info = fakeSession.first(); info && !fakeInfo; info = \
fakeSession.next() ) +        if ( info->resourceName == resourceName && 
+             info->resourceClass == resourceClass &&
+             info->wmClientMachine == wmClientMachine ) 
+            fakeInfo = fakeSession.take();
+    
+    // Reconciliate
+    if (fakeInfo)
+        c->setStoreSettings( TRUE );
+    if (fakeInfo && realInfo)
+        delete fakeInfo;
+    if (realInfo)
+        return realInfo;
+    if (fakeInfo)
+        return fakeInfo;
     return 0;
 }
 
Index: workspace.h
===================================================================
RCS file: /home/kde/kdebase/kwin/workspace.h,v
retrieving revision 1.69
diff -u -3 -p -r1.69 workspace.h
--- workspace.h	2001/03/08 14:28:07	1.69
+++ workspace.h	2001/03/12 17:14:38
@@ -56,10 +56,9 @@ struct SessionInfo
 {
     QCString sessionId;
     QCString windowRole;
-
-    QCString wmCommand; // compatibility
-
-    QCString resourceName; // for faked session info
+    QCString wmCommand;
+    QCString wmClientMachine;
+    QCString resourceName;
     QCString resourceClass;
 
     QRect geometry;
@@ -177,6 +176,8 @@ public:
 
     void performWindowOperation( Client* c, Options::WindowOperation op );
 
+    void restoreLegacySession( KConfig* config );
+    void storeLegacySession( KConfig* config );
     void storeSession( KConfig* config );
 
     SessionInfo* takeSessionInfo( Client* );



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic