Subject: Fancy Titlebars, Mark 3

From: Suzanne Britton <[email-masked]>
Date: Wed, 10 Oct 2001 03:16:09 -0400

Here's the latest incarnation of the spiffy titlebars patch. It's not yet
guaranteed stable or in its final form, but it's getting there. This one was
generated against 2.4.3. It fixes a silly crashing bug and changes to a new
position-independent format for the MultiPixmap TitleStyle.

There are ten pixmaps, all of which are optional except for Main (or, define
both LeftMain and RightMain):

Main                      - tiled all the way across before anything else
LeftMain, RightMain       - tiled on the left and right sides of the title
                            (if titleless and no Main, LeftMain is tiled all
                            the way across)
UnderText                 - tiled underneath the title text
LeftButtons, RightButtons - tiled underneath left and right buttons in case of
                            ButtonStyle -- UseTitleStyle
                            (if not specified, LeftMain/RightMain is used, if
                             that isn't specified, Main is used)
LeftEnd, RightEnd         - Non-tiled pixmaps for the far ends of the titlebar
                            (just before the buttons)
LeftOfText, RightOfText   - Non-tiled pixmaps for left and right ends of text

This may sound daunting, but there's very little overhead for a decor if
TitleStyle MultiPixmap isn't used (and 0 overhead if #undef FANCY_TITLEBARS,
of course). Just a single unallocated Picture** pointer.

The new config syntax is:
  MultiPixmap <pic name> <filepath>, <pic name> <filepath>, ...

Since the syntax is no longer position-dependent, you don't have to include
any "placeholders" for pixmaps you don't use.

Stretching instead of tiling isn't implemented yet (config syntax?). Mikhael's
request for a way to have nothing tiled under title text is implemented in a
sneaky way: specify LeftMain and RightMain instead of Main. It would be great
if any brave prospective users of this patch could test it a bit, since I no
longer personally use all of the features present :-)

Final note: I notice the parameter left1right0 to DrawButton (in borders.c),
which is supposed to indicate which side the button is on, goes unused:
RedrawButtons always passes 1! Since I need to know which side in order to
handle UseTitleStyle correctly, I fixed this. If that's a problem, lemme know.

Suzanne

-- 
[email-masked] - http://www.igs.net/~tril/
"I'm aware of that, sweetheart. It's just that when I wake up to a hissing
goat skull on my nightstand, and it hops off and runs across the floor on
spider legs, I sleep a lot better knowing where it ran off to."
                                                          - Ted (Red Meat)
--- ChangeLog.orig	Wed Oct 10 01:26:04 2001
+++ ChangeLog	Wed Oct 10 01:17:28 2001
@@ -1,3 +1,32 @@
+2001-10-10  Suzanne Britton  <[email-masked]>
+
+	* config.h.in: Added FANCY_TITLEBARS option, off by default
+
+	* fvwm/screen.h:
+	[All changes #ifdeffed FANCY_TITLEBARS]
+	Added TITLE_PADDING define for fancy titlebar rendering
+	Added tb_pixmap_enum
+	Added MultiPixmap to DecorFaceType enum
+	Added Picture **multi_pixmaps to DecorFace structure
+
+	* fvwm/borders.c:
+	[All changes #ifdeffed FANCY_TITLEBARS]
+	(DrawButton): Handle UseTitleStyle where TitleStyle is MultiPixmap
+	(TileIntoWindow): [new]
+	(DrawMultiPixmapTitlebar): [new]
+	(RedrawButtons): Pass the left1right0 parameter properly to DrawButton,
+	instead of always sending 1
+	(RedrawTitle):
+	Call DrawFancyTitlebar for MultiPixmap style
+	Skip DrawString calls for MultiPixmap style (title is drawn inside
+	DrawMultiPixmapTitlebar)
+
+	* fvwm/builtins.c:
+	[All changes #ifdeffed FANCY_TITLEBARS]
+	(FreeDecorFace): Free up multi_pixmaps array for a MultiPixmap decor
+	(ReadDecorFace): Call ReadMultiPixmapDecor for a MultiPixmap TitleStyle
+	(ReadMultiPixmapDecor): [new]
+
 2001-10-08  olicha  <[email-masked]>
 
 	* fvwm/borders.c (RedrawTitle):
--- AUTHORS.orig	Wed Oct 10 01:25:58 2001
+++ AUTHORS	Wed Oct 10 01:15:06 2001
@@ -182,6 +182,8 @@
 Echo. Improve modules: Make FvwmM4 pass args on to m4, font-related
 seg-fault bug fix in FvwmButtons.
 
+Suzanne Britton:
+Multi-pixmap titlebars patch.
 
 Along with a cast of thousands (well, dozens) mentioned in old
 ChangeLog entries.  If you find your name below, please send an entry
--- config.h.in.orig	Wed Oct 10 01:26:19 2001
+++ config.h.in	Wed Oct 10 01:15:06 2001
@@ -2,6 +2,9 @@
 /* Suffix for config filenames */
 #define FVWMRC ".fvwm2rc"
 
+/* Define for fancy, multi-pixmap-themeable titlebars */
+#undef FANCY_TITLEBARS
+
 /* Define if gdk-imlib is used */
 #undef GDK_IMLIB
 
--- fvwm/screen.h.orig	Wed Oct 10 01:26:43 2001
+++ fvwm/screen.h	Wed Oct 10 01:15:06 2001
@@ -54,6 +54,13 @@
 #define COLORMAP_FOLLOWS_MOUSE 1 /* default */
 #define COLORMAP_FOLLOWS_FOCUS 2
 
+#ifdef FANCY_TITLEBARS
+#define TITLE_PADDING 5
+enum tb_pixmap_enum {TBP_MAIN, TBP_LEFT_MAIN, TBP_RIGHT_MAIN, TBP_UNDER_TEXT,
+                     TBP_LEFT_OF_TEXT, TBP_RIGHT_OF_TEXT, TBP_LEFT_END,
+                     TBP_RIGHT_END, TBP_LEFT_BUTTONS, TBP_RIGHT_BUTTONS,
+                     NUM_TB_PIXMAPS};
+#endif
 
 typedef struct
 {
@@ -70,6 +77,9 @@
     GradientButton              ,
     PixmapButton                ,
     TiledPixmapButton           ,
+#ifdef FANCY_TITLEBARS
+    MultiPixmap                 ,
+#endif
 #ifdef MINI_ICONS
     MiniIconButton              ,
 #endif
@@ -123,6 +133,9 @@
   struct
   {
     Picture *p;
+#ifdef FANCY_TITLEBARS
+    Picture **multi_pixmaps;
+#endif
     Pixel back;
     struct
     {
--- fvwm/borders.c.orig	Wed Oct 10 01:26:50 2001
+++ fvwm/borders.c	Wed Oct 10 01:15:06 2001
@@ -271,10 +271,27 @@
   case MiniIconButton:
   case PixmapButton:
   case TiledPixmapButton:
+#ifdef FANCY_TITLEBARS
+  case MultiPixmap:       /* in case of UseTitleStyle */
+#endif
     if (type == PixmapButton || type == TiledPixmapButton)
     {
       p = df->u.p;
     }
+#ifdef FANCY_TITLEBARS
+    else if (type == MultiPixmap) {
+      if (left1right0 && df->u.multi_pixmaps[TBP_LEFT_BUTTONS])
+        p = df->u.multi_pixmaps[TBP_LEFT_BUTTONS];
+      else if (!left1right0 && df->u.multi_pixmaps[TBP_RIGHT_BUTTONS])
+        p = df->u.multi_pixmaps[TBP_RIGHT_BUTTONS];
+      else if (left1right0 && df->u.multi_pixmaps[TBP_LEFT_MAIN])
+        p = df->u.multi_pixmaps[TBP_LEFT_MAIN];
+      else if (!left1right0 && df->u.multi_pixmaps[TBP_RIGHT_MAIN])
+        p = df->u.multi_pixmaps[TBP_RIGHT_MAIN];
+      else
+        p = df->u.multi_pixmaps[TBP_MAIN];
+    }
+#endif
     else
     {
       if (!t->mini_icon)
@@ -298,6 +315,9 @@
     if (is_lowest && !p->mask && pbutton_background_pixmap)
     {
       if (type == TiledPixmapButton ||
+#ifdef FANCY_TITLEBARS
+          type == MultiPixmap ||
+#endif
 	  (p && p->width >= width && p->height >= height))
       {
 	/* better performance: set a background pixmap if possible, i.e. if the
@@ -326,7 +346,11 @@
 	XClearWindow(dpy, win);
       }
     }
-    if (type != TiledPixmapButton)
+    if (type != TiledPixmapButton
+#ifdef FANCY_TITLEBARS
+        && type != MultiPixmap
+#endif
+       )
     {
       if (DFS_H_JUSTIFICATION(df->style) == JUST_RIGHT)
 	x += (int)(width - p->width);
@@ -354,7 +378,11 @@
 
     XSetClipMask(dpy, Scr.TransMaskGC, p->mask);
     XSetClipOrigin(dpy, Scr.TransMaskGC, x, y);
-    if (type != TiledPixmapButton)
+    if (type != TiledPixmapButton
+#ifdef FANCY_TITLEBARS
+        && type != MultiPixmap
+#endif
+       )
     {
       int cx = x;
       int cy = y;
@@ -448,6 +476,155 @@
   return;
 }
 
+#ifdef FANCY_TITLEBARS
+
+/****************************************************************************
+ *
+ *  Tile src into dest, starting at the given location and continuing for
+ *  the given width and height. This is a utility function used by
+ *  DrawMultiPixmapTitlebar. ([email-masked])
+ *
+ ****************************************************************************/
+static void TileIntoWindow(GC gc, Picture *src, Window dest, int x_start,
+                           int y_start, int width, int height)
+{
+  Pixmap pm = CreateTiledPixmap(dpy, src->picture, src->width, src->height,
+                                width, height, src->depth, gc);
+  XCopyArea(dpy, pm, dest, gc, 0, 0, width, height, x_start, y_start);
+  XFreePixmap(dpy, pm);
+}
+
+/****************************************************************************
+ *
+ *  Redraws multi-pixmap titlebar ([email-masked])
+ *
+ ****************************************************************************/
+static void DrawMultiPixmapTitlebar(FvwmWindow *window, DecorFace *df)
+{
+  Window       title_win;
+  GC           gc;
+  const char  *title;
+  int          title_width, title_height, text_width, text_offset, text_y_pos;
+  int          left_space, right_space, under_offset, under_width;
+  int          state;
+  mwm_flags    state_flags;
+  Bool         toggled;
+  Picture    **pm;
+  Picture     *main_pm;
+  Pixmap      *p;
+
+  pm = df->u.multi_pixmaps;
+  gc = Scr.TitleGC;
+  XSetClipMask(dpy, gc, None);
+  title_win = window->title_w;
+  title = window->name;
+  title_width = window->title_g.width;
+  title_height = window->title_g.height;
+
+  if (pm[TBP_MAIN])
+    TileIntoWindow(gc, pm[TBP_MAIN], title_win, 0, 0, title_width,
+                   title_height);
+  else if (!title)
+    TileIntoWindow(gc, pm[TBP_LEFT_MAIN], title_win, 0, 0, title_width,
+                   title_height);
+
+  if (title) {
+#ifdef I18N_MB
+    text_width = XmbTextEscapement(window->title_font.fontset, title,
+                                   strlen(title));
+#else
+    text_width = XTextWidth(window->title_font.font, title, strlen(title));
+#endif
+    if (text_width > title_width)
+      text_width = title_width;
+    switch (TB_JUSTIFICATION(GetDecor(window, titlebar))) {
+    case JUST_LEFT:
+      text_offset = TITLE_PADDING;
+      if (pm[TBP_LEFT_OF_TEXT])
+        text_offset += pm[TBP_LEFT_OF_TEXT]->width;
+      if (pm[TBP_LEFT_END])
+        text_offset += pm[TBP_LEFT_END]->width;
+      if (text_offset > title_width - text_width)
+        text_offset = title_width - text_width;
+      break;
+    case JUST_RIGHT:
+      text_offset = title_width - text_width - TITLE_PADDING;
+      if (pm[TBP_RIGHT_OF_TEXT])
+        text_offset -= pm[TBP_RIGHT_OF_TEXT]->width;
+      if (pm[TBP_RIGHT_END])
+        text_offset -= pm[TBP_RIGHT_END]->width;
+      if (text_offset < 0)
+        text_offset = 0;
+      break;
+    default:
+      text_offset = (title_width - text_width) / 2;
+      break;
+    }
+    under_offset = text_offset;
+    under_width = text_width;
+    /* If there's title padding, put it *inside* the undertext area: */
+    if (under_offset >= TITLE_PADDING) {
+      under_offset -= TITLE_PADDING;
+      under_width += TITLE_PADDING;
+    }
+    if (under_offset + under_width + TITLE_PADDING <= title_width)
+      under_width += TITLE_PADDING;
+    left_space = under_offset;
+    right_space = title_width - left_space - under_width;
+
+    if (pm[TBP_LEFT_MAIN] && left_space > 0)
+      TileIntoWindow(gc, pm[TBP_LEFT_MAIN], title_win, 0, 0, left_space,
+                     title_height);
+    if (pm[TBP_RIGHT_MAIN] && right_space > 0)
+      TileIntoWindow(gc, pm[TBP_RIGHT_MAIN], title_win,
+                     under_offset + under_width, 0, right_space, title_height);
+    if (pm[TBP_UNDER_TEXT] && under_width > 0)
+      TileIntoWindow(gc, pm[TBP_UNDER_TEXT], title_win, under_offset, 0,
+                     under_width, title_height);
+    if (pm[TBP_LEFT_OF_TEXT] &&
+        pm[TBP_LEFT_OF_TEXT]->width <= left_space) {
+      XCopyArea(dpy, pm[TBP_LEFT_OF_TEXT]->picture, title_win, gc, 0, 0,
+                pm[TBP_LEFT_OF_TEXT]->width, title_height,
+                under_offset - pm[TBP_LEFT_OF_TEXT]->width, 0);
+      left_space -= pm[TBP_LEFT_OF_TEXT]->width;
+    }
+    if (pm[TBP_RIGHT_OF_TEXT] &&
+        pm[TBP_RIGHT_OF_TEXT]->width <= right_space) {
+      XCopyArea(dpy, pm[TBP_RIGHT_OF_TEXT]->picture, title_win, gc, 0, 0,
+                pm[TBP_RIGHT_OF_TEXT]->width, title_height,
+                under_offset + under_width, 0);
+      right_space -= pm[TBP_RIGHT_OF_TEXT]->width;
+    }
+
+    text_y_pos = title_height
+                 - (title_height - window->title_font.font->ascent) / 2
+                 - 1;
+    if (title_height > 19)
+      text_y_pos--;
+    if (text_y_pos < 0)
+      text_y_pos = 0;
+#ifdef I18N_MB
+    XmbDrawString(dpy, title_win, window->title_font.fontset, gc, text_offset,
+                  gc, text_offset, text_y_pos, title, strlen(title));
+#else
+    XDrawString(dpy, title_win, gc, text_offset, text_y_pos, title,
+                strlen(title));
+#endif
+  }
+  else
+    left_space = right_space = title_width;
+
+  if (pm[TBP_LEFT_END] && pm[TBP_LEFT_END]->width <= left_space)
+    XCopyArea(dpy, pm[TBP_LEFT_END]->picture, title_win, gc, 0, 0,
+              pm[TBP_LEFT_END]->width, title_height, 0, 0);
+  if (pm[TBP_RIGHT_END] && pm[TBP_RIGHT_END]->width <= right_space)
+    XCopyArea(dpy, pm[TBP_RIGHT_END]->picture, title_win, gc, 0, 0,
+              pm[TBP_RIGHT_END]->width, title_height,
+              title_width - pm[TBP_RIGHT_END]->width, 0);
+}
+
+#endif /* FANCY_TITLEBARS */
+
 /* rules to get button state */
 static enum ButtonState get_button_state(
   Bool has_focus, Bool toggled, Window w)
@@ -1029,6 +1206,7 @@
   Window expose_win, XRectangle *rclip)
 {
   int i;
+  int left1right0;
   Bool is_lowest = True;
   Pixmap *pass_bg_pixmap;
 
@@ -1042,8 +1220,10 @@
 
   for (i = 0; i < NUMBER_OF_BUTTONS; i++)
   {
-    if (t->button_w[i] != None && (((i & 1) && i / 2 < Scr.nr_right_buttons) ||
-				   (!(i & 1) && i / 2 < Scr.nr_left_buttons)))
+    left1right0 = !(i&1);
+    if (t->button_w[i] != None &&
+        ((!left1right0 && i/2 < Scr.nr_right_buttons) ||
+         (left1right0  && i/2 < Scr.nr_left_buttons)))
     {
       mwm_flags stateflags =
 	TB_MWM_DECOR_FLAGS(GetDecor(t, buttons[i]));
@@ -1097,8 +1277,8 @@
 	    DrawButton(t, t->button_w[i], t->title_g.height, t->title_g.height,
 		       tsdf, cd->relief_gc, cd->shadow_gc,
 		       cd->fore_color, cd->back_color, is_lowest,
-		       TB_MWM_DECOR_FLAGS(GetDecor(t, buttons[i])), 1, NULL,
-		       pass_bg_pixmap);
+		       TB_MWM_DECOR_FLAGS(GetDecor(t, buttons[i])),
+                       left1right0, NULL, pass_bg_pixmap);
 	    is_lowest = False;
 	  }
 	}
@@ -1110,8 +1290,8 @@
 	  DrawButton(t, t->button_w[i], t->title_g.height, t->title_g.height,
 		     df, cd->relief_gc, cd->shadow_gc,
 		     cd->fore_color, cd->back_color, is_lowest,
-		     TB_MWM_DECOR_FLAGS(GetDecor(t, buttons[i])), 1, NULL,
-		     pass_bg_pixmap);
+		     TB_MWM_DECOR_FLAGS(GetDecor(t, buttons[i])), left1right0,
+                     NULL, pass_bg_pixmap);
 	  is_lowest = False;
 	}
 
@@ -1276,6 +1456,11 @@
     /* draw compound titlebar ([email-masked]) */
     Bool is_lowest = True;
 
+#ifdef FANCY_TITLEBARS
+    if (df->style.face_type == MultiPixmap)
+      DrawMultiPixmapTitlebar(t, df);
+    else
+#endif
     if (PressedW == t->title_w)
     {
 #ifdef MULTISTYLE
@@ -1319,6 +1504,11 @@
       break;
     }
 
+#ifdef FANCY_TITLEBARS
+    if (TB_STATE(GetDecor(t, titlebar))[title_state].style.face_type
+        != MultiPixmap)
+#endif
+    {
 #ifdef I18N_MB
     if(t->name != (char *)NULL)
       XmbDrawString(dpy, t->title_w, t->title_font.fontset,
@@ -1329,6 +1519,7 @@
       XDrawString(dpy, t->title_w, Scr.TitleGC, hor_off,
 		  t->title_font.y + 1, t->name, strlen(t->name));
 #endif
+    }
   }
 
   /*
--- fvwm/builtins.c.orig	Wed Oct 10 01:26:55 2001
+++ fvwm/builtins.c	Wed Oct 10 01:15:06 2001
@@ -63,6 +63,9 @@
 
 static char *ReadTitleButton(
     char *s, TitleButton *tb, Boolean append, int button);
+#ifdef FANCY_TITLEBARS
+static char *ReadMultiPixmapDecor(char *s, DecorFace *df);
+#endif
 static void DestroyFvwmDecor(FvwmDecor *decor);
 
 extern float rgpctMovementDefault[32];
@@ -1401,6 +1404,10 @@
 
 void FreeDecorFace(Display *dpy, DecorFace *df)
 {
+#ifdef FANCY_TITLEBARS
+  int i;
+#endif
+
   switch (DFS_FACE_TYPE(df->style))
   {
   case GradientButton:
@@ -1418,6 +1425,18 @@
       DestroyPicture(dpy, df->u.p);
     break;
 
+#ifdef FANCY_TITLEBARS
+  case MultiPixmap:
+    if (df->u.multi_pixmaps) {
+      for (i=0; i < NUM_TB_PIXMAPS; i++) {
+        if (df->u.multi_pixmaps[i])
+          DestroyPicture(dpy, df->u.multi_pixmaps[i]);
+      }
+      free(df->u.multi_pixmaps);
+    }
+    break;
+#endif
+
   case VectorButton:
   case DefaultVectorButton:
     if (df->u.vector.x)
@@ -1649,6 +1668,19 @@
       else
 	DFS_FACE_TYPE(df->style) = PixmapButton;
     }
+#ifdef FANCY_TITLEBARS
+    else if (strncasecmp(style,"MultiPixmap",11)==0) {
+      if (button != -1) {
+        if (verbose)
+          fvwm_msg(ERR, "ReadDecorFace",
+                   "MultiPixmap is only valid for TitleStyle");
+        return False;
+      }
+      s = ReadMultiPixmapDecor(s, df);
+      if (!s)
+        return False;
+    }
+#endif
 #ifdef MINI_ICONS
     else if (strncasecmp (style, "MiniIcon", 8) == 0)
     {
@@ -1956,6 +1988,68 @@
   return end;
 }
 
+#ifdef FANCY_TITLEBARS
+/*****************************************************************************
+ *
+ * Reads a multi-pixmap titlebar config. ([email-masked])
+ *
+ ****************************************************************************/
+static char *ReadMultiPixmapDecor(char *s, DecorFace *df)
+{
+  Picture **pm;
+  char *token, *next;
+  int i;
+  static char *pm_names[NUM_TB_PIXMAPS] = {
+    "Main",
+    "LeftMain",
+    "RightMain",
+    "UnderText",
+    "LeftOfText",
+    "RightOfText",
+    "LeftEnd",
+    "RightEnd",
+    "LeftButtons",
+    "RightButtons"
+  };
+
+  df->style.face_type = MultiPixmap;
+  df->u.multi_pixmaps = pm =
+    (Picture**)safecalloc(NUM_TB_PIXMAPS, sizeof(Picture*));
+
+  while (token = PeekToken(s, &next)) {
+    for (i=0; i < NUM_TB_PIXMAPS && !StrEquals(token, pm_names[i]); i++) {}
+    if (i == NUM_TB_PIXMAPS)
+      break;
+    s = next;
+    next = DoPeekToken(s, &token, NULL, ",", NULL);
+    if (!token)
+      break;
+    s = next;
+    if (pm[i]) {
+      fvwm_msg(WARN, "ReadMultiPixmapDecor",
+               "Ignoring already-specified pixmap in TitleStyle MultiPixmap");
+      continue;
+    }
+    pm[i] = CachePicture(dpy, Scr.NoFocusWin, NULL, token, Scr.ColorLimit);
+    if (!pm[i])
+      fvwm_msg(ERR, "ReadMultiPixmapDecor", "Pixmap '%s' could not be loaded",
+               token);
+  }
+
+  if (!pm[TBP_MAIN] && !(pm[TBP_LEFT_MAIN] && pm[TBP_RIGHT_MAIN])) {
+    fvwm_msg(ERR, "ReadMultiPixmapDecor",
+             "No Main pixmap found for TitleStyle MultiPixmap (you must specify either Main, or both LeftMain and RightMain)");
+    for (i=0; i < NUM_TB_PIXMAPS; i++) {
+      if (pm[i])
+        DestroyPicture(dpy, pm[i]);
+    }
+    free(pm);
+    return NULL;
+  }
+
+  return s;
+}
+#endif /* FANCY_TITLEBARS */
 
 #ifdef USEDECOR
 /*****************************************************************************

---

From: Mikhael Goikhman <[email-masked]>
Date: Thu, 11 Oct 2001 23:59:37 +0000

> of course). Just a single unallocated Picture** pointer.

Is anyone against applying this/updated patch? It is #ifdef'd and does not
add any memory overhead or instability when the new feature is not used.

Suzanne, it seems logical to have Buttons pixmap, not only LeftButtons and
RightButtons. Or I may add this later myself.

There is one bug with stippled titles, try opaque move of sticky windows.
The stipples disappear when they should be redrawn during the move.
To be honest I don't know what to do with stipples when MultiPixmap used.
Stipples don't look very nice with MultiPixmap or TiledPixmap titlebars.

Regards,
Mikhael.
--
Visit the official FVWM web page at <URL:http://www.fvwm.org/>.
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: Suzanne Britton <[email-masked]>
Date: Fri, 12 Oct 2001 13:39:00 -0400

> add any memory overhead or instability when the new feature is not used.

Please hold off a bit. As mentioned in e-mail, my computer monitor is
dying (ever seen hourglass-shaped windows? and no, I'm not using the
Shape extension!) so I may not have computer access at all much longer
until we replace it (within a week or so). If problems come up I won't be
able to help right away in fixing them.

Also, if any of my code makes it into CVS I should give myself a crash
course on CVS usage :-)

> RightButtons. Or I may add this later myself.

Sure, I can add that in.

Suzanne

-- 
[email-masked] - http://www.igs.net/~tril/
"The only time we should hear anyone asking if something is 'ready for the
Enterprise' is if we are listening into Jim & Scotty discussing the merits of
a new Warp drive."                     -- Seen on LinuxToday.com
--
Visit the official FVWM web page at <URL:http://www.fvwm.org/>.
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]