[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-10 6:20:17
[Download RAW message or body]

Matthias,

This is my first working code for solution #2.
The attached patch gives kwin the following capabilities:

- ability to track WM_CLIENT_LEADER 
    - for finding the modern sessionID
		(e.g. seamless management of gnome apps)
    - in legacy session management 
		(e.g. motif apps, netscape, xemacs, etc.)

- ability to safely perform the WM_SAVE_YOURSELF protocol
	(e.g. emacs, netscape, motif apps)

- ability to restart remote legacy application
   	(assuming that the proper .Xauthority file is accessible)

- ability to match windows with session saved windows on the
  basis of sessionId + windowRole
     or  sessionId + resName + resClass (suggested by ICCCM6)
     or  resName + resClass + clientMachine + Command
     or  resName + resClass + clientMachine
     or  resName + resClass

- ability to properly handle window description that 
        appear both in [Session] and [fakeSession].

I added a new section in the sessionConfig file.
This new section is named [LegacySession] and contains
the list of applications to start. 

This version behaves quite well in all my tests.
Please let me know what you think.

- Leon Bottou



P.S. - Moritz, you are welcome to try and report whatever
       problems you observe.  Thanks


It is late.  Good night.
["2001-03-10.diff" (text/plain)]

? 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/10 06:03:58
@@ -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/10 06:03:58
@@ -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/10 06:03:58
@@ -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/10 06:03:58
@@ -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/10 06:03:59
@@ -280,11 +280,20 @@ 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() ) {
+    if ( restore ) { 
+        // legacy session management
+        KConfig* config = kapp->sessionConfig();
+        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;
-                proc << QString::fromLatin1( info->wmCommand );
+                if ( wmClientMachine != "localhost" )
+                    proc << "xon" << wmClientMachine;
+                proc << QString::fromLatin1( wmCommand );
                 proc.start(KShellProcess::DontCare);
             }
         }
@@ -2888,6 +2897,160 @@ void Workspace::slotResetAllClients()
         requestFocus( active );
 }
 
+
+/* 
+ * Legacy session management
+ */
+
+#ifndef NO_LEGACY_SESSION_MANAGEMENT
+#define WM_SAVE_YOURSELF_TIMEOUT 2000 
+
+#ifndef X_GETTIMEOFDAY  // normally defined in Xos.h
+#define X_GETTIMEOFDAY(t) gettimeofday(t, 0)
+#endif
+
+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);
+    int msecs = WM_SAVE_YOURSELF_TIMEOUT;
+    while (awaiting_replies > 0 && msecs > 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 {
+            /* Wait for more events */
+            int fd = ConnectionNumber(newdisplay);
+            struct timeval tmwait, tmbefore, tmafter;
+            fd_set fds;
+            FD_ZERO(&fds);
+            FD_SET(fd, &fds);
+            tmwait.tv_sec = msecs / 1000;
+            tmwait.tv_usec = 1000 * (msecs % 1000);
+            X_GETTIMEOFDAY(&tmbefore);
+            select(fd+1, &fds, NULL, &fds, &tmwait);
+            X_GETTIMEOFDAY(&tmafter);
+            msecs -= (tmafter.tv_sec - tmbefore.tv_sec) * 1000;
+            msecs -= (tmafter.tv_usec - tmbefore.tv_usec) / 1000;
+            msecs -= 1;
+        }
+    }
+
+    // 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.
+    kapp->processEvents(200);
+}
+#endif
+
 /*!
   Stores the current session in the config file
 
@@ -2895,28 +3058,36 @@ void Workspace::slotResetAllClients()
  */
 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
+            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 +3111,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 +3137,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 +3157,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 +3178,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 +3192,74 @@ 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
+        for (SessionInfo* info = session.first(); info && !realInfo; info = \
session.next() )  +            if ( info->sessionId == sessionId && 
+                 info->windowRole.isEmpty() && windowRole.isEmpty() &&
+                 info->resourceName == resourceName && info->resourceClass == \
resourceClass ) +                realInfo = session.take();                 
+        for (SessionInfo* info = session.first(); info && !realInfo; info = \
session.next() )  +            if ( info->sessionId == sessionId && 
+                 ( info->windowRole == windowRole ||
+                   ( info->windowRole.isEmpty() && windowRole.isEmpty() ) ) )
+                realInfo = session.take();                 
+    } else {
+        // look for a window with matching class hints, 
+        // and preferably matching command and client machine.
+        for (SessionInfo* info = session.first(); info && !realInfo; info = \
session.next() )  +            if ( info->resourceName == resourceName && \
info->resourceClass == resourceClass && +                 info->wmCommand == \
wmCommand && info->wmClientMachine == wmClientMachine )  +                realInfo = \
session.take(); +        for (SessionInfo* info = session.first(); info && !realInfo; \
info = session.next() )  +            if ( info->resourceName == resourceName && \
info->resourceClass == resourceClass && +                 info->wmClientMachine == \
wmClientMachine )  +                realInfo = session.take();
+        for (SessionInfo* info = session.first(); info && !realInfo; info = \
session.next() )  +            if ( info->resourceName == resourceName && \
info->resourceClass == resourceClass ) +                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();
+    for (SessionInfo* info = fakeSession.first(); info && !fakeInfo; info = \
fakeSession.next() ) +        if ( info->resourceName == resourceName && \
info->resourceClass == resourceClass )  +            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/10 06:03:59
@@ -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,7 @@ public:
 
     void performWindowOperation( Client* c, Options::WindowOperation op );
 
+    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