Subject: A layered stacking order patch

From: Matthias Clasen <[email-masked]>
Date: Mon, 18 Jan 1999 19:51:22 +0100

This is a first prototype of a more general reimplementation
of StaysOnTop in the form of layers: 

Every window belongs to a layer. Raise and Lower stay within 
the given layer. There is a new command "Layer rel [abs]" 
for changing layers that parses its arguments like the 
"Desk" command. Initial layers can be assigned via
"Style name Layer n", where n can be any layer index, ie
any nonnegative integer. 

Still to do:
 * special handling of transients in Raise.
 * should transients inherit the layer ?
 * should "Layer" also handle transients specially ?
 * add a condition "Layer n" for selecting only windows
   in a certain layer.
 * get rid of code needed only to maintain StaysOnTop:
    - KeepOnTop can be eliminated
    - the ONTOP and RAISED flags are no longer needed
 * extend GNOME support for layers.

Matthias

--- fvwm-orig/add_window.c	Fri Jan 15 21:55:51 1999
+++ fvwm/add_window.c	Mon Jan 18 12:27:22 1999
@@ -195,6 +195,9 @@
 
   tmp_win->IconBoxes = styles.IconBoxes; /* copy iconboxes ptr (if any) */
   tmp_win->buttons = styles.on_buttons; /* on and off buttons combined. */
+  /* FIXME: shouldn't transients inherit the layer ? */
+  tmp_win->layer = styles.layer;
+
 #ifdef USEDECOR
   /* search for a UseDecor tag in the Style */
   tmp_win->fl = NULL;
@@ -389,7 +392,6 @@
   /* tmp_win->prev points to the last window in the list, tmp_win->next is NULL.
      Now fix the last window to point to tmp_win */
   tmp_win->prev->next = tmp_win;
-
   /*
       RBW - 11/13/1998 - add it into the stacking order chain also.
       This chain is anchored at both ends on Scr.FvwmRoot, there are
@@ -399,8 +401,6 @@
   Scr.FvwmRoot.stack_next->stack_prev = tmp_win;
   tmp_win->stack_prev = &Scr.FvwmRoot;
   Scr.FvwmRoot.stack_next = tmp_win;
-
-
   /* create windows */
   tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->bw;
   tmp_win->frame_y = tmp_win->attr.y + tmp_win->old_bw - tmp_win->bw;
@@ -1149,5 +1149,9 @@
   if(nptr->IconBoxes != NULL) {         /* If style has iconboxes */
     styles->IconBoxes = nptr->IconBoxes; /* copy it */
   }
+  /* FIXME: must have a flag */
+ if (nptr->layer != 0) {
+   styles->layer = nptr->layer;
+ }
   return;                               /* return */
 }
--- fvwm-orig/builtins.c	Sat Jan 16 21:54:50 1999
+++ fvwm/builtins.c	Mon Jan 18 19:09:36 1999
@@ -4852,3 +4852,64 @@
     rgpctMovementDefault[i++] = 1.0;
   }
 }
+
+void list_layers()
+{
+  FvwmWindow *t;
+
+  puts("layers: ");
+  for (t = Scr.FvwmRoot.stack_next; t != &Scr.FvwmRoot; t = t->stack_next)
+    {
+        printf("%s %d ", t->name, t->layer);
+    }
+  putchar('\n');
+}
+
+void change_layer(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+		  unsigned long context, char *action,int* Module)
+{
+  int n, layer, val[2];
+  
+  if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
+    return;
+  
+  if(tmp_win == NULL)
+    return;
+
+  n = GetIntegerArguments(action, NULL, val, 2);
+
+  layer = tmp_win->layer;
+  if ((n == 1) || 
+      ((n == 2) && (val[0] != 0))) 
+    {
+      layer += val[0];
+    }
+  else if (n == 2)
+    {
+      layer = val[1];
+    }
+
+  if (layer < 0) 
+    {
+      layer = 0;
+    } 
+
+  if (layer < tmp_win->layer)
+    {
+      DBUG("Layer", "putting %s at top of layer %d\n",
+	     tmp_win->name, layer);
+      tmp_win->layer = layer;
+      RaiseWindow(tmp_win);
+    } 
+  else if (layer > tmp_win->layer)
+    {
+      /* FIXME: If we want to keep transients above, have
+         to take special action here */
+      DBUG("Layer", "putting %s at bottom of layer %d\n",
+	     tmp_win->name, layer);
+      tmp_win->layer = layer;
+      LowerWindow(tmp_win);
+    } 
+ list_layers();
+}
+
--- fvwm-orig/events.c	Sat Jan 16 21:54:51 1999
+++ fvwm/events.c	Mon Jan 18 13:05:59 1999
@@ -1388,10 +1388,33 @@
                     (XFindContext (dpy, cre->above, FvwmContext,
                                    (caddr_t *) &otherwin) == XCSUCCESS))
                    ? otherwin->frame : cre->above);
