[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-19 16:31:23
[Download RAW message or body]

Matthias Ettrich wrote:
> This looks very nice, Leon. 
> Can you apply it to the CVS tree, please?
> Matthias

I got confused.
Do you mean that you want me to ask Coloo for a cvs write access?  
I can do that.

- Leon


-----------------------------------------


P.S. (history)

Started with a patch for #9394
implementing legacy session management in kwin.
Mostly useful for EMACS.

Discovered that XEMACS and many MOTIF APPS (e.g. NETSCAPE)
perform their legacy session management on the leader window
and not on the client window.

Discovered that GNOME APPS do modern session management
but have their session id on the leader window only.
Kwin currently does not restore their geometry properly.

Fixed all of the above:

 atoms.{h,cpp} : new atoms
 client.{h,cpp} : changes to track the leader windows
 workspace.{h,cpp} : changes to legacy session management code.


-----------------------------------------

Latest patch is attached.
["2001-03-19.diff" (text/plain)]

? 2001-03-16.diff
? 2001-03-12.diff
? 2001-03-10.diff
? 2001-03-14.diff
? 2001-03-19.diff
? workspace.cpp.debug
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/19 16:31:07
@@ -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/19 16:31:07
@@ -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.228
diff -u -3 -p -r1.228 client.cpp
--- client.cpp	2001/03/14 09:21:16	1.228
+++ client.cpp	2001/03/19 16:31:08
@@ -518,6 +518,7 @@ Client::Client( Workspace *ws, WId w, QW
     getWMHints();
     getWindowProtocols();
     getWmNormalHints(); // get xSizeHint
+    getWmClientLeader();
     fetchName();
 
     if ( mainClient()->isSticky() )
@@ -1150,6 +1151,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;
@@ -2603,79 +2606,183 @@ void Client::keyPressEvent( QKeyEvent * 
     QCursor::setPos( pos );
 }
 
+static int nullErrorHandler(Display *, XErrorEvent *)
+{
+    return 0;
+}
 
-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,
-			     FALSE, XA_STRING, &type, &format,
-			     &length, &after, &data ) == Success ) {
-	if ( data )
-	    result = (const char*) data;
-	XFree( data );
+    int format, status;
+    unsigned long nitems = 0;
+    unsigned long extra = 0;
+    unsigned char *data = 0;
+    QCString result = "";
+    XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
+    status = XGetWindowProperty( qt_xdisplay(), w, prop, 0, 10000,
+                                 FALSE, XA_STRING, &type, &format,
+                                 &nitems, &extra, &data );
+    XSetErrorHandler(oldHandler);
+    if ( status == 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 );
+    int format, status;
+    unsigned long nitems = 0;
+    unsigned long extra = 0;
+    unsigned char *data = 0;
+    Window result = w;
+    XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
+    status = XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, \
10000, +                                 FALSE, XA_WINDOW, &type, &format,
+                                 &nitems, &extra, &data );
+    XSetErrorHandler(oldHandler);
+    if (status  == Success ) {
+        if (data && nitems > 0)
+            result = *((Window*) data);
+        XFree(data);
     }
     return result;
 }
 
+void Client::getWmClientLeader()
+{
+    wmClientLeaderWin = staticWmClientLeader(win);
+}
 
-static int getprop(Window w, Atom a, Atom type, long len, unsigned char **p)
+/*!
+  Returns WINDOW_ROLE for this client
+ */
+QCString Client::windowRole()
 {
-    Atom real_type;
-    int format;
-    unsigned long n, extra;
-    int status;
-
-    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;
+    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.65
diff -u -3 -p -r1.65 client.h
--- client.h	2001/03/12 21:32:13	1.65
+++ client.h	2001/03/19 16:31:08
@@ -181,9 +181,11 @@ public:
 
     QCString windowRole();
     QCString sessionId();
-    QCString wmCommand();
     QCString resourceName();
     QCString resourceClass();
+    QCString wmCommand();
+    QCString wmClientMachine();
+    Window   wmClientLeader();
 
     QRect adjustedClientArea( const QRect& area ) const;
 
@@ -317,6 +319,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.221
diff -u -3 -p -r1.221 workspace.cpp
--- workspace.cpp	2001/03/14 10:16:08	1.221
+++ workspace.cpp	2001/03/19 16:31:08
@@ -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()
@@ -2924,26 +2929,201 @@ void Workspace::slotResetAllClients()
         requestFocus( active );
 }
 
+
+/* 
+ * Legacy session management
+ */
+
+#ifndef NO_LEGACY_SESSION_MANAGEMENT
+#define WM_SAVE_YOURSELF_TIMEOUT 4000 
+
+typedef QMap<WId,int> WindowMap;
+#define HAS_ERROR          0
+#define HAS_WMCOMMAND      1
+#define HAS_WMSAVEYOURSELF 2
+
+static WindowMap *windowMapPtr = 0;
+
+static int winsErrorHandler(Display *, XErrorEvent *ev)
+{
+    if (windowMapPtr) {
+        WindowMap::Iterator it = windowMapPtr->find(ev->resourceid);
+        if (it != windowMapPtr->end())
+            it.data() = HAS_ERROR;
+    }
+    return 0;
+}
+
 /*!
+  Stores legacy session management data
+*/
+void Workspace::storeLegacySession( KConfig* config )
+{
+    // Setup error handler
+    WindowMap wins;
+    windowMapPtr = &wins;
+    XErrorHandler oldHandler = XSetErrorHandler(winsErrorHandler);
+    // Compute set of leader windows that need legacy session management
+    // and determine which style (WM_COMMAND or WM_SAVE_YOURSELF)
+    for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it) {
+        Client* c = (*it);
+        WId leader = c->wmClientLeader();
+        if (!wins.contains(leader) && c->sessionId().isEmpty()) {
+            int wtype = HAS_WMCOMMAND;
+            int nprotocols = 0;
+            Atom *protocols = 0;
+            XGetWMProtocols(qt_xdisplay(), leader, &protocols, &nprotocols);
+            for (int i=0; i<nprotocols; i++)
+                if (protocols[i] == atoms->wm_save_yourself) {
+                    wtype = HAS_WMSAVEYOURSELF;
+                    break;
+                }
+            XFree((void*) protocols);
+            wins.insert(leader, wtype);
+        }
+    }
+    // Open fresh display for sending WM_SAVE_YOURSELF
+    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);
+    // Send WM_SAVE_YOURSELF messages
+    XEvent ev;
+    int awaiting_replies = 0;
+    for (WindowMap::Iterator it = wins.begin(); it != wins.end(); ++it) {
+        if ( it.data() == HAS_WMSAVEYOURSELF ) {
+            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);
+            if ( ( ev.xany.type == UnmapNotify ) ||
+                 ( ev.xany.type == PropertyNotify && ev.xproperty.atom == \
XA_WM_COMMAND ) ) { +                WindowMap::Iterator it = wins.find( \
ev.xany.window ); +                if ( it != wins.end() && it.data() != \
HAS_WMCOMMAND ) { +                    awaiting_replies -= 1;
+                    if ( it.data() != HAS_ERROR )
+                        it.data() = HAS_WMCOMMAND;
+                }
+            }
+        } else {
+            /* Check timeout */
+            int msecs = start.elapsed();
+            if (msecs >= WM_SAVE_YOURSELF_TIMEOUT)
+                break;
+            /* Wait for more events */
+            fd_set fds;
+            FD_ZERO(&fds);
+            int fd = ConnectionNumber(newdisplay);
+            FD_SET(fd, &fds);
+            struct timeval tmwait;
+            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 (WindowMap::Iterator it = wins.begin(); it != wins.end(); ++it) {
+        if (it.data() != HAS_ERROR) {
+            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() ) {
+        if (! sessionId.isEmpty() 
+#ifndef NO_LEGACY_SESSION_MANAGEMENT
+            || ! wmCommand.isEmpty() ) 
+#endif 
+        {
             count++;
             QString n = QString::number(count);
             config->writeEntry( QString("sessionId")+n, sessionId.data() );
-            config->writeEntry( QString("windowRole")+n, windowRole.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() );
@@ -2952,7 +3132,7 @@ void Workspace::storeSession( KConfig* c
             config->writeEntry( QString("sticky")+n, c->isSticky() );
             config->writeEntry( QString("shaded")+n, c->isShade() );
             config->writeEntry( QString("staysOnTop")+n, c->staysOnTop() );
- 	    config->writeEntry( QString("skipTaskbar")+n, c->skipTaskbar() );
+            config->writeEntry( QString("skipTaskbar")+n, c->skipTaskbar() );
         }
     }
     config->writeEntry( "count", count );
@@ -2977,6 +3157,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 );
@@ -3001,6 +3184,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 );
@@ -3021,6 +3205,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();
@@ -3042,6 +3227,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 );
@@ -3056,47 +3242,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.72
diff -u -3 -p -r1.72 workspace.h
--- workspace.h	2001/03/14 10:16:08	1.72
+++ workspace.h	2001/03/19 16:31:08
@@ -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;
@@ -180,6 +179,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