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

List:       kde-bugs-dist
Subject:    Bug#9394: KDE2 session manager does not restart legacy apps (e.g   emacs)
From:       Leon Bottou <leonb () research ! att ! com>
Date:       2001-03-07 1:07:15
[Download RAW message or body]

Matthias Ettrich wrote:
> I don't indent to support the WM_SAVE_YOURSELF protocol again. It's really
> obsolete and its implications are not that easy. I'd rather add a hack to
> restart emacs as emacs.

I had to do it to understand your reservations.

The attached patch saves the correct information 
into the kwin config file.   KWin is then able to 
restart these programs on startup.  Of course it not 
able to recognize the window when it appears on the desktop, 
and not readily able to apply the proper geometry, 
iconification, etc.

But everything works decently when using 
the ``Store Settings'' option in the window 
operations menu!  

I believe that this ``Store Settings'' capability 
makes the patch useful. Let me attempt to overcome your 
reservations with four arguments:

- Compact: only one file (workspace.cpp) is affected in two places.
- Fast: it processes all eligible windows simultaneously.
- Safe: there is a strict timeout: it cannot hang.
- Isolated: everything is done by opening an auxilliary connection 
        to the X server. It does not mess with QT's settings.

Hope it helps.

- Leon Bottou
["workspace.cpp.diff" (text/plain)]

--- workspace.cpp.orig	Tue Mar  6 19:16:17 2001
+++ workspace.cpp	Tue Mar  6 18:45:53 2001
@@ -2888,6 +2888,122 @@
         requestFocus( active );
 }
 
+
+
+/* Helper for Workspace::storeSession
+
+   This function first sends a WM_SAVE_YOURSELF to all eligible windows 
+   among the #count# windows in array #w#.  Then it waits at most #msecs#
+   milliseconds for the application to change in the WM_COMMAND property.
+   The contents of array #w# is destroyed during the call.
+   The function returns the number of replies received.
+ */
+#define HONOR_SAVE_YOURSELF
+#ifdef HONOR_SAVE_YOURSELF
+static int
+saveyourself(Display *dpy, Window *w, int count, long msecs)
+{
+#ifndef X_GETTIMEOFDAY /* From Xos.h */
+#define X_GETTIMEOFDAY(t) gettimeofday(t, 0)
+#endif
+  Display *newdisplay = 0;
+  Atom wm_save_yourself;
+  Atom wm_protocols;
+  int waiting = 0;
+  int replies = 0;
+  Window root;
+  XEvent ev;
+  int i, j;
+  /* Get atoms */
+  wm_save_yourself = XInternAtom(dpy, "WM_SAVE_YOURSELF", False);
+  wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
+  if (!wm_protocols || !wm_save_yourself)
+    return -1;
+  /* Everything is done using a fresh connection to the server! */
+  XSync(dpy, False);
+  newdisplay = XOpenDisplay(DisplayString(dpy));
+  if (!newdisplay) 
+    return -1;  
+  /* Grab mouse and keyboard */
+  root = DefaultRootWindow(newdisplay);
+  XGrabKeyboard(newdisplay, root, False, 
+                GrabModeAsync, GrabModeAsync, CurrentTime);
+  XGrabPointer(newdisplay, root, False, Button1Mask|Button2Mask|Button3Mask,
+               GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
+  /* Send client messages */
+  for (i=0; i<count; i++) {
+    /* Check protocols */
+    Atom *protocols = 0;
+    int nprotocols = 0;
+    XGetWMProtocols(newdisplay, w[i], &protocols, &nprotocols);
+    for (j=0; j<nprotocols; j++)
+      if (protocols[j] == wm_save_yourself)
+        break;
+    XFree((void*) protocols);
+    if (j >= nprotocols)
+      continue;
+    /* Send message */
+    waiting += 1;
+    memset(&ev, 0, sizeof(ev));
+    ev.xclient.type = ClientMessage;
+    ev.xclient.window = w[i];
+    ev.xclient.message_type = wm_protocols;
+    ev.xclient.format = 32;
+    ev.xclient.data.l[0] = wm_save_yourself;
+    ev.xclient.data.l[1] = CurrentTime;
+    XSelectInput(newdisplay, w[i], PropertyChangeMask|StructureNotifyMask);
+    XSendEvent(newdisplay, w[i], False, 0, &ev);
+  }
+  /* Flush */
+  XFlush(newdisplay);
+  /* Wait */
+  while (waiting > 0 && msecs > 0) {
+    if (XPending(newdisplay)) {
+      /* Process pending event */
+      XNextEvent(newdisplay, &ev);
+      for (i=0; i<count; i++)
+        if (ev.xany.window == w[i])
+          break;
+      if (i < count) {
+        if (ev.xany.type == PropertyNotify 
+            && ev.xproperty.atom == XA_WM_COMMAND) {
+          replies += 1;
+          waiting -= 1;
+          w[i] = 0;
+        } else if (ev.type == UnmapNotify) { /* wooow */
+          waiting -= 1;
+          w[i] = 0;
+        }
+      }
+    } 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;
+    }
+  }
+  /* Finished */
+  if (newdisplay) {
+    XAllowEvents(newdisplay, ReplayPointer, CurrentTime);
+    XAllowEvents(newdisplay, ReplayKeyboard, CurrentTime);
+    XSync(newdisplay, False);
+    XCloseDisplay(newdisplay);
+  }
+  XSync(dpy, False);
+  return replies;
+}
+#endif
+
+
 /*!
   Stores the current session in the config file
 
@@ -2895,6 +3011,27 @@
  */
 void Workspace::storeSession( KConfig* config )
 {
+#ifdef HONOR_SAVE_YOURSELF
+    int numClients = clients.count();
+    if (numClients > 0) {
+      Window *w = new Window[numClients];
+      if (w) {
+        numClients = 0;
+        for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it) {
+          Client* c = (*it);
+          if (c->sessionId().isEmpty()) {
+            w[numClients] = c->window();
+            numClients++;
+          }
+        }
+        if (numClients > 0) {
+          saveyourself(qt_xdisplay(), w, numClients, 2000);
+          kapp->processEvents(250); /* Update client list */
+        }
+        delete [] w;
+      }
+    }
+#endif
     config->setGroup("Session" );
     int count =  0;
     for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it) {


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

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