+    /* we only allow clients to restack their windows within
+       their layer. Thus we don't handle TopIf, BottomIf or
+       Opposite modes. We could perhaps allow them and then 
+       catch windows that have gone off to the end of the stack
+       and bring them back to the layer, but who cares ? Nobody will 
+       use these modes anyway. 
+    */
+    if (!(cre->value_mask & CWSibling)) 
+      {
+         switch (cre->detail) 
+           {
+            case Above: 
+              RaiseWindow (Tmp_win);
+              break;
+            case Below:
+              LowerWindow (Tmp_win);
+              break;
+           }
+      }
+    else if (otherwin && 
+	(otherwin->layer == Tmp_win->layer) &&
+	((cre->detail == Above) || (cre->detail == Below)))
+      {
     xwc.stack_mode = cre->detail;
     XConfigureWindow (dpy, Tmp_win->frame,
                       cre->value_mask & (CWSibling | CWStackMode), &xwc);
-DB(("HandleConfigureRequest: reconfiguring frame window 0x%x for CWSibling|CWStackMode (sendEvent enabled)", Tmp_win->frame));
+	DB(("HandleConfigureRequest: reconfiguring frame window 0x%x for CWSibling|CWStackMode (sendEvent enabled)", Tmp_win->frame));
     sendEvent = True;
 
     /*
@@ -1427,6 +1450,7 @@
         ResyncFvwmStackRing();
       }
   }
+  }
 
 #ifdef SHAPE
   if (ShapesSupported)
--- fvwm-orig/functions.c	Sat Jan 16 20:47:09 1999
+++ fvwm/functions.c	Mon Jan 18 11:16:58 1999
@@ -1,4 +1,3 @@
-e
 /****************************************************************************
  * This module is all original code
  * by Rob Nation
@@ -118,6 +117,7 @@
   {"IconPath",     setIconPath,      F_ICON_PATH,           FUNC_NO_WINDOW},
   {"Key",          ParseKeyEntry,    F_KEY,                 FUNC_NO_WINDOW},
   {"KillModule",   module_zapper,    F_ZAP,                 FUNC_NO_WINDOW},
+  {"Layer",        change_layer,     F_LAYER,               FUNC_NEEDS_WINDOW},
   {"Lower",        lower_function,   F_LOWER,               FUNC_NEEDS_WINDOW},
   {"Maximize",     Maximize,         F_MAXIMIZE,            FUNC_NEEDS_WINDOW},
   {"Menu",         staysup_func,     F_STAYSUP,             FUNC_NO_WINDOW},
--- fvwm-orig/fvwm.c	Sat Jan 16 02:46:18 1999
+++ fvwm/fvwm.c	Mon Jan 18 13:06:22 1999
@@ -420,7 +420,6 @@
   Scr.gray_bitmap =
     XCreateBitmapFromData(dpy,Scr.Root,g_bits, g_width,g_height);
 
-#define DBUG(x, y) printf("%s: %s\n", x,y );
   DBUG("main","Setting up rc file defaults...");
   SetRCDefaults();
 
@@ -1301,6 +1300,7 @@
   /*  RBW - 11/13/1998 - 2 new fields to init - stacking order chain.  */
   Scr.FvwmRoot.stack_next  =  &Scr.FvwmRoot;
   Scr.FvwmRoot.stack_prev  =  &Scr.FvwmRoot;
+  Scr.FvwmRoot.layer = -1; 
 
   XGetWindowAttributes(dpy,Scr.Root,&(Scr.FvwmRoot.attr));
   Scr.root_pushes = 0;
@@ -1393,7 +1393,6 @@
   Scr.gs.EmulateWIN = False;
   /* Not the right place for this, should only be called once somewhere .. */
   InitPictureCMap(dpy,Scr.Root);
-
   return;
 }
 
--- fvwm-orig/fvwm.h	Sat Jan 16 21:54:51 1999
+++ fvwm/fvwm.h	Mon Jan 18 10:42:54 1999
@@ -275,6 +275,7 @@
     Pixel BackPixel;
     unsigned long buttons;
     icon_boxes *IconBoxes;              /* zero or more iconboxes */
+  int layer;
 } FvwmWindow;
 
 /* Window mask for Circulate and Direction functions */
--- fvwm-orig/misc.c	Fri Jan 15 22:06:26 1999
+++ fvwm/misc.c	Mon Jan 18 19:08:40 1999
@@ -799,34 +799,10 @@
   XSync(dpy,0);
 }
 
-
-
-/****************************************************************************
- *
- * Keeps the "StaysOnTop" windows on the top of the pile.
- * This is achieved by clearing a flag for OnTop windows here, and waiting
- * for a visibility notify on the windows. Exeption: OnTop windows which are
- * obscured by other OnTop windows, which need to be raised here.
- *
- ****************************************************************************/
 void KeepOnTop()
 {
-  FvwmWindow *t;
-
-  /* flag that on-top windows should be re-raised */
-  for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
-    {
-      if((t->flags & ONTOP)&&!(t->flags & VISIBLE))
-	{
-	  RaiseWindow(t);
-	  t->flags &= ~RAISED;
-	}
-      else
-	t->flags |= RAISED;
-    }
 }
 
-
 /**************************************************************************
  *
  * Unmaps a window on transition to a new desktop
@@ -879,174 +855,128 @@
    }
 }
 
-
-
+void list_layers(void);
 
 void RaiseWindow(FvwmWindow *t)
 {
-  FvwmWindow *t2;
-  int count, i;
-  Window *wins;
+  FvwmWindow *s;
+  unsigned int flags;
+  int i;
   XWindowChanges changes;
-  FvwmWindow *t1;
-  FvwmWindow **FvwmTopwins = NULL;
-  int j, count2;
-
 
-  memset((void *) &changes, '\0', sizeof(changes));
-  /* raise the target, at least */
-  count = 1;
-  BroadcastPacket(M_RAISE_WINDOW, 3, t->w, t->frame, (unsigned long)t);
+  Scr.LastWindowRaised = t;
 
-  for (t2 = Scr.FvwmRoot.stack_next; t2 != &Scr.FvwmRoot; t2 = t2->stack_next)
+  for (s = Scr.FvwmRoot.stack_next; s != &Scr.FvwmRoot; s = s->stack_next)
     {
-      if(t2->flags & ONTOP)
-	count++;
-      if((t2->flags & TRANSIENT) &&(t2->transientfor == t->w)&&
-	 (t2 != t))
+       if ((t != s) && (t->layer >= s->layer))
 	{
-	  count++;
-	  BroadcastPacket(M_RAISE_WINDOW, 3,
-                          t2->w, t2->frame,(unsigned long) t2);
-	  if ((t2->flags & ICONIFIED)&&(!(t2->flags & SUPPRESSICON)))
-	    {
-	      count += 2;
-	    }
+	      break;
 	}
     }
-  if ((t->flags & ICONIFIED)&&(!(t->flags & SUPPRESSICON)))
+
+  if (s == t->stack_next) 
     {
-      count += 2;
+      puts("RaiseWindow: nothing to do\n");
+      return;
     }
 
-  wins = (Window *)safemalloc(count*sizeof(Window));
-  FvwmTopwins = (FvwmWindow **)safemalloc(count*sizeof(FvwmWindow));
+  BroadcastPacket(M_RAISE_WINDOW, 3, t->w, t->frame, (unsigned long)t);
 
-  i=0;
-  j = 0;
-  count2 = 0;
+  /* now we know above which window to raise */
+  DBUG("RaiseWindow", "raising %s in layer %d above %s", 
+       t->name, t->layer, s->name);
+
+  /* FIXME: If we want to keep transients above, we
+     must collect transients for t in its layer here
+     and restack them above t */
 
-  /* ONTOP windows on top */
-  for (t2 = Scr.FvwmRoot.stack_next; t2 != &Scr.FvwmRoot; t2 = t2->stack_next)
-    {
-      if(t2->flags & ONTOP)
+  changes.sibling = s->frame;
+  if (changes.sibling != None)
 	{
-	  BroadcastPacket(M_RAISE_WINDOW, 3,
-                          t2->w, t2->frame, (unsigned long) t2);
-	  wins[i++] = t2->frame;
-          FvwmTopwins[j++] = t2;
+      changes.stack_mode = Above;
+      flags = CWSibling|CWStackMode;
 	}
+  else 
+    {
+      changes.stack_mode = Below;
+      flags = CWStackMode;
     }
 
-  /* now raise transients */
-#ifndef DONT_RAISE_TRANSIENTS
-  for (t2 = Scr.FvwmRoot.stack_next; t2 != &Scr.FvwmRoot; t2 = t2->stack_next)
-  {
-    if((t2->flags & TRANSIENT) &&
-       (t2->transientfor == t->w) &&
-       (t2 != t) &&
-       (!(t2->flags & ONTOP)))
-    {
-      wins[i++] = t2->frame;
-      FvwmTopwins[j++] = t2;
-      if ((t2->flags & ICONIFIED)&&(!(t2->flags & SUPPRESSICON)))
+  XConfigureWindow (dpy, t->frame, flags, &changes);
+
+  t->stack_prev->stack_next = t->stack_next;            
+  t->stack_next->stack_prev = t->stack_prev;
+
+  t->stack_next = s;
+  t->stack_prev = s->stack_prev; 
+  t->stack_prev->stack_next = t;
+  t->stack_next->stack_prev = t;
+
+  /* This should be unnecessary, since we never 
+     do an unguarded XRaiseWindow */
+  raisePanFrames();  
+  
+  list_layers();
+}
+
+
+void LowerWindow(FvwmWindow *t)
+{
+  FvwmWindow *s;
+  XWindowChanges changes;
+  int i;
+  unsigned int flags;
+  
+  Scr.LastWindowRaised = NULL;
+
+  for (s = Scr.FvwmRoot.stack_next; s != &Scr.FvwmRoot; s = s->stack_next)
       {
-        if(!(t2->flags & NOICON_TITLE))
-          wins[i++] = t2->icon_w;
-        if(!(t2->icon_pixmap_w))
-          wins[i++] = t2->icon_pixmap_w;
-      }
-    }
-  }
-#endif
-  if ((t->flags & ICONIFIED)&&(!(t->flags & SUPPRESSICON)))
+       if (t->layer > s->layer)
   {
-    if(!(t->flags & NOICON_TITLE))
-      wins[i++] = t->icon_w;
-    if (t->icon_pixmap_w)
-      wins[i++] = t->icon_pixmap_w;
+	      break;
   }
-  if(!(t->flags & ONTOP))
-    {
-      wins[i++] = t->frame;
-      FvwmTopwins[j++] = t;
-      Scr.LastWindowRaised = t;
     }
-  count2 = j;
 
-  if(i > 0)
+  if (s == t->stack_next)
     {
-/*      XRaiseWindow(dpy,wins[0]);  */
-      /*
-           [email-masked] - 01/01/1999 - 
-         simply calling XRaiseWindow(dpy,wins[0]); here will put StaysOnTop
-         windows over override_redirect windows like FvwmPager ballon_win or
-         Motif menus. Instead raise wins[0] only above the topmost window
-	 which is managed by us. 
-      */
-     if (wins[0] != Scr.FvwmRoot.stack_next->frame) 
-      { 
-        changes.sibling = Scr.FvwmRoot.stack_next->frame;
-        changes.stack_mode = Above;
-        XConfigureWindow(dpy, wins[0], (CWSibling|CWStackMode), &changes);
+      DBUG("LowerWindow", "nothing to do");
+      return;
       }
 
+  BroadcastPacket(M_LOWER_WINDOW, 3, t->w, t->frame, (unsigned long)t);
 
-      /*
-          RBW  - 01/05/1998 - move all raised windows to front of stacking
-          order chain.
-      */
-      j = 0;
-      t2 = &Scr.FvwmRoot;
-      while (j < count2)
-        {
-          t1 = FvwmTopwins[j];
-	  if (t1 != t2->stack_next)
+  DBUG("LowerWindow", "raising %s in layer %d above %s\n", 
+       t->name, t->layer, s->name);
+  
+  changes.sibling = s->frame;
+  if (changes.sibling != None)
             {
-              t1->stack_prev->stack_next = t1->stack_next;  /* Pluck from chain.       */
-              t1->stack_next->stack_prev = t1->stack_prev;
-              t1->stack_next = t2->stack_next;    /* Set new pointers.       */
-              t1->stack_prev = t2->stack_next->stack_prev;
-              t2->stack_next->stack_prev = t1;    /* Insert in new position in chain. */
-              t2->stack_next = t1;
+      changes.stack_mode = Above;
+      flags = CWSibling|CWStackMode;
             }
-          j++;
-          if (t2->stack_next != &Scr.FvwmRoot)
+  else 
           {
-	    t2 = t2->stack_next;
-          }
-        }
-
+      changes.stack_mode = Below;
+      flags = CWStackMode;
     }
 
-  XRestackWindows(dpy,wins,i);
-  free(wins);
-  if (FvwmTopwins) free(FvwmTopwins);
-  raisePanFrames();
-}
-
-
-void LowerWindow(FvwmWindow *t)
-{
-  XLowerWindow(dpy,t->frame);
-
-  BroadcastPacket(M_LOWER_WINDOW, 3, t->w, t->frame, (unsigned long)t);
+  XConfigureWindow(dpy, t->frame, flags, &changes);
 
   if((t->flags & ICONIFIED)&&(!(t->flags & SUPPRESSICON)))
     {
-      XLowerWindow(dpy, t->icon_w);
-      XLowerWindow(dpy, t->icon_pixmap_w);
+      XConfigureWindow(dpy, t->icon_w, flags, &changes);
+      XConfigureWindow(dpy, t->icon_pixmap_w, flags, &changes);
     }
-  Scr.LastWindowRaised = (FvwmWindow *)0;
-  /*
-      RBW - 11/13/1998 - new: maintain the stacking order chain.
-  */
-  t->stack_prev->stack_next = t->stack_next;            /* Pluck from chain.       */
+  
+  t->stack_prev->stack_next = t->stack_next;            
   t->stack_next->stack_prev = t->stack_prev;
-  t->stack_next = Scr.FvwmRoot.stack_prev->stack_next;  /* Set new pointers.       */
-  t->stack_prev = Scr.FvwmRoot.stack_prev;
-  Scr.FvwmRoot.stack_prev->stack_next = t;              /* Insert at end of chain. */
-  Scr.FvwmRoot.stack_prev = t;
+
+  t->stack_next = s;
+  t->stack_prev = s->stack_prev; 
+  t->stack_prev->stack_next = t;
+  t->stack_next->stack_prev = t;
+
+  list_layers();
 }

--- fvwm-orig/misc.h	Sat Jan 16 20:47:09 1999
+++ fvwm/misc.h	Mon Jan 18 13:08:07 1999
@@ -45,7 +45,7 @@
   icon_boxes *IconBoxes;                /* pointer to iconbox(s) */
   unsigned long on_buttons;
   unsigned long off_buttons;
-
+  int layer;
 } name_list;
 
 /* used for parsing configuration */
@@ -474,6 +474,8 @@
 void SetEnv(F_CMD_ARGS);
 
 void CoerceEnterNotifyOnCurrentWindow();
+
+void change_layer(F_CMD_ARGS);
 
 /*
 ** message levels for fvwm_msg:
--- fvwm-orig/parse.h	Sat Jan 16 20:47:09 1999
+++ fvwm/parse.h	Mon Jan 18 11:15:52 1999
@@ -86,7 +86,7 @@
     F_DFLT_COLORS,
     F_GLOBAL_OPTS,
     F_EMULATE,
-
+    F_LAYER,
     F_RESIZE = 100,
     F_RAISE,
     F_LOWER,
--- fvwm-orig/style.c	Fri Jan 15 22:07:29 1999
+++ fvwm/style.c	Mon Jan 18 10:45:54 1999
@@ -488,6 +488,16 @@
           SKIP("LENIENCE");
           tname.off_flags |= LENIENCE_FLAG;
         }
+	else if (ITIS("LAYER"))
+	  {
+	    SKIP("LAYER");
+	    sscanf(restofline,"%d",&tname.layer);
+	    if(tname.layer < 0)
+	      fvwm_msg(ERR,"ProcessNewStyle", "Layer must be non-negative." );
+	    GETWORD;
+	    restofline = tmp;
+	    SKIPSPACE;
+	  }
         break;
       case 'm':
         if(ITIS("MWMBUTTONS"))

-- 
Matthias Clasen, 
Tel. 0761/203-5606
Email: [email-masked]
Mathematisches Institut, Albert-Ludwigs-Universitaet Freiburg
--
Visit the official FVWM web page at <URL:http://fvwm.math.uh.edu/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked].

---

From: Jay Painter <[email-masked]>
Date: Mon, 18 Jan 1999 11:31:30 -0800 (PST)

Wonderful!  I'll include this in my next GNOME patch with layers support!
I also want to let everyone know that I've abandoned work on older
versions of fvwm, as I started noticing bugs I didn't want to fix ;)

-----------------------------------------------------------------------
Jay Painter -- [email-masked] -- [email-masked] -- [email-masked]
http://www.serv.net/~jpaint/

---

From: [email-masked] (Paul D. Smith)
Date: 18 Jan 1999 14:48:09 -0500

Please be aware that these changes are not going to be included with
fvwm 2.2; that version is in feature-freeze (in fact, we hope it's damn
near released) and you won't see these kinds of changes in the source
tree until after that (except maybe on a private branch).

People like Matthias are working on extremely cool "future stuff" like
layers but it's not clear what the release schedule beyond 2.2 will be
or what the goals for 2.4 will be--I know one definite feature for 2.4
is the GSFR but we don't know what else might be in there yet.

I'm not sure what your intent is for the GNOME stuff, so just FYI.

-- 
-------------------------------------------------------------------------------
 Paul D. Smith <[email-masked]>         Network Management Development
 "Please remain calm...I may be mad, but I am a professional." --Mad Scientist
-------------------------------------------------------------------------------
   These are my opinions---Nortel Networks takes no responsibility for them.
--
Visit the official FVWM web page at <URL:http://fvwm.math.uh.edu/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked].

---

From: Dominik Vogt <[email-masked]>
Date: Tue, 19 Jan 1999 01:05:12 +0100

> tree until after that (except maybe on a private branch).

Yes. Matthias, please don't misunderstand me, I don't want to
stop you making enhancements. But at the current time nobody
except yourself will be able to apply them. They overlap each
other more or less and we will need *you* to merge the patches
that will be included into a single patch. Currently I'm
collecting all the patches that don't go into 2.2 and I'm
losing track fast. I Can't possibly remember all the discussions
about the various patches.

> is the GSFR but we don't know what else might be in there yet.

The first two things can only be (in my eyes):

1) Incorporate the unapplied patches

2) GSFR

Then we should make a beta 2.3.1 extremely fast so we can
tell people to write patches for this one and not 2.2.

Apart from this I'd love to take up Steve's offer from
October and pass the 'pumpking' to him right after 2.2 (and
let him apply all these patches - about twenty or so :-b ).

Bye

Dominik

--
Dominik Vogt, [email-masked]
Reply-To: [email-masked]

---

From: Matthias Clasen <[email-masked]>
Date: Tue, 19 Jan 1999 09:46:01 +0100

> about the various patches.

I'm fully aware of that. The reason I don't wait till after 2.2
is that I have the energy now, don't know how long that will last...
I don't expect you or any post-2.2 maintainer to sort out all my
patches. I just wanted to demonstrate some possible directions for
post-2.2 work and I think sending working (well if you can get
them to apply) patches seems to be a nicer way to do this than just 
shouting "Fvwm should do this or that". 

After 2.2, I will go over my pending patches and propose them again,
one by one. And I won't send any more till then - I'm out of ideas  :-) 

Matthias