[SM-Commit] GIT changes to master grimoire by Florian Franzmann (32ae7949fc150fa81867eccdf34d531e3acfab93)

Florian Franzmann scm at mail.sourcemage.org
Sat Mar 3 08:03:54 EST 2007


GIT changes to master grimoire by Florian Franzmann <siflfran at hawo.stw.uni-erlangen.de>:

 windowmanagers/fvwm/DETAILS                                |    2 
 windowmanagers/fvwm/HISTORY                                |   23 
 windowmanagers/fvwm/PREPARE                                |    4 
 windowmanagers/fvwm/PRE_BUILD                              |   10 
 windowmanagers/fvwm/patches/02-ResizeOutlineThin.patch     |  636 
 windowmanagers/fvwm/patches/03-Conditionals.patch          | 2294 ++
 windowmanagers/fvwm/patches/04-FlatSeparators.patch        |10801 +++++++++
 windowmanagers/fvwm/patches/05-BorderUnderTitle.patch      |14348 +++++++++++++
 windowmanagers/fvwm/patches/06-InactiveFont.patch          | 4386 +++
 windowmanagers/fvwm/patches/07-FluxboxHandles.patch        | 1470 +
 windowmanagers/fvwm/patches/08-RoundedCorners.patch        | 3477 +++
 windowmanagers/fvwm/patches/09-TopBorder.patch             |  649 
 windowmanagers/fvwm/patches/10-ButtonWidth.patch           |  370 
 windowmanagers/fvwm/patches/11-MultiBorder.patch           | 5638 +++++
 windowmanagers/fvwm/patches/12-Hover.patch                 | 5549 +++++
 windowmanagers/fvwm/patches/15-FvwmIconMan.patch           |  181 
 windowmanagers/fvwm/patches/16-FvwmButtonsTips.patch       |  547 
 windowmanagers/fvwm/patches/17-DefaultCharset.patch        |   26 
 windowmanagers/fvwm/patches/18-FirstItemUnderPointer.patch |  181 
 windowmanagers/fvwm/patches/19-FluxCorner.patch            |   26 
 windowmanagers/fvwm/patches/20-ThinGeometryProxy.patch     | 3580 +++
 21 files changed, 54197 insertions(+), 1 deletion(-)

New commits:
commit 32ae7949fc150fa81867eccdf34d531e3acfab93
Author: Florian Franzmann <siflfran at hawo.stw.uni-erlangen.de>
Commit: Florian Franzmann <siflfran at hawo.stw.uni-erlangen.de>

    windowmanagers/fvwm: added optional support for the patchset from
    http://abdn.ac.uk/~u15dm4/fvwm/

diff --git a/windowmanagers/fvwm/DETAILS b/windowmanagers/fvwm/DETAILS
index e2589f3..f37d51f 100755
--- a/windowmanagers/fvwm/DETAILS
+++ b/windowmanagers/fvwm/DETAILS
@@ -35,7 +35,7 @@ SOURCE_DIRECTORY=$BUILD_DIRECTORY/fvwm-c
 fi
         WEB_SITE=http://www.fvwm.org
          ENTERED=20040524
-      PATCHLEVEL=1
+      PATCHLEVEL=2
       LICENSE[0]=GPL
       LICENSE[1]=MIT
         KEYWORDS="windowmanagers"
diff --git a/windowmanagers/fvwm/HISTORY b/windowmanagers/fvwm/HISTORY
index 6c8558b..6509d86 100644
--- a/windowmanagers/fvwm/HISTORY
+++ b/windowmanagers/fvwm/HISTORY
@@ -1,3 +1,26 @@
+2007-03-03 Florian Franzmann <siflfran at hawo.stw.uni-erlangen.de>
+	* DETAILS: PATCHLEVEL++
+	* PRE_BUILD, PREPARE: added optional support for the patchset
+	  from http://abdn.ac.uk/~u15dm4/fvwm
+	* patches/{02-ResizeOutlineThin.patch,
+		   03-Conditionals.patch,
+		   04-FlatSeparators.patch,
+		   05-BorderUnderTitle.patch,
+		   06-InactiveFont.patch,
+		   07-FluxboxHandles.patch,
+		   08-RoundedCorners.patch,
+		   09-TopBorder.patch,
+		   10-ButtonWidth.patch,
+		   11-MultiBorder.patch,
+		   12-Hover.patch,
+		   15-FvwmIconMan.patch,
+		   16-FvwmButtonsTips.patch,
+		   17-DefaultCharset.patch,
+		   18-FirstItemUnderPointer.patch,
+		   19-FluxCorner.patch,
+		   20-ThinGeometryProxy.patch}:
+	  added patches from http://abdn.ac.uk/~u15dm4/fvwm
+
 2007-02-28 Florian Franzmann <siflfran at hawo.stw.uni-erlangen.de>
 	* DEPENDS: added optional dependency on rplay
 	* DETAILS: removed UPDATED, added PATCHLEVEL
diff --git a/windowmanagers/fvwm/PREPARE b/windowmanagers/fvwm/PREPARE
index 7fffbee..d53ff25 100755
--- a/windowmanagers/fvwm/PREPARE
+++ b/windowmanagers/fvwm/PREPARE
@@ -6,3 +6,7 @@ config_query_list FVWM_RELEASE "Which re
 if [[ "${FVWM_RELEASE}" == "cvs" ]]
 then config_query FVWM_CVS_AUTOUPDATE "Update on every system update?" n
 fi
+if [[ "${FVWM_RELEASE}" == "unstable" ]]; then
+	config_query FVWM_PATCHSET \
+		"apply the patchset from http://abdn.ac.uk/~u15dm4/fvwm?" n
+fi
diff --git a/windowmanagers/fvwm/PRE_BUILD b/windowmanagers/fvwm/PRE_BUILD
new file mode 100755
index 0000000..5fbd5d5
--- /dev/null
+++ b/windowmanagers/fvwm/PRE_BUILD
@@ -0,0 +1,10 @@
+default_pre_build &&
+if [[ "$FVWM_RELEASE" == "unstable" ]] && 
+   [[ "$FVWM_PATCHSET" == "y" ]]; then
+	cd ${SCRIPT_DIRECTORY}/patches
+	for patch in *.patch; do
+		cd ${SOURCE_DIRECTORY} &&
+		message "${MESSAGE_COLOR}applying ${FILE_COLOR}$patch${DEFAULT_COLOR}" &&
+		patch -p1 < ${SCRIPT_DIRECTORY}/patches/$patch
+	done
+fi
diff --git a/windowmanagers/fvwm/patches/02-ResizeOutlineThin.patch b/windowmanagers/fvwm/patches/02-ResizeOutlineThin.patch
new file mode 100644
index 0000000..b0f7882
--- /dev/null
+++ b/windowmanagers/fvwm/patches/02-ResizeOutlineThin.patch
@@ -0,0 +1,636 @@
+diff -U10 -Naupr fvwm-2.5.21/fvwm/fvwm.h fvwm-2.5.21-02/fvwm/fvwm.h
+--- fvwm-2.5.21/fvwm/fvwm.h	2007-01-18 09:47:54.000000000 +0100
++++ fvwm-2.5.21-02/fvwm/fvwm.h	2007-03-03 13:17:38.000000000 +0100
+@@ -216,20 +216,21 @@ typedef struct
+ 		unsigned do_ewmh_ignore_window_type : 1;
+ 		unsigned do_iconify_window_groups : 1;
+ 		unsigned do_ignore_gnome_hints : 1;
+ 		unsigned do_ignore_icon_boxes : 1;
+ 		unsigned do_ignore_restack : 1;
+ 		unsigned do_use_window_group_hint : 1;
+ 		unsigned do_lower_transient : 1;
+ 		unsigned do_not_show_on_map : 1;
+ 		unsigned do_raise_transient : 1;
+ 		unsigned do_resize_opaque : 1;
++		unsigned do_resize_outline_thin : 1;
+ 		unsigned do_shrink_windowshade : 1;
+ 		unsigned do_stack_transient_parent : 1;
+ 		unsigned do_window_list_skip : 1;
+ 		unsigned ewmh_maximize_mode : 2; /* see ewmh.h */
+ 		unsigned has_depressable_border : 1;
+ 		unsigned has_mwm_border : 1;
+ 		unsigned has_mwm_buttons : 1;
+ 		unsigned has_mwm_override : 1;
+ 		unsigned has_no_icon_title : 1;
+ 		unsigned has_override_size : 1;
+diff -U10 -Naupr fvwm-2.5.21/fvwm/move_resize.c fvwm-2.5.21-02/fvwm/move_resize.c
+--- fvwm-2.5.21/fvwm/move_resize.c	2007-01-14 16:07:58.000000000 +0100
++++ fvwm-2.5.21-02/fvwm/move_resize.c	2007-03-03 13:17:38.000000000 +0100
+@@ -102,179 +102,195 @@ static int move_drag_finish_button_mask 
+ /* ----- end of move globals ----- */
+ 
+ /* ----- resize globals ----- */
+ 
+ /* DO NOT USE (STATIC) GLOBALS IN THIS MODULE!
+  * Since some functions are called from other modules unwanted side effects
+  * (i.e. bugs.) would be created */
+ 
+ extern Window PressedW;
+ 
+-static void draw_move_resize_grid(int x, int  y, int  width, int height);
++static void draw_move_resize_grid(int x, int  y, int  width, int height, Bool thin);
+ 
+ /* ----- end of resize globals ----- */
+ 
+ /*
+  *
+  *  Procedure:
+  *      draw_move_resize_grid - move a window outline
+  *
+  *  Inputs:
+  *      root        - the window we are outlining
+  *      x           - upper left x coordinate
+  *      y           - upper left y coordinate
+  *      width       - the width of the rectangle
+  *      height      - the height of the rectangle
+  *
+  */
+ static int get_outline_rects(
+-	XRectangle *rects, int x, int y, int width, int height)
++	XRectangle *rects, int x, int y, int width, int height, Bool do_outline_thin)
+ {
+ 	int i;
+ 	int n;
+ 	int m;
+ 
+-	n = 3;
+-	m = (width - 5) / 2;
+-	if (m < n)
++	if (do_outline_thin)
+ 	{
+-		n = m;
+-	}
+-	m = (height - 5) / 2;
+-	if (m < n)
+-	{
+-		n = m;
++		n = 1;
+ 	}
+-	if (n < 1)
++	else
+ 	{
+-		n = 1;
++		n = 3;
++		m = (width - 5) / 2;
++		if (m < n)
++		{
++			n = m;
++		}
++		m = (height - 5) / 2;
++		if (m < n)
++		{
++			n = m;
++		}
++		if (n < 1)
++		{
++			n = 1;
++		}
+ 	}
+ 
+ 	for (i = 0; i < n; i++)
+ 	{
+ 		rects[i].x = x + i;
+ 		rects[i].y = y + i;
+ 		rects[i].width = width - (i << 1);
+ 		rects[i].height = height - (i << 1);
+ 	}
+-	if (width - (n << 1) >= 5 && height - (n << 1) >= 5)
++	if (!do_outline_thin)
+ 	{
+-		if (width - (n << 1) >= 10)
++		if (width - (n << 1) >= 5 && height - (n << 1) >= 5)
+ 		{
+-			int off = (width - (n << 1)) / 3 + n;
+-			rects[i].x = x + off;
+-			rects[i].y = y + n;
+-			rects[i].width = width - (off << 1);
+-			rects[i].height = height - (n << 1);
+-			i++;
+-		}
+-		if (height - (n << 1) >= 10)
+-		{
+-			int off = (height - (n << 1)) / 3 + n;
+-			rects[i].x = x + n;
+-			rects[i].y = y + off;
+-			rects[i].width = width - (n << 1);
+-			rects[i].height = height - (off << 1);
+-			i++;
++			if (width - (n << 1) >= 10)
++			{
++				int off = (width - (n << 1)) / 3 + n;
++				rects[i].x = x + off;
++				rects[i].y = y + n;
++				rects[i].width = width - (off << 1);
++				rects[i].height = height - (n << 1);
++				i++;
++			}
++			if (height - (n << 1) >= 10)
++			{
++				int off = (height - (n << 1)) / 3 + n;
++				rects[i].x = x + n;
++				rects[i].y = y + off;
++				rects[i].width = width - (n << 1);
++				rects[i].height = height - (off << 1);
++				i++;
++			}
+ 		}
+ 	}
+ 
+ 	return i;
+ }
+ 
+ struct
+ {
+ 	rectangle geom;
+ 	struct
+ 	{
+ 		unsigned is_enabled : 1;
++		unsigned do_outline_thin : 1;
+ 	} flags;
+ } move_resize_grid =
+ {
+ 	{ 0, 0, 0, 0 },
+-	{ 0 }
++	{ 0, 0 }
+ };
+ 
+-static void draw_move_resize_grid(int x, int  y, int  width, int height)
++static void draw_move_resize_grid(int x, int  y, int  width, int height, Bool do_outline_thin)
+ {
+ 	int nrects = 0;
+ 	XRectangle rects[10];
+ 
+ 	if (move_resize_grid.flags.is_enabled &&
+ 	    x == move_resize_grid.geom.x &&
+ 	    y == move_resize_grid.geom.y &&
+ 	    width == move_resize_grid.geom.width &&
+-	    height == move_resize_grid.geom.height)
++	    height == move_resize_grid.geom.height &&
++		do_outline_thin == move_resize_grid.flags.do_outline_thin)
+ 	{
+ 		return;
+ 	}
+ 
+ 	memset(rects, 0, 10 * sizeof(XRectangle));
+ 	/* place the resize rectangle into the array of rectangles */
+ 	/* interleave them for best visual look */
+ 	/* draw the new one, if any */
+ 	if (move_resize_grid.flags.is_enabled
+ 	    /*move_resize_grid.geom.width && move_resize_grid.geom.height*/)
+ 	{
+ 		move_resize_grid.flags.is_enabled = 0;
+ 		nrects +=
+ 			get_outline_rects(
+ 				&(rects[0]), move_resize_grid.geom.x,
+ 				move_resize_grid.geom.y,
+ 				move_resize_grid.geom.width,
+-				move_resize_grid.geom.height);
++				move_resize_grid.geom.height,
++				move_resize_grid.flags.do_outline_thin);
+ 	}
+ 	if (width && height)
+ 	{
+ 		move_resize_grid.flags.is_enabled = 1;
+ 		move_resize_grid.geom.x = x;
+ 		move_resize_grid.geom.y = y;
+ 		move_resize_grid.geom.width = width;
+ 		move_resize_grid.geom.height = height;
++		move_resize_grid.flags.do_outline_thin = do_outline_thin;
+ 		nrects += get_outline_rects(
+-			&(rects[nrects]), x, y, width, height);
++			&(rects[nrects]), x, y, width, height, do_outline_thin);
+ 	}
+ 	if (nrects > 0)
+ 	{
+ 		XDrawRectangles(dpy, Scr.Root, Scr.XorGC, rects, nrects);
+ 		XFlush(dpy);
+ 	}
+ 
+ 	return;
+ }
+ 
+ void switch_move_resize_grid(Bool state)
+ {
+ 	if (state == False)
+ 	{
+ 		if (move_resize_grid.flags.is_enabled)
+ 		{
+-			draw_move_resize_grid(0, 0, 0, 0);
++			draw_move_resize_grid(0, 0, 0, 0, 0);
+ 		}
+ 		else
+ 		{
+ 			move_resize_grid.geom.x = 0;
+ 			move_resize_grid.geom.y = 0;
+ 			move_resize_grid.geom.width = 0;
+ 			move_resize_grid.geom.height = 0;
++			move_resize_grid.flags.do_outline_thin = 0;
+ 		}
+ 	}
+ 	else if (!move_resize_grid.flags.is_enabled)
+ 	{
+ 		if (move_resize_grid.geom.width &&
+ 		    move_resize_grid.geom.height)
+ 		{
+ 			draw_move_resize_grid(
+ 				move_resize_grid.geom.x,
+ 				move_resize_grid.geom.y,
+ 				move_resize_grid.geom.width,
+-				move_resize_grid.geom.height);
++				move_resize_grid.geom.height,
++				move_resize_grid.flags.do_outline_thin);
+ 		}
+ 	}
+ 
+ 	return;
+ }
+ 
+ /* The vars are named for the x-direction, but this is used for both x and y */
+ static int GetOnePositionArgument(
+ 	char *s1, int x, int w, int *pFinalX, float factor, int max, int off,
+ 	Bool is_x)
+@@ -2189,20 +2205,21 @@ Bool __move_loop(
+ 	int orig_icon_x = 0;
+ 	int orig_icon_y = 0;
+ 	Bool do_snap = True;
+ 	Bool was_snapped = False;
+ 	/* if Alt is initially pressed don't enable no-snap until Alt is
+ 	 * released */
+ 	Bool nosnap_enabled = False;
+ 	/* Must not set placed by button if the event is a modified KeyEvent */
+ 	Bool is_fake_event;
+ 	FvwmWindow *fw = exc->w.fw;
++ 	Bool do_outline_thin = DO_RESIZE_OUTLINE_THIN(fw);
+ 	unsigned int draw_parts = PART_NONE;
+ 	XEvent e;
+ 
+ 	if (!GrabEm(CRS_MOVE, GRAB_NORMAL))
+ 	{
+ 		XBell(dpy, 0);
+ 		return False;
+ 	}
+ 	if (!IS_MAPPED(fw) && !IS_ICONIFIED(fw))
+ 	{
+@@ -2262,21 +2279,21 @@ Bool __move_loop(
+ 		yt += YOffset;
+ 	}
+ 	button_mask &= DEFAULT_ALL_BUTTONS_MASK;
+ 	xl_orig = xl;
+ 	yt_orig = yt;
+ 
+ 	/* draw initial outline */
+ 	if (!IS_ICONIFIED(fw) &&
+ 	    ((!do_move_opaque && !Scr.gs.do_emulate_mwm) || !IS_MAPPED(fw)))
+ 	{
+-		draw_move_resize_grid(xl, yt, Width - 1, Height - 1);
++		draw_move_resize_grid(xl, yt, Width - 1, Height - 1, do_outline_thin);
+ 	}
+ 
+ 	if (move_w == FW_W_FRAME(fw) && do_move_opaque)
+ 	{
+ 		draw_parts = border_get_transparent_decorations_part(fw);
+ 	}
+ 	DisplayPosition(fw, exc->x.elast, xl, yt, True);
+ 
+ 	memset(&e, 0, sizeof(e));
+ 
+@@ -2590,21 +2607,21 @@ Bool __move_loop(
+ 			}
+ 
+ 			/* check Paging request once and only once after
+ 			 * outline redrawn redraw after paging if needed
+ 			 * - mab */
+ 			for (paged = 0; paged <= 1; paged++)
+ 			{
+ 				if (!do_move_opaque)
+ 				{
+ 					draw_move_resize_grid(
+-						xl, yt, Width - 1, Height - 1);
++						xl, yt, Width - 1, Height - 1, do_outline_thin);
+ 				}
+ 				else
+ 				{
+ 					if (IS_ICONIFIED(fw))
+ 					{
+ 						set_icon_position(fw, xl, yt);
+ 						move_icon_to_position(fw);
+ 						broadcast_icon_geometry(
+ 							fw, False);
+ 					}
+@@ -2661,21 +2678,21 @@ Bool __move_loop(
+ 			if (!do_move_opaque)
+ 			{
+ 				/* must undraw the rubber band in case the
+ 				 * event causes some drawing */
+ 				switch_move_resize_grid(False);
+ 			}
+ 			dispatch_event(&e);
+ 			if (!do_move_opaque)
+ 			{
+ 				draw_move_resize_grid(
+-					xl, yt, Width - 1, Height - 1);
++					xl, yt, Width - 1, Height - 1, do_outline_thin);
+ 			}
+ 			break;
+ 
+ 		default:
+ 			/* cannot happen */
+ 			break;
+ 		} /* switch */
+ 		xl += x_virtual_offset;
+ 		yt += y_virtual_offset;
+ 		if (do_move_opaque && !IS_ICONIFIED(fw) &&
+@@ -3194,21 +3211,21 @@ static void __resize_get_refpos(
+  *      y_off    - y offset of pointer from border (input/output)
+  *      drag     - resize internal structure
+  *      orig     - resize internal structure
+  *      xmotionp - pointer to xmotion in resize_window
+  *      ymotionp - pointer to ymotion in resize_window
+  *
+  */
+ static void __resize_step(
+ 	const exec_context_t *exc, int x_root, int y_root, int *x_off,
+ 	int *y_off, rectangle *drag, const rectangle *orig, int *xmotionp,
+-	int *ymotionp, Bool do_resize_opaque, Bool is_direction_fixed)
++	int *ymotionp, Bool do_resize_opaque, Bool is_direction_fixed, Bool do_outline_thin)
+ {
+ 	int action = 0;
+ 	XEvent e;
+ 	int x2;
+ 	int y2;
+ 	int xdir;
+ 	int ydir;
+ 
+ 	x2 = x_root - *x_off;
+ 	x_root += *x_off;
+@@ -3317,21 +3334,21 @@ static void __resize_step(
+ 			drag->x = orig->x + orig->width - drag->width;
+ 		}
+ 		if (*ymotionp == 1)
+ 		{
+ 			drag->y = orig->y + orig->height - drag->height;
+ 		}
+ 		if (!do_resize_opaque)
+ 		{
+ 			draw_move_resize_grid(
+ 				drag->x, drag->y, drag->width - 1,
+-				drag->height - 1);
++				drag->height - 1, do_outline_thin);
+ 		}
+ 		else
+ 		{
+ 			frame_setup_window(
+ 				exc->w.fw, drag->x, drag->y, drag->width,
+ 				drag->height, False);
+ 		}
+ 	}
+ 	e.type = MotionNotify;
+ 	e.xbutton.x_root = x_root;
+@@ -3377,20 +3394,21 @@ static Bool __resize_window(F_CMD_ARGS)
+ 	int i;
+ 	size_borders b;
+ 	frame_move_resize_args mr_args = NULL;
+ 	long evmask;
+ 	XEvent ev;
+ 	int ref_x;
+ 	int ref_y;
+ 	int x_off;
+ 	int y_off;
+ 	direction_t dir;
++	Bool do_outline_thin = DO_RESIZE_OUTLINE_THIN(fw);
+ 
+ 	bad_window = False;
+ 	ResizeWindow = FW_W_FRAME(fw);
+ 	if (fev_get_evpos_or_query(dpy, Scr.Root, exc->x.etrigger, &px, &py) ==
+ 	    False ||
+ 	    XTranslateCoordinates(
+ 		    dpy, Scr.Root, ResizeWindow, px, py, &px, &py,
+ 		    &JunkChild) == False)
+ 	{
+ 		/* pointer is on a different screen - that's okay here */
+@@ -3657,42 +3675,42 @@ static Bool __resize_window(F_CMD_ARGS)
+ 	else
+ 	{
+ 		/* wait until the pointer hits a border before making a
+ 		 * decision about the resize direction */
+ 	}
+ 
+ 	/* draw the rubber-band window */
+ 	if (!do_resize_opaque)
+ 	{
+ 		draw_move_resize_grid(
+-			drag->x, drag->y, drag->width - 1, drag->height - 1);
++			drag->x, drag->y, drag->width - 1, drag->height - 1, do_outline_thin);
+ 	}
+ 	/* kick off resizing without requiring any motion if invoked with a key
+ 	 * press */
+ 	if (exc->x.elast->type == KeyPress)
+ 	{
+ 		int xo;
+ 		int yo;
+ 
+ 		if (FQueryPointer(
+ 			    dpy, Scr.Root, &JunkRoot, &JunkChild, &stashed_x,
+ 			    &stashed_y, &JunkX, &JunkY, &JunkMask) == False)
+ 		{
+ 			/* pointer is on a different screen */
+ 			stashed_x = 0;
+ 			stashed_y = 0;
+ 		}
+ 		xo = 0;
+ 		yo = 0;
+ 		__resize_step(
+ 			exc, stashed_x, stashed_y, &xo, &yo, drag, orig,
+-			&xmotion, &ymotion, do_resize_opaque, True);
++			&xmotion, &ymotion, do_resize_opaque, True, do_outline_thin);
+ 	}
+ 	else
+ 	{
+ 		stashed_x = stashed_y = -1;
+ 	}
+ 
+ 	/* loop to resize */
+ 	memset(&ev, 0, sizeof(ev));
+ 	while (!is_finished && bad_window != FW_W(fw))
+ 	{
+@@ -3842,38 +3860,38 @@ static Bool __resize_window(F_CMD_ARGS)
+ 			}
+ 			if (!fForceRedraw)
+ 			{
+ 				x = ev.xmotion.x_root;
+ 				y = ev.xmotion.y_root;
+ 				/* resize before paging request to prevent
+ 				 * resize from lagging * mouse - mab */
+ 				__resize_step(
+ 					exc, x, y, &x_off, &y_off, drag, orig,
+ 					&xmotion, &ymotion, do_resize_opaque,
+-					is_direction_fixed);
++					is_direction_fixed, do_outline_thin);
+ 				/* need to move the viewport */
+ 				HandlePaging(
+ 					&ev, dx, dy, &x, &y, &delta_x,
+ 					&delta_y, False, False, False);
+ 			}
+ 			/* redraw outline if we paged - mab */
+ 			if (delta_x != 0 || delta_y != 0)
+ 			{
+ 				sorig.x -= delta_x;
+ 				sorig.y -= delta_y;
+ 				drag->x -= delta_x;
+ 				drag->y -= delta_y;
+ 
+ 				__resize_step(
+ 					exc, x, y, &x_off, &y_off, drag, orig,
+ 					&xmotion, &ymotion, do_resize_opaque,
+-					is_direction_fixed);
++					is_direction_fixed, do_outline_thin);
+ 			}
+ 			fForceRedraw = False;
+ 			is_done = True;
+ 			break;
+ 
+ 		case PropertyNotify:
+ 		{
+ 			evh_args_t ea;
+ 			exec_context_changes_t ecc;
+ 
+@@ -3894,21 +3912,21 @@ static Bool __resize_window(F_CMD_ARGS)
+ 			{
+ 				/* must undraw the rubber band in case the
+ 				 * event causes some drawing */
+ 				switch_move_resize_grid(False);
+ 			}
+ 			dispatch_event(&ev);
+ 			if (!do_resize_opaque)
+ 			{
+ 				draw_move_resize_grid(
+ 					drag->x, drag->y, drag->width - 1,
+-					drag->height - 1);
++					drag->height - 1, do_outline_thin);
+ 			}
+ 		}
+ 		else
+ 		{
+ 			if (do_resize_opaque)
+ 			{
+ 				/* only do this with opaque resizes, (i.e. the
+ 				 * server is not grabbed) */
+ 				BroadcastConfig(M_CONFIGURE_WINDOW, fw);
+ 				FlushAllMessageQueues();
+@@ -3947,21 +3965,21 @@ static Bool __resize_window(F_CMD_ARGS)
+ 			int yo;
+ 			rectangle g;
+ 
+ 			xo = 0;
+ 			yo = 0;
+ 			xmotion = 1;
+ 			ymotion = 1;
+ 			g = sorig;
+ 			__resize_step(
+ 				exc, sorig.x, sorig.y, &xo, &yo, &g, orig,
+-				&xmotion, &ymotion, do_resize_opaque, True);
++				&xmotion, &ymotion, do_resize_opaque, True, do_outline_thin);
+ 		}
+ 		if (vx != Scr.Vx || vy != Scr.Vy)
+ 		{
+ 			MoveViewport(vx, vy, False);
+ 		}
+ 		/* restore all geometry-related info */
+ 		fw->g = g_backup;
+ 		if (bad_window == FW_W(fw))
+ 		{
+ 			XUnmapWindow(dpy, FW_W_FRAME(fw));
+diff -U10 -Naupr fvwm-2.5.21/fvwm/style.c fvwm-2.5.21-02/fvwm/style.c
+--- fvwm-2.5.21/fvwm/style.c	2007-01-18 09:47:55.000000000 +0100
++++ fvwm-2.5.21-02/fvwm/style.c	2007-03-03 13:17:38.000000000 +0100
+@@ -3402,20 +3402,26 @@ static Bool style_parse_one_style_option
+ 			S_SET_DO_RESIZE_OPAQUE(SCF(*ps), on);
+ 			S_SET_DO_RESIZE_OPAQUE(SCM(*ps), 1);
+ 			S_SET_DO_RESIZE_OPAQUE(SCC(*ps), 1);
+ 		}
+ 		else if (StrEquals(token, "ResizeOutline"))
+ 		{
+ 			S_SET_DO_RESIZE_OPAQUE(SCF(*ps), !on);
+ 			S_SET_DO_RESIZE_OPAQUE(SCM(*ps), 1);
+ 			S_SET_DO_RESIZE_OPAQUE(SCC(*ps), 1);
+ 		}
++		else if (StrEquals(token, "ResizeOutlineThin"))
++		{
++			S_SET_DO_RESIZE_OUTLINE_THIN(SCF(*ps), on);
++			S_SET_DO_RESIZE_OUTLINE_THIN(SCM(*ps), 1);
++			S_SET_DO_RESIZE_OUTLINE_THIN(SCC(*ps), 1);
++		}
+ 		else if (StrEquals(token, "RightTitleRotatedCW"))
+ 		{
+ 			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCF(*ps), on);
+ 			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCM(*ps), 1);
+ 			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCC(*ps), 1);
+ 		}
+ 		else if (StrEquals(token, "RightTitleRotatedCCW"))
+ 		{
+ 			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCF(*ps), !on);
+ 			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCM(*ps), 1);
+diff -U10 -Naupr fvwm-2.5.21/fvwm/style.h fvwm-2.5.21-02/fvwm/style.h
+--- fvwm-2.5.21/fvwm/style.h	2006-12-21 18:21:16.000000000 +0100
++++ fvwm-2.5.21-02/fvwm/style.h	2007-03-03 13:17:38.000000000 +0100
+@@ -184,20 +184,24 @@
+ #define S_SET_DO_NOT_SHOW_ON_MAP(c,x) \
+ 	((c).s.do_not_show_on_map = !!(x))
+ #define S_DO_RAISE_TRANSIENT(c) \
+ 	((c).s.do_raise_transient)
+ #define S_SET_DO_RAISE_TRANSIENT(c,x) \
+ 	((c).s.do_raise_transient = !!(x))
+ #define S_DO_RESIZE_OPAQUE(c) \
+ 	((c).s.do_resize_opaque)
+ #define S_SET_DO_RESIZE_OPAQUE(c,x) \
+ 	((c).s.do_resize_opaque = !!(x))
++#define S_DO_RESIZE_OUTLINE_THIN(c) \
++	((c).s.do_resize_outline_thin)
++#define S_SET_DO_RESIZE_OUTLINE_THIN(c,x) \
++	((c).s.do_resize_outline_thin = !!(x))
+ #define S_DO_SHRINK_WINDOWSHADE(c) \
+ 	((c).s.do_shrink_windowshade)
+ #define S_SET_DO_SHRINK_WINDOWSHADE(c,x) \
+ 	((c).s.do_shrink_windowshade = !!(x))
+ #define S_DO_STACK_TRANSIENT_PARENT(c) \
+ 	((c).s.do_stack_transient_parent)
+ #define S_SET_DO_STACK_TRANSIENT_PARENT(c,x) \
+ 	((c).s.do_stack_transient_parent = !!(x))
+ #define S_DO_WINDOW_LIST_SKIP(c) \
+ 	((c).s.do_window_list_skip)
+diff -U10 -Naupr fvwm-2.5.21/fvwm/window_flags.h fvwm-2.5.21-02/fvwm/window_flags.h
+--- fvwm-2.5.21/fvwm/window_flags.h	2006-12-21 18:21:16.000000000 +0100
++++ fvwm-2.5.21-02/fvwm/window_flags.h	2007-03-03 13:17:38.000000000 +0100
+@@ -14,20 +14,22 @@
+ 	((fw)->flags.common.s.focus_policy)
+ 
+ #define DO_LOWER_TRANSIENT(fw) \
+ 	((fw)->flags.common.s.do_lower_transient)
+ #define DO_NOT_SHOW_ON_MAP(fw) \
+ 	((fw)->flags.common.s.do_not_show_on_map)
+ #define DO_RAISE_TRANSIENT(fw) \
+ 	((fw)->flags.common.s.do_raise_transient)
+ #define DO_RESIZE_OPAQUE(fw) \
+ 	((fw)->flags.common.s.do_resize_opaque)
++#define DO_RESIZE_OUTLINE_THIN(fw) \
++	((fw)->flags.common.s.do_resize_outline_thin)
+ #define DO_SHRINK_WINDOWSHADE(fw) \
+ 	((fw)->flags.common.s.do_shrink_windowshade)
+ #define SET_DO_SHRINK_WINDOWSHADE(fw,x) \
+ 	(fw)->flags.common.s.do_shrink_windowshade = !!(x)
+ #define SETM_DO_SHRINK_WINDOWSHADE(fw,x) \
+ 	(fw)->flag_mask.common.s.do_shrink_windowshade = !!(x)
+ #define DO_SKIP_CIRCULATE(fw) \
+ 	((fw)->flags.common.s.do_circulate_skip)
+ #define SET_DO_SKIP_CIRCULATE(fw,x) \
+ 	(fw)->flags.common.s.do_circulate_skip = !!(x)
diff --git a/windowmanagers/fvwm/patches/03-Conditionals.patch b/windowmanagers/fvwm/patches/03-Conditionals.patch
new file mode 100644
index 0000000..f059b75
--- /dev/null
+++ b/windowmanagers/fvwm/patches/03-Conditionals.patch
@@ -0,0 +1,2294 @@
+diff -U10 -Naupr fvwm-2.5.21-02/fvwm/conditional.c fvwm-2.5.21-03/fvwm/conditional.c
+--- fvwm-2.5.21-02/fvwm/conditional.c	2007-03-03 13:17:21.000000000 +0100
++++ fvwm-2.5.21-03/fvwm/conditional.c	2007-03-03 13:18:11.000000000 +0100
+@@ -591,20 +591,50 @@ void CreateConditionMask(char *flags, Wi
+ 		else if (StrEquals(cond, "FixedPosition"))
+ 		{
+ 			SET_FIXED(mask, on);
+ 			SETM_FIXED(mask, 1);
+ 		}
+ 		else if (StrEquals(cond,"HasHandles"))
+ 		{
+ 			SET_HAS_HANDLES(mask, on);
+ 			SETM_HAS_HANDLES(mask, 1);
+ 		}
++		else if (StrEquals(cond, "HasTitle"))
++		{
++			SET_HAS_TITLE(mask, on);
++			SETM_HAS_TITLE(mask, 1);
++		}
++		else if (StrEquals(cond, "HasBorders"))
++		{
++			SET_HAS_NO_BORDER(mask, !on);
++			SETM_HAS_NO_BORDER(mask, 1);
++		}
++		else if (StrEquals(cond, "TitleAtBottom"))
++		{
++			SET_TITLE_DIR(mask, DIR_S);
++			SETM_TITLE_DIR(mask, 1);
++		}
++		else if (StrEquals(cond, "TitleAtTop"))
++		{
++			SET_TITLE_DIR(mask, DIR_N);
++			SETM_TITLE_DIR(mask, 1);
++		}
++		else if (StrEquals(cond, "TitleAtLeft"))
++		{
++			SET_TITLE_DIR(mask, DIR_W);
++			SETM_TITLE_DIR(mask, 1);
++		}
++		else if (StrEquals(cond, "TitleAtRight"))
++		{
++			SET_TITLE_DIR(mask, DIR_E);
++			SETM_TITLE_DIR(mask, 1);
++		}
+ 		else if (StrEquals(cond,"Iconifiable"))
+ 		{
+ 			SET_IS_UNICONIFIABLE(mask, !on);
+ 			SETM_IS_UNICONIFIABLE(mask, 1);
+ 		}
+ 		else if (StrEquals(cond,"Maximizable"))
+ 		{
+ 			SET_IS_UNMAXIMIZABLE(mask, !on);
+ 			SETM_IS_UNMAXIMIZABLE(mask, 1);
+ 		}
+diff -U10 -Naupr fvwm-2.5.21-02/fvwm/conditional.c~ fvwm-2.5.21-03/fvwm/conditional.c~
+--- fvwm-2.5.21-02/fvwm/conditional.c~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-03/fvwm/conditional.c~	2007-03-03 13:17:58.000000000 +0100
+@@ -0,0 +1,2236 @@
++/* -*-c-*- */
++/* This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*
++ * This module is all original code
++ * by Rob Nation
++ * Copyright 1993, Robert Nation
++ *     You may use this code for any purpose, as long as the original
++ *     copyright remains in the source code and all documentation
++ */
++
++/* ---------------------------- included header files ---------------------- */
++
++#include "config.h"
++
++#include <stdio.h>
++#include <math.h>
++
++#include "libs/fvwmlib.h"
++#include "libs/FScreen.h"
++#include "libs/charmap.h"
++#include "libs/wcontext.h"
++#include "fvwm.h"
++#include "externs.h"
++#include "execcontext.h"
++#include "functions.h"
++#include "conditional.h"
++#include "misc.h"
++#include "screen.h"
++#include "update.h"
++#include "style.h"
++#include "focus.h"
++#include "geometry.h"
++#include "stack.h"
++#include "commands.h"
++#include "decorations.h"
++#include "virtual.h"
++
++/* ---------------------------- local definitions -------------------------- */
++
++/* ---------------------------- local macros ------------------------------- */
++
++/* ---------------------------- imports ------------------------------------ */
++
++/* ---------------------------- included code files ------------------------ */
++
++/* ---------------------------- local types -------------------------------- */
++
++/* ---------------------------- forward declarations ----------------------- */
++
++/* ---------------------------- local variables ---------------------------- */
++
++/* ---------------------------- exported variables (globals) --------------- */
++
++/* ---------------------------- local functions ---------------------------- */
++
++/*
++ *
++ * Direction = 1 ==> "Next" operation
++ * Direction = -1 ==> "Previous" operation
++ * Direction = 0 ==> operation on current window (returns pass or fail)
++ *
++ */
++static FvwmWindow *Circulate(
++	FvwmWindow *sf, char *action, int Direction, char **restofline)
++{
++	int pass = 0;
++	FvwmWindow *fw, *found = NULL;
++	WindowConditionMask mask;
++	char *flags;
++
++	/* Create window mask */
++	flags = CreateFlagString(action, restofline);
++	DefaultConditionMask(&mask);
++	if (Direction == 0)
++	{ /* override for Current [] */
++		mask.my_flags.use_circulate_hit = 1;
++		mask.my_flags.use_circulate_hit_icon = 1;
++		mask.my_flags.use_circulate_hit_shaded = 1;
++	}
++	CreateConditionMask(flags, &mask);
++	if (flags)
++	{
++		free(flags);
++	}
++	if (sf == NULL || Direction == 0)
++	{
++		sf = get_focus_window();
++	}
++	if (sf != NULL)
++	{
++		if (Direction > 0)
++		{
++			fw = sf->prev;
++		}
++		else if (Direction < 0)
++		{
++			fw = sf->next;
++		}
++		else
++		{
++			fw = sf;
++		}
++	}
++	else
++	{
++		fw = NULL;
++		if (Direction == 0)
++		{
++			FreeConditionMask(&mask);
++			return NULL;
++		}
++	}
++
++	for (pass = 0; pass < 3 && !found; pass++)
++	{
++		while (fw && !found && fw != &Scr.FvwmRoot)
++		{
++			/* Make CirculateUp and CirculateDown take args. by
++			 * Y.NOMURA */
++			if (MatchesConditionMask(fw, &mask))
++			{
++				found = fw;
++			}
++			else
++			{
++				if (Direction > 0)
++				{
++					fw = fw->prev;
++				}
++				else
++				{
++					fw = fw->next;
++				}
++			}
++			if (Direction == 0)
++			{
++				FreeConditionMask(&mask);
++				return found;
++			}
++		}
++		if (fw == NULL || fw == &Scr.FvwmRoot)
++		{
++			if (Direction > 0)
++			{
++				/* Go to end of list */
++				for (fw = Scr.FvwmRoot.next; fw && fw->next;
++				     fw = fw->next)
++				{
++					/* nop */
++				}
++			}
++			else
++			{
++				/* Go to top of list */
++				fw = Scr.FvwmRoot.next;
++			}
++		}
++	}
++	FreeConditionMask(&mask);
++
++	return found;
++}
++
++static void circulate_cmd(
++	F_CMD_ARGS, int new_context, int circ_dir, Bool do_use_found,
++	Bool do_exec_on_match)
++{
++	FvwmWindow *found;
++	char *restofline;
++
++	found = Circulate(exc->w.fw, action, circ_dir, &restofline);
++	if (cond_rc != NULL)
++	{
++		cond_rc->rc = (found == NULL) ? COND_RC_NO_MATCH : COND_RC_OK;
++	}
++	if ((!found == !do_exec_on_match) && restofline)
++	{
++		const exec_context_t *exc2;
++		exec_context_changes_t ecc;
++		int flags;
++
++		ecc.w.fw = (do_use_found == True) ? found : NULL;
++		if (found != NULL)
++		{
++			ecc.w.w = FW_W(found);
++			flags = FUNC_DONT_DEFER;
++		}
++		else
++		{
++			ecc.w.w = None;
++			flags = 0;
++		}
++		ecc.w.wcontext = new_context;
++		exc2 = exc_clone_context(
++			exc, &ecc, ECC_FW | ECC_W | ECC_WCONTEXT);
++		execute_function(cond_rc, exc2, restofline, flags);
++		exc_destroy_context(exc2);
++	}
++
++	return;
++}
++
++static void select_cmd(F_CMD_ARGS)
++{
++	char *restofline;
++	char *flags;
++	WindowConditionMask mask;
++	FvwmWindow * const fw = exc->w.fw;
++
++	if (!fw || IS_EWMH_DESKTOP(FW_W(fw)))
++	{
++		if (cond_rc != NULL)
++		{
++			cond_rc->rc = COND_RC_ERROR;
++		}
++		return;
++	}
++	flags = CreateFlagString(action, &restofline);
++	DefaultConditionMask(&mask);
++	mask.my_flags.use_circulate_hit = 1;
++	mask.my_flags.use_circulate_hit_icon = 1;
++	mask.my_flags.use_circulate_hit_shaded = 1;
++	CreateConditionMask(flags, &mask);
++	if (flags)
++	{
++		free(flags);
++	}
++	if (MatchesConditionMask(fw, &mask) && restofline)
++	{
++		if (cond_rc != NULL)
++		{
++			cond_rc->rc = COND_RC_OK;
++		}
++		execute_function_override_wcontext(
++			cond_rc, exc, restofline, 0, C_WINDOW);
++	}
++	else if (cond_rc != NULL)
++	{
++		cond_rc->rc = COND_RC_NO_MATCH;
++	}
++	FreeConditionMask(&mask);
++
++	return;
++}
++
++static Bool cond_check_access(char *file, int type, Bool im)
++{
++	char *full_file;
++	char *path = NULL;
++
++	if (!file || *file == 0)
++	{
++		return False;
++	}
++	if (file[0] == '/')
++	{
++		if (access(file, type) == 0)
++		{
++			return True;
++		}
++		else
++		{
++			return False;
++		}
++	}
++	if (type != X_OK && im == False)
++	{
++		return False;
++	}
++	if (im == False)
++	{
++		path = getenv("PATH");
++	}
++	else
++	{
++		path = PictureGetImagePath();
++	}
++	if (path == NULL || *path == 0)
++	{
++		return False;
++	}
++	full_file = searchPath(path, file, NULL, type);
++	if (full_file)
++	{
++		free(full_file);
++		return True;
++	}
++	return False;
++}
++
++/* ---------------------------- interface functions ------------------------ */
++
++/*
++ * Parses the flag string and returns the text between [ ] or ( )
++ * characters.  The start of the rest of the line is put in restptr.
++ * Note that the returned string is allocated here and it must be
++ * freed when it is not needed anymore.
++ * NOTE - exported via .h
++ */
++char *CreateFlagString(char *string, char **restptr)
++{
++	char *retval;
++	char *c;
++	char *start;
++	char closeopt;
++	int length;
++
++	c = string;
++	while (isspace((unsigned char)*c) && (*c != 0))
++	{
++		c++;
++	}
++
++
++	if (*c == '[' || *c == '(')
++	{
++		char *d;
++
++		/* Get the text between [ ] or ( ) */
++		if (*c == '[')
++		{
++			closeopt = ']';
++		}
++		else
++		{
++			closeopt = ')';
++		}
++		c++;
++		start = c;
++		length = 0;
++		while (*c != closeopt)
++		{
++			if (*c == 0)
++			{
++				fvwm_msg(ERR, "CreateFlagString",
++					 "Conditionals require closing "
++					 "parenthesis");
++				*restptr = NULL;
++				return NULL;
++			}
++
++			/* skip quoted string */
++			d = SkipQuote(c, NULL, NULL, NULL);
++			length += d - c;
++			c = d;
++		}
++
++		/* We must allocate a new string because we null terminate the
++		 * string between the [ ] or ( ) characters. */
++		retval = safemalloc(length + 1);
++		strncpy(retval, start, length);
++		retval[length] = 0;
++
++		*restptr = c + 1;
++	}
++	else
++	{
++		retval = NULL;
++		*restptr = c;
++	}
++
++	return retval;
++}
++
++/*
++ * The name_condition field of the mask is allocated in CreateConditionMask.
++ * It must be freed.
++ * NOTE - exported via .h
++ */
++void FreeConditionMask(WindowConditionMask *mask)
++{
++	struct name_condition *pp,*pp2;
++	struct namelist *p,*p2;
++
++	for (pp=mask->name_condition; pp; )
++	{
++		/* One malloc() is done for all the name strings.
++		   The string is tokenised & the name fields point to
++		   different parts of the one string.
++		   The start of the string is the first name in the string
++		   which is actually the last node in the linked list. */
++		for (p=pp->namelist; p; )
++		{
++			p2=p->next;
++			if(!p2)
++			{
++				free(p->name - (pp->invert ? 1 : 0));
++			}
++			free(p);
++			p=p2;
++		}
++		pp2=pp->next;
++		free(pp);
++		pp=pp2;
++	}
++}
++
++/* Assign the default values for the window mask
++ * NOTE - exported via .h */
++void DefaultConditionMask(WindowConditionMask *mask)
++{
++	memset(mask, 0, sizeof(WindowConditionMask));
++	/* -2  means no layer condition, -1 means current */
++	mask->layer = -2;
++
++	return;
++}
++
++/*
++ * Note that this function allocates the name field of the mask struct.
++ * FreeConditionMask must be called for the mask when the mask is discarded.
++ * NOTE - exported via .h
++ */
++void CreateConditionMask(char *flags, WindowConditionMask *mask)
++{
++	char *condition;
++	char *prev_condition = NULL;
++	char *tmp;
++	unsigned int state;
++
++	if (flags == NULL)
++	{
++		return;
++	}
++
++	/* Next parse the flags in the string. */
++	tmp = flags;
++	tmp = GetNextSimpleOption(tmp, &condition);
++
++	while (condition)
++	{
++		char *cond;
++		int on;
++
++		cond = condition;
++		on = 1;
++		if (*cond == '!')
++		{
++			on = 0;
++			cond++;
++		}
++		if (StrEquals(cond,"AcceptsFocus"))
++		{
++			mask->my_flags.do_accept_focus = on;
++			mask->my_flags.use_do_accept_focus = 1;
++		}
++		else if (StrEquals(cond,"Focused"))
++		{
++			mask->my_flags.needs_focus =
++				(on) ? NEEDS_TRUE : NEEDS_FALSE;
++		}
++		else if (StrEquals(cond,"HasPointer"))
++		{
++			mask->my_flags.needs_pointer =
++				(on) ? NEEDS_TRUE : NEEDS_FALSE;
++		}
++		else if (StrEquals(cond,"Iconic"))
++		{
++			SET_ICONIFIED(mask, on);
++			SETM_ICONIFIED(mask, 1);
++		}
++		else if (StrEquals(cond,"Visible"))
++		{
++			SET_PARTIALLY_VISIBLE(mask, on);
++			SETM_PARTIALLY_VISIBLE(mask, 1);
++		}
++		else if (StrEquals(cond,"Overlapped"))
++		{
++			mask->my_flags.needs_overlapped = on;
++			mask->my_flags.do_check_overlapped = 1;
++		}
++		else if (StrEquals(cond,"PlacedByButton"))
++		{
++			int button;
++			int button_mask;
++
++			if (sscanf(tmp, "%d", &button) &&
++			    (button >= 1 &&
++			     button <= NUMBER_OF_EXTENDED_MOUSE_BUTTONS))
++			{
++				free(condition);
++				tmp = GetNextToken (tmp, &condition);
++				button_mask = (1<<(button-1));
++			}
++			else
++			{
++				button_mask =
++				     (1<<NUMBER_OF_EXTENDED_MOUSE_BUTTONS) - 1;
++			}
++			if (on)
++			{
++				if (mask->placed_by_button_mask &
++				    mask->placed_by_button_set_mask &
++				    ~button_mask)
++				{
++				  	  fvwm_msg(WARN, "PlacedByButton",
++						   "Condition always False.");
++				}
++				mask->placed_by_button_mask |= button_mask;
++			}
++			else
++			{
++				mask->placed_by_button_mask &= ~button_mask;
++			}
++			mask->placed_by_button_set_mask |= button_mask;
++		}
++		else if (StrEquals(cond,"PlacedByButton3"))
++		{
++			if (on)
++			{
++				if (mask->placed_by_button_mask &
++				    mask->placed_by_button_set_mask & ~(1<<2))
++				{
++				  	  fvwm_msg(WARN, "PlacedByButton3",
++						   "Condition always False.");
++				}
++				mask->placed_by_button_mask |= (1<<2);
++			}
++			else
++			{
++				mask->placed_by_button_mask &= ~(1<<2);
++			}
++			mask->placed_by_button_set_mask |= (1<<2);
++		}
++		else if (StrEquals(cond,"Raised"))
++		{
++			SET_FULLY_VISIBLE(mask, on);
++			SETM_FULLY_VISIBLE(mask, 1);
++		}
++		else if (StrEquals(cond,"Sticky"))
++		{
++			SET_STICKY_ACROSS_PAGES(mask, on);
++			SET_STICKY_ACROSS_DESKS(mask, on);
++			SETM_STICKY_ACROSS_PAGES(mask, 1);
++			SETM_STICKY_ACROSS_DESKS(mask, 1);
++		}
++		else if (StrEquals(cond,"StickyAcrossPages"))
++		{
++			SET_STICKY_ACROSS_PAGES(mask, on);
++			SETM_STICKY_ACROSS_PAGES(mask, 1);
++		}
++		else if (StrEquals(cond,"StickyAcrossDesks"))
++		{
++			SET_STICKY_ACROSS_DESKS(mask, on);
++			SETM_STICKY_ACROSS_DESKS(mask, 1);
++		}
++		else if (StrEquals(cond,"StickyIcon"))
++		{
++			SET_ICON_STICKY_ACROSS_PAGES(mask, on);
++			SET_ICON_STICKY_ACROSS_DESKS(mask, on);
++			SETM_ICON_STICKY_ACROSS_PAGES(mask, 1);
++			SETM_ICON_STICKY_ACROSS_DESKS(mask, 1);
++		}
++		else if (StrEquals(cond,"StickyAcrossPagesIcon"))
++		{
++			SET_ICON_STICKY_ACROSS_PAGES(mask, on);
++			SETM_ICON_STICKY_ACROSS_PAGES(mask, 1);
++		}
++		else if (StrEquals(cond,"StickyAcrossDesksIcon"))
++		{
++			SET_ICON_STICKY_ACROSS_DESKS(mask, on);
++			SETM_ICON_STICKY_ACROSS_DESKS(mask, 1);
++		}
++		else if (StrEquals(cond,"Maximized"))
++		{
++			SET_MAXIMIZED(mask, on);
++			SETM_MAXIMIZED(mask, 1);
++		}
++		else if (StrEquals(cond,"FixedSize"))
++		{
++			/* don't set mask here, because we make the test here
++			   (and don't compare against window's mask)
++			   by checking allowed function */
++			SET_SIZE_FIXED(mask, on);
++			SETM_SIZE_FIXED(mask, 1);
++		}
++		else if (StrEquals(cond, "FixedPosition"))
++		{
++			SET_FIXED(mask, on);
++			SETM_FIXED(mask, 1);
++		}
++		else if (StrEquals(cond,"HasHandles"))
++		{
++			SET_HAS_HANDLES(mask, on);
++			SETM_HAS_HANDLES(mask, 1);
++		}
++		else if (StrEquals(cond,"Iconifiable"))
++		{
++			SET_IS_UNICONIFIABLE(mask, !on);
++			SETM_IS_UNICONIFIABLE(mask, 1);
++		}
++		else if (StrEquals(cond,"Maximizable"))
++		{
++			SET_IS_UNMAXIMIZABLE(mask, !on);
++			SETM_IS_UNMAXIMIZABLE(mask, 1);
++		}
++		else if (StrEquals(cond,"Closable"))
++		{
++			SET_IS_UNCLOSABLE(mask, !on);
++			SETM_IS_UNCLOSABLE(mask, 1);
++		}
++		else if (StrEquals(cond,"Shaded"))
++		{
++			SET_SHADED(mask, on);
++			SETM_SHADED(mask, 1);
++		}
++		else if (StrEquals(cond,"Transient"))
++		{
++			SET_TRANSIENT(mask, on);
++			SETM_TRANSIENT(mask, 1);
++		}
++		else if (StrEquals(cond,"PlacedByFvwm"))
++		{
++			SET_PLACED_BY_FVWM(mask, on);
++			SETM_PLACED_BY_FVWM(mask, 1);
++		}
++		else if (StrEquals(cond,"CurrentDesk"))
++		{
++			mask->my_flags.needs_current_desk = on;
++			mask->my_flags.do_check_desk = 1;
++		}
++		else if (StrEquals(cond,"CurrentPage"))
++		{
++			mask->my_flags.needs_current_desk_and_page = on;
++			mask->my_flags.do_check_desk_and_page = 1;
++		}
++		else if (StrEquals(cond,"CurrentGlobalPage"))
++		{
++			mask->my_flags.needs_current_desk_and_global_page = on;
++			mask->my_flags.do_check_desk_and_global_page = 1;
++		}
++		else if (StrEquals(cond,"CurrentPageAnyDesk") ||
++			 StrEquals(cond,"CurrentScreen"))
++		{
++			mask->my_flags.needs_current_page = on;
++			mask->my_flags.do_check_page = 1;
++		}
++		else if (StrEquals(cond,"AnyScreen"))
++		{
++			mask->my_flags.do_not_check_screen = on;
++		}
++		else if (StrEquals(cond,"CurrentGlobalPageAnyDesk"))
++		{
++			mask->my_flags.needs_current_global_page = on;
++			mask->my_flags.do_check_global_page = 1;
++		}
++		else if (StrEquals(cond,"CirculateHit"))
++		{
++			mask->my_flags.use_circulate_hit = on;
++		}
++		else if (StrEquals(cond,"CirculateHitIcon"))
++		{
++			mask->my_flags.use_circulate_hit_icon = on;
++		}
++		else if (StrEquals(cond,"CirculateHitShaded"))
++		{
++			mask->my_flags.use_circulate_hit_shaded = on;
++		}
++		else if (StrEquals(cond,"State"))
++		{
++			if (sscanf(tmp, "%u", &state) &&
++			    state >= 0 && state <= 31)
++			{
++				state = (1 << state);
++				if (on)
++				{
++					SET_USER_STATES(mask, state);
++				}
++				else
++				{
++					CLEAR_USER_STATES(mask, state);
++				}
++				SETM_USER_STATES(mask, state);
++				free(condition);
++				tmp = GetNextToken(tmp, &condition);
++			}
++		}
++		else if (StrEquals(condition, "Layer"))
++		{
++			if (sscanf(tmp, "%d", &mask->layer))
++			{
++				free(condition);
++				tmp = GetNextToken (tmp, &condition);
++				if (mask->layer < 0)
++				{
++					/* silently ignore invalid layers */
++					mask->layer = -2;
++				}
++			}
++			else
++			{
++				/* needs current layer */
++				mask->layer = -1;
++			}
++			mask->my_flags.needs_same_layer = on;
++		}
++		else
++		{
++			struct name_condition *pp;
++			struct namelist *p;
++			char *condp;
++
++			pp = (struct name_condition *)
++				safemalloc(sizeof(struct name_condition));
++			pp->invert = (!on ? True : False);
++			pp->namelist = NULL;
++			pp->next = mask->name_condition;
++			mask->name_condition = pp;
++			for(condp=cond; ; )
++			{
++				p = (struct namelist *)
++					safemalloc(sizeof(struct namelist));
++				p->name=condp;
++				p->next=pp->namelist;
++				pp->namelist=p;
++				while(*condp && *condp != '|')
++				{
++					condp++;
++				}
++				if(!*condp)
++				{
++					break;
++				}
++				*condp++='\0';
++			}
++			condition = NULL;	/* so it won't be freed */
++		}
++
++		if (prev_condition)
++		{
++			free(prev_condition);
++		}
++
++		prev_condition = condition;
++		tmp = GetNextSimpleOption(tmp, &condition);
++	}
++	if (prev_condition)
++	{
++		free(prev_condition);
++	}
++
++	return;
++}
++
++/*
++ * Checks whether the given window matches the mask created with
++ * CreateConditionMask.
++ * NOTE - exported via .h
++ */
++Bool MatchesConditionMask(FvwmWindow *fw, WindowConditionMask *mask)
++{
++	int does_match;
++	int is_on_desk;
++	int is_on_page;
++	int is_on_global_page;
++	FvwmWindow *sf = get_focus_window();
++	struct name_condition *pp;
++	struct namelist *p;
++	char *name;
++
++	/* match FixedSize conditional */
++	/* special treatment for FixedSize, because more than just
++	   the is_size_fixed flag makes a window unresizable (width and height
++	   hints etc.) */
++	if (IS_SIZE_FIXED(mask) &&
++	    mask->flag_mask.common.s.is_size_fixed &&
++	    is_function_allowed(F_RESIZE,NULL,fw,True,False))
++	{
++	        return False;
++	}
++	if (!IS_SIZE_FIXED(mask) &&
++	    mask->flag_mask.common.s.is_size_fixed &&
++	    !is_function_allowed(F_RESIZE,NULL,fw,True,False))
++	{
++	        return False;
++	}
++	if (IS_FIXED(mask) &&
++	    mask->flag_mask.common.s.is_fixed &&
++	    is_function_allowed(F_MOVE, NULL, fw, True, False))
++	{
++	        return False;
++	}
++	if (!IS_FIXED(mask) &&
++	    mask->flag_mask.common.s.is_fixed &&
++	    !is_function_allowed(F_MOVE, NULL, fw, True, False))
++	{
++	        return False;
++	}
++	if (IS_UNICONIFIABLE(mask) &&
++	    mask->flag_mask.common.s.is_uniconifiable &&
++	    is_function_allowed(F_ICONIFY,NULL,fw,True,False))
++	{
++	        return False;
++	}
++	if (!IS_UNICONIFIABLE(mask) &&
++	    mask->flag_mask.common.s.is_uniconifiable &&
++	    !is_function_allowed(F_ICONIFY,NULL,fw,True,False))
++	{
++	        return False;
++	}
++	if (IS_UNMAXIMIZABLE(mask) &&
++	    mask->flag_mask.common.s.is_unmaximizable &&
++	    is_function_allowed(F_MAXIMIZE,NULL,fw,True,False))
++	{
++	        return False;
++	}
++	if (!IS_UNMAXIMIZABLE(mask) &&
++	    mask->flag_mask.common.s.is_unmaximizable &&
++	    !is_function_allowed(F_MAXIMIZE,NULL,fw,True,False))
++	{
++	        return False;
++	}
++	if (IS_UNCLOSABLE(mask) &&
++	    mask->flag_mask.common.s.is_unclosable &&
++	    (is_function_allowed(F_CLOSE,NULL,fw,True,False) ||
++	     is_function_allowed(F_DELETE,NULL,fw,True,False) ||
++	     is_function_allowed(F_DESTROY,NULL,fw,True,False)))
++	{
++	        return False;
++	}
++	if (!IS_UNCLOSABLE(mask) &&
++	    mask->flag_mask.common.s.is_unclosable &&
++	    (!is_function_allowed(F_CLOSE,NULL,fw,True,False) &&
++	     !is_function_allowed(F_DELETE,NULL,fw,True,False) &&
++	     !is_function_allowed(F_DESTROY,NULL,fw,True,False)))
++	{
++	        return False;
++	}
++	if (!blockcmpmask((char *)&(fw->flags), (char *)&(mask->flags),
++			  (char *)&(mask->flag_mask), sizeof(fw->flags)))
++	{
++		return False;
++	}
++	if (!mask->my_flags.use_circulate_hit && DO_SKIP_CIRCULATE(fw))
++	{
++		return False;
++	}
++	if (!mask->my_flags.use_circulate_hit_icon && IS_ICONIFIED(fw) &&
++	    DO_SKIP_ICON_CIRCULATE(fw))
++	{
++		return False;
++	}
++	if (!mask->my_flags.use_circulate_hit_shaded && IS_SHADED(fw) &&
++	    DO_SKIP_SHADED_CIRCULATE(fw))
++	{
++		return False;
++	}
++	if (IS_ICONIFIED(fw) && IS_TRANSIENT(fw) && IS_ICONIFIED_BY_PARENT(fw))
++	{
++		return False;
++	}
++
++	/* desk and page matching */
++	is_on_desk = 1;
++	if (mask->my_flags.do_check_desk ||
++	    mask->my_flags.do_check_desk_and_page ||
++	    mask->my_flags.do_check_desk_and_global_page)
++	{
++		is_on_desk = (fw->Desk == Scr.CurrentDesk);
++	}
++	is_on_page = 1;
++	if (mask->my_flags.do_check_page ||
++	    mask->my_flags.do_check_desk_and_page)
++	{
++		if (FScreenIsEnabled() && !mask->my_flags.do_not_check_screen)
++		{
++			is_on_page = !!FScreenIsRectangleOnScreen(
++				NULL, FSCREEN_CURRENT, &(fw->g.frame));
++		}
++		else
++		{
++			is_on_page = !!IsRectangleOnThisPage(
++				&(fw->g.frame), Scr.CurrentDesk);
++		}
++	}
++	is_on_global_page = 1;
++	if (mask->my_flags.do_check_global_page ||
++	    mask->my_flags.do_check_desk_and_global_page)
++	{
++		is_on_global_page = !!IsRectangleOnThisPage(
++			&(fw->g.frame), Scr.CurrentDesk);
++	}
++
++	if (mask->my_flags.do_check_desk_and_page)
++	{
++		int is_on_desk_and_page;
++
++		is_on_desk_and_page = (is_on_desk && is_on_page);
++		if (mask->my_flags.needs_current_desk_and_page !=
++		    is_on_desk_and_page)
++		{
++			return False;
++		}
++	}
++	else if (mask->my_flags.do_check_desk_and_global_page)
++	{
++		int is_on_desk_and_global_page;
++
++		is_on_desk_and_global_page = (is_on_desk && is_on_global_page);
++		if (mask->my_flags.needs_current_desk_and_global_page !=
++		    is_on_desk_and_global_page)
++		{
++			return False;
++		}
++	}
++	if (mask->my_flags.do_check_desk &&
++	    mask->my_flags.needs_current_desk != is_on_desk)
++	{
++		return False;
++	}
++	if (mask->my_flags.do_check_page)
++	{
++		if (mask->my_flags.needs_current_page != is_on_page)
++		{
++			return False;
++		}
++	}
++	else if (mask->my_flags.do_check_global_page)
++	{
++		if (mask->my_flags.needs_current_global_page !=
++		    is_on_global_page)
++		{
++			return False;
++		}
++	}
++
++	for (pp = mask->name_condition; pp; pp = pp->next)
++	{
++		does_match = 0;
++		for (p = pp->namelist; p; p = p->next)
++		{
++			name=p->name;
++			does_match |= matchWildcards(name, fw->name.name);
++			does_match |= matchWildcards(name, fw->icon_name.name);
++			if(fw->class.res_class)
++				does_match |= matchWildcards(name,
++					fw->class.res_class);
++			if(fw->class.res_name)
++				does_match |= matchWildcards(name,
++					fw->class.res_name);
++		}
++		if(( pp->invert &&  does_match) ||
++		   (!pp->invert && !does_match))
++		{
++			return False;
++		}
++	}
++
++	if (mask->layer == -1 && sf)
++	{
++		int is_same_layer;
++
++		is_same_layer = (fw->layer == sf->layer);
++		if (mask->my_flags.needs_same_layer != is_same_layer)
++		{
++			return False;
++		}
++	}
++	if (mask->layer >= 0)
++	{
++		int is_same_layer;
++
++		is_same_layer = (fw->layer == mask->layer);
++		if (mask->my_flags.needs_same_layer != is_same_layer)
++		{
++			return False;
++		}
++	}
++	if (mask->placed_by_button_set_mask)
++	{
++		if (!((mask->placed_by_button_set_mask &
++			(1<<(fw->placed_by_button - 1))) ==
++		     (mask->placed_by_button_set_mask &
++		      mask->placed_by_button_mask)))
++		{
++			return False;
++		}
++	}
++	if (GET_USER_STATES(mask) !=
++	    (mask->flag_mask.common.user_states & GET_USER_STATES(fw)))
++	{
++		return False;
++	}
++	if (mask->my_flags.use_do_accept_focus)
++	{
++		Bool f;
++
++		f = focus_does_accept_input_focus(fw);
++		if (fw && !FP_DO_FOCUS_BY_FUNCTION(FW_FOCUS_POLICY(fw)))
++		{
++			f = False;
++		}
++		else if (fw && FP_IS_LENIENT(FW_FOCUS_POLICY(fw)))
++		{
++			f = True;
++		}
++		if (!f != !mask->my_flags.do_accept_focus)
++		{
++			return False;
++		}
++	}
++	if (mask->my_flags.needs_focus != NEEDS_ANY)
++	{
++		int is_focused;
++
++		is_focused = (fw == get_focus_window());
++		if (!is_focused && mask->my_flags.needs_focus == NEEDS_TRUE)
++		{
++			return False;
++		}
++		else if (is_focused &&
++			 mask->my_flags.needs_focus == NEEDS_FALSE)
++		{
++			return False;
++		}
++	}
++	if (mask->my_flags.needs_pointer != NEEDS_ANY)
++	{
++		int has_pointer;
++		FvwmWindow *t;
++
++		t = get_pointer_fvwm_window();
++		if (t != NULL && t == fw)
++		{
++			has_pointer = 1;
++		}
++		else
++		{
++			has_pointer = 0;
++		}
++		if (!has_pointer && mask->my_flags.needs_pointer == NEEDS_TRUE)
++		{
++			return False;
++		}
++		else if (has_pointer &&
++			 mask->my_flags.needs_pointer == NEEDS_FALSE)
++		{
++			return False;
++		}
++	}
++	if (mask->my_flags.do_check_overlapped)
++	{
++		int is_o;
++
++		is_o = (is_on_top_of_layer(fw) == False);
++		if (is_o != mask->my_flags.needs_overlapped)
++		{
++			return False;
++		}
++	}
++
++	return True;
++}
++
++static void direction_cmd(F_CMD_ARGS, Bool is_scan)
++{
++	rectangle my_g;
++	rectangle his_g;
++	int my_cx;
++	int my_cy;
++	int his_cx;
++	int his_cy;
++	int cross = 0;
++	int offset = 0;
++	int distance = 0;
++	int cycle = False;
++	int forward = False;
++	int score;
++	int best_cross = 0;
++	int best_score;
++	int worst_score = -1;
++	FvwmWindow *tfw;
++	FvwmWindow *fw_best;
++	int dir;
++	int dir2;
++	Bool right_handed=False;
++	char *flags;
++	char *restofline;
++	char *tmp;
++	float tx;
++	float ty;
++	WindowConditionMask mask;
++	Bool is_pointer_relative;
++	FvwmWindow * const fw = exc->w.fw;
++
++	/* Parse the direction. */
++	tmp = PeekToken(action, &action);
++	if (StrEquals(tmp, "FromPointer"))
++	{
++		is_pointer_relative = True;
++		tmp = PeekToken(action, &action);
++	}
++	else
++	{
++		is_pointer_relative = False;
++	}
++	dir = gravity_parse_dir_argument(tmp, NULL, -1);
++	if (dir == -1 || dir > DIR_ALL_MASK)
++	{
++		fvwm_msg(ERR, "Direction", "Invalid direction %s",
++			 (tmp) ? tmp : "");
++		if (cond_rc != NULL)
++		{
++			cond_rc->rc = COND_RC_ERROR;
++		}
++		return;
++	}
++	if (is_scan)
++	{
++		cycle = True;
++		tmp = PeekToken(action, &action);
++		if ( ! tmp )
++		{
++			fvwm_msg(
++				ERR, "Direction", "Missing minor direction %s",
++				(tmp) ? tmp : "");
++			if (cond_rc != NULL)
++			{
++				cond_rc->rc = COND_RC_ERROR;
++			}
++			return;
++		}
++		dir2 = gravity_parse_dir_argument(tmp, NULL, -1);
++		/* if enum direction_t changes, this is trashed. */
++		if (dir2 == -1 || dir2 > DIR_NW ||
++		    (dir < 4) != (dir2 < 4) || (abs(dir - dir2) & 1) != 1)
++		{
++			fvwm_msg(
++				ERR, "Direction", "Invalid minor direction %s",
++				(tmp) ? tmp : "");
++			if (cond_rc != NULL)
++			{
++				cond_rc->rc = COND_RC_ERROR;
++			}
++			return;
++		}
++		else if (dir2 - dir == 1 || dir2 - dir == -3)
++		{
++			right_handed=True;
++		}
++	}
++
++	/* Create the mask for flags */
++	flags = CreateFlagString(action, &restofline);
++	if (!restofline)
++	{
++		if (flags)
++		{
++			free(flags);
++		}
++		if (cond_rc != NULL)
++		{
++			cond_rc->rc = COND_RC_NO_MATCH;
++		}
++		return;
++	}
++	DefaultConditionMask(&mask);
++	CreateConditionMask(flags, &mask);
++	if (flags)
++	{
++		free(flags);
++	}
++
++	/* If there is a focused window, use that as a starting point.
++	 * Otherwise we use the pointer as a starting point. */
++	if (fw && is_pointer_relative == False)
++	{
++		get_visible_window_or_icon_geometry(fw, &my_g);
++		my_cx = my_g.x + my_g.width / 2;
++		my_cy = my_g.y + my_g.height / 2;
++	}
++	else
++	{
++		if (FQueryPointer(
++			    dpy, Scr.Root, &JunkRoot, &JunkChild, &my_g.x,
++			    &my_g.y, &JunkX, &JunkY, &JunkMask) == False)
++		{
++			/* pointer is on a different screen */
++			my_g.x = 0;
++			my_g.y = 0;
++		}
++		my_g.width = 1;
++		my_g.height = 1;
++		my_cx = my_g.x;
++		my_cy = my_g.y;
++	}
++
++	/* Next we iterate through all windows and choose the closest one in
++	 * the wanted direction. */
++	fw_best = NULL;
++	best_score = -1;
++	for (tfw = Scr.FvwmRoot.next; tfw != NULL; tfw = tfw->next)
++	{
++		/* Skip every window that does not match conditionals.  Also
++		 * skip the currently focused window.  That would be too
++		 * close. :) */
++		if (tfw == fw || !MatchesConditionMask(tfw, &mask))
++		{
++			continue;
++		}
++
++		/* Calculate relative location of the window. */
++		get_visible_window_or_icon_geometry(tfw, &his_g);
++		his_g.x -= my_cx;
++		his_g.y -= my_cy;
++		his_cx = his_g.x + his_g.width / 2;
++		his_cy = his_g.y + his_g.height / 2;
++
++		if (dir > DIR_MAJOR_MASK && dir <= DIR_MINOR_MASK)
++		{
++			int tx;
++			/* Rotate the diagonals 45 degrees counterclockwise. To
++			 * do this, multiply the matrix /+h +h\ with the vector
++			 * (x y).                       \-h +h/
++			 * h = sqrt(0.5). We can set h := 1 since absolute
++			 * distance doesn't * matter here. */
++			tx = his_cx + his_cy;
++			his_cy = -his_cx + his_cy;
++			his_cx = tx;
++		}
++		/* Arrange so that distance and offset are positive in desired
++		 * direction. */
++		switch (dir)
++		{
++		case DIR_S:
++		case DIR_SW:
++			forward = True;
++		case DIR_N:
++		case DIR_NE:
++			cross = -his_cx;
++			offset = (his_cx < 0) ? -his_cx : his_cx;
++			distance = (dir == DIR_N || dir == DIR_NE) ?
++				-his_cy : his_cy;
++			break;
++		case DIR_E: /* E */
++		case DIR_SE: /* SE */
++			forward = True;
++		case DIR_W: /* W */
++		case DIR_NW: /* NW */
++			cross = his_cy;
++			offset = (his_cy < 0) ? -his_cy : his_cy;
++			distance = (dir == DIR_W || dir == DIR_NW) ?
++				-his_cx : his_cx;
++			break;
++		case DIR_C:
++			offset = 0;
++			tx = (float)his_cx;
++			ty = (float)his_cy;
++			distance = (int)sqrt(tx * tx + ty * ty);
++			break;
++		}
++
++		if (cycle)
++		{
++			offset=0;
++		}
++		else if (distance < 0)
++		{
++			/* Target must be in given direction. */
++			continue;
++		}
++		else if (distance == 0 && dir != DIR_C)
++		{
++			continue;
++		}
++
++		/* Calculate score for this window.  The smaller the better. */
++		score = distance + offset;
++		if (!right_handed)
++		{
++			cross= -cross;
++		}
++		if (cycle)
++		{
++			int ordered = (forward == (cross < best_cross));
++
++			if (distance < 0 && best_score == -1 &&
++				(score < worst_score ||
++				(score == worst_score && ordered)))
++			{
++				fw_best = tfw;
++				worst_score = score;
++				best_cross = cross;
++			}
++			if (score == 0 && forward == (cross < 0) &&
++			    dir != DIR_C)
++			{
++				continue;
++			}
++			if (distance >= 0 &&
++				(best_score == -1 || score < best_score ||
++				 (score == best_score && ordered)))
++			{
++				fw_best = tfw;
++				best_score = score;
++				best_cross = cross;
++			}
++		}
++		else
++		{
++			/* windows more than 45 degrees off the direction are
++			 * heavily penalized and will only be chosen if nothing
++			 * else within a million pixels */
++			if (offset > distance)
++			{
++				score += 1000000;
++			}
++			if (best_score == -1 || score < best_score ||
++			    (score == best_score && dir == DIR_C))
++			{
++				fw_best = tfw;
++				best_score = score;
++			}
++		}
++	} /* for */
++
++	if (fw_best)
++	{
++		if (cond_rc != NULL)
++		{
++			cond_rc->rc = COND_RC_OK;
++		}
++		execute_function_override_window(
++			cond_rc, exc, restofline, 0, fw_best);
++	}
++	else if (cond_rc != NULL)
++	{
++		cond_rc->rc = COND_RC_NO_MATCH;
++	}
++	FreeConditionMask(&mask);
++
++	return;
++}
++
++static int __rc_matches_rcstring_consume(
++	char **ret_rest, cond_rc_t *cond_rc, char *action)
++{
++	cond_rc_enum match_rc;
++	char *orig_flags;
++	char *flags;
++	int is_not_reversed = 1;
++	int ret;
++
++	/* Create window mask */
++	orig_flags = CreateFlagString(action, ret_rest);
++	flags = orig_flags;
++	if (flags == NULL)
++	{
++		match_rc = COND_RC_NO_MATCH;
++	}
++	else
++	{
++		if (*flags == '!')
++		{
++			is_not_reversed = 0;
++			flags++;
++		}
++		if (StrEquals(flags, "1") || StrEquals(flags, "match"))
++		{
++			match_rc = COND_RC_OK;
++		}
++		else if (StrEquals(flags, "0") || StrEquals(flags, "nomatch"))
++		{
++			match_rc = COND_RC_NO_MATCH;
++		}
++		else if (StrEquals(flags, "-1") || StrEquals(flags, "error"))
++		{
++			match_rc = COND_RC_ERROR;
++		}
++		else if (StrEquals(flags, "-2") || StrEquals(flags, "break"))
++		{
++			match_rc = COND_RC_BREAK;
++		}
++		else
++		{
++			match_rc = COND_RC_NO_MATCH;
++			/* Does anyone check for other numerical returncode
++			 * values? If so, this might have to be changed. */
++			fprintf(stderr, "Unrecognised condition \"%s\" in TestRc command.\n", flags);
++		}
++	}
++	if (orig_flags != NULL)
++	{
++		free(orig_flags);
++	}
++	ret = ((cond_rc->rc == match_rc) == is_not_reversed);
++
++	return ret;
++}
++
++/* ---------------------------- builtin commands --------------------------- */
++
++void CMD_Prev(F_CMD_ARGS)
++{
++	circulate_cmd(F_PASS_ARGS, C_WINDOW, -1, True, True);
++
++	return;
++}
++
++void CMD_Next(F_CMD_ARGS)
++{
++	circulate_cmd(F_PASS_ARGS, C_WINDOW, 1, True, True);
++
++	return;
++}
++
++void CMD_None(F_CMD_ARGS)
++{
++	circulate_cmd(F_PASS_ARGS, C_ROOT, 1, False, False);
++	/* invert return code */
++	switch (cond_rc->rc)
++	{
++	case COND_RC_OK:
++		cond_rc->rc = COND_RC_NO_MATCH;
++		break;
++	case COND_RC_NO_MATCH:
++		cond_rc->rc = COND_RC_OK;
++		break;
++	default:
++		break;
++	}
++
++	return;
++}
++
++void CMD_Any(F_CMD_ARGS)
++{
++	circulate_cmd(F_PASS_ARGS, exc->w.wcontext, 1, False, True);
++
++	return;
++}
++
++void CMD_Current(F_CMD_ARGS)
++{
++	circulate_cmd(F_PASS_ARGS, C_WINDOW, 0, True, True);
++
++	return;
++}
++
++void CMD_PointerWindow(F_CMD_ARGS)
++{
++	exec_context_changes_t ecc;
++
++	ecc.w.fw = get_pointer_fvwm_window();
++	exc = exc_clone_context(exc, &ecc, ECC_FW);
++	select_cmd(F_PASS_ARGS);
++	exc_destroy_context(exc);
++
++	return;
++}
++
++void CMD_ThisWindow(F_CMD_ARGS)
++{
++	select_cmd(F_PASS_ARGS);
++
++	return;
++}
++
++void CMD_Pick(F_CMD_ARGS)
++{
++	select_cmd(F_PASS_ARGS);
++
++	return;
++}
++
++void CMD_All(F_CMD_ARGS)
++{
++	FvwmWindow *t, **g;
++	char *restofline;
++	WindowConditionMask mask;
++	char *flags;
++	int num, i;
++	Bool does_any_window_match = False;
++	char *token;
++	Bool do_reverse = False;
++	Bool use_stack = False;
++
++	while (True) /* break when a non-option is found */
++	{
++		token = PeekToken(action, &restofline);
++		if (StrEquals(token, "Reverse"))
++		{
++			if (!*restofline)
++			{
++				/* if not any more actions, then Reverse
++				 * probably is some user function, so ignore
++				 * it and do the old  behaviour */
++				break;
++			}
++			else
++			{
++				do_reverse = True;
++				action = restofline;
++			}
++		}
++		else if (StrEquals(token, "UseStack"))
++		{
++			if (!*restofline)
++			{
++				/* if not any more actions, then UseStack
++				 * probably is some user function, so ignore
++				 * it and do the old behaviour */
++				break;
++			}
++			else
++			{
++				use_stack = True;
++				action = restofline;
++			}
++		}
++		else
++		{
++			/* No more options -- continue with flags and
++			 * commands */
++			break;
++		}
++	}
++
++	flags = CreateFlagString(action, &restofline);
++	DefaultConditionMask(&mask);
++	mask.my_flags.use_circulate_hit = 1;
++	mask.my_flags.use_circulate_hit_icon = 1;
++	mask.my_flags.use_circulate_hit_shaded = 1;
++	CreateConditionMask(flags, &mask);
++	if (flags)
++	{
++		free(flags);
++	}
++
++	num = 0;
++	for (t = Scr.FvwmRoot.next; t; t = t->next)
++	{
++		num++;
++	}
++	g = (FvwmWindow **)safemalloc(num * sizeof(FvwmWindow *));
++	num = 0;
++	if (!use_stack)
++	{
++		for (t = Scr.FvwmRoot.next; t; t = t->next)
++		{
++			if (MatchesConditionMask(t, &mask))
++			{
++				g[num++] = t;
++				does_any_window_match = True;
++			}
++		}
++	}
++	else
++	{
++		for (t = Scr.FvwmRoot.stack_next; t && t != &Scr.FvwmRoot;
++		     t = t->stack_next)
++		{
++			if (MatchesConditionMask(t, &mask))
++			{
++				g[num++] = t;
++				does_any_window_match = True;
++			}
++		}
++	}
++	if (do_reverse)
++	{
++		for (i = num-1; i >= 0; i--)
++		{
++			execute_function_override_window(
++				cond_rc, exc, restofline, 0, g[i]);
++		}
++	}
++	else
++	{
++		for (i = 0; i < num; i++)
++		{
++			execute_function_override_window(
++				cond_rc, exc, restofline, 0, g[i]);
++		}
++	}
++	if (cond_rc != NULL && cond_rc->rc != COND_RC_BREAK)
++	{
++		cond_rc->rc = (does_any_window_match == False) ?
++			COND_RC_NO_MATCH : COND_RC_OK;
++	}
++	free(g);
++	FreeConditionMask(&mask);
++
++	return;
++}
++
++/*
++ * Execute a function to the closest window in the given
++ * direction.
++ */
++void CMD_Direction(F_CMD_ARGS)
++{
++	direction_cmd(F_PASS_ARGS,False);
++}
++
++void CMD_ScanForWindow(F_CMD_ARGS)
++{
++	direction_cmd(F_PASS_ARGS,True);
++}
++
++void CMD_WindowId(F_CMD_ARGS)
++{
++	FvwmWindow *t;
++	char *token;
++	char *naction;
++	unsigned long win;
++	Bool use_condition = False;
++	Bool use_screenroot = False;
++	WindowConditionMask mask;
++	char *flags, *restofline;
++
++	/* Get window ID */
++	action = GetNextToken(action, &token);
++
++	if (token && StrEquals(token, "root"))
++	{
++		int screen = Scr.screen;
++
++		free(token);
++		token = PeekToken(action, &naction);
++		if (!token || GetIntegerArguments(token, NULL, &screen, 1) != 1)
++		{
++			screen = Scr.screen;
++		}
++		else
++		{
++			action = naction;
++		}
++		use_screenroot = True;
++		if (screen < 0 || screen >= Scr.NumberOfScreens)
++		{
++			screen = 0;
++		}
++		win = XRootWindow(dpy, screen);
++		if (win == None)
++		{
++			if (cond_rc != NULL)
++			{
++				cond_rc->rc = COND_RC_ERROR;
++			}
++			return;
++		}
++	}
++	else if (token)
++	{
++		/* SunOS doesn't have strtoul */
++		win = (unsigned long)strtol(token, NULL, 0);
++		free(token);
++	}
++	else
++	{
++		win = 0;
++	}
++
++	/* Look for condition - CreateFlagString returns NULL if no '(' or '['
++	 */
++	if (!use_screenroot)
++	{
++		flags = CreateFlagString(action, &restofline);
++		if (flags)
++		{
++			/* Create window mask */
++			use_condition = True;
++			DefaultConditionMask(&mask);
++
++			/* override for Current [] */
++			mask.my_flags.use_circulate_hit = 1;
++			mask.my_flags.use_circulate_hit_icon = 1;
++			mask.my_flags.use_circulate_hit_icon = 1;
++
++			CreateConditionMask(flags, &mask);
++			free(flags);
++
++			/* Relocate action */
++			action = restofline;
++		}
++	}
++
++	/* Search windows */
++	for (t = Scr.FvwmRoot.next; t; t = t->next)
++	{
++		if (FW_W(t) == win)
++		{
++			/* do it if no conditions or the conditions match */
++			if (action && (!use_condition ||
++				       MatchesConditionMask(t, &mask)))
++			{
++				if (cond_rc != NULL)
++				{
++					cond_rc->rc = COND_RC_OK;
++				}
++				execute_function_override_window(
++					cond_rc, exc, action, 0, t);
++			}
++			else if (cond_rc != NULL)
++			{
++				cond_rc->rc = COND_RC_NO_MATCH;
++			}
++			break;
++		}
++	}
++	if (!t)
++	{
++		/* The window is not managed by fvwm. Still some functions may
++		 * work on it. */
++		if (use_condition)
++		{
++			if (cond_rc != NULL)
++			{
++				cond_rc->rc = COND_RC_ERROR;
++			}
++		}
++		else if (XGetGeometry(
++				 dpy, win, &JunkRoot, &JunkX, &JunkY,
++				 (unsigned int*)&JunkWidth,
++				 (unsigned int*)&JunkHeight,
++				 (unsigned int*)&JunkBW,
++				 (unsigned int*)&JunkDepth) != 0)
++		{
++			if (cond_rc != NULL)
++			{
++				cond_rc->rc = COND_RC_OK;
++			}
++			if (action != NULL)
++			{
++				const exec_context_t *exc2;
++				exec_context_changes_t ecc;
++
++				ecc.w.fw = NULL;
++				ecc.w.w = win;
++				ecc.w.wcontext = C_UNMANAGED;
++				exc2 = exc_clone_context(
++					exc, &ecc,
++					ECC_FW | ECC_W | ECC_WCONTEXT);
++				execute_function(
++					cond_rc, exc2, action,
++					FUNC_IS_UNMANAGED);
++				exc_destroy_context(exc2);
++			}
++		}
++		else
++		{
++			/* window id does not exist */
++			if (cond_rc != NULL)
++			{
++				cond_rc->rc = COND_RC_ERROR;
++			}
++		}
++	}
++
++	/* Tidy up */
++	if (use_condition)
++	{
++		FreeConditionMask(&mask);
++	}
++
++	return;
++}
++
++void CMD_TestRc(F_CMD_ARGS)
++{
++	char *rest;
++
++	if (cond_rc == NULL)
++	{
++		/* useless if no return code to compare to is given */
++		return;
++	}
++	if (__rc_matches_rcstring_consume(&rest, cond_rc, action) &&
++	    rest != NULL)
++	{
++		/* execute the command in root window context; overwrite the
++		 * return code with the return code of the command */
++		execute_function(cond_rc, exc, rest, 0);
++	}
++
++	return;
++}
++
++void CMD_Break(F_CMD_ARGS)
++{
++	int rc;
++
++	if (cond_rc == NULL)
++	{
++		return;
++	}
++	rc = GetIntegerArguments(action, &action, &cond_rc->break_levels, 1);
++	if (rc != 1 || cond_rc->break_levels <= 0)
++	{
++		cond_rc->break_levels = -1;
++	}
++	cond_rc->rc = COND_RC_BREAK;
++
++	return;
++}
++
++void CMD_NoWindow(F_CMD_ARGS)
++{
++	execute_function_override_window(cond_rc, exc, action, 0, NULL);
++
++	return;
++}
++
++/* ver() - convert a version string to a floating-point number that
++ * can be used to compare different versions.
++ * ie. converts "2.5.11" to 2005011 */
++static int ver (char *str)
++{
++	char *n;
++	int v;
++
++	str = DoPeekToken(str, &n, NULL, ".", NULL);
++	if (!n)
++	{
++		return -1.0;
++	}
++	v = atoi(n) * 1000000;
++	str = DoPeekToken(str, &n, NULL, ".", NULL);
++	if (!n)
++	{
++		return -1.0;
++	}
++	v += atoi(n) * 1000;
++	str = DoPeekToken(str, &n, NULL, ".", NULL);
++	if (!n)
++	{
++		return -1.0;
++	}
++	v += atoi(n);
++
++	return v;
++}
++
++/* match_version() - compare $version against this version of FVWM
++ * using the operator specified by $operator. */
++static Bool match_version(char *version, char *operator)
++{
++	static int fvwm_version = -1;
++	const int v = ver(version);
++
++	if (fvwm_version < 0)
++	{
++		char *tmp = safestrdup(VERSION);
++		fvwm_version = ver(tmp);
++		free(tmp);
++	}
++	if (v < 0)
++	{
++		fprintf(
++			stderr, "match_version: Invalid version: %s\n",
++			version);
++		return False;
++	}
++	if (strcmp(operator, ">=") == 0)
++	{
++		return fvwm_version >= v;
++	}
++	else if (strcmp(operator, ">") == 0)
++	{
++		return fvwm_version > v;
++	}
++	else if (strcmp(operator, "<=") == 0)
++	{
++		return fvwm_version <= v;
++	}
++	else if (strcmp(operator, "<") == 0)
++	{
++		return fvwm_version < v;
++	}
++	else if (strcmp(operator, "==") == 0)
++	{
++		return (v == fvwm_version);
++	}
++	else if (strcmp(operator, "!=") == 0)
++	{
++		return (v != fvwm_version);
++	}
++	else
++	{
++		fprintf(
++			stderr, "match_version: Invalid operator: %s\n",
++			operator);
++	}
++
++	return False;
++}
++
++void CMD_Test(F_CMD_ARGS)
++{
++	char *restofline;
++	char *flags;
++	char *condition;
++	char *flags_ptr;
++	int match;
++	int error;
++
++	flags = CreateFlagString(action, &restofline);
++
++	/* Next parse the flags in the string. */
++	flags_ptr = flags;
++	flags_ptr = GetNextSimpleOption(flags_ptr, &condition);
++
++	match = 1;
++	error = 0;
++	while (condition)
++	{
++		char *cond;
++		int reverse;
++
++		cond = condition;
++		reverse = 0;
++		if (*cond == '!')
++		{
++			reverse = 1;
++			cond++;
++		}
++		if (StrEquals(cond, "True"))
++		{
++			match = 1;
++		}
++		else if (StrEquals(cond, "False"))
++		{
++			match = 0;
++		}
++		else if (StrEquals(cond, "Version"))
++		{
++			char *pattern;
++			flags_ptr = GetNextSimpleOption(flags_ptr, &pattern);
++			if (pattern)
++			{
++				char *ver;
++				flags_ptr = GetNextSimpleOption(
++					flags_ptr, &ver);
++				if (ver == NULL)
++				{
++					match = matchWildcards(
++						pattern, VERSION);
++				}
++				else
++				{
++					match = match_version(ver, pattern);
++					free(ver);
++				}
++				free(pattern);
++			}
++			else
++			{
++				error = 1;
++			}
++		}
++		else if (StrEquals(cond, "Start"))
++		{
++			match = exc->type == EXCT_INIT ||
++				exc->type == EXCT_RESTART;
++		}
++		else if (StrEquals(cond, "Init"))
++		{
++			match = exc->type == EXCT_INIT;
++		}
++		else if (StrEquals(cond, "Restart"))
++		{
++			match = exc->type == EXCT_RESTART;
++		}
++		else if (StrEquals(cond, "Exit"))
++		{
++			match = exc->type == EXCT_QUIT ||
++				exc->type == EXCT_TORESTART;
++		}
++		else if (StrEquals(cond, "Quit"))
++		{
++			match = exc->type == EXCT_QUIT;
++		}
++		else if (StrEquals(cond, "ToRestart"))
++		{
++			match = exc->type == EXCT_TORESTART;
++		}
++		else if (StrEquals(cond, "x") || StrEquals(cond, "r") ||
++			 StrEquals(cond, "w") || StrEquals(cond, "f") ||
++			 StrEquals(cond, "i"))
++		{
++			char *pattern;
++			int type = X_OK;
++			Bool im = 0;
++
++			switch(cond[0])
++			{
++			case 'X':
++			case 'x':
++				type = X_OK;
++				break;
++			case 'R':
++			case 'r':
++				type = R_OK;
++				break;
++			case 'W':
++			case 'w':
++				type = W_OK;
++				break;
++			case 'f':
++			case 'F':
++				type = F_OK;
++				break;
++			case 'i':
++			case 'I':
++				im = True;
++				type = R_OK;
++				break;
++			default:
++				/* cannot happen */
++				break;
++			}
++			flags_ptr = GetNextSimpleOption(flags_ptr, &pattern);
++			if (pattern)
++			{
++				match = cond_check_access(pattern, type, im);
++				free(pattern);
++			}
++			else
++			{
++				error = 1;
++			}
++		}
++		else if (StrEquals(cond, "EnvIsSet"))
++		{
++			char *var_name;
++			flags_ptr = GetNextSimpleOption(flags_ptr, &var_name);
++			if (var_name)
++			{
++				const char *value = getenv(var_name);
++				match = value != NULL;
++			}
++			else
++			{
++				error = 1;
++			}
++		}
++		else if (StrEquals(cond, "EnvMatch"))
++		{
++			char *var_name;
++			flags_ptr = GetNextSimpleOption(flags_ptr, &var_name);
++			if (var_name)
++			{
++				const char *value = getenv(var_name);
++				char *pattern;
++				/* unfortunately, GetNextSimpleOption is
++				 * broken, does not accept quoted empty "" */
++				flags_ptr = GetNextSimpleOption(
++					flags_ptr, &pattern);
++				if (!value)
++				{
++					value = "";
++				}
++				if (pattern)
++				{
++					match =
++						/* include empty string case */
++						(!pattern[0] && !value[0])
++						||
++						matchWildcards(pattern, value);
++				}
++				else
++				{
++					error = 1;
++				}
++			}
++			else
++			{
++				error = 1;
++			}
++		}
++		else if (StrEquals(cond, "EdgeIsActive"))
++		{
++			direction_t dir= DIR_NONE;
++			char *dirname;
++			char *next;
++			next = GetNextSimpleOption(flags_ptr, &dirname);
++			if (dirname)
++			{
++				dir = gravity_parse_dir_argument(
++					dirname, NULL, DIR_NONE);
++				if (dir == DIR_NONE)
++				{
++					if (!StrEquals(dirname, "Any"))
++					{
++						next = flags_ptr;
++					}
++				}
++				else if (dir > DIR_MAJOR_MASK)
++				{
++					error = 1;
++				}
++				free(dirname);
++			}
++
++			if (!error)
++			{
++				if (((dir == DIR_W || dir == DIR_NONE) &&
++					Scr.PanFrameLeft.isMapped) ||
++				    ((dir == DIR_N || dir == DIR_NONE) &&
++					Scr.PanFrameTop.isMapped) ||
++				    ((dir == DIR_S || dir == DIR_NONE) &&
++					Scr.PanFrameBottom.isMapped) ||
++				    ((dir == DIR_E || dir == DIR_NONE) &&
++ 				    	Scr.PanFrameRight.isMapped))
++				{
++				  	match = 1;
++				}
++				else
++				{
++				  	match = 0;
++				}
++			}
++			flags_ptr = next;
++		}
++		else if (StrEquals(cond, "EdgeHasPointer"))
++		{
++			int x,y;
++			Window win;
++			direction_t dir = DIR_NONE;
++			char *dirname;
++			char *next;
++			next = GetNextSimpleOption(flags_ptr, &dirname);
++			if (dirname)
++			{
++				dir = gravity_parse_dir_argument(
++					dirname, NULL, DIR_NONE);
++				if (dir == DIR_NONE)
++				{
++					if (!StrEquals(dirname, "Any"))
++					{
++						next = flags_ptr;
++					}
++				}
++				else if (dir > DIR_MAJOR_MASK)
++				{
++					error = 1;
++				}
++				free(dirname);
++			}
++
++			if (!error)
++			{
++				if (FQueryPointer(
++					dpy, Scr.Root, &JunkRoot, &win,
++					&JunkX, &JunkY,	&x, &y, &JunkMask)
++ 					== False)
++				{
++					/* pointer is on a different screen */
++					match = 0;
++				}
++				else if (is_pan_frame(win))
++				{
++					if (dir == DIR_NONE ||
++					    (dir == DIR_N &&
++					     win == Scr.PanFrameTop.win) ||
++					    (dir == DIR_S &&
++					     win == Scr.PanFrameBottom.win) ||
++					    (dir == DIR_E &&
++					     win == Scr.PanFrameRight.win) ||
++					    (dir == DIR_W &&
++					     win == Scr.PanFrameLeft.win))
++					{
++						match = 1;
++					}
++					else
++					{
++						match = 0;
++					}
++				}
++				else
++				{
++					match = 0;
++				}
++			}
++			flags_ptr = next;
++		}
++		else
++		{
++			/* unrecognized condition */
++			error = 1;
++			fprintf(stderr, "Unrecognised condition \"%s\" in Test command.\n", cond);
++		}
++
++		if (reverse)
++		{
++			match = !match;
++		}
++		free(condition);
++		if (error || !match)
++		{
++			break;
++		}
++		flags_ptr = GetNextSimpleOption(flags_ptr, &condition);
++	}
++
++	if (flags != NULL)
++	{
++		free(flags);
++	}
++	if (!error && match)
++	{
++		execute_function(cond_rc, exc, restofline, 0);
++	}
++	if (cond_rc != NULL)
++	{
++		if (error)
++		{
++			cond_rc->rc = COND_RC_ERROR;
++		}
++		else if (match)
++		{
++			cond_rc->rc = COND_RC_OK;
++		}
++		else
++		{
++			cond_rc->rc = COND_RC_NO_MATCH;
++		}
++	}
++
++	return;
++}
diff --git a/windowmanagers/fvwm/patches/04-FlatSeparators.patch b/windowmanagers/fvwm/patches/04-FlatSeparators.patch
new file mode 100644
index 0000000..2d86aea
--- /dev/null
+++ b/windowmanagers/fvwm/patches/04-FlatSeparators.patch
@@ -0,0 +1,10801 @@
+diff -U10 -Naupr fvwm-2.5.21-03/fvwm/menuitem.c fvwm-2.5.21-04/fvwm/menuitem.c
+--- fvwm-2.5.21-03/fvwm/menuitem.c	2007-03-03 13:17:58.000000000 +0100
++++ fvwm-2.5.21-04/fvwm/menuitem.c	2007-03-03 13:18:29.000000000 +0100
+@@ -74,24 +74,32 @@ static void clear_menu_item_background(
+ 		XClearArea(dpy, mpip->w, x, y, w, h, False);
+ 	}
+ }
+ 
+ /*
+  *
+  *  Draws two horizontal lines to form a separator
+  *
+  */
+ static void draw_separator(
+-	Window w, GC TopGC, GC BottomGC, int x1, int y, int x2)
++	Window w, GC TopGC, GC BottomGC, GC ForeGC, int x1, int y, int x2,
++	Bool do_flat_separators)
+ {
+-	XDrawLine(dpy, w, TopGC   , x1,   y,   x2,   y);
+-	XDrawLine(dpy, w, BottomGC, x1-1, y+1, x2+1, y+1);
++   if (do_flat_separators)
++   {
++       XDrawLine(dpy, w, ForeGC, x1, y, x2, y);
++   }
++   else
++   {
++       XDrawLine(dpy, w, TopGC   , x1,   y,   x2,   y);
++       XDrawLine(dpy, w, BottomGC, x1-1, y+1, x2+1, y+1);
++   }
+ 
+ 	return;
+ }
+ 
+ /*
+  *
+  *  Draws a tear off bar.  Similar to a separator, but with a dashed line.
+  *
+  */
+ static void draw_tear_off_bar(
+@@ -374,20 +382,21 @@ void menuitem_paint(
+ 	int lit_x_start;
+ 	int lit_x_end;
+ 	gc_quad_t gcs;
+ 	gc_quad_t off_gcs;
+ 	int cs = -1;
+ 	int off_cs;
+ 	FvwmRenderAttributes fra;
+ 	/*Pixel fg, fgsh;*/
+ 	int relief_thickness = ST_RELIEF_THICKNESS(ms);
+ 	Bool is_item_selected;
++	Bool do_flat_separators;
+ 	Bool item_cleared = False;
+ 	Bool xft_clear = False;
+ 	Bool empty_inter = False;
+ 	XRectangle b;
+ 	Region region = None;
+ 	int i;
+ 	int sx1;
+ 	int sx2;
+ 	FlocaleFont* font;
+ 
+@@ -590,43 +599,45 @@ void menuitem_paint(
+ 				MI_HEIGHT(mi) - 1 + relief_thickness, rgc, sgc,
+ 				relief_thickness);
+ 		}
+ 	}
+ 
+ 
+ 	/*
+ 	 * Draw the item itself.
+ 	 */
+ 
++	do_flat_separators = ST_DO_FLAT_SEPARATOR(ms);
++	
+ 	/* Calculate the separator offsets. */
+ 	if (ST_HAS_LONG_SEPARATORS(ms))
+ 	{
+ 		sx1 = MDIM_ITEM_X_OFFSET(*dim) + relief_thickness;
+ 		sx2 = MDIM_ITEM_X_OFFSET(*dim) + MDIM_ITEM_WIDTH(*dim) - 1 -
+ 			relief_thickness;
+ 	}
+ 	else
+ 	{
+ 		sx1 = MDIM_ITEM_X_OFFSET(*dim) + relief_thickness +
+ 			MENU_SEPARATOR_SHORT_X_OFFSET;
+ 		sx2 = MDIM_ITEM_X_OFFSET(*dim) + MDIM_ITEM_WIDTH(*dim) - 1 -
+ 			relief_thickness - MENU_SEPARATOR_SHORT_X_OFFSET;
+ 	}
+ 	if (MI_IS_SEPARATOR(mi))
+ 	{
+ 		if (sx1 < sx2)
+ 		{
+ 			/* It's a separator. */
+ 			draw_separator(
+-				mpip->w, gcs.shadow_gc, gcs.hilight_gc, sx1,
+-				y_offset + y_height - MENU_SEPARATOR_HEIGHT,
+-				sx2);
++				mpip->w, gcs.shadow_gc, gcs.hilight_gc, gcs.fore_gc,
++				sx1, y_offset + y_height - MENU_SEPARATOR_HEIGHT,
++				sx2, do_flat_separators);
+ 			/* Nothing else to do. */
+ 		}
+ 		return;
+ 	}
+ 	else if (MI_IS_TEAR_OFF_BAR(mi))
+ 	{
+ 		int tx1;
+ 		int tx2;
+ 
+ 		tx1 = MDIM_ITEM_X_OFFSET(*dim) + relief_thickness +
+@@ -652,36 +663,36 @@ void menuitem_paint(
+ 		if (ST_TITLE_UNDERLINES(ms) > 0 && !mpip->flags.is_first_item)
+ 		{
+ 			int add = (MI_IS_SELECTABLE(MI_PREV_ITEM(mi))) ?
+ 				relief_thickness : 0;
+ 
+ 			text_y += MENU_SEPARATOR_HEIGHT + add;
+ 			y = y_offset + add;
+ 			if (sx1 < sx2)
+ 			{
+ 				draw_separator(
+-					mpip->w, gcs.shadow_gc, gcs.hilight_gc,
+-					sx1, y, sx2);
++					mpip->w, gcs.shadow_gc, gcs.hilight_gc, gcs.fore_gc,
++					sx1, y, sx2, do_flat_separators);
+ 			}
+ 		}
+ 		/* Underline the title. */
+ 		switch (ST_TITLE_UNDERLINES(ms))
+ 		{
+ 		case 0:
+ 			break;
+ 		case 1:
+ 			if (MI_NEXT_ITEM(mi) != NULL)
+ 			{
+ 				y = y_offset + y_height - MENU_SEPARATOR_HEIGHT;
+ 				draw_separator(
+-					mpip->w, gcs.shadow_gc, gcs.hilight_gc,
+-					sx1, y, sx2);
++					mpip->w, gcs.shadow_gc, gcs.hilight_gc, gcs.fore_gc,
++					sx1, y, sx2, do_flat_separators);
+ 			}
+ 			break;
+ 		default:
+ 			for (i = ST_TITLE_UNDERLINES(ms); i-- > 0; )
+ 			{
+ 				y = y_offset + y_height - 1 -
+ 					i * MENU_UNDERLINE_HEIGHT;
+ 				XDrawLine(
+ 					dpy, mpip->w, gcs.shadow_gc, sx1, y,
+ 					sx2, y);
+diff -U10 -Naupr fvwm-2.5.21-03/fvwm/menuitem.c~ fvwm-2.5.21-04/fvwm/menuitem.c~
+--- fvwm-2.5.21-03/fvwm/menuitem.c~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-04/fvwm/menuitem.c~	2007-03-03 13:18:21.000000000 +0100
+@@ -0,0 +1,1035 @@
++/* -*-c-*- */
++/* This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* ---------------------------- included header files ---------------------- */
++
++#include "config.h"
++
++#include <stdio.h>
++
++#include "libs/fvwmlib.h"
++#include "libs/Picture.h"
++#include "libs/PictureGraphics.h"
++#include "libs/Rectangles.h"
++#include "fvwm.h"
++#include "externs.h"
++#include "execcontext.h"
++#include "misc.h"
++#include "screen.h"
++#include "menudim.h"
++#include "menustyle.h"
++#include "menuitem.h"
++#include "decorations.h"
++
++/* ---------------------------- local definitions -------------------------- */
++
++/* ---------------------------- local macros ------------------------------- */
++
++/* ---------------------------- imports ------------------------------------ */
++
++/* ---------------------------- included code files ------------------------ */
++
++/* ---------------------------- local types -------------------------------- */
++
++/* ---------------------------- forward declarations ----------------------- */
++
++/* ---------------------------- local variables ---------------------------- */
++
++/* ---------------------------- exported variables (globals) --------------- */
++
++/* ---------------------------- local functions ---------------------------- */
++static void clear_menu_item_background(
++	MenuPaintItemParameters *mpip, int x, int y, int w, int h)
++{
++	MenuStyle *ms = mpip->ms;
++
++	if (!ST_HAS_MENU_CSET(ms) &&
++	    ST_FACE(ms).type == GradientMenu &&
++	    (ST_FACE(ms).gradient_type == D_GRADIENT ||
++	     ST_FACE(ms).gradient_type == B_GRADIENT))
++	{
++		XEvent e;
++
++		e.xexpose.x = x;
++		e.xexpose.y = y;
++		e.xexpose.width = w;
++		e.xexpose.height = h;
++		mpip->cb_reset_bg(mpip->cb_mr, &e);
++	}
++	else
++	{
++		XClearArea(dpy, mpip->w, x, y, w, h, False);
++	}
++}
++
++/*
++ *
++ *  Draws two horizontal lines to form a separator
++ *
++ */
++static void draw_separator(
++	Window w, GC TopGC, GC BottomGC, int x1, int y, int x2)
++{
++	XDrawLine(dpy, w, TopGC   , x1,   y,   x2,   y);
++	XDrawLine(dpy, w, BottomGC, x1-1, y+1, x2+1, y+1);
++
++	return;
++}
++
++/*
++ *
++ *  Draws a tear off bar.  Similar to a separator, but with a dashed line.
++ *
++ */
++static void draw_tear_off_bar(
++	Window w, GC TopGC, GC BottomGC, int x1, int y, int x2)
++{
++	XGCValues xgcv;
++	int width;
++	int offset;
++
++	xgcv.line_style = LineOnOffDash;
++	xgcv.dashes = MENU_TEAR_OFF_BAR_DASH_WIDTH;
++	XChangeGC(dpy, TopGC, GCLineStyle | GCDashList, &xgcv);
++	XChangeGC(dpy, BottomGC, GCLineStyle | GCDashList, &xgcv);
++	width = (x2 - x1 + 1);
++	offset = (width / MENU_TEAR_OFF_BAR_DASH_WIDTH) *
++		MENU_TEAR_OFF_BAR_DASH_WIDTH;
++	offset = (width - offset) / 2;
++	x1 += offset;
++	x2 += offset;
++	XDrawLine(dpy, w, TopGC,    x1, y,     x2, y);
++	XDrawLine(dpy, w, BottomGC, x1, y + 1, x2, y + 1);
++	xgcv.line_style = LineSolid;
++	XChangeGC(dpy, TopGC, GCLineStyle, &xgcv);
++	XChangeGC(dpy, BottomGC, GCLineStyle, &xgcv);
++
++	return;
++}
++
++static void draw_higlight_background(
++	struct MenuPaintItemParameters *mpip, int x, int y, int width,
++	int height, colorset_t *cs, GC gc)
++{
++	if (cs != NULL && cs->pixmap && cs->pixmap_type != PIXMAP_TILED)
++	{
++		Pixmap p;
++
++		p = CreateOffsetBackgroundPixmap(
++			dpy, mpip->w, x, y, width, height, cs, Pdepth, gc,
++			False);
++		switch (cs->pixmap_type)
++		{
++		case PIXMAP_STRETCH_X:
++			/* todo: optimize to only create one pixmap and gc per
++			 * mr. */
++		case PIXMAP_STRETCH_Y:
++		{
++			XGCValues gcv;
++			int gcm;
++			GC bgc;
++
++			gcv.tile = p;
++			gcv.fill_style = FillTiled;
++			gcm = GCFillStyle | GCTile;
++
++			/* vertcal gradients has to be aligned properly */
++			if (cs->pixmap_type == PIXMAP_STRETCH_Y)
++			{
++				gcv.ts_y_origin = y;
++				gcm|=GCTileStipYOrigin;
++			}
++			else if (cs->pixmap_type == PIXMAP_STRETCH_X)
++			{
++				gcv.ts_x_origin = x;
++				gcm|=GCTileStipXOrigin;
++			}
++
++			bgc = fvwmlib_XCreateGC(dpy, mpip->w, gcm, &gcv);
++			XFillRectangle(dpy, mpip->w, bgc, x, y, width, height);
++			XFreeGC(dpy, bgc);
++			break;
++		}
++		default:
++			XCopyArea(dpy, p, mpip->w, gc, 0, 0, width, height,
++				  x, y);
++			break;
++		}
++		XFreePixmap(dpy, p);
++	}
++	else
++	{
++		XFillRectangle(dpy, mpip->w, gc, x, y, width, height);
++	}
++}
++
++/* ---------------------------- interface functions ------------------------ */
++
++/* Allocates a new, empty menu item */
++struct MenuItem *menuitem_create(void)
++{
++	MenuItem *mi;
++
++	mi = (MenuItem *)safemalloc(sizeof(MenuItem));
++	memset(mi, 0, sizeof(MenuItem));
++
++	return mi;
++}
++
++/* Frees a menu item and all of its allocated resources. */
++void menuitem_free(struct MenuItem *mi)
++{
++	int i;
++
++	if (!mi)
++	{
++		return;
++	}
++	for (i = 0; i < MAX_MENU_ITEM_LABELS; i++)
++	{
++		if (MI_LABEL(mi)[i] != NULL)
++		{
++			free(MI_LABEL(mi)[i]);
++		}
++	}
++	if (MI_ACTION(mi) != NULL)
++	{
++		free(MI_ACTION(mi));
++	}
++	if (MI_PICTURE(mi))
++	{
++		PDestroyFvwmPicture(dpy, MI_PICTURE(mi));
++	}
++	for (i = 0; i < MAX_MENU_ITEM_MINI_ICONS; i++)
++	{
++		if (MI_MINI_ICON(mi)[i])
++		{
++			PDestroyFvwmPicture(dpy, MI_MINI_ICON(mi)[i]);
++		}
++	}
++	free(mi);
++
++	return;
++}
++
++/* Duplicate a menu item into newly allocated memory.  The new item is
++ * completely independent of the old one. */
++struct MenuItem *menuitem_clone(struct MenuItem *mi)
++{
++	MenuItem *new_mi;
++	int i;
++
++	/* copy everything */
++	new_mi = (MenuItem *)safemalloc(sizeof(MenuItem));
++	memcpy(new_mi, mi, sizeof(MenuItem));
++	/* special treatment for a few parts */
++	MI_NEXT_ITEM(new_mi) = NULL;
++	MI_PREV_ITEM(new_mi) = NULL;
++	MI_WAS_DESELECTED(new_mi) = 0;
++	if (MI_ACTION(mi) != NULL)
++	{
++		MI_ACTION(new_mi) = safestrdup(MI_ACTION(mi));
++	}
++	for (i = 0; i < MAX_MENU_ITEM_LABELS; i++)
++	{
++		if (MI_LABEL(mi)[i] != NULL)
++		{
++			MI_LABEL(new_mi)[i] = strdup(MI_LABEL(mi)[i]);
++		}
++	}
++	if (MI_PICTURE(mi) != NULL)
++	{
++		MI_PICTURE(new_mi) = PCloneFvwmPicture(MI_PICTURE(mi));
++	}
++	for (i = 0; i < MAX_MENU_ITEM_MINI_ICONS; i++)
++	{
++		if (MI_MINI_ICON(mi)[i] != NULL)
++		{
++			MI_MINI_ICON(new_mi)[i] =
++				PCloneFvwmPicture(MI_MINI_ICON(mi)[i]);
++		}
++	}
++
++	return new_mi;
++}
++
++/* Calculate the size of the various parts of the item.  The sizes are returned
++ * through mipst. */
++void menuitem_get_size(
++	struct MenuItem *mi, struct MenuItemPartSizesT *mipst,
++	FlocaleFont *font, Bool do_reverse_icon_order)
++{
++	int i;
++	int j;
++	int w;
++
++	memset(mipst, 0, sizeof(MenuItemPartSizesT));
++	if (MI_IS_POPUP(mi))
++	{
++		mipst->triangle_width = MENU_TRIANGLE_WIDTH;
++	}
++	else if (MI_IS_TITLE(mi) && !MI_HAS_PICTURE(mi))
++	{
++		Bool is_formatted = False;
++
++		/* titles stretch over the whole menu width, so count the
++		 * maximum separately if the title is unformatted. */
++		for (j = 1; j < MAX_MENU_ITEM_LABELS; j++)
++		{
++			if (MI_LABEL(mi)[j] != NULL)
++			{
++				is_formatted = True;
++				break;
++			}
++			else
++			{
++				MI_LABEL_OFFSET(mi)[j] = 0;
++			}
++		}
++		if (!is_formatted && MI_LABEL(mi)[0] != NULL)
++		{
++			MI_LABEL_STRLEN(mi)[0] =
++				strlen(MI_LABEL(mi)[0]);
++			w = FlocaleTextWidth(
++				font, MI_LABEL(mi)[0], MI_LABEL_STRLEN(mi)[0]);
++			MI_LABEL_OFFSET(mi)[0] = w;
++			MI_IS_TITLE_CENTERED(mi) = True;
++			if (mipst->title_width < w)
++			{
++				mipst->title_width = w;
++			}
++			return;
++		}
++	}
++	/* regular item or formatted title */
++	for (i = 0; i < MAX_MENU_ITEM_LABELS; i++)
++	{
++		if (MI_LABEL(mi)[i])
++		{
++			MI_LABEL_STRLEN(mi)[i] = strlen(MI_LABEL(mi)[i]);
++			w = FlocaleTextWidth(
++				font, MI_LABEL(mi)[i], MI_LABEL_STRLEN(mi)[i]);
++			MI_LABEL_OFFSET(mi)[i] = w;
++			if (mipst->label_width[i] < w)
++			{
++				mipst->label_width[i] = w;
++			}
++		}
++	}
++	if (MI_PICTURE(mi) && mipst->picture_width < MI_PICTURE(mi)->width)
++	{
++		mipst->picture_width = MI_PICTURE(mi)->width;
++	}
++	for (i = 0; i < MAX_MENU_ITEM_MINI_ICONS; i++)
++	{
++		if (MI_MINI_ICON(mi)[i])
++		{
++			int k;
++
++			/* Reverse mini icon order for left submenu style. */
++			k = (do_reverse_icon_order == True) ?
++				MAX_MENU_ITEM_MINI_ICONS - 1 - i : i;
++			mipst->icon_width[k] = MI_MINI_ICON(mi)[i]->width;
++		}
++	}
++
++	return;
++}
++
++/*
++ *
++ *  Procedure:
++ *      menuitem_paint - draws a single entry in a popped up menu
++ *
++ *      mr - the menu instance that holds the menu item
++ *      mi - the menu item to redraw
++ *      fw - the FvwmWindow structure to check against allowed functions
++ *
++ */
++void menuitem_paint(
++	struct MenuItem *mi, struct MenuPaintItemParameters *mpip)
++{
++	struct MenuStyle *ms = mpip->ms;
++	struct MenuDimensions *dim = mpip->dim;
++
++	static FlocaleWinString *fws = NULL;
++	int y_offset;
++	int text_y;
++	int y_height;
++	int x;
++	int y;
++	int lit_x_start;
++	int lit_x_end;
++	gc_quad_t gcs;
++	gc_quad_t off_gcs;
++	int cs = -1;
++	int off_cs;
++	FvwmRenderAttributes fra;
++	/*Pixel fg, fgsh;*/
++	int relief_thickness = ST_RELIEF_THICKNESS(ms);
++	Bool is_item_selected;
++	Bool item_cleared = False;
++	Bool xft_clear = False;
++	Bool empty_inter = False;
++	XRectangle b;
++	Region region = None;
++	int i;
++	int sx1;
++	int sx2;
++	FlocaleFont* font;
++
++	if (!mi)
++	{
++		return;
++	}
++	is_item_selected = (mi == mpip->selected_item);
++
++	if (MI_IS_TITLE(mi))
++	{
++		font = ST_PTITLEFONT(ms);
++	}
++	else
++	{
++		font = ST_PSTDFONT(ms);
++	}
++
++	y_offset = MI_Y_OFFSET(mi);
++	y_height = MI_HEIGHT(mi);
++	if (MI_IS_SELECTABLE(mi))
++	{
++		text_y = y_offset + MDIM_ITEM_TEXT_Y_OFFSET(*dim);
++	}
++	else
++	{
++		text_y = y_offset + font->ascent +
++			ST_TITLE_GAP_ABOVE(ms);
++	}
++	/* center text vertically if the pixmap is taller */
++	if (MI_PICTURE(mi))
++	{
++		text_y += MI_PICTURE(mi)->height;
++	}
++	for (i = 0; i < mpip->used_mini_icons; i++)
++	{
++		y = 0;
++		if (MI_MINI_ICON(mi)[i])
++		{
++			if (MI_MINI_ICON(mi)[i]->height > y)
++			{
++				y = MI_MINI_ICON(mi)[i]->height;
++			}
++		}
++		y -= font->height;
++		if (y > 1)
++		{
++			text_y += y / 2;
++		}
++	}
++
++	off_cs = ST_HAS_MENU_CSET(ms) ? ST_CSET_MENU(ms) : -1;
++	/* Note: it's ok to pass a NULL label to is_function_allowed. */
++	if (!IS_EWMH_DESKTOP_FW(mpip->fw) &&
++	    !is_function_allowed(
++		    MI_FUNC_TYPE(mi), MI_LABEL(mi)[0], mpip->fw, True, False))
++	{
++		gcs = ST_MENU_STIPPLE_GCS(ms);
++		off_gcs = gcs;
++		off_cs = ST_HAS_GREYED_CSET(ms) ? ST_CSET_GREYED(ms) : -1;
++	}
++	else if (is_item_selected)
++	{
++		gcs = ST_MENU_ACTIVE_GCS(ms);
++		off_gcs = ST_MENU_INACTIVE_GCS(ms);
++	}
++	else if (MI_IS_TITLE(mi))
++	{
++		gcs = ST_MENU_TITLE_GCS(ms);
++		off_gcs = ST_MENU_INACTIVE_GCS(ms);
++	}
++	else
++	{
++		gcs = ST_MENU_INACTIVE_GCS(ms);
++		off_gcs = ST_MENU_INACTIVE_GCS(ms);
++	}
++	if (is_item_selected)
++	{
++		cs = (ST_HAS_ACTIVE_CSET(ms)) ? ST_CSET_ACTIVE(ms) : -1;
++	}
++	else if (MI_IS_TITLE(mi))
++	{
++		cs = (ST_HAS_TITLE_CSET(ms)) ? ST_CSET_TITLE(ms) : off_cs;
++	}
++	else
++	{
++		cs = off_cs;
++	}
++
++	/*
++	 * Hilight the item.
++	 */
++	if (FftSupport && ST_PSTDFONT(ms)->fftf.fftfont != NULL)
++	{
++		xft_clear = True;
++	}
++
++	/* Hilight or clear the background. */
++	lit_x_start = -1;
++	lit_x_end = -1;
++	if (is_item_selected &&
++	    (ST_DO_HILIGHT_BACK(ms) || ST_DO_HILIGHT_FORE(ms)))
++	{
++		/* Hilight the background. */
++		if (MDIM_HILIGHT_WIDTH(*dim) - 2 * relief_thickness > 0)
++		{
++			lit_x_start = MDIM_HILIGHT_X_OFFSET(*dim) +
++				relief_thickness;
++			lit_x_end = lit_x_start + MDIM_HILIGHT_WIDTH(*dim) -
++				2 * relief_thickness;
++			if (ST_DO_HILIGHT_BACK(ms))
++			{
++				draw_higlight_background(
++					mpip, lit_x_start,
++					y_offset + relief_thickness,
++					lit_x_end - lit_x_start,
++					y_height - relief_thickness,
++					(cs >= 0 ? &Colorset[cs] : NULL),
++					gcs.back_gc);
++				item_cleared = True;
++			}
++		}
++	}
++	else if ((MI_WAS_DESELECTED(mi) &&
++		  (relief_thickness > 0 ||
++		   ST_DO_HILIGHT_BACK(ms) || ST_DO_HILIGHT_FORE(ms)) &&
++		  (ST_FACE(ms).type != GradientMenu || ST_HAS_MENU_CSET(ms))))
++	{
++		int x1;
++		int x2;
++		/* we clear if xft_clear and !ST_HAS_MENU_CSET(ms) as the
++		 * non colorset code is too complicate ... olicha */
++		int d = 0;
++
++		if (MI_PREV_ITEM(mi) &&
++		    mpip->selected_item == MI_PREV_ITEM(mi))
++		{
++			/* Don't paint over the hilight relief. */
++			d = relief_thickness;
++		}
++		/* Undo the hilighting. */
++		x1 = min(
++			MDIM_HILIGHT_X_OFFSET(*dim), MDIM_ITEM_X_OFFSET(*dim));
++		x2 = max(
++			MDIM_HILIGHT_X_OFFSET(*dim) + MDIM_HILIGHT_WIDTH(*dim),
++			MDIM_ITEM_X_OFFSET(*dim) + MDIM_ITEM_WIDTH(*dim));
++		clear_menu_item_background(
++			mpip, x1, y_offset + d, x2 - x1,
++			y_height + relief_thickness - d);
++		item_cleared = True;
++	}
++	else if (MI_IS_TITLE(mi))
++	{
++		lit_x_start = MDIM_ITEM_X_OFFSET(*dim);
++		lit_x_end = lit_x_start + MDIM_ITEM_WIDTH(*dim);
++		/* Hilight the background. */
++		if (
++			MDIM_HILIGHT_WIDTH(*dim) > 0 &&
++			ST_DO_HILIGHT_TITLE_BACK(ms))
++		{
++			draw_higlight_background(
++				mpip, lit_x_start,
++				y_offset + relief_thickness,
++				lit_x_end - lit_x_start,
++				y_height - relief_thickness,
++				(cs >= 0 ? &Colorset[cs] : NULL),
++				gcs.back_gc);
++			item_cleared = True;
++		}
++	}
++
++	MI_WAS_DESELECTED(mi) = False;
++	memset(&fra, 0, sizeof(fra));
++	fra.mask = 0;
++
++	/* Hilight 3D */
++	if (is_item_selected && relief_thickness > 0)
++	{
++		GC rgc;
++		GC sgc;
++
++		rgc = gcs.hilight_gc;
++		sgc = gcs.shadow_gc;
++		if (ST_IS_ITEM_RELIEF_REVERSED(ms))
++		{
++			GC tgc = rgc;
++
++			/* swap gcs for reversed relief */
++			rgc = sgc;
++			sgc = tgc;
++		}
++		if (MDIM_HILIGHT_WIDTH(*dim) - 2 * relief_thickness > 0)
++		{
++			/* The relief reaches down into the next item, hence
++			 * the value for the second y coordinate:
++			 * MI_HEIGHT(mi) + 1 */
++			RelieveRectangle(
++				dpy, mpip->w,  MDIM_HILIGHT_X_OFFSET(*dim),
++				y_offset, MDIM_HILIGHT_WIDTH(*dim) - 1,
++				MI_HEIGHT(mi) - 1 + relief_thickness, rgc, sgc,
++				relief_thickness);
++		}
++	}
++
++
++	/*
++	 * Draw the item itself.
++	 */
++
++	/* Calculate the separator offsets. */
++	if (ST_HAS_LONG_SEPARATORS(ms))
++	{
++		sx1 = MDIM_ITEM_X_OFFSET(*dim) + relief_thickness;
++		sx2 = MDIM_ITEM_X_OFFSET(*dim) + MDIM_ITEM_WIDTH(*dim) - 1 -
++			relief_thickness;
++	}
++	else
++	{
++		sx1 = MDIM_ITEM_X_OFFSET(*dim) + relief_thickness +
++			MENU_SEPARATOR_SHORT_X_OFFSET;
++		sx2 = MDIM_ITEM_X_OFFSET(*dim) + MDIM_ITEM_WIDTH(*dim) - 1 -
++			relief_thickness - MENU_SEPARATOR_SHORT_X_OFFSET;
++	}
++	if (MI_IS_SEPARATOR(mi))
++	{
++		if (sx1 < sx2)
++		{
++			/* It's a separator. */
++			draw_separator(
++				mpip->w, gcs.shadow_gc, gcs.hilight_gc, sx1,
++				y_offset + y_height - MENU_SEPARATOR_HEIGHT,
++				sx2);
++			/* Nothing else to do. */
++		}
++		return;
++	}
++	else if (MI_IS_TEAR_OFF_BAR(mi))
++	{
++		int tx1;
++		int tx2;
++
++		tx1 = MDIM_ITEM_X_OFFSET(*dim) + relief_thickness +
++			MENU_TEAR_OFF_BAR_X_OFFSET;
++		tx2 = MDIM_ITEM_X_OFFSET(*dim) + MDIM_ITEM_WIDTH(*dim) - 1 -
++			relief_thickness -
++			MENU_TEAR_OFF_BAR_X_OFFSET;
++		if (tx1 < tx2)
++		{
++
++			/* It's a tear off bar. */
++			draw_tear_off_bar(
++				mpip->w, gcs.shadow_gc, gcs.hilight_gc, tx1,
++				y_offset + relief_thickness +
++				MENU_TEAR_OFF_BAR_Y_OFFSET, tx2);
++		}
++		/* Nothing else to do. */
++		return;
++	}
++	else if (MI_IS_TITLE(mi))
++	{
++		/* Separate the title. */
++		if (ST_TITLE_UNDERLINES(ms) > 0 && !mpip->flags.is_first_item)
++		{
++			int add = (MI_IS_SELECTABLE(MI_PREV_ITEM(mi))) ?
++				relief_thickness : 0;
++
++			text_y += MENU_SEPARATOR_HEIGHT + add;
++			y = y_offset + add;
++			if (sx1 < sx2)
++			{
++				draw_separator(
++					mpip->w, gcs.shadow_gc, gcs.hilight_gc,
++					sx1, y, sx2);
++			}
++		}
++		/* Underline the title. */
++		switch (ST_TITLE_UNDERLINES(ms))
++		{
++		case 0:
++			break;
++		case 1:
++			if (MI_NEXT_ITEM(mi) != NULL)
++			{
++				y = y_offset + y_height - MENU_SEPARATOR_HEIGHT;
++				draw_separator(
++					mpip->w, gcs.shadow_gc, gcs.hilight_gc,
++					sx1, y, sx2);
++			}
++			break;
++		default:
++			for (i = ST_TITLE_UNDERLINES(ms); i-- > 0; )
++			{
++				y = y_offset + y_height - 1 -
++					i * MENU_UNDERLINE_HEIGHT;
++				XDrawLine(
++					dpy, mpip->w, gcs.shadow_gc, sx1, y,
++					sx2, y);
++			}
++			break;
++		}
++	}
++
++	/*
++	 * Draw the labels.
++	 */
++	if (fws == NULL)
++	{
++		FlocaleAllocateWinString(&fws);
++	}
++	fws->win = mpip->w;
++	fws->y = text_y;
++	fws->flags.has_colorset = 0;
++	b.y = text_y - font->ascent;
++	b.height = font->height + 1; /* ? */
++	if (!item_cleared && mpip->ev)
++	{
++		int u,v;
++		if (!frect_get_seg_intersection(
++			    mpip->ev->xexpose.y, mpip->ev->xexpose.height,
++			    b.y, b.height, &u, &v))
++		{
++			/* empty intersection */
++			empty_inter = True;
++		}
++		b.y = u;
++		b.height = v;
++	}
++
++	for (i = MAX_MENU_ITEM_LABELS; i-- > 0; )
++	{
++		if (!empty_inter && MI_LABEL(mi)[i] && *(MI_LABEL(mi)[i]))
++		{
++			Bool draw_string = True;
++			int text_width;
++			int tmp_cs;
++
++			if (MI_LABEL_OFFSET(mi)[i] >= lit_x_start &&
++			    MI_LABEL_OFFSET(mi)[i] < lit_x_end)
++			{
++				/* label is in hilighted area */
++				fws->gc = gcs.fore_gc;
++				tmp_cs = cs;
++			}
++			else
++			{
++				/* label is in unhilighted area */
++				fws->gc = off_gcs.fore_gc;
++				tmp_cs = off_cs;
++			}
++			if (tmp_cs >= 0)
++			{
++				fws->colorset = &Colorset[tmp_cs];
++				fws->flags.has_colorset = 1;
++			}
++			fws->str = MI_LABEL(mi)[i];
++			b.x = fws->x = MI_LABEL_OFFSET(mi)[i];
++			b.width = text_width = FlocaleTextWidth(
++				font, fws->str, strlen(fws->str));
++
++			if (!item_cleared && mpip->ev)
++			{
++				int s_x,s_w;
++				if (frect_get_seg_intersection(
++					    mpip->ev->xexpose.x,
++					    mpip->ev->xexpose.width,
++					    fws->x, text_width,
++					    &s_x, &s_w))
++				{
++					b.x = s_x;
++					b.width = s_w;
++					region = XCreateRegion();
++					XUnionRectWithRegion(
++						&b, region, region);
++					fws->flags.has_clip_region = True;
++					fws->clip_region = region;
++					draw_string = True;
++					XSetRegion(dpy, fws->gc, region);
++				}
++				else
++				{
++					/* empty intersection */
++					draw_string = False;
++				}
++			}
++			if (draw_string)
++			{
++				if (!item_cleared && xft_clear)
++				{
++					clear_menu_item_background(
++						mpip, b.x, b.y, b.width,
++						b.height);
++				}
++				FlocaleDrawString(dpy, font, fws, 0);
++
++				/* hot key */
++				if (MI_HAS_HOTKEY(mi) && !MI_IS_TITLE(mi) &&
++				    (!MI_IS_HOTKEY_AUTOMATIC(mi) ||
++				     ST_USE_AUTOMATIC_HOTKEYS(ms)) &&
++				    MI_HOTKEY_COLUMN(mi) == i)
++				{
++					FlocaleDrawUnderline(
++						dpy, ST_PSTDFONT(ms), fws,
++						MI_HOTKEY_COFFSET(mi));
++				}
++			}
++		}
++		if (region)
++		{
++			XDestroyRegion(region);
++			region = None;
++			fws->flags.has_clip_region = False;
++			fws->clip_region = None;
++			XSetClipMask(dpy, fws->gc, None);
++		}
++	}
++
++	/*
++	 * Draw the submenu triangle.
++	 */
++
++	if (MI_IS_POPUP(mi))
++	{
++		GC tmp_gc;
++
++		if (MDIM_TRIANGLE_X_OFFSET(*dim) >= lit_x_start &&
++		    MDIM_TRIANGLE_X_OFFSET(*dim) < lit_x_end &&
++		    is_item_selected)
++		{
++			/* triangle is in hilighted area */
++			if (ST_TRIANGLES_USE_FORE(ms))
++			{
++				tmp_gc = gcs.fore_gc;
++			}
++			else
++			{
++				tmp_gc = gcs.hilight_gc;
++			}
++		}
++		else
++		{
++			/* triangle is in unhilighted area */
++			if (ST_TRIANGLES_USE_FORE(ms))
++			{
++				tmp_gc = off_gcs.fore_gc;
++			}
++			else
++			{
++				tmp_gc = off_gcs.hilight_gc;
++			}
++		}
++		y = y_offset + (y_height - MENU_TRIANGLE_HEIGHT +
++				relief_thickness) / 2;
++
++		if (ST_TRIANGLES_USE_FORE(ms))
++		{
++			DrawTrianglePattern(
++				dpy, mpip->w, tmp_gc, tmp_gc, tmp_gc,
++				MDIM_TRIANGLE_X_OFFSET(*dim), y,
++				MENU_TRIANGLE_WIDTH, MENU_TRIANGLE_HEIGHT, 0,
++				(mpip->flags.is_left_triangle) ? 'l' : 'r',
++				ST_HAS_TRIANGLE_RELIEF(ms),
++				!ST_HAS_TRIANGLE_RELIEF(ms), is_item_selected);
++
++		}
++		else
++		{
++			DrawTrianglePattern(
++				dpy, mpip->w, gcs.hilight_gc, gcs.shadow_gc,
++				tmp_gc,	MDIM_TRIANGLE_X_OFFSET(*dim), y,
++				MENU_TRIANGLE_WIDTH, MENU_TRIANGLE_HEIGHT, 0,
++				(mpip->flags.is_left_triangle) ? 'l' : 'r',
++				ST_HAS_TRIANGLE_RELIEF(ms),
++				!ST_HAS_TRIANGLE_RELIEF(ms), is_item_selected);
++		}
++	}
++
++	/*
++	 * Draw the item picture.
++	 */
++
++	if (MI_PICTURE(mi))
++	{
++		GC tmp_gc;
++		int tmp_cs;
++		Bool draw_picture = True;
++
++		x = menudim_middle_x_offset(mpip->dim) -
++			MI_PICTURE(mi)->width / 2;
++		y = y_offset + ((MI_IS_SELECTABLE(mi)) ? relief_thickness : 0);
++		if (x >= lit_x_start && x < lit_x_end)
++		{
++			tmp_gc = gcs.fore_gc;
++			tmp_cs = cs;
++		}
++		else
++		{
++			tmp_gc = off_gcs.fore_gc;
++			tmp_cs = off_cs;
++		}
++		fra.mask = FRAM_DEST_IS_A_WINDOW;
++		if (tmp_cs >= 0)
++		{
++			fra.mask |= FRAM_HAVE_ICON_CSET;
++			fra.colorset = &Colorset[tmp_cs];
++		}
++		b.x = x;
++		b.y = y;
++		b.width = MI_PICTURE(mi)->width;
++		b.height = MI_PICTURE(mi)->height;
++		if (!item_cleared && mpip->ev)
++		{
++			if (!frect_get_intersection(
++				    mpip->ev->xexpose.x, mpip->ev->xexpose.y,
++				    mpip->ev->xexpose.width,
++				    mpip->ev->xexpose.height,
++				    b.x, b.y, b.width, b.height, &b))
++			{
++				draw_picture = False;
++			}
++		}
++		if (draw_picture)
++		{
++			if (
++				!item_cleared &&
++				(MI_PICTURE(mi)->alpha != None ||
++				 (tmp_cs >=0 &&
++				  Colorset[tmp_cs].icon_alpha_percent < 100)))
++			{
++				clear_menu_item_background(
++					mpip, b.x, b.y, b.width, b.height);
++			}
++			PGraphicsRenderPicture(
++				dpy, mpip->w, MI_PICTURE(mi), &fra,
++				mpip->w, tmp_gc, Scr.MonoGC, Scr.AlphaGC,
++				b.x - x, b.y - y, b.width, b.height,
++				b.x, b.y, b.width, b.height, False);
++		}
++	}
++
++	/*
++	 * Draw the mini icons.
++	 */
++
++	for (i = 0; i < mpip->used_mini_icons; i++)
++	{
++		int k;
++		Bool draw_picture = True;
++
++		/* We need to reverse the mini icon order for left submenu
++		 * style. */
++		k = (ST_USE_LEFT_SUBMENUS(ms)) ?
++			mpip->used_mini_icons - 1 - i : i;
++
++		if (MI_MINI_ICON(mi)[i])
++		{
++			GC tmp_gc;
++			int tmp_cs;
++
++			if (MI_PICTURE(mi))
++			{
++				y = y_offset + MI_HEIGHT(mi) -
++					MI_MINI_ICON(mi)[i]->height;
++			}
++			else
++			{
++				y = y_offset +
++					(MI_HEIGHT(mi) +
++					 ((MI_IS_SELECTABLE(mi)) ?
++					  relief_thickness : 0) -
++					 MI_MINI_ICON(mi)[i]->height) / 2;
++			}
++			if (MDIM_ICON_X_OFFSET(*dim)[k] >= lit_x_start &&
++			    MDIM_ICON_X_OFFSET(*dim)[k] < lit_x_end)
++			{
++				/* icon is in hilighted area */
++				tmp_gc = gcs.fore_gc;
++				tmp_cs = cs;
++			}
++			else
++			{
++				/* icon is in unhilighted area */
++				tmp_gc = off_gcs.fore_gc;
++				tmp_cs = off_cs;
++			}
++			fra.mask = FRAM_DEST_IS_A_WINDOW;
++			if (tmp_cs >= 0)
++			{
++				fra.mask |= FRAM_HAVE_ICON_CSET;
++				fra.colorset = &Colorset[tmp_cs];
++			}
++			b.x = MDIM_ICON_X_OFFSET(*dim)[k];
++			b.y = y;
++			b.width = MI_MINI_ICON(mi)[i]->width;
++			b.height = MI_MINI_ICON(mi)[i]->height;
++			if (!item_cleared && mpip->ev)
++			{
++				if (!frect_get_intersection(
++					    mpip->ev->xexpose.x,
++					    mpip->ev->xexpose.y,
++					    mpip->ev->xexpose.width,
++					    mpip->ev->xexpose.height,
++					    b.x, b.y, b.width, b.height, &b))
++				{
++					draw_picture = False;
++				}
++			}
++			if (draw_picture)
++			{
++				if (!item_cleared &&
++				    (MI_MINI_ICON(mi)[i]->alpha != None
++				     || (tmp_cs >=0 &&
++					 Colorset[tmp_cs].icon_alpha_percent <
++					 100)))
++				{
++					clear_menu_item_background(
++						mpip,
++						b.x, b.y, b.width, b.height);
++				}
++				PGraphicsRenderPicture(
++					dpy, mpip->w, MI_MINI_ICON(mi)[i],
++					&fra, mpip->w, tmp_gc, Scr.MonoGC,
++					Scr.AlphaGC,
++					b.x - MDIM_ICON_X_OFFSET(*dim)[k],
++					b.y - y, b.width, b.height,
++					b.x, b.y, b.width, b.height, False);
++			}
++		}
++	}
++
++	return;
++}
++
++/* returns the center y coordinate of the menu item */
++int menuitem_middle_y_offset(struct MenuItem *mi, struct MenuStyle *ms)
++{
++	int r;
++
++	if (!mi)
++	{
++		return ST_BORDER_WIDTH(ms);
++	}
++	r = (MI_IS_SELECTABLE(mi)) ? ST_RELIEF_THICKNESS(ms) : 0;
++
++	return MI_Y_OFFSET(mi) + (MI_HEIGHT(mi) + r) / 2;
++}
+diff -U10 -Naupr fvwm-2.5.21-03/fvwm/menus.c fvwm-2.5.21-04/fvwm/menus.c
+--- fvwm-2.5.21-03/fvwm/menus.c	2007-03-03 13:17:58.000000000 +0100
++++ fvwm-2.5.21-04/fvwm/menus.c	2007-03-03 13:18:29.000000000 +0100
+@@ -1456,20 +1456,24 @@ static Bool size_menu_vertically(MenuSiz
+ 	{
+ 		Bool last_item_has_relief =
+ 			(MI_PREV_ITEM(mi)) ?
+ 			MI_IS_SELECTABLE(MI_PREV_ITEM(mi)) : False;
+ 		Bool has_mini_icon = False;
+ 		int separator_height;
+ 
+ 		separator_height = (last_item_has_relief) ?
+ 			MENU_SEPARATOR_HEIGHT + relief_thickness :
+ 			MENU_SEPARATOR_TOTAL_HEIGHT;
++		if (MST_DO_FLAT_SEPARATOR(msp->menu))
++		{
++			separator_height += 1;
++		}
+ 		MI_Y_OFFSET(mi) = y;
+ 		if (MI_IS_TITLE(mi))
+ 		{
+ 			MI_HEIGHT(mi) = MST_PTITLEFONT(msp->menu)->height +
+ 				MST_TITLE_GAP_ABOVE(msp->menu) +
+ 				MST_TITLE_GAP_BELOW(msp->menu);
+ 		}
+ 		else if (MI_IS_SEPARATOR(mi))
+ 		{
+ 			/* Separator */
+diff -U10 -Naupr fvwm-2.5.21-03/fvwm/menus.c~ fvwm-2.5.21-04/fvwm/menus.c~
+--- fvwm-2.5.21-03/fvwm/menus.c~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-04/fvwm/menus.c~	2007-03-03 13:18:21.000000000 +0100
+@@ -0,0 +1,7495 @@
++/* -*-c-*- */
++/* This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*
++ * Copyright 1993, Robert Nation
++ *     You may use this code for any purpose, as long as the original
++ *     copyright remains in the source code and all documentation
++ */
++
++/* IMPORTANT NOTE: Do *not* use any constant numbers in this file. All values
++ * have to be #defined in the section below or in defaults.h to ensure full
++ * control over the menus. */
++
++/* ---------------------------- included header files ---------------------- */
++
++#include "config.h"
++
++#include <stdio.h>
++#include <assert.h>
++#include <X11/keysym.h>
++
++#include "libs/ftime.h"
++#include "libs/fvwmlib.h"
++#include "libs/FScreen.h"
++#include "libs/Picture.h"
++#include "libs/PictureUtils.h"
++#include "libs/PictureGraphics.h"
++#include "libs/charmap.h"
++#include "libs/wcontext.h"
++#include "fvwm.h"
++#include "externs.h"
++#include "execcontext.h"
++#include "events.h"
++#include "eventhandler.h"
++#include "eventmask.h"
++#include "cursor.h"
++#include "functions.h"
++#include "commands.h"
++#include "misc.h"
++#include "screen.h"
++#include "colormaps.h"
++#include "geometry.h"
++#include "move_resize.h"
++#include "menudim.h"
++#include "menuitem.h"
++#include "menuroot.h"
++#include "menustyle.h"
++#include "bindings.h"
++#include "menubindings.h"
++#include "menugeometry.h"
++#include "menuparameters.h"
++#include "menus.h"
++
++/* ---------------------------- local definitions -------------------------- */
++
++/* used in float to int arithmetic */
++#define ROUNDING_ERROR_TOLERANCE  0.005
++
++/* ---------------------------- local macros ------------------------------- */
++
++/* ---------------------------- imports ------------------------------------ */
++
++/* This external is safe. It's written only during startup. */
++extern XContext MenuContext;
++
++/* ---------------------------- included code files ------------------------ */
++
++/* ---------------------------- local types -------------------------------- */
++
++/* patch to pass the last popups position hints to popup_func */
++typedef struct
++{
++	struct
++	{
++		unsigned is_last_menu_pos_hints_valid : 1;
++		unsigned do_ignore_pos_hints : 1;
++		unsigned do_warp_title : 1;
++	} flags;
++	struct MenuPosHints pos_hints;
++} saved_pos_hints;
++
++typedef struct MenuInfo
++{
++	MenuRoot *all;
++	int n_destroyed_menus;
++} MenuInfo;
++
++typedef struct MenuSizingParameters
++{
++	MenuRoot *menu;
++	/* number of item labels present in the item format */
++	int used_item_labels;
++	/* same for mini icons */
++	int used_mini_icons;
++	struct
++	{
++		int sidepic_width;
++		MenuItemPartSizesT i;
++	} max;
++	struct
++	{
++		unsigned is_popup_indicator_used : 1;
++	} flags;
++} MenuSizingParameters;
++
++/* ---------------------------- menu loop types ---------------------------- */
++
++typedef enum
++{
++	MENU_MLOOP_RET_NORMAL,
++	MENU_MLOOP_RET_LOOP,
++	MENU_MLOOP_RET_END
++} mloop_ret_code_t;
++
++typedef struct
++{
++	unsigned do_popup_immediately : 1;
++	/* used for delay popups, to just popup the menu */
++	unsigned do_popup_now : 1;
++	unsigned do_popdown_now : 1;
++	/* used for keystrokes, to popup and move to that menu */
++	unsigned do_popup_and_warp : 1;
++	unsigned do_force_reposition : 1;
++	unsigned do_force_popup : 1;
++	unsigned do_popdown : 1;
++	unsigned do_popup : 1;
++	unsigned do_menu : 1;
++	unsigned do_recycle_event : 1;
++	unsigned do_propagate_event_into_submenu : 1;
++	unsigned has_mouse_moved : 1;
++	unsigned is_off_menu_allowed : 1;
++	unsigned is_key_press : 1;
++	unsigned is_item_entered_by_key_press : 1;
++	unsigned is_motion_faked : 1;
++	unsigned is_popped_up_by_timeout : 1;
++	unsigned is_pointer_in_active_item_area : 1;
++	unsigned is_motion_first : 1;
++	unsigned is_release_first : 1;
++	unsigned is_submenu_mapped : 1;
++	unsigned was_item_unposted : 1;
++	unsigned is_button_release : 1;
++} mloop_flags_t;
++
++typedef struct
++{
++	MenuItem *mi;
++	MenuRoot *mrMi;
++	int x_offset;
++	int popdown_delay_10ms;
++	int popup_delay_10ms;
++} mloop_evh_data_t;
++
++typedef struct
++{
++	MenuRoot *mrPopup;
++	MenuRoot *mrPopdown;
++	mloop_flags_t mif;
++	/* used to reduce network traffic with delayed popup/popdown */
++	MenuItem *mi_with_popup;
++	MenuItem *mi_wants_popup;
++	MenuItem *miRemovedSubmenu;
++} mloop_evh_input_t;
++
++/* values that are set once when the menu loop is entered */
++typedef struct mloop_static_info_t
++{
++	int x_init;
++	int y_init;
++	Time t0;
++	unsigned int event_mask;
++} mloop_static_info_t;
++
++/* ---------------------------- forward declarations ----------------------- */
++
++/* ---------------------------- local variables ---------------------------- */
++
++/* This global is saved and restored every time a function is called that
++ * might modify them, so we can safely let it live outside a function. */
++static saved_pos_hints last_saved_pos_hints =
++{
++	{ False, False },
++	{ 0, 0, 0.0, 0.0, 0, 0, False, False, False, False }
++};
++
++/* structures for menus */
++static MenuInfo Menus;
++
++/* ---------------------------- exported variables (globals) --------------- */
++
++/* ---------------------------- local functions ---------------------------- */
++
++static void __menu_execute_function(const exec_context_t **pexc, char *action)
++{
++	const exec_context_t *exc;
++	exec_context_changes_t ecc;
++	int old_emf;
++
++	ecc.w.w = ((*pexc)->w.fw) ? FW_W((*pexc)->w.fw) : None;
++	exc = exc_clone_context(*pexc, &ecc, ECC_W);
++	old_emf = Scr.flags.is_executing_menu_function;
++	Scr.flags.is_executing_menu_function = 1;
++	execute_function(NULL, exc, action, FUNC_DONT_EXPAND_COMMAND);
++	Scr.flags.is_executing_menu_function = old_emf;
++	exc_destroy_context(exc);
++	/* See if the window has been deleted */
++	if (!check_if_fvwm_window_exists((*pexc)->w.fw))
++	{
++		ecc.w.fw = NULL;
++		ecc.w.w = None;
++		ecc.w.wcontext = 0;
++		exc = exc_clone_context(
++			*pexc, &ecc, ECC_FW | ECC_W | ECC_WCONTEXT);
++		exc_destroy_context(*pexc);
++		*pexc = exc;
++	}
++
++	return;
++}
++
++static Bool pointer_in_active_item_area(int x_offset, MenuRoot *mr)
++{
++	float ratio = (float)MST_ACTIVE_AREA_PERCENT(mr) / 100.0;
++
++	if (MST_ACTIVE_AREA_PERCENT(mr) >= 100)
++	{
++		return False;
++	}
++	if (MST_USE_LEFT_SUBMENUS(mr))
++	{
++		return (x_offset <=
++			MR_ITEM_X_OFFSET(mr) + MR_ITEM_WIDTH(mr) -
++			MR_ITEM_WIDTH(mr) * ratio);
++	}
++	else
++	{
++		return (x_offset >=
++			MR_ITEM_X_OFFSET(mr) + MR_ITEM_WIDTH(mr) * ratio);
++	}
++}
++
++static Bool pointer_in_passive_item_area(int x_offset, MenuRoot *mr)
++{
++	float ratio = (float)MST_ACTIVE_AREA_PERCENT(mr) / 100.0;
++
++	if (MST_ACTIVE_AREA_PERCENT(mr) >= 100)
++	{
++		return False;
++	}
++	if (MST_USE_LEFT_SUBMENUS(mr))
++	{
++		return (x_offset >=
++			MR_ITEM_X_OFFSET(mr) + MR_ITEM_WIDTH(mr) * ratio);
++	}
++	else
++	{
++		return (x_offset <=
++			MR_ITEM_X_OFFSET(mr) + MR_ITEM_WIDTH(mr) -
++			MR_ITEM_WIDTH(mr) * ratio);
++	}
++}
++
++/*
++ * warping functions
++ */
++
++static void warp_pointer_to_title(MenuRoot *mr)
++{
++	FWarpPointer(
++		dpy, 0, MR_WINDOW(mr), 0, 0, 0, 0,
++		menudim_middle_x_offset(&MR_DIM(mr)),
++		menuitem_middle_y_offset(MR_FIRST_ITEM(mr), MR_STYLE(mr)));
++}
++
++static MenuItem *warp_pointer_to_item(
++	MenuRoot *mr, MenuItem *mi, Bool do_skip_title)
++{
++	if (do_skip_title)
++	{
++		while (MI_NEXT_ITEM(mi) != NULL &&
++		       (!MI_IS_SELECTABLE(mi) || MI_IS_TEAR_OFF_BAR(mi)))
++		{
++			/* skip separators, titles and tear off bars until the
++			 * first 'real' item is found */
++			mi = MI_NEXT_ITEM(mi);
++		}
++	}
++	if (mi == NULL)
++	{
++		mi = MR_LAST_ITEM(mr);
++	}
++	if (mi == NULL)
++	{
++		return mi;
++	}
++	FWarpPointer(
++		dpy, 0, MR_WINDOW(mr), 0, 0, 0, 0,
++		menudim_middle_x_offset(&MR_DIM(mr)),
++		menuitem_middle_y_offset(mi, MR_STYLE(mr)));
++
++	return mi;
++}
++
++/*
++ * menu animation functions
++ */
++
++/* prepares the parameters to be passed to AnimatedMoveOfWindow
++ * mr - the menu instance that holds the menu item
++ * fw - the FvwmWindow structure to check against allowed functions */
++static void get_menu_repaint_transparent_parameters(
++	MenuRepaintTransparentParameters *pmrtp, MenuRoot *mr, FvwmWindow *fw)
++{
++	pmrtp->mr = mr;
++	pmrtp->fw = fw;
++
++	return;
++}
++
++
++/* Undo the animation of a menu */
++static void animated_move_back(
++	MenuRoot *mr, Bool do_warp_pointer, FvwmWindow *fw)
++{
++	MenuRepaintTransparentParameters mrtp;
++	int act_x;
++	int act_y;
++
++	if (MR_XANIMATION(mr) == 0)
++	{
++		return;
++	}
++	if (menu_get_geometry(
++		    mr, &JunkRoot, &act_x, &act_y, &JunkWidth, &JunkHeight,
++		    &JunkBW, &JunkDepth))
++	{
++		Bool transparent_bg = False;
++
++		/* move it back */
++		if (ST_HAS_MENU_CSET(MR_STYLE(mr)) &&
++		    CSET_IS_TRANSPARENT(ST_CSET_MENU(MR_STYLE(mr))))
++		{
++			transparent_bg = True;
++			get_menu_repaint_transparent_parameters(
++				&mrtp, mr, fw);
++		}
++		AnimatedMoveOfWindow(
++			MR_WINDOW(mr), act_x, act_y, act_x - MR_XANIMATION(mr),
++			act_y, do_warp_pointer, -1, NULL,
++			(transparent_bg)? &mrtp:NULL);
++		MR_XANIMATION(mr) = 0;
++	}
++
++	return;
++}
++
++/* move a menu or a tear-off menu preserving transparency.
++ * tear-off menus are moved with their frame coordinates. */
++static void move_any_menu(
++	MenuRoot *mr, MenuParameters *pmp, int endX, int endY)
++{
++	if (MR_IS_TEAR_OFF_MENU(mr))
++	{
++		float fFull = 1.0;
++		AnimatedMoveFvwmWindow(
++			pmp->tear_off_root_menu_window,
++			FW_W_FRAME(pmp->tear_off_root_menu_window),
++			-1, -1, endX, endY, False, 0, &fFull);
++	}
++	else
++	{
++		XMoveWindow(dpy, MR_WINDOW(mr), endX, endY);
++		if (ST_HAS_MENU_CSET(MR_STYLE(mr)) &&
++		    CSET_IS_TRANSPARENT(ST_CSET_MENU(MR_STYLE(mr))))
++	        {
++			MenuRepaintTransparentParameters mrtp;
++
++			get_menu_repaint_transparent_parameters(
++				&mrtp, mr, (*pmp->pexc)->w.fw);
++			repaint_transparent_menu(
++				&mrtp,False, endX,endY, endX, endY);
++      	      	}
++	}
++}
++
++/* ---------------------------- submenu function --------------------------- */
++
++/* Search for a submenu that was popped up by the given item in the given
++ * instance of the menu. */
++static MenuRoot *seek_submenu_instance(
++	MenuRoot *parent_menu, MenuItem *parent_item)
++{
++	MenuRoot *mr;
++
++	for (mr = Menus.all; mr != NULL; mr = MR_NEXT_MENU(mr))
++	{
++		if (MR_PARENT_MENU(mr) == parent_menu &&
++		    MR_PARENT_ITEM(mr) == parent_item)
++		{
++			/* here it is */
++			break;
++		}
++	}
++
++	return mr;
++}
++
++static Bool is_submenu_mapped(MenuRoot *parent_menu, MenuItem *parent_item)
++{
++	XWindowAttributes win_attribs;
++	MenuRoot *mr;
++
++	mr = seek_submenu_instance(parent_menu, parent_item);
++	if (mr == NULL)
++	{
++		return False;
++	}
++
++	if (MR_WINDOW(mr) == None)
++	{
++		return False;
++	}
++	if (!XGetWindowAttributes(dpy, MR_WINDOW(mr), &win_attribs))
++	{
++		return False;
++	}
++
++	return (win_attribs.map_state == IsViewable);
++}
++
++/* Returns the menu root that a given menu item pops up */
++static MenuRoot *mr_popup_for_mi(MenuRoot *mr, MenuItem *mi)
++{
++	char *menu_name;
++	MenuRoot *menu = NULL;
++
++	/* This checks if mi is != NULL too */
++	if (!mi || !MI_IS_POPUP(mi))
++	{
++		return NULL;
++	}
++
++	/* first look for a menu that is aleady mapped */
++	menu = seek_submenu_instance(mr, mi);
++	if (menu)
++	{
++		return menu;
++	}
++
++	/* just look past "Popup " in the action, and find that menu root */
++	menu_name = PeekToken(SkipNTokens(MI_ACTION(mi), 1), NULL);
++	menu = menus_find_menu(menu_name);
++
++	return menu;
++}
++
++/* ---------------------------- item handling ------------------------------ */
++
++/*
++ * find_entry()
++ *
++ * Returns the menu item the pointer is over and optionally the offset
++ * from the left side of the menu entry (if px_offset is != NULL) and
++ * the MenuRoot the pointer is over (if pmr is != NULL).
++ */
++static MenuItem *find_entry(
++	MenuParameters *pmp,
++	int *px_offset /*NULL means don't return this value */,
++	MenuRoot **pmr /*NULL means don't return this value */,
++	/* values passed in from caller it FQueryPointer was already called
++	 * there */
++	Window p_child, int p_rx, int p_ry)
++{
++	MenuItem *mi;
++	MenuRoot *mr;
++	int root_x, root_y;
++	int x, y;
++	Window Child;
++	int r;
++
++	/* x_offset returns the x offset of the pointer in the found menu item
++	 */
++	if (px_offset)
++	{
++		*px_offset = 0;
++	}
++	if (pmr)
++	{
++		*pmr = NULL;
++	}
++	/* get the pointer position */
++	if (p_rx < 0)
++	{
++		if (!FQueryPointer(
++			    dpy, Scr.Root, &JunkRoot, &Child,
++			    &root_x, &root_y, &JunkX, &JunkY, &JunkMask))
++		{
++			/* pointer is on a different screen */
++			return NULL;
++		}
++	}
++	else
++	{
++		root_x = p_rx;
++		root_y = p_ry;
++		Child = p_child;
++	}
++	/* find out the menu the pointer is in */
++	if (pmp->tear_off_root_menu_window != NULL &&
++	    Child == FW_W_FRAME(pmp->tear_off_root_menu_window))
++	{
++		/* we're in the top level torn off menu */
++		Child = FW_W(pmp->tear_off_root_menu_window);
++	}
++	if (XFindContext(dpy, Child, MenuContext, (caddr_t *)&mr) == XCNOENT)
++	{
++		return NULL;
++	}
++	/* get position in that child window */
++	if (!XTranslateCoordinates(
++		    dpy, Scr.Root, MR_WINDOW(mr), root_x, root_y, &x, &y,
++		    &JunkChild))
++	{
++		return NULL;
++	}
++	if (x < 0 || y < 0 || x >= MR_WIDTH(mr) || y >= MR_HEIGHT(mr))
++	{
++		return NULL;
++	}
++	if (pmr)
++	{
++		*pmr = mr;
++	}
++	r = MST_RELIEF_THICKNESS(mr);
++	/* look for the entry that the mouse is in */
++	for (mi = MR_FIRST_ITEM(mr); mi; mi = MI_NEXT_ITEM(mi))
++	{
++		int a;
++		int b;
++
++		a = (MI_PREV_ITEM(mi) &&
++		     MI_IS_SELECTABLE(MI_PREV_ITEM(mi))) ? r / 2 : 0;
++		if (!MI_IS_SELECTABLE(mi))
++		{
++			b = 0;
++		}
++		else if (MI_NEXT_ITEM(mi) &&
++			 MI_IS_SELECTABLE(MI_NEXT_ITEM(mi)))
++		{
++			b = r / 2;
++		}
++		else
++		{
++			b = r;
++		}
++		if (y >= MI_Y_OFFSET(mi) - a &&
++		    y < MI_Y_OFFSET(mi) + MI_HEIGHT(mi) + b)
++		{
++			break;
++		}
++	}
++	if (x < MR_ITEM_X_OFFSET(mr) ||
++	    x >= MR_ITEM_X_OFFSET(mr) + MR_ITEM_WIDTH(mr) - 1)
++	{
++		mi = NULL;
++	}
++	if (mi && px_offset)
++	{
++		*px_offset = x;
++	}
++
++	return mi;
++}
++
++/* ---------------------------- keyboard shortcuts ------------------------- */
++
++static Bool is_double_click(
++	Time t0, MenuItem *mi, MenuParameters *pmp, MenuReturn *pmret,
++	double_keypress *pdkp, Bool has_mouse_moved)
++{
++	if ((*pmp->pexc)->x.elast->type == KeyPress)
++	{
++		return False;
++	}
++	if (fev_get_evtime() - t0 >= MST_DOUBLE_CLICK_TIME(pmp->menu))
++	{
++		return False;
++	}
++	if (has_mouse_moved)
++	{
++		return False;
++	}
++	if (!pmp->flags.has_default_action &&
++	    (mi && mi == MR_FIRST_ITEM(pmp->menu) && MI_IS_SELECTABLE(mi)))
++	{
++		return False;
++	}
++	if (pmp->flags.is_submenu)
++	{
++		return False;
++	}
++	if (pmp->flags.is_invoked_by_key_press && pdkp->timestamp == 0)
++	{
++		return False;
++	}
++
++	return True;
++}
++
++/* ---------------------------- item label parsing ------------------------- */
++
++/*
++ * Procedure:
++ *      scanForHotkeys - Look for hotkey markers in a MenuItem
++ *                                                      (pete at tecc.co.uk)
++ *
++ * Inputs:
++ *      it      - MenuItem to scan
++ *      column  - The column number in which to look for a hotkey.
++ *
++ */
++static void scanForHotkeys(
++	MenuItem *it, int column)
++{
++	char *start;
++	char *s;
++	char *t;
++
++	/* Get start of string */
++	start = MI_LABEL(it)[column];
++	/* Scan whole string */
++	for (s = start; *s != '\0'; s++)
++	{
++		if (*s != '&')
++		{
++			continue;
++		}
++		if (s[1] != '&')
++		{
++			/* found a hotkey - only one hotkey per item */
++			break;
++		}
++		/* Just an escaped '&'; copy the string down over it    */
++		for (t = s; *t != '\0'; t++)
++		{
++			t[0] = t[1];
++		}
++
++	}
++	if (*s != 0)
++	{
++		/* It's a hot key marker - work out the offset value */
++		MI_HOTKEY_COFFSET(it) = s - start;
++		MI_HOTKEY_COLUMN(it) = column;
++		MI_HAS_HOTKEY(it) = (s[1] != '\0');
++		MI_IS_HOTKEY_AUTOMATIC(it) = 0;
++		for ( ; *s != '\0'; s++)
++		{
++			/* Copy down.. */
++			s[0] = s[1];
++		}
++	}
++
++	return;
++}
++
++
++/* Side picture support: this scans for a color int the menu name
++   for colorization */
++static void scanForColor(
++	char *instring, Pixel *p, Bool *flag, char identifier)
++{
++	char *tstart;
++	char *s;
++	char *save_instring;
++	char *name;
++	char *t;
++	int i;
++	int len;
++
++	*flag = False;
++
++	len = strlen(instring) + 1;
++	/* save instring in case can't find pixmap */
++	save_instring = (char *)alloca(len);
++	name = (char *)alloca(len);
++	strcpy(save_instring, instring);
++
++	/* Scan whole string          */
++	for (s = instring; *s != '\0'; s++)
++	{
++		if (*s != identifier)
++		{
++			continue;
++		}
++		/* Just an escaped '^'  */
++		if (s[1] != identifier)
++		{
++			/* found the identifier */
++			break;
++		}
++		/* Copy the string down over it */
++		for (t = s; *t != '\0'; t++)
++		{
++			t[0] = t[1];
++		}
++	}
++	if (*s != 0)
++	{
++		/* work out the offset value */
++		tstart = s;
++		for (i = 0, s++; *s != identifier && *s != 0; i++, s++)
++		{
++			name[i] = *s;
++		}
++		name[i] = 0;
++		*p = GetColor(name);
++		*flag = True;
++		if (*s != '\0')
++		{
++			s++;
++		}
++		while (*s != '\0')
++		{
++			*tstart++ = *s++;
++		}
++		*tstart = 0;
++	}
++
++	return;
++}
++
++static Bool scanForPixmap(
++	char *instring, FvwmPicture **p, char identifier)
++{
++	char *tstart;
++	char *s;
++	char *t;
++	char *name;
++	int i;
++	FvwmPicture *pp;
++	FvwmPictureAttributes fpa;
++
++	*p = NULL;
++	fpa.mask = 0;
++	if (!instring)
++	{
++		return False;
++	}
++	name = (char *)safemalloc(strlen(instring)+1);
++
++	/* Scan whole string    */
++	for (s = instring; *s != '\0'; s++)
++	{
++		if (*s != identifier)
++		{
++			continue;
++		}
++		/* A hotkey marker? */
++		/* Just an escaped &    */
++		if (s[1] != identifier)
++		{
++			break;
++		}
++
++		/* copy the string down over it */
++		for (t = s; *t != '\0'; t++)
++		{
++			t[0] = t[1];
++		}
++	}
++	if (*s != 0)
++	{
++		/* work out the offset value */
++		tstart = s;
++		for (i = 0, s++; *s != identifier && *s != 0; i++, s++)
++		{
++			name[i] = *s;
++		}
++		name[i] = 0;
++		/* Next, check for a color pixmap */
++		pp = PCacheFvwmPicture(
++			dpy, Scr.NoFocusWin, NULL, name, fpa);
++		if (*s != '\0')
++		{
++			s++;
++		}
++		while (*s != '\0')
++		{
++			*tstart++ = *s++;
++		}
++		*tstart = 0;
++		if (pp)
++		{
++			*p = pp;
++		}
++		else
++		{
++			fvwm_msg(WARN, "scanForPixmap",
++				 "Couldn't load image from %s", name);
++		}
++	}
++	free(name);
++
++	return (*p != NULL);
++}
++
++/* ---------------------------- item list handling ------------------------- */
++
++static void unlink_item_from_menu(
++	MenuRoot *mr, MenuItem *mi)
++{
++	MenuItem *next;
++	MenuItem *prev;
++
++	next = MI_NEXT_ITEM(mi);
++	prev = MI_PREV_ITEM(mi);
++	if (next != NULL)
++	{
++		MI_PREV_ITEM(next) = prev;
++	}
++	else
++	{
++		MR_LAST_ITEM(mr) = prev;
++	}
++	if (prev != NULL)
++	{
++		MI_NEXT_ITEM(prev) = next;
++	}
++	else
++	{
++		MR_FIRST_ITEM(mr) = next;
++	}
++	MI_NEXT_ITEM(mi) = NULL;
++	MI_PREV_ITEM(mi) = NULL;
++	MR_ITEMS(mr)--;
++
++	return;
++}
++
++/* Add the given menu item to the menu.  If the first item of the menu is a
++ * title, and the do_replace_title flag is True, the old title is deleted and
++ * replaced by the new item.  Otherwise the item is appended at the end of the
++ * menu. */
++static void append_item_to_menu(
++	MenuRoot *mr, MenuItem *mi, Bool do_replace_title)
++{
++	if (MR_FIRST_ITEM(mr) == NULL)
++	{
++		MR_FIRST_ITEM(mr) = mi;
++		MR_LAST_ITEM(mr) = mi;
++		MI_NEXT_ITEM(mi) = NULL;
++		MI_PREV_ITEM(mi) = NULL;
++	}
++	else if (do_replace_title)
++	{
++		if (MI_IS_TITLE(MR_FIRST_ITEM(mr)))
++		{
++			if (MR_FIRST_ITEM(mr) == MR_LAST_ITEM(mr))
++			{
++				MR_LAST_ITEM(mr) = mi;
++			}
++			if (MI_NEXT_ITEM(MR_FIRST_ITEM(mr)) != NULL)
++			{
++				MI_PREV_ITEM(MI_NEXT_ITEM(
++						     MR_FIRST_ITEM(mr))) = mi;
++			}
++			MI_NEXT_ITEM(mi) = MI_NEXT_ITEM(MR_FIRST_ITEM(mr));
++			menuitem_free(MR_FIRST_ITEM(mr));
++		}
++		else
++		{
++			MI_PREV_ITEM(MR_FIRST_ITEM(mr)) = mi;
++			MI_NEXT_ITEM(mi) = MR_FIRST_ITEM(mr);
++		}
++		MI_PREV_ITEM(mi) = NULL;
++		MR_FIRST_ITEM(mr) = mi;
++	}
++	else
++	{
++		MI_NEXT_ITEM(MR_LAST_ITEM(mr)) = mi;
++		MI_PREV_ITEM(mi) = MR_LAST_ITEM(mr);
++		MR_LAST_ITEM(mr) = mi;
++	}
++
++	return;
++}
++
++static void clone_menu_item_list(
++	MenuRoot *dest_mr, MenuRoot *src_mr)
++{
++	MenuItem *mi;
++	MenuItem *cloned_mi;
++	MenuRoot *mr;
++
++	MR_FIRST_ITEM(dest_mr) = NULL;
++	MR_LAST_ITEM(dest_mr) = NULL;
++	/* traverse the menu and all its continuations */
++	for (mr = src_mr; mr != NULL; mr = MR_CONTINUATION_MENU(mr))
++	{
++		/* duplicate all items in the current menu */
++		for (mi = MR_FIRST_ITEM(mr); mi != NULL; mi = MI_NEXT_ITEM(mi))
++		{
++			if (MI_IS_CONTINUATION(mi))
++			{
++				/* skip this item */
++				continue;
++			}
++			cloned_mi = menuitem_clone(mi);
++			append_item_to_menu(dest_mr, cloned_mi, False);
++		}
++	}
++
++	return;
++}
++
++/* ---------------------------- MenuRoot maintenance functions ------------- */
++
++/* Extract interesting values from the item format string that are needed by
++ * the size_menu_... functions. */
++static void calculate_item_sizes(MenuSizingParameters *msp)
++{
++	MenuItem *mi;
++	MenuItemPartSizesT mipst;
++	int i;
++	Bool do_reverse_icon_order =
++		(MST_USE_LEFT_SUBMENUS(msp->menu)) ? True : False;
++
++	memset(&(msp->max), 0, sizeof(msp->max));
++	/* Calculate the widths for all columns of all items. */
++	for (mi = MR_FIRST_ITEM(msp->menu); mi != NULL; mi = MI_NEXT_ITEM(mi))
++	{
++		if (MI_IS_TITLE(mi))
++		{
++			menuitem_get_size(
++				mi, &mipst, MST_PTITLEFONT(msp->menu),
++				do_reverse_icon_order);
++		}
++		else
++		{
++			menuitem_get_size(
++				mi, &mipst, MST_PSTDFONT(msp->menu),
++				do_reverse_icon_order);
++		}
++		/* adjust maximums */
++		if (msp->max.i.triangle_width < mipst.triangle_width)
++		{
++			msp->max.i.triangle_width = mipst.triangle_width;
++		}
++		if (msp->max.i.title_width < mipst.title_width)
++		{
++			msp->max.i.title_width = mipst.title_width;
++		}
++		for (i = 0; i < MAX_MENU_ITEM_LABELS; i++)
++		{
++			if (msp->max.i.label_width[i] < mipst.label_width[i])
++			{
++				msp->max.i.label_width[i] =
++					mipst.label_width[i];
++			}
++		}
++		if (msp->max.i.picture_width < mipst.picture_width)
++		{
++			msp->max.i.picture_width = mipst.picture_width;
++		}
++		for (i = 0; i < MAX_MENU_ITEM_MINI_ICONS; i++)
++		{
++			if (msp->max.i.icon_width[i] < mipst.icon_width[i])
++			{
++				msp->max.i.icon_width[i] = mipst.icon_width[i];
++			}
++		}
++	}
++	if (MR_SIDEPIC(msp->menu))
++	{
++		msp->max.sidepic_width = MR_SIDEPIC(msp->menu)->width;
++	}
++	else if (MST_SIDEPIC(msp->menu))
++	{
++		msp->max.sidepic_width = MST_SIDEPIC(msp->menu)->width;
++	}
++
++	return;
++}
++
++/*
++ *
++ * Calculate the positions of the columns in the menu.
++ * Called by make_menu().
++ *
++ */
++static void size_menu_horizontally(MenuSizingParameters *msp)
++{
++	MenuItem *mi;
++	Bool sidepic_is_left = True;
++	int total_width;
++	int sidepic_space = 0;
++	int label_offset[MAX_MENU_ITEM_LABELS];
++	char lcr_column[MAX_MENU_ITEM_LABELS];
++	int i;
++	int d;
++	int relief_thickness = MST_RELIEF_THICKNESS(msp->menu);
++	int *item_order[
++		MAX_MENU_ITEM_LABELS + MAX_MENU_ITEM_MINI_ICONS +
++		1 /* triangle */ + 2 /* relief markers */];
++	int used_objects = 0;
++	int left_objects = 0;
++	int right_objects = 0;
++	int x;
++	unsigned char icons_placed = 0;
++	Bool sidepic_placed = False;
++	Bool triangle_placed = False;
++	Bool relief_begin_placed = False;
++	Bool relief_end_placed = False;
++	char *format;
++	Bool first = True;
++	Bool done = False;
++	Bool is_last_object_left = True;
++	unsigned char columns_placed = 0;
++	int relief_gap = 0;
++	int gap_left;
++	int gap_right;
++	int chars;
++
++	memset(item_order, 0, sizeof(item_order));
++	for (i = 0; i < MAX_MENU_ITEM_LABELS; i++)
++	{
++		lcr_column[i] = 'l';
++	}
++
++	/* Now calculate the offsets for the columns. */
++	format = MST_ITEM_FORMAT(msp->menu);
++	if (!format)
++	{
++		format = (MST_USE_LEFT_SUBMENUS(msp->menu)) ?
++			DEFAULT_LEFT_MENU_ITEM_FORMAT :
++			DEFAULT_MENU_ITEM_FORMAT;
++	}
++	/* Place the individual items off the menu in case they are not
++	 * set in the format string. */
++	for (i = 0; i < MAX_MENU_ITEM_LABELS; i++)
++	{
++		label_offset[i] = 2 * Scr.MyDisplayWidth;
++	}
++
++	x = MST_BORDER_WIDTH(msp->menu);
++	while (*format && !done)
++	{
++		switch (*format)
++		{
++		case '%':
++			format++;
++			chars = 0;
++			gap_left = 0;
++			gap_right = 0;
++
++			/* Insert a gap of %d pixels. */
++			if (sscanf(format, "%d.%d%n", &gap_left,
++				   &gap_right, &chars) >= 2 ||
++			    (sscanf(format, "%d.%n", &gap_left,
++				    &chars) >= 1 && chars > 0) ||
++			    sscanf(format, "%d%n", &gap_left,
++				   &chars) >= 1 ||
++			    sscanf(format, ".%d%n", &gap_right,
++				   &chars) >= 1)
++			{
++				if (gap_left > MR_SCREEN_WIDTH(msp->menu) ||
++				    gap_left < -MR_SCREEN_WIDTH(msp->menu))
++				{
++					gap_left = 0;
++				}
++				if (gap_right > MR_SCREEN_HEIGHT(msp->menu) ||
++				    gap_right < -MR_SCREEN_HEIGHT(msp->menu))
++				{
++					gap_right = 0;
++				}
++				/* Skip the number. */
++				format += chars;
++			}
++			else if (*format == '.')
++			{
++				/* Skip a dot without values */
++				format++;
++			}
++			if (!*format)
++			{
++				break;
++			}
++			switch (*format)
++			{
++			case 'l':
++			case 'c':
++			case 'r':
++				/* A left, center or right aligned column. */
++				if (columns_placed >=
++				    MAX_MENU_ITEM_LABELS)
++				{
++					break;
++				}
++				if (
++					msp->max.i.label_width[columns_placed]
++					<= 0)
++				{
++					columns_placed++;
++					break;
++				}
++				lcr_column[columns_placed] = *format;
++				x += gap_left;
++				label_offset[columns_placed] = x;
++				x += msp->max.i.label_width[columns_placed] +
++					gap_right;
++				item_order[used_objects++] =
++					&(label_offset[columns_placed]);
++				if (is_last_object_left && (*format == 'l'))
++				{
++					left_objects++;
++				}
++				else
++				{
++					is_last_object_left = False;
++					if (*format == 'r')
++					{
++						right_objects++;
++					}
++					else
++					{
++						right_objects = 0;
++					}
++				}
++				columns_placed++;
++				break;
++			case 's':
++				/* the sidepic */
++				if (sidepic_placed)
++				{
++					break;
++				}
++				sidepic_placed = True;
++				if (msp->max.sidepic_width <= 0)
++				{
++					break;
++				}
++				x += gap_left;
++				MR_SIDEPIC_X_OFFSET(msp->menu) = x;
++				sidepic_is_left = first;
++				sidepic_space = msp->max.sidepic_width +
++					((sidepic_is_left) ?
++					 gap_left : gap_right);
++				x += msp->max.sidepic_width + gap_right;
++				break;
++			case 'i':
++				/* a mini icon */
++				if (icons_placed >=
++				    MAX_MENU_ITEM_MINI_ICONS)
++				{
++					break;
++				}
++				if (msp->max.i.icon_width[icons_placed] > 0)
++				{
++					x += gap_left;
++					MR_ICON_X_OFFSET(msp->menu)
++						[icons_placed] = x;
++					x += msp->max.i.icon_width
++						[icons_placed] + gap_right;
++					item_order[used_objects++] =
++						&(MR_ICON_X_OFFSET(msp->menu)
++						  [icons_placed]);
++					if (is_last_object_left)
++					{
++						left_objects++;
++					}
++					else
++					{
++						right_objects++;
++					}
++				}
++				icons_placed++;
++				break;
++			case '|':
++				if (!relief_begin_placed)
++				{
++					relief_begin_placed = True;
++					x += gap_left;
++					MR_HILIGHT_X_OFFSET(msp->menu) =
++						x;
++					x += relief_thickness +
++						gap_right;
++					relief_gap += gap_right;
++					item_order[used_objects++] =
++						&(MR_HILIGHT_X_OFFSET(
++							  msp->menu));
++					if (is_last_object_left)
++					{
++						left_objects++;
++					}
++					else
++					{
++						right_objects = 0;
++					}
++				}
++				else if (!relief_end_placed)
++				{
++					relief_end_placed = True;
++					x += relief_thickness + gap_left;
++					/* This is a hack: for now we record
++					 * the x coordinate of the end of the
++					 * hilight area, but later we'll place
++					 * the width in here. */
++					MR_HILIGHT_WIDTH(msp->menu) = x;
++					x += gap_right;
++					relief_gap += gap_left;
++					item_order[used_objects++] =
++						&(MR_HILIGHT_WIDTH(msp->menu));
++					right_objects++;
++				}
++				break;
++			case '>':
++			case '<':
++				/* the triangle for popup menus */
++				if (triangle_placed)
++				{
++					break;
++				}
++				triangle_placed = True;
++				if (msp->max.i.triangle_width > 0)
++				{
++					x += gap_left;
++					MR_TRIANGLE_X_OFFSET(
++						msp->menu) = x;
++					MR_IS_LEFT_TRIANGLE(msp->menu) =
++						(*format == '<');
++					x += msp->max.i.triangle_width +
++						gap_right;
++					item_order[used_objects++] =
++						&(MR_TRIANGLE_X_OFFSET(
++							  msp->menu));
++					if (is_last_object_left &&
++					    *format == '<')
++					{
++						left_objects++;
++					}
++					else
++					{
++						is_last_object_left = False;
++						right_objects++;
++					}
++				}
++				break;
++			case 'p':
++				/* Simply add a gap. */
++				x += gap_right + gap_left;
++				break;
++			case '\t':
++				x += MENU_TAB_WIDTH * FlocaleTextWidth(
++					MST_PSTDFONT(
++						msp->menu), " ", 1);
++				break;
++			case ' ':
++				/* Advance the x position. */
++				x += FlocaleTextWidth(
++					MST_PSTDFONT(msp->menu), format,
++					1);
++				break;
++			default:
++				/* Ignore unknown characters. */
++				break;
++			} /* switch (*format) */
++			break;
++		case '\t':
++			x += MENU_TAB_WIDTH * FlocaleTextWidth(
++				MST_PSTDFONT(msp->menu), " ", 1);
++			break;
++		case ' ':
++			/* Advance the x position. */
++			x += FlocaleTextWidth(
++				MST_PSTDFONT(msp->menu), format, 1);
++			break;
++		default:
++			/* Ignore unknown characters. */
++			break;
++		} /* switch (*format) */
++		format++;
++		first = False;
++	} /* while (*format) */
++	/* stored for vertical sizing */
++	msp->used_item_labels = columns_placed;
++	msp->used_mini_icons = icons_placed;
++
++	/* Hide unplaced parts of the menu. */
++	if (!sidepic_placed)
++	{
++		MR_SIDEPIC_X_OFFSET(msp->menu) =
++			2 * MR_SCREEN_WIDTH(msp->menu);
++	}
++	for (i = icons_placed; i < MAX_MENU_ITEM_MINI_ICONS; i++)
++	{
++		MR_ICON_X_OFFSET(msp->menu)[i] =
++			2 * MR_SCREEN_WIDTH(msp->menu);
++	}
++	if (!triangle_placed)
++	{
++		MR_TRIANGLE_X_OFFSET(msp->menu) =
++			2 * MR_SCREEN_WIDTH(msp->menu);
++	}
++	msp->flags.is_popup_indicator_used = triangle_placed;
++
++	total_width = x - MST_BORDER_WIDTH(msp->menu);
++	d = (sidepic_space + 2 * relief_thickness +
++	     max(msp->max.i.title_width, msp->max.i.picture_width)) -
++		total_width;
++	if (d > 0)
++	{
++		int m = 1 - left_objects;
++		int n = 1 + used_objects - left_objects - right_objects;
++
++		/* The title is larger than all menu items. Stretch the
++		 * gaps between the items up to the total width of the
++		 * title. */
++		for (i = 0; i < used_objects; i++)
++		{
++			if (i < left_objects)
++			{
++				continue;
++			}
++			if (i >= used_objects - right_objects)
++			{
++				/* Right aligned item. */
++				*(item_order[i]) += d;
++			}
++			else
++			{
++				/* Neither left nor right aligned item.
++				 * Divide the overhead gap evenly
++				 * between the items. */
++				*(item_order[i]) += d * (m + i) / n;
++			}
++		}
++		total_width += d;
++		if (!sidepic_is_left)
++		{
++			MR_SIDEPIC_X_OFFSET(msp->menu) += d;
++		}
++	} /* if (d > 0) */
++	MR_WIDTH(msp->menu) =
++		total_width + 2 * MST_BORDER_WIDTH(msp->menu);
++	MR_ITEM_WIDTH(msp->menu) = total_width - sidepic_space;
++	MR_ITEM_X_OFFSET(msp->menu) = MST_BORDER_WIDTH(msp->menu);
++	if (sidepic_is_left)
++	{
++		MR_ITEM_X_OFFSET(msp->menu) += sidepic_space;
++	}
++	if (!relief_begin_placed)
++	{
++		MR_HILIGHT_X_OFFSET(msp->menu) = MR_ITEM_X_OFFSET(msp->menu);
++	}
++	if (relief_end_placed)
++	{
++		MR_HILIGHT_WIDTH(msp->menu) =
++			MR_HILIGHT_WIDTH(msp->menu) -
++			MR_HILIGHT_X_OFFSET(msp->menu);
++	}
++	else
++	{
++		MR_HILIGHT_WIDTH(msp->menu) =
++			MR_ITEM_WIDTH(msp->menu) +
++			MR_ITEM_X_OFFSET(msp->menu) -
++			MR_HILIGHT_X_OFFSET(msp->menu);
++	}
++
++	/* Now calculate the offsets for the individual labels. */
++	for (mi = MR_FIRST_ITEM(msp->menu); mi != NULL; mi = MI_NEXT_ITEM(mi))
++	{
++		for (i = 0; i < MAX_MENU_ITEM_LABELS; i++)
++		{
++			if (MI_LABEL(mi)[i] == NULL)
++			{
++				continue;
++			}
++			if (!MI_IS_TITLE(mi) || !MI_IS_TITLE_CENTERED(mi))
++			{
++				switch (lcr_column[i])
++				{
++				case 'l':
++					MI_LABEL_OFFSET(mi)[i] =
++						label_offset[i];
++					break;
++				case 'c':
++					MI_LABEL_OFFSET(mi)[i] =
++						label_offset[i] +
++						(msp->max.i.label_width[i] -
++						 MI_LABEL_OFFSET(mi)[i]) / 2;
++					break;
++				case 'r':
++					MI_LABEL_OFFSET(mi)[i] =
++						label_offset[i] +
++						msp->max.i.label_width[i] -
++						MI_LABEL_OFFSET(mi)[i];
++					break;
++				}
++			}
++			else
++			{
++				/* This is a centered title item (indicated by
++				 * negative width). */
++				MI_LABEL_OFFSET(mi)[i] =
++					menudim_middle_x_offset(
++						&MR_DIM(msp->menu)) -
++					MI_LABEL_OFFSET(mi)[i] / 2;
++			}
++		} /* for */
++	} /* for */
++
++	return;
++}
++
++
++/*
++ *
++ * Calculate the positions of the columns in the menu.
++ * Called by make_menu().
++ *
++ */
++static Bool size_menu_vertically(MenuSizingParameters *msp)
++{
++	MenuItem *mi;
++	int y;
++	int cItems;
++	int relief_thickness = MST_RELIEF_THICKNESS(msp->menu);
++	int simple_entry_height;
++	int i;
++	Bool has_continuation_menu = False;
++
++	MR_ITEM_TEXT_Y_OFFSET(msp->menu) =
++		MST_PSTDFONT(msp->menu)->ascent + relief_thickness +
++		MST_ITEM_GAP_ABOVE(msp->menu);
++	simple_entry_height =   MST_PSTDFONT(msp->menu)->height +
++		MST_ITEM_GAP_ABOVE(msp->menu) + MST_ITEM_GAP_BELOW(msp->menu);
++
++	/* mi_prev trails one behind mi, since we need to move that
++	   into a newly-made menu if we run out of space */
++	y = MST_BORDER_WIDTH(msp->menu);
++	for (cItems = 0, mi = MR_FIRST_ITEM(msp->menu); mi != NULL;
++	     mi = MI_NEXT_ITEM(mi), cItems++)
++	{
++		Bool last_item_has_relief =
++			(MI_PREV_ITEM(mi)) ?
++			MI_IS_SELECTABLE(MI_PREV_ITEM(mi)) : False;
++		Bool has_mini_icon = False;
++		int separator_height;
++
++		separator_height = (last_item_has_relief) ?
++			MENU_SEPARATOR_HEIGHT + relief_thickness :
++			MENU_SEPARATOR_TOTAL_HEIGHT;
++		MI_Y_OFFSET(mi) = y;
++		if (MI_IS_TITLE(mi))
++		{
++			MI_HEIGHT(mi) = MST_PTITLEFONT(msp->menu)->height +
++				MST_TITLE_GAP_ABOVE(msp->menu) +
++				MST_TITLE_GAP_BELOW(msp->menu);
++		}
++		else if (MI_IS_SEPARATOR(mi))
++		{
++			/* Separator */
++			MI_HEIGHT(mi) = separator_height;
++		}
++		else if (MI_IS_TEAR_OFF_BAR(mi))
++		{
++			/* Tear off bar */
++			MI_HEIGHT(mi) = relief_thickness +
++				MENU_TEAR_OFF_BAR_HEIGHT;
++		}
++		else
++		{
++			/* Normal text entry or an entry with a sub menu
++			 * triangle */
++			if ((MI_HAS_TEXT(mi) && msp->used_item_labels) ||
++			    (MI_IS_POPUP(mi) &&
++			     msp->flags.is_popup_indicator_used))
++			{
++				MI_HEIGHT(mi) = simple_entry_height +
++					relief_thickness;
++			}
++			else
++			{
++				MI_HEIGHT(mi) =
++					MST_ITEM_GAP_ABOVE(msp->menu) +
++					MST_ITEM_GAP_BELOW(msp->menu) +
++					relief_thickness;
++			}
++		}
++		if (MI_IS_TITLE(mi))
++		{
++			/* add space for the underlines */
++			switch (MST_TITLE_UNDERLINES(msp->menu))
++			{
++			case 0:
++				if (last_item_has_relief)
++					MI_HEIGHT(mi) += relief_thickness;
++				break;
++			case 1:
++				if (mi != MR_FIRST_ITEM(msp->menu))
++				{
++					/* Space to draw the separator plus a
++					 * gap above */
++					MI_HEIGHT(mi) += separator_height;
++				}
++				if (MI_NEXT_ITEM(mi) != NULL)
++				{
++					/* Space to draw the separator */
++					MI_HEIGHT(mi) += MENU_SEPARATOR_HEIGHT;
++				}
++				break;
++			default:
++				/* Space to draw n underlines. */
++				MI_HEIGHT(mi) +=
++					MENU_UNDERLINE_HEIGHT *
++					MST_TITLE_UNDERLINES(msp->menu);
++				if (last_item_has_relief)
++					MI_HEIGHT(mi) += relief_thickness;
++				break;
++			}
++		}
++		for (i = 0; i < msp->used_mini_icons; i++)
++		{
++			if (MI_MINI_ICON(mi)[i])
++			{
++				has_mini_icon = True;
++			}
++			if (MI_MINI_ICON(mi)[i] &&
++			    MI_HEIGHT(mi) <
++			    MI_MINI_ICON(mi)[i]->height + relief_thickness)
++			{
++				MI_HEIGHT(mi) = MI_MINI_ICON(mi)[i]->height +
++					relief_thickness;
++			}
++		}
++		if (MI_PICTURE(mi))
++		{
++			if ((MI_HAS_TEXT(mi) && msp->used_item_labels) ||
++			    has_mini_icon)
++			{
++				MI_HEIGHT(mi) += MI_PICTURE(mi)->height;
++			}
++			else
++			{
++				MI_HEIGHT(mi) = MI_PICTURE(mi)->height +
++					relief_thickness;
++			}
++		}
++		y += MI_HEIGHT(mi);
++		/* this item would have to be the last item, or else
++		 * we need to add a "More..." entry pointing to a new menu */
++		if (y + MST_BORDER_WIDTH(msp->menu) +
++		    ((MI_IS_SELECTABLE(mi)) ? relief_thickness : 0)
++		    > MR_SCREEN_HEIGHT(msp->menu))
++		{
++			/* Item does not fit on screen anymore. */
++			Bool does_fit = False;
++			char *t;
++			char *tempname;
++			MenuRoot *menuContinuation;
++
++			/* Remove items form the menu until it fits (plus a
++			 * 'More' entry). */
++			while (MI_PREV_ITEM(mi) != NULL)
++			{
++				/* Remove current item. */
++				y -= MI_HEIGHT(mi);
++				mi = MI_PREV_ITEM(mi);
++				cItems--;
++				if (y + MST_BORDER_WIDTH(msp->menu) +
++				    simple_entry_height +
++				    2 * relief_thickness <=
++				    MR_SCREEN_HEIGHT(msp->menu))
++				{
++					/* ok, it fits now */
++					does_fit = True;
++					break;
++				}
++			}
++			if (!does_fit || MI_PREV_ITEM(mi) == NULL)
++			{
++				fvwm_msg(ERR, "size_menu_vertically",
++					 "Menu entry does not fit on screen");
++				/* leave a coredump */
++				abort();
++				exit(1);
++			}
++
++			t = EscapeString(MR_NAME(msp->menu), "\"", '\\');
++			tempname = (char *)safemalloc(
++				(10 + strlen(t)) * sizeof(char));
++			strcpy(tempname, "Popup \"");
++			strcat(tempname, t);
++			strcat(tempname, "$\"");
++			free(t);
++			/* NewMenuRoot inserts at the head of the list of menus
++			   but, we need it at the end.  (Give it just the name,
++			   * which is 6 chars past the action since
++			   * strlen("Popup ")==6 ) */
++			t = (char *)safemalloc(strlen(MR_NAME(msp->menu)) + 2);
++			strcpy(t, MR_NAME(msp->menu));
++			strcat(t, "$");
++			menuContinuation = NewMenuRoot(t);
++			free(t);
++			MR_CONTINUATION_MENU(msp->menu) = menuContinuation;
++
++			/* Now move this item and the remaining items into the
++			 * new menu */
++			MR_FIRST_ITEM(menuContinuation) = MI_NEXT_ITEM(mi);
++			MR_LAST_ITEM(menuContinuation) =
++				MR_LAST_ITEM(msp->menu);
++			MR_ITEMS(menuContinuation) =
++				MR_ITEMS(msp->menu) - cItems;
++			MI_PREV_ITEM(MI_NEXT_ITEM(mi)) = NULL;
++
++			/* mi_prev is now the last item in the parent menu */
++			MR_LAST_ITEM(msp->menu) = mi;
++			MR_ITEMS(msp->menu) = cItems;
++			MI_NEXT_ITEM(mi) = NULL;
++
++			/* use the same style for the submenu */
++			MR_STYLE(menuContinuation) = MR_STYLE(msp->menu);
++			MR_IS_LEFT_TRIANGLE(menuContinuation) =
++				MR_IS_LEFT_TRIANGLE(msp->menu);
++			/* migo: propagate missing_submenu_func */
++			if (MR_MISSING_SUBMENU_FUNC(msp->menu))
++			{
++				MR_MISSING_SUBMENU_FUNC(menuContinuation) =
++					safestrdup(MR_MISSING_SUBMENU_FUNC(
++							   msp->menu));
++			}
++			/* don't propagate sidepic, sidecolor, popup and
++			 * popdown actions */
++			/* And add the entry pointing to the new menu */
++			AddToMenu(
++				msp->menu, "More&...", tempname,
++				False /* no pixmap scan */, False, True);
++			free(tempname);
++			has_continuation_menu = True;
++		}
++	} /* for */
++	/* The menu may be empty here! */
++	if (MR_LAST_ITEM(msp->menu) != NULL &&
++	    MI_IS_SELECTABLE(MR_LAST_ITEM(msp->menu)))
++	{
++		y += relief_thickness;
++	}
++	MR_HEIGHT(msp->menu) = y + MST_BORDER_WIDTH(msp->menu);
++
++	return has_continuation_menu;
++}
++
++/*
++ *
++ * Merge menu continuations back into the original menu.
++ * Called by make_menu().
++ *
++ */
++static void merge_continuation_menus(MenuRoot *mr)
++{
++	/* merge menu continuations into one menu again - needed when changing
++	 * the font size of a long menu. */
++	while (MR_CONTINUATION_MENU(mr) != NULL)
++	{
++		MenuRoot *cont = MR_CONTINUATION_MENU(mr);
++
++		/* link first item of continuation to item before 'more...' */
++		MI_NEXT_ITEM(MI_PREV_ITEM(MR_LAST_ITEM(mr))) =
++			MR_FIRST_ITEM(cont);
++		MI_PREV_ITEM(MR_FIRST_ITEM(cont)) =
++			MI_PREV_ITEM(MR_LAST_ITEM(mr));
++		menuitem_free(MR_LAST_ITEM(mr));
++		MR_LAST_ITEM(mr) = MR_LAST_ITEM(cont);
++		MR_CONTINUATION_MENU(mr) = MR_CONTINUATION_MENU(cont);
++		/* fake an empty menu so that DestroyMenu does not destroy the
++		 * items. */
++		MR_FIRST_ITEM(cont) = NULL;
++		DestroyMenu(cont, False, False);
++	}
++
++	return;
++}
++
++/*
++ *
++ * Creates the window for the menu.
++ *
++ */
++static void make_menu_window(MenuRoot *mr, Bool is_tear_off)
++{
++	unsigned long valuemask;
++	XSetWindowAttributes attributes;
++	int w;
++	int h;
++	unsigned int evmask;
++
++	w = MR_WIDTH(mr);
++	if (w == 0)
++	{
++		w = 1;
++	}
++	h = MR_HEIGHT(mr);
++	if (h == 0)
++	{
++		h = 1;
++	}
++
++	attributes.background_pixel = (MST_HAS_MENU_CSET(mr)) ?
++		Colorset[MST_CSET_MENU(mr)].bg : MST_MENU_COLORS(mr).back;
++	if (MR_WINDOW(mr) != None)
++	{
++		/* just resize the existing window */
++		XResizeWindow(dpy, MR_WINDOW(mr), w, h);
++		/* and change the background color */
++		valuemask = CWBackPixel | CWCursor;
++		XChangeWindowAttributes(
++			dpy, MR_WINDOW(mr), valuemask, &attributes);
++	}
++	else
++	{
++		/* create a new window */
++		valuemask = CWBackPixel | CWEventMask | CWCursor | CWColormap
++			| CWBorderPixel | CWSaveUnder;
++		attributes.border_pixel = 0;
++		attributes.colormap = Pcmap;
++		evmask = XEVMASK_MENUW;
++		attributes.event_mask = 0;
++		attributes.cursor = Scr.FvwmCursors[CRS_MENU];
++		attributes.save_under = True;
++
++		/* Create a display used to create the window.  Can't use the
++		 * normal display because 'xkill' would  kill the window
++		 * manager if used on a tear off menu.  The display can't be
++		 * deleted right now because that would either destroy the new
++		 * window or leave it as an orphan if fvwm dies or is
++		 * restarted. */
++		if (is_tear_off)
++		{
++			MR_CREATE_DPY(mr) = XOpenDisplay(display_name);
++			if (MR_CREATE_DPY(mr) == NULL)
++			{
++				/* Doh.  Use the standard display instead. */
++				MR_CREATE_DPY(mr) = dpy;
++			}
++		}
++		else
++		{
++			MR_CREATE_DPY(mr) = dpy;
++		}
++		MR_WINDOW(mr) = XCreateWindow(
++			MR_CREATE_DPY(mr), Scr.Root, 0, 0, w, h,
++			0, Pdepth, InputOutput, Pvisual, valuemask,
++			&attributes);
++		if (MR_CREATE_DPY(mr) != dpy)
++		{
++			/* We *must* synchronize the display here.  Otherwise
++			 * the request will never be processed. */
++			XSync(MR_CREATE_DPY(mr), 1);
++		}
++		if (MR_WINDOW(mr) != None)
++		{
++			/* select events for the window from the standard
++			 * display */
++			XSelectInput(dpy, MR_WINDOW(mr), evmask);
++		}
++		XSaveContext(dpy, MR_WINDOW(mr), MenuContext,(caddr_t)mr);
++	}
++
++	return;
++}
++
++
++/*
++ *
++ * Generates the window for a menu
++ *
++ */
++static void make_menu(MenuRoot *mr, Bool is_tear_off)
++{
++	MenuSizingParameters msp;
++	Bool has_continuation_menu = False;
++
++	if (MR_MAPPED_COPIES(mr) > 0)
++	{
++		return;
++	}
++	merge_continuation_menus(mr);
++	do
++	{
++		memset(&msp, 0, sizeof(MenuSizingParameters));
++		msp.menu = mr;
++		calculate_item_sizes(&msp);
++		/* Call size_menu_horizontally first because it calculated
++		 * some values used by size_menu_vertically. */
++		size_menu_horizontally(&msp);
++		has_continuation_menu = size_menu_vertically(&msp);
++		/* repeat this step if the menu was split */
++	} while (has_continuation_menu);
++	MR_USED_MINI_ICONS(mr) = msp.used_mini_icons;
++
++	MR_XANIMATION(mr) = 0;
++	memset(&(MR_DYNAMIC_FLAGS(mr)), 0, sizeof(MR_DYNAMIC_FLAGS(mr)));
++
++	/* create a new window for the menu */
++	make_menu_window(mr, is_tear_off);
++	MR_IS_UPDATED(mr) = 0;
++
++	return;
++}
++
++/* Make sure the menu is properly rebuilt when the style or the menu has
++ * changed. */
++static void update_menu(MenuRoot *mr, MenuParameters *pmp)
++{
++	int sw;
++	int sh;
++	Bool has_screen_size_changed = False;
++	fscreen_scr_arg fscr;
++
++	if (MST_IS_UPDATED(mr))
++	{
++		/* The menu style has changed. */
++		MenuRoot *menu;
++
++		for (menu = Menus.all; menu; menu = MR_NEXT_MENU(menu))
++		{
++			if (MR_STYLE(menu) == MR_STYLE(mr))
++			{
++				/* Mark all other menus with the same style as
++				 * changed. */
++				MR_IS_UPDATED(menu) = 1;
++			}
++		}
++		MST_IS_UPDATED(mr) = 0;
++	}
++	fscr.xypos.x = pmp->screen_origin_x;
++	fscr.xypos.y = pmp->screen_origin_y;
++	FScreenGetScrRect(&fscr, FSCREEN_XYPOS, &JunkX, &JunkY, &sw, &sh);
++	if (sw != MR_SCREEN_WIDTH(mr) || sh != MR_SCREEN_HEIGHT(mr))
++	{
++		has_screen_size_changed = True;
++		MR_SCREEN_WIDTH(mr) = sw;
++		MR_SCREEN_HEIGHT(mr) = sh;
++	}
++	if (MR_IS_UPDATED(mr) || has_screen_size_changed)
++	{
++		/* The menu or the screen dimensions have changed. We have to
++		 * re-make it. */
++		make_menu(mr, False);
++	}
++
++	return;
++}
++
++/*
++ *
++ *  Procedure:
++ *      copy_menu_root - creates a new instance of an existing menu
++ *
++ *  Returned Value:
++ *      (MenuRoot *)
++ *
++ *  Inputs:
++ *      mr      - the MenuRoot structure of the existing menu
++ *
++ */
++static MenuRoot *copy_menu_root(MenuRoot *mr)
++{
++	MenuRoot *tmp;
++
++	if (!mr || MR_COPIES(mr) >= MAX_MENU_COPIES)
++	{
++		return NULL;
++	}
++	tmp = (MenuRoot *)safemalloc(sizeof(MenuRoot));
++	tmp->d = (MenuRootDynamic *)safemalloc(sizeof(MenuRootDynamic));
++	memset(tmp->d, 0, sizeof(MenuRootDynamic));
++	tmp->s = mr->s;
++
++	MR_COPIES(mr)++;
++	MR_ORIGINAL_MENU(tmp) = MR_ORIGINAL_MENU(mr);
++	MR_CONTINUATION_MENU(tmp) = MR_CONTINUATION_MENU(mr);
++	MR_NEXT_MENU(tmp) = MR_NEXT_MENU(mr);
++	MR_NEXT_MENU(mr) = tmp;
++	MR_WINDOW(tmp) = None;
++	memset(&(MR_DYNAMIC_FLAGS(tmp)), 0, sizeof(MR_DYNAMIC_FLAGS(tmp)));
++
++	return tmp;
++}
++
++/*
++ *
++ *  Procedure:
++ *      clone_menu - duplicates an existing menu in newly allocated
++ memory.  The new menu is independent of the original.
++ *
++ *  Returned Value:
++ *      (MenuRoot *)
++ *
++ *  Inputs:
++ *      mr      - the MenuRoot structure of the existing menu
++ *
++ */
++static void clone_menu_root_static(
++	MenuRoot *dest_mr, MenuRoot *src_mr)
++{
++	dest_mr->s = (MenuRootStatic *)safemalloc(sizeof(MenuRootStatic));
++	/* copy everything */
++	memcpy(dest_mr->s, src_mr->s, sizeof(MenuRootStatic));
++	/* special treatment for a few parts */
++	if (MR_NAME(src_mr) != NULL)
++	{
++		MR_NAME(dest_mr) = safestrdup(MR_NAME(src_mr));
++	}
++	MR_COPIES(dest_mr) = 1;
++	MR_MAPPED_COPIES(dest_mr) = 0;
++	MR_POPUP_ACTION(dest_mr) = NULL;
++	MR_POPDOWN_ACTION(dest_mr) = NULL;
++	if (MR_MISSING_SUBMENU_FUNC(src_mr))
++	{
++		MR_MISSING_SUBMENU_FUNC(dest_mr) =
++			safestrdup(MR_MISSING_SUBMENU_FUNC(src_mr));
++	}
++	if (MR_HAS_SIDECOLOR(src_mr))
++	{
++		MR_SIDECOLOR(dest_mr) =
++			fvwmlib_clone_color(MR_SIDECOLOR(src_mr));
++	}
++	MR_SIDEPIC(dest_mr) = PCloneFvwmPicture(MR_SIDEPIC(src_mr));
++	clone_menu_item_list(dest_mr, src_mr);
++
++	return;
++}
++
++static MenuRoot *clone_menu(MenuRoot *mr)
++{
++	MenuRoot *new_mr;
++
++	new_mr = (MenuRoot *)safemalloc(sizeof(MenuRoot));
++	new_mr->d = (MenuRootDynamic *)safemalloc(sizeof(MenuRootDynamic));
++	memset(new_mr->d, 0, sizeof(MenuRootDynamic));
++	clone_menu_root_static(new_mr, mr);
++
++	return new_mr;
++}
++
++/* ---------------------------- position hints ----------------------------- */
++
++static int float_to_int_with_tolerance(float f)
++{
++	int low;
++
++	if (f < 0)
++	{
++		low = (int)(f - ROUNDING_ERROR_TOLERANCE);
++	}
++	else
++	{
++		low = (int)(f + ROUNDING_ERROR_TOLERANCE);
++	}
++	if ((int)f != low)
++	{
++		return low;
++	}
++	else
++	{
++		return (int)(f);
++	}
++}
++
++static void get_xy_from_position_hints(
++	struct MenuPosHints *ph, int width, int height, int context_width,
++	Bool do_reverse_x, int *ret_x, int *ret_y)
++{
++	float x_add;
++	float y_add;
++
++	*ret_x = ph->x;
++	*ret_y = ph->y;
++	if (ph->is_menu_relative)
++	{
++		if (do_reverse_x)
++		{
++			*ret_x -= ph->x_offset;
++			x_add = width * (-1.0 - ph->x_factor) +
++				ph->menu_width * (1.0 - ph->context_x_factor);
++		}
++		else
++		{
++			*ret_x += ph->x_offset;
++			x_add = width * ph->x_factor +
++				ph->menu_width * ph->context_x_factor;
++		}
++		y_add = height * ph->y_factor;
++	}
++	else
++	{
++		x_add = width * ph->x_factor;
++		y_add = height * ph->y_factor;
++	}
++	*ret_x += float_to_int_with_tolerance(x_add);
++	*ret_y += float_to_int_with_tolerance(y_add);
++
++	return;
++}
++
++/*
++ * Used by get_menu_options
++ *
++ * The vars are named for the x-direction, but this is used for both x and y
++ */
++static char *get_one_menu_position_argument(
++	char *action, int x, int w, int *pFinalX, int *x_offset,
++	float *width_factor, float *context_width_factor,
++	Bool *is_menu_relative)
++{
++	char *token, *orgtoken, *naction;
++	char c;
++	int val;
++	int chars;
++	float fval;
++	float factor = (float)w/100;
++	float x_add = 0;
++
++	naction = GetNextToken(action, &token);
++	if (token == NULL)
++	{
++		return action;
++	}
++	orgtoken = token;
++	*pFinalX = x;
++	*x_offset = 0;
++	*width_factor = 0.0;
++	*context_width_factor = 0.0;
++	if (sscanf(token,"o%d%n", &val, &chars) >= 1)
++	{
++		fval = val;
++		token += chars;
++		x_add += fval*factor;
++		*width_factor -= fval / 100.0;
++		*context_width_factor += fval / 100.0;
++	}
++	else if (token[0] == 'c')
++	{
++		token++;
++		x_add += ((float)w) / 2.0;
++		*width_factor -= 0.5;
++		*context_width_factor += 0.5;
++	}
++	while (*token != 0)
++	{
++		if (sscanf(token,"%d%n", &val, &chars) < 1)
++		{
++			naction = action;
++			break;
++		}
++		fval = (float)val;
++		token += chars;
++		if (sscanf(token,"%c", &c) == 1)
++		{
++			switch (c)
++			{
++			case 'm':
++				token++;
++				*width_factor += fval / 100.0;
++				*is_menu_relative = True;
++				break;
++			case 'p':
++				token++;
++				x_add += val;
++				*x_offset += val;
++				break;
++			default:
++				x_add += fval * factor;
++				*context_width_factor += fval / 100.0;
++				break;
++			}
++		}
++		else
++		{
++			x_add += fval * factor;
++			*context_width_factor += fval / 100.0;
++		}
++	}
++	*pFinalX += float_to_int_with_tolerance(x_add);
++	free(orgtoken);
++
++	return naction;
++}
++
++/* Returns the menu options for the menu that a given menu item pops up */
++static void get_popup_options(
++	MenuParameters *pmp, MenuItem *mi, MenuOptions *pops)
++{
++	if (!mi)
++	{
++		return;
++	}
++	pops->flags.has_poshints = 0;
++	pops->pos_hints.has_screen_origin = True;
++	pops->pos_hints.screen_origin_x = pmp->screen_origin_x;
++	pops->pos_hints.screen_origin_y = pmp->screen_origin_y;
++	/* just look past "Popup <name>" in the action */
++	get_menu_options(
++		SkipNTokens(MI_ACTION(mi), 2), MR_WINDOW(pmp->menu), NULL,
++		NULL, pmp->menu, mi, pops);
++
++	return;
++}
++
++/* ---------------------------- menu painting functions --------------------- */
++
++static void clear_expose_menu_area(Window win, XEvent *e)
++{
++	if (e == NULL)
++	{
++		XClearWindow(dpy, win);
++	}
++	else
++	{
++		XClearArea(
++			dpy, win, e->xexpose.x, e->xexpose.y, e->xexpose.width,
++			e->xexpose.height, False);
++	}
++
++	return;
++}
++
++/*
++ *
++ * Draws a picture on the left side of the menu
++ * What about a SidePic Colorset ? (olicha 2002-08-21)
++ *
++ */
++static void paint_side_pic(MenuRoot *mr, XEvent *pevent)
++{
++	GC gc;
++	FvwmPicture *sidePic;
++	int ys;
++	int yt;
++	int h;
++	int bw = MST_BORDER_WIDTH(mr);
++
++	if (MR_SIDEPIC(mr))
++	{
++		sidePic = MR_SIDEPIC(mr);
++	}
++	else if (MST_SIDEPIC(mr))
++	{
++		sidePic = MST_SIDEPIC(mr);
++	}
++	else
++	{
++		return;
++	}
++
++	if (Pdepth < 2)
++	{
++		/* ? */
++		gc = SHADOW_GC(MST_MENU_INACTIVE_GCS(mr));
++	}
++	else
++	{
++		gc = FORE_GC(MST_MENU_INACTIVE_GCS(mr));
++	}
++
++	if (sidePic->height > MR_HEIGHT(mr) - 2 * bw)
++	{
++		h = MR_HEIGHT(mr) - 2 * bw;
++		ys = sidePic->height - h;
++		yt = bw;
++	}
++	else
++	{
++		h = sidePic->height;
++		ys = 0;
++		yt = MR_HEIGHT(mr) - bw - sidePic->height;
++	}
++
++	if (MR_HAS_SIDECOLOR(mr))
++	{
++		Globalgcv.foreground = MR_SIDECOLOR(mr);
++	}
++	else if (MST_HAS_SIDE_COLOR(mr))
++	{
++		Globalgcv.foreground = MST_SIDE_COLOR(mr);
++	}
++
++	if (MR_HAS_SIDECOLOR(mr) || MST_HAS_SIDE_COLOR(mr))
++	{
++		Globalgcm = GCForeground;
++		XChangeGC(dpy, Scr.ScratchGC1, Globalgcm, &Globalgcv);
++		XFillRectangle(dpy, MR_WINDOW(mr), Scr.ScratchGC1,
++			       MR_SIDEPIC_X_OFFSET(mr), bw,
++			       sidePic->width, MR_HEIGHT(mr) - 2 * bw);
++	}
++	else if (sidePic->alpha != None)
++	{
++		XClearArea(
++			dpy, MR_WINDOW(mr),
++			MR_SIDEPIC_X_OFFSET(mr), yt, sidePic->width, h, False);
++	}
++
++	PGraphicsRenderPicture(
++		dpy, MR_WINDOW(mr), sidePic, 0, MR_WINDOW(mr),
++		gc, Scr.MonoGC, Scr.AlphaGC,
++		0, ys, sidePic->width, h,
++		MR_SIDEPIC_X_OFFSET(mr), yt, sidePic->width, h, False);
++
++	return;
++}
++
++static Bool paint_menu_gradient_background(
++	MenuRoot *mr, XEvent *pevent)
++{
++	MenuStyle *ms = MR_STYLE(mr);
++	int bw = MST_BORDER_WIDTH(mr);
++	XRectangle bounds;
++	Pixmap pmap;
++	GC pmapgc;
++	XGCValues gcv;
++	unsigned long gcm = GCLineWidth;
++	int switcher = -1;
++	Bool do_clear = False;
++
++	gcv.line_width = 1;
++	bounds.x = bw;
++	bounds.y = bw;
++	bounds.width = MR_WIDTH(mr) - bw;
++	bounds.height = MR_HEIGHT(mr) - bw;
++	/* H, V, D and B gradients are optimized and have
++	 * their own code here. (if no dither) */
++	if (!ST_FACE(ms).u.grad.do_dither)
++	{
++		switcher = ST_FACE(ms).gradient_type;
++	}
++	switch (switcher)
++	{
++	case H_GRADIENT:
++		if (MR_IS_BACKGROUND_SET(mr) == False)
++		{
++			register int i;
++			register int dw;
++
++			pmap = XCreatePixmap(
++				dpy, MR_WINDOW(mr), MR_WIDTH(mr),
++				DEFAULT_MENU_GRADIENT_PIXMAP_THICKNESS,
++				Pdepth);
++			pmapgc = fvwmlib_XCreateGC(dpy, pmap, gcm, &gcv);
++			dw = (float)
++				(bounds.width / ST_FACE(ms).u.grad.npixels)
++				+ 1;
++			for (i = 0; i < ST_FACE(ms).u.grad.npixels; i++)
++			{
++				int x;
++
++				x = i * bounds.width /
++					ST_FACE(ms).u.grad.npixels;
++				XSetForeground(
++					dpy, pmapgc,
++					ST_FACE(ms).u.grad.xcs[i].pixel);
++				XFillRectangle(
++					dpy, pmap, pmapgc, x, 0, dw,
++					DEFAULT_MENU_GRADIENT_PIXMAP_THICKNESS);
++			}
++			XSetWindowBackgroundPixmap(dpy, MR_WINDOW(mr), pmap);
++			XFreeGC(dpy,pmapgc);
++			XFreePixmap(dpy,pmap);
++			MR_IS_BACKGROUND_SET(mr) = True;
++		}
++		do_clear = True;
++		break;
++	case V_GRADIENT:
++		if (MR_IS_BACKGROUND_SET(mr) == False)
++		{
++			register int i;
++			register int dh;
++			static int best_tile_width = 0;
++			int junk;
++
++			if (best_tile_width == 0)
++			{
++				int tw = DEFAULT_MENU_GRADIENT_PIXMAP_THICKNESS;
++
++				if (!XQueryBestTile(
++					    dpy, Scr.screen, tw, tw,
++					    (unsigned int*)&best_tile_width,
++					    (unsigned int*)&junk))
++				{
++					/* call failed, use default and risk a
++					 * screwed up tile */
++					best_tile_width = tw;
++				}
++			}
++			pmap = XCreatePixmap(
++				dpy, MR_WINDOW(mr), best_tile_width,
++				MR_HEIGHT(mr), Pdepth);
++			pmapgc = fvwmlib_XCreateGC(dpy, pmap, gcm, &gcv);
++			dh = (float) (bounds.height /
++				      ST_FACE(ms).u.grad.npixels) + 1;
++			for (i = 0; i < ST_FACE(ms).u.grad.npixels; i++)
++			{
++				int y;
++
++				y = i * bounds.height /
++					ST_FACE(ms).u.grad.npixels;
++				XSetForeground(
++					dpy, pmapgc,
++					ST_FACE(ms).u.grad.xcs[i].pixel);
++				XFillRectangle(
++					dpy, pmap, pmapgc, 0, y,
++					best_tile_width, dh);
++			}
++			XSetWindowBackgroundPixmap(dpy, MR_WINDOW(mr), pmap);
++			XFreeGC(dpy,pmapgc);
++			XFreePixmap(dpy,pmap);
++			MR_IS_BACKGROUND_SET(mr) = True;
++		}
++		do_clear = True;
++		break;
++	case D_GRADIENT:
++	case B_GRADIENT:
++	{
++		register int i = 0, numLines;
++		int cindex = -1;
++		XRectangle r;
++		FvwmPicture *sidePic = NULL;
++
++		if (MR_SIDEPIC(mr))
++		{
++			sidePic = MR_SIDEPIC(mr);
++		}
++		else if (MST_SIDEPIC(mr))
++		{
++			sidePic = MST_SIDEPIC(mr);
++		}
++		if (pevent)
++		{
++			r.x = pevent->xexpose.x;
++			r.y = pevent->xexpose.y;
++			r.width = pevent->xexpose.width;
++			r.height = pevent->xexpose.height;
++		}
++		else
++		{
++			r.x = bw;
++			r.y = bw;
++			r.width = MR_WIDTH(mr) - 2 * bw;
++			r.height = MR_HEIGHT(mr) - 2 * bw;
++		}
++		XSetClipRectangles(
++			dpy, Scr.TransMaskGC, 0, 0, &r, 1, Unsorted);
++		numLines = MR_WIDTH(mr) + MR_HEIGHT(mr) - 2 * bw;
++		for (i = 0; i < numLines; i++)
++		{
++			if ((int)(i * ST_FACE(ms).u.grad.npixels / numLines) >
++			    cindex)
++			{
++				/* pick the next colour (skip if necc.) */
++				cindex = i * ST_FACE(ms).u.grad.npixels /
++					numLines;
++				XSetForeground(
++					dpy, Scr.TransMaskGC,
++					ST_FACE(ms).u.grad.xcs[cindex].pixel);
++			}
++			if (ST_FACE(ms).gradient_type == D_GRADIENT)
++			{
++				XDrawLine(dpy, MR_WINDOW(mr),
++					  Scr.TransMaskGC, 0, i, i, 0);
++			}
++			else /* B_GRADIENT */
++			{
++				XDrawLine(dpy, MR_WINDOW(mr), Scr.TransMaskGC,
++					  0, MR_HEIGHT(mr) - 1 - i, i,
++					  MR_HEIGHT(mr) - 1);
++			}
++		}
++	}
++	XSetClipMask(dpy, Scr.TransMaskGC, None);
++	break;
++	default:
++		if (MR_IS_BACKGROUND_SET(mr) == False)
++		{
++			int g_width;
++			int g_height;
++
++			/* let library take care of all other gradients */
++			pmap = XCreatePixmap(
++				dpy, MR_WINDOW(mr), MR_WIDTH(mr),
++				MR_HEIGHT(mr), Pdepth);
++			pmapgc = fvwmlib_XCreateGC(dpy, pmap, gcm, &gcv);
++
++			/* find out the size the pixmap should be */
++			CalculateGradientDimensions(
++				dpy, MR_WINDOW(mr), ST_FACE(ms).u.grad.npixels,
++				ST_FACE(ms).gradient_type,
++				ST_FACE(ms).u.grad.do_dither, &g_width,
++				&g_height);
++			/* draw the gradient directly into the window */
++			CreateGradientPixmap(
++				dpy, MR_WINDOW(mr), pmapgc,
++				ST_FACE(ms).gradient_type, g_width, g_height,
++				ST_FACE(ms).u.grad.npixels,
++				ST_FACE(ms).u.grad.xcs,
++				ST_FACE(ms).u.grad.do_dither,
++				&(MR_STORED_PIXELS(mr).d_pixels),
++				&(MR_STORED_PIXELS(mr).d_npixels),
++				pmap, bw, bw,
++				MR_WIDTH(mr) - bw, MR_HEIGHT(mr) - bw, NULL);
++			XSetWindowBackgroundPixmap(dpy, MR_WINDOW(mr), pmap);
++			XFreeGC(dpy, pmapgc);
++			XFreePixmap(dpy, pmap);
++			MR_IS_BACKGROUND_SET(mr) = True;
++		}
++		do_clear = True;
++		break;
++	}
++	return do_clear;
++}
++
++static Bool paint_menu_pixmap_background(
++	MenuRoot *mr, XEvent *pevent)
++{
++	MenuStyle *ms = MR_STYLE(mr);
++	int width, height, x, y;
++	int bw = MST_BORDER_WIDTH(mr);
++	FvwmPicture *p;
++
++	p = ST_FACE(ms).u.p;
++	width = MR_WIDTH(mr) - 2 * bw;
++	height = MR_HEIGHT(mr) - 2 * bw;
++	y = (int)(height - p->height) / 2;
++	x = (int)(width - p->width) / 2;
++	if (x < bw)
++	{
++		x = bw;
++	}
++	if (y < bw)
++	{
++		y = bw;
++	}
++	if (width > p->width)
++	{
++		width = p->width;
++	}
++	if (height > p->height)
++	{
++		height = p->height;
++	}
++	if (width > MR_WIDTH(mr) - x - bw)
++	{
++		width = MR_WIDTH(mr) - x - bw;
++	}
++	if (height > MR_HEIGHT(mr) - y - bw)
++	{
++		height = MR_HEIGHT(mr) - y - bw;
++	}
++	XSetClipMask(dpy, Scr.TransMaskGC, p->mask);
++	XSetClipOrigin(dpy, Scr.TransMaskGC, x, y);
++	XCopyArea(
++		dpy, p->picture, MR_WINDOW(mr), Scr.TransMaskGC,
++		bw, bw, width, height, x, y);
++
++	return False;
++}
++
++/*
++ *
++ *  Procedure:
++ *      get_menu_paint_item_parameters - prepares the parameters to be
++ *      passed to menuitem_paint().
++ *
++ *      mr - the menu instance that holds the menu item
++ *      mi - the menu item to redraw
++ *      fw - the FvwmWindow structure to check against allowed functions
++ *
++ */
++static void get_menu_paint_item_parameters(
++	MenuPaintItemParameters *mpip, MenuRoot *mr, MenuItem *mi,
++	FvwmWindow *fw, XEvent *pevent, Bool do_redraw_menu_border)
++{
++	mpip->ms = MR_STYLE(mr);
++	mpip->w = MR_WINDOW(mr);
++	mpip->selected_item = MR_SELECTED_ITEM(mr);
++	mpip->dim = &MR_DIM(mr);
++	mpip->fw = fw;
++	mpip->used_mini_icons = MR_USED_MINI_ICONS(mr);
++	mpip->cb_mr = mr;
++	mpip->cb_reset_bg = paint_menu_gradient_background;
++	mpip->flags.is_first_item = (MR_FIRST_ITEM(mr) == mi);
++	mpip->flags.is_left_triangle = MR_IS_LEFT_TRIANGLE(mr);
++	mpip->ev = pevent;
++
++	return;
++}
++
++/*
++ *
++ *  Procedure:
++ *      paint_menu - draws the entire menu
++ *
++ */
++static void paint_menu(
++	MenuRoot *mr, XEvent *pevent, FvwmWindow *fw)
++{
++	MenuItem *mi;
++	MenuStyle *ms = MR_STYLE(mr);
++	int bw = MST_BORDER_WIDTH(mr);
++	XGCValues gcv;
++	int relief_thickness = ST_RELIEF_THICKNESS(MR_STYLE(mr));
++
++	gcv.line_width = 3;
++	if (fw && !check_if_fvwm_window_exists(fw))
++	{
++		fw = NULL;
++	}
++	if (MR_IS_PAINTED(mr) && pevent &&
++	    (pevent->xexpose.x >= MR_WIDTH(mr) - bw ||
++	     pevent->xexpose.x + pevent->xexpose.width <= bw ||
++	     pevent->xexpose.y >= MR_HEIGHT(mr) - bw ||
++	     pevent->xexpose.y + pevent->xexpose.height <= bw))
++	{
++		/* Only the border was obscured. Redraw it centrally instead of
++		 * redrawing several menu items. */
++		RelieveRectangle(
++			dpy, MR_WINDOW(mr), 0, 0, MR_WIDTH(mr) - 1,
++			MR_HEIGHT(mr) - 1, (Pdepth < 2) ?
++			SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)) :
++			HILIGHT_GC(MST_MENU_INACTIVE_GCS(mr)),
++			SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)), bw);
++		{
++			return;
++		}
++	}
++	MR_IS_PAINTED(mr) = 1;
++	/* paint the menu background */
++	if (ms && ST_HAS_MENU_CSET(ms))
++	{
++		if (MR_IS_BACKGROUND_SET(mr) == False)
++		{
++			SetWindowBackground(
++				dpy, MR_WINDOW(mr), MR_WIDTH(mr),
++				MR_HEIGHT(mr), &Colorset[ST_CSET_MENU(ms)],
++				Pdepth, FORE_GC(ST_MENU_INACTIVE_GCS(ms)),
++				True);
++			MR_IS_BACKGROUND_SET(mr) = True;
++		}
++	}
++	else if (ms)
++	{
++		int type;
++		Bool do_clear = False;
++
++		type = ST_FACE(ms).type;
++		switch(type)
++		{
++		case SolidMenu:
++			XSetWindowBackground(
++				dpy, MR_WINDOW(mr), MST_FACE(mr).u.back);
++			do_clear = True;
++			break;
++		case GradientMenu:
++			do_clear = paint_menu_gradient_background(mr, pevent);
++			break;
++		case PixmapMenu:
++			do_clear = paint_menu_pixmap_background(mr, pevent);
++			break;
++		case TiledPixmapMenu:
++			XSetWindowBackgroundPixmap(
++				dpy, MR_WINDOW(mr), ST_FACE(ms).u.p->picture);
++			do_clear = True;
++			break;
++		} /* switch(type) */
++		if (do_clear == True)
++		{
++			clear_expose_menu_area(MR_WINDOW(mr), pevent);
++		}
++	} /* if (ms) */
++	/* draw the relief */
++	RelieveRectangle(dpy, MR_WINDOW(mr), 0, 0, MR_WIDTH(mr) - 1,
++			 MR_HEIGHT(mr) - 1, (Pdepth < 2) ?
++			 SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)) :
++			 HILIGHT_GC(MST_MENU_INACTIVE_GCS(mr)),
++			 SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)), bw);
++	/* paint the menu items */
++	for (mi = MR_FIRST_ITEM(mr); mi != NULL; mi = MI_NEXT_ITEM(mi))
++	{
++		int do_draw = 0;
++
++		/* be smart about handling the expose, redraw only the entries
++		 * that we need to */
++		if (pevent == NULL)
++		{
++			do_draw = True;
++		}
++		else
++		{
++			register int b_offset;
++
++			b_offset = MI_Y_OFFSET(mi) + MI_HEIGHT(mi);
++			if (MR_SELECTED_ITEM(mr) == mi)
++			{
++				b_offset += relief_thickness;
++			}
++			if (pevent->xexpose.y < b_offset &&
++			    (pevent->xexpose.y + pevent->xexpose.height) >
++			    MI_Y_OFFSET(mi))
++			{
++				do_draw = True;
++			}
++		}
++		if (do_draw)
++		{
++			MenuPaintItemParameters mpip;
++
++			get_menu_paint_item_parameters(
++				&mpip, mr, NULL, fw, pevent, True);
++			mpip.flags.is_first_item = (MR_FIRST_ITEM(mr) == mi);
++			menuitem_paint(mi, &mpip);
++		}
++	}
++	paint_side_pic(mr, pevent);
++	XFlush(dpy);
++
++	return;
++}
++
++/* Set the selected-ness state of the menuitem passed in */
++static void select_menu_item(
++	MenuRoot *mr, MenuItem *mi, Bool select, FvwmWindow *fw)
++{
++	if (select == True && MR_SELECTED_ITEM(mr) != NULL &&
++	    MR_SELECTED_ITEM(mr) != mi)
++	{
++		select_menu_item(mr, MR_SELECTED_ITEM(mr), False, fw);
++	}
++	else if (select == False && MR_SELECTED_ITEM(mr) == NULL)
++	{
++		return;
++	}
++	else if (select == True && MR_SELECTED_ITEM(mr) == mi)
++	{
++		return;
++	}
++	if (!MI_IS_SELECTABLE(mi))
++	{
++		return;
++	}
++
++	if (select == False)
++	{
++		MI_WAS_DESELECTED(mi) = True;
++	}
++
++	if (!MST_HAS_MENU_CSET(mr))
++	{
++		switch (MST_FACE(mr).type)
++		{
++		case GradientMenu:
++			if (select == True)
++			{
++				int iy;
++				int ih;
++				int mw;
++				XEvent e;
++
++				if (!MR_IS_PAINTED(mr))
++				{
++					flush_expose(MR_WINDOW(mr));
++					paint_menu(mr, NULL, fw);
++				}
++				iy = MI_Y_OFFSET(mi);
++				ih = MI_HEIGHT(mi) +
++					(MI_IS_SELECTABLE(mi) ?
++					 MST_RELIEF_THICKNESS(mr) : 0);
++				if (iy < 0)
++				{
++					ih += iy;
++					iy = 0;
++				}
++				mw = MR_WIDTH(mr) - 2 * MST_BORDER_WIDTH(mr);
++				if (iy + ih > MR_HEIGHT(mr))
++					ih = MR_HEIGHT(mr) - iy;
++				/* grab image */
++				MR_STORED_ITEM(mr).stored =
++					XCreatePixmap(
++						dpy, Scr.NoFocusWin, mw, ih,
++						Pdepth);
++				XSetGraphicsExposures(
++					dpy,
++					FORE_GC(MST_MENU_INACTIVE_GCS(mr)),
++					True);
++				XSync(dpy, 0);
++				while (FCheckTypedEvent(dpy, NoExpose, &e))
++				{
++					/* nothing to do here */
++				}
++				XCopyArea(
++					dpy, MR_WINDOW(mr),
++					MR_STORED_ITEM(mr).stored,
++					FORE_GC(MST_MENU_INACTIVE_GCS(mr)),
++					MST_BORDER_WIDTH(mr), iy, mw, ih, 0,
++					0);
++				XSync(dpy, 0);
++				if (FCheckTypedEvent(dpy, NoExpose, &e))
++				{
++					MR_STORED_ITEM(mr).y = iy;
++					MR_STORED_ITEM(mr).width = mw;
++					MR_STORED_ITEM(mr).height = ih;
++				}
++				else
++				{
++					XFreePixmap(
++						dpy,
++						MR_STORED_ITEM(mr).stored);
++					MR_STORED_ITEM(mr).stored = None;
++					MR_STORED_ITEM(mr).width = 0;
++					MR_STORED_ITEM(mr).height = 0;
++					MR_STORED_ITEM(mr).y = 0;
++				}
++				XSetGraphicsExposures(
++					dpy,
++					FORE_GC(MST_MENU_INACTIVE_GCS(mr)),
++					False);
++			}
++			else if (select == False &&
++				 MR_STORED_ITEM(mr).width != 0)
++			{
++				/* ungrab image */
++				XCopyArea(
++					dpy, MR_STORED_ITEM(mr).stored,
++					MR_WINDOW(mr),
++					FORE_GC(MST_MENU_INACTIVE_GCS(mr)),
++					0, 0, MR_STORED_ITEM(mr).width,
++					MR_STORED_ITEM(mr).height,
++					MST_BORDER_WIDTH(mr),
++					MR_STORED_ITEM(mr).y);
++
++				if (MR_STORED_ITEM(mr).stored != None)
++				{
++					XFreePixmap(
++						dpy, MR_STORED_ITEM(mr).stored);
++				}
++				MR_STORED_ITEM(mr).stored = None;
++				MR_STORED_ITEM(mr).width = 0;
++				MR_STORED_ITEM(mr).height = 0;
++				MR_STORED_ITEM(mr).y = 0;
++			}
++			else if (select == False)
++			{
++				XEvent e;
++				FvwmPicture *sidePic = NULL;
++
++				e.type = Expose;
++				e.xexpose.x = MST_BORDER_WIDTH(mr);
++				e.xexpose.y = MI_Y_OFFSET(mi);
++				e.xexpose.width = MR_WIDTH(mr) - 2 *
++					MST_BORDER_WIDTH(mr);
++				e.xexpose.height = MI_HEIGHT(mi) +
++					(MI_IS_SELECTABLE(mi) ?
++					 MST_RELIEF_THICKNESS(mr) : 0);
++				if (MR_SIDEPIC(mr))
++				{
++					sidePic = MR_SIDEPIC(mr);
++				}
++				else if (MST_SIDEPIC(mr))
++				{
++					sidePic = MST_SIDEPIC(mr);
++				}
++				if (sidePic)
++				{
++					e.xexpose.width -= sidePic->width;
++					if (MR_SIDEPIC_X_OFFSET(mr) ==
++					    MST_BORDER_WIDTH(mr))
++					{
++						e.xexpose.x += sidePic->width;
++					}
++				}
++				MR_SELECTED_ITEM(mr) = (select) ? mi : NULL;
++				paint_menu(mr, &e, fw);
++			}
++			break;
++		default:
++			if (MR_STORED_ITEM(mr).width != 0)
++			{
++				if (MR_STORED_ITEM(mr).stored != None)
++				{
++					XFreePixmap(
++						dpy,
++						MR_STORED_ITEM(mr).stored);
++				}
++				MR_STORED_ITEM(mr).stored = None;
++				MR_STORED_ITEM(mr).width = 0;
++				MR_STORED_ITEM(mr).height = 0;
++				MR_STORED_ITEM(mr).y = 0;
++			}
++			break;
++		} /* switch */
++	} /* if */
++
++	if (fw && !check_if_fvwm_window_exists(fw))
++	{
++		fw = NULL;
++	}
++	MR_SELECTED_ITEM(mr) = (select) ? mi : NULL;
++	if (MR_IS_PAINTED(mr))
++	{
++		MenuPaintItemParameters mpip;
++
++		get_menu_paint_item_parameters(&mpip, mr, mi, fw, NULL, False);
++		menuitem_paint(mi, &mpip);
++	}
++
++	return;
++}
++
++/* ---------------------------- popping menu up or down -------------------- */
++
++static int get_left_popup_x_position(MenuRoot *mr, MenuRoot *submenu, int x)
++{
++	if (MST_USE_LEFT_SUBMENUS(mr))
++	{
++		return (x - MST_POPUP_OFFSET_ADD(mr) - MR_WIDTH(submenu) +
++			MR_WIDTH(mr) *
++			(100 - MST_POPUP_OFFSET_PERCENT(mr)) / 100);
++	}
++	else
++	{
++		return (x - MR_WIDTH(submenu) + MST_BORDER_WIDTH(mr));
++	}
++}
++
++static int get_right_popup_x_position(MenuRoot *mr, MenuRoot *submenu, int x)
++{
++	if (MST_USE_LEFT_SUBMENUS(mr))
++	{
++		return (x + MR_WIDTH(mr) - MST_BORDER_WIDTH(mr));
++	}
++	else
++	{
++		return (x + MR_WIDTH(mr) * MST_POPUP_OFFSET_PERCENT(mr) / 100 +
++			MST_POPUP_OFFSET_ADD(mr));
++	}
++}
++
++static void get_prefered_popup_position(
++	MenuRoot *mr, MenuRoot *submenu, int *px, int *py,
++	Bool *pprefer_left_submenus)
++{
++	int menu_x, menu_y;
++	MenuItem *mi = NULL;
++
++	if (!menu_get_geometry(
++		    mr, &JunkRoot, &menu_x, &menu_y, &JunkWidth, &JunkHeight,
++		    &JunkBW, &JunkDepth))
++	{
++		*px = 0;
++		*py = 0;
++		*pprefer_left_submenus = False;
++		fvwm_msg(ERR, "get_prefered_popup_position",
++			 "can't get geometry of menu %s", MR_NAME(mr));
++		return;
++	}
++	/* set the direction flag */
++	*pprefer_left_submenus =
++		(MR_HAS_POPPED_UP_LEFT(mr) ||
++		 (MST_USE_LEFT_SUBMENUS(mr) &&
++		  !MR_HAS_POPPED_UP_RIGHT(mr)));
++	/* get the x position */
++	if (*pprefer_left_submenus)
++	{
++		*px = get_left_popup_x_position(mr, submenu, menu_x);
++	}
++	else
++	{
++		*px = get_right_popup_x_position(mr, submenu, menu_x);
++	}
++	/* get the y position */
++	if (MR_SELECTED_ITEM(mr))
++	{
++		mi = MR_SELECTED_ITEM(mr);
++	}
++	if (mi)
++	{
++		*py = menu_y + MI_Y_OFFSET(mi) -
++			MST_BORDER_WIDTH(mr) + MST_RELIEF_THICKNESS(mr);
++	}
++	else
++	{
++		*py = menu_y;
++	}
++}
++
++static int do_menus_overlap(
++	MenuRoot *mr, int x, int y, int width, int height, int h_tolerance,
++	int v_tolerance, int s_tolerance, Bool allow_popup_offset_tolerance)
++{
++	int prior_x, prior_y, x_overlap;
++	int prior_width, prior_height;
++
++	if (mr == NULL)
++	{
++		return 0;
++	}
++	if (!menu_get_geometry(
++		    mr, &JunkRoot,&prior_x,&prior_y, &prior_width,
++		    &prior_height, &JunkBW, &JunkDepth))
++	{
++		return 0;
++	}
++	x_overlap = 0;
++	if (allow_popup_offset_tolerance)
++	{
++		if (MST_POPUP_OFFSET_ADD(mr) < 0)
++		{
++			s_tolerance = -MST_POPUP_OFFSET_ADD(mr);
++		}
++		if (MST_USE_LEFT_SUBMENUS(mr))
++		{
++			prior_x += (100 - MST_POPUP_OFFSET_PERCENT(mr)) / 100;
++		}
++		else
++		{
++			prior_width *=
++				(float)(MST_POPUP_OFFSET_PERCENT(mr)) / 100.0;
++		}
++	}
++	if (MST_USE_LEFT_SUBMENUS(mr))
++	{
++		int t = s_tolerance;
++		s_tolerance = h_tolerance;
++		h_tolerance = t;
++	}
++	if (y < prior_y + prior_height - v_tolerance &&
++	    prior_y < y + height - v_tolerance &&
++	    x < prior_x + prior_width - s_tolerance &&
++	    prior_x < x + width - h_tolerance)
++	{
++		x_overlap = x - prior_x;
++		if (x <= prior_x)
++		{
++			x_overlap--;
++		}
++	}
++
++	return x_overlap;
++}
++
++/*
++ *
++ *  Procedure:
++ *      pop_menu_up - pop up a pull down menu
++ *
++ *  Inputs:
++ *      x, y      - location of upper left of menu
++ *      do_warp_to_item - warp pointer to the first item after title
++ *      pops      - pointer to the menu options for new menu
++ *
++ */
++static int pop_menu_up(
++	MenuRoot **pmenu, MenuParameters *pmp, MenuRoot *parent_menu,
++	MenuItem *parent_item, const exec_context_t **pexc, int x, int y,
++	Bool prefer_left_submenu, Bool do_warp_to_item, MenuOptions *pops,
++	Bool *ret_overlap, Window popdown_window)
++{
++	Bool do_warp_to_title = False;
++	int x_overlap = 0;
++	int x_clipped_overlap;
++	MenuRoot *mrMi;
++	MenuRoot *mr;
++	FvwmWindow *fw;
++	int context;
++	int bw = 0;
++	int bwp = 0;
++	int prev_x;
++	int prev_y;
++	int prev_width;
++	int prev_height;
++	unsigned int event_mask;
++	int scr_x, scr_y;
++	int scr_w, scr_h;
++
++	mr = *pmenu;
++	if (!mr ||
++	    (MR_MAPPED_COPIES(mr) > 0 && MR_COPIES(mr) >= MAX_MENU_COPIES))
++	{
++		return False;
++	}
++
++	/*
++	 * handle dynamic menu actions
++	 */
++
++	/* First of all, execute the popup action (if defined). */
++	if (MR_POPUP_ACTION(mr))
++	{
++		char *menu_name;
++		saved_pos_hints pos_hints;
++		Bool is_busy_grabbed = False;
++		int mapped_copies = MR_MAPPED_COPIES(mr);
++
++		/* save variables that we still need but that may be
++		 * overwritten */
++		menu_name = safestrdup(MR_NAME(mr));
++		pos_hints = last_saved_pos_hints;
++		if (Scr.BusyCursor & BUSY_DYNAMICMENU)
++		{
++			is_busy_grabbed = GrabEm(CRS_WAIT, GRAB_BUSYMENU);
++		}
++		/* Execute the action */
++		__menu_execute_function(pmp->pexc, MR_POPUP_ACTION(mr));
++		if (is_busy_grabbed)
++		{
++			UngrabEm(GRAB_BUSYMENU);
++		}
++		/* restore the stuff we saved */
++		last_saved_pos_hints = pos_hints;
++		if (mapped_copies == 0)
++		{
++			/* Now let's see if the menu still exists. It may have
++			 * been destroyed and recreated, so we have to look for
++			 * a menu with the saved name. menus_find_menu() always
++			 * returns the original menu, not one of its copies, so
++			 * below logic would fail miserably if used with a menu
++			 * copy. On the other hand, menu copies can't be
++			 * deleted within a dynamic popup action, so just
++			 * ignore this case. */
++			*pmenu = menus_find_menu(menu_name);
++			if (menu_name)
++			{
++				free(menu_name);
++			}
++			mr = *pmenu;
++		}
++	}
++	if (mr)
++	{
++		update_menu(mr, pmp);
++	}
++	if (mr == NULL || MR_FIRST_ITEM(mr) == NULL || MR_ITEMS(mr) == 0)
++	{
++		/* The menu deleted itself or all its items or it has been
++		 * empty from the start. */
++		return False;
++	}
++	fw = (*pexc)->w.fw;
++	if (fw && !check_if_fvwm_window_exists(fw))
++	{
++		fw = NULL;
++	}
++	context = (*pexc)->w.wcontext;
++
++	/*
++	 * Create a new menu instance (if necessary)
++	 */
++
++	if (MR_MAPPED_COPIES(mr) > 0)
++	{
++		/* create a new instance of the menu */
++		*pmenu = copy_menu_root(*pmenu);
++		if (!*pmenu)
++		{
++			return False;
++		}
++		make_menu_window(*pmenu, False);
++		mr = *pmenu;
++	}
++
++	/*
++	 * Evaluate position hints
++	 */
++
++	/* calculate position from position hints if available */
++	if (pops->flags.has_poshints &&
++	    !last_saved_pos_hints.flags.do_ignore_pos_hints)
++	{
++		get_xy_from_position_hints(
++			&(pops->pos_hints), MR_WIDTH(mr), MR_HEIGHT(mr),
++			(parent_menu) ? MR_WIDTH(parent_menu) : 0,
++			prefer_left_submenu, &x, &y);
++	}
++
++	/*
++	 * Initialise new menu
++	 */
++
++	MR_PARENT_MENU(mr) = parent_menu;
++	MR_PARENT_ITEM(mr) = parent_item;
++	MR_IS_PAINTED(mr) = 0;
++	MR_IS_LEFT(mr) = 0;
++	MR_IS_RIGHT(mr) = 0;
++	MR_IS_UP(mr) = 0;
++	MR_IS_DOWN(mr) = 0;
++	MR_XANIMATION(mr) = 0;
++	InstallFvwmColormap();
++
++	/*
++	 * Handle popups from button clicks on buttons in the title bar,
++	 * or the title bar itself. Position hints override this.
++	 */
++
++	if (!pops->flags.has_poshints && fw && parent_menu == NULL &&
++	    pmp->flags.is_first_root_menu)
++	{
++		int cx;
++		int cy;
++		int gx;
++		int gy;
++		Bool has_context;
++		rectangle button_g;
++
++		has_context = get_title_button_geometry(
++			fw, &button_g, context);
++		if (has_context)
++		{
++			fscreen_scr_arg fscr;
++
++			get_title_gravity_factors(fw, &gx, &gy);
++			cx = button_g.x + button_g.width / 2;
++			cy = button_g.y + button_g.height / 2;
++			if (gx != 0)
++			{
++				x = button_g.x +
++					(gx == 1) * button_g.width -
++					(gx == -1) * MR_WIDTH(mr);
++			}
++			if (gy != 0)
++			{
++				y = button_g.y +
++					(gy == 1) * button_g.height -
++					(gy == -1) * MR_HEIGHT(mr);
++			}
++			if (gx == 0 && x < button_g.x)
++			{
++				x = button_g.x;
++			}
++			else if (gx == 0 && x + MR_WIDTH(mr) >=
++				 button_g.x + button_g.width)
++			{
++				x = button_g.x + button_g.width - MR_WIDTH(mr);
++			}
++			if (gy == 0 && y < button_g.y)
++			{
++				y = button_g.y;
++			}
++			else if (gy == 0 && y + MR_HEIGHT(mr) >=
++				 button_g.y + button_g.height)
++			{
++				y = button_g.y + button_g.height -
++					MR_HEIGHT(mr);
++			}
++			pops->pos_hints.has_screen_origin = True;
++			fscr.xypos.x = cx;
++			fscr.xypos.y = cy;
++			if (FScreenGetScrRect(
++				    &fscr, FSCREEN_XYPOS, &JunkX, &JunkY,
++				    &JunkWidth, &JunkHeight))
++			{
++				/* use current cx/cy */
++			}
++			else if (FQueryPointer(
++					 dpy, Scr.Root, &JunkRoot, &JunkChild,
++					 &cx, &cy, &JunkX, &JunkY, &JunkMask))
++			{
++				/* use pointer's position */
++			}
++			else
++			{
++				cx = -1;
++				cy = -1;
++			}
++			pops->pos_hints.screen_origin_x = cx;
++			pops->pos_hints.screen_origin_y = cy;
++		}
++	} /* if (pops->flags.has_poshints) */
++
++	/*
++	 * Clip to screen
++	 */
++
++	{
++		fscreen_scr_arg fscr;
++
++		fscr.xypos.x = pops->pos_hints.screen_origin_x;
++		fscr.xypos.y = pops->pos_hints.screen_origin_y;
++		/* clip to screen */
++		FScreenClipToScreen(
++			&fscr, FSCREEN_XYPOS, &x, &y, MR_WIDTH(mr),
++			MR_HEIGHT(mr));
++		/* "this" screen is defined -- so get its coords for future
++		 * reference */
++		FScreenGetScrRect(
++			&fscr, FSCREEN_XYPOS, &scr_x, &scr_y, &scr_w, &scr_h);
++	}
++
++	if (parent_menu)
++	{
++		bw = MST_BORDER_WIDTH(mr);
++		bwp = MST_BORDER_WIDTH(parent_menu);
++		x_overlap = do_menus_overlap(
++			parent_menu, x, y, MR_WIDTH(mr), MR_HEIGHT(mr), bwp,
++			bwp, bwp, True);
++	}
++
++	/*
++	 * Calculate position and animate menus
++	 */
++
++	if (parent_menu == NULL ||
++	    !menu_get_geometry(
++		    parent_menu, &JunkRoot, &prev_x, &prev_y, &prev_width,
++		    &prev_height, &JunkBW, &JunkDepth))
++	{
++		MR_HAS_POPPED_UP_LEFT(mr) = 0;
++		MR_HAS_POPPED_UP_RIGHT(mr) = 0;
++	}
++	else
++	{
++		int left_x;
++		int right_x;
++		Bool use_left_submenus = MST_USE_LEFT_SUBMENUS(mr);
++		MenuRepaintTransparentParameters mrtp;
++		Bool transparent_bg = False;
++
++		/* check if menus overlap */
++		x_clipped_overlap =
++			do_menus_overlap(
++				parent_menu, x, y, MR_WIDTH(mr), MR_HEIGHT(mr),
++				bwp, bwp, bwp, True);
++		if (x_clipped_overlap &&
++		    (!pops->flags.has_poshints ||
++		     pops->pos_hints.is_relative == False ||
++		     x_overlap == 0))
++		{
++			/* menus do overlap, but do not reposition if overlap
++			 * was caused by relative positioning hints */
++			left_x = get_left_popup_x_position(
++				parent_menu, mr, prev_x);
++			right_x = get_right_popup_x_position(
++				parent_menu, mr, prev_x);
++			if (use_left_submenus)
++			{
++				if (left_x + MR_WIDTH(mr) < prev_x + bwp)
++				{
++					left_x = prev_x + bwp - MR_WIDTH(mr);
++				}
++			}
++			else
++			{
++				if (right_x > prev_x + prev_width - bwp)
++				{
++					right_x = prev_x + prev_width - bwp;
++				}
++			}
++
++			/*
++			 * Animate parent menu
++			 */
++
++			if (MST_IS_ANIMATED(mr))
++			{
++				/* animate previous out of the way */
++				int a_left_x;
++				int a_right_x;
++				int end_x;
++				Window w;
++
++				if (use_left_submenus)
++				{
++					if (prev_x - left_x < MR_WIDTH(mr))
++					{
++						a_right_x =
++							x + (prev_x - left_x);
++					}
++					else
++					{
++						a_right_x =
++							x + MR_WIDTH(mr) - bw;
++					}
++					a_left_x = x - MR_WIDTH(parent_menu);
++				}
++				else
++				{
++					if (right_x - prev_x < prev_width)
++					{
++						a_left_x =
++							x + (prev_x - right_x);
++					}
++					else
++					{
++						a_left_x =
++							x - prev_width + bw;
++					}
++					a_right_x = x + MR_WIDTH(mr);
++				}
++				if (prefer_left_submenu)
++				{
++					/* popup menu is left of old menu, try
++					 * to move prior menu right */
++					if (a_right_x + prev_width <=
++					    scr_x + scr_w)
++					{
++						end_x = a_right_x;
++					}
++					else if (a_left_x >= scr_x)
++					{
++						end_x = a_left_x;
++					}
++					else
++					{
++						end_x = scr_x + scr_w -
++							prev_width;
++					}
++				}
++				else
++				{
++					/* popup menu is right of old menu, try
++					 * to move prior menu left */
++					if (a_left_x >= scr_x)
++					{
++						end_x = a_left_x;
++					}
++					else if (a_right_x + prev_width <=
++						 scr_x + scr_w)
++					{
++						end_x = a_right_x;
++					}
++					else
++					{
++						end_x = scr_x;
++					}
++				}
++				if (end_x == a_left_x || end_x == 0)
++				{
++					MR_HAS_POPPED_UP_LEFT(mr) = 0;
++					MR_HAS_POPPED_UP_RIGHT(mr) = 1;
++				}
++				else
++				{
++					MR_HAS_POPPED_UP_LEFT(mr) = 1;
++					MR_HAS_POPPED_UP_RIGHT(mr) = 0;
++				}
++				MR_XANIMATION(parent_menu) += end_x - prev_x;
++				if (ST_HAS_MENU_CSET(MR_STYLE(parent_menu)) &&
++				    CSET_IS_TRANSPARENT(
++					    ST_CSET_MENU(
++						    MR_STYLE(parent_menu))))
++				{
++					transparent_bg = True;
++					get_menu_repaint_transparent_parameters(
++						&mrtp, parent_menu, fw);
++				}
++
++				if (MR_IS_TEAR_OFF_MENU(parent_menu))
++				{
++					int cx;
++					int cy;
++
++					w = FW_W_FRAME(
++						pmp->tear_off_root_menu_window
++						);
++					if (XGetGeometry(
++						    dpy, w, &JunkRoot, &cx,
++						    &cy,
++						    (unsigned int*)&JunkWidth,
++						    (unsigned int*)&JunkHeight,
++						    (unsigned int*)&JunkBW,
++						    (unsigned int*)&JunkDepth))
++					{
++						end_x += (cx - prev_x );
++						prev_x = cx;
++						prev_y = cy;
++					}
++				}
++				else
++				{
++					w = MR_WINDOW(parent_menu);
++				}
++				AnimatedMoveOfWindow(
++					w, prev_x, prev_y, end_x, prev_y, True,
++					-1, NULL,
++					(transparent_bg)? &mrtp:NULL);
++			} /* if (MST_IS_ANIMATED(mr)) */
++
++			/*
++			 * Try the other side of the parent menu
++			 */
++
++			else if (!pops->flags.is_fixed)
++			{
++				Bool may_use_left;
++				Bool may_use_right;
++				Bool do_use_left;
++				Bool use_left_as_last_resort;
++
++				use_left_as_last_resort =
++					(left_x > scr_x + scr_w - right_x -
++					 MR_WIDTH(mr));
++				may_use_left = (left_x >= scr_x);
++				may_use_right = (right_x + MR_WIDTH(mr) <=
++						 scr_x + scr_w);
++				if (!may_use_left && !may_use_right)
++				{
++					/* If everything goes wrong, put the
++					 * submenu on the side with more free
++					 * space. */
++					do_use_left = use_left_as_last_resort;
++				}
++				else if (may_use_left &&
++					 (prefer_left_submenu ||
++					  !may_use_right))
++				{
++					do_use_left = True;
++				}
++				else
++				{
++					do_use_left = False;
++				}
++				x = (do_use_left) ? left_x : right_x;
++				MR_HAS_POPPED_UP_LEFT(mr) = do_use_left;
++				MR_HAS_POPPED_UP_RIGHT(mr) = !do_use_left;
++
++				/* Force the menu onto the screen, but leave at
++				 * least PARENT_MENU_FORCE_VISIBLE_WIDTH pixels
++				 * of the parent menu visible */
++				if (x + MR_WIDTH(mr) > scr_x + scr_w)
++				{
++					int d = x + MR_WIDTH(mr) -
++						(scr_x + scr_w);
++					int c;
++
++					if (prev_width >=
++					    PARENT_MENU_FORCE_VISIBLE_WIDTH)
++					{
++						c = PARENT_MENU_FORCE_VISIBLE_WIDTH +
++							prev_x;
++					}
++					else
++					{
++						c = prev_x + prev_width;
++					}
++
++					if (x - c >= d || x <= prev_x)
++					{
++						x -= d;
++					}
++					else if (x > c)
++					{
++						x = c;
++					}
++				}
++				if (x < scr_x)
++				{
++					int c = prev_width -
++						PARENT_MENU_FORCE_VISIBLE_WIDTH;
++
++					if (c < 0)
++					{
++						c = 0;
++					}
++					if (scr_x - x > c)
++					{
++						x += c;
++					}
++					else
++					{
++						x = scr_x;
++					}
++				}
++			} /* else if (non-overlapping menu style) */
++		} /* if (x_clipped_overlap && ...) */
++		else
++		{
++			MR_HAS_POPPED_UP_LEFT(mr) = prefer_left_submenu;
++			MR_HAS_POPPED_UP_RIGHT(mr) = !prefer_left_submenu;
++		}
++
++		if (x < prev_x)
++		{
++			MR_IS_LEFT(mr) = 1;
++		}
++		if (x + MR_WIDTH(mr) > prev_x + prev_width)
++		{
++			MR_IS_RIGHT(mr) = 1;
++		}
++		if (y < prev_y)
++		{
++			MR_IS_UP(mr) = 1;
++		}
++		if (y + MR_HEIGHT(mr) > prev_y + prev_height)
++		{
++			MR_IS_DOWN(mr) = 1;
++		}
++		if (!MR_IS_LEFT(mr) && !MR_IS_RIGHT(mr))
++		{
++			MR_IS_LEFT(mr) = 1;
++			MR_IS_RIGHT(mr) = 1;
++		}
++	} /* if (parent_menu) */
++
++	/*
++	 * Make sure we have the correct events selected
++	 */
++
++	if (pmp->tear_off_root_menu_window == NULL)
++	{
++		/* normal menus and sub menus */
++		event_mask = XEVMASK_MENUW;
++	}
++	else if (parent_menu == NULL)
++	{
++		/* tear off menu needs more events */
++		event_mask = XEVMASK_TEAR_OFF_MENUW;
++	}
++	else
++	{
++		/* sub menus of tear off menus need LeaveNotify */
++		event_mask = XEVMASK_TEAR_OFF_SUBMENUW;
++	}
++
++	/*
++	 * Pop up the menu
++	 */
++
++	XMoveWindow(dpy, MR_WINDOW(mr), x, y);
++	XSelectInput(dpy, MR_WINDOW(mr), event_mask);
++	XMapRaised(dpy, MR_WINDOW(mr));
++	if (popdown_window)
++		XUnmapWindow(dpy, popdown_window);
++	XFlush(dpy);
++	MR_MAPPED_COPIES(mr)++;
++	MST_USAGE_COUNT(mr)++;
++	if (ret_overlap)
++	{
++		*ret_overlap =
++			do_menus_overlap(
++				parent_menu, x, y, MR_WIDTH(mr), MR_HEIGHT(mr),
++				0, 0, 0, False) ? True : False;
++	}
++
++	/*
++	 * Warp the pointer
++	 */
++
++	if (!do_warp_to_item && parent_menu != NULL)
++	{
++		MenuItem *mi;
++
++		mi = find_entry(pmp, NULL, &mrMi, None, -1, -1);
++		if (mi && mrMi == mr && mi != MR_FIRST_ITEM(mrMi))
++		{
++			/* pointer is on an item of the popup */
++			if (MST_DO_WARP_TO_TITLE(mr))
++			{
++				/* warp pointer if not on a root menu */
++				do_warp_to_title = True;
++			}
++		}
++	} /* if (!do_warp_to_item) */
++
++	if (pops->flags.do_not_warp)
++	{
++		do_warp_to_title = False;
++	}
++	else if (pops->flags.do_warp_title)
++	{
++		do_warp_to_title = True;
++	}
++	if (pops->flags.has_poshints &&
++	    !last_saved_pos_hints.flags.do_ignore_pos_hints &&
++	    pops->flags.do_warp_title)
++	{
++		do_warp_to_title = True;
++	}
++	if (do_warp_to_item)
++	{
++		/* also warp */
++		MR_SELECTED_ITEM(mr) = NULL;
++		warp_pointer_to_item(
++			mr, MR_FIRST_ITEM(mr), True /* skip Title */);
++		select_menu_item(mr, MR_SELECTED_ITEM(mr), True, fw);
++	}
++	else if (do_warp_to_title)
++	{
++		/* Warp pointer to middle of top line, since we don't
++		 * want the user to come up directly on an option */
++		warp_pointer_to_title(mr);
++	}
++
++	return True;
++}
++
++/*
++ *
++ *  Procedure:
++ *      pop_menu_down - unhighlight the current menu selection and
++ *                    take down the menus
++ *
++ *      mr     - menu to pop down; this pointer is invalid after the function
++ *               returns. Don't use it anymore!
++ *      parent - the menu that has spawned mr (may be NULL). this is
++ *               used to see if mr was spawned by itself on some level.
++ *               this is a hack to allow specifying 'Popup foo' within
++ *               menu foo. You must use the MenuRoot that is currently
++ *               being processed here. DO NOT USE MR_PARENT_MENU(mr) here!
++ *
++ */
++static void pop_menu_down(MenuRoot **pmr, MenuParameters *pmp)
++{
++	MenuItem *mi;
++
++	assert(*pmr);
++	memset(&(MR_DYNAMIC_FLAGS(*pmr)), 0, sizeof(MR_DYNAMIC_FLAGS(*pmr)));
++	XUnmapWindow(dpy, MR_WINDOW(*pmr));
++	MR_MAPPED_COPIES(*pmr)--;
++	MST_USAGE_COUNT(*pmr)--;
++	UninstallFvwmColormap();
++	XFlush(dpy);
++	if ((mi = MR_SELECTED_ITEM(*pmr)) != NULL)
++	{
++		select_menu_item(*pmr, mi, False, (*pmp->pexc)->w.fw);
++	}
++	if (MR_STORED_PIXELS(*pmr).d_pixels != NULL)
++	{
++		PictureFreeColors(
++			dpy, Pcmap, MR_STORED_PIXELS(*pmr).d_pixels,
++			MR_STORED_PIXELS(*pmr).d_npixels, 0, False);
++		free(MR_STORED_PIXELS(*pmr).d_pixels);
++		MR_STORED_PIXELS(*pmr).d_pixels = NULL;
++	}
++	if (MR_COPIES(*pmr) > 1)
++	{
++		/* delete this instance of the menu */
++		DestroyMenu(*pmr, False, False);
++	}
++	else if (MR_POPDOWN_ACTION(*pmr))
++	{
++		/* Finally execute the popdown action (if defined). */
++		saved_pos_hints pos_hints;
++
++		/* save variables that we still need but that may be
++		 * overwritten */
++		pos_hints = last_saved_pos_hints;
++		/* Execute the action */
++		__menu_execute_function(pmp->pexc, MR_POPDOWN_ACTION(*pmr));
++		/* restore the stuff we saved */
++		last_saved_pos_hints = pos_hints;
++	}
++
++	return;
++}
++
++/*
++ *
++ *  Procedure:
++ *      pop_menu_down_and_repaint_parent - Pops down a menu and repaints the
++ *      overlapped portions of the parent menu. This is done only if
++ *      *fSubmenuOverlaps is True. *fSubmenuOverlaps is set to False
++ *      afterwards.
++ *
++ */
++static void pop_menu_down_and_repaint_parent(
++	MenuRoot **pmr, Bool *fSubmenuOverlaps, MenuParameters *pmp)
++{
++	MenuRoot *parent = MR_PARENT_MENU(*pmr);
++	Window win;
++	XEvent event;
++	int mr_x;
++	int mr_y;
++	int mr_width;
++	int mr_height;
++	int parent_x;
++	int parent_y;
++	int parent_width;
++	int parent_height;
++
++	if (*fSubmenuOverlaps && parent)
++	{
++		/* popping down the menu may destroy the menu via the dynamic
++		 * popdown action! Thus we must not access *pmr afterwards. */
++		win = MR_WINDOW(*pmr);
++
++		/* Create a fake event to pass into paint_menu */
++		event.type = Expose;
++		if (!menu_get_geometry(
++			    *pmr, &JunkRoot, &mr_x, &mr_y, &mr_width,
++			    &mr_height, &JunkBW, &JunkDepth) ||
++		    !menu_get_geometry(
++			    parent, &JunkRoot, &parent_x, &parent_y,
++			    &parent_width, &parent_height, &JunkBW,
++			    &JunkDepth))
++		{
++			pop_menu_down(pmr, pmp);
++			paint_menu(parent, NULL, (*pmp->pexc)->w.fw);
++		}
++		else
++		{
++			pop_menu_down(pmr, pmp);
++			event.xexpose.x = mr_x - parent_x;
++			event.xexpose.width = mr_width;
++			if (event.xexpose.x < 0)
++			{
++				event.xexpose.width += event.xexpose.x;
++				event.xexpose.x = 0;
++			}
++			if (event.xexpose.x + event.xexpose.width >
++			    parent_width)
++			{
++				event.xexpose.width =
++					parent_width - event.xexpose.x;
++			}
++			event.xexpose.y = mr_y - parent_y;
++			event.xexpose.height = mr_height;
++			if (event.xexpose.y < 0)
++			{
++				event.xexpose.height += event.xexpose.y;
++				event.xexpose.y = 0;
++			}
++			if (event.xexpose.y + event.xexpose.height >
++			    parent_height)
++			{
++				event.xexpose.height =
++					parent_height - event.xexpose.y;
++			}
++			flush_accumulate_expose(MR_WINDOW(parent), &event);
++			paint_menu(parent, &event, (*pmp->pexc)->w.fw);
++		}
++	}
++	else
++	{
++		/* popping down the menu may destroy the menu via the dynamic
++		 * popdown action! Thus we must not access *pmr afterwards. */
++		pop_menu_down(pmr, pmp);
++	}
++	*fSubmenuOverlaps = False;
++
++	return;
++}
++
++/* ---------------------------- menu main loop ------------------------------ */
++
++static void __mloop_init(
++	MenuParameters *pmp, MenuReturn *pmret,
++	mloop_evh_input_t *in, mloop_evh_data_t *med, mloop_static_info_t *msi,
++	MenuOptions *pops)
++{
++	memset(in, 0, sizeof(*in));
++	in->mif.do_force_reposition = 1;
++	memset(med, 0, sizeof(*med));
++	msi->t0 = fev_get_evtime();
++	pmret->rc = MENU_NOP;
++	memset(pops, 0, sizeof(*pops));
++	/* remember where the pointer was so we can tell if it has moved */
++	if (FQueryPointer(
++		    dpy, Scr.Root, &JunkRoot, &JunkChild, &(msi->x_init),
++		    &(msi->y_init), &JunkX, &JunkY, &JunkMask) == False)
++	{
++		/* pointer is on a different screen */
++		msi->x_init = 0;
++		msi->y_init = 0;
++	}
++	/* get the event mask right */
++	msi->event_mask = (pmp->tear_off_root_menu_window == NULL) ?
++		XEVMASK_MENU : XEVMASK_TEAR_OFF_MENU;
++
++	return;
++}
++
++static void __mloop_get_event_timeout_loop(
++	MenuParameters *pmp,
++	mloop_evh_input_t *in, mloop_evh_data_t *med, mloop_static_info_t *msi)
++{
++	XEvent e = *(*pmp->pexc)->x.elast;
++
++	while (!FPending(dpy) || !FCheckMaskEvent(dpy, msi->event_mask, &e))
++	{
++		Bool is_popup_timed_out =
++			(MST_POPUP_DELAY(pmp->menu) > 0 &&
++			 med->popup_delay_10ms++ >=
++			 MST_POPUP_DELAY(pmp->menu) + 1);
++		Bool is_popdown_timed_out =
++			(MST_POPDOWN_DELAY(pmp->menu) > 0 && in->mrPopdown &&
++			 med->popdown_delay_10ms++ >=
++			 MST_POPDOWN_DELAY(pmp->menu) + 1);
++		Bool do_fake_motion = False;
++
++		if (is_popup_timed_out)
++		{
++			med->popup_delay_10ms = MST_POPUP_DELAY(pmp->menu);
++		}
++		if (is_popdown_timed_out)
++		{
++			med->popdown_delay_10ms = MST_POPDOWN_DELAY(pmp->menu);
++		}
++		if (
++			in->mif.do_force_popup ||
++			(is_popup_timed_out &&
++			 (is_popdown_timed_out ||
++			  in->mif.is_item_entered_by_key_press ||
++			  !in->mrPopdown ||
++			  MST_DO_POPDOWN_IMMEDIATELY(pmp->menu))))
++		{
++			in->mif.do_popup_now = True;
++			in->mif.do_force_popup = False;
++			do_fake_motion = True;
++			in->mif.is_popped_up_by_timeout = True;
++			is_popdown_timed_out = True;
++		}
++		if ((in->mrPopdown || in->mrPopup) &&
++		    (is_popdown_timed_out ||
++		     MST_DO_POPDOWN_IMMEDIATELY(pmp->menu)))
++		{
++			MenuRoot *m = (in->mrPopdown) ?
++				in->mrPopdown : in->mrPopup;
++
++			if (!m || med->mi != MR_PARENT_ITEM(m))
++			{
++				in->mif.do_popdown_now = True;
++				do_fake_motion = True;
++				if (MST_DO_POPUP_IMMEDIATELY(pmp->menu))
++				{
++					in->mif.do_popup_now = True;
++					in->mif.is_popped_up_by_timeout = True;
++				}
++				else if (
++					!MST_DO_POPUP_IMMEDIATELY(pmp->menu) &&
++					in->mif.is_pointer_in_active_item_area)
++				{
++					in->mif.do_popup_now = True;
++					in->mif.is_popped_up_by_timeout = True;
++				}
++				else if (
++					!MST_DO_POPUP_IMMEDIATELY(pmp->menu) &&
++					!MST_DO_POPDOWN_IMMEDIATELY(pmp->menu)
++					&& MST_POPUP_DELAY(pmp->menu) <=
++					MST_POPDOWN_DELAY(pmp->menu) &&
++					med->popup_delay_10ms ==
++					med->popdown_delay_10ms)
++				{
++					in->mif.do_popup_now = True;
++					in->mif.is_popped_up_by_timeout = True;
++				}
++			}
++		}
++		if (in->mif.do_popup_now && med->mi == in->miRemovedSubmenu &&
++		    !in->mif.is_key_press)
++		{
++			/* prevent popping up the menu again with
++			 * RemoveSubemenus */
++			in->mif.do_popup_now = False;
++			in->mif.do_force_popup = False;
++			do_fake_motion = in->mif.do_popdown_now;
++			in->mif.is_popped_up_by_timeout = False;
++		}
++
++		if (do_fake_motion)
++		{
++			/* fake a motion event, and set in->mif.do_popup_now */
++			e.type = MotionNotify;
++			e.xmotion.time = fev_get_evtime();
++			fev_fake_event(&e);
++			in->mif.is_motion_faked = True;
++			break;
++		}
++		usleep(10000 /* 10 ms*/);
++	}
++
++	return;
++}
++
++static mloop_ret_code_t __mloop_get_event(
++	MenuParameters *pmp, MenuReturn *pmret,
++	mloop_evh_input_t *in, mloop_evh_data_t *med, mloop_static_info_t *msi)
++{
++	XEvent e = *(*pmp->pexc)->x.elast;
++
++	in->mif.do_popup_and_warp = False;
++	in->mif.do_popup_now = False;
++	in->mif.do_popdown_now = False;
++	in->mif.do_propagate_event_into_submenu = False;
++	in->mif.is_key_press = False;
++	in->mif.is_button_release = 0;
++	if (pmp->event_propagate_to_submenu)
++	{
++		/* handle an event that was passed in from the parent menu */
++		fev_fake_event(pmp->event_propagate_to_submenu);
++		pmp->event_propagate_to_submenu = NULL;
++	}
++	else if (in->mif.do_recycle_event)
++	{
++		in->mif.is_popped_up_by_timeout = False;
++		in->mif.do_recycle_event = 0;
++		if (pmp->menu != pmret->target_menu)
++		{
++			/* the event is for a previous menu, just close this
++			 * one */
++			pmret->rc = MENU_PROPAGATE_EVENT;
++			return MENU_MLOOP_RET_END;
++		}
++		if ((*pmp->pexc)->x.elast->type == KeyPress)
++		{
++			/* since the pointer has been warped since the key was
++			 * pressed, fake a different key press position */
++			if (FQueryPointer(
++				    dpy, Scr.Root, &JunkRoot, &JunkChild,
++				    &e.xkey.x_root, &e.xkey.y_root,
++				    &JunkX, &JunkY, &e.xkey.state) == False)
++			{
++				/* pointer is on a different screen */
++				e.xkey.x_root = 0;
++				e.xkey.y_root = 0;
++			}
++			fev_fake_event(&e);
++			med->mi = MR_SELECTED_ITEM(pmp->menu);
++		}
++	}
++	else if (pmp->tear_off_root_menu_window != NULL &&
++		 FCheckTypedWindowEvent(
++			 dpy, FW_W_PARENT(pmp->tear_off_root_menu_window),
++			 ClientMessage, &e))
++	{
++		/* Got a ClientMessage for the tear out menu */
++	}
++	else
++	{
++		if (in->mif.do_force_reposition)
++		{
++			e.type = MotionNotify;
++			e.xmotion.time = fev_get_evtime();
++			in->mif.is_motion_faked = True;
++			in->mif.do_force_reposition = False;
++			in->mif.is_popped_up_by_timeout = False;
++			fev_fake_event(&e);
++		}
++		else if (!FCheckMaskEvent(dpy, ExposureMask, &e))
++		{
++			Bool is_popdown_timer_active = False;
++			Bool is_popup_timer_active = False;
++
++			if (MST_POPDOWN_DELAY(pmp->menu) > 0 &&
++			    in->mi_with_popup != NULL &&
++			    in->mi_with_popup != MR_SELECTED_ITEM(pmp->menu))
++			{
++				is_popdown_timer_active = True;
++			}
++			if (MST_POPUP_DELAY(pmp->menu) > 0 &&
++			    !in->mif.is_popped_up_by_timeout &&
++			    in->mi_wants_popup != NULL)
++			{
++				is_popup_timer_active = True;
++			}
++			/* handle exposure events first */
++			if (in->mif.do_force_popup ||
++			    in->mif.is_pointer_in_active_item_area ||
++			    is_popdown_timer_active || is_popup_timer_active)
++			{
++				__mloop_get_event_timeout_loop(
++					pmp, in, med, msi);
++			}
++			else
++			{
++				/* block until there is an event */
++				FMaskEvent(dpy, msi->event_mask, &e);
++				in->mif.is_popped_up_by_timeout = False;
++			}
++		}
++		else
++		{
++			in->mif.is_popped_up_by_timeout = False;
++		}
++	}
++
++	in->mif.is_pointer_in_active_item_area = False;
++	if (e.type == MotionNotify)
++	{
++		/* discard any extra motion events before a release */
++		while (FCheckMaskEvent(
++			       dpy, ButtonMotionMask | ButtonReleaseMask,
++			       &e) && (e.type != ButtonRelease))
++		{
++			/* nothing */
++		}
++	}
++
++	return MENU_MLOOP_RET_NORMAL;
++}
++
++static mloop_ret_code_t __mloop_handle_event(
++	MenuParameters *pmp, MenuReturn *pmret, double_keypress *pdkp,
++	mloop_evh_input_t *in, mloop_evh_data_t *med, mloop_static_info_t *msi)
++{
++	MenuRoot *tmrMi;
++	Bool rc;
++
++	pmret->rc = MENU_NOP;
++	switch ((*pmp->pexc)->x.elast->type)
++	{
++	case ButtonRelease:
++		in->mif.is_button_release = 1;
++		med->mi = find_entry(
++			pmp, &med->x_offset, &med->mrMi,
++			(*pmp->pexc)->x.elast->xbutton.subwindow,
++			(*pmp->pexc)->x.elast->xbutton.x_root,
++			(*pmp->pexc)->x.elast->xbutton.y_root);
++		/* hold the menu up when the button is released
++		 * for the first time if released OFF of the menu */
++		if (pmp->flags.is_sticky && !in->mif.is_motion_first)
++		{
++			in->mif.is_release_first = True;
++			pmp->flags.is_sticky = False;
++			return MENU_MLOOP_RET_LOOP;
++		}
++		if (med->mrMi != NULL)
++		{
++			int menu_x;
++			int menu_y;
++
++			menu_shortcuts(
++				med->mrMi, pmp, pmret, (*pmp->pexc)->x.elast,
++				&med->mi, pdkp, &menu_x, &menu_y);
++			if (pmret->rc == MENU_NEWITEM_MOVEMENU)
++			{
++				move_any_menu(med->mrMi, pmp, menu_x, menu_y);
++				pmret->rc = MENU_NEWITEM;
++			}
++			else if (pmret->rc == MENU_NEWITEM_FIND)
++			{
++				med->mi = find_entry(
++					pmp, NULL, NULL, None, -1, -1);
++				pmret->rc = MENU_NEWITEM;
++			}
++		}
++		else
++		{
++			pmret->rc = MENU_SELECTED;
++		}
++		switch (pmret->rc)
++		{
++		case MENU_NOP:
++			return MENU_MLOOP_RET_LOOP;
++		case MENU_POPDOWN:
++		case MENU_ABORTED:
++		case MENU_DOUBLE_CLICKED:
++		case MENU_TEAR_OFF:
++		case MENU_KILL_TEAR_OFF_MENU:
++			return MENU_MLOOP_RET_END;
++		case MENU_POPUP:
++			/* Allow for MoveLeft/MoveRight action to work with
++			 * Mouse */
++			in->mif.do_popup_and_warp = True;
++		case MENU_NEWITEM:
++			/* unpost the menu if posted */
++			pmret->flags.is_menu_posted = 0;
++			return MENU_MLOOP_RET_NORMAL;
++		case MENU_SELECTED:
++			in->mif.was_item_unposted = 0;
++			if (pmret->flags.is_menu_posted &&
++			    med->mrMi != NULL)
++			{
++				if (pmret->flags.do_unpost_submenu)
++				{
++					pmret->flags.do_unpost_submenu = 0;
++					pmret->flags.is_menu_posted = 0;
++					/* just ignore the event */
++					return MENU_MLOOP_RET_LOOP;
++				}
++				else if (med->mi && MI_IS_POPUP(med->mi)
++					 && med->mrMi == pmp->menu)
++				{
++					/* post menu - done below */
++				}
++				else if (MR_PARENT_ITEM(pmp->menu) &&
++					 med->mi == MR_PARENT_ITEM(pmp->menu))
++				{
++					/* propagate back to parent menu
++					 * and unpost current menu */
++					pmret->flags.do_unpost_submenu = 1;
++					pmret->rc = MENU_PROPAGATE_EVENT;
++					pmret->target_menu = med->mrMi;
++					return MENU_MLOOP_RET_END;
++				}
++				else if (med->mrMi != pmp->menu &&
++					 med->mrMi != in->mrPopup)
++				{
++					/* unpost and propagate back to
++					 * ancestor */
++					pmret->flags.is_menu_posted = 0;
++					pmret->rc = MENU_PROPAGATE_EVENT;
++					pmret->target_menu = med->mrMi;
++					return MENU_MLOOP_RET_END;
++				}
++				else if (in->mrPopup && med->mrMi ==
++					 in->mrPopup)
++				{
++					/* unpost and propagate into
++					 * submenu */
++					in->mif.was_item_unposted = 1;
++					in->mif.do_propagate_event_into_submenu
++						= True;
++					break;
++				}
++				else
++				{
++					/* simply unpost the menu */
++					pmret->flags.is_menu_posted = 0;
++				}
++			}
++			if (is_double_click(
++				    msi->t0, med->mi, pmp, pmret, pdkp,
++				    in->mif.has_mouse_moved))
++			{
++				pmret->rc = MENU_DOUBLE_CLICKED;
++				return MENU_MLOOP_RET_END;
++			}
++			if (med->mi == NULL)
++			{
++				pmret->rc = MENU_ABORTED;
++			}
++			else if (MI_IS_POPUP(med->mi))
++			{
++				switch (MST_DO_POPUP_AS(pmp->menu))
++				{
++				case MDP_POST_MENU:
++					if (in->mif.was_item_unposted)
++					{
++						pmret->flags.is_menu_posted =
++							0;
++						pmret->rc = MENU_UNPOST;
++						pmret->target_menu = NULL;
++						in->mif.do_popup_now = False;
++					}
++					else
++					{
++						pmret->flags.is_menu_posted =
++							1;
++						pmret->rc = MENU_POST;
++						pmret->target_menu = NULL;
++						in->mif.do_popup_now = True;
++						if ((in->mrPopup ||
++						     in->mrPopdown)
++						    && med->mi !=
++						    MR_SELECTED_ITEM(
++							    pmp->menu))
++						{
++							in->mif.do_popdown_now
++								= True;
++						}
++					}
++					return MENU_MLOOP_RET_NORMAL;
++				case MDP_IGNORE:
++					pmret->rc = MENU_NOP;
++					return MENU_MLOOP_RET_NORMAL;
++				case MDP_CLOSE:
++					pmret->rc = MENU_ABORTED;
++					break;
++				case MDP_ROOT_MENU:
++				default:
++					break;
++				}
++			}
++			break;
++		default:
++			break;
++		}
++
++		pdkp->timestamp = 0;
++		return MENU_MLOOP_RET_END;
++
++	case ButtonPress:
++		/* if the first event is a button press allow the release to
++		 * select something */
++		pmp->flags.is_sticky = False;
++		return MENU_MLOOP_RET_LOOP;
++
++	case VisibilityNotify:
++		return MENU_MLOOP_RET_LOOP;
++
++	case KeyRelease:
++		if ((*pmp->pexc)->x.elast->xkey.keycode !=
++		    MST_SELECT_ON_RELEASE_KEY(pmp->menu))
++		{
++			return MENU_MLOOP_RET_LOOP;
++		}
++		/* fall through to KeyPress */
++
++	case KeyPress:
++		/* Handle a key press events to allow mouseless operation */
++		in->mif.is_key_press = True;
++		med->x_offset = menudim_middle_x_offset(&MR_DIM(pmp->menu));
++
++		/* if there is a posted menu we may have to move back into a
++		 * previous menu or possibly ignore the mouse position */
++		if (pmret->flags.is_menu_posted)
++		{
++			MenuItem *l_mi;
++			MenuRoot *l_mrMi;
++			int l_x_offset;
++			XEvent e;
++
++			pmret->flags.is_menu_posted = 0;
++			l_mi = find_entry(
++				pmp, &l_x_offset, &l_mrMi, None, -1, -1);
++			if (l_mrMi != NULL)
++			{
++				if (pmp->menu != l_mrMi)
++				{
++					/* unpost the menu and propagate the
++					 * event to the correct menu */
++					pmret->rc = MENU_PROPAGATE_EVENT;
++					pmret->target_menu = l_mrMi;
++					return MENU_MLOOP_RET_END;
++				}
++			}
++			med->mi = MR_SELECTED_ITEM(pmp->menu);
++			e = *(*pmp->pexc)->x.elast;
++			e.xkey.x_root = med->x_offset;
++			e.xkey.y_root = menuitem_middle_y_offset(
++				med->mi, MR_STYLE(pmp->menu));
++			fev_fake_event(&e);
++		}
++
++		/* now handle the actual key press */
++		{
++			int menu_x;
++			int menu_y;
++
++			menu_shortcuts(
++				pmp->menu, pmp, pmret, (*pmp->pexc)->x.elast,
++				&med->mi, pdkp, &menu_x, &menu_y);
++			if (pmret->rc == MENU_NEWITEM_MOVEMENU)
++			{
++				move_any_menu(pmp->menu, pmp, menu_x, menu_y);
++				pmret->rc = MENU_NEWITEM;
++			}
++			else if (pmret->rc == MENU_NEWITEM_FIND)
++			{
++				med->mi = find_entry(
++					pmp, NULL, NULL, None, -1, -1);
++				pmret->rc = MENU_NEWITEM;
++			}
++		}
++		if (pmret->rc != MENU_NOP)
++		{
++			/* using a key 'unposts' the posted menu */
++			pmret->flags.is_menu_posted = 0;
++		}
++		switch (pmret->rc)
++		{
++		case MENU_SELECTED:
++			if (med->mi && MI_IS_POPUP(med->mi))
++			{
++				switch (MST_DO_POPUP_AS(pmp->menu))
++				{
++				case MDP_POST_MENU:
++					pmret->rc = MENU_POPUP;
++					break;
++				case MDP_IGNORE:
++					pmret->rc = MENU_NOP;
++					return MENU_MLOOP_RET_NORMAL;
++				case MDP_CLOSE:
++					pmret->rc = MENU_ABORTED;
++					return MENU_MLOOP_RET_END;
++				case MDP_ROOT_MENU:
++				default:
++					return MENU_MLOOP_RET_END;
++				}
++				break;
++			}
++			return MENU_MLOOP_RET_END;
++		case MENU_POPDOWN:
++		case MENU_ABORTED:
++		case MENU_DOUBLE_CLICKED:
++		case MENU_TEAR_OFF:
++		case MENU_KILL_TEAR_OFF_MENU:
++			return MENU_MLOOP_RET_END;
++		case MENU_NEWITEM:
++		case MENU_POPUP:
++			if (med->mrMi == NULL)
++			{
++				/* Set the MenuRoot of the current item in case
++				 * we have just warped to the menu from the
++				 * void or unposted a popup menu. */
++				med->mrMi = pmp->menu;
++			}
++			/*tmrMi = med->mrMi;*/
++			break;
++		default:
++			break;
++		}
++		/* now warp to the new menu item, if any */
++		if (pmret->rc == MENU_NEWITEM && med->mi)
++		{
++			warp_pointer_to_item(med->mrMi, med->mi, False);
++		}
++		if (pmret->rc == MENU_POPUP && med->mi && MI_IS_POPUP(med->mi))
++		{
++			in->mif.do_popup_and_warp = True;
++			break;
++		}
++		break;
++
++	case MotionNotify:
++	{
++		int p_rx = -1;
++		int p_ry = -1;
++		Window p_child = None;
++
++		if (in->mif.has_mouse_moved == False)
++		{
++			if (FQueryPointer(
++				    dpy, Scr.Root, &JunkRoot, &p_child, &p_rx,
++				    &p_ry, &JunkX, &JunkY, &JunkMask) == False)
++			{
++				/* pointer is on a different screen */
++				p_rx = 0;
++				p_ry = 0;
++			}
++			if (p_rx - msi->x_init > Scr.MoveThreshold ||
++			    msi->x_init - p_rx > Scr.MoveThreshold ||
++			    p_ry - msi->y_init > Scr.MoveThreshold ||
++			    msi->y_init - p_ry > Scr.MoveThreshold)
++			{
++				/* remember that this isn't just a click any
++				 * more since the pointer moved */
++				in->mif.has_mouse_moved = True;
++			}
++		}
++		med->mi = find_entry(
++			pmp, &med->x_offset, &med->mrMi, p_child, p_rx, p_ry);
++		if (pmret->flags.is_menu_posted &&
++		    med->mrMi != pmret->target_menu)
++		{
++			/* ignore mouse movement outside a posted menu */
++			med->mrMi = NULL;
++			med->mi = NULL;
++		}
++		if (!in->mif.is_release_first && !in->mif.is_motion_faked &&
++		    in->mif.has_mouse_moved)
++		{
++			in->mif.is_motion_first = True;
++		}
++		in->mif.is_motion_faked = False;
++		break;
++	}
++
++	case Expose:
++		/* grab our expose events, let the rest go through */
++		XFlush(dpy);
++		rc = menu_expose((*pmp->pexc)->x.elast, (*pmp->pexc)->w.fw);
++		/* we want to dispatch this too so that icons and maybe tear
++		 * off get redrawn after being obscured by menus. */
++		if (rc == False)
++		{
++			dispatch_event((*pmp->pexc)->x.elast);
++		}
++		return MENU_MLOOP_RET_LOOP;
++
++	case ClientMessage:
++		if ((*pmp->pexc)->x.elast->xclient.format == 32 &&
++		    (*pmp->pexc)->x.elast->xclient.data.l[0] ==
++		    _XA_WM_DELETE_WINDOW &&
++		    pmp->tear_off_root_menu_window != NULL &&
++		    (*pmp->pexc)->x.elast->xclient.window == FW_W_PARENT(
++			    pmp->tear_off_root_menu_window))
++		{
++			/* handle deletion of tear out menus */
++			pmret->rc = MENU_KILL_TEAR_OFF_MENU;
++			return MENU_MLOOP_RET_END;
++		}
++		break;
++
++	case EnterNotify:
++		/* ignore EnterNotify events */
++		break;
++
++	case LeaveNotify:
++		if (pmp->tear_off_root_menu_window != NULL &&
++		    find_entry(pmp, NULL, &tmrMi, None, -1, -1) == NULL &&
++		    tmrMi == NULL)
++		{
++			/* handle deletion of tear out menus */
++			pmret->rc = MENU_ABORTED;
++			return MENU_MLOOP_RET_END;
++		}
++		/* ignore it */
++		return MENU_MLOOP_RET_LOOP;
++
++	case UnmapNotify:
++		/* should never happen, but does not hurt */
++		if (pmp->tear_off_root_menu_window != NULL &&
++		    (*pmp->pexc)->x.elast->xunmap.window ==
++		    FW_W(pmp->tear_off_root_menu_window))
++		{
++			/* handle deletion of tear out menus */
++			pmret->rc = MENU_KILL_TEAR_OFF_MENU;
++			/* extra safety: pass event back to main event loop to
++			 * make sure the window is destroyed */
++			FPutBackEvent(dpy, (*pmp->pexc)->x.elast);
++			return MENU_MLOOP_RET_END;
++		}
++		break;
++
++	default:
++		/* We must not dispatch events here.  There is no guarantee
++		 * that dispatch_event doesn't destroy a window stored in the
++		 * menu structures.  Anyway, no events should ever get here
++		 * except to tear off menus and these must be handled
++		 * individually. */
++#if 0
++		dispatch_event((*pmp->pexc)->x.elast);
++#endif
++		break;
++	}
++
++	return MENU_MLOOP_RET_NORMAL;
++}
++
++static void __mloop_select_item(
++	MenuParameters *pmp, mloop_evh_input_t *in, mloop_evh_data_t *med,
++	Bool does_submenu_overlap, Bool *pdoes_popdown_submenu_overlap)
++{
++	in->mif.is_item_entered_by_key_press = in->mif.is_key_press;
++	med->popup_delay_10ms = 0;
++	/* we're on the same menu, but a different item, so we need to unselect
++	 * the old item */
++	if (MR_SELECTED_ITEM(pmp->menu))
++	{
++		/* something else was already selected on this menu.  We have
++		 * to pop down the menu before unselecting the item in case we
++		 * are using gradient menus. The recalled image would paint
++		 * over the submenu. */
++		if (in->mrPopup && in->mrPopup != in->mrPopdown)
++		{
++			in->mrPopdown = in->mrPopup;
++			med->popdown_delay_10ms = 0;
++			*pdoes_popdown_submenu_overlap = does_submenu_overlap;
++			in->mrPopup = NULL;
++		}
++		select_menu_item(
++			pmp->menu, MR_SELECTED_ITEM(pmp->menu), False,
++			(*pmp->pexc)->w.fw);
++	}
++	/* highlight the new item; sets MR_SELECTED_ITEM(pmp->menu) too */
++	select_menu_item(pmp->menu, med->mi, True, (*pmp->pexc)->w.fw);
++
++	return;
++}
++
++static void __mloop_wants_popup(
++	MenuParameters *pmp, mloop_evh_input_t *in, mloop_evh_data_t *med,
++	MenuRoot *mrMiPopup)
++{
++	Bool do_it_now = False;
++
++	in->mi_wants_popup = med->mi;
++	if (in->mif.do_popup_now)
++	{
++		do_it_now = True;
++	}
++	else if (MST_DO_POPUP_IMMEDIATELY(pmp->menu) &&
++		 med->mi != in->miRemovedSubmenu)
++	{
++		if (in->mif.is_key_press ||
++		    MST_DO_POPDOWN_IMMEDIATELY(pmp->menu) || !in->mrPopdown)
++		{
++			do_it_now = True;
++		}
++	}
++	else if (pointer_in_active_item_area(med->x_offset, med->mrMi))
++	{
++		if (in->mif.is_key_press || med->mi == in->miRemovedSubmenu ||
++		    MST_DO_POPDOWN_IMMEDIATELY(pmp->menu) || !in->mrPopdown)
++		{
++			do_it_now = True;
++		}
++		else
++		{
++			in->mif.is_pointer_in_active_item_area = 1;
++		}
++	}
++	if (do_it_now)
++	{
++		in->miRemovedSubmenu = NULL;
++		/* must create a new menu or popup */
++		if (in->mrPopup == NULL || in->mrPopup != mrMiPopup)
++		{
++			if (in->mif.do_popup_now)
++			{
++				in->mif.do_popup = True;
++			}
++			else
++			{
++				/* pop up in next pass through loop */
++				in->mif.do_force_popup = True;
++			}
++		}
++		else if (in->mif.do_popup_and_warp)
++		{
++			warp_pointer_to_item(
++				in->mrPopup, MR_FIRST_ITEM(in->mrPopup), True);
++		}
++	}
++
++	return;
++}
++
++static mloop_ret_code_t __mloop_make_popup(
++	MenuParameters *pmp, MenuReturn *pmret,
++	mloop_evh_input_t *in, mloop_evh_data_t *med,
++	MenuOptions *pops, Bool *pdoes_submenu_overlap)
++{
++	/* create a popup menu */
++	if (!is_submenu_mapped(pmp->menu, med->mi))
++	{
++		/* We want to pop prepop menus so it doesn't *have* to be
++		   unpopped; do_menu pops down any menus it pops up, but we
++		   want to be able to popdown w/o actually removing the menu */
++		int x;
++		int y;
++		Bool prefer_left_submenus;
++
++		/* Make sure we are using the latest style and menu layout. */
++		update_menu(in->mrPopup, pmp);
++
++		get_prefered_popup_position(
++			pmp->menu, in->mrPopup, &x, &y, &prefer_left_submenus);
++		/* Note that we don't care if popping up the menu works. If it
++		 * doesn't we'll catch it below. */
++		pop_menu_up(
++			&in->mrPopup, pmp, pmp->menu, med->mi, pmp->pexc, x, y,
++			prefer_left_submenus, in->mif.do_popup_and_warp, pops,
++			pdoes_submenu_overlap,
++			(in->mrPopdown) ? MR_WINDOW(in->mrPopdown) : None);
++		in->mi_with_popup = med->mi;
++		in->mi_wants_popup = NULL;
++		if (in->mrPopup == NULL)
++		{
++			/* the menu deleted itself when execution the dynamic
++			 * popup * action */
++			pmret->rc = MENU_ERROR;
++			return MENU_MLOOP_RET_END;
++		}
++		MR_SUBMENU_ITEM(pmp->menu) = med->mi;
++	}
++
++	return MENU_MLOOP_RET_NORMAL;
++}
++
++static mloop_ret_code_t __mloop_get_mi_actions(
++	MenuParameters *pmp, MenuReturn *pmret, double_keypress *pdkp,
++	mloop_evh_input_t *in, mloop_evh_data_t *med, mloop_static_info_t *msi,
++	MenuRoot *mrMiPopup, Bool *pdoes_submenu_overlap,
++	Bool *pdoes_popdown_submenu_overlap)
++{
++	in->mif.do_popdown = False;
++	in->mif.do_popup = False;
++	in->mif.do_menu = False;
++	in->mif.is_submenu_mapped = False;
++	if (!in->mrPopup && in->mrPopdown &&
++	    med->mi == MR_PARENT_ITEM(in->mrPopdown))
++	{
++		/* We're again on the item that we left before.
++		 * Deschedule popping it down. */
++		in->mrPopup = in->mrPopdown;
++		in->mrPopdown = NULL;
++	}
++	if (med->mrMi == in->mrPopup)
++	{
++		/* must make current popup menu a real menu */
++		in->mif.do_menu = True;
++		in->mif.is_submenu_mapped = True;
++	}
++	else if (pmret->rc == MENU_POST)
++	{
++		/* must create a real menu and warp into it */
++		if (in->mrPopup == NULL || in->mrPopup != mrMiPopup)
++		{
++			in->mif.do_popup = True;
++		}
++		in->mif.do_menu = True;
++		in->mif.is_submenu_mapped = True;
++	}
++	else if (in->mif.do_popup_and_warp)
++	{
++		/* must create a real menu and warp into it */
++		if (in->mrPopup == NULL || in->mrPopup != mrMiPopup)
++		{
++			in->mif.do_popup = True;
++		}
++		else
++		{
++			XRaiseWindow(dpy, MR_WINDOW(in->mrPopup));
++			warp_pointer_to_item(
++				in->mrPopup, MR_FIRST_ITEM(in->mrPopup), True);
++			in->mif.do_menu = True;
++			in->mif.is_submenu_mapped = True;
++		}
++	}
++	else if (med->mi && MI_IS_POPUP(med->mi))
++	{
++		if ((*pmp->pexc)->x.elast->type == ButtonPress &&
++		    is_double_click(
++			    msi->t0, med->mi, pmp, pmret, pdkp,
++			    in->mif.has_mouse_moved))
++		{
++			pmret->rc = MENU_DOUBLE_CLICKED;
++			return MENU_MLOOP_RET_END;
++		}
++		else if (!in->mrPopup || in->mrPopup != mrMiPopup ||
++			 in->mif.do_popup_and_warp)
++		{
++			__mloop_wants_popup(pmp, in, med, mrMiPopup);
++		}
++	}
++	if (in->mif.do_popdown_now)
++	{
++		in->mif.do_popdown = True;
++		in->mif.do_popdown_now = False;
++	}
++	else if (in->mif.do_popup)
++	{
++		if (in->mrPopup && in->mrPopup != mrMiPopup)
++		{
++			in->mif.do_popdown = True;
++			in->mrPopdown = in->mrPopup;
++			med->popdown_delay_10ms = 0;
++			*pdoes_popdown_submenu_overlap =
++				*pdoes_submenu_overlap;
++		}
++		else if (in->mrPopdown && in->mrPopdown != mrMiPopup)
++		{
++			in->mif.do_popdown = True;
++		}
++		else if (in->mrPopdown && in->mrPopdown == mrMiPopup)
++		{
++			in->mrPopup = in->mrPopdown;
++			*pdoes_submenu_overlap =
++				*pdoes_popdown_submenu_overlap;
++			in->mrPopdown = NULL;
++			in->mif.do_popup = False;
++			in->mif.do_popdown = False;
++		}
++	}
++
++	return MENU_MLOOP_RET_NORMAL;
++}
++
++static void __mloop_do_popdown(
++	MenuParameters *pmp, mloop_evh_input_t *in,
++	Bool *pdoes_popdown_submenu_overlap)
++{
++	if (in->mrPopdown)
++	{
++		pop_menu_down_and_repaint_parent(
++			&in->mrPopdown, pdoes_popdown_submenu_overlap, pmp);
++		in->mi_with_popup = NULL;
++		MR_SUBMENU_ITEM(pmp->menu) = NULL;
++		if (in->mrPopup == in->mrPopdown)
++		{
++			in->mrPopup = NULL;
++		}
++		in->mrPopdown = NULL;
++	}
++	in->mif.do_popdown = False;
++
++	return;
++}
++
++static mloop_ret_code_t __mloop_do_popup(
++	MenuParameters *pmp, MenuReturn *pmret,
++	mloop_evh_input_t *in, mloop_evh_data_t *med,
++	MenuOptions *pops, MenuRoot *mrMiPopup, Bool *pdoes_submenu_overlap,
++	Bool *pdoes_popdown_submenu_overlap)
++{
++	if (!MR_IS_PAINTED(pmp->menu))
++	{
++		/* draw the parent menu if it is not already drawn */
++		flush_expose(MR_WINDOW(pmp->menu));
++		paint_menu(pmp->menu, NULL, (*pmp->pexc)->w.fw);
++	}
++	/* get pos hints for item's action */
++	get_popup_options(pmp, med->mi, pops);
++	if (med->mrMi == pmp->menu && mrMiPopup == NULL &&
++	    MI_IS_POPUP(med->mi) && MR_MISSING_SUBMENU_FUNC(pmp->menu))
++	{
++		/* We're on a submenu item, but the submenu does not exist.
++		 * The user defined missing_submenu_action may create it. */
++		Bool is_complex_function;
++		Bool is_busy_grabbed = False;
++		char *menu_name;
++		char *action;
++		char *missing_action = MR_MISSING_SUBMENU_FUNC(pmp->menu);
++
++		menu_name = PeekToken(
++			SkipNTokens(MI_ACTION(med->mi), 1), NULL);
++		if (!menu_name)
++		{
++			menu_name = "";
++		}
++		is_complex_function =
++			functions_is_complex_function(missing_action);
++		if (is_complex_function)
++		{
++			char *action_ptr;
++			action =
++				safemalloc(
++					strlen("Function") + 3 +
++					strlen(missing_action) * 2 + 3 +
++					strlen(menu_name) * 2 + 1);
++			strcpy(action, "Function ");
++			action_ptr = action + strlen(action);
++			action_ptr = QuoteString(action_ptr, missing_action);
++			*action_ptr++ = ' ';
++			action_ptr = QuoteString(action_ptr, menu_name);
++		}
++		else
++		{
++			action = MR_MISSING_SUBMENU_FUNC(pmp->menu);
++		}
++		if (Scr.BusyCursor & BUSY_DYNAMICMENU)
++		{
++			is_busy_grabbed = GrabEm(CRS_WAIT, GRAB_BUSYMENU);
++		}
++		/* Execute the action */
++		__menu_execute_function(pmp->pexc, action);
++		if (is_complex_function)
++		{
++			free(action);
++		}
++		if (is_busy_grabbed)
++		{
++			UngrabEm(GRAB_BUSYMENU);
++		}
++		/* Let's see if the menu exists now. */
++		mrMiPopup = mr_popup_for_mi(pmp->menu, med->mi);
++	} /* run MISSING_SUBMENU_FUNCTION */
++	in->mrPopup = mrMiPopup;
++	if (!in->mrPopup)
++	{
++		in->mif.do_menu = False;
++		pmret->flags.is_menu_posted = 0;
++	}
++	else
++	{
++		if (__mloop_make_popup(
++			    pmp, pmret, in, med, pops, pdoes_submenu_overlap)
++		    == MENU_MLOOP_RET_END)
++		{
++			return MENU_MLOOP_RET_END;
++		}
++	} /* else (in->mrPopup) */
++	if (in->mif.do_popdown)
++	{
++		if (in->mrPopdown)
++		{
++			if (in->mrPopdown != in->mrPopup)
++			{
++				if (in->mi_with_popup ==
++				    MR_PARENT_ITEM(in->mrPopdown))
++				{
++					in->mi_with_popup = NULL;
++				}
++				pop_menu_down_and_repaint_parent(
++					&in->mrPopdown,
++					pdoes_popdown_submenu_overlap, pmp);
++			}
++			in->mrPopdown = NULL;
++		}
++		in->mif.do_popdown = False;
++	}
++	if (in->mrPopup)
++	{
++		if (MR_PARENT_MENU(in->mrPopup) == pmp->menu)
++		{
++			med->mi = find_entry(
++				pmp, NULL, &med->mrMi, None, -1, -1);
++			if (med->mi && med->mrMi == in->mrPopup)
++			{
++				in->mif.do_menu = True;
++				in->mif.is_submenu_mapped = True;
++			}
++		}
++		else
++		{
++			/* This menu must be already mapped somewhere else, so
++			 * ignore it completely.  This can only happen if we
++			 * have reached the maximum allowed number of menu
++			 * copies. */
++			in->mif.do_menu = False;
++			in->mif.do_popdown = False;
++			in->mrPopup = NULL;
++		}
++	}
++
++	return MENU_MLOOP_RET_NORMAL;
++}
++
++static mloop_ret_code_t __mloop_do_menu(
++	MenuParameters *pmp, MenuReturn *pmret, double_keypress *pdkp,
++	mloop_evh_input_t *in, mloop_evh_data_t *med, MenuOptions *pops,
++	Bool *pdoes_submenu_overlap)
++{
++	MenuParameters mp;
++	XEvent e;
++
++	memset(&mp, 0, sizeof(mp));
++	mp.menu = in->mrPopup;
++	mp.pexc = pmp->pexc;
++	mp.parent_menu = pmp->menu;
++	mp.parent_item = med->mi;
++	mp.tear_off_root_menu_window = pmp->tear_off_root_menu_window;
++	MR_IS_TEAR_OFF_MENU(in->mrPopup) = 0;
++	mp.flags.has_default_action = False;
++	mp.flags.is_already_mapped = in->mif.is_submenu_mapped;
++	mp.flags.is_sticky = False;
++	mp.flags.is_submenu = True;
++	mp.flags.is_triggered_by_keypress = !!in->mif.do_popup_and_warp;
++	mp.pops = pops;
++	mp.ret_paction = pmp->ret_paction;
++	mp.screen_origin_x = pmp->screen_origin_x;
++	mp.screen_origin_y = pmp->screen_origin_y;
++	if (in->mif.do_propagate_event_into_submenu)
++	{
++		e = *(*pmp->pexc)->x.elast;
++		mp.event_propagate_to_submenu = &e;
++	}
++	else
++	{
++		mp.event_propagate_to_submenu = NULL;
++	}
++
++	/* recursively do the new menu we've moved into */
++	do_menu(&mp, pmret);
++
++	in->mif.do_propagate_event_into_submenu = False;
++	if (pmret->rc == MENU_PROPAGATE_EVENT)
++	{
++		in->mif.do_recycle_event = 1;
++		return MENU_MLOOP_RET_LOOP;
++	}
++	if (IS_MENU_RETURN(pmret->rc))
++	{
++		pdkp->timestamp = 0;
++		return MENU_MLOOP_RET_END;
++	}
++	if (MST_DO_UNMAP_SUBMENU_ON_POPDOWN(pmp->menu) &&
++	    pmret->flags.is_key_press)
++	{
++		in->miRemovedSubmenu = MR_PARENT_ITEM(in->mrPopup);
++		pop_menu_down_and_repaint_parent(
++			&in->mrPopup, pdoes_submenu_overlap, pmp);
++		in->mi_with_popup = NULL;
++		MR_SUBMENU_ITEM(pmp->menu) = NULL;
++		if (in->mrPopup == in->mrPopdown)
++		{
++			in->mrPopdown = NULL;
++		}
++		in->mrPopup = NULL;
++	}
++	if (pmret->rc == MENU_POPDOWN)
++	{
++		med->popup_delay_10ms = 0;
++		in->mif.do_force_reposition = True;
++	}
++
++	return MENU_MLOOP_RET_NORMAL;
++}
++
++static mloop_ret_code_t __mloop_handle_action_with_mi(
++	MenuParameters *pmp, MenuReturn *pmret, double_keypress *pdkp,
++	mloop_evh_input_t *in, mloop_evh_data_t *med, mloop_static_info_t *msi,
++	MenuOptions *pops, Bool *pdoes_submenu_overlap,
++	Bool *pdoes_popdown_submenu_overlap)
++{
++	MenuItem *tmi;
++	MenuRoot *tmrMi;
++	MenuRoot *mrMiPopup = NULL;
++
++	pmret->flags.do_unpost_submenu = 0;
++	/* we're on a menu item */
++	in->mif.is_off_menu_allowed = False;
++	if (med->mrMi == pmp->menu && med->mi != in->miRemovedSubmenu)
++	{
++		in->miRemovedSubmenu = NULL;
++	}
++	if (med->mrMi != pmp->menu && med->mrMi != in->mrPopup &&
++	    med->mrMi != in->mrPopdown)
++	{
++		/* we're on an item from a prior menu */
++		if (med->mrMi != MR_PARENT_MENU(pmp->menu))
++		{
++			/* the event is for a previous menu, just close
++			 * this one */
++			pmret->rc = MENU_PROPAGATE_EVENT;
++			pmret->target_menu = med->mrMi;
++		}
++		else
++		{
++			pmret->rc = MENU_POPDOWN;
++		}
++		pdkp->timestamp = 0;
++		return MENU_MLOOP_RET_END;
++	}
++	if (med->mi != MR_SELECTED_ITEM(pmp->menu) && med->mrMi == pmp->menu)
++	{
++		/* new item of the same menu */
++		__mloop_select_item(
++			pmp, in, med, *pdoes_submenu_overlap,
++			pdoes_popdown_submenu_overlap);
++	}
++	else if (med->mi != MR_SELECTED_ITEM(pmp->menu) && med->mrMi &&
++		 med->mrMi == in->mrPopdown)
++	{
++		/* we're on the popup menu of a different menu item of this
++		 * menu */
++		med->mi = MR_PARENT_ITEM(in->mrPopdown);
++		in->mrPopup = in->mrPopdown;
++		in->mrPopdown = NULL;
++		*pdoes_submenu_overlap = *pdoes_popdown_submenu_overlap;
++		select_menu_item(pmp->menu, med->mi, True, (*pmp->pexc)->w.fw);
++	}
++	mrMiPopup = mr_popup_for_mi(pmp->menu, med->mi);
++	/* check what has to be done with the item */
++	if (__mloop_get_mi_actions(
++		    pmp, pmret, pdkp, in, med, msi, mrMiPopup,
++		    pdoes_submenu_overlap, pdoes_popdown_submenu_overlap) ==
++	    MENU_MLOOP_RET_END)
++	{
++		return MENU_MLOOP_RET_END;
++	}
++	/* do what needs to be done */
++	if (in->mif.do_popdown && !in->mif.do_popup)
++	{
++		/* popdown previous popup */
++		__mloop_do_popdown(pmp, in, pdoes_popdown_submenu_overlap);
++	}
++	if (in->mif.do_popup)
++	{
++		if (__mloop_do_popup(
++			    pmp, pmret, in, med, pops, mrMiPopup,
++			    pdoes_submenu_overlap,
++			    pdoes_popdown_submenu_overlap) ==
++		    MENU_MLOOP_RET_END)
++		{
++			return MENU_MLOOP_RET_END;
++		}
++	}
++	/* remember the 'posted' menu */
++	if (pmret->flags.is_menu_posted && in->mrPopup != NULL &&
++	    pmret->target_menu == NULL)
++	{
++		pmret->target_menu = in->mrPopup;
++	}
++	else if (pmret->flags.is_menu_posted && in->mrPopup == NULL)
++	{
++		pmret->flags.is_menu_posted = 0;
++	}
++	if (in->mif.do_menu)
++	{
++		mloop_ret_code_t rc;
++
++		rc = __mloop_do_menu(
++			pmp, pmret, pdkp, in, med, pops,
++			pdoes_submenu_overlap);
++		if (rc != MENU_MLOOP_RET_NORMAL)
++		{
++			return rc;
++		}
++	}
++	/* Now check whether we can animate the current popup menu back to the
++	 * original place to unobscure the current menu;  this happens only
++	 * when using animation */
++	if (in->mrPopup && MR_XANIMATION(in->mrPopup) &&
++	    (tmi = find_entry(pmp, NULL, &tmrMi, None, -1, -1))  &&
++	    (tmi == MR_SELECTED_ITEM(pmp->menu) || tmrMi != pmp->menu))
++	{
++		animated_move_back(in->mrPopup, False, (*pmp->pexc)->w.fw);
++	}
++	/* now check whether we should animate the current real menu
++	 * over to the right to unobscure the prior menu; only a very
++	 * limited case where this might be helpful and not too disruptive */
++	/* but this cause terrible back-and-forth under certain circonstance,
++	 * I think we should disable this ... 2002-09-17 olicha */
++	if (in->mrPopup == NULL && pmp->parent_menu != NULL &&
++	    MR_XANIMATION(pmp->menu) != 0 &&
++	    pointer_in_passive_item_area(med->x_offset, med->mrMi))
++	{
++		/* we have to see if we need menu to be moved */
++		animated_move_back(pmp->menu, True, (*pmp->pexc)->w.fw);
++		if (in->mrPopdown)
++		{
++			if (in->mrPopdown != in->mrPopup)
++			{
++				pop_menu_down_and_repaint_parent(
++					&in->mrPopdown,
++					pdoes_popdown_submenu_overlap, pmp);
++				in->mi_with_popup = NULL;
++			}
++			in->mrPopdown = NULL;
++		}
++		in->mif.do_popdown = False;
++	}
++
++	return MENU_MLOOP_RET_NORMAL;
++}
++
++static mloop_ret_code_t __mloop_handle_action_without_mi(
++	MenuParameters *pmp, MenuReturn *pmret, double_keypress *pdkp,
++	mloop_evh_input_t *in, mloop_evh_data_t *med, mloop_static_info_t *msi,
++	MenuOptions *pops, Bool *pdoes_submenu_overlap,
++	Bool *pdoes_popdown_submenu_overlap)
++{
++	pmret->flags.do_unpost_submenu = 0;
++	/* moved off menu, deselect selected item... */
++	if (!MR_SELECTED_ITEM(pmp->menu) ||
++	    in->mif.is_off_menu_allowed == True || pmret->flags.is_menu_posted)
++	{
++		/* nothing to do */
++		return MENU_MLOOP_RET_NORMAL;
++	}
++	if (in->mrPopup)
++	{
++		int x, y, mx, my;
++		int mw, mh;
++
++		if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
++				  &x, &y, &JunkX, &JunkY, &JunkMask) == False)
++		{
++			/* pointer is on a different screen */
++			x = 0;
++			y = 0;
++		}
++		if (menu_get_geometry(
++			    pmp->menu, &JunkRoot, &mx, &my, &mw, &mh, &JunkBW,
++			    &JunkDepth) &&
++		    ((!MR_IS_LEFT(in->mrPopup)  && x < mx) ||
++		     (!MR_IS_RIGHT(in->mrPopup) && x > mx + mw) ||
++		     (!MR_IS_UP(in->mrPopup)    && y < my) ||
++		     (!MR_IS_DOWN(in->mrPopup)  && y > my + mh)))
++		{
++			select_menu_item(
++				pmp->menu, MR_SELECTED_ITEM(pmp->menu), False,
++				(*pmp->pexc)->w.fw);
++			pop_menu_down_and_repaint_parent(
++				&in->mrPopup, pdoes_submenu_overlap, pmp);
++			in->mi_with_popup = NULL;
++			MR_SUBMENU_ITEM(pmp->menu) = NULL;
++			if (in->mrPopup == in->mrPopdown)
++			{
++				in->mrPopdown = NULL;
++			}
++			in->mrPopup = NULL;
++		}
++		else if (x < mx || x >= mx + mw || y < my || y >= my + mh)
++		{
++			/* pointer is outside the menu but do not pop down */
++			in->mif.is_off_menu_allowed = True;
++		}
++		else
++		{
++			/* Pointer is still in the menu. Postpone the decision
++			 * if we have to pop down. */
++		}
++	} /* if (in->mrPopup) */
++	else
++	{
++		select_menu_item(
++			pmp->menu, MR_SELECTED_ITEM(pmp->menu), False,
++			(*pmp->pexc)->w.fw);
++	}
++
++	return MENU_MLOOP_RET_NORMAL;
++}
++
++static void __mloop_exit_warp_back(MenuParameters *pmp)
++{
++	MenuItem *tmi;
++	MenuRoot *tmrMi;
++
++	if (pmp->parent_menu && MR_SELECTED_ITEM(pmp->parent_menu))
++	{
++		warp_pointer_to_item(
++			pmp->parent_menu, MR_SELECTED_ITEM(pmp->parent_menu),
++			False);
++		tmi = find_entry(pmp, NULL, &tmrMi, None, -1, -1);
++		if (pmp->parent_menu != tmrMi && MR_XANIMATION(pmp->menu) == 0)
++		{
++			/* Warping didn't take us to the correct menu, i.e. the
++			 * spot we want to warp to is obscured. So raise our
++			 * window first. */
++			XRaiseWindow(dpy, MR_WINDOW(pmp->parent_menu));
++		}
++	}
++
++	return;
++}
++
++static void __mloop_exit_select_in_place(
++	MenuParameters *pmp, mloop_evh_data_t *med, MenuOptions *pops)
++{
++	MenuRoot *submenu;
++	XWindowAttributes win_attribs;
++
++	last_saved_pos_hints.flags.is_last_menu_pos_hints_valid = True;
++	last_saved_pos_hints.pos_hints.x_offset = 0;
++	last_saved_pos_hints.pos_hints.x_factor = 0;
++	last_saved_pos_hints.pos_hints.context_x_factor = 0;
++	last_saved_pos_hints.pos_hints.y_factor = 0;
++	last_saved_pos_hints.pos_hints.is_relative = False;
++	last_saved_pos_hints.pos_hints.is_menu_relative = False;
++	submenu = mr_popup_for_mi(pmp->menu, med->mi);
++	if (submenu && MR_WINDOW(submenu) != None &&
++	    XGetWindowAttributes(dpy, MR_WINDOW(submenu), &win_attribs) &&
++	    win_attribs.map_state == IsViewable &&
++	    menu_get_geometry(
++		    submenu, &JunkRoot, &last_saved_pos_hints.pos_hints.x,
++		    &last_saved_pos_hints.pos_hints.y, &JunkWidth, &JunkHeight,
++		    &JunkBW, &JunkDepth))
++	{
++		/* The submenu is mapped, just take its position and put it in
++		 * the position hints. */
++	}
++	else if (pops->flags.has_poshints)
++	{
++		last_saved_pos_hints.pos_hints = pops->pos_hints;
++	}
++	else
++	{
++		Bool dummy;
++
++		get_prefered_popup_position(
++			pmp->menu, submenu, &last_saved_pos_hints. pos_hints.x,
++			&last_saved_pos_hints. pos_hints.y, &dummy);
++	}
++	if (pops->flags.do_warp_on_select)
++	{
++		last_saved_pos_hints.flags.do_warp_title = 1;
++	}
++
++	return;
++}
++
++static void __mloop_exit_selected(
++	MenuParameters *pmp, MenuReturn *pmret,
++	mloop_evh_data_t *med, MenuOptions *pops)
++{
++	/* save action to execute so that the menu may be destroyed
++	 * now */
++	if (pmp->ret_paction)
++	{
++		if (*pmp->ret_paction)
++		{
++			free(*pmp->ret_paction);
++		}
++		*pmp->ret_paction = (med->mi) ?
++			safestrdup(MI_ACTION(med->mi)) : NULL;
++	}
++	if (pmp->ret_paction && *pmp->ret_paction && med->mi &&
++	    MI_IS_POPUP(med->mi))
++	{
++		get_popup_options(pmp, med->mi, pops);
++		if (pops->flags.do_select_in_place)
++		{
++			__mloop_exit_select_in_place(pmp, med, pops);
++		}
++		else
++		{
++			last_saved_pos_hints.flags.do_ignore_pos_hints = True;
++		} /* pops->flags.do_select_in_place */
++		last_saved_pos_hints.pos_hints.screen_origin_x =
++			pmp->screen_origin_x;
++		last_saved_pos_hints.pos_hints.screen_origin_y =
++			pmp->screen_origin_y;
++	}
++
++	return;
++}
++
++static void __mloop_exit(
++	MenuParameters *pmp, MenuReturn *pmret, double_keypress *pdkp,
++	mloop_evh_input_t *in, mloop_evh_data_t *med, mloop_static_info_t *msi,
++	MenuOptions *pops)
++{
++	Bool no = False;
++	Bool do_deselect = False;
++
++	if (in->mrPopdown)
++	{
++		pop_menu_down_and_repaint_parent(&in->mrPopdown, &no, pmp);
++		MR_SUBMENU_ITEM(pmp->menu) = NULL;
++	}
++	if (pmret->rc == MENU_SELECTED && is_double_click(
++		    msi->t0, med->mi, pmp, pmret, pdkp,
++		    in->mif.has_mouse_moved))
++	{
++		pmret->rc = MENU_DOUBLE_CLICKED;
++	}
++	if (pmret->rc == MENU_SELECTED && med->mi &&
++	    MI_FUNC_TYPE(med->mi) == F_TEARMENUOFF)
++	{
++		pmret->rc = (MR_IS_TEAR_OFF_MENU(pmp->menu)) ?
++			MENU_KILL_TEAR_OFF_MENU : MENU_TEAR_OFF;
++	}
++	switch (pmret->rc)
++	{
++	case MENU_POPDOWN:
++	case MENU_PROPAGATE_EVENT:
++	case MENU_DOUBLE_CLICKED:
++		do_deselect = True;
++		/* Allow popdown to warp back pointer to main menu with mouse
++		   button control. (MoveLeft/MoveRight on a mouse binding) */
++		if (((pmret->rc == MENU_POPDOWN && in->mif.is_button_release)
++		     || in->mif.is_key_press) &&
++		    pmret->rc != MENU_DOUBLE_CLICKED)
++		{
++			if (!pmp->flags.is_submenu)
++			{
++				/* abort a root menu rather than pop it down */
++				pmret->rc = MENU_ABORTED;
++			}
++			__mloop_exit_warp_back(pmp);
++		}
++		break;
++	case MENU_ABORTED:
++	case MENU_TEAR_OFF:
++	case MENU_KILL_TEAR_OFF_MENU:
++		do_deselect = True;
++		break;
++	case MENU_SELECTED:
++		__mloop_exit_selected(pmp, pmret, med, pops);
++		pmret->rc = MENU_DONE;
++		break;
++
++	default:
++		break;
++	}
++	if (do_deselect && MR_SELECTED_ITEM(pmp->menu))
++	{
++		select_menu_item(
++			pmp->menu, MR_SELECTED_ITEM(pmp->menu), False,
++			(*pmp->pexc)->w.fw);
++	}
++	if (pmret->rc == MENU_SUBMENU_TORN_OFF)
++	{
++		in->mrPopup = NULL;
++		MR_SUBMENU_ITEM(pmp->menu) = NULL;
++	}
++	if (in->mrPopup)
++	{
++		pop_menu_down_and_repaint_parent(&in->mrPopup, &no, pmp);
++		MR_SUBMENU_ITEM(pmp->menu) = NULL;
++	}
++	pmret->flags.is_key_press = in->mif.is_key_press;
++
++	return;
++}
++
++static void __menu_loop(
++	MenuParameters *pmp, MenuReturn *pmret, double_keypress *pdkp)
++{
++	mloop_evh_input_t mei;
++	mloop_ret_code_t mloop_ret;
++	mloop_evh_data_t med;
++	mloop_static_info_t msi;
++	MenuOptions mops;
++	Bool is_finished;
++	Bool does_submenu_overlap = False;
++	Bool does_popdown_submenu_overlap = False;
++
++	__mloop_init(pmp, pmret, &mei, &med, &msi, &mops);
++	for (is_finished = False; !is_finished; )
++	{
++		mloop_ret = __mloop_get_event(pmp, pmret, &mei, &med, &msi);
++		switch (mloop_ret)
++		{
++		case MENU_MLOOP_RET_END:
++			is_finished = True;
++		case MENU_MLOOP_RET_LOOP:
++			continue;
++		default:
++			break;
++		}
++		mloop_ret = __mloop_handle_event(
++			pmp, pmret, pdkp, &mei, &med, &msi);
++		switch (mloop_ret)
++		{
++		case MENU_MLOOP_RET_END:
++			is_finished = True;
++		case MENU_MLOOP_RET_LOOP:
++			continue;
++		default:
++			break;
++		}
++		/* Now handle new menu items, whether it is from a keypress or
++		 * a pointer motion event. */
++		if (med.mi != NULL)
++		{
++			mloop_ret = __mloop_handle_action_with_mi(
++				pmp, pmret, pdkp, &mei, &med, &msi, &mops,
++				&does_submenu_overlap,
++				&does_popdown_submenu_overlap);
++		}
++		else
++		{
++			mloop_ret = __mloop_handle_action_without_mi(
++				pmp, pmret, pdkp, &mei, &med, &msi, &mops,
++				&does_submenu_overlap,
++				&does_popdown_submenu_overlap);
++		}
++		if (mloop_ret == MENU_MLOOP_RET_END)
++		{
++			is_finished = True;
++		}
++		XFlush(dpy);
++	}
++	__mloop_exit(pmp, pmret, pdkp, &mei, &med, &msi, &mops);
++
++	return;
++}
++
++/*
++ * Functions dealing with tear off menus
++ */
++
++static char *menu_strip_tear_off_title(MenuRoot *mr)
++{
++	MenuItem *mi;
++	int i;
++	int len;
++	char *name;
++
++	for (mi = MR_FIRST_ITEM(mr); mi != NULL; mi = MI_NEXT_ITEM(mi))
++	{
++		if (MI_IS_TITLE(mi))
++		{
++			break;
++		}
++		else if (!MI_IS_SEPARATOR(mi) && !MI_IS_TEAR_OFF_BAR(mi))
++		{
++			/* a normal item, no title found */
++			return NULL;
++		}
++		/* skip separators and tear off bars */
++	}
++	if (mi == NULL || !MI_HAS_TEXT(mi) || MI_NEXT_ITEM(mi) == NULL)
++	{
++		return NULL;
++	}
++	/* extract the window title from the labels */
++	for (i = 0, len = 0; i < MAX_MENU_ITEM_LABELS; i++)
++	{
++		if (MI_LABEL(mi)[i] != 0)
++		{
++			len += strlen(MI_LABEL(mi)[i]) + 1;
++		}
++	}
++	if (len == 0)
++	{
++		return NULL;
++	}
++	name = safemalloc(len + 1);
++	*name = 0;
++	for (i = 0; i < MAX_MENU_ITEM_LABELS; i++)
++	{
++		if (MI_LABEL(mi)[i] != 0)
++		{
++			strcat(name, MI_LABEL(mi)[i]);
++			strcat(name, " ");
++		}
++	}
++	/* strip the last space */
++	name[len - 1] = 0;
++	/* unlink and destroy the item */
++	unlink_item_from_menu(mr, mi);
++	menuitem_free(mi);
++
++	return name;
++}
++
++static void menu_tear_off(MenuRoot *mr_to_copy)
++{
++	MenuRoot *mr;
++	MenuStyle *ms;
++	XEvent ev;
++	XSizeHints menusizehints;
++	XClassHint menuclasshints;
++	XTextProperty menunametext;
++	XWMHints menuwmhints;
++	char *list[] ={ NULL, NULL };
++	char *t;
++	char *name = NULL;
++	Atom protocols[1];
++	int x = 0;
++	int y = 0;
++	unsigned int add_mask = 0;
++	initial_window_options_t win_opts;
++	evh_args_t ea;
++	exec_context_changes_t ecc;
++	char *buffer;
++	char *action;
++	cond_rc_t *cond_rc = NULL;
++	const exec_context_t *exc = NULL;
++
++	/* keep the menu open */
++	if (MR_WINDOW(mr_to_copy) != None)
++	{
++		discard_window_events(
++			MR_WINDOW(mr_to_copy), SubstructureNotifyMask);
++	}
++	mr = clone_menu(mr_to_copy);
++	/* also dump the menu style */
++	buffer = (char *)safemalloc(23);
++	sprintf(buffer,"%lu",(unsigned long)mr);
++	action = buffer;
++	ms = menustyle_parse_style(F_PASS_ARGS);
++	if (!ms)
++	{
++		/* this must never happen */
++		fvwm_msg(
++			ERR, "menu_tear_off",
++			"impossible to create %s menu style", buffer);
++		free(buffer);
++		DestroyMenu(mr, False, False);
++		return;
++	}
++	free(buffer);
++	menustyle_copy(MR_STYLE(mr_to_copy),ms);
++	MR_STYLE(mr) = ms;
++	MST_USAGE_COUNT(mr) = 0;
++	name = menu_strip_tear_off_title(mr);
++	/* create the menu window and size the menu */
++	make_menu(mr, True);
++	/* set position */
++	if (menu_get_geometry(
++		    mr_to_copy, &JunkRoot, &x, &y, &JunkWidth, &JunkHeight,
++		    &JunkBW, &JunkDepth))
++	{
++		add_mask = PPosition;
++		XMoveWindow(dpy, MR_WINDOW(mr), x, y);
++	}
++	else
++	{
++		add_mask = 0;
++	}
++	/* focus policy */
++	menuwmhints.flags = InputHint;
++	menuwmhints.input = False;
++	/* size hints */
++	menusizehints.flags = PBaseSize | PMinSize | PMaxSize | add_mask;
++	menusizehints.base_width  = 0;
++	menusizehints.base_height = 0;
++	menusizehints.min_width = MR_WIDTH(mr);
++	menusizehints.min_height = MR_HEIGHT(mr);
++	menusizehints.max_width = MR_WIDTH(mr);
++	menusizehints.max_height = MR_HEIGHT(mr);
++	/* class, resource and names */
++	menuclasshints.res_name =
++		(name != NULL) ? name : safestrdup(MR_NAME(mr));
++	menuclasshints.res_class = safestrdup("fvwm_menu");
++	for (t = menuclasshints.res_name; t != NULL && *t != 0; t++)
++	{
++		/* replace tabs in the title with spaces */
++		if (*t == '\t')
++		{
++			*t = ' ';
++		}
++	}
++	list[0] = menuclasshints.res_name;
++	menunametext.value = NULL;
++	XStringListToTextProperty(list, 1, &menunametext);
++	/* set all properties and hints */
++	XSetWMProperties(
++		dpy, MR_WINDOW(mr), &menunametext, &menunametext, NULL, 0,
++		&menusizehints, NULL, &menuclasshints);
++	XSetWMHints(dpy, MR_WINDOW(mr), &menuwmhints);
++	protocols[0] = _XA_WM_DELETE_WINDOW;
++	XSetWMProtocols(dpy, MR_WINDOW(mr), &(protocols[0]), 1);
++
++	/* free memory */
++	if (menunametext.value != NULL)
++	{
++		XFree(menunametext.value);
++	}
++	free(menuclasshints.res_class);
++	free(menuclasshints.res_name);
++
++	/* manage the window */
++	memset(&win_opts, 0, sizeof(win_opts));
++	win_opts.flags.is_menu = True;
++	ev.type = MapRequest;
++	ev.xmaprequest.send_event = True;
++	ev.xmaprequest.display = dpy;
++	ev.xmaprequest.parent = Scr.Root;
++	ev.xmaprequest.window = MR_WINDOW(mr);
++	fev_fake_event(&ev);
++	ecc.type = EXCT_NULL;
++	ecc.x.etrigger = &ev;
++	ecc.w.w = MR_WINDOW(mr);
++	ecc.w.wcontext = C_ROOT;
++	ea.exc = exc_create_context(
++		&ecc, ECC_TYPE | ECC_ETRIGGER | ECC_W | ECC_WCONTEXT);
++	HandleMapRequestKeepRaised(&ea, None, NULL, &win_opts);
++	exc_destroy_context(ea.exc);
++
++	return;
++}
++
++static void do_menu_close_tear_off_menu(MenuRoot *mr, MenuParameters mp)
++{
++	pop_menu_down(&mr, &mp);
++	menustyle_free(MR_STYLE(mr));
++	DestroyMenu(mr, False, False);
++}
++
++/* ---------------------------- interface functions ------------------------- */
++
++void menus_init(void)
++{
++	memset((&Menus), 0, sizeof(MenuInfo));
++
++	return;
++}
++
++/* menus_find_menu expects a token as the input. Make sure you have used
++ * GetNextToken before passing a menu name to remove quotes (if necessary) */
++MenuRoot *menus_find_menu(char *name)
++{
++	MenuRoot *mr;
++
++	if (name == NULL)
++	{
++		return NULL;
++	}
++	for (mr = Menus.all; mr != NULL; mr = MR_NEXT_MENU(mr))
++	{
++		if (!MR_IS_DESTROYED(mr) && mr == MR_ORIGINAL_MENU(mr) &&
++		    MR_NAME(mr) != NULL && StrEquals(name, MR_NAME(mr)))
++		{
++			break;
++		}
++	}
++
++	return mr;
++}
++
++void menus_remove_style_from_menus(MenuStyle *ms)
++{
++	MenuRoot *mr;
++
++	for (mr = Menus.all; mr; mr = MR_NEXT_MENU(mr))
++	{
++		if (MR_STYLE(mr) == ms)
++		{
++			MR_STYLE(mr) = menustyle_get_default_style();
++			MR_IS_UPDATED(mr) = 1;
++		}
++	}
++
++	return;
++}
++
++/*
++ * Functions dealing with tear off menus
++ */
++
++void menu_enter_tear_off_menu(const exec_context_t *exc)
++{
++	MenuRoot *mr;
++	char *ret_action = NULL;
++	MenuOptions mops;
++	MenuParameters mp;
++	MenuReturn mret;
++	const exec_context_t *exc2;
++	exec_context_changes_t ecc;
++
++	if (XFindContext(
++		    dpy, FW_W(exc->w.fw), MenuContext,
++		    (caddr_t *)&mr) == XCNOENT)
++	{
++		return;
++	}
++	ecc.w.fw = NULL;
++	ecc.w.w = None;
++	ecc.w.wcontext = C_ROOT;
++	exc2 = exc_clone_context(exc, &ecc, ECC_FW | ECC_W | ECC_WCONTEXT);
++	memset(&mops, 0, sizeof(mops));
++	memset(&mret, 0, sizeof(MenuReturn));
++	memset(&mp, 0, sizeof(mp));
++	mp.menu = mr;
++	mp.pexc = &exc2;
++	mp.tear_off_root_menu_window = exc->w.fw;
++	MR_IS_TEAR_OFF_MENU(mr) = 1;
++	mp.flags.has_default_action = 0;
++	mp.flags.is_already_mapped = True;
++	mp.flags.is_sticky = False;
++	mp.flags.is_submenu = False;
++	mp.pops = &mops;
++	mp.ret_paction = &ret_action;
++	do_menu(&mp, &mret);
++	exc_destroy_context(exc2);
++
++	return;
++}
++
++void menu_close_tear_off_menu(FvwmWindow *fw)
++{
++	MenuRoot *mr;
++	MenuParameters mp;
++	const exec_context_t *exc;
++	exec_context_changes_t ecc;
++
++	if (XFindContext(
++		    dpy, FW_W(fw), MenuContext, (caddr_t *)&mr) == XCNOENT)
++	{
++		return;
++	}
++	memset(&mp, 0, sizeof(mp));
++	mp.menu = mr;
++	ecc.w.fw = NULL;
++	ecc.w.w = None;
++	ecc.w.wcontext = C_ROOT;
++	exc = exc_create_context(&ecc, ECC_FW | ECC_W | ECC_WCONTEXT);
++	mp.pexc = &exc;
++	do_menu_close_tear_off_menu(mr, mp);
++	exc_destroy_context(exc);
++
++	return;
++}
++
++Bool menu_redraw_transparent_tear_off_menu(FvwmWindow *fw, Bool pr_only)
++{
++	MenuRoot *mr;
++	MenuStyle *ms = NULL;
++	int cs;
++
++	if (!(IS_TEAR_OFF_MENU(fw) &&
++	      XFindContext(dpy, FW_W(fw), MenuContext,(caddr_t *)&mr) !=
++	      XCNOENT &&
++	      (ms = MR_STYLE(mr)) &&
++	      ST_HAS_MENU_CSET(ms)))
++	{
++		return False;
++	}
++
++	cs = ST_CSET_MENU(ms);
++
++	if (!CSET_IS_TRANSPARENT(cs) ||
++	    (pr_only && !CSET_IS_TRANSPARENT_PR(cs)))
++	{
++		return False;
++	}
++
++	return UpdateBackgroundTransparency(
++		dpy, MR_WINDOW(mr), MR_WIDTH(mr),
++		MR_HEIGHT(mr),
++		&Colorset[ST_CSET_MENU(ms)],
++		Pdepth,
++		FORE_GC(MST_MENU_INACTIVE_GCS(mr)),
++		True);
++}
++
++/*
++ *
++ * Initiates a menu pop-up
++ *
++ * fStick = True  = sticky menu, stays up on initial button release.
++ * fStick = False = transient menu, drops on initial release.
++ *
++ * eventp = 0: menu opened by mouse, do not warp
++ * eventp > 1: root menu opened by keypress with 'Menu', warp pointer and
++ *             allow 'double-keypress'.
++ * eventp = 1: menu opened by keypress, warp but forbid 'double-keypress'
++ *             this should always be used except in the call in 'staysup_func'
++ *             in builtin.c
++ *
++ * Returns one of MENU_NOP, MENU_ERROR, MENU_ABORTED, MENU_DONE
++ * do_menu() may destroy the *pmp->pexec member and replace it with a new
++ * copy.  Be sure not to rely on the original structure being kept intact
++ * when calling do_menu().
++ */
++void do_menu(MenuParameters *pmp, MenuReturn *pmret)
++{
++	int x;
++	int y;
++	Bool fWasAlreadyPopped = False;
++	Bool key_press;
++	Bool is_pointer_grabbed = False;
++	Bool is_pointer_ungrabbed = False;
++	Bool do_menu_interaction;
++	Bool do_check_pop_down;
++	Bool do_warp;
++	Time t0 = fev_get_evtime();
++	XEvent tmpevent;
++	double_keypress dkp;
++	/* don't save these ones, we want them to work even within recursive
++	 * menus popped up by dynamic actions. */
++	static int indirect_depth = 0;
++	static int x_start;
++	static int y_start;
++	static Bool has_mouse_moved = False;
++	int scr_x, scr_y;
++	int scr_w, scr_h;
++
++	pmret->rc = MENU_NOP;
++	if (pmp->flags.is_sticky && !pmp->flags.is_submenu)
++	{
++		FCheckTypedEvent(dpy, ButtonPressMask, &tmpevent);
++	}
++	if (pmp->menu == NULL)
++	{
++		pmret->rc = MENU_ERROR;
++		return;
++	}
++	key_press = pmp->flags.is_triggered_by_keypress;
++
++	/* Try to pick a root-relative optimal x,y to
++	 * put the mouse right on the title w/o warping */
++	if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
++			  &x, &y, &JunkX, &JunkY, &JunkMask) == False)
++	{
++		/* pointer is on a different screen */
++		x = 0;
++		y = 0;
++	}
++	/* Save these - we want to warp back here if this is a top level
++	 * menu brought up by a keystroke */
++	if (!pmp->flags.is_submenu)
++	{
++		pmp->flags.is_invoked_by_key_press = key_press;
++		pmp->flags.is_first_root_menu = !indirect_depth;
++	}
++	else
++	{
++		pmp->flags.is_first_root_menu = 0;
++	}
++	if (!pmp->flags.is_submenu && indirect_depth == 0)
++	{
++		if (key_press)
++		{
++			x_start = x;
++			y_start = y;
++		}
++		else
++		{
++			x_start = -1;
++			y_start = -1;
++		}
++		pmp->screen_origin_x = pmp->pops->pos_hints.screen_origin_x;
++		pmp->screen_origin_y = pmp->pops->pos_hints.screen_origin_y;
++	}
++	if (pmp->pops->flags.do_warp_title)
++	{
++		do_warp = True;
++	}
++	else if (pmp->pops->flags.do_not_warp)
++	{
++		do_warp = False;
++	}
++	else if (key_press)
++	{
++		do_warp = True;
++	}
++	else
++	{
++		do_warp = False;
++	}
++	/* Figure out where we should popup, if possible */
++	if (!pmp->flags.is_already_mapped)
++	{
++		Bool prefer_left_submenus = False;
++		/* Make sure we are using the latest style and menu layout. */
++		update_menu(pmp->menu, pmp);
++
++		if (pmp->flags.is_submenu)
++		{
++			/* this is a submenu popup */
++			get_prefered_popup_position(
++				pmp->parent_menu, pmp->menu, &x, &y,
++				&prefer_left_submenus);
++		}
++		else
++		{
++			fscreen_scr_arg fscr;
++
++			/* we're a top level menu */
++			has_mouse_moved = False;
++			if (!GrabEm(CRS_MENU, GRAB_MENU))
++			{
++				/* GrabEm specifies the cursor to use */
++				XBell(dpy, 0);
++				pmret->rc = MENU_ABORTED;
++				return;
++			}
++			is_pointer_grabbed = True;
++			/* Make the menu appear under the pointer rather than
++			 * warping */
++			fscr.xypos.x = x;
++			fscr.xypos.y = y;
++			FScreenGetScrRect(
++				&fscr, FSCREEN_XYPOS, &scr_x, &scr_y, &scr_w,
++				&scr_h);
++			x -= menudim_middle_x_offset(&MR_DIM(pmp->menu));
++			y -= menuitem_middle_y_offset(
++				MR_FIRST_ITEM(pmp->menu), MR_STYLE(pmp->menu));
++			if (x < scr_x)
++			{
++				x = scr_x;
++			}
++			if (y < scr_y)
++			{
++				y = scr_y;
++			}
++		}
++
++		/* pop_menu_up may move the x,y to make it fit on screen more
++		 * nicely. It might also move parent_menu out of the way. */
++		if (!pop_menu_up(
++			    &(pmp->menu), pmp, pmp->parent_menu, NULL,
++			    pmp->pexc, x, y, prefer_left_submenus, do_warp,
++			    pmp->pops, NULL, None))
++		{
++			XBell(dpy, 0);
++			UngrabEm(GRAB_MENU);
++			pmret->rc = MENU_ERROR;
++			return;
++		}
++	}
++	else
++	{
++		fWasAlreadyPopped = True;
++		if (pmp->tear_off_root_menu_window != NULL)
++		{
++			if (!GrabEm(CRS_MENU, GRAB_MENU))
++			{
++				/* GrabEm specifies the cursor to use */
++				XBell(dpy, 0);
++				pmret->rc = MENU_ABORTED;
++				return;
++			}
++			is_pointer_grabbed = True;
++		}
++		if (key_press)
++		{
++			warp_pointer_to_item(
++				pmp->menu, MR_FIRST_ITEM(pmp->menu),
++				True /* skip Title */);
++		}
++	}
++
++	/* Remember the key that popped up the root menu. */
++	if (pmp->flags.is_submenu)
++	{
++		dkp.timestamp = 0;
++	}
++	else
++	{
++		if (pmp->flags.is_triggered_by_keypress)
++		{
++			/* we have a real key event */
++			dkp.keystate = (*pmp->pexc)->x.etrigger->xkey.state;
++			dkp.keycode = (*pmp->pexc)->x.etrigger->xkey.keycode;
++		}
++		dkp.timestamp =
++			(key_press && pmp->flags.has_default_action) ? t0 : 0;
++	}
++	if (!pmp->flags.is_submenu && indirect_depth == 0)
++	{
++		/* we need to grab the keyboard so we are sure no key presses
++		 * are lost */
++		MyXGrabKeyboard(dpy);
++	}
++	/* This may loop for tear off menus */
++	for (do_menu_interaction = True; do_menu_interaction == True; )
++	{
++		if (is_pointer_ungrabbed && !GrabEm(CRS_MENU, GRAB_MENU))
++		{
++			/* re-grab the pointer in this cycle */
++			XBell(dpy, 0);
++			pmret->rc = MENU_ABORTED;
++			break;
++		}
++		do_menu_interaction = False;
++		if (pmp->pops->flags.do_tear_off_immediately == 1)
++		{
++			pmret->rc = MENU_TEAR_OFF;
++		}
++		else
++		{
++			if (!pmp->flags.is_submenu)
++			{
++				XSelectInput(
++					dpy, Scr.NoFocusWin, XEVMASK_MENUNFW);
++				XFlush(dpy);
++			}
++			__menu_loop(pmp, pmret, &dkp);
++			if (!pmp->flags.is_submenu)
++			{
++				XSelectInput(
++					dpy, Scr.NoFocusWin, XEVMASK_NOFOCUSW);
++				XFlush(dpy);
++			}
++		}
++		do_check_pop_down = False;
++		switch (pmret->rc)
++		{
++		case MENU_TEAR_OFF:
++			menu_tear_off(pmp->menu);
++			pop_menu_down(&pmp->menu, pmp);
++			break;
++		case MENU_KILL_TEAR_OFF_MENU:
++			if (MR_IS_TEAR_OFF_MENU(pmp->menu))
++			{
++				/* kill the menu */
++				do_menu_close_tear_off_menu(pmp->menu, *pmp);
++				pmret->rc = MENU_ABORTED;
++			}
++			else
++			{
++				/* pass return code up to the torn off menu */
++			}
++			break;
++		case MENU_DOUBLE_CLICKED:
++		case MENU_DONE:
++			if (MR_IS_TEAR_OFF_MENU(pmp->menu))
++			{
++				do_menu_interaction = True;
++			}
++			else
++			{
++				do_check_pop_down = True;
++			}
++			break;
++		case MENU_SUBMENU_TORN_OFF:
++			pmret->rc = MENU_ABORTED;
++			do_check_pop_down = True;
++			break;
++		default:
++			do_check_pop_down = True;
++			break;
++		}
++		if (do_check_pop_down == True)
++		{
++			/* popping down may destroy the menu via the dynamic
++			 * popdown action! */
++			if (!MR_IS_TEAR_OFF_MENU(pmp->menu) &&
++			    fWasAlreadyPopped == False)
++			{
++				pop_menu_down(&pmp->menu, pmp);
++			}
++		}
++		XFlush(dpy);
++
++		if (!pmp->flags.is_submenu && x_start >= 0 && y_start >= 0 &&
++		    pmret->flags.is_key_press && pmret->rc != MENU_TEAR_OFF)
++		{
++			/* warp pointer back to where invoked if this was
++			 * brought up with a keypress and we're returning from
++			 * a top level menu, and a button release event didn't
++			 * end it */
++			FWarpPointer(
++				dpy, 0, Scr.Root, 0, 0, Scr.MyDisplayWidth,
++				Scr.MyDisplayHeight, x_start, y_start);
++			if ((*pmp->pexc)->x.elast->type == KeyPress)
++			{
++				XEvent e = *(*pmp->pexc)->x.elast;
++
++				e.xkey.x_root = x_start;
++				e.xkey.y_root = y_start;
++				fev_fake_event(&e);
++			}
++		}
++		if (pmret->rc == MENU_TEAR_OFF)
++		{
++			pmret->rc = MENU_SUBMENU_TORN_OFF;
++		}
++
++		dkp.timestamp = 0;
++		if (is_pointer_grabbed)
++		{
++			UngrabEm(GRAB_MENU);
++			WaitForButtonsUp(True);
++			is_pointer_ungrabbed = True;
++		}
++		if (!pmp->flags.is_submenu)
++		{
++			if (pmret->rc == MENU_DONE)
++			{
++				if (pmp->ret_paction && *pmp->ret_paction)
++				{
++					indirect_depth++;
++					/* Execute the action */
++					__menu_execute_function(
++						pmp->pexc, *pmp->ret_paction);
++					indirect_depth--;
++					free(*pmp->ret_paction);
++					*pmp->ret_paction = NULL;
++				}
++				last_saved_pos_hints.flags.
++					do_ignore_pos_hints = False;
++				last_saved_pos_hints.flags.
++					is_last_menu_pos_hints_valid = False;
++			}
++			if (indirect_depth == 0)
++			{
++				last_saved_pos_hints.flags.
++					do_ignore_pos_hints = False;
++				last_saved_pos_hints.flags.
++					is_last_menu_pos_hints_valid = False;
++			}
++		}
++	}
++	if (!pmp->flags.is_submenu && indirect_depth == 0)
++	{
++		/* release the keyboard when the last menu closes */
++		MyXUngrabKeyboard(dpy);
++	}
++
++	return;
++}
++
++Bool menu_expose(XEvent *event, FvwmWindow *fw)
++{
++	MenuRoot *mr = NULL;
++
++	if ((XFindContext(
++		     dpy, event->xany.window, MenuContext, (caddr_t *)&mr) !=
++	     XCNOENT))
++	{
++		flush_accumulate_expose(event->xany.window, event);
++		paint_menu(mr, event, fw);
++
++		return True;
++	}
++	else
++	{
++		return False;
++	}
++}
++
++/*
++ *
++ *  Procedure:
++ *      repaint_transparent_menu - repaint the menu background if it is
++ *      tranparent during an animated move. Called in move_resize.c
++ *      (AnimatedMoveAnyWindow). Performance improvement Welcome!
++ *  ideas: - write the foreground into a pixmap and a mask the first time
++ *          this function is called. Then use these pixmaps to draw
++ *	    the items
++ *         - Use a Buffer if !IS_TRANSPARENT_PR_PURE and if we do not have one
++ *           already
++ */
++void repaint_transparent_menu(
++	MenuRepaintTransparentParameters *prtm,
++	Bool first, int x, int y, int end_x, int end_y)
++{
++	MenuItem *mi;
++	MenuRoot *mr;
++	MenuStyle *ms;
++	int h = 0;
++	int s_h = 0;
++	int e_h = 0;
++	Bool last = False;
++
++	mr = prtm->mr;
++	ms = MR_STYLE(mr);
++	if (x == end_x && y == end_y)
++	{
++		last = True;
++	}
++	if (!last && CSET_IS_TRANSPARENT_PR_TINT(ST_CSET_MENU(ms)))
++	{
++		/* too slow ... */
++		return;
++	}
++	SetWindowBackground(
++		dpy, MR_WINDOW(mr), MR_WIDTH(mr), MR_HEIGHT(mr),
++		&Colorset[ST_CSET_MENU(ms)], Pdepth,
++		FORE_GC(MST_MENU_INACTIVE_GCS(mr)), False);
++	/* redraw the background of non active item */
++	for (mi = MR_FIRST_ITEM(mr); mi != NULL; mi = MI_NEXT_ITEM(mi))
++	{
++		if (mi == MR_SELECTED_ITEM(mr) && MST_DO_HILIGHT_BACK(mr))
++		{
++			int left;
++
++			left = MR_HILIGHT_X_OFFSET(mr) - MR_ITEM_X_OFFSET(mr);
++			if (left > 0)
++			{
++				XClearArea(
++					dpy, MR_WINDOW(mr),
++					MR_ITEM_X_OFFSET(mr), MI_Y_OFFSET(mi),
++					left, MI_HEIGHT(mi) +
++					MST_RELIEF_THICKNESS(mr), 0);
++			}
++			h = MI_HEIGHT(mi);
++			continue;
++		}
++		if (h == 0)
++		{
++			s_h += MI_HEIGHT(mi);
++		}
++		else
++		{
++			e_h += MI_HEIGHT(mi);
++		}
++	}
++	XClearArea(
++		dpy, MR_WINDOW(mr), MR_ITEM_X_OFFSET(mr), MST_BORDER_WIDTH(mr),
++		MR_ITEM_WIDTH(mr), s_h, 0);
++	if (e_h != 0)
++	{
++		XClearArea(
++			dpy, MR_WINDOW(mr), MR_ITEM_X_OFFSET(mr),
++			s_h + h + MST_RELIEF_THICKNESS(mr) +
++			MST_BORDER_WIDTH(mr), MR_ITEM_WIDTH(mr), e_h, 0);
++	}
++
++	/* now redraw the items */
++	for (mi = MR_FIRST_ITEM(mr); mi != NULL; mi = MI_NEXT_ITEM(mi))
++	{
++		MenuPaintItemParameters mpip;
++
++		if (mi == MR_SELECTED_ITEM(mr) && MST_DO_HILIGHT_BACK(mr) &&
++		    !CSET_IS_TRANSPARENT_PR_TINT(ST_CSET_MENU(ms)))
++		{
++			continue;
++		}
++		get_menu_paint_item_parameters(
++			&mpip, mr, NULL, prtm->fw, NULL, True);
++		mpip.flags.is_first_item = (MR_FIRST_ITEM(mr) == mi);
++		menuitem_paint(mi, &mpip);
++	}
++
++	/* if we have a side pic and no side colors we shound repaint the side
++	 * pic */
++	if ((MR_SIDEPIC(mr) || MST_SIDEPIC(mr)) &&
++	    !MR_HAS_SIDECOLOR(mr) && !MST_HAS_SIDE_COLOR(mr))
++	{
++		FvwmPicture *sidePic;
++		if (MR_SIDEPIC(mr))
++		{
++			sidePic = MR_SIDEPIC(mr);
++		}
++		else if (MST_SIDEPIC(mr))
++		{
++			sidePic = MST_SIDEPIC(mr);
++		}
++		else
++		{
++			return;
++		}
++		XClearArea(
++			dpy, MR_WINDOW(mr), MR_SIDEPIC_X_OFFSET(mr),
++			MST_BORDER_WIDTH(mr), sidePic->width,
++			MR_HEIGHT(mr) - 2 * MST_BORDER_WIDTH(mr), 0);
++		paint_side_pic(mr, NULL);
++	}
++}
++
++Bool DestroyMenu(MenuRoot *mr, Bool do_recreate, Bool is_command_request)
++{
++	MenuItem *mi,*tmp2;
++	MenuRoot *tmp, *prev;
++	Bool in_list = True;
++
++	if (mr == NULL)
++	{
++		return False;
++	}
++
++	/* seek menu in master list */
++	tmp = Menus.all;
++	prev = NULL;
++	while (tmp && tmp != mr)
++	{
++		prev = tmp;
++		tmp = MR_NEXT_MENU(tmp);
++	}
++	if (tmp != mr)
++	{
++		/* no such menu */
++		in_list = False;
++	}
++
++	if (MR_MAPPED_COPIES(mr) > 0 &&
++	    (is_command_request || MR_COPIES(mr) == 1))
++	{
++		/* can't destroy a menu while in use */
++		fvwm_msg(ERR, "DestroyMenu", "Menu %s is in use", MR_NAME(mr));
++		return False;
++	}
++
++	if (in_list && MR_COPIES(mr) > 1 && MR_ORIGINAL_MENU(mr) == mr)
++	{
++		MenuRoot *m;
++		MenuRoot *new_orig;
++
++		/* find a new 'original' menu */
++		for (m = Menus.all, new_orig = NULL; m; m = MR_NEXT_MENU(m))
++		{
++			if (m != mr && MR_ORIGINAL_MENU(m) == mr)
++			{
++				if (new_orig == NULL)
++				{
++					new_orig = m;
++				}
++				MR_ORIGINAL_MENU(m) = new_orig;
++			}
++		}
++		MR_ORIGINAL_MENU(mr) = new_orig;
++		/* now dump old original menu */
++	}
++
++	MR_COPIES(mr)--;
++	if (MR_STORED_ITEM(mr).stored)
++	{
++		XFreePixmap(dpy, MR_STORED_ITEM(mr).stored);
++	}
++	if (MR_COPIES(mr) > 0)
++	{
++		do_recreate = False;
++	}
++	else
++	{
++		/* free all items */
++		mi = MR_FIRST_ITEM(mr);
++		while (mi != NULL)
++		{
++			tmp2 = MI_NEXT_ITEM(mi);
++			menuitem_free(mi);
++			mi = tmp2;
++		}
++		if (do_recreate)
++		{
++			/* just dump the menu items but keep the menu itself */
++			MR_COPIES(mr)++;
++			MR_FIRST_ITEM(mr) = NULL;
++			MR_LAST_ITEM(mr) = NULL;
++			MR_SELECTED_ITEM(mr) = NULL;
++			MR_CONTINUATION_MENU(mr) = NULL;
++			MR_PARENT_MENU(mr) = NULL;
++			MR_ITEMS(mr) = 0;
++			memset(&(MR_STORED_ITEM(mr)), 0 ,
++			       sizeof(MR_STORED_ITEM(mr)));
++			MR_IS_UPDATED(mr) = 1;
++			return True;
++		}
++	}
++
++	/* unlink menu from list */
++	if (in_list)
++	{
++		if (prev == NULL)
++		{
++			Menus.all = MR_NEXT_MENU(mr);
++		}
++		else
++		{
++			MR_NEXT_MENU(prev) = MR_NEXT_MENU(mr);
++		}
++	}
++	/* destroy the window and the display */
++	if (MR_WINDOW(mr) != None)
++	{
++		XDeleteContext(dpy, MR_WINDOW(mr), MenuContext);
++		XFlush(dpy);
++		XDestroyWindow(MR_CREATE_DPY(mr), MR_WINDOW(mr));
++		MR_WINDOW(mr) = None;
++		XFlush(MR_CREATE_DPY(mr));
++	}
++	if (MR_CREATE_DPY(mr) != NULL && MR_CREATE_DPY(mr) != dpy)
++	{
++		XCloseDisplay(MR_CREATE_DPY(mr));
++		MR_CREATE_DPY(mr) = NULL;
++	}
++
++	if (MR_COPIES(mr) == 0)
++	{
++		if (MR_POPUP_ACTION(mr))
++		{
++			free(MR_POPUP_ACTION(mr));
++		}
++		if (MR_POPDOWN_ACTION(mr))
++		{
++			free(MR_POPDOWN_ACTION(mr));
++		}
++		if (MR_MISSING_SUBMENU_FUNC(mr))
++		{
++			free(MR_MISSING_SUBMENU_FUNC(mr));
++		}
++		free(MR_NAME(mr));
++		if (MR_SIDEPIC(mr))
++		{
++			PDestroyFvwmPicture(dpy, MR_SIDEPIC(mr));
++		}
++		memset(mr->s, 0, sizeof(*(mr->s)));
++		free(mr->s);
++	}
++	memset(mr->d, 0, sizeof(*(mr->d)));
++	free(mr->d);
++	memset(mr, 0, sizeof(*mr));
++	free(mr);
++
++	return True;
++}
++
++/* FollowMenuContinuations
++ * Given an menu root, return the menu root to add to by
++ * following continuation links until there are no more
++ */
++MenuRoot *FollowMenuContinuations(MenuRoot *mr, MenuRoot **pmrPrior )
++{
++	*pmrPrior = NULL;
++	while ((mr != NULL) &&
++	       (MR_CONTINUATION_MENU(mr) != NULL))
++	{
++		*pmrPrior = mr;
++		mr = MR_CONTINUATION_MENU(mr);
++	}
++
++	return mr;
++}
++
++/*
++ *
++ *  Procedure:
++ *      AddToMenu - add an item to a root menu
++ *
++ *  Returned Value:
++ *      (MenuItem *)
++ *
++ *  Inputs:
++ *      menu    - pointer to the root menu to add the item
++ *      item    - the text to appear in the menu
++ *      action  - the string to possibly execute
++ *
++ * ckh - need to add boolean to say whether or not to expand for pixmaps,
++ *       so built in window list can handle windows w/ * and % in title.
++ *
++ */
++void AddToMenu(
++	MenuRoot *mr, char *item, char *action, Bool fPixmapsOk, Bool fNoPlus,
++	Bool is_continuation_item)
++{
++	MenuItem *tmp;
++	char *start;
++	char *end;
++	char *token = NULL;
++	char *option = NULL;
++	int i;
++	int current_mini_icon = 0;
++	int is_empty;
++	Bool do_replace_title;
++
++	if (MR_MAPPED_COPIES(mr) > 0)
++	{
++		/* whoa, we can't handle *everything* */
++		return;
++	}
++	if ((item == NULL || *item == 0) && (action == NULL || *action == 0) &&
++	    fNoPlus)
++	{
++		return;
++	}
++	/* empty items screw up our menu when painted, so we replace them with
++	 * a separator */
++	if (item == NULL)
++		item = "";
++
++	/*
++	 * Handle dynamic actions
++	 */
++
++	if (StrEquals(item, "DynamicPopupAction"))
++	{
++		if (MR_POPUP_ACTION(mr))
++		{
++			free(MR_POPUP_ACTION(mr));
++		}
++		if (!action || *action == 0)
++		{
++			MR_POPUP_ACTION(mr) = NULL;
++		}
++		else
++		{
++			MR_POPUP_ACTION(mr) = stripcpy(action);
++		}
++		return;
++	}
++	else if (StrEquals(item, "DynamicPopdownAction"))
++	{
++		if (MR_POPDOWN_ACTION(mr))
++		{
++			free(MR_POPDOWN_ACTION(mr));
++		}
++		if (!action || *action == 0)
++		{
++			MR_POPDOWN_ACTION(mr) = NULL;
++		}
++		else
++		{
++			MR_POPDOWN_ACTION(mr) = stripcpy(action);
++		}
++		return;
++	}
++	else if (StrEquals(item, "MissingSubmenuFunction"))
++	{
++		if (MR_MISSING_SUBMENU_FUNC(mr))
++		{
++			free(MR_MISSING_SUBMENU_FUNC(mr));
++		}
++		if (!action || *action == 0)
++		{
++			MR_MISSING_SUBMENU_FUNC(mr) = NULL;
++		}
++		else
++		{
++			MR_MISSING_SUBMENU_FUNC(mr) = stripcpy(action);
++		}
++		return;
++	}
++
++	/*
++	 * Parse the action
++	 */
++
++	if (action == NULL || *action == 0)
++	{
++		action = "Nop";
++	}
++	GetNextToken(GetNextToken(action, &token), &option);
++	tmp = menuitem_create();
++	if (MR_FIRST_ITEM(mr) != NULL && StrEquals(token, "title") &&
++	    option != NULL && StrEquals(option, "top"))
++	{
++		do_replace_title = True;
++	}
++	else
++	{
++		do_replace_title = False;
++	}
++	append_item_to_menu(mr, tmp, do_replace_title);
++	if (token)
++	{
++		free(token);
++	}
++	if (option)
++	{
++		free(option);
++	}
++
++	MI_ACTION(tmp) = stripcpy(action);
++
++	/*
++	 * Parse the labels
++	 */
++
++	start = item;
++	end = item;
++	for (i = 0; i < MAX_MENU_ITEM_LABELS; i++, start = end)
++	{
++		/* Read label up to next tab. */
++		if (*end)
++		{
++			if (i < MAX_MENU_ITEM_LABELS - 1)
++			{
++				while (*end && *end != '\t')
++				{
++					/* seek next tab or end of string */
++					end++;
++				}
++			}
++			else
++			{
++				/* remove all tabs in last label */
++				while (*end)
++				{
++					if (*end == '\t')
++					{
++						*end = ' ';
++					}
++					end++;
++				}
++			}
++			/* Copy the label. */
++			MI_LABEL(tmp)[i] = safemalloc(end - start + 1);
++			strncpy(MI_LABEL(tmp)[i], start, end - start);
++			(MI_LABEL(tmp)[i])[end - start] = 0;
++			if (*end == '\t')
++			{
++				/* skip the tab */
++				end++;
++			}
++		}
++		else
++		{
++			MI_LABEL(tmp)[i] = NULL;
++		}
++
++		/* Parse the label. */
++		if (MI_LABEL(tmp)[i] != NULL)
++		{
++			if (fPixmapsOk)
++			{
++				if (!MI_PICTURE(tmp))
++				{
++					if (scanForPixmap(
++						    MI_LABEL(tmp)[i],
++						    &MI_PICTURE(tmp), '*'))
++					{
++						MI_HAS_PICTURE(tmp) = True;
++					}
++				}
++				while (current_mini_icon <
++				       MAX_MENU_ITEM_MINI_ICONS)
++				{
++					if (scanForPixmap(
++						    MI_LABEL(tmp)[i],
++						    &(MI_MINI_ICON(tmp)
++						      [current_mini_icon]),
++						    '%'))
++					{
++						current_mini_icon++;
++						MI_HAS_PICTURE(tmp) = True;
++					}
++					else
++					{
++						break;
++					}
++				}
++			}
++			if (!MI_HAS_HOTKEY(tmp))
++			{
++				/* pete at tecc.co.uk */
++				scanForHotkeys(tmp, i);
++
++				if (!MI_HAS_HOTKEY(tmp) &&
++				    *MI_LABEL(tmp)[i] != 0)
++				{
++					MI_HOTKEY_COFFSET(tmp) = 0;
++					MI_HOTKEY_COLUMN(tmp) = i;
++					MI_HAS_HOTKEY(tmp) = 1;
++					MI_IS_HOTKEY_AUTOMATIC(tmp) = 1;
++				}
++			}
++			if (*(MI_LABEL(tmp)[i]))
++			{
++				MI_HAS_TEXT(tmp) = True;
++			}
++			else
++			{
++				free(MI_LABEL(tmp)[i]);
++				MI_LABEL(tmp)[i] = NULL;
++			}
++		}
++		MI_LABEL_STRLEN(tmp)[i] =
++			(MI_LABEL(tmp)[i]) ? strlen(MI_LABEL(tmp)[i]) : 0;
++	} /* for */
++
++	/*
++	 * Set the type flags
++	 */
++
++	if (is_continuation_item)
++	{
++		MI_IS_CONTINUATION(tmp) = True;
++	}
++	find_func_t(MI_ACTION(tmp), &(MI_FUNC_TYPE(tmp)), NULL);
++	switch (MI_FUNC_TYPE(tmp))
++	{
++	case F_POPUP:
++		MI_IS_POPUP(tmp) = True;
++	case F_WINDOWLIST:
++	case F_STAYSUP:
++		MI_IS_MENU(tmp) = True;
++		break;
++	case F_TITLE:
++		MI_IS_TITLE(tmp) = True;
++		break;
++	default:
++		break;
++	}
++	is_empty = (!MI_HAS_TEXT(tmp) && !MI_HAS_PICTURE(tmp));
++	if (is_empty)
++	{
++		if (MI_FUNC_TYPE(tmp) == F_TEARMENUOFF)
++		{
++			MI_IS_TEAR_OFF_BAR(tmp) = 1;
++			MI_IS_SEPARATOR(tmp) = 0;
++		}
++		else
++		{
++			MI_IS_TEAR_OFF_BAR(tmp) = 0;
++			MI_IS_SEPARATOR(tmp) = 1;
++		}
++	}
++	if (MI_IS_SEPARATOR(tmp))
++	{
++		/* An empty title is handled like a separator. */
++		MI_IS_TITLE(tmp) = False;
++	}
++	MI_IS_SELECTABLE(tmp) =
++		((MI_HAS_TEXT(tmp) || MI_HAS_PICTURE(tmp) ||
++		  MI_IS_TEAR_OFF_BAR(tmp)) && !MI_IS_TITLE(tmp));
++
++	/*
++	 * misc stuff
++	 */
++
++	MR_ITEMS(mr)++;
++	MR_IS_UPDATED(mr) = 1;
++
++	return;
++}
++
++/*
++ *
++ *  Procedure:
++ *      NewMenuRoot - create a new menu root
++ *
++ *  Returned Value:
++ *      (MenuRoot *)
++ *
++ *  Inputs:
++ *      name    - the name of the menu root
++ *
++ */
++MenuRoot *NewMenuRoot(char *name)
++{
++	MenuRoot *mr;
++	Bool flag;
++
++	mr = (MenuRoot *)safemalloc(sizeof(MenuRoot));
++	mr->s = (MenuRootStatic *)safemalloc(sizeof(MenuRootStatic));
++	mr->d = (MenuRootDynamic *)safemalloc(sizeof(MenuRootDynamic));
++
++	memset(mr->s, 0, sizeof(MenuRootStatic));
++	memset(mr->d, 0, sizeof(MenuRootDynamic));
++	MR_NEXT_MENU(mr) = Menus.all;
++	MR_NAME(mr) = safestrdup(name);
++	MR_WINDOW(mr) = None;
++	scanForPixmap(MR_NAME(mr), &MR_SIDEPIC(mr), '@');
++	scanForColor(MR_NAME(mr), &MR_SIDECOLOR(mr), &flag,'^');
++	MR_HAS_SIDECOLOR(mr) = flag;
++	MR_STYLE(mr) = menustyle_get_default_style();
++	MR_ORIGINAL_MENU(mr) = mr;
++	MR_COPIES(mr) = 1;
++	MR_IS_UPDATED(mr) = 1;
++
++	Menus.all = mr;
++	return mr;
++}
++
++void SetMenuCursor(Cursor cursor)
++{
++	MenuRoot *mr;
++
++	mr = Menus.all;
++	for (mr = Menus.all; mr; mr = MR_NEXT_MENU(mr))
++	{
++		if (MR_WINDOW(mr))
++		{
++			XDefineCursor(dpy, MR_WINDOW(mr), cursor);
++		}
++	}
++
++	return;
++}
++
++void UpdateAllMenuStyles(void)
++{
++	MenuStyle *ms;
++
++	for (ms = menustyle_get_default_style(); ms; ms = ST_NEXT_STYLE(ms))
++	{
++		menustyle_update(ms);
++	}
++
++	return;
++}
++
++void UpdateMenuColorset(int cset)
++{
++	MenuStyle *ms;
++	FvwmWindow *t;
++
++	for (ms = menustyle_get_default_style(); ms; ms = ST_NEXT_STYLE(ms))
++	{
++		if ((ST_HAS_MENU_CSET(ms) && ST_CSET_MENU(ms) == cset) ||
++		    (ST_HAS_ACTIVE_CSET(ms) && ST_CSET_ACTIVE(ms) == cset) ||
++		    (ST_HAS_GREYED_CSET(ms) && ST_CSET_GREYED(ms) == cset) ||
++		    (ST_HAS_TITLE_CSET(ms) && ST_CSET_TITLE(ms) == cset))
++		{
++			menustyle_update(ms);
++		}
++	}
++
++	for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
++	{
++		MenuRoot *mr = NULL;
++		MenuStyle *ms = NULL;
++
++		if (IS_TEAR_OFF_MENU(t) &&
++		    XFindContext(dpy, FW_W(t), MenuContext, (caddr_t *)&mr) !=
++		    XCNOENT &&
++		    (ms = MR_STYLE(mr)))
++		{
++			if   (ST_HAS_MENU_CSET(ms) &&
++			      ST_CSET_MENU(ms) == cset)
++			{
++				SetWindowBackground(
++					dpy, MR_WINDOW(mr), MR_WIDTH(mr),
++					MR_HEIGHT(mr),
++					&Colorset[ST_CSET_MENU(ms)],
++					Pdepth,
++					FORE_GC(MST_MENU_INACTIVE_GCS(mr)),
++					True);
++			}
++			else if ((ST_HAS_ACTIVE_CSET(ms) &&
++				  ST_CSET_ACTIVE(ms) == cset) ||
++				 (ST_HAS_GREYED_CSET(ms) &&
++				  ST_CSET_GREYED(ms) == cset))
++			{
++				paint_menu(mr, NULL, NULL);
++			}
++		}
++	}
++
++	return;
++}
++
++/* This is called by the window list function */
++void change_mr_menu_style(MenuRoot *mr, char *stylename)
++{
++	MenuStyle *ms = NULL;
++
++	ms = menustyle_find(stylename);
++	if (ms == NULL)
++	{
++		return;
++	}
++	if (MR_MAPPED_COPIES(mr) != 0)
++	{
++		fvwm_msg(ERR,"ChangeMenuStyle", "menu %s is in use",
++			 MR_NAME(mr));
++	}
++	else
++	{
++		MR_STYLE(mr) = ms;
++		MR_IS_UPDATED(mr) = 1;
++	}
++
++	return;
++}
++
++void add_another_menu_item(char *action)
++{
++	MenuRoot *mr;
++	MenuRoot *mrPrior;
++	char *rest,*item;
++
++	mr = FollowMenuContinuations(Scr.last_added_item.item, &mrPrior);
++	if (mr == NULL)
++	{
++		return;
++	}
++	if (MR_MAPPED_COPIES(mr) != 0)
++	{
++		fvwm_msg(ERR,"add_another_menu_item", "menu is in use");
++		return;
++	}
++	rest = GetNextToken(action,&item);
++	AddToMenu(mr, item, rest, True /* pixmap scan */, False, False);
++	if (item)
++	{
++		free(item);
++	}
++
++	return;
++}
++
++/*
++ * get_menu_options is used for Menu, Popup and WindowList
++ * It parses strings matching
++ *
++ *   [ [context-rectangle] x y ] [special-options] [other arguments]
++ *
++ * and returns a pointer to the first part of the input string that doesn't
++ * match this syntax.
++ *
++ * See documentation for a detailed description.
++ */
++char *get_menu_options(
++	char *action, Window w, FvwmWindow *fw, XEvent *e, MenuRoot *mr,
++	MenuItem *mi, MenuOptions *pops)
++{
++	char *tok = NULL;
++	char *naction = action;
++	char *taction;
++	int x;
++	int y;
++	int button;
++	int gflags;
++	int width;
++	int height;
++	int dummy_int;
++	float dummy_float;
++	Bool dummy_flag;
++	Window context_window = None;
++	Bool fHasContext, fUseItemOffset, fRectangleContext, fXineramaRoot;
++	Bool fValidPosHints =
++		last_saved_pos_hints.flags.is_last_menu_pos_hints_valid;
++	Bool is_action_empty = False;
++	Bool once_more = True;
++	Bool is_icon_context;
++	rectangle icon_g;
++
++	/* If this is set we may want to reverse the position hints, so don't
++	 * sum up the totals right now. This is useful for the SubmenusLeft
++	 * style. */
++
++	fXineramaRoot = False;
++	last_saved_pos_hints.flags.is_last_menu_pos_hints_valid = False;
++	if (pops == NULL)
++	{
++		fvwm_msg(ERR,
++			 "get_menu_options","no MenuOptions pointer passed");
++		return action;
++	}
++
++	taction = action;
++	memset(&(pops->flags), 0, sizeof(pops->flags));
++	pops->flags.has_poshints = 0;
++	if (!action || *action == 0)
++	{
++		is_action_empty = True;
++	}
++	while (action != NULL && *action != 0 && once_more)
++	{
++		/* ^ just to be able to jump to end of loop without 'goto' */
++		gflags = NoValue;
++		pops->pos_hints.is_relative = False;
++		pops->pos_hints.menu_width = 0;
++		pops->pos_hints.is_menu_relative = False;
++		/* parse context argument (if present) */
++		naction = GetNextToken(taction, &tok);
++		if (!tok)
++		{
++			/* no context string */
++			fHasContext = False;
++			is_action_empty = True;
++			break;
++		}
++		/* set to False for absolute hints! */
++		pops->pos_hints.is_relative = True;
++		fUseItemOffset = False;
++		fHasContext = True;
++		fRectangleContext = False;
++		is_icon_context = False;
++		if (StrEquals(tok, "context"))
++		{
++			if (mi && mr)
++			{
++				context_window = MR_WINDOW(mr);
++			}
++			else if (fw)
++			{
++				if (IS_ICONIFIED(fw))
++				{
++					is_icon_context = True;
++					get_icon_geometry(fw, &icon_g);
++					context_window = None;
++				}
++				else
++				{
++					context_window =
++						FW_W_FRAME(fw);
++				}
++			}
++			else
++			{
++				context_window = w;
++			}
++		}
++		else if (StrEquals(tok,"menu"))
++		{
++			if (mr)
++			{
++				context_window = MR_WINDOW(mr);
++				pops->pos_hints.is_menu_relative = True;
++				pops->pos_hints.menu_width = MR_WIDTH(mr);
++			}
++		}
++		else if (StrEquals(tok,"item"))
++		{
++			if (mi && mr)
++			{
++				context_window = MR_WINDOW(mr);
++				fUseItemOffset = True;
++				pops->pos_hints.is_menu_relative = True;
++				pops->pos_hints.menu_width = MR_WIDTH(mr);
++			}
++		}
++		else if (StrEquals(tok,"icon"))
++		{
++			if (fw && IS_ICONIFIED(fw))
++			{
++				is_icon_context = True;
++				get_icon_geometry(fw, &icon_g);
++				context_window = None;
++			}
++		}
++		else if (StrEquals(tok,"window"))
++		{
++			if (fw && !IS_ICONIFIED(fw))
++			{
++				context_window = FW_W_FRAME(fw);
++			}
++		}
++		else if (StrEquals(tok,"interior"))
++		{
++			if (fw && !IS_ICONIFIED(fw))
++			{
++				context_window = FW_W(fw);
++			}
++		}
++		else if (StrEquals(tok,"title"))
++		{
++			if (fw)
++			{
++				if (IS_ICONIFIED(fw))
++				{
++					context_window =
++						FW_W_ICON_TITLE(fw);
++				}
++				else
++				{
++					context_window = FW_W_TITLE(fw);
++				}
++			}
++		}
++		else if (strncasecmp(tok,"button",6) == 0)
++		{
++			if (sscanf(&(tok[6]),"%d",&button) != 1 ||
++			    tok[6] == '+' || tok[6] == '-' || button < 0 ||
++			    button > 9)
++			{
++				fHasContext = False;
++			}
++			else if (fw && !IS_ICONIFIED(fw))
++			{
++				button = BUTTON_INDEX(button);
++				context_window = FW_W_BUTTON(fw, button);
++			}
++		}
++		else if (StrEquals(tok,"root"))
++		{
++			context_window = Scr.Root;
++			pops->pos_hints.is_relative = False;
++		}
++		else if (StrEquals(tok,"xineramaroot"))
++		{
++			context_window = Scr.Root;
++			pops->pos_hints.is_relative = False;
++			fXineramaRoot = True;
++		}
++		else if (StrEquals(tok,"mouse"))
++		{
++			context_window = None;
++		}
++		else if (StrEquals(tok,"rectangle"))
++		{
++			int flags;
++			int screen;
++			int sx;
++			int sy;
++			int sw;
++			int sh;
++
++			/* parse the rectangle */
++			free(tok);
++			naction = GetNextToken(naction, &tok);
++			if (tok == NULL)
++			{
++				fvwm_msg(ERR, "get_menu_options",
++					 "missing rectangle geometry");
++				if (!pops->pos_hints.has_screen_origin)
++				{
++					/* xinerama: emergency fallback */
++					pops->pos_hints.has_screen_origin = 1;
++					pops->pos_hints.screen_origin_x = 0;
++					pops->pos_hints.screen_origin_y = 0;
++				}
++				return action;
++			}
++			flags = FScreenParseGeometryWithScreen(
++				tok, &x, &y,
++				(unsigned int*)&width,
++				(unsigned int*)&height, &screen);
++			if ((flags & (XValue | YValue)) != (XValue | YValue))
++			{
++				free(tok);
++				fvwm_msg(ERR, "get_menu_options",
++					 "invalid rectangle geometry");
++				if (!pops->pos_hints.has_screen_origin)
++				{
++					/* xinerama: emergency fallback */
++					pops->pos_hints.has_screen_origin = 1;
++					pops->pos_hints.screen_origin_x = 0;
++					pops->pos_hints.screen_origin_y = 0;
++				}
++				return action;
++			}
++			pops->pos_hints.has_screen_origin = 1;
++			FScreenGetScrRect(NULL, screen, &sx, &sy, &sw, &sh);
++			pops->pos_hints.screen_origin_x = sx;
++			pops->pos_hints.screen_origin_y = sy;
++			if (!(flags & WidthValue))
++			{
++				width = 1;
++			}
++			if (!(flags & HeightValue))
++			{
++				height = 1;
++			}
++			x += sx;
++			y += sy;
++			if (flags & XNegative)
++			{
++				x = sx + sw - x - width;
++			}
++			if (flags & YNegative)
++			{
++				y = sy + sh - y - height;
++			}
++			pops->pos_hints.is_relative = False;
++			fRectangleContext = True;
++		}
++		else if (StrEquals(tok,"this"))
++		{
++			MenuRoot *dummy_mr;
++
++			context_window = w;
++			if (XFindContext(
++				    dpy, w, MenuContext,
++				    (caddr_t *)&dummy_mr) != XCNOENT)
++			{
++				if (mr)
++				{
++					/* the parent menu */
++					pops->pos_hints.is_menu_relative =
++						True;
++					pops->pos_hints.menu_width =
++						MR_WIDTH(mr);
++				}
++			}
++		}
++		else
++		{
++			/* no context string */
++			fHasContext = False;
++		}
++
++		if (tok)
++		{
++			free(tok);
++		}
++		if (fHasContext)
++		{
++			taction = naction;
++		}
++		else
++		{
++			naction = action;
++		}
++
++		if (fRectangleContext)
++		{
++			if (!pops->pos_hints.has_screen_origin)
++			{
++				/* xinerama: use global screen as reference */
++				pops->pos_hints.has_screen_origin = 1;
++				pops->pos_hints.screen_origin_x = -1;
++				pops->pos_hints.screen_origin_y = -1;
++			}
++			/* nothing else to do */
++		}
++		else if (!is_icon_context &&
++			 (!fHasContext || !context_window ||
++			  !XGetGeometry(
++				  dpy, context_window, &JunkRoot, &JunkX,
++				  &JunkY, (unsigned int*)&width,
++				  (unsigned int*)&height,
++				  (unsigned int*)&JunkBW,
++				  (unsigned int*)&JunkDepth) ||
++			  !XTranslateCoordinates(
++				  dpy, context_window, Scr.Root, 0, 0, &x, &y,
++				  &JunkChild)))
++		{
++			/* no window or could not get geometry */
++			if (FQueryPointer(
++				    dpy,Scr.Root, &JunkRoot, &JunkChild, &x,
++				    &y, &JunkX, &JunkY, &JunkMask) == False)
++			{
++				/* pointer is on a different screen - that's
++				 * okay here */
++				x = 0;
++				y = 0;
++			}
++			width = height = 1;
++			if (!pops->pos_hints.has_screen_origin)
++			{
++				/* xinerama: use screen with pinter as
++				 * reference */
++				pops->pos_hints.has_screen_origin = 1;
++				pops->pos_hints.screen_origin_x = x;
++				pops->pos_hints.screen_origin_y = y;
++			}
++		}
++		else
++		{
++			if (is_icon_context)
++			{
++				x = icon_g.x;
++				y = icon_g.y;
++				width = icon_g.width;
++				height = icon_g.height;
++			}
++			/* we have a context window */
++			if (fUseItemOffset)
++			{
++				y += MI_Y_OFFSET(mi);
++				height = MI_HEIGHT(mi);
++			}
++			if (!pops->pos_hints.has_screen_origin)
++			{
++				pops->pos_hints.has_screen_origin = 1;
++				if (fXineramaRoot)
++				{
++					/* use whole screen */
++					pops->pos_hints.screen_origin_x = -1;
++					pops->pos_hints.screen_origin_y = -1;
++				}
++				else if (context_window == Scr.Root)
++				{
++					/* xinerama: use screen that contains
++					 * the window center as reference */
++					if (!fev_get_evpos_or_query(
++						    dpy, context_window, e,
++						    &pops->pos_hints.
++						    screen_origin_x,
++						    &pops->pos_hints.
++						    screen_origin_y))
++					{
++						pops->pos_hints.
++							screen_origin_x = 0;
++						pops->pos_hints.
++							screen_origin_y = 0;
++					}
++					else
++					{
++						fscreen_scr_arg fscr;
++
++						fscr.xypos.x = pops->pos_hints.
++							screen_origin_x;
++						fscr.xypos.y = pops->pos_hints.
++							screen_origin_y;
++						FScreenGetScrRect(
++							&fscr, FSCREEN_XYPOS,
++							&x, &y, &width,
++							&height);
++					}
++				}
++				else
++				{
++					/* xinerama: use screen that contains
++					 * the window center as reference */
++					pops->pos_hints.screen_origin_x =
++						JunkX + width / 2;
++					pops->pos_hints.screen_origin_y =
++						JunkY + height / 2;
++				}
++			}
++		}
++
++		/* parse position arguments */
++		taction = get_one_menu_position_argument(
++			naction, x, width, &(pops->pos_hints.x),
++			&(pops->pos_hints.x_offset),
++			&(pops->pos_hints.x_factor),
++			&(pops->pos_hints.context_x_factor),
++			&pops->pos_hints.is_menu_relative);
++		if (pops->pos_hints.is_menu_relative)
++		{
++			pops->pos_hints.x = x;
++			if (pops->pos_hints.menu_width == 0 && mr)
++			{
++				pops->pos_hints.menu_width = MR_WIDTH(mr);
++			}
++		}
++		naction = get_one_menu_position_argument(
++			taction, y, height, &(pops->pos_hints.y), &dummy_int,
++			&(pops->pos_hints.y_factor), &dummy_float,
++			&dummy_flag);
++		if (naction == taction)
++		{
++			/* argument is missing or invalid */
++			if (fHasContext)
++			{
++				fvwm_msg(ERR, "get_menu_options",
++					 "invalid position arguments");
++			}
++			naction = action;
++			taction = action;
++			break;
++		}
++		taction = naction;
++		pops->flags.has_poshints = 1;
++		if (fValidPosHints == True &&
++		    pops->pos_hints.is_relative == True)
++		{
++			pops->pos_hints = last_saved_pos_hints.pos_hints;
++		}
++		/* we want to do this only once */
++		once_more = False;
++	} /* while */
++	if (is_action_empty)
++	{
++		if (!pops->pos_hints.has_screen_origin)
++		{
++			pops->pos_hints.has_screen_origin = 1;
++			if (!fev_get_evpos_or_query(
++				    dpy, Scr.Root, e,
++				    &pops->pos_hints.screen_origin_x,
++				    &pops->pos_hints.screen_origin_y))
++			{
++				pops->pos_hints.screen_origin_x = 0;
++				pops->pos_hints.screen_origin_y = 0;
++			}
++		}
++	}
++
++	if (!pops->flags.has_poshints && fValidPosHints)
++	{
++		pops->flags.has_poshints = 1;
++		pops->pos_hints = last_saved_pos_hints.pos_hints;
++		pops->pos_hints.is_relative = False;
++	}
++
++	action = naction;
++	/* to keep Purify silent */
++	pops->flags.do_select_in_place = 0;
++	/* parse additional options */
++	while (naction && *naction)
++	{
++		naction = GetNextToken(action, &tok);
++		if (!tok)
++		{
++			break;
++		}
++		if (StrEquals(tok, "WarpTitle"))
++		{
++			pops->flags.do_warp_title = 1;
++			pops->flags.do_not_warp = 0;
++		}
++		else if (StrEquals(tok, "NoWarp"))
++		{
++			pops->flags.do_warp_title = 0;
++			pops->flags.do_not_warp = 1;
++		}
++		else if (StrEquals(tok, "Fixed"))
++		{
++			pops->flags.is_fixed = 1;
++		}
++		else if (StrEquals(tok, "SelectInPlace"))
++		{
++			pops->flags.do_select_in_place = 1;
++		}
++		else if (StrEquals(tok, "SelectWarp"))
++		{
++			pops->flags.do_warp_on_select = 1;
++		}
++		else if (StrEquals(tok, "TearOffImmediately"))
++		{
++			pops->flags.do_tear_off_immediately = 1;
++		}
++		else
++		{
++			free (tok);
++			break;
++		}
++		action = naction;
++		free (tok);
++	}
++	if (!pops->flags.do_select_in_place)
++	{
++		pops->flags.do_warp_on_select = 0;
++	}
++
++	return action;
++}
++
++/* ---------------------------- new menu loop code ------------------------- */
++
++#if 0
++/*!!!*/
++typedef enum
++{
++	MTR_XEVENT = 0x1,
++	MTR_FAKE_ENTER_ITEM = 0x2,
++	MTR_PROPAGATE_XEVENT_UP = 0x4,
++	MTR_PROPAGATE_XEVENT_DOWN = 0x8,
++	MTR_POPUP_TIMEOUT = 0x10,
++	MTR_POPDOWN_TIMEOUT = 0x20
++} mloop_trigger_type_t;
++
++typedef_struct
++{
++	mloop_trigger_type_t type;
++	XEvent trigger_ev;
++	int ticks_passed;
++} mloop_trigger_t;
++
++typedef_struct
++{
++	int popup_10ms;
++	int popdown_10ms;
++} mloop_timeouts_t;
++
++typedef struct
++{
++	MenuRoot *current_menu;
++	XEvent *in_ev;
++	struct
++	{
++		unsigned do_fake_enter_item : 1;
++		unsigned do_propagete_event_up : 1;
++		unsigned do_propagete_event_down : 1;
++	} flags;
++} mloop_get_trigger_input_t;
++
++/*!!!static*/
++mloop_trigger_type_t __mloop_get_trigger(
++	mloop_trigger_t *ret_trigger, mloop_timeouts_t *io_timeouts,
++	const mloop_get_trigger_input_t * const in,
++	{
++		if (in_out->in_flags->do_propagate_event_down)
++		{
++			return MTR_PROPAGATE_XEVENT_DOWN;
++		}
++		else if (in_out->in_flags->do_propagate_event_up)
++		{
++			if (a != b)
++			{
++				return MTR_PROPAGATE_XEVENT_UP;
++			}
++			else
++			{
++			}
++			/*!!!return propagate up*/
++			/*!!!*/
++		}
++		/*!!!read event or wait for timeout*/
++		while (0/*!!!not finished*/)
++		{
++			/*!!!rc = 0*/
++			if (0/*!!!wait for tiomeout*/)
++			{
++				/*!!!check for event*/
++			}
++			else
++			{
++				/*!!!block for event*/
++			}
++			if (0/*got event*/)
++			{
++				/*!!!rc = MTR_XEVENT*/
++			}
++			if (0/*!!!popup timed out;break*/)
++			{
++				/*!!!rc = MTR_POPUP;break*/
++			}
++			if (0/*!!!popdown timed out;break*/)
++			{
++				/*!!!rc = MTR_POPDOWN;break*/
++			}
++			/*!!!sleep*/
++		}
++		if (0/*!!!rc == MTR_XEVENT && evtype == MotionNotify*/)
++		{
++			/*!!!eat up further MotionNotify events*/
++		}
++
++		return 0/*!!!rc*/;
++	}
++
++	/*!!!static*/
++	void __menu_loop_new(
++		MenuParameters *pmp, MenuReturn *pmret, double_keypress *pdkp)
++	{
++		mloop_evh_input_t mei;
++#if 0
++		mloop_ret_code_t mloop_ret;
++#endif
++		mloop_evh_data_t med;
++		mloop_static_info_t msi;
++		MenuOptions mops;
++		Bool is_finished;
++
++		/*!!!init menu loop*/
++		__mloop_init(pmp, pmret, &mei, &med, &msi, &mops);
++		for (is_finished = False; !is_finished; )
++		{
++			mloop_trigger_type_t mtr;
++
++			mtr = __mloop_get_trigger(
++				pmp, pmret, &mei, &med, &msi);
++			switch (mtr)
++			{
++			case MTR_XEVENT:
++				/*!!!handle event*/
++				break;
++			case MTR_FAKE_ENTER_ITEM:
++				/*!!!fake enter item*/
++				break;
++			case MTR_PROPAGATE_XEVENT_UP:
++				/*!!!handle propagation*/
++				break;
++			case MTR_PROPAGATE_XEVENT_DOWN:
++				/*!!!handle propagation*/
++				break;
++			case MTR_POPUP_TIMEOUT:
++				/*!!!handle popup*/
++				break;
++			case MTR_POPDOWN_TIMEOUT:
++				/*!!!handle popdown*/
++				break;
++			}
++
++
++
++
++
++#if 0
++			mloop_ret = __mloop_handle_event(
++				pmp, pmret, pdkp, &mei, &med, &msi);
++			switch (mloop_ret)
++			{
++			case MENU_MLOOP_RET_LOOP:
++				continue;
++			case MENU_MLOOP_RET_END:
++				is_finished = True;
++				break;
++			default:
++				break;
++			}
++			/* Now handle new menu items, whether it is from a
++			 * keypress or a pointer motion event. */
++			if (med.mi != NULL)
++			{
++				mloop_ret = __mloop_handle_action_with_mi(
++					pmp, pmret, pdkp, &mei, &med, &msi,
++					&mops);
++			}
++			else
++			{
++				mloop_ret = __mloop_handle_action_without_mi(
++					pmp, pmret, pdkp, &mei, &med, &msi,
++					&mops);
++			}
++			if (mloop_ret == MENU_MLOOP_RET_END)
++			{
++				is_finished = True;
++			}
++			XFlush(dpy);
++#endif
++		}
++		__mloop_exit(pmp, pmret, pdkp, &mei, &med, &msi, &mops);
++
++		return;
++	}
++#endif
+diff -U10 -Naupr fvwm-2.5.21-03/fvwm/menustyle.c fvwm-2.5.21-04/fvwm/menustyle.c
+--- fvwm-2.5.21-03/fvwm/menustyle.c	2007-03-03 13:17:58.000000000 +0100
++++ fvwm-2.5.21-04/fvwm/menustyle.c	2007-03-03 13:18:29.000000000 +0100
+@@ -395,21 +395,21 @@ static int menustyle_get_styleopt_index(
+ 		"VerticalTitleSpacing",
+ 		"MenuColorset", "ActiveColorset", "GreyedColorset",
+ 		"SelectOnRelease",
+ 		"PopdownImmediately", "PopdownDelayed",
+ 		"PopdownDelay",
+ 		"PopupActiveArea",
+ 		"PopupIgnore", "PopupClose",
+ 		"MouseWheel", "ScrollOffPage",
+ 		"TrianglesUseFore",
+ 		"TitleColorset", "HilightTitleBack",
+-		"TitleFont",
++		"TitleFont", "FlatSeparators",
+ 		NULL
+ 	};
+ 
+ 	return GetTokenIndex(option, optlist, 0, NULL);
+ }
+ 
+ static void change_or_make_gc(GC *gc, unsigned long gcm, XGCValues *gcv)
+ {
+ 	if (*gc != None)
+ 	{
+@@ -870,20 +870,21 @@ MenuStyle *menustyle_parse_style(F_CMD_A
+ 			ST_HAS_ACTIVE_FORE(tmpms) = 0;
+ 			ST_HAS_ACTIVE_BACK(tmpms) = 0;
+ 			ST_DO_POPUP_AS(tmpms) = MDP_POST_MENU;
+ 			ST_DOUBLE_CLICK_TIME(tmpms) = DEFAULT_MENU_CLICKTIME;
+ 			ST_POPUP_DELAY(tmpms) = DEFAULT_POPUP_DELAY;
+ 			ST_POPDOWN_DELAY(tmpms) = DEFAULT_POPDOWN_DELAY;
+ 			ST_MOUSE_WHEEL(tmpms) = MMW_POINTER;
+ 			ST_SCROLL_OFF_PAGE(tmpms) = 1;
+ 			ST_DO_HILIGHT_TITLE_BACK(tmpms) = 0;
+ 			ST_USING_DEFAULT_TITLEFONT(tmpms) = True;
++			ST_DO_FLAT_SEPARATOR(tmpms) = 0;
+ 			has_gc_changed = True;
+ 			option = "fvwm";
+ 		}
+ 		else
+ 		{
+ 			/* Read next option specification (delimited by a comma
+ 			 * or \0). */
+ 			args = action;
+ 			action = GetQuotedString(
+ 				action, &optstring, ",", NULL, NULL, NULL);
+@@ -1557,21 +1558,23 @@ MenuStyle *menustyle_parse_style(F_CMD_A
+ 				ST_PTITLEFONT(tmpms) = Scr.DefaultFont;
+ 				ST_USING_DEFAULT_TITLEFONT(tmpms) = True;
+ 			}
+ 			else
+ 			{
+ 				ST_PTITLEFONT(tmpms) = new_font;
+ 				ST_USING_DEFAULT_TITLEFONT(tmpms) = False;
+ 			}
+ 			has_gc_changed = True;
+ 			break;
+-
++		case 62: /* FlatSeparators */
++			ST_DO_FLAT_SEPARATOR(tmpms) = on;
++			break;
+ 
+ #if 0
+ 		case 99: /* PositionHints */
+ 			/* to be implemented */
+ 			break;
+ #endif
+ 
+ 		default:
+ 			fvwm_msg(ERR, "NewMenuStyle", "unknown option '%s'",
+ 				 poption);
+@@ -1811,20 +1814,22 @@ void menustyle_copy(MenuStyle *origms, M
+ 	/* PopdownDelay */
+ 	ST_POPDOWN_DELAY(destms) = ST_POPDOWN_DELAY(origms);
+ 	/* Scroll */
+ 	ST_MOUSE_WHEEL(destms) = ST_MOUSE_WHEEL(origms);
+ 	/* ScrollOffPage */
+ 	ST_SCROLL_OFF_PAGE(destms) = ST_SCROLL_OFF_PAGE(origms);
+ 	/* TrianglesUseFore */
+ 	ST_TRIANGLES_USE_FORE(destms) = ST_TRIANGLES_USE_FORE(origms);
+ 	/* Title */
+ 	ST_DO_HILIGHT_TITLE_BACK(destms) = ST_DO_HILIGHT_TITLE_BACK(origms);
++	/* FlatSeparators */
++	ST_DO_FLAT_SEPARATOR(destms) = ST_DO_FLAT_SEPARATOR(origms);
+ 
+ 	menustyle_update(destms);
+ 
+ 	return;
+ }
+ 
+ /* ---------------------------- builtin commands --------------------------- */
+ 
+ void CMD_CopyMenuStyle(F_CMD_ARGS)
+ {
+diff -U10 -Naupr fvwm-2.5.21-03/fvwm/menustyle.c~ fvwm-2.5.21-04/fvwm/menustyle.c~
+--- fvwm-2.5.21-03/fvwm/menustyle.c~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-04/fvwm/menustyle.c~	2007-03-03 13:18:21.000000000 +0100
+@@ -0,0 +1,1936 @@
++/* -*-c-*- */
++/* This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* ---------------------------- included header files ---------------------- */
++
++#include "config.h"
++
++#include <stdio.h>
++#include <assert.h>
++#include <X11/keysym.h>
++
++#include "libs/fvwmlib.h"
++#include "libs/Picture.h"
++#include "libs/PictureUtils.h"
++#include "fvwm.h"
++#include "externs.h"
++#include "execcontext.h"
++#include "functions.h"
++#include "misc.h"
++#include "screen.h"
++#include "colorset.h"
++#include "menustyle.h"
++
++/* ---------------------------- local definitions -------------------------- */
++
++/* ---------------------------- local macros ------------------------------- */
++
++/* ---------------------------- imports ------------------------------------ */
++
++/* ---------------------------- included code files ------------------------ */
++
++/* ---------------------------- local types -------------------------------- */
++
++/* ---------------------------- forward declarations ----------------------- */
++
++/* ---------------------------- local variables ---------------------------- */
++
++static MenuStyle *default_menu_style;
++
++/* ---------------------------- exported variables (globals) --------------- */
++
++/* ---------------------------- local functions ---------------------------- */
++
++static void menustyle_free_face(MenuFace *mf)
++{
++	switch (mf->type)
++	{
++	case GradientMenu:
++		if (Pdepth <= 8 && mf->u.grad.npixels > 0 &&
++		    !mf->u.grad.do_dither)
++		{
++			Pixel *p;
++			int i;
++
++			p = (Pixel *)safemalloc(
++				mf->u.grad.npixels * sizeof(Pixel));
++			for(i=0; i < mf->u.grad.npixels; i++)
++			{
++				p[i] = mf->u.grad.xcs[i].pixel;
++			}
++			PictureFreeColors(
++				dpy, Pcmap, p, mf->u.grad.npixels, 0, False);
++			free(p);
++		}
++		free(mf->u.grad.xcs);
++		mf->u.grad.xcs = NULL;
++		break;
++	case PixmapMenu:
++	case TiledPixmapMenu:
++		if (mf->u.p)
++		{
++			PDestroyFvwmPicture(dpy, mf->u.p);
++		}
++		mf->u.p = NULL;
++		break;
++	case SolidMenu:
++		fvwmlib_free_colors(dpy, &mf->u.back, 1, True);
++	default:
++		break;
++	}
++	mf->type = SimpleMenu;
++
++	return;
++}
++
++static void menustyle_copy_face(MenuFace *destmf, MenuFace *origmf)
++{
++	FvwmPictureAttributes fpa;
++	int i;
++
++	menustyle_free_face(destmf);
++	destmf->type = SimpleMenu;
++	switch (origmf->type)
++	{
++	case SolidMenu:
++		fvwmlib_copy_color(
++			dpy, &destmf->u.back, &origmf->u.back, False, True);
++		destmf->type = SolidMenu;
++		break;
++	case GradientMenu:
++		destmf->u.grad.xcs =
++			(XColor *)safemalloc(sizeof(XColor) *
++					     origmf->u.grad.npixels);
++		memcpy(destmf->u.grad.xcs,
++		       origmf->u.grad.xcs,
++		       sizeof(XColor) * origmf->u.grad.npixels);
++		for (i = 0; i<origmf->u.grad.npixels;i++)
++		{
++			fvwmlib_clone_color(origmf->u.grad.xcs[i].pixel);
++		}
++
++		destmf->u.grad.npixels = origmf->u.grad.npixels;
++		destmf->u.grad.do_dither = origmf->u.grad.do_dither;
++		destmf->type = GradientMenu;
++		destmf->gradient_type = origmf->gradient_type;
++		break;
++	case PixmapMenu:
++	case TiledPixmapMenu:
++		fpa.mask = (Pdepth <= 8)?  FPAM_DITHER:0;
++		destmf->u.p = PCacheFvwmPicture(
++			dpy, Scr.NoFocusWin, NULL, origmf->u.p->name,
++			fpa);
++		fvwmlib_copy_color(
++			dpy, &destmf->u.back, &origmf->u.back, False,True);
++		destmf->type = origmf->type;
++		break;
++	default:
++		break;
++	}
++}
++
++/*
++ *
++ * Reads a menu face line into a structure (veliaa at rpi.edu)
++ *
++ */
++static Boolean menustyle_parse_face(char *s, MenuFace *mf, int verbose)
++{
++	char *style;
++	char *token;
++	char *action = s;
++	FvwmPictureAttributes fpa;
++
++	s = GetNextToken(s, &style);
++	if (style && strncasecmp(style, "--", 2) == 0)
++	{
++		free(style);
++		return True;
++	}
++
++	menustyle_free_face(mf);
++	mf->type = SimpleMenu;
++
++	/* determine menu style */
++	if (!style)
++	{
++		return True;
++	}
++	else if (StrEquals(style,"Solid"))
++	{
++		s = GetNextToken(s, &token);
++		if (token)
++		{
++			mf->type = SolidMenu;
++			mf->u.back = GetColor(token);
++			free(token);
++		}
++		else
++		{
++			if (verbose)
++			{
++				fvwm_msg(ERR, "menustyle_parse_face",
++					 "no color given for Solid face type:"
++					 " %s", action);
++			}
++			free(style);
++			return False;
++		}
++	}
++
++	else if (StrEquals(style+1, "Gradient"))
++	{
++		char **s_colors;
++		int npixels, nsegs, *perc;
++		XColor *xcs;
++
++		if (!IsGradientTypeSupported(style[0]))
++		{
++			return False;
++		}
++
++		/* translate the gradient string into an array of colors etc */
++		npixels = ParseGradient(s, NULL, &s_colors, &perc, &nsegs);
++		if (npixels <= 0)
++		{
++			return False;
++		}
++		/* dither ? */
++		mf->u.grad.do_dither = False;
++		if (Pdepth <= 8)
++		{
++			mf->u.grad.do_dither = True;
++		}
++		/* grab the colors */
++		xcs = AllocAllGradientColors(
++			s_colors, perc, nsegs, npixels, mf->u.grad.do_dither);
++		if (xcs == None)
++		{
++			return False;
++		}
++
++		mf->u.grad.xcs = xcs;
++		mf->u.grad.npixels = npixels;
++		mf->type = GradientMenu;
++		mf->gradient_type = toupper(style[0]);
++	}
++
++	else if (StrEquals(style,"Pixmap") || StrEquals(style,"TiledPixmap"))
++	{
++		s = GetNextToken(s, &token);
++		fpa.mask = (Pdepth <= 8)?  FPAM_DITHER:0;
++		if (token)
++		{
++			mf->u.p = PCacheFvwmPicture(
++				dpy, Scr.NoFocusWin, NULL, token, fpa);
++			if (mf->u.p == NULL)
++			{
++				if (verbose)
++				{
++					fvwm_msg(ERR, "menustyle_parse_face",
++						 "couldn't load pixmap %s",
++						 token);
++				}
++				free(token);
++				free(style);
++				return False;
++			}
++			free(token);
++			mf->type = (StrEquals(style,"TiledPixmap")) ?
++				TiledPixmapMenu : PixmapMenu;
++		}
++		else
++		{
++			if (verbose)
++			{
++				fvwm_msg(ERR, "menustyle_parse_face",
++					 "missing pixmap name for style %s",
++					 style);
++			}
++			free(style);
++			return False;
++		}
++	}
++	else
++	{
++		if (verbose)
++		{
++			fvwm_msg(
++				ERR,
++				"menustyle_parse_face", "unknown style %s: %s",
++				style, action);
++		}
++		free(style);
++		return False;
++	}
++	free(style);
++
++	return True;
++}
++
++static void parse_vertical_spacing_line(
++	char *args, signed char *above, signed char *below,
++	signed char above_default, signed char below_default)
++{
++	int val[2];
++
++	if (GetIntegerArguments(args, NULL, val, 2) != 2 ||
++	    val[0] < MIN_VERTICAL_SPACING || val[0] > MAX_VERTICAL_SPACING ||
++	    val[1] < MIN_VERTICAL_SPACING || val[1] > MAX_VERTICAL_SPACING)
++	{
++		/* illegal or missing parameters, return to default */
++		*above = above_default;
++		*below = below_default;
++		return;
++	}
++	*above = val[0];
++	*below = val[1];
++
++	return;
++}
++
++static MenuStyle *menustyle_parse_old_style(F_CMD_ARGS)
++{
++	char *buffer, *rest;
++	char *fore, *back, *stipple, *font, *style, *animated;
++	MenuStyle *ms = NULL;
++
++	rest = GetNextToken(action,&fore);
++	rest = GetNextToken(rest,&back);
++	rest = GetNextToken(rest,&stipple);
++	rest = GetNextToken(rest,&font);
++	rest = GetNextToken(rest,&style);
++	rest = GetNextToken(rest,&animated);
++
++	if (!fore || !back || !stipple || !font || !style)
++	{
++		fvwm_msg(ERR, "menustyle_parse_old_style",
++			 "error in %s style specification", action);
++	}
++	else
++	{
++		buffer = (char *)alloca(strlen(action) + 100);
++		sprintf(buffer,
++			"* \"%s\", Foreground \"%s\", Background \"%s\", "
++			"Greyed \"%s\", Font \"%s\", \"%s\"",
++			style, fore, back, stipple, font,
++			(animated && StrEquals(animated, "anim")) ?
++			"Animation" : "AnimationOff");
++		fvwm_msg(OLD, "menustyle_parse_old_style",
++			 "The old MenuStyle snytax has been deprecated.  "
++			 "Use 'MenuStyle %s' instead of 'MenuStyle %s'\n",
++			 buffer, action);
++		action = buffer;
++		ms = menustyle_parse_style(F_PASS_ARGS);
++	}
++
++	if (fore)
++	{
++		free(fore);
++	}
++	if (back)
++	{
++		free(back);
++	}
++	if (stipple)
++	{
++		free(stipple);
++	}
++	if (font)
++	{
++		free(font);
++	}
++	if (style)
++	{
++		free(style);
++	}
++	if (animated)
++	{
++		free(animated);
++	}
++
++	return ms;
++}
++
++static int menustyle_get_styleopt_index(char *option)
++{
++	char *optlist[] = {
++		"fvwm", "mwm", "win",
++		"Foreground", "Background", "Greyed",
++		"HilightBack", "HilightBackOff",
++		"ActiveFore", "ActiveForeOff",
++		"Hilight3DThick", "Hilight3DThin", "Hilight3DOff",
++		"Animation", "AnimationOff",
++		"Font",
++		"MenuFace",
++		"PopupDelay", "PopupOffset",
++		"TitleWarp", "TitleWarpOff",
++		"TitleUnderlines0", "TitleUnderlines1", "TitleUnderlines2",
++		"SeparatorsLong", "SeparatorsShort",
++		"TrianglesSolid", "TrianglesRelief",
++		"PopupImmediately", "PopupDelayed",
++		"DoubleClickTime",
++		"SidePic", "SideColor",
++		"PopupAsRootmenu", "PopupAsSubmenu",
++		"RemoveSubmenus", "HoldSubmenus",
++		"SubmenusRight", "SubmenusLeft",
++		"BorderWidth",
++		"Hilight3DThickness",
++		"ItemFormat",
++		"AutomaticHotkeys", "AutomaticHotkeysOff",
++		"VerticalItemSpacing",
++		"VerticalTitleSpacing",
++		"MenuColorset", "ActiveColorset", "GreyedColorset",
++		"SelectOnRelease",
++		"PopdownImmediately", "PopdownDelayed",
++		"PopdownDelay",
++		"PopupActiveArea",
++		"PopupIgnore", "PopupClose",
++		"MouseWheel", "ScrollOffPage",
++		"TrianglesUseFore",
++		"TitleColorset", "HilightTitleBack",
++		"TitleFont",
++		NULL
++	};
++
++	return GetTokenIndex(option, optlist, 0, NULL);
++}
++
++static void change_or_make_gc(GC *gc, unsigned long gcm, XGCValues *gcv)
++{
++	if (*gc != None)
++	{
++		XChangeGC(dpy, *gc, gcm, gcv);
++	}
++	else
++	{
++		*gc = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, gcv);
++	}
++
++	return;
++}
++
++/* ---------------------------- interface functions ------------------------ */
++
++MenuStyle *menustyle_get_default_style(void)
++{
++	return default_menu_style;
++}
++
++void menustyle_free(MenuStyle *ms)
++{
++	MenuStyle *before = default_menu_style;
++
++	if (!ms)
++	{
++		return;
++	}
++	menustyle_free_face(&ST_FACE(ms));
++	if (FORE_GC(ST_MENU_INACTIVE_GCS(ms)))
++	{
++		XFreeGC(dpy, FORE_GC(ST_MENU_INACTIVE_GCS(ms)));
++	}
++	if (FORE_GC(ST_MENU_ACTIVE_GCS(ms)))
++	{
++		XFreeGC(dpy, FORE_GC(ST_MENU_ACTIVE_GCS(ms)));
++	}
++	if (BACK_GC(ST_MENU_ACTIVE_GCS(ms)))
++	{
++		XFreeGC(dpy, BACK_GC(ST_MENU_ACTIVE_GCS(ms)));
++	}
++	if (HILIGHT_GC(ST_MENU_ACTIVE_GCS(ms)))
++	{
++		XFreeGC(dpy, HILIGHT_GC(ST_MENU_ACTIVE_GCS(ms)));
++	}
++	if (SHADOW_GC(ST_MENU_ACTIVE_GCS(ms)))
++	{
++		XFreeGC(dpy, SHADOW_GC(ST_MENU_ACTIVE_GCS(ms)));
++	}
++	if (HILIGHT_GC(ST_MENU_INACTIVE_GCS(ms)))
++	{
++		XFreeGC(dpy, HILIGHT_GC(ST_MENU_INACTIVE_GCS(ms)));
++	}
++	if (SHADOW_GC(ST_MENU_INACTIVE_GCS(ms)))
++	{
++		XFreeGC(dpy, SHADOW_GC(ST_MENU_INACTIVE_GCS(ms)));
++	}
++	if (FORE_GC(ST_MENU_STIPPLE_GCS(ms)))
++	{
++		XFreeGC(dpy, FORE_GC(ST_MENU_STIPPLE_GCS(ms)));
++	}
++	if (FORE_GC(ST_MENU_TITLE_GCS(ms)))
++	{
++		XFreeGC(dpy, FORE_GC(ST_MENU_TITLE_GCS(ms)));
++	}
++	if (BACK_GC(ST_MENU_TITLE_GCS(ms)))
++	{
++		XFreeGC(dpy, BACK_GC(ST_MENU_TITLE_GCS(ms)));
++	}
++	if (HILIGHT_GC(ST_MENU_TITLE_GCS(ms)))
++	{
++		XFreeGC(dpy, HILIGHT_GC(ST_MENU_TITLE_GCS(ms)));
++	}
++	if (SHADOW_GC(ST_MENU_TITLE_GCS(ms)))
++	{
++		XFreeGC(dpy, SHADOW_GC(ST_MENU_TITLE_GCS(ms)));
++	}
++	if (ST_SIDEPIC(ms))
++	{
++		PDestroyFvwmPicture(dpy, ST_SIDEPIC(ms));
++	}
++	if (ST_HAS_SIDE_COLOR(ms) == 1)
++	{
++		fvwmlib_free_colors(dpy, &ST_SIDE_COLOR(ms), 1, True);
++	}
++	if (ST_PSTDFONT(ms) && !ST_USING_DEFAULT_FONT(ms))
++	{
++		FlocaleUnloadFont(dpy, ST_PSTDFONT(ms));
++	}
++	if (ST_PTITLEFONT(ms) && !ST_USING_DEFAULT_TITLEFONT(ms))
++	{
++		FlocaleUnloadFont(dpy, ST_PTITLEFONT(ms));
++	}
++	if (ST_ITEM_FORMAT(ms))
++	{
++		free(ST_ITEM_FORMAT(ms));
++	}
++
++	fvwmlib_free_colors(dpy, &ST_MENU_COLORS(ms).back,1,True);
++	fvwmlib_free_colors(dpy, &ST_MENU_COLORS(ms).fore,1,True);
++	if (ST_HAS_STIPPLE_FORE(ms))
++	{
++		fvwmlib_free_colors(
++			dpy, &ST_MENU_STIPPLE_COLORS(ms).fore,1,True);
++	}
++	if (ST_HAS_ACTIVE_BACK(ms))
++	{
++		fvwmlib_free_colors(
++			dpy, &ST_MENU_ACTIVE_COLORS(ms).back,1,True);
++	}
++	if (ST_HAS_ACTIVE_FORE(ms))
++	{
++		fvwmlib_free_colors(
++			dpy, &ST_MENU_ACTIVE_COLORS(ms).fore,1,True);
++	}
++
++	while (ST_NEXT_STYLE(before) != ms)
++	{
++		/* Not too many checks, may segfault in race conditions */
++		before = ST_NEXT_STYLE(before);
++	}
++
++	ST_NEXT_STYLE(before) = ST_NEXT_STYLE(ms);
++	free(ST_NAME(ms));
++	free(ms);
++
++	return;
++}
++
++MenuStyle *menustyle_find(char *name)
++{
++	MenuStyle *ms = default_menu_style;
++
++	while (ms)
++	{
++		if (strcasecmp(ST_NAME(ms),name)==0)
++		{
++			return ms;
++		}
++		ms = ST_NEXT_STYLE(ms);
++	}
++
++	return NULL;
++}
++
++void menustyle_update(MenuStyle *ms)
++{
++	XGCValues gcv;
++	unsigned long gcm;
++	color_quad c_inactive;
++	color_quad c_active;
++	color_quad c_stipple;
++	color_quad c_title;
++	colorset_t *menu_cs = &Colorset[ST_CSET_MENU(ms)];
++	colorset_t *active_cs = &Colorset[ST_CSET_ACTIVE(ms)];
++	colorset_t *greyed_cs = &Colorset[ST_CSET_GREYED(ms)];
++	colorset_t *title_cs = &Colorset[ST_CSET_TITLE(ms)];
++
++	if (ST_USAGE_COUNT(ms) != 0)
++	{
++		fvwm_msg(ERR,"menustyle_update", "menu style %s is in use",
++			 ST_NAME(ms));
++		return;
++	}
++	ST_IS_UPDATED(ms) = 1;
++	if (ST_USING_DEFAULT_FONT(ms))
++	{
++		ST_PSTDFONT(ms) = Scr.DefaultFont;
++	}
++	if (ST_USING_DEFAULT_TITLEFONT(ms))
++	{
++		ST_PTITLEFONT(ms) = ST_PSTDFONT(ms);
++	}
++	/* calculate colors based on foreground */
++	if (!ST_HAS_ACTIVE_FORE(ms))
++	{
++		ST_MENU_ACTIVE_COLORS(ms).fore = ST_MENU_COLORS(ms).fore;
++	}
++	/* calculate colors based on background */
++	if (!ST_HAS_ACTIVE_BACK(ms))
++	{
++		ST_MENU_ACTIVE_COLORS(ms).back = ST_MENU_COLORS(ms).back;
++	}
++	if (!ST_HAS_STIPPLE_FORE(ms))
++	{
++		ST_MENU_STIPPLE_COLORS(ms).fore = ST_MENU_COLORS(ms).back;
++	}
++	ST_MENU_STIPPLE_COLORS(ms).back = ST_MENU_COLORS(ms).back;
++	/* prepare colours for changing the gcs */
++	if (ST_HAS_MENU_CSET(ms))
++	{
++		c_inactive.fore = menu_cs->fg;
++		c_inactive.back = menu_cs->bg;
++		c_inactive.hilight = menu_cs->hilite;
++		c_inactive.shadow = menu_cs->shadow;
++	}
++	else
++	{
++		c_inactive.fore = ST_MENU_COLORS(ms).fore;
++		c_inactive.back = ST_MENU_COLORS(ms).back;
++		if (Pdepth > 2)
++		{
++			c_inactive.hilight = GetHilite(ST_MENU_COLORS(ms).back);
++			c_inactive.shadow = GetShadow(ST_MENU_COLORS(ms).back);
++		}
++		else
++		{
++			c_inactive.hilight = GetColor(DEFAULT_HILIGHT_COLOR);
++			c_inactive.shadow = GetColor(DEFAULT_SHADOW_COLOR);
++		}
++	}
++	if (ST_HAS_ACTIVE_CSET(ms))
++	{
++		c_active.fore = active_cs->fg;
++		c_active.back = active_cs->bg;
++		c_active.hilight = active_cs->hilite;
++		c_active.shadow = active_cs->shadow;
++	}
++	else
++	{
++		c_active.fore = ST_MENU_ACTIVE_COLORS(ms).fore;
++		c_active.back = ST_MENU_ACTIVE_COLORS(ms).back;
++		if (Pdepth > 2)
++		{
++			c_active.hilight =
++				GetHilite(ST_MENU_ACTIVE_COLORS(ms).back);
++			c_active.shadow =
++				GetShadow(ST_MENU_ACTIVE_COLORS(ms).back);
++		}
++		else
++		{
++			c_active.hilight = GetColor(DEFAULT_HILIGHT_COLOR);
++			c_active.shadow = GetColor(DEFAULT_SHADOW_COLOR);
++		}
++	}
++	if (ST_HAS_GREYED_CSET(ms))
++	{
++		c_stipple.fore = greyed_cs->fg;
++		c_stipple.back = greyed_cs->fg;
++	}
++	else
++	{
++		c_stipple.fore = ST_MENU_STIPPLE_COLORS(ms).fore;
++		c_stipple.back = ST_MENU_STIPPLE_COLORS(ms).back;
++	}
++	if (ST_HAS_TITLE_CSET(ms))
++	{
++		c_title.fore = title_cs->fg;
++		c_title.back = title_cs->bg;
++		c_title.hilight = title_cs->hilite;
++		c_title.shadow = title_cs->shadow;
++	}
++	else
++	{
++		c_title.fore = c_inactive.fore;
++		c_title.back = c_inactive.back;
++		c_title.hilight = c_inactive.hilight;
++		c_title.shadow = c_inactive.shadow;
++	}
++	/* override hilighting colours if necessary */
++	if (!ST_DO_HILIGHT_FORE(ms))
++	{
++		c_active.fore = c_inactive.fore;
++	}
++	if (!ST_DO_HILIGHT_BACK(ms))
++	{
++		c_active.back = c_inactive.back;
++		c_active.hilight = c_inactive.hilight;
++		c_active.shadow = c_inactive.shadow;
++	}
++	if (!ST_DO_HILIGHT_TITLE_BACK(ms))
++	{
++		c_title.fore = c_inactive.fore;
++		c_title.back = c_inactive.back;
++		c_title.hilight = c_inactive.hilight;
++		c_title.shadow = c_inactive.shadow;
++	}
++	/* make GC's */
++	gcm = GCFunction|GCLineWidth|GCForeground|GCBackground;
++	if (ST_PSTDFONT(ms)->font != NULL)
++	{
++		gcm |= GCFont;
++		gcv.font = ST_PSTDFONT(ms)->font->fid;
++	}
++	gcv.function = GXcopy;
++	gcv.line_width = 0;
++	/* update inactive menu gcs */
++	gcv.foreground = c_inactive.fore;
++	gcv.background = c_inactive.back;
++	change_or_make_gc(&FORE_GC(ST_MENU_INACTIVE_GCS(ms)), gcm, &gcv);
++	BACK_GC(ST_MENU_INACTIVE_GCS(ms)) = FORE_GC(ST_MENU_INACTIVE_GCS(ms));
++	gcv.foreground = c_inactive.hilight;
++	gcv.background = c_inactive.shadow;
++	change_or_make_gc(&HILIGHT_GC(ST_MENU_INACTIVE_GCS(ms)), gcm, &gcv);
++	gcv.foreground = c_inactive.shadow;
++	gcv.background = c_inactive.hilight;
++	change_or_make_gc(&SHADOW_GC(ST_MENU_INACTIVE_GCS(ms)), gcm, &gcv);
++	/* update active menu gcs */
++	gcv.foreground = c_active.fore;
++	gcv.background = c_active.back;
++	change_or_make_gc(&FORE_GC(ST_MENU_ACTIVE_GCS(ms)), gcm, &gcv);
++	gcv.foreground = c_active.back;
++	gcv.background = c_active.fore;
++
++	if (ST_HAS_ACTIVE_CSET(ms) && active_cs->pixmap &&
++	    active_cs->pixmap_type == PIXMAP_TILED)
++	{
++		gcv.tile = active_cs->pixmap;
++		gcv.fill_style = FillTiled;
++		change_or_make_gc(&BACK_GC(ST_MENU_ACTIVE_GCS(ms)),
++				  gcm | GCFillStyle | GCTile , &gcv);
++	}
++	else
++	{
++		gcv.fill_style = FillSolid;
++		change_or_make_gc(&BACK_GC(ST_MENU_ACTIVE_GCS(ms)),
++				  gcm | GCFillStyle , &gcv);
++	}
++
++
++	gcv.foreground = c_active.hilight;
++	gcv.background = c_active.shadow;
++	change_or_make_gc(&HILIGHT_GC(ST_MENU_ACTIVE_GCS(ms)), gcm, &gcv);
++	gcv.foreground = c_active.shadow;
++	gcv.background = c_active.hilight;
++	change_or_make_gc(&SHADOW_GC(ST_MENU_ACTIVE_GCS(ms)), gcm, &gcv);
++	/* update title gcs */
++	if (ST_PTITLEFONT(ms)->font != NULL && ST_PSTDFONT(ms)->font == NULL)
++	{
++		if (ST_PSTDFONT(ms)->font == NULL)
++		{
++			gcm |= GCFont;
++		}
++		gcv.font = ST_PTITLEFONT(ms)->font->fid;
++	}
++	gcv.foreground = c_title.fore;
++	gcv.background = c_title.back;
++	change_or_make_gc(&FORE_GC(ST_MENU_TITLE_GCS(ms)), gcm, &gcv);
++	gcv.foreground = c_title.back;
++	gcv.background = c_title.fore;
++
++	if (ST_HAS_TITLE_CSET(ms) && title_cs->pixmap &&
++	    title_cs->pixmap_type == PIXMAP_TILED)
++	{
++		gcv.tile = title_cs->pixmap;
++		gcv.fill_style = FillTiled;
++		change_or_make_gc(&BACK_GC(ST_MENU_TITLE_GCS(ms)),
++				  gcm | GCFillStyle | GCTile , &gcv);
++	}
++	else
++	{
++		gcv.fill_style = FillSolid;
++		change_or_make_gc(&BACK_GC(ST_MENU_TITLE_GCS(ms)),
++				  gcm | GCFillStyle , &gcv);
++	}
++
++	gcv.foreground = c_title.hilight;
++	gcv.background = c_title.shadow;
++	change_or_make_gc(&HILIGHT_GC(ST_MENU_TITLE_GCS(ms)), gcm, &gcv);
++	gcv.foreground = c_title.shadow;
++	gcv.background = c_title.hilight;
++	change_or_make_gc(&SHADOW_GC(ST_MENU_TITLE_GCS(ms)), gcm, &gcv);
++	/* update stipple menu gcs */
++	SHADOW_GC(ST_MENU_STIPPLE_GCS(ms)) =
++		SHADOW_GC(ST_MENU_INACTIVE_GCS(ms));
++	if (Pdepth < 2)
++	{
++		gcv.fill_style = FillStippled;
++		gcv.stipple = Scr.gray_bitmap;
++		/* no need to reset fg/bg, FillStipple wins */
++		gcm |= GCStipple | GCFillStyle;
++		HILIGHT_GC(ST_MENU_STIPPLE_GCS(ms)) =
++			SHADOW_GC(ST_MENU_INACTIVE_GCS(ms));
++	}
++	else
++	{
++		gcv.foreground = c_stipple.fore;
++		gcv.background = c_stipple.back;
++		HILIGHT_GC(ST_MENU_STIPPLE_GCS(ms)) =
++			HILIGHT_GC(ST_MENU_INACTIVE_GCS(ms));
++	}
++	change_or_make_gc(&FORE_GC(ST_MENU_STIPPLE_GCS(ms)), gcm, &gcv);
++	BACK_GC(ST_MENU_STIPPLE_GCS(ms)) = BACK_GC(ST_MENU_INACTIVE_GCS(ms));
++
++	return;
++}
++
++MenuStyle *menustyle_parse_style(F_CMD_ARGS)
++{
++	char *name;
++	char *option = NULL;
++	char *poption = NULL;
++	char *optstring = NULL;
++	char *nextarg;
++	char *args = NULL;
++	char *arg1;
++	int on;
++	MenuStyle *ms;
++	MenuStyle *tmpms;
++	Bool is_initialised = True;
++	Bool has_gc_changed = False;
++	Bool is_default_style = False;
++	int val[2];
++	int n;
++	FlocaleFont *new_font = NULL;
++	int i;
++	KeyCode keycode;
++	FvwmPictureAttributes fpa;
++
++	action = GetNextToken(action, &name);
++	if (!name)
++	{
++		fvwm_msg(ERR, "NewMenuStyle",
++			 "error in %s style specification",action);
++		return NULL;
++	}
++
++	ms = menustyle_find(name);
++	if (ms && ST_USAGE_COUNT(ms) != 0)
++	{
++		fvwm_msg(ERR,"NewMenuStyle", "menu style %s is in use", name);
++		return ms;
++	}
++	tmpms = (MenuStyle *)safemalloc(sizeof(MenuStyle));
++	if (ms)
++	{
++		/* copy the structure over our temporary menu face. */
++		memcpy(tmpms, ms, sizeof(MenuStyle));
++		if (ms == default_menu_style)
++		{
++			is_default_style = True;
++		}
++		free(name);
++	}
++	else
++	{
++		memset(tmpms, 0, sizeof(MenuStyle));
++		ST_NAME(tmpms) = name;
++		is_initialised = False;
++	}
++	ST_IS_UPDATED(tmpms) = 1;
++
++	/* Parse the options. */
++	while (!is_initialised || (action && *action))
++	{
++	  	on = 1;
++		if (!is_initialised)
++		{
++			/* some default configuration goes here for the new
++			 * menu style */
++			ST_MENU_COLORS(tmpms).back =
++				GetColor(DEFAULT_BACK_COLOR);
++			ST_MENU_COLORS(tmpms).fore =
++				GetColor(DEFAULT_FORE_COLOR);
++			ST_PSTDFONT(tmpms) = Scr.DefaultFont;
++			ST_USING_DEFAULT_FONT(tmpms) = True;
++			ST_FACE(tmpms).type = SimpleMenu;
++			ST_HAS_ACTIVE_FORE(tmpms) = 0;
++			ST_HAS_ACTIVE_BACK(tmpms) = 0;
++			ST_DO_POPUP_AS(tmpms) = MDP_POST_MENU;
++			ST_DOUBLE_CLICK_TIME(tmpms) = DEFAULT_MENU_CLICKTIME;
++			ST_POPUP_DELAY(tmpms) = DEFAULT_POPUP_DELAY;
++			ST_POPDOWN_DELAY(tmpms) = DEFAULT_POPDOWN_DELAY;
++			ST_MOUSE_WHEEL(tmpms) = MMW_POINTER;
++			ST_SCROLL_OFF_PAGE(tmpms) = 1;
++			ST_DO_HILIGHT_TITLE_BACK(tmpms) = 0;
++			ST_USING_DEFAULT_TITLEFONT(tmpms) = True;
++			has_gc_changed = True;
++			option = "fvwm";
++		}
++		else
++		{
++			/* Read next option specification (delimited by a comma
++			 * or \0). */
++			args = action;
++			action = GetQuotedString(
++				action, &optstring, ",", NULL, NULL, NULL);
++			if (!optstring)
++			{
++				break;
++			}
++			args = GetNextToken(optstring, &option);
++			if (!option)
++			{
++				free(optstring);
++				break;
++			}
++			nextarg = GetNextToken(args, &arg1);
++		}
++		poption = option;
++		while (poption[0] == '!')
++		{
++			on ^= 1;
++			poption++;
++		}
++		switch((i = menustyle_get_styleopt_index(poption)))
++		{
++		case 0: /* fvwm */
++		case 1: /* mwm */
++		case 2: /* win */
++			if (i == 0)
++			{
++				ST_POPUP_OFFSET_PERCENT(tmpms) = 67;
++				ST_POPUP_OFFSET_ADD(tmpms) = 0;
++				ST_DO_POPUP_IMMEDIATELY(tmpms) = 0;
++				ST_DO_WARP_TO_TITLE(tmpms) = 1;
++				ST_DO_UNMAP_SUBMENU_ON_POPDOWN(tmpms) = 0;
++				ST_RELIEF_THICKNESS(tmpms) = 1;
++				ST_TITLE_UNDERLINES(tmpms) = 1;
++				ST_HAS_LONG_SEPARATORS(tmpms) = 0;
++				ST_HAS_TRIANGLE_RELIEF(tmpms) = 1;
++				ST_DO_HILIGHT_BACK(tmpms) = 0;
++				ST_DO_HILIGHT_FORE(tmpms) = 0;
++			}
++			else if (i == 1)
++			{
++				ST_POPUP_OFFSET_PERCENT(tmpms) = 100;
++				ST_POPUP_OFFSET_ADD(tmpms) =
++					-DEFAULT_MENU_BORDER_WIDTH - 1;
++				ST_DO_POPUP_IMMEDIATELY(tmpms) = 1;
++				ST_DO_WARP_TO_TITLE(tmpms) = 0;
++				ST_DO_UNMAP_SUBMENU_ON_POPDOWN(tmpms) = 0;
++				ST_RELIEF_THICKNESS(tmpms) = 2;
++				ST_TITLE_UNDERLINES(tmpms) = 2;
++				ST_HAS_LONG_SEPARATORS(tmpms) = 1;
++				ST_HAS_TRIANGLE_RELIEF(tmpms) = 1;
++				ST_DO_HILIGHT_BACK(tmpms) = 0;
++				ST_DO_HILIGHT_FORE(tmpms) = 0;
++			}
++			else /* i == 2 */
++			{
++				ST_POPUP_OFFSET_PERCENT(tmpms) = 100;
++				ST_POPUP_OFFSET_ADD(tmpms) =
++					-DEFAULT_MENU_BORDER_WIDTH - 3;
++				ST_DO_POPUP_IMMEDIATELY(tmpms) = 1;
++				ST_DO_WARP_TO_TITLE(tmpms) = 0;
++				ST_DO_UNMAP_SUBMENU_ON_POPDOWN(tmpms) = 1;
++				ST_RELIEF_THICKNESS(tmpms) = 0;
++				ST_TITLE_UNDERLINES(tmpms) = 1;
++				ST_HAS_LONG_SEPARATORS(tmpms) = 0;
++				ST_HAS_TRIANGLE_RELIEF(tmpms) = 0;
++				ST_DO_HILIGHT_BACK(tmpms) = 1;
++				ST_DO_HILIGHT_FORE(tmpms) = 1;
++			}
++
++			/* common settings */
++			ST_CSET_MENU(tmpms) = 0;
++			ST_HAS_MENU_CSET(tmpms) = 0;
++			ST_CSET_ACTIVE(tmpms) = 0;
++			ST_HAS_ACTIVE_CSET(tmpms) = 0;
++			ST_CSET_GREYED(tmpms) = 0;
++			ST_HAS_GREYED_CSET(tmpms) = 0;
++			ST_BORDER_WIDTH(tmpms) = DEFAULT_MENU_BORDER_WIDTH;
++			ST_ACTIVE_AREA_PERCENT(tmpms) =
++				DEFAULT_MENU_POPUP_NOW_RATIO;
++			ST_ITEM_GAP_ABOVE(tmpms) =
++				DEFAULT_MENU_ITEM_TEXT_Y_OFFSET;
++			ST_ITEM_GAP_BELOW(tmpms) =
++				DEFAULT_MENU_ITEM_TEXT_Y_OFFSET2;
++			ST_TITLE_GAP_ABOVE(tmpms) =
++				DEFAULT_MENU_TITLE_TEXT_Y_OFFSET;
++			ST_TITLE_GAP_BELOW(tmpms) =
++				DEFAULT_MENU_TITLE_TEXT_Y_OFFSET2;
++			ST_USE_LEFT_SUBMENUS(tmpms) = 0;
++			ST_IS_ANIMATED(tmpms) = 0;
++			ST_USE_AUTOMATIC_HOTKEYS(tmpms) = 0;
++			menustyle_free_face(&ST_FACE(tmpms));
++			ST_FACE(tmpms).type = SimpleMenu;
++			if (ST_PSTDFONT(tmpms) && !ST_USING_DEFAULT_FONT(tmpms))
++			{
++				FlocaleUnloadFont(dpy, ST_PSTDFONT(tmpms));
++			}
++			ST_PSTDFONT(tmpms) = Scr.DefaultFont;
++			ST_USING_DEFAULT_FONT(tmpms) = True;
++			has_gc_changed = True;
++			if (ST_HAS_SIDE_COLOR(tmpms) == 1)
++			{
++				fvwmlib_free_colors(
++					dpy, &ST_SIDE_COLOR(tmpms), 1, True);
++				ST_HAS_SIDE_COLOR(tmpms) = 0;
++			}
++			ST_HAS_SIDE_COLOR(tmpms) = 0;
++			if (ST_SIDEPIC(tmpms))
++			{
++				PDestroyFvwmPicture(dpy, ST_SIDEPIC(tmpms));
++				ST_SIDEPIC(tmpms) = NULL;
++			}
++
++			if (is_initialised == False)
++			{
++				/* now begin the real work */
++				is_initialised = True;
++				continue;
++			}
++			break;
++
++		case 3: /* Foreground */
++			fvwmlib_free_colors(
++				dpy, &ST_MENU_COLORS(tmpms).fore, 1, True);
++			if (arg1)
++			{
++				ST_MENU_COLORS(tmpms).fore = GetColor(arg1);
++			}
++			else
++			{
++				ST_MENU_COLORS(tmpms).fore =
++					GetColor(DEFAULT_FORE_COLOR);
++			}
++			has_gc_changed = True;
++			break;
++
++		case 4: /* Background */
++			fvwmlib_free_colors(
++				dpy, &ST_MENU_COLORS(tmpms).back, 1, True);
++			if (arg1)
++			{
++				ST_MENU_COLORS(tmpms).back = GetColor(arg1);
++			}
++			else
++			{
++				ST_MENU_COLORS(tmpms).back =
++					GetColor(DEFAULT_BACK_COLOR);
++			}
++			has_gc_changed = True;
++			break;
++
++		case 5: /* Greyed */
++			if (ST_HAS_STIPPLE_FORE(tmpms))
++			{
++				fvwmlib_free_colors(
++					dpy,
++					&ST_MENU_STIPPLE_COLORS(tmpms).fore, 1,
++					True);
++			}
++			if (arg1 == NULL)
++			{
++				ST_HAS_STIPPLE_FORE(tmpms) = 0;
++			}
++			else
++			{
++				ST_MENU_STIPPLE_COLORS(tmpms).fore =
++					GetColor(arg1);
++				ST_HAS_STIPPLE_FORE(tmpms) = 1;
++			}
++			has_gc_changed = True;
++			break;
++
++		case 7: /* HilightBackOff */
++			on ^= 1;
++			/* fall throw */
++		case 6: /* HilightBack */
++			if (ST_HAS_ACTIVE_BACK(tmpms))
++			{
++				fvwmlib_free_colors(
++					dpy,
++					&ST_MENU_ACTIVE_COLORS(tmpms).back, 1,
++					True);
++			}
++			if (arg1 == NULL || !on)
++			{
++				ST_HAS_ACTIVE_BACK(tmpms) = 0;
++			}
++			else
++			{
++				ST_MENU_ACTIVE_COLORS(tmpms).back =
++					GetColor(arg1);
++				ST_HAS_ACTIVE_BACK(tmpms) = 1;
++			}
++			ST_DO_HILIGHT_BACK(tmpms) = on;
++			has_gc_changed = True;
++			break;
++
++		case 9: /* ActiveForeOff */
++			on ^= 1;
++			/* fall throw */
++		case 8: /* ActiveFore */
++			if (ST_HAS_ACTIVE_FORE(tmpms))
++			{
++				fvwmlib_free_colors(
++					dpy,
++					&ST_MENU_ACTIVE_COLORS(tmpms).fore, 1,
++					True);
++			}
++			if (arg1 == NULL || !on)
++			{
++				ST_HAS_ACTIVE_FORE(tmpms) = 0;
++			}
++			else
++			{
++				ST_MENU_ACTIVE_COLORS(tmpms).fore =
++					GetColor(arg1);
++				ST_HAS_ACTIVE_FORE(tmpms) = 1;
++			}
++			ST_DO_HILIGHT_FORE(tmpms) = on;
++			has_gc_changed = True;
++			break;
++
++		case 10: /* Hilight3DThick */
++			ST_RELIEF_THICKNESS(tmpms) = 2;
++			break;
++
++		case 11: /* Hilight3DThin */
++			ST_RELIEF_THICKNESS(tmpms) = 1;
++			break;
++
++		case 12: /* Hilight3DOff */
++			ST_RELIEF_THICKNESS(tmpms) = 0;
++			break;
++
++		case 13: /* Animation */
++			ST_IS_ANIMATED(tmpms) = on;
++			break;
++
++		case 14: /* AnimationOff */
++			ST_IS_ANIMATED(tmpms) = !on;
++			break;
++
++		case 15: /* Font */
++			if (arg1 != NULL &&
++			    !(new_font = FlocaleLoadFont(dpy, arg1, "FVWM")))
++			{
++				fvwm_msg(ERR, "NewMenuStyle",
++					 "Couldn't load font '%s'\n", arg1);
++				break;
++			}
++			if (ST_PSTDFONT(tmpms) && !ST_USING_DEFAULT_FONT(tmpms))
++			{
++				FlocaleUnloadFont(dpy, ST_PSTDFONT(tmpms));
++			}
++			if (arg1 == NULL)
++			{
++				/* reset to screen font */
++				ST_PSTDFONT(tmpms) = Scr.DefaultFont;
++				ST_USING_DEFAULT_FONT(tmpms) = True;
++			}
++			else
++			{
++				ST_PSTDFONT(tmpms) = new_font;
++				ST_USING_DEFAULT_FONT(tmpms) = False;
++			}
++			has_gc_changed = True;
++			break;
++
++		case 16: /* MenuFace */
++			while (args && *args != '\0' &&
++			       isspace((unsigned char)*args))
++			{
++				args++;
++			}
++			menustyle_parse_face(args, &ST_FACE(tmpms), True);
++			break;
++
++		case 17: /* PopupDelay */
++			if (GetIntegerArguments(args, NULL, val, 1) == 0 ||
++			    *val < 0)
++			{
++				ST_POPUP_DELAY(tmpms) = DEFAULT_POPUP_DELAY;
++			}
++			else
++			{
++				ST_POPUP_DELAY(tmpms) = (*val+9)/10;
++			}
++			break;
++
++		case 18: /* PopupOffset */
++			if ((n = GetIntegerArguments(args, NULL, val, 2)) == 0)
++			{
++				fvwm_msg(ERR,"NewMenuStyle",
++					 "PopupOffset requires one or two"
++					 " arguments");
++			}
++			else
++			{
++				ST_POPUP_OFFSET_ADD(tmpms) = val[0];
++				if (n == 2 && val[1] <= 100 && val[1] >= 0)
++				{
++					ST_POPUP_OFFSET_PERCENT(tmpms) = val[1];
++				}
++				else
++				{
++					ST_POPUP_OFFSET_PERCENT(tmpms) = 100;
++				}
++			}
++			break;
++
++		case 19: /* TitleWarp */
++			ST_DO_WARP_TO_TITLE(tmpms) = on;
++			break;
++
++		case 20: /* TitleWarpOff */
++			ST_DO_WARP_TO_TITLE(tmpms) = !on;
++			break;
++
++		case 21: /* TitleUnderlines0 */
++			ST_TITLE_UNDERLINES(tmpms) = 0;
++			break;
++
++		case 22: /* TitleUnderlines1 */
++			ST_TITLE_UNDERLINES(tmpms) = 1;
++			break;
++
++		case 23: /* TitleUnderlines2 */
++			ST_TITLE_UNDERLINES(tmpms) = 2;
++			break;
++
++		case 24: /* SeparatorsLong */
++			ST_HAS_LONG_SEPARATORS(tmpms) = on;
++			break;
++
++		case 25: /* SeparatorsShort */
++			ST_HAS_LONG_SEPARATORS(tmpms) = !on;
++			break;
++
++		case 26: /* TrianglesSolid */
++			ST_HAS_TRIANGLE_RELIEF(tmpms) = !on;
++			break;
++
++		case 27: /* TrianglesRelief */
++			ST_HAS_TRIANGLE_RELIEF(tmpms) = on;
++			break;
++
++		case 28: /* PopupImmediately */
++			ST_DO_POPUP_IMMEDIATELY(tmpms) = on;
++			break;
++
++		case 29: /* PopupDelayed */
++			ST_DO_POPUP_IMMEDIATELY(tmpms) = !on;
++			break;
++
++		case 30: /* DoubleClickTime */
++			if (GetIntegerArguments(args, NULL, val, 1) == 0 ||
++			    *val < 0)
++			{
++				ST_DOUBLE_CLICK_TIME(tmpms) =
++					DEFAULT_MENU_CLICKTIME;
++			}
++			else
++			{
++				ST_DOUBLE_CLICK_TIME(tmpms) = *val;
++			}
++			break;
++
++		case 31: /* SidePic */
++			if (ST_SIDEPIC(tmpms))
++			{
++				PDestroyFvwmPicture(dpy, ST_SIDEPIC(tmpms));
++				ST_SIDEPIC(tmpms) = NULL;
++			}
++			if (arg1)
++			{
++				fpa.mask = (Pdepth <= 8)?  FPAM_DITHER:0;
++				ST_SIDEPIC(tmpms) = PCacheFvwmPicture(
++					dpy, Scr.NoFocusWin, NULL, arg1, fpa);
++				if (!ST_SIDEPIC(tmpms))
++				{
++					fvwm_msg(WARN, "NewMenuStyle",
++						 "Couldn't find pixmap %s",
++						 arg1);
++				}
++			}
++			break;
++
++		case 32: /* SideColor */
++			if (ST_HAS_SIDE_COLOR(tmpms) == 1)
++			{
++				fvwmlib_free_colors(
++					dpy, &ST_SIDE_COLOR(tmpms), 1, True);
++				ST_HAS_SIDE_COLOR(tmpms) = 0;
++			}
++			if (arg1)
++			{
++				ST_SIDE_COLOR(tmpms) = GetColor(arg1);
++				ST_HAS_SIDE_COLOR(tmpms) = 1;
++			}
++			break;
++
++		case 33: /* PopupAsRootmenu */
++			ST_DO_POPUP_AS(tmpms) = MDP_ROOT_MENU;
++			break;
++
++		case 34: /* PopupAsSubmenu */
++			ST_DO_POPUP_AS(tmpms) = MDP_POST_MENU;
++			break;
++
++		case 35: /* RemoveSubmenus */
++			ST_DO_UNMAP_SUBMENU_ON_POPDOWN(tmpms) = on;
++			break;
++
++		case 36: /* HoldSubmenus */
++			ST_DO_UNMAP_SUBMENU_ON_POPDOWN(tmpms) = !on;
++			break;
++
++		case 37: /* SubmenusRight */
++			ST_USE_LEFT_SUBMENUS(tmpms) = !on;
++			break;
++
++		case 38: /* SubmenusLeft */
++			ST_USE_LEFT_SUBMENUS(tmpms) = on;
++			break;
++
++		case 39: /* BorderWidth */
++			if (GetIntegerArguments(args, NULL, val, 1) == 0 ||
++			    *val < 0 || *val > MAX_MENU_BORDER_WIDTH)
++			{
++				ST_BORDER_WIDTH(tmpms) =
++					DEFAULT_MENU_BORDER_WIDTH;
++			}
++			else
++			{
++				ST_BORDER_WIDTH(tmpms) = *val;
++			}
++			break;
++
++		case 40: /* Hilight3DThickness */
++			if (GetIntegerArguments(args, NULL, val, 1) > 0)
++			{
++				if (*val < 0)
++				{
++					*val = -*val;
++					ST_IS_ITEM_RELIEF_REVERSED(tmpms) = 1;
++				}
++				else
++				{
++					ST_IS_ITEM_RELIEF_REVERSED(tmpms) = 0;
++				}
++				if (*val > MAX_MENU_ITEM_RELIEF_THICKNESS)
++					*val = MAX_MENU_ITEM_RELIEF_THICKNESS;
++				ST_RELIEF_THICKNESS(tmpms) = *val;
++			}
++			break;
++
++		case 41: /* ItemFormat */
++			if (ST_ITEM_FORMAT(tmpms))
++			{
++				free(ST_ITEM_FORMAT(tmpms));
++				ST_ITEM_FORMAT(tmpms) = NULL;
++			}
++			if (arg1)
++			{
++				ST_ITEM_FORMAT(tmpms) = safestrdup(arg1);
++			}
++			break;
++
++		case 42: /* AutomaticHotkeys */
++			ST_USE_AUTOMATIC_HOTKEYS(tmpms) = on;
++			break;
++
++		case 43: /* AutomaticHotkeysOff */
++			ST_USE_AUTOMATIC_HOTKEYS(tmpms) = !on;
++			break;
++
++		case 44: /* VerticalItemSpacing */
++			parse_vertical_spacing_line(
++				args, &ST_ITEM_GAP_ABOVE(tmpms),
++				&ST_ITEM_GAP_BELOW(tmpms),
++				DEFAULT_MENU_ITEM_TEXT_Y_OFFSET,
++				DEFAULT_MENU_ITEM_TEXT_Y_OFFSET2);
++			break;
++
++		case 45: /* VerticalTitleSpacing */
++			parse_vertical_spacing_line(
++				args, &ST_TITLE_GAP_ABOVE(tmpms),
++				&ST_TITLE_GAP_BELOW(tmpms),
++				DEFAULT_MENU_TITLE_TEXT_Y_OFFSET,
++				DEFAULT_MENU_TITLE_TEXT_Y_OFFSET2);
++			break;
++		case 46: /* MenuColorset */
++			if (GetIntegerArguments(args, NULL, val, 1) == 0 ||
++			    *val < 0)
++			{
++				ST_HAS_MENU_CSET(tmpms) = 0;
++				ST_CSET_MENU(tmpms) = 0;
++			}
++			else
++			{
++				ST_HAS_MENU_CSET(tmpms) = 1;
++				ST_CSET_MENU(tmpms) = *val;
++				alloc_colorset(*val);
++			}
++			has_gc_changed = True;
++			break;
++		case 47: /* ActiveColorset */
++			if (GetIntegerArguments(args, NULL, val, 1) == 0 ||
++			    *val < 0)
++			{
++				ST_HAS_ACTIVE_CSET(tmpms) = 0;
++				ST_CSET_ACTIVE(tmpms) = 0;
++			}
++			else
++			{
++				ST_HAS_ACTIVE_CSET(tmpms) = 1;
++				ST_CSET_ACTIVE(tmpms) = *val;
++				alloc_colorset(*val);
++			}
++			has_gc_changed = True;
++			break;
++
++		case 48: /* GreyedColorset */
++			if (GetIntegerArguments(args, NULL, val, 1) == 0 ||
++			    *val < 0)
++			{
++				ST_HAS_GREYED_CSET(tmpms) = 0;
++				ST_CSET_GREYED(tmpms) = 0;
++			}
++			else
++			{
++				ST_HAS_GREYED_CSET(tmpms) = 1;
++				ST_CSET_GREYED(tmpms) = *val;
++				alloc_colorset(*val);
++			}
++			has_gc_changed = True;
++			break;
++
++		case 49: /* SelectOnRelease */
++			keycode = 0;
++			if (arg1)
++			{
++				keycode = XKeysymToKeycode(
++					dpy, FvwmStringToKeysym(dpy, arg1));
++			}
++			ST_SELECT_ON_RELEASE_KEY(tmpms) = keycode;
++			break;
++
++		case 50: /* PopdownImmediately */
++			ST_DO_POPDOWN_IMMEDIATELY(tmpms) = 1;
++			break;
++
++		case 51: /* PopdownDelayed */
++			ST_DO_POPDOWN_IMMEDIATELY(tmpms) = 0;
++			break;
++
++		case 52: /* PopdownDelay */
++			if (GetIntegerArguments(args, NULL, val, 1) == 0 ||
++			    *val < 0)
++			{
++				ST_POPDOWN_DELAY(tmpms) = DEFAULT_POPDOWN_DELAY;
++			}
++			else
++			{
++				ST_POPDOWN_DELAY(tmpms) = (*val+9)/10;
++			}
++			break;
++
++		case 53: /* PopupActiveArea */
++			if (GetIntegerArguments(args, NULL, val, 1) == 0 ||
++			    *val <= 50 || *val > 100)
++			{
++				ST_ACTIVE_AREA_PERCENT(tmpms) =
++					DEFAULT_MENU_POPUP_NOW_RATIO;
++			}
++			else
++			{
++				ST_ACTIVE_AREA_PERCENT(tmpms) = *val;
++			}
++			break;
++
++		case 54: /* PopupIgnore */
++			ST_DO_POPUP_AS(tmpms) = MDP_IGNORE;
++			break;
++
++		case 55: /* PopupClose */
++			ST_DO_POPUP_AS(tmpms) = MDP_CLOSE;
++			break;
++
++		case 56: /* MouseWheel */
++			if (arg1)
++		        {
++				if (StrEquals(arg1, "ActivatesItem"))
++				{
++					ST_MOUSE_WHEEL(tmpms) = MMW_OFF;
++				}
++				else if (StrEquals(arg1,
++						   "ScrollsMenuBackwards"))
++				{
++					ST_MOUSE_WHEEL(tmpms) =
++						MMW_MENU_BACKWARDS;
++				}
++				else if (StrEquals(arg1, "ScrollsMenu"))
++				{
++					ST_MOUSE_WHEEL(tmpms) = MMW_MENU;
++				}
++				else if (StrEquals(arg1, "ScrollsPointer"))
++				{
++					ST_MOUSE_WHEEL(tmpms) = MMW_POINTER;
++				}
++				else
++				{
++					fvwm_msg(
++						ERR, "NewMenuStyle",
++						"unknown argument to"
++						" MouseWheel '%s'",
++						 arg1);
++					ST_MOUSE_WHEEL(tmpms) = MMW_POINTER;
++				}
++		        }
++		        else
++		        {
++		        	ST_MOUSE_WHEEL(tmpms) =
++					(on) ? MMW_POINTER : MMW_OFF;
++			}
++			break;
++		case 57: /* ScrollOffPage */
++	        	ST_SCROLL_OFF_PAGE(tmpms) = on;
++			break;
++
++		case 58: /* TrianglesUseFore */
++			ST_TRIANGLES_USE_FORE(tmpms) = on;
++			break;
++		case 59: /* TitleColorset */
++			if (GetIntegerArguments(args, NULL, val, 1) == 0 ||
++			    *val < 0)
++			{
++				ST_HAS_TITLE_CSET(tmpms) = 0;
++				ST_CSET_TITLE(tmpms) = 0;
++			}
++			else
++			{
++				ST_HAS_TITLE_CSET(tmpms) = 1;
++				ST_CSET_TITLE(tmpms) = *val;
++				alloc_colorset(*val);
++			}
++			has_gc_changed = True;
++			break;
++		case 60: /* TitleHilightBack */
++			ST_DO_HILIGHT_TITLE_BACK(tmpms) = on;
++			has_gc_changed = True;
++			break;
++		case 61: /* TitleFont */
++			if (arg1 != NULL &&
++			    !(new_font = FlocaleLoadFont(dpy, arg1, "FVWM")))
++			{
++				fvwm_msg(ERR, "NewMenuStyle",
++					 "Couldn't load font '%s'\n", arg1);
++				break;
++			}
++			if (
++				ST_PTITLEFONT(tmpms) &&
++				!ST_USING_DEFAULT_TITLEFONT(tmpms))
++			{
++				FlocaleUnloadFont(dpy, ST_PTITLEFONT(tmpms));
++			}
++			if (arg1 == NULL)
++			{
++				/* reset to screen font */
++				ST_PTITLEFONT(tmpms) = Scr.DefaultFont;
++				ST_USING_DEFAULT_TITLEFONT(tmpms) = True;
++			}
++			else
++			{
++				ST_PTITLEFONT(tmpms) = new_font;
++				ST_USING_DEFAULT_TITLEFONT(tmpms) = False;
++			}
++			has_gc_changed = True;
++			break;
++
++
++#if 0
++		case 99: /* PositionHints */
++			/* to be implemented */
++			break;
++#endif
++
++		default:
++			fvwm_msg(ERR, "NewMenuStyle", "unknown option '%s'",
++				 poption);
++			break;
++		} /* switch */
++
++		if (option)
++		{
++			free(option);
++			option = NULL;
++		}
++		free(optstring);
++		optstring = NULL;
++		if (arg1)
++		{
++			free(arg1);
++			arg1 = NULL;
++		}
++	} /* while */
++
++	if (has_gc_changed)
++	{
++		menustyle_update(tmpms);
++	}
++
++	if (default_menu_style == NULL)
++	{
++		/* First MenuStyle MUST be the default style */
++		default_menu_style = tmpms;
++		ST_NEXT_STYLE(tmpms) = NULL;
++	}
++	else if (ms)
++	{
++		/* copy our new menu face over the old one */
++		memcpy(ms, tmpms, sizeof(MenuStyle));
++		free(tmpms);
++		return ms;
++	}
++	else
++	{
++		MenuStyle *before = default_menu_style;
++
++		/* add a new menu face to list */
++		ST_NEXT_STYLE(tmpms) = NULL;
++		while (ST_NEXT_STYLE(before))
++			before = ST_NEXT_STYLE(before);
++		ST_NEXT_STYLE(before) = tmpms;
++	}
++
++	return tmpms;
++}
++
++void menustyle_copy(MenuStyle *origms, MenuStyle *destms)
++{
++	FvwmPictureAttributes fpa;
++	/* Copy origms to destms, be aware of all pointers in the MenuStyle
++	   strcture. Use  the same order as in menustyle_parse_style */
++
++	/* menu colors */
++	fvwmlib_copy_color(
++		dpy, &ST_MENU_COLORS(destms).fore,
++		&ST_MENU_COLORS(origms).fore, True, True);
++	fvwmlib_copy_color(
++		dpy, &ST_MENU_COLORS(destms).back,
++		&ST_MENU_COLORS(origms).back, True, True);
++	/* Greyed */
++	fvwmlib_copy_color(
++		dpy, &ST_MENU_STIPPLE_COLORS(destms).fore,
++		&ST_MENU_STIPPLE_COLORS(origms).fore,
++		ST_HAS_STIPPLE_FORE(destms), ST_HAS_STIPPLE_FORE(origms));
++	ST_MENU_STIPPLE_COLORS(destms).back =
++		ST_MENU_STIPPLE_COLORS(origms).back;
++	ST_HAS_STIPPLE_FORE(destms) = ST_HAS_STIPPLE_FORE(origms);
++
++	/* HilightBack */
++	fvwmlib_copy_color(
++		dpy, &ST_MENU_ACTIVE_COLORS(destms).back,
++		&ST_MENU_ACTIVE_COLORS(origms).back,
++		ST_HAS_ACTIVE_BACK(destms), ST_HAS_ACTIVE_BACK(origms));
++	ST_HAS_ACTIVE_BACK(destms) = ST_HAS_ACTIVE_BACK(origms);
++	ST_DO_HILIGHT_BACK(destms) = ST_DO_HILIGHT_BACK(origms);
++
++	/* ActiveFore */
++	fvwmlib_copy_color(
++		dpy, &ST_MENU_ACTIVE_COLORS(destms).fore,
++		&ST_MENU_ACTIVE_COLORS(origms).fore,
++		ST_HAS_ACTIVE_FORE(destms), ST_HAS_ACTIVE_FORE(origms));
++	ST_HAS_ACTIVE_FORE(destms) = ST_HAS_ACTIVE_FORE(origms);
++	ST_DO_HILIGHT_FORE(destms) = ST_DO_HILIGHT_FORE(origms);
++
++	/* Hilight3D */
++	ST_RELIEF_THICKNESS(destms) = ST_RELIEF_THICKNESS(origms);
++	/* Animation */
++	ST_IS_ANIMATED(destms) = ST_IS_ANIMATED(origms);
++
++	/* font */
++	if (ST_PSTDFONT(destms) &&  !ST_USING_DEFAULT_FONT(destms))
++	{
++		FlocaleUnloadFont(dpy, ST_PSTDFONT(destms));
++	}
++	if (ST_PSTDFONT(origms) && !ST_USING_DEFAULT_FONT(origms))
++	{
++		if (!(ST_PSTDFONT(destms) =
++		      FlocaleLoadFont(dpy, ST_PSTDFONT(origms)->name, "FVWM")))
++		{
++			ST_PSTDFONT(destms) = Scr.DefaultFont;
++			ST_USING_DEFAULT_FONT(destms) = True;
++			fvwm_msg(ERR, "CopyMenuStyle",
++				 "Couldn't load font '%s' use Default Font\n",
++				 ST_PSTDFONT(origms)->name);
++		}
++		else
++		{
++			ST_USING_DEFAULT_FONT(destms) = False;
++		}
++	}
++	else
++	{
++		ST_USING_DEFAULT_FONT(destms) = True;
++		ST_PSTDFONT(destms) = Scr.DefaultFont;
++	}
++	/* TitleFont */
++	if (ST_PTITLEFONT(destms) &&  !ST_USING_DEFAULT_TITLEFONT(destms))
++	{
++		FlocaleUnloadFont(dpy, ST_PTITLEFONT(destms));
++	}
++	if (ST_PTITLEFONT(origms) && !ST_USING_DEFAULT_TITLEFONT(origms))
++	{
++		if (
++			!(ST_PTITLEFONT(destms) = FlocaleLoadFont(
++				  dpy, ST_PTITLEFONT(origms)->name, "FVWM")))
++		{
++			ST_PTITLEFONT(destms) = Scr.DefaultFont;
++			ST_USING_DEFAULT_TITLEFONT(destms) = True;
++			fvwm_msg(ERR, "CopyMenuStyle",
++				 "Couldn't load font '%s' use Default Font\n",
++				 ST_PTITLEFONT(origms)->name);
++		}
++		else
++		{
++			ST_USING_DEFAULT_TITLEFONT(destms) = False;
++		}
++	}
++	else
++	{
++		ST_USING_DEFAULT_TITLEFONT(destms) = True;
++		ST_PTITLEFONT(destms) = Scr.DefaultFont;
++	}
++	/* MenuFace */
++	menustyle_copy_face(&ST_FACE(destms), &ST_FACE(origms));
++
++	/* PopupDelay */
++	ST_POPUP_DELAY(destms) = ST_POPUP_DELAY(origms);
++	/* PopupOffset */
++	ST_POPUP_OFFSET_PERCENT(destms) = ST_POPUP_OFFSET_PERCENT(origms);
++	ST_POPUP_OFFSET_ADD(destms) = ST_POPUP_OFFSET_ADD(origms);
++	/* TitleWarp */
++	ST_DO_WARP_TO_TITLE(destms) = ST_DO_WARP_TO_TITLE(origms);
++	/* TitleUnderlines */
++	ST_TITLE_UNDERLINES(destms) = ST_TITLE_UNDERLINES(origms);
++	/* Separators */
++	ST_HAS_LONG_SEPARATORS(destms) = ST_HAS_LONG_SEPARATORS(origms);
++	/* Triangles */
++	ST_HAS_TRIANGLE_RELIEF(destms) = ST_HAS_TRIANGLE_RELIEF(origms);
++	/* PopupDelayed */
++	ST_DO_POPUP_IMMEDIATELY(destms) = ST_DO_POPUP_IMMEDIATELY(origms);
++	/* DoubleClickTime */
++	ST_DOUBLE_CLICK_TIME(destms) = ST_DOUBLE_CLICK_TIME(origms);
++
++	/* SidePic */
++	if (ST_SIDEPIC(destms))
++	{
++		PDestroyFvwmPicture(dpy, ST_SIDEPIC(destms));
++		ST_SIDEPIC(destms) = NULL;
++	}
++	if (ST_SIDEPIC(origms))
++	{
++		fpa.mask = (Pdepth <= 8)?  FPAM_DITHER:0;
++		ST_SIDEPIC(destms) = PCacheFvwmPicture(
++			dpy, Scr.NoFocusWin, NULL, ST_SIDEPIC(origms)->name,
++			fpa);
++	}
++
++	/* side color */
++	fvwmlib_copy_color(
++		dpy, &ST_SIDE_COLOR(destms), &ST_SIDE_COLOR(origms),
++		ST_HAS_SIDE_COLOR(destms), ST_HAS_SIDE_COLOR(origms));
++	ST_HAS_SIDE_COLOR(destms) = ST_HAS_SIDE_COLOR(origms);
++
++	/* PopupAsRootmenu */
++	ST_DO_POPUP_AS(destms) = ST_DO_POPUP_AS(origms);
++	/* RemoveSubmenus */
++	ST_DO_UNMAP_SUBMENU_ON_POPDOWN(destms) =
++		ST_DO_UNMAP_SUBMENU_ON_POPDOWN(origms);
++	/* SubmenusRight */
++	ST_USE_LEFT_SUBMENUS(destms) = ST_USE_LEFT_SUBMENUS(origms);
++	/* BorderWidth */
++	ST_BORDER_WIDTH(destms) = ST_BORDER_WIDTH(origms);
++	/* Hilight3DThickness */
++	ST_IS_ITEM_RELIEF_REVERSED(destms) =
++		ST_IS_ITEM_RELIEF_REVERSED(origms);
++
++	/* ItemFormat */
++	if (ST_ITEM_FORMAT(destms))
++	{
++		free(ST_ITEM_FORMAT(destms));
++		ST_ITEM_FORMAT(destms) = NULL;
++	}
++	if (ST_ITEM_FORMAT(origms))
++	{
++		ST_ITEM_FORMAT(destms) = safestrdup(ST_ITEM_FORMAT(origms));
++	}
++
++	/* AutomaticHotkeys */
++	ST_USE_AUTOMATIC_HOTKEYS(destms) = ST_USE_AUTOMATIC_HOTKEYS(origms);
++	/* Item and Title Spacing */
++	ST_ITEM_GAP_ABOVE(destms) =  ST_ITEM_GAP_ABOVE(origms);
++	ST_ITEM_GAP_BELOW(destms) = ST_ITEM_GAP_BELOW(origms);
++	ST_TITLE_GAP_ABOVE(destms) = ST_TITLE_GAP_ABOVE(origms);
++	ST_TITLE_GAP_BELOW(destms) = ST_TITLE_GAP_BELOW(origms);
++	/* MenuColorset */
++	ST_HAS_MENU_CSET(destms) = ST_HAS_MENU_CSET(origms);
++	ST_CSET_MENU(destms) = ST_CSET_MENU(origms);
++	/* ActiveColorset */
++	ST_HAS_ACTIVE_CSET(destms) = ST_HAS_ACTIVE_CSET(origms);
++	ST_CSET_ACTIVE(destms) = ST_CSET_ACTIVE(origms);
++	/* MenuColorset */
++	ST_HAS_GREYED_CSET(destms) = ST_HAS_GREYED_CSET(origms);
++	ST_CSET_GREYED(destms) = ST_CSET_GREYED(origms);
++	/* TitleColorset */
++	ST_HAS_TITLE_CSET(destms) = ST_HAS_TITLE_CSET(origms);
++	ST_CSET_TITLE(destms) = ST_CSET_TITLE(origms);
++	/* SelectOnRelease */
++	ST_SELECT_ON_RELEASE_KEY(destms) = ST_SELECT_ON_RELEASE_KEY(origms);
++	/* PopdownImmediately */
++	ST_DO_POPDOWN_IMMEDIATELY(destms) = ST_DO_POPDOWN_IMMEDIATELY(origms);
++	/* PopdownDelay */
++	ST_POPDOWN_DELAY(destms) = ST_POPDOWN_DELAY(origms);
++	/* Scroll */
++	ST_MOUSE_WHEEL(destms) = ST_MOUSE_WHEEL(origms);
++	/* ScrollOffPage */
++	ST_SCROLL_OFF_PAGE(destms) = ST_SCROLL_OFF_PAGE(origms);
++	/* TrianglesUseFore */
++	ST_TRIANGLES_USE_FORE(destms) = ST_TRIANGLES_USE_FORE(origms);
++	/* Title */
++	ST_DO_HILIGHT_TITLE_BACK(destms) = ST_DO_HILIGHT_TITLE_BACK(origms);
++
++	menustyle_update(destms);
++
++	return;
++}
++
++/* ---------------------------- builtin commands --------------------------- */
++
++void CMD_CopyMenuStyle(F_CMD_ARGS)
++{
++	char *origname = NULL;
++	char *destname = NULL;
++	char *buffer;
++	MenuStyle *origms;
++	MenuStyle *destms;
++
++	origname = PeekToken(action, &action);
++	if (origname == NULL)
++	{
++		fvwm_msg(ERR,"CopyMenuStyle", "need two arguments");
++		return;
++	}
++
++	origms = menustyle_find(origname);
++	if (!origms)
++	{
++		fvwm_msg(ERR, "CopyMenuStyle", "%s: no such menu style",
++			 origname);
++		return;
++	}
++
++	destname = PeekToken(action, &action);
++	if (destname == NULL)
++	{
++		fvwm_msg(ERR,"CopyMenuStyle", "need two arguments");
++		return;
++	}
++
++	if (action && *action)
++	{
++		fvwm_msg(ERR,"CopyMenuStyle", "too many arguments");
++		return;
++	}
++
++	destms = menustyle_find(destname);
++	if (!destms)
++	{
++		/* create destms menu style */
++		buffer = (char *)safemalloc(strlen(destname) + 3);
++		sprintf(buffer,"\"%s\"",destname);
++		action = buffer;
++		destms = menustyle_parse_style(F_PASS_ARGS);
++		free(buffer);
++		if (!destms)
++		{
++			/* this must never happen */
++			fvwm_msg(ERR, "CopyMenuStyle",
++				 "impossible to create %s menu style",
++				 destname);
++			return;
++		}
++	}
++
++	if (strcasecmp("*",destname) == 0)
++	{
++		fvwm_msg(ERR, "CopyMenuStyle",
++			 "You cannot copy on the default menu style");
++		return;
++	}
++	if (strcasecmp(ST_NAME(origms),destname) == 0)
++	{
++		fvwm_msg(ERR, "CopyMenuStyle",
++			 "%s and %s identify the same menu style",
++			 ST_NAME(origms),destname);
++		return;
++	}
++
++	if (ST_USAGE_COUNT(destms) != 0)
++	{
++		fvwm_msg(ERR, "CopyMenuStyle", "menu style %s is in use",
++			 destname);
++		return;
++	}
++
++	menustyle_copy(origms, destms);
++
++	return;
++}
++
++void CMD_MenuStyle(F_CMD_ARGS)
++{
++	char *option;
++	char *poption;
++	MenuStyle *dummy;
++
++	GetNextSimpleOption(SkipNTokens(action, 1), &option);
++	poption = option;
++	while (poption && poption[0] == '!')
++	{
++		poption++;
++	}
++	if (option == NULL || menustyle_get_styleopt_index(poption) != -1)
++	{
++		dummy = menustyle_parse_style(F_PASS_ARGS);
++	}
++	else
++	{
++		dummy = menustyle_parse_old_style(F_PASS_ARGS);
++	}
++	if (option)
++	{
++		free(option);
++	}
++
++	return;
++}
+diff -U10 -Naupr fvwm-2.5.21-03/fvwm/menustyle.h fvwm-2.5.21-04/fvwm/menustyle.h
+--- fvwm-2.5.21-03/fvwm/menustyle.h	2007-03-03 13:17:58.000000000 +0100
++++ fvwm-2.5.21-04/fvwm/menustyle.h	2007-03-03 13:18:29.000000000 +0100
+@@ -16,20 +16,22 @@
+ #define ST_USAGE_COUNT(s)             ((s)->usage_count)
+ #define MST_USAGE_COUNT(m)            ((m)->s->ms->usage_count)
+ /* flags */
+ #define ST_IS_UPDATED(s)              ((s)->flags.is_updated)
+ #define MST_IS_UPDATED(m)             ((m)->s->ms->flags.is_updated)
+ /* look */
+ #define ST_FACE(s)                    ((s)->look.face)
+ #define MST_FACE(m)                   ((m)->s->ms->look.face)
+ #define ST_DO_HILIGHT_BACK(s)         ((s)->look.flags.do_hilight_back)
+ #define MST_DO_HILIGHT_BACK(m)        ((m)->s->ms->look.flags.do_hilight_back)
++#define ST_DO_FLAT_SEPARATOR(s)       ((s)->look.flags.do_flat_separator)
++#define MST_DO_FLAT_SEPARATOR(m)      ((m)->s->ms->look.flags.do_flat_separator)
+ #define ST_DO_HILIGHT_FORE(s)         ((s)->look.flags.do_hilight_fore)
+ #define MST_DO_HILIGHT_FORE(m)        ((m)->s->ms->look.flags.do_hilight_fore)
+ #define ST_DO_HILIGHT_TITLE_BACK(s)   ((s)->look.flags.do_hilight_title_back)
+ #define MST_DO_HILIGHT_TITLE_BACK(m)			\
+ 	((m)->s->ms->look.flags.do_hilight_title_back)
+ #define ST_HAS_ACTIVE_FORE(s)         ((s)->look.flags.has_active_fore)
+ #define MST_HAS_ACTIVE_FORE(m)        ((m)->s->ms->look.flags.has_active_fore)
+ #define ST_HAS_ACTIVE_BACK(s)         ((s)->look.flags.has_active_back)
+ #define MST_HAS_ACTIVE_BACK(m)        ((m)->s->ms->look.flags.has_active_back)
+ #define ST_HAS_STIPPLE_FORE(s)        ((s)->look.flags.has_stipple_fore)
+@@ -268,20 +270,21 @@ typedef struct MenuLook
+ 		unsigned has_side_color : 1;
+ 		unsigned has_menu_cset : 1;
+ 		unsigned has_active_cset : 1;
+ 		unsigned has_greyed_cset : 1;
+ 		unsigned is_item_relief_reversed : 1;
+ 		unsigned using_default_font : 1;
+ 		unsigned triangles_use_fore : 1;
+ 		unsigned has_title_cset : 1;
+ 		unsigned do_hilight_title_back : 1;
+ 		unsigned using_default_titlefont : 1;
++		unsigned do_flat_separator : 1;
+ 	} flags;
+ 	unsigned char ReliefThickness;
+ 	unsigned char TitleUnderlines;
+ 	unsigned char BorderWidth;
+ 	struct
+ 	{
+ 		signed char item_above;
+ 		signed char item_below;
+ 		signed char title_above;
+ 		signed char title_below;
diff --git a/windowmanagers/fvwm/patches/05-BorderUnderTitle.patch b/windowmanagers/fvwm/patches/05-BorderUnderTitle.patch
new file mode 100644
index 0000000..0298d2f
--- /dev/null
+++ b/windowmanagers/fvwm/patches/05-BorderUnderTitle.patch
@@ -0,0 +1,14348 @@
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/borders.c fvwm-2.5.21-05/fvwm/borders.c
+--- fvwm-2.5.21-04/fvwm/borders.c	2007-03-03 13:18:21.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/borders.c	2007-03-03 13:18:49.000000000 +0100
+@@ -4590,20 +4590,21 @@ int border_context_to_parts(
+ 	}
+ 
+ 	return PART_NONE;
+ }
+ 
+ void border_get_part_geometry(
+ 	FvwmWindow *fw, window_parts part, rectangle *sidebar_g,
+ 	rectangle *ret_g, Window *ret_w)
+ {
+ 	int bw;
++	Bool title;
+ 
+ 	bw = fw->boundary_width;
+ 	/* ret_g->x and ret->y is just an offset relatively to the w,
+ 	 * maybe we can take the relief in account? */
+ 	switch (part)
+ 	{
+ 	case PART_BORDER_N:
+ 		ret_g->x = sidebar_g->x;
+ 		ret_g->y = 0;
+ 		*ret_w = FW_W_SIDE(fw, 0);
+@@ -4660,21 +4661,46 @@ void border_get_part_geometry(
+ 		ret_g->height = sidebar_g->height;
+ 		break;
+ 	case PART_BORDER_NW:
+ 	case PART_BORDER_NE:
+ 	case PART_BORDER_SW:
+ 	case PART_BORDER_SE:
+ 		ret_g->width = sidebar_g->x;
+ 		ret_g->height = sidebar_g->y;
+ 		break;
+ 	default:
+-		return;
++		break;
++	}
++
++	if (HAS_BORDER_UNDER_TITLE(fw))
++	{
++		title = False;
++		switch (GET_TITLE_DIR(fw))
++		{
++		case DIR_N: title = part & PART_TOP; break;
++		case DIR_E: title = part & PART_RIGHT; break;
++		case DIR_S: title = part & PART_BOTTOM; break;
++		case DIR_W: title = part & PART_LEFT; break;
++		}
++		if (title)
++		{
++			ret_g->width = max(ret_g->width, 2 * bw + fw->title_thickness);
++			ret_g->height = max(ret_g->height, 2 * bw + fw->title_thickness);
++			if (part & PART_RIGHT)
++			{
++				ret_g->x = 2 * sidebar_g->x + sidebar_g->width - ret_g->width;
++			}
++			if (part & PART_BOTTOM)
++			{
++				ret_g->y = 2 * sidebar_g->y + sidebar_g->height - ret_g->height;
++			}
++		}
+ 	}
+ 
+ 	return;
+ }
+ 
+ int get_button_number(int context)
+ {
+ 	int i;
+ 
+ 	for (i = 0; (C_L1 << i) & (C_LALL | C_RALL); i++)
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/borders.c~ fvwm-2.5.21-05/fvwm/borders.c~
+--- fvwm-2.5.21-04/fvwm/borders.c~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/borders.c~	2007-03-03 13:18:42.000000000 +0100
+@@ -0,0 +1,5118 @@
++/* -*-c-*- */
++/* This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*
++ * This module is all original code
++ * by Rob Nation
++ * Copyright 1993, Robert Nation
++ *     You may use this code for any purpose, as long as the original
++ *     copyright remains in the source code and all documentation
++ */
++
++/* IMPORTANT NOTE:
++ *
++ * The functions in this module *must not* assume that the geometries in the
++ * FvwmWindow structure reflect the desired geometry of the window or its
++ * parts.  While the window is resized or shaded, they may hold the old
++ * geometry instead of the new one (but you can not rely on this).  Therefore,
++ * these geometries must not be accessed directly or indirectly (by the
++ * functions from geometry,c).  Use the geometries that are passed in via
++ * structure pointers, e.d. "td".
++ */
++
++/* ---------------------------- included header files ---------------------- */
++
++#include "config.h"
++
++#include <stdio.h>
++
++#include "libs/fvwmlib.h"
++#include "libs/Picture.h"
++#include "libs/PictureGraphics.h"
++#include "libs/FRenderInit.h"
++#include "libs/charmap.h"
++#include "libs/wcontext.h"
++#include "fvwm.h"
++#include "execcontext.h"
++#include "externs.h"
++#include "misc.h"
++#include "screen.h"
++#include "geometry.h"
++#include "borders.h"
++#include "builtins.h"
++#include "icons.h"
++#include "frame.h"
++
++/* ---------------------------- local definitions -------------------------- */
++
++/* ---------------------------- local macros ------------------------------- */
++
++#define SWAP_ARGS(f,a1,a2) (f)?(a2):(a1),(f)?(a1):(a2)
++
++/* ---------------------------- imports ------------------------------------ */
++
++extern Window PressedW;
++
++/* ---------------------------- included code files ------------------------ */
++
++/* ---------------------------- local types -------------------------------- */
++
++typedef struct
++{
++	struct
++	{
++		unsigned use_pixmap : 1;
++	} flags;
++	Pixel pixel;
++	struct
++	{
++		Pixmap p;
++		Pixmap shape;
++		Pixmap alpha;
++		int depth;
++		FvwmRenderAttributes fra;
++		rectangle g;
++		int stretch_w;
++		int stretch_h;
++		struct
++		{
++			unsigned is_tiled : 1;
++			unsigned is_stretched : 1;
++		} flags;
++	} pixmap;
++} pixmap_background_type;
++
++typedef struct
++{
++	Pixmap p;
++	FvwmPicture *mp_created_pic;
++	int cs;
++	FvwmPicture *mp_pic;
++	int mp_part;
++	Bool created;
++} bar_pixmap;
++
++typedef struct
++{
++	int count;
++	bar_pixmap *bps;
++} bar_bs_pixmaps;    /* for UseTitleStyle & Colorset */
++
++typedef struct
++{
++	Pixmap frame_pixmap;
++	bar_bs_pixmaps bar_pixmaps[BS_MaxButtonState];
++} dynamic_common_decorations;
++
++typedef struct
++{
++	int relief_width;
++	GC relief_gc;
++	GC shadow_gc;
++	Pixel fore_color;
++	Pixel back_color;
++	int cs;
++	int border_cs;		/* for UseBorderStyle */
++	int bg_border_cs;	/* for UseBorderStyle */
++	Pixmap back_pixmap;
++	XSetWindowAttributes attributes;
++	unsigned long valuemask;
++	Pixmap texture_pixmap;
++	int texture_pixmap_width;
++	int texture_pixmap_height;
++	XSetWindowAttributes notex_attributes;
++	unsigned long notex_valuemask;
++	dynamic_common_decorations dynamic_cd;
++} common_decorations_type;
++
++typedef struct
++{
++	GC relief;
++	GC shadow;
++	GC transparent;
++} draw_border_gcs;
++
++typedef struct
++{
++	int offset_tl;
++	int offset_br;
++	int thickness;
++	int length;
++	unsigned has_x_marks : 1;
++	unsigned has_y_marks : 1;
++} border_marks_descr;
++
++typedef struct
++{
++	int w_dout;
++	int w_hiout;
++	int w_trout;
++	int w_c;
++	int w_trin;
++	int w_shin;
++	int w_din;
++	int sum;
++	int trim;
++	unsigned is_flat : 1;
++} border_relief_size_descr;
++
++typedef struct
++{
++	rectangle sidebar_g;
++	border_relief_size_descr relief;
++	border_marks_descr marks;
++	draw_border_gcs gcs;
++} border_relief_descr;
++
++typedef struct
++{
++	unsigned pressed_bmask : NUMBER_OF_TITLE_BUTTONS;
++	unsigned lit_bmask : NUMBER_OF_TITLE_BUTTONS;
++	unsigned toggled_bmask : NUMBER_OF_TITLE_BUTTONS;
++	unsigned clear_bmask : NUMBER_OF_TITLE_BUTTONS;
++	unsigned draw_bmask : NUMBER_OF_TITLE_BUTTONS;
++	unsigned max_bmask : NUMBER_OF_TITLE_BUTTONS;
++	ButtonState bstate[NUMBER_OF_TITLE_BUTTONS];
++	unsigned is_title_pressed : 1;
++	unsigned is_title_lit : 1;
++	unsigned do_clear_title : 1;
++	ButtonState tstate;
++} border_titlebar_state;
++
++typedef struct
++{
++	GC rgc;
++	GC sgc;
++	FlocaleWinString fstr;
++	DecorFaceStyle *tstyle;
++	DecorFace *df;
++	unsigned is_toggled : 1;
++} title_draw_descr;
++
++typedef struct
++{
++	common_decorations_type *cd;
++	rectangle frame_g;
++	rectangle bar_g;		/* titlebar geo vs the frame */
++	rectangle left_buttons_g;	/* vs the frame */
++	rectangle right_buttons_g;	/* vs the frame */
++	frame_title_layout_t layout;
++	frame_title_layout_t old_layout;
++	border_titlebar_state tbstate;
++	int length;			/* text */
++	int offset;			/* text offset */
++	/* MultiPixmap Geometries */
++	rectangle under_text_g;		/* vs the titlebar */
++	rectangle left_main_g;		/* vs the titlebar */
++	rectangle right_main_g;		/* vs the titlebar */
++	rectangle full_left_main_g;	/* vs the frame */
++	rectangle full_right_main_g;	/* vs the frame */
++	int left_end_length;
++	int left_of_text_length;
++	int right_end_length;
++	int right_of_text_length;
++	rotation_t draw_rotation;
++	rotation_t restore_rotation;
++	unsigned td_is_rotated : 1;
++	unsigned has_been_saved : 1;
++	unsigned has_vt : 1;		/* vertical title ? */
++	unsigned has_an_upsidedown_rotation : 1;  /* 270 || 180 */
++} titlebar_descr;
++
++/* ---------------------------- forward declarations ----------------------- */
++/*  forward declarations are not so good */
++
++/* for grouping titlebar_descr computation */
++static void border_rotate_titlebar_descr(FvwmWindow *fw, titlebar_descr *td);
++
++/* for grouping the MultiPixmap stuff */
++static Bool border_mp_get_use_title_style_parts_and_geometry(
++	titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs,
++	unsigned short sf, int is_left, rectangle *g, int *part);
++
++/* ---------------------------- local variables ---------------------------- */
++
++static const char ulgc[] = { 1, 0, 0, 0x7f, 2, 1, 1 };
++static const char brgc[] = { 1, 1, 2, 0x7f, 0, 0, 3 };
++
++/* ---------------------------- exported variables (globals) --------------- */
++
++XGCValues Globalgcv;
++unsigned long Globalgcm;
++
++/* ---------------------------- local functions ---------------------------- */
++
++static Bool is_button_toggled(
++	FvwmWindow *fw, int button)
++{
++	mwm_flags mf;
++
++	if (!HAS_MWM_BUTTONS(fw))
++	{
++		return False;
++	}
++	mf = TB_MWM_DECOR_FLAGS(GetDecor(fw, buttons[button]));
++	if ((mf & MWM_DECOR_MAXIMIZE) && IS_MAXIMIZED(fw))
++	{
++		return True;
++	}
++	if ((mf & MWM_DECOR_SHADE) && IS_SHADED(fw))
++	{
++		return True;
++	}
++	if ((mf & MWM_DECOR_STICK) &&
++	    (IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw)))
++	{
++		return True;
++	}
++	if (TB_FLAGS(fw->decor->buttons[button]).has_layer &&
++	    fw->layer == TB_LAYER(fw->decor->buttons[button]))
++	{
++		return True;
++	}
++
++	return False;
++}
++
++
++/* rules to get button state */
++static ButtonState border_flags_to_button_state(
++	int is_pressed, int is_lit, int is_toggled)
++{
++	if (!is_lit && Scr.gs.use_inactive_buttons)
++	{
++		if (is_pressed && Scr.gs.use_inactive_down_buttons)
++		{
++			return (is_toggled) ?
++				BS_ToggledInactiveDown : BS_InactiveDown;
++		}
++		else
++		{
++			return (is_toggled) ?
++				BS_ToggledInactiveUp : BS_InactiveUp;
++		}
++	}
++	else
++	{
++		if (is_pressed && Scr.gs.use_active_down_buttons)
++		{
++			return (is_toggled) ?
++				BS_ToggledActiveDown : BS_ActiveDown;
++		}
++		else
++		{
++			return (is_toggled) ?
++				BS_ToggledActiveUp : BS_ActiveUp;
++		}
++	}
++}
++
++static void get_common_decorations(
++	common_decorations_type *cd, FvwmWindow *t,
++	window_parts draw_parts, Bool has_focus, Bool is_border,
++	Bool do_change_gcs)
++{
++	DecorFace *df;
++	color_quad *draw_colors;
++
++	df = border_get_border_style(t, has_focus);
++	cd->bg_border_cs = -1;
++	cd->cs = -1;
++	if (has_focus)
++	{
++		/* are we using textured borders? */
++		if (DFS_FACE_TYPE(df->style) == TiledPixmapButton &&
++		    GetDecor(t, BorderStyle.active.u.p->depth) == Pdepth)
++		{
++			cd->texture_pixmap = GetDecor(
++				t, BorderStyle.active.u.p->picture);
++			cd->texture_pixmap_width = GetDecor(
++				t, BorderStyle.active.u.p->width);
++			cd->texture_pixmap_height = GetDecor(
++				t, BorderStyle.active.u.p->height);
++		}
++		else if (DFS_FACE_TYPE(df->style) == ColorsetButton)
++		{
++			cd->bg_border_cs = GetDecor(
++				t, BorderStyle.active.u.acs.cs);
++		}
++		cd->back_pixmap = Scr.gray_pixmap;
++		if (is_border)
++		{
++			draw_colors = &(t->border_hicolors);
++			cd->cs = t->border_cs_hi;
++		}
++		else
++		{
++			draw_colors = &(t->hicolors);
++			cd->cs = t->cs_hi;
++		}
++	}
++	else
++	{
++		if (DFS_FACE_TYPE(df->style) == TiledPixmapButton &&
++		    GetDecor(t, BorderStyle.inactive.u.p->depth) == Pdepth)
++		{
++			cd->texture_pixmap = GetDecor(
++				t, BorderStyle.inactive.u.p->picture);
++			cd->texture_pixmap_width = GetDecor(
++				t, BorderStyle.inactive.u.p->width);
++			cd->texture_pixmap_height = GetDecor(
++				t, BorderStyle.inactive.u.p->height);
++		}
++		else if (DFS_FACE_TYPE(df->style) == ColorsetButton)
++		{
++			cd->bg_border_cs = GetDecor(
++				t, BorderStyle.inactive.u.acs.cs);
++		}
++		if (IS_STICKY_ACROSS_PAGES(t) || IS_STICKY_ACROSS_DESKS(t))
++		{
++			cd->back_pixmap = Scr.sticky_gray_pixmap;
++		}
++		else
++		{
++			cd->back_pixmap = Scr.light_gray_pixmap;
++		}
++		if (is_border)
++		{
++			draw_colors = &(t->border_colors);
++			cd->cs = t->border_cs;
++		}
++		else
++		{
++			draw_colors = &(t->colors);
++			cd->cs = t->cs;
++		}
++	}
++	cd->fore_color = draw_colors->fore;
++	cd->back_color = draw_colors->back;
++	if (do_change_gcs)
++	{
++		Globalgcv.foreground = draw_colors->hilight;
++		Globalgcm = GCForeground;
++		XChangeGC(dpy, Scr.ScratchGC1, Globalgcm, &Globalgcv);
++		Globalgcv.foreground = draw_colors->shadow;
++		XChangeGC(dpy, Scr.ScratchGC2, Globalgcm, &Globalgcv);
++		cd->relief_gc = Scr.ScratchGC1;
++		cd->shadow_gc = Scr.ScratchGC2;
++	}
++
++	/* MWMBorder style means thin 3d effects */
++	cd->relief_width = (HAS_MWM_BORDER(t) ? 1 : 2);
++
++	if (cd->texture_pixmap)
++	{
++		cd->attributes.background_pixmap = cd->texture_pixmap;
++		cd->valuemask = CWBackPixmap;
++	}
++	else
++	{
++		if (Pdepth < 2)
++		{
++			cd->attributes.background_pixmap = cd->back_pixmap;
++			cd->valuemask = CWBackPixmap;
++		}
++		else
++		{
++			cd->attributes.background_pixel = cd->back_color;
++			cd->valuemask = CWBackPixel;
++		}
++	}
++	if (Pdepth < 2)
++	{
++		cd->notex_attributes.background_pixmap = cd->back_pixmap;
++		cd->notex_valuemask = CWBackPixmap;
++	}
++	else
++	{
++		cd->notex_attributes.background_pixel = cd->back_color;
++		cd->notex_valuemask = CWBackPixel;
++	}
++
++	return;
++}
++
++static window_parts border_get_changed_border_parts(
++	FvwmWindow *fw, rectangle *old_sidebar_g, rectangle *new_sidebar_g,
++	int cs)
++{
++	window_parts changed_parts;
++
++	changed_parts = PART_NONE;
++	if (!CSET_IS_TRANSPARENT_PR(cs) && CSET_HAS_PIXMAP(cs) &&
++	    (old_sidebar_g->x != new_sidebar_g->x ||
++	     old_sidebar_g->y != new_sidebar_g->y ||
++	     old_sidebar_g->width != new_sidebar_g->width ||
++	     old_sidebar_g->height != new_sidebar_g->height))
++	{
++		/* optimizable? */
++		changed_parts |= PART_FRAME;
++		return changed_parts;
++	}
++	if (old_sidebar_g->x != new_sidebar_g->x)
++	{
++		changed_parts |= (PART_FRAME & (~PART_BORDER_W));
++	}
++	if (old_sidebar_g->y != new_sidebar_g->y)
++	{
++		changed_parts |= (PART_FRAME & (~PART_BORDER_N));
++	}
++	if (old_sidebar_g->width != new_sidebar_g->width)
++	{
++		changed_parts |=
++			PART_BORDER_N | PART_BORDER_S;
++		if (DFS_FACE_TYPE(GetDecor(fw, BorderStyle.active.style)) ==
++		    TiledPixmapButton)
++		{
++			changed_parts |=
++				PART_BORDER_NE | PART_BORDER_E | PART_BORDER_SE;
++		}
++	}
++	if (old_sidebar_g->height != new_sidebar_g->height)
++	{
++		changed_parts |=
++			PART_BORDER_W | PART_BORDER_E;
++		if (DFS_FACE_TYPE(GetDecor(fw, BorderStyle.active.style)) ==
++		    TiledPixmapButton)
++		{
++			changed_parts |=
++				PART_BORDER_SW | PART_BORDER_S | PART_BORDER_SE;
++		}
++	}
++
++	return changed_parts;
++}
++
++static int border_get_parts_and_pos_to_draw(
++	common_decorations_type *cd, FvwmWindow *fw,
++	window_parts pressed_parts, window_parts force_draw_parts,
++	rectangle *old_g, rectangle *new_g, Bool do_hilight,
++	border_relief_descr *br)
++{
++	window_parts draw_parts;
++	window_parts parts_to_light;
++	rectangle sidebar_g_old;
++	DecorFaceStyle *borderstyle;
++	Bool has_x_marks;
++	Bool has_x_marks_old;
++	Bool has_y_marks;
++	Bool has_y_marks_old;
++	int cs = cd->bg_border_cs;
++
++	draw_parts = 0;
++	borderstyle = (do_hilight) ?
++		&GetDecor(fw, BorderStyle.active.style) :
++		&GetDecor(fw, BorderStyle.inactive.style);
++	frame_get_sidebar_geometry(
++		fw, borderstyle,  new_g, &br->sidebar_g, &has_x_marks,
++		&has_y_marks);
++	if (has_x_marks == True)
++	{
++		draw_parts |= PART_X_HANDLES;
++		br->marks.has_x_marks = 1;
++	}
++	else
++	{
++		br->marks.has_x_marks = 0;
++	}
++	if (has_y_marks == True)
++	{
++		draw_parts |= PART_Y_HANDLES;
++		br->marks.has_y_marks = 1;
++	}
++	else
++	{
++		br->marks.has_y_marks = 0;
++	}
++	draw_parts |= (pressed_parts ^ fw->decor_state.parts_inverted);
++	parts_to_light = (do_hilight == True) ? PART_FRAME : PART_NONE;
++	draw_parts |= (parts_to_light ^ fw->decor_state.parts_lit);
++	draw_parts |= (~(fw->decor_state.parts_drawn) & PART_FRAME);
++	draw_parts |= force_draw_parts;
++	if (old_g == NULL)
++	{
++		old_g = &fw->g.frame;
++	}
++	if ((draw_parts & PART_FRAME) == PART_FRAME)
++	{
++		draw_parts |= PART_FRAME;
++		return draw_parts;
++	}
++	frame_get_sidebar_geometry(
++		fw, borderstyle, old_g, &sidebar_g_old, &has_x_marks_old,
++		&has_y_marks_old);
++	if (has_x_marks_old != has_x_marks)
++	{
++		draw_parts |= (PART_FRAME & (~(PART_BORDER_N | PART_BORDER_S)));
++	}
++	if (has_y_marks_old != has_y_marks)
++	{
++		draw_parts |= (PART_FRAME & (~(PART_BORDER_W | PART_BORDER_E)));
++	}
++	draw_parts |= border_get_changed_border_parts(
++		fw, &sidebar_g_old, &br->sidebar_g, cs);
++	draw_parts &= (PART_FRAME | PART_HANDLES);
++
++	return draw_parts;
++}
++
++static window_parts border_get_tb_parts_to_draw(
++	FvwmWindow *fw, titlebar_descr *td, rectangle *old_g, rectangle *new_g,
++	window_parts force_draw_parts)
++{
++	window_parts draw_parts;
++	ButtonState old_state;
++	int i;
++	DecorFace *df,*tdf;
++
++	td->tbstate.draw_bmask = 0;
++	draw_parts = PART_NONE;
++	/* first time? */
++	draw_parts |= (~(fw->decor_state.parts_drawn) & PART_TITLE);
++	td->tbstate.draw_bmask |= (~(fw->decor_state.buttons_drawn));
++	/* forced? */
++	draw_parts |= force_draw_parts;
++	td->tbstate.draw_bmask |= (force_draw_parts & PART_BUTTONS) ? ~0 : 0;
++	/* check if state changed */
++	old_state = border_flags_to_button_state(
++		(fw->decor_state.parts_inverted & PART_TITLE),
++		(fw->decor_state.parts_lit & PART_TITLE), 0);
++	if (old_state != td->tbstate.tstate)
++	{
++		draw_parts |= PART_TITLE;
++	}
++	/* size changed? */
++	if ((td->old_layout.title_g.width != td->layout.title_g.width ||
++	     td->old_layout.title_g.height != td->layout.title_g.height) &&
++	    td->layout.title_g.x >= 0 && td->layout.title_g.y >= 0)
++	{
++		draw_parts |= PART_TITLE;
++	}
++	/* same for buttons */
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		unsigned int mask = (1 << i);
++
++		if (FW_W_BUTTON(fw, i) == None)
++		{
++			continue;
++		}
++		old_state = border_flags_to_button_state(
++			(fw->decor_state.buttons_inverted & mask),
++			(fw->decor_state.buttons_lit & mask),
++			(fw->decor_state.buttons_toggled & mask));
++		if (old_state != td->tbstate.bstate[i])
++		{
++			draw_parts |= PART_BUTTONS;
++			td->tbstate.draw_bmask |= mask;
++		}
++		if ((td->old_layout.button_g[i].width !=
++		     td->layout.button_g[i].width ||
++		     td->old_layout.button_g[i].height !=
++		     td->layout.button_g[i].height) &&
++		    td->layout.button_g[i].x >= 0 &&
++		    td->layout.button_g[i].y >= 0)
++		{
++			draw_parts |= PART_BUTTONS;
++			td->tbstate.draw_bmask |= mask;
++		}
++	}
++	/* position changed and background is tiled or a cset? */
++	if ((draw_parts & PART_TITLE) == PART_NONE &&
++	    td->layout.title_g.x >= 0 &&
++	    td->layout.title_g.y >= 0)
++	{
++		df = &TB_STATE(GetDecor(fw, titlebar))[td->tbstate.tstate];
++		if (DFS_USE_BORDER_STYLE(df->style) &&
++		    (((td->old_layout.title_g.x != td->layout.title_g.x ||
++		       td->old_layout.title_g.y != td->layout.title_g.y) &&
++		      ((td->cd->valuemask & CWBackPixmap) ||
++		       CSET_PIXMAP_IS_TILED(td->cd->bg_border_cs)))
++		     ||
++		     (old_g->width != new_g->width &&
++		      CSET_PIXMAP_IS_X_STRETCHED(td->cd->bg_border_cs))
++		     ||
++		     (old_g->height != new_g->height
++		      && CSET_PIXMAP_IS_Y_STRETCHED(td->cd->bg_border_cs))
++		     ||
++		     ((old_g->x != new_g->x || old_g->y != new_g->y)
++		      && CSET_IS_TRANSPARENT_ROOT(td->cd->bg_border_cs))))
++		{
++				draw_parts |= PART_TITLE;
++		}
++		if ((draw_parts & PART_TITLE) == PART_NONE &&
++		    (old_g->x != new_g->x || old_g->y != new_g->y))
++		{
++			for (tdf = df; tdf != NULL; tdf = tdf->next)
++			{
++				if (DFS_FACE_TYPE(tdf->style) ==
++				    ColorsetButton &&
++				    CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
++				{
++					draw_parts |= PART_TITLE;
++					break;
++				}
++			}
++		}
++	}
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		unsigned int mask;
++		DecorFaceStyle *bs;
++
++		mask = (1 << i);
++		bs = &TB_STATE(
++			GetDecor(fw, buttons[i]))[td->tbstate.bstate[i]].style;
++		if ((td->tbstate.draw_bmask & mask) ||
++		    td->layout.button_g[i].x < 0 ||
++		    td->layout.button_g[i].y < 0)
++		{
++			continue;
++		}
++		if (DFS_USE_BORDER_STYLE(*bs) &&
++		    (((td->old_layout.button_g[i].x !=
++		       td->layout.button_g[i].x||
++		       td->old_layout.button_g[i].y !=
++		       td->layout.button_g[i].y)
++		      && ((td->cd->valuemask & CWBackPixmap) ||
++			  CSET_PIXMAP_IS_TILED(td->cd->bg_border_cs)))
++		     ||
++		     (old_g->width != new_g->width &&
++		      CSET_PIXMAP_IS_X_STRETCHED(td->cd->bg_border_cs))
++		     ||
++		     (old_g->height != new_g->height
++		      && CSET_PIXMAP_IS_Y_STRETCHED(td->cd->bg_border_cs))
++		     ||
++		     ((old_g->x != new_g->x || old_g->y != new_g->y)
++		      && CSET_IS_TRANSPARENT_ROOT(td->cd->bg_border_cs))))
++		{
++			td->tbstate.draw_bmask |= mask;
++		}
++		else if (DFS_USE_TITLE_STYLE(*bs))
++		{
++			df = &TB_STATE(GetDecor(
++				fw, titlebar))[td->tbstate.bstate[i]];
++			for(tdf = df; tdf != NULL; tdf = tdf->next)
++			{
++				int cs;
++				if (DFS_FACE_TYPE(tdf->style) == MultiPixmap)
++				{
++					/* can be improved */
++					td->tbstate.draw_bmask |= mask;
++					break;
++				}
++				if (DFS_FACE_TYPE(tdf->style) != ColorsetButton
++				    || !CSET_HAS_PIXMAP(tdf->u.acs.cs))
++				{
++					continue;
++				}
++				cs = tdf->u.acs.cs;
++				if(((td->old_layout.button_g[i].x !=
++				     td->layout.button_g[i].x ||
++				     td->old_layout.button_g[i].y !=
++				     td->layout.button_g[i].y) ||
++				    CSET_PIXMAP_IS_TILED(cs))
++				   ||
++				   (old_g->width != new_g->width &&
++				    CSET_PIXMAP_IS_X_STRETCHED(cs))
++				   ||
++				   (old_g->height != new_g->height &&
++				    CSET_PIXMAP_IS_Y_STRETCHED(cs))
++					||
++				   ((old_g->x != new_g->x ||
++				     old_g->y != new_g->y)
++				    && CSET_IS_TRANSPARENT_ROOT(cs)))
++				{
++					td->tbstate.draw_bmask |= mask;
++					break;
++				}
++			}
++		}
++		if (td->tbstate.draw_bmask & mask)
++		{
++			continue;
++		}
++		if (old_g->x != new_g->x || old_g->y != new_g->y)
++		{
++			df = &TB_STATE(GetDecor(
++				fw, buttons[i]))[td->tbstate.bstate[i]];
++			for(tdf = df; tdf != NULL; tdf = tdf->next)
++			{
++				if (DFS_FACE_TYPE(tdf->style) ==
++				    ColorsetButton &&
++				    CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
++				{
++					td->tbstate.draw_bmask |= mask;
++					break;
++				}
++			}
++		}
++	}
++	td->tbstate.max_bmask = 0;
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		if (FW_W_BUTTON(fw, i) == None)
++		{
++			continue;
++		}
++		if ((i & 1) == 1 && i / 2 < Scr.nr_right_buttons)
++		{
++			td->tbstate.max_bmask |= (1 << i);
++		}
++		else if ((i & 1) == 0 && i / 2 < Scr.nr_left_buttons)
++		{
++			td->tbstate.max_bmask |= (1 << i);
++		}
++	}
++	td->tbstate.draw_bmask &= td->tbstate.max_bmask;
++	td->tbstate.pressed_bmask &= td->tbstate.max_bmask;
++	td->tbstate.lit_bmask &= td->tbstate.max_bmask;
++	td->tbstate.toggled_bmask &= td->tbstate.max_bmask;
++	td->tbstate.clear_bmask &= td->tbstate.max_bmask;
++	if (td->tbstate.draw_bmask == 0)
++	{
++		draw_parts &= ~PART_BUTTONS;
++	}
++	else
++	{
++		draw_parts |= PART_BUTTONS;
++	}
++	draw_parts &= PART_TITLEBAR;
++
++	return draw_parts;
++}
++
++static void border_get_border_gcs(
++	draw_border_gcs *ret_gcs, common_decorations_type *cd, FvwmWindow *fw,
++	Bool do_hilight)
++{
++	static GC transparent_gc = None;
++	DecorFaceStyle *borderstyle;
++	Bool is_reversed = False;
++
++	if (transparent_gc == None && !HAS_NO_BORDER(fw) && !HAS_MWM_BORDER(fw))
++	{
++		XGCValues xgcv;
++
++		xgcv.function = GXnoop;
++		xgcv.plane_mask = 0;
++		transparent_gc = fvwmlib_XCreateGC(
++			dpy, Scr.NoFocusWin, GCFunction | GCPlaneMask, &xgcv);
++	}
++	ret_gcs->transparent = transparent_gc;
++	/* get the border style bits */
++	borderstyle = (do_hilight) ?
++		&GetDecor(fw, BorderStyle.active.style) :
++		&GetDecor(fw, BorderStyle.inactive.style);
++	if (borderstyle->flags.button_relief == DFS_BUTTON_IS_SUNK)
++	{
++		is_reversed = True;
++	}
++	if (is_reversed)
++	{
++		ret_gcs->shadow = cd->relief_gc;
++		ret_gcs->relief = cd->shadow_gc;
++	}
++	else
++	{
++		ret_gcs->relief = cd->relief_gc;
++		ret_gcs->shadow = cd->shadow_gc;
++	}
++
++	return;
++}
++
++static void trim_border_layout(
++	FvwmWindow *fw, DecorFaceStyle *borderstyle,
++	border_relief_size_descr *ret_size_descr)
++{
++	/* If the border is too thin to accomodate the standard look, we remove
++	 * parts of the border so that at least one pixel of the original
++	 * colour is visible. We make an exception for windows with a border
++	 * width of 2, though. */
++	if ((!IS_SHADED(fw) || HAS_TITLE(fw)) && fw->boundary_width == 2)
++	{
++		ret_size_descr->trim--;
++	}
++	if (ret_size_descr->trim < 0)
++	{
++		ret_size_descr->trim = 0;
++	}
++	for ( ; ret_size_descr->trim > 0; ret_size_descr->trim--)
++	{
++		if (ret_size_descr->w_hiout > 1)
++		{
++			ret_size_descr->w_hiout--;
++		}
++		else if (ret_size_descr->w_shin > 0)
++		{
++			ret_size_descr->w_shin--;
++		}
++		else if (ret_size_descr->w_hiout > 0)
++		{
++			ret_size_descr->w_hiout--;
++		}
++		else if (ret_size_descr->w_trout > 0)
++		{
++			ret_size_descr->w_trout = 0;
++			ret_size_descr->w_trin = 0;
++			ret_size_descr->w_din = 0;
++			ret_size_descr->w_hiout = 1;
++		}
++		ret_size_descr->sum--;
++	}
++	ret_size_descr->w_c = fw->boundary_width - ret_size_descr->sum;
++
++	return;
++}
++
++static void check_remove_inset(
++	DecorFaceStyle *borderstyle, border_relief_size_descr *ret_size_descr)
++{
++	if (!DFS_HAS_NO_INSET(*borderstyle))
++	{
++		return;
++	}
++	ret_size_descr->w_shin = 0;
++	ret_size_descr->sum--;
++	ret_size_descr->trim--;
++	if (ret_size_descr->w_trin)
++	{
++		ret_size_descr->w_trout = 0;
++		ret_size_descr->w_trin = 0;
++		ret_size_descr->w_din = 0;
++		ret_size_descr->w_hiout = 1;
++		ret_size_descr->sum -= 2;
++		ret_size_descr->trim -= 2;
++	}
++
++	return;
++}
++
++static void border_fetch_mwm_layout(
++	FvwmWindow *fw, DecorFaceStyle *borderstyle,
++	border_relief_size_descr *ret_size_descr)
++{
++	/* MWM borders look like this:
++	 *
++	 * HHCCCCS  from outside to inside on the left and top border
++	 * SSCCCCH  from outside to inside on the bottom and right border
++	 * |||||||
++	 * |||||||__ w_shin	(inner shadow area)
++	 * ||||||___ w_c	(transparent area)
++	 * |||||____ w_c	(transparent area)
++	 * ||||_____ w_c	(transparent area)
++	 * |||______ w_c	(transparent area)
++	 * ||_______ w_hiout	(outer hilight area)
++	 * |________ w_hiout	(outer hilight area)
++	 *
++	 *
++	 * C = original colour
++	 * H = hilight
++	 * S = shadow
++	 */
++	ret_size_descr->w_dout = 0;
++	ret_size_descr->w_hiout = 2;
++	ret_size_descr->w_trout = 0;
++	ret_size_descr->w_trin = 0;
++	ret_size_descr->w_shin = 1;
++	ret_size_descr->w_din = 0;
++	ret_size_descr->sum = 3;
++	ret_size_descr->trim = ret_size_descr->sum - fw->boundary_width + 1;
++	check_remove_inset(borderstyle, ret_size_descr);
++	trim_border_layout(fw, borderstyle, ret_size_descr);
++
++	return;
++}
++
++static void border_fetch_fvwm_layout(
++	FvwmWindow *fw, DecorFaceStyle *borderstyle,
++	border_relief_size_descr *ret_size_descr)
++{
++	/* Fvwm borders look like this:
++	 *
++	 * SHHCCSS  from outside to inside on the left and top border
++	 * SSCCHHS  from outside to inside on the bottom and right border
++	 * |||||||
++	 * |||||||__ w_din	(inner dark area)
++	 * ||||||___ w_shin	(inner shadow area)
++	 * |||||____ w_trin	(inner transparent/shadow area)
++	 * ||||_____ w_c	(transparent area)
++	 * |||______ w_trout	(outer transparent/hilight area)
++	 * ||_______ w_hiout	(outer hilight area)
++	 * |________ w_dout	(outer dark area)
++	 *
++	 * C = original colour
++	 * H = hilight
++	 * S = shadow
++	 *
++	 * reduced to 5 pixels it looks like this:
++	 *
++	 * SHHCS
++	 * SSCHS
++	 * |||||
++	 * |||||__ w_din	(inner dark area)
++	 * ||||___ w_trin	(inner transparent/shadow area)
++	 * |||____ w_trout	(outer transparent/hilight area)
++	 * ||_____ w_hiout	(outer hilight area)
++	 * |______ w_dout	(outer dark area)
++	 */
++	ret_size_descr->w_dout = 1;
++	ret_size_descr->w_hiout = 1;
++	ret_size_descr->w_trout = 1;
++	ret_size_descr->w_trin = 1;
++	ret_size_descr->w_shin = 1;
++	ret_size_descr->w_din = 1;
++	/* w_trout + w_trin counts only as one pixel of border because
++	 * they let one pixel of the original colour shine through. */
++	ret_size_descr->sum = 6;
++	ret_size_descr->trim = ret_size_descr->sum - fw->boundary_width;
++	check_remove_inset(borderstyle, ret_size_descr);
++	trim_border_layout(fw, borderstyle, ret_size_descr);
++
++	return;
++}
++
++static void border_get_border_relief_size_descr(
++	border_relief_size_descr *ret_size_descr, FvwmWindow *fw,
++	Bool do_hilight)
++{
++	DecorFaceStyle *borderstyle;
++
++	if (is_window_border_minimal(fw))
++	{
++		/* the border is too small, only a background but no relief */
++		ret_size_descr->is_flat = 1;
++		return;
++	}
++	borderstyle = (do_hilight) ?
++		&GetDecor(fw, BorderStyle.active.style) :
++		&GetDecor(fw, BorderStyle.inactive.style);
++	if (borderstyle->flags.button_relief == DFS_BUTTON_IS_FLAT)
++	{
++		ret_size_descr->is_flat = 1;
++		return;
++	}
++	ret_size_descr->is_flat = 0;
++	/* get the relief layout */
++	if (HAS_MWM_BORDER(fw))
++	{
++		border_fetch_mwm_layout(fw, borderstyle, ret_size_descr);
++	}
++	else
++	{
++		border_fetch_fvwm_layout(fw, borderstyle, ret_size_descr);
++	}
++
++	return;
++}
++
++static void border_get_border_marks_descr(
++	common_decorations_type *cd, border_relief_descr *br, FvwmWindow *fw)
++{
++	int inset;
++
++	/* get mark's length and thickness */
++	inset = (br->relief.w_shin != 0 || br->relief.w_din != 0);
++	br->marks.length = fw->boundary_width - br->relief.w_dout - inset;
++	if (br->marks.length <= 0)
++	{
++		br->marks.has_x_marks = 0;
++		br->marks.has_y_marks = 0;
++		return;
++	}
++	br->marks.thickness = cd->relief_width;
++	if (br->marks.thickness > br->marks.length)
++	{
++		br->marks.thickness = br->marks.length;
++	}
++	/* get offsets from outer side of window */
++	br->marks.offset_tl = br->relief.w_dout;
++	br->marks.offset_br =
++		-br->relief.w_dout - br->marks.length - br->marks.offset_tl;
++
++	return;
++}
++
++static Pixmap border_create_decor_pixmap(
++	common_decorations_type *cd, rectangle *decor_g)
++{
++	Pixmap p;
++
++	p = XCreatePixmap(
++		dpy, Scr.Root, decor_g->width, decor_g->height, Pdepth);
++
++	return p;
++}
++
++static void border_draw_part_relief(
++	border_relief_descr *br, rectangle *frame_g, rectangle *part_g,
++	Pixmap dest_pix, Bool is_inverted)
++{
++	int i;
++	int off_x = 0;
++	int off_y = 0;
++	int width = frame_g->width - 1;
++	int height = frame_g->height - 1;
++	int w[7];
++	GC gc[4];
++
++	w[0] = br->relief.w_dout;
++	w[1] = br->relief.w_hiout;
++	w[2] = br->relief.w_trout;
++	w[3] = br->relief.w_c;
++	w[4] = br->relief.w_trin;
++	w[5] = br->relief.w_shin;
++	w[6] = br->relief.w_din;
++	gc[(is_inverted == True)] = br->gcs.relief;
++	gc[!(is_inverted == True)] = br->gcs.shadow;
++	gc[2] = br->gcs.transparent;
++	gc[3] = br->gcs.shadow;
++
++	off_x = -part_g->x;
++	off_y = -part_g->y;
++	width = frame_g->width - 1;
++	height = frame_g->height - 1;
++	for (i = 0; i < 7; i++)
++	{
++		if (ulgc[i] != 0x7f && w[i] > 0)
++		{
++			do_relieve_rectangle(
++				dpy, dest_pix, off_x, off_y,
++				width, height, gc[(int)ulgc[i]],
++				gc[(int)brgc[i]], w[i], False);
++		}
++		off_x += w[i];
++		off_y += w[i];
++		width -= 2 * w[i];
++		height -= 2 * w[i];
++	}
++
++	return;
++}
++
++static void border_draw_x_mark(
++	border_relief_descr *br, int x, int y, Pixmap dest_pix,
++	Bool do_draw_shadow)
++{
++	int k;
++	int length;
++	GC gc;
++
++	if (br->marks.has_x_marks == 0)
++	{
++		return;
++	}
++	x += br->marks.offset_tl;
++	gc = (do_draw_shadow) ? br->gcs.shadow : br->gcs.relief;
++	/* draw it */
++	for (k = 0, length = br->marks.length - 1; k < br->marks.thickness;
++	     k++, length--)
++	{
++		int x1;
++		int x2;
++		int y1;
++		int y2;
++
++		if (length < 0)
++		{
++			break;
++		}
++		if (do_draw_shadow)
++		{
++			x1 = x + k;
++			y1 = y - 1 - k;
++		}
++		else
++		{
++			x1 = x;
++			y1 = y + k;
++		}
++		x2 = x1 + length;
++		y2 = y1;
++		XDrawLine(dpy, dest_pix, gc, x1, y1, x2, y2);
++	}
++
++	return;
++}
++
++static void border_draw_y_mark(
++	border_relief_descr *br, int x, int y, Pixmap dest_pix,
++	Bool do_draw_shadow)
++{
++	int k;
++	int length;
++	GC gc;
++
++	if (br->marks.has_y_marks == 0)
++	{
++		return;
++	}
++	y += br->marks.offset_tl;
++	gc = (do_draw_shadow) ? br->gcs.shadow : br->gcs.relief;
++	/* draw it */
++	for (k = 0, length = br->marks.length; k < br->marks.thickness;
++	     k++, length--)
++	{
++		int x1;
++		int x2;
++		int y1;
++		int y2;
++
++		if (length <= 0)
++		{
++			break;
++		}
++		if (do_draw_shadow)
++		{
++			x1 = x - 1 - k;
++			y1 = y + k;
++		}
++		else
++		{
++			x1 = x + k;
++			y1 = y;
++		}
++		x2 = x1;
++		y2 = y1 + length - 1;
++		XDrawLine(dpy, dest_pix, gc, x1, y1, x2, y2);
++	}
++
++	return;
++}
++
++static void border_draw_part_marks(
++	border_relief_descr *br, rectangle *part_g, window_parts part,
++	Pixmap dest_pix)
++{
++	int l;
++	int t;
++	int w;
++	int h;
++	int o;
++
++	l = br->sidebar_g.x;
++	t = br->sidebar_g.y;
++	w = part_g->width;
++	h = part_g->height;
++	o = br->marks.offset_br;
++	switch (part)
++	{
++	case PART_BORDER_N:
++		border_draw_y_mark(br, 0, 0, dest_pix, False);
++		border_draw_y_mark(br, w, 0, dest_pix, True);
++		break;
++	case PART_BORDER_S:
++		border_draw_y_mark(br, 0, h + o, dest_pix, False);
++		border_draw_y_mark(br, w, h + o, dest_pix, True);
++		break;
++	case PART_BORDER_E:
++		border_draw_x_mark(br, w + o, 0, dest_pix, False);
++		border_draw_x_mark(br, w + o, h, dest_pix, True);
++		break;
++	case PART_BORDER_W:
++		border_draw_x_mark(br, 0, 0, dest_pix, False);
++		border_draw_x_mark(br, 0, h, dest_pix, True);
++		break;
++	case PART_BORDER_NW:
++		border_draw_x_mark(br, 0, t, dest_pix, True);
++		border_draw_y_mark(br, l, 0, dest_pix, True);
++		break;
++	case PART_BORDER_NE:
++		border_draw_x_mark(br, l + o, t, dest_pix, True);
++		border_draw_y_mark(br, 0, 0, dest_pix, False);
++		break;
++	case PART_BORDER_SW:
++		border_draw_x_mark(br, 0, 0, dest_pix, False);
++		border_draw_y_mark(br, l, t + o, dest_pix, True);
++		break;
++	case PART_BORDER_SE:
++		border_draw_x_mark(br, l + o, 0, dest_pix, False);
++		border_draw_y_mark(br, 0, t + o, dest_pix, False);
++		break;
++	default:
++		return;
++	}
++
++	return;
++}
++
++inline static void border_set_part_background(
++	Window w, Pixmap pix)
++{
++	XSetWindowAttributes xswa;
++
++	xswa.background_pixmap = pix;
++	XChangeWindowAttributes(dpy, w, CWBackPixmap, &xswa);
++
++	return;
++}
++
++/* render the an image into the pixmap */
++static void border_fill_pixmap_background(
++	Pixmap dest_pix, rectangle *dest_g, pixmap_background_type *bg,
++	common_decorations_type *cd)
++{
++	Bool do_tile;
++	Bool do_stretch;
++	XGCValues xgcv;
++	unsigned long valuemask;
++	Pixmap p = None, shape = None, alpha = None;
++	int src_width, src_height;
++
++	do_tile = (bg->flags.use_pixmap && bg->pixmap.flags.is_tiled) ?
++		True : False;
++	do_stretch = (bg->flags.use_pixmap && bg->pixmap.flags.is_stretched) ?
++		True : False;
++	xgcv.fill_style = FillSolid;
++	valuemask = GCFillStyle;
++	if (!bg->flags.use_pixmap)
++	{
++		/* solid pixel */
++		xgcv.foreground = bg->pixel;
++		xgcv.clip_x_origin = 0;
++		xgcv.clip_y_origin = 0;
++		xgcv.clip_mask = None;
++		valuemask |= GCForeground | GCClipMask | GCClipXOrigin |
++			GCClipYOrigin;
++		XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv);
++		XFillRectangle(
++			dpy, dest_pix, Scr.BordersGC, dest_g->x, dest_g->y,
++			dest_g->width - dest_g->x, dest_g->height - dest_g->y);
++		return;
++	}
++
++	if (do_stretch)
++	{
++		if (bg->pixmap.p)
++		{
++			p = CreateStretchPixmap(
++				dpy, bg->pixmap.p,
++				bg->pixmap.g.width, bg->pixmap.g.height,
++				bg->pixmap.depth,
++				bg->pixmap.stretch_w, bg->pixmap.stretch_h,
++				(bg->pixmap.depth == 1)?
++				Scr.MonoGC:Scr.BordersGC);
++		}
++		if (bg->pixmap.shape)
++		{
++			shape = CreateStretchPixmap(
++				dpy, bg->pixmap.shape,
++				bg->pixmap.g.width, bg->pixmap.g.height, 1,
++				bg->pixmap.stretch_w, bg->pixmap.stretch_h,
++				Scr.MonoGC);
++		}
++		if (bg->pixmap.alpha)
++		{
++			alpha = CreateStretchPixmap(
++				dpy, bg->pixmap.alpha,
++				bg->pixmap.g.width, bg->pixmap.g.height,
++				FRenderGetAlphaDepth(),
++				bg->pixmap.stretch_w, bg->pixmap.stretch_h,
++				Scr.AlphaGC);
++		}
++		src_width = bg->pixmap.stretch_w;
++		src_height = bg->pixmap.stretch_h;
++	}
++	else
++	{
++		p = bg->pixmap.p;
++		shape = bg->pixmap.shape;
++		alpha =	bg->pixmap.alpha;
++		src_width = bg->pixmap.g.width;
++		src_height = bg->pixmap.g.height;
++	}
++
++	if (do_tile == False)
++	{
++		/* pixmap, offset stored in dest_g->x/y */
++		xgcv.foreground = cd->fore_color;
++		xgcv.background = cd->back_color;
++		valuemask |= GCForeground|GCBackground;
++		XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv);
++		PGraphicsRenderPixmaps(
++			dpy, Scr.NoFocusWin, p, shape, alpha,
++			bg->pixmap.depth, &(bg->pixmap.fra),
++			dest_pix, Scr.BordersGC, Scr.MonoGC, Scr.AlphaGC,
++			bg->pixmap.g.x, bg->pixmap.g.y,
++			src_width, src_height,
++			dest_g->x, dest_g->y, dest_g->width - dest_g->x,
++			dest_g->height - dest_g->y, False);
++	}
++	else
++	{
++		/* tiled pixmap */
++		xgcv.foreground = cd->fore_color;
++		xgcv.background = cd->back_color;
++		valuemask |= GCForeground|GCBackground;
++		XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv);
++		PGraphicsRenderPixmaps(
++			dpy, Scr.NoFocusWin, p, shape, alpha,
++			bg->pixmap.depth, &(bg->pixmap.fra),
++			dest_pix, Scr.BordersGC, Scr.MonoGC, Scr.AlphaGC,
++			bg->pixmap.g.x, bg->pixmap.g.y,
++			src_width, src_height,
++			dest_g->x, dest_g->y,
++			dest_g->width - dest_g->x,
++			dest_g->height - dest_g->y, True);
++	}
++	if (p && p != bg->pixmap.p)
++	{
++		XFreePixmap(dpy, p);
++	}
++	if (shape && shape != bg->pixmap.shape)
++	{
++		XFreePixmap(dpy, shape);
++	}
++	if (alpha && alpha != bg->pixmap.alpha)
++	{
++		XFreePixmap(dpy, alpha);
++	}
++	return;
++}
++
++/* create a root transparent colorset bg, we take in account a possible
++ * drawing rotation */
++static Pixmap border_create_root_transparent_pixmap(
++	titlebar_descr *td, Window w, int width, int height, int cs)
++{
++	int my_w, my_h;
++	Pixmap p;
++
++	if (!CSET_IS_TRANSPARENT_ROOT(cs))
++	{
++		return None;
++	}
++	if (td->td_is_rotated &&
++	    (td->draw_rotation == ROTATION_90 ||
++	     td->draw_rotation == ROTATION_270))
++	{
++		my_h = width;
++		my_w = height;
++	}
++	else
++	{
++		my_w = width;
++		my_h = height;
++	}
++	p = CreateBackgroundPixmap(
++		dpy, w, my_w, my_h, &Colorset[cs],
++		Pdepth, Scr.BordersGC, False);
++	if (p && td->td_is_rotated)
++	{
++		Pixmap tmp;
++		tmp = CreateRotatedPixmap(
++			dpy, p, my_w, my_h, Pdepth, Scr.BordersGC,
++			td->restore_rotation);
++		XFreePixmap(dpy, p);
++		p = tmp;
++	}
++	return p;
++}
++
++static void border_get_frame_pixmap(
++	common_decorations_type *cd, rectangle *frame_g)
++{
++	dynamic_common_decorations *dcd = &(cd->dynamic_cd);
++
++	if (dcd->frame_pixmap != None)
++	{
++		/* should not happen */
++		fprintf(stderr, "Bad use of border_get_frame_pixmap!!\n");
++		dcd->frame_pixmap = None;
++	}
++
++	if (cd->bg_border_cs < 0 || CSET_IS_TRANSPARENT(cd->bg_border_cs))
++	{
++		/* should not happen */
++	}
++	else
++	{
++		dcd->frame_pixmap = CreateBackgroundPixmap(
++			dpy, Scr.NoFocusWin, frame_g->width, frame_g->height,
++			&Colorset[cd->bg_border_cs], Pdepth, Scr.BordersGC,
++			False);
++	}
++	return;
++}
++
++static void border_get_border_background(
++	pixmap_background_type *bg, common_decorations_type *cd,
++	rectangle *part_g, rectangle *relative_g, int *free_bg_pixmap, Window w)
++{
++	*free_bg_pixmap = False;
++
++	if (cd->texture_pixmap)
++	{
++		bg->flags.use_pixmap = 1;
++		bg->pixmap.p = cd->texture_pixmap;
++		bg->pixmap.g.width = cd->texture_pixmap_width;
++		bg->pixmap.g.height = cd->texture_pixmap_height;
++		bg->pixmap.shape = None;
++		bg->pixmap.alpha = None;
++		bg->pixmap.depth = Pdepth;
++		bg->pixmap.flags.is_tiled = 1;
++		bg->pixmap.flags.is_stretched = 0;
++		bg->pixmap.fra.mask = 0;
++	}
++	else if (cd->bg_border_cs >= 0 &&
++		 !CSET_IS_TRANSPARENT_PR(cd->bg_border_cs))
++	{
++		colorset_t *cs_t = &Colorset[cd->bg_border_cs];
++		XGCValues xgcv;
++
++		if (CSET_IS_TRANSPARENT_ROOT(cd->bg_border_cs))
++		{
++			bg->pixmap.p = CreateBackgroundPixmap(
++				dpy, w, part_g->width, part_g->height, cs_t,
++				Pdepth, Scr.BordersGC, False);
++		}
++		else
++		{
++			/* FIXME */
++			if (cd->dynamic_cd.frame_pixmap == None)
++			{
++				border_get_frame_pixmap(cd, relative_g);
++			}
++			bg->pixmap.p = XCreatePixmap(
++				dpy, cd->dynamic_cd.frame_pixmap, part_g->width,
++				part_g->height, Pdepth);
++			xgcv.fill_style = FillTiled;
++			xgcv.tile = cd->dynamic_cd.frame_pixmap;
++			xgcv.ts_x_origin = - relative_g->x;
++			xgcv.ts_y_origin = - relative_g->y;
++			XChangeGC(
++				dpy, Scr.BordersGC, GCTile | GCTileStipXOrigin |
++				GCTileStipYOrigin | GCFillStyle, &xgcv);
++			XFillRectangle(
++				dpy, bg->pixmap.p, Scr.BordersGC, 0, 0,
++				part_g->width, part_g->height);
++			xgcv.fill_style = FillSolid;
++			XChangeGC(dpy, Scr.BordersGC, GCFillStyle, &xgcv);
++		}
++		bg->pixmap.g.width = part_g->width;
++		bg->pixmap.g.height = part_g->height;
++		bg->flags.use_pixmap = 1;
++		bg->pixmap.shape = None;
++		bg->pixmap.alpha = None;
++		bg->pixmap.depth = Pdepth;
++		bg->pixmap.flags.is_tiled = 1;
++		bg->pixmap.flags.is_stretched = 0;
++		bg->pixmap.fra.mask = 0;
++		*free_bg_pixmap = True;
++	}
++	else
++	{
++		bg->flags.use_pixmap = 0;
++		bg->pixel = cd->attributes.background_pixel;
++	}
++
++	return;
++}
++
++static void border_draw_one_border_part(
++	common_decorations_type *cd, FvwmWindow *fw, rectangle *sidebar_g,
++	rectangle *frame_g, border_relief_descr *br, window_parts part,
++	window_parts draw_handles, Bool is_inverted, Bool do_clear)
++{
++	pixmap_background_type bg;
++	rectangle part_g;
++	rectangle pix_g;
++	rectangle relative_g;
++	Pixmap p;
++	Window w;
++	Bool free_bg_pixmap = False;
++
++	/* make a pixmap */
++	border_get_part_geometry(fw, part, sidebar_g, &part_g, &w);
++	if (part_g.width <= 0 || part_g.height <= 0)
++	{
++		return;
++	}
++	p = border_create_decor_pixmap(cd, &part_g);
++	/* set the background tile */
++	relative_g.width = fw->g.frame.width;
++	relative_g.height = fw->g.frame.height;
++	relative_g.x = part_g.x;
++	relative_g.y = part_g.y;
++	border_get_border_background(
++		&bg, cd, &part_g, &relative_g, &free_bg_pixmap, w);
++	if (cd->texture_pixmap)
++	{
++		switch (part)
++		{
++		case PART_BORDER_E:
++			bg.pixmap.g.x = frame_g->width - fw->boundary_width;
++			break;
++		case PART_BORDER_NE:
++		case PART_BORDER_SE:
++			bg.pixmap.g.x = frame_g->width - fw->corner_width;
++			break;
++		case PART_BORDER_N:
++		case PART_BORDER_S:
++			bg.pixmap.g.x = fw->corner_width;
++			break;
++		default:
++			bg.pixmap.g.x = 0;
++			break;
++		}
++		switch (part)
++		{
++		case PART_BORDER_S:
++			bg.pixmap.g.y = frame_g->height - fw->boundary_width;
++			break;
++		case PART_BORDER_SW:
++		case PART_BORDER_SE:
++			bg.pixmap.g.y = frame_g->height - fw->corner_width;
++			break;
++		case PART_BORDER_W:
++		case PART_BORDER_E:
++			bg.pixmap.g.y = fw->corner_width;
++			break;
++		default:
++			bg.pixmap.g.y = 0;
++			break;
++		}
++	}
++	else
++	{
++		bg.pixmap.g.x = 0;
++		bg.pixmap.g.y = 0;
++	}
++	/* set the geometry for drawing the Tiled pixmap; maybe add the relief
++	 * as offset? */
++	pix_g.x = 0;
++	pix_g.y = 0;
++	pix_g.width = part_g.width;
++	pix_g.height = part_g.height;
++	border_fill_pixmap_background(p, &pix_g, &bg, cd);
++	if (free_bg_pixmap && bg.pixmap.p)
++	{
++		XFreePixmap(dpy, bg.pixmap.p);
++	}
++	/* draw the relief over the background */
++	if (!br->relief.is_flat)
++	{
++		border_draw_part_relief(br, frame_g, &part_g, p, is_inverted);
++		/* draw the handle marks */
++		if (br->marks.has_x_marks || br->marks.has_y_marks)
++		{
++			border_draw_part_marks(br, &part_g, part, p);
++		}
++	}
++	/* apply the pixmap and destroy it */
++	border_set_part_background(w, p);
++	if (do_clear == True)
++	{
++		XClearWindow(dpy,w);
++	}
++	XFreePixmap(dpy, p);
++
++	return;
++}
++
++static void border_draw_all_border_parts(
++	common_decorations_type *cd, FvwmWindow *fw, border_relief_descr *br,
++	rectangle *frame_g, window_parts draw_parts,
++	window_parts pressed_parts, Bool do_hilight, Bool do_clear)
++{
++	window_parts part;
++	window_parts draw_handles;
++
++	/* get the description of the drawing directives */
++	border_get_border_relief_size_descr(&br->relief, fw, do_hilight);
++	border_get_border_marks_descr(cd, br, fw);
++	/* fetch the gcs used to draw the border */
++	border_get_border_gcs(&br->gcs, cd, fw, do_hilight);
++	/* draw everything in a big loop */
++	draw_parts &= (PART_FRAME | PART_HANDLES);
++	draw_handles = (draw_parts & PART_HANDLES);
++
++	for (part = PART_BORDER_N; (part & PART_FRAME); part <<= 1)
++	{
++		if (part & draw_parts)
++		{
++			border_draw_one_border_part(
++				cd, fw, &br->sidebar_g, frame_g, br, part,
++				draw_handles,
++				(pressed_parts & part) ? True : False,
++				do_clear);
++		}
++	}
++
++	return;
++}
++
++/*
++ *
++ *  Draws a little pattern within a window (more complex)
++ *
++ */
++static void border_draw_vector_to_pixmap(
++	Pixmap dest_pix, common_decorations_type *cd, int is_toggled,
++	struct vector_coords *coords, rectangle *pixmap_g)
++{
++	GC gcs[4];
++	int i;
++
++	if (coords->use_fgbg == 1)
++	{
++		Globalgcv.foreground = cd->fore_color;
++		Globalgcm = GCForeground;
++		XChangeGC(dpy, Scr.ScratchGC3, Globalgcm, &Globalgcv);
++		Globalgcv.foreground = cd->back_color;
++		XChangeGC(dpy, Scr.ScratchGC4, Globalgcm, &Globalgcv);
++		gcs[3] = Scr.ScratchGC3; /* @3 is fg */
++		gcs[2] = Scr.ScratchGC4; /* @2 is bg */
++	}
++	if (is_toggled)
++	{
++		gcs[0] = cd->relief_gc;
++		gcs[1] = cd->shadow_gc;
++	}
++	else
++	{
++		gcs[0] = cd->shadow_gc;
++		gcs[1] = cd->relief_gc;
++	}
++	for (i = 1; i < coords->num; i++)
++	{
++		if (coords->c[i] < 0 || coords->c[i] >= 4)
++		{
++			/* don't draw a line */
++			continue;
++		}
++		XDrawLine(
++			dpy, dest_pix, gcs[coords->c[i]],
++			pixmap_g->width * coords->x[i-1] / 100 +
++			coords->xoff[i-1],
++			pixmap_g->height * coords->y[i-1] / 100 +
++			coords->yoff[i-1],
++			pixmap_g->width * coords->x[i] / 100 +
++			coords->xoff[i],
++			pixmap_g->height * coords->y[i] / 100 +
++			coords->yoff[i]);
++	}
++
++	return;
++}
++
++/*
++ *
++ *  Handle Title pixmaps used for UseTitleStyle
++ *
++ */
++static void border_setup_bar_pixmaps(
++	titlebar_descr *td, dynamic_common_decorations *dcd, DecorFace *df,
++	ButtonState bs)
++{
++	int count = dcd->bar_pixmaps[bs].count;
++	DecorFace *tsdf;
++	int i, j, mp_part_left, mp_part_right;
++
++	if (count != 0)
++	{
++		/* ok */
++		return;
++	}
++
++	for (tsdf = df; tsdf != NULL; tsdf = tsdf->next)
++	{
++		if (DFS_FACE_TYPE(tsdf->style) == ColorsetButton)
++		{
++			count++;
++		}
++		else if (DFS_FACE_TYPE(tsdf->style) == MultiPixmap)
++		{
++			border_mp_get_use_title_style_parts_and_geometry(
++				td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
++				tsdf->u.mp.solid_flags, True, NULL,
++				&mp_part_left);
++			border_mp_get_use_title_style_parts_and_geometry(
++				td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
++				tsdf->u.mp.solid_flags, False, NULL,
++				&mp_part_right);
++			for (j = 0; j < UTS_TBMP_NUM_PIXMAPS; j++)
++			{
++				if (j != mp_part_left && j != mp_part_right)
++				{
++					continue;
++				}
++				if (tsdf->u.mp.acs[j].cs >= 0 ||
++				    tsdf->u.mp.pixmaps[j])
++				{
++					count++;
++				}
++			}
++		}
++	}
++	if (count == 0)
++	{
++		dcd->bar_pixmaps[bs].count = -1;
++		return;
++	}
++	else
++	{
++		dcd->bar_pixmaps[bs].bps =
++			(bar_pixmap *)safemalloc(count*sizeof(bar_pixmap));
++	}
++	dcd->bar_pixmaps[bs].count = count;
++	i = 0;
++	for (tsdf = df; tsdf != NULL; tsdf = tsdf->next)
++	{
++		if (DFS_FACE_TYPE(tsdf->style) == ColorsetButton)
++		{
++			dcd->bar_pixmaps[bs].bps[i].p = None;
++			dcd->bar_pixmaps[bs].bps[i].mp_created_pic = NULL;
++			dcd->bar_pixmaps[bs].bps[i].cs = tsdf->u.acs.cs;
++			dcd->bar_pixmaps[bs].bps[i].mp_pic = NULL;
++			dcd->bar_pixmaps[bs].bps[i].created = 0;
++			dcd->bar_pixmaps[bs].bps[i].mp_part = TBMP_NONE;
++			i++;
++		}
++		else if (DFS_FACE_TYPE(tsdf->style) == MultiPixmap)
++		{
++			border_mp_get_use_title_style_parts_and_geometry(
++				td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
++				tsdf->u.mp.solid_flags, True, NULL,
++				&mp_part_left);
++			border_mp_get_use_title_style_parts_and_geometry(
++				td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
++				tsdf->u.mp.solid_flags, False, NULL,
++				&mp_part_right);
++			for (j = 0; j < UTS_TBMP_NUM_PIXMAPS; j++)
++			{
++				if (j != mp_part_left && j != mp_part_right)
++				{
++					continue;
++				}
++				if (tsdf->u.mp.acs[j].cs >= 0 ||
++				    tsdf->u.mp.pixmaps[j])
++				{
++					dcd->bar_pixmaps[bs].bps[i].p = None;
++					dcd->bar_pixmaps[bs].bps[i].
++						mp_created_pic = NULL;
++					dcd->bar_pixmaps[bs].bps[i].cs =
++						tsdf->u.mp.acs[j].cs;
++					dcd->bar_pixmaps[bs].bps[i].mp_pic =
++						tsdf->u.mp.pixmaps[j];
++					dcd->bar_pixmaps[bs].bps[i].created = 0;
++					dcd->bar_pixmaps[bs].bps[i].mp_part = j;
++					i++;
++				}
++			}
++		}
++	}
++}
++
++static Pixmap border_get_bar_pixmaps(
++	dynamic_common_decorations *dcd, rectangle *bar_g, ButtonState bs,
++	int cset, FvwmPicture *mp_pic, int mp_part, int stretch,
++	FvwmPicture **mp_ret_pic)
++{
++	ButtonState b;
++	int i,j;
++	int count = dcd->bar_pixmaps[bs].count;
++
++	if (count <= 0)
++	{
++		return None;
++	}
++
++	i = 0;
++	while(i < count &&
++	(dcd->bar_pixmaps[bs].bps[i].cs != cset ||
++	      dcd->bar_pixmaps[bs].bps[i].mp_part != mp_part ||
++	      dcd->bar_pixmaps[bs].bps[i].mp_pic != mp_pic))
++	{
++		i++;
++	}
++	if (i == count)
++	{
++		return None;
++	}
++	if (mp_ret_pic)
++	{
++		*mp_ret_pic = dcd->bar_pixmaps[bs].bps[i].mp_created_pic;
++	}
++	if (dcd->bar_pixmaps[bs].bps[i].p == None)
++	{
++		/* see if we have it */
++		b = 0;
++		while (b < BS_MaxButtonState)
++		{
++			int c = dcd->bar_pixmaps[b].count;
++			j = 0;
++			while(j < c &&
++			      (dcd->bar_pixmaps[b].bps[j].cs != cset ||
++			       dcd->bar_pixmaps[b].bps[j].mp_part != mp_part ||
++			       dcd->bar_pixmaps[b].bps[j].mp_pic != mp_pic))
++			{
++				j++;
++			}
++			if (j < c && dcd->bar_pixmaps[b].bps[j].p)
++			{
++				dcd->bar_pixmaps[bs].bps[i].p =
++					dcd->bar_pixmaps[b].bps[j].p;
++				if (mp_pic && mp_ret_pic)
++				{
++					*mp_ret_pic =
++						dcd->bar_pixmaps[bs].bps[i].
++						mp_created_pic =
++						dcd->bar_pixmaps[b].bps[j].
++						mp_created_pic;
++				}
++				break;
++			}
++			b++;
++		}
++	}
++	if (dcd->bar_pixmaps[bs].bps[i].p == None)
++	{
++		if (cset >= 0)
++		{
++			dcd->bar_pixmaps[bs].bps[i].p = CreateBackgroundPixmap(
++				dpy, Scr.NoFocusWin, bar_g->width, bar_g->height,
++				&Colorset[cset], Pdepth, Scr.BordersGC, False);
++			dcd->bar_pixmaps[bs].bps[i].created = True;
++		}
++		else if (mp_pic && mp_ret_pic)
++		{
++			if (stretch)
++			{
++				dcd->bar_pixmaps[bs].bps[i].mp_created_pic =
++					PGraphicsCreateStretchPicture(
++						dpy, Scr.NoFocusWin, mp_pic,
++						bar_g->width, bar_g->height,
++						Scr.BordersGC, Scr.MonoGC,
++						Scr.AlphaGC);
++			}
++			else
++			{
++				dcd->bar_pixmaps[bs].bps[i].mp_created_pic =
++					PGraphicsCreateTiledPicture(
++						dpy, Scr.NoFocusWin, mp_pic,
++						bar_g->width, bar_g->height,
++						Scr.BordersGC, Scr.MonoGC,
++						Scr.AlphaGC);
++			}
++			if (dcd->bar_pixmaps[bs].bps[i].mp_created_pic)
++			{
++				dcd->bar_pixmaps[bs].bps[i].created = True;
++				*mp_ret_pic =
++					dcd->bar_pixmaps[bs].bps[i].
++					mp_created_pic;
++				dcd->bar_pixmaps[bs].bps[i].p =
++					dcd->bar_pixmaps[bs].bps[i].
++					mp_created_pic->picture;
++			}
++		}
++	}
++	return dcd->bar_pixmaps[bs].bps[i].p;
++}
++
++static void border_free_bar_pixmaps(
++	dynamic_common_decorations *dcd)
++{
++	ButtonState bs;
++	int i;
++
++	for (bs = 0; bs < BS_MaxButtonState; bs++)
++	{
++		if (dcd->bar_pixmaps[bs].count < 1)
++		{
++			continue;
++		}
++		for (i = 0; i < dcd->bar_pixmaps[bs].count; i++)
++		{
++			if (dcd->bar_pixmaps[bs].bps[i].mp_created_pic &&
++			    dcd->bar_pixmaps[bs].bps[i].created)
++			{
++				PDestroyFvwmPicture(
++					dpy,
++					dcd->bar_pixmaps[bs].bps[i].
++					mp_created_pic);
++			}
++			else if (dcd->bar_pixmaps[bs].bps[i].p != None &&
++				 dcd->bar_pixmaps[bs].bps[i].created)
++			{
++				XFreePixmap(
++					dpy, dcd->bar_pixmaps[bs].bps[i].p);
++			}
++		}
++		free(dcd->bar_pixmaps[bs].bps);
++	}
++}
++
++/*
++ *
++ *  MultiPixmap (aka, fancy title bar) (tril at igs.net)
++ *
++ */
++#define TBMP_HAS_PART(p, pm, acs, sf) \
++       (pm[p] || acs[p].cs >= 0 || (sf & (1 << p)))
++
++/*  Tile or stretch src into dest, starting at the given location and
++ *  continuing for the given width and height. This is a utility function used
++ *  by border_mp_draw_mp_titlebar. (tril at igs.net) */
++static void border_mp_render_into_pixmap(
++	titlebar_descr *td, common_decorations_type *cd, FvwmPicture **src,
++	FvwmAcs *acs, Pixel *pixels, unsigned short solid_flags,
++	unsigned short stretch_flags, int part, Pixmap dest, Window w,
++	rectangle *full_g, rectangle *title_g, ButtonState bs, rectangle *g)
++{
++	int x = 0;
++	int y = 0;
++	pixmap_background_type bg;
++	rectangle dest_g;
++	dynamic_common_decorations *dcd;
++
++	dcd = &cd->dynamic_cd;
++	/* setup some default */
++	bg.pixmap.fra.mask = 0;
++	bg.pixmap.flags.is_stretched = 0;
++	bg.pixmap.flags.is_tiled = 0;
++	bg.flags.use_pixmap = 1;
++	bg.pixmap.p = bg.pixmap.alpha = bg.pixmap.shape = None;
++	bg.pixmap.g.x = 0;
++	bg.pixmap.g.y = 0;
++	dest_g.width = g->width + g->x;
++	dest_g.height = g->height + g->y;
++	dest_g.x = g->x;
++	dest_g.y = g->y;
++
++	if (solid_flags & (1 << part))
++	{
++		bg.flags.use_pixmap = 0;
++		bg.pixel = pixels[part];
++		border_fill_pixmap_background(dest, &dest_g, &bg, cd);
++		return;
++	}
++	else if (acs[part].cs >= 0)
++	{
++		Pixmap p = None;
++
++		bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA;
++		bg.pixmap.fra.added_alpha_percent = acs[part].alpha_percent;
++		if (CSET_IS_TRANSPARENT_PR(acs[part].cs))
++		{
++			return;
++		}
++		if (CSET_IS_TRANSPARENT_ROOT(acs[part].cs))
++		{
++			p = border_create_root_transparent_pixmap(
++				td, w, g->width + g->x, g->height + g->y,
++				acs[part].cs);
++			bg.pixmap.p = p;
++			bg.pixmap.depth = Pdepth;
++			bg.pixmap.g.width = g->width;
++			bg.pixmap.g.height = g->height;
++			bg.pixmap.g.x = g->x;
++			bg.pixmap.g.y = g->y;
++		}
++		else if (full_g != NULL)
++		{
++			bg.pixmap.p = border_get_bar_pixmaps(
++				dcd, full_g, bs, acs[part].cs, NULL, part,
++				(stretch_flags & (1 << part)), NULL);
++			if (bg.pixmap.p)
++			{
++				if (part != TBMP_RIGHT_MAIN)
++				{
++					/* left buttons offset */
++					x = title_g->x - full_g->x;
++					y = title_g->y - full_g->y;
++				}
++				bg.pixmap.g.width = full_g->width;
++				bg.pixmap.g.height = full_g->height;
++				bg.pixmap.flags.is_tiled = 1;
++				bg.pixmap.g.x = x;
++				bg.pixmap.g.y = y;
++				bg.pixmap.depth = Pdepth;
++			}
++		}
++		if (!bg.pixmap.p)
++		{
++			int bg_w, bg_h;
++
++			p = CreateBackgroundPixmap(
++				dpy, w, g->width, g->height,
++				&Colorset[acs[part].cs], Pdepth, Scr.BordersGC,
++				False);
++			bg.pixmap.p = p;
++			GetWindowBackgroundPixmapSize(
++				&Colorset[acs[part].cs], g->width, g->height,
++				&bg_w, &bg_h);
++			bg.pixmap.g.width = bg_w;
++			bg.pixmap.g.height = bg_h;
++			bg.pixmap.depth = Pdepth;
++			bg.pixmap.flags.is_tiled = 1;
++		}
++		if (bg.pixmap.p)
++		{
++			border_fill_pixmap_background(dest, &dest_g, &bg, cd);
++		}
++		if (p)
++		{
++			XFreePixmap(dpy, p);
++		}
++	}
++	else if (src[part])
++	{
++		FvwmPicture *full_pic = NULL;
++		Pixmap p;
++
++		if (full_g != NULL)
++		{
++			p = border_get_bar_pixmaps(
++				dcd, full_g, bs, -1, src[part], part,
++				(stretch_flags & (1 << part)), &full_pic);
++			if (p && full_pic)
++			{
++				if (part != TBMP_RIGHT_MAIN)
++				{
++					/* left buttons offset */
++					x = title_g->x - full_g->x;
++					y = title_g->y - full_g->y;
++				}
++				bg.pixmap.p = full_pic->picture;
++				bg.pixmap.shape = full_pic->mask;
++				bg.pixmap.alpha = full_pic->alpha;
++				bg.pixmap.depth = full_pic->depth;
++				bg.pixmap.g.width = full_pic->width;
++				bg.pixmap.g.height = full_pic->height;
++				bg.pixmap.g.x = x;
++				bg.pixmap.g.y = y;
++			}
++		}
++		if (!bg.pixmap.p)
++		{
++			if (stretch_flags & (1 << part))
++			{
++				bg.pixmap.flags.is_stretched = 1;
++			}
++			else
++			{
++				bg.pixmap.flags.is_tiled = 1;
++			}
++			bg.pixmap.p = src[part]->picture;
++			bg.pixmap.shape = src[part]->mask;
++			bg.pixmap.alpha = src[part]->alpha;
++			bg.pixmap.depth = src[part]->depth;
++			bg.pixmap.g.width = src[part]->width;
++			bg.pixmap.g.height = src[part]->height;
++			bg.pixmap.stretch_w = dest_g.width - dest_g.x;
++			bg.pixmap.stretch_h = dest_g.height - dest_g.y;
++
++		}
++		if (bg.pixmap.p)
++		{
++			border_fill_pixmap_background(dest, &dest_g, &bg, cd);
++		}
++	}
++
++	return;
++}
++
++static int border_mp_get_length(
++	titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs,
++	unsigned int solid_flags, int part)
++{
++	if (acs[part].cs >= 0 || (solid_flags & (1 << part)))
++	{
++		/* arbitrary */
++		if (td->has_vt)
++		{
++			return td->bar_g.width/2;
++		}
++		else
++		{
++			return td->bar_g.height/2;
++		}
++	}
++	if (pm[part] == NULL)
++	{
++		return 0;
++	}
++	else if (td->has_vt)
++	{
++		return pm[part]->height;
++	}
++	else
++	{
++		return pm[part]->width;
++	}
++}
++
++/* geometries relatively to the frame */
++static void border_mp_get_titlebar_descr(
++	FvwmWindow *fw, titlebar_descr *td, DecorFace *df)
++{
++	DecorFace *tsdf;
++	FvwmPicture **pm;
++	FvwmAcs *acs;
++	int add,tmpi;
++	int left_of_text = 0;
++	int right_of_text = 0;
++	int left_end = 0;
++	int right_end = 0;
++	int before_space, after_space, under_offset, under_width;
++	Bool has_mp = False;
++	JustificationType just;
++	unsigned short sf;
++	int is_start = 0;
++
++	just = TB_JUSTIFICATION(GetDecor(fw, titlebar));
++	/* first compute under text width */
++	if (td->length > 0)
++	{
++		under_width = td->length + 2*TBMP_TITLE_PADDING;
++	}
++	else
++	{
++		under_width = 0;
++	}
++	if (under_width > fw->title_length)
++	{
++		under_width = fw->title_length;
++		td->offset = (fw->title_length - td->length) / 2;
++		just = JUST_CENTER;
++	}
++	for (tsdf = df; tsdf != NULL; tsdf = tsdf->next)
++	{
++		if (tsdf->style.face_type != MultiPixmap)
++		{
++			continue;
++		}
++		has_mp = True;
++		acs = tsdf->u.mp.acs;
++		pm = tsdf->u.mp.pixmaps;
++		sf = tsdf->u.mp.solid_flags;
++		add = border_mp_get_length(
++			td, pm, acs, sf, TBMP_LEFT_OF_TEXT);
++		if (add > left_of_text &&
++		    add + left_end + right_of_text + right_end + under_width +
++		    2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
++		{
++			left_of_text = add;
++		}
++		add = border_mp_get_length(
++			td, pm, acs, sf, TBMP_RIGHT_OF_TEXT);
++		if (add > right_of_text &&
++		    add + left_end + left_of_text + right_end + under_width +
++		    2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
++		{
++			right_of_text = add;
++		}
++		add = border_mp_get_length(
++			td, pm, acs, sf, TBMP_LEFT_END);
++		if (add > left_end &&
++		    add + right_of_text + left_of_text + right_end +
++		    under_width + 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
++		{
++			left_end = add;
++		}
++		add = border_mp_get_length(
++			td, pm, acs, sf, TBMP_RIGHT_END);
++		if (add > right_end &&
++		    add + right_of_text + left_of_text + left_end +
++		    under_width + 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
++		{
++			right_end = add;
++		}
++	}
++
++	if (!has_mp)
++	{
++		return;
++	}
++
++	switch (just)
++	{
++	case JUST_LEFT:
++		is_start = 1;
++		/* fall through */
++	case JUST_RIGHT:
++		if (td->has_an_upsidedown_rotation)
++		{
++			is_start = !is_start;
++		}
++		if (is_start)
++		{
++			if (td->has_an_upsidedown_rotation)
++			{
++				td->offset = max(
++					td->offset, right_of_text + right_end +
++					TBMP_MIN_RL_TITLE_LENGTH +
++					TBMP_TITLE_PADDING);
++			}
++			else
++			{
++				td->offset = max(
++					td->offset, left_of_text + left_end +
++					TBMP_MIN_RL_TITLE_LENGTH +
++					TBMP_TITLE_PADDING);
++			}
++		}
++		else
++		{
++			if (td->has_an_upsidedown_rotation)
++			{
++				td->offset = min(
++					td->offset, fw->title_length -
++					(td->length + left_of_text +
++					 left_end + TBMP_MIN_RL_TITLE_LENGTH +
++					 TBMP_TITLE_PADDING));
++			}
++			else
++			{
++				td->offset = min(
++					td->offset, fw->title_length -
++					(td->length + right_of_text +
++					 right_end + TBMP_MIN_RL_TITLE_LENGTH +
++					 TBMP_TITLE_PADDING));
++			}
++		}
++		break;
++	case JUST_CENTER:
++	default:
++		break;
++	}
++
++	under_offset = td->offset - (under_width - td->length)/2;
++	before_space = under_offset;
++	if (td->has_vt)
++	{
++		after_space =
++			td->layout.title_g.height - before_space - under_width;
++	}
++	else
++	{
++		after_space =
++			td->layout.title_g.width - before_space - under_width;
++	}
++	if (td->has_an_upsidedown_rotation)
++	{
++		td->left_end_length = right_end;
++		td->left_of_text_length = right_of_text;
++		td->right_of_text_length = left_of_text;
++		td->right_end_length = left_end;
++		tmpi = before_space;
++		before_space = after_space;
++		after_space = tmpi;
++	}
++	else
++	{
++		td->left_end_length = left_end;
++		td->left_of_text_length = left_of_text;
++		td->right_of_text_length = right_of_text;
++		td->right_end_length = right_end;
++	}
++
++	if (td->has_vt)
++	{
++		td->under_text_g.width = td->bar_g.width;
++		td->under_text_g.height = under_width;
++		td->under_text_g.x = 0;
++		td->under_text_g.y = under_offset;
++	}
++	else
++	{
++		td->under_text_g.height = td->bar_g.height;
++		td->under_text_g.width = under_width;
++		td->under_text_g.x = under_offset;
++		td->under_text_g.y = 0;
++	}
++
++	/* width & height */
++	if (td->has_vt)
++	{
++		/* left */
++		td->full_left_main_g.width = td->bar_g.width;
++		td->full_left_main_g.height =
++			before_space + td->left_buttons_g.height;
++		td->left_main_g.width = td->bar_g.width;
++		td->left_main_g.height = before_space;
++		/* right */
++		td->full_right_main_g.width = td->bar_g.width;
++		td->full_right_main_g.height = after_space +
++			td->right_buttons_g.height;
++		td->right_main_g.width = td->bar_g.width;
++		td->right_main_g.height = after_space;
++	}
++	else
++	{
++		/* left */
++		td->full_left_main_g.height = td->bar_g.height;
++		td->full_left_main_g.width =
++			before_space + td->left_buttons_g.width;
++		td->left_main_g.height = td->bar_g.height;
++		td->left_main_g.width = before_space;
++		/* right */
++		td->full_right_main_g.height = td->bar_g.height;
++		td->full_right_main_g.width = after_space +
++			td->right_buttons_g.width;
++		td->right_main_g.height = td->bar_g.height;
++		td->right_main_g.width = after_space;
++	}
++
++	/* position */
++	if (td->has_an_upsidedown_rotation)
++	{
++		td->full_right_main_g.x = td->bar_g.x;
++		td->full_right_main_g.y = td->bar_g.y;
++		td->right_main_g.x = 0;
++		td->right_main_g.y = 0;
++	}
++	else
++	{
++		td->full_left_main_g.x = td->bar_g.x;
++		td->full_left_main_g.y = td->bar_g.y;
++		td->left_main_g.x = 0;
++		td->left_main_g.y = 0;
++	}
++
++	if (td->has_vt)
++	{
++		if (td->has_an_upsidedown_rotation)
++		{
++			td->full_left_main_g.x = td->bar_g.x;
++			td->full_left_main_g.y =
++				td->full_right_main_g.height + td->bar_g.y +
++				td->under_text_g.height;
++			td->left_main_g.y =
++				td->under_text_g.y + td->under_text_g.height;
++			td->left_main_g.x = 0;
++		}
++		else
++		{
++			td->full_right_main_g.x = td->bar_g.x;
++			td->full_right_main_g.y =
++				td->full_left_main_g.height + td->bar_g.y +
++				td->under_text_g.height;
++			td->right_main_g.y =
++				td->under_text_g.y + td->under_text_g.height;
++			td->right_main_g.x = 0;
++		}
++	}
++	else
++	{
++		if (td->has_an_upsidedown_rotation)
++		{
++			td->full_left_main_g.x =
++				td->full_right_main_g.width + td->bar_g.x +
++				td->under_text_g.width;
++			td->full_left_main_g.y = td->bar_g.y;
++			td->left_main_g.x =
++				td->under_text_g.x + td->under_text_g.width;
++			td->left_main_g.y = 0;
++		}
++		else
++		{
++			td->full_right_main_g.x =
++				td->full_left_main_g.width + td->bar_g.x +
++				td->under_text_g.width;
++			td->full_right_main_g.y = td->bar_g.y;
++			td->right_main_g.x =
++				td->under_text_g.x + td->under_text_g.width;
++			td->right_main_g.y = 0;
++		}
++	}
++}
++
++/* the returned geometries are relative to the titlebar (not the frame) */
++static void border_mp_get_extreme_geometry(
++	titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs, unsigned short sf,
++	rectangle *left_of_text_g, rectangle *right_of_text_g,
++	rectangle *left_end_g, rectangle *right_end_g)
++{
++	int left_of_text = 0;
++	int right_of_text = 0;
++	int left_end = 0;
++	int right_end = 0;
++
++	left_of_text = border_mp_get_length(
++		td, pm, acs, sf, TBMP_LEFT_OF_TEXT);
++	left_end = border_mp_get_length(
++		td, pm, acs, sf, TBMP_LEFT_END);
++	right_of_text = border_mp_get_length(
++		td, pm, acs, sf, TBMP_RIGHT_OF_TEXT);
++	right_end = border_mp_get_length(
++			td, pm, acs, sf, TBMP_RIGHT_END);
++
++	if (left_of_text > 0 && left_of_text <= td->left_of_text_length)
++	{
++		if (td->has_vt)
++		{
++			left_of_text_g->y = td->under_text_g.y - left_of_text;
++			left_of_text_g->x = 0;
++			left_of_text_g->height = left_of_text;
++			left_of_text_g->width = td->bar_g.width;
++		}
++		else
++		{
++			left_of_text_g->x = td->under_text_g.x - left_of_text;
++			left_of_text_g->y = 0;
++			left_of_text_g->width = left_of_text;
++			left_of_text_g->height = td->bar_g.height;
++		}
++	}
++	else
++	{
++		left_of_text_g->x = 0;
++		left_of_text_g->y = 0;
++		left_of_text_g->width = 0;
++		left_of_text_g->height = 0;
++	}
++
++	if (right_of_text > 0 && right_of_text <= td->right_of_text_length)
++	{
++		if (td->has_vt)
++		{
++			right_of_text_g->y =
++				td->under_text_g.y + td->under_text_g.height;
++			right_of_text_g->x = 0;
++			right_of_text_g->height = right_of_text;
++			right_of_text_g->width = td->bar_g.width;
++		}
++		else
++		{
++			right_of_text_g->x =
++				td->under_text_g.x + td->under_text_g.width;
++			right_of_text_g->y = 0;
++			right_of_text_g->width = right_of_text;
++			right_of_text_g->height = td->bar_g.height;
++		}
++	}
++	else
++	{
++		right_of_text_g->x = 0;
++		right_of_text_g->y = 0;
++		right_of_text_g->width = 0;
++		right_of_text_g->height = 0;
++	}
++
++	if (left_end > 0 && left_end <= td->left_end_length)
++	{
++		if (td->has_vt)
++		{
++			left_end_g->y = 0;
++			left_end_g->x = 0;
++			left_end_g->height = left_end;
++			left_end_g->width = td->bar_g.width;
++		}
++		else
++		{
++			left_end_g->x = 0;
++			left_end_g->y = 0;
++			left_end_g->width = left_end;
++			left_end_g->height = td->bar_g.height;
++		}
++	}
++	else
++	{
++		left_end_g->x = 0;
++		left_end_g->y = 0;
++		left_end_g->width = 0;
++		left_end_g->height = 0;
++	}
++
++	if (right_end > 0 && right_end <= td->right_end_length)
++	{
++		if (td->has_vt)
++		{
++			right_end_g->y =
++				td->layout.title_g.height - right_end;
++			right_end_g->x = 0;
++			right_end_g->height = right_end;
++			right_end_g->width = td->bar_g.width;
++		}
++		else
++		{
++			right_end_g->x =
++				td->layout.title_g.width - right_end;
++			right_end_g->y = 0;
++			right_end_g->width = right_end;
++			right_end_g->height = td->bar_g.height;
++		}
++	}
++	else
++	{
++		right_end_g->x = 0;
++		right_end_g->y = 0;
++		right_end_g->width = 0;
++		right_end_g->height = 0;
++	}
++
++	return;
++}
++
++static Bool border_mp_get_use_title_style_parts_and_geometry(
++	titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs,
++	unsigned short sf, int is_left, rectangle *g, int *part)
++{
++	rectangle *tmp_g = NULL;
++	Bool g_ok = True;
++
++	if (is_left && TBMP_HAS_PART(TBMP_LEFT_BUTTONS, pm, acs, sf))
++	{
++		*part = TBMP_LEFT_BUTTONS;
++		tmp_g = &td->left_buttons_g;
++	}
++	else if (!is_left && TBMP_HAS_PART(TBMP_RIGHT_BUTTONS, pm, acs, sf))
++	{
++		*part = TBMP_RIGHT_BUTTONS;
++		tmp_g = &td->right_buttons_g;
++	}
++	else if (is_left && TBMP_HAS_PART(TBMP_LEFT_MAIN, pm, acs, sf))
++	{
++		*part = TBMP_LEFT_MAIN;
++		tmp_g = &td->full_left_main_g;
++	}
++	else if (!is_left && TBMP_HAS_PART(TBMP_RIGHT_MAIN, pm, acs, sf))
++	{
++		*part = TBMP_RIGHT_MAIN;
++		tmp_g = &td->full_right_main_g;
++	}
++	else if (TBMP_HAS_PART(TBMP_MAIN, pm, acs, sf))
++	{
++		*part = TBMP_MAIN;
++		tmp_g = &(td->bar_g);
++	}
++	else
++	{
++		*part = TBMP_NONE;
++	}
++	if (g && tmp_g)
++	{
++		g->x = tmp_g->x;
++		g->y = tmp_g->y;
++		g->width = tmp_g->width;
++		g->height = tmp_g->height;
++		g_ok = True;
++	}
++
++	return g_ok;
++}
++
++/*  Redraws multi-pixmap titlebar (tril at igs.net) */
++static void border_mp_draw_mp_titlebar(
++	FvwmWindow *fw, titlebar_descr *td, DecorFace *df, Pixmap dest_pix,
++	Window w)
++{
++	FvwmPicture **pm;
++	FvwmAcs *acs;
++	Pixel *pixels;
++	unsigned short solid_flags;
++	unsigned short stretch_flags;
++	rectangle tmp_g, left_of_text_g,left_end_g,right_of_text_g,right_end_g;
++	dynamic_common_decorations *dcd;
++	ButtonState bs;
++
++	dcd = &(td->cd->dynamic_cd);
++	bs = td->tbstate.tstate;
++	pm = df->u.mp.pixmaps;
++	acs = df->u.mp.acs;
++	pixels = df->u.mp.pixels;
++	stretch_flags = df->u.mp.stretch_flags;
++	solid_flags = df->u.mp.solid_flags;
++	tmp_g.x = 0;
++	tmp_g.y = 0;
++	tmp_g.width = td->layout.title_g.width;
++	tmp_g.height = td->layout.title_g.height;
++
++	if (TBMP_HAS_PART(TBMP_MAIN, pm, acs, solid_flags))
++	{
++		border_mp_render_into_pixmap(
++			td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
++			TBMP_MAIN, dest_pix, w, &td->bar_g, &td->layout.title_g,
++			bs, &tmp_g);
++	}
++	else if (td->length <= 0)
++	{
++		border_mp_render_into_pixmap(
++			td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
++			TBMP_LEFT_MAIN, dest_pix, w, NULL, &td->layout.title_g,
++			bs, &tmp_g);
++	}
++
++	border_mp_get_extreme_geometry(
++		td, pm, acs, solid_flags, &left_of_text_g, &right_of_text_g,
++		&left_end_g, &right_end_g);
++
++	if (td->length > 0)
++	{
++		if (TBMP_HAS_PART(TBMP_LEFT_MAIN, pm, acs, solid_flags) &&
++		    td->left_main_g.width > 0 && td->left_main_g.height > 0)
++		{
++			border_mp_render_into_pixmap(
++				td, td->cd, pm, acs, pixels, solid_flags,
++				stretch_flags, TBMP_LEFT_MAIN, dest_pix, w,
++				&td->full_left_main_g, &td->layout.title_g, bs,
++				&td->left_main_g);
++		}
++		if (TBMP_HAS_PART(TBMP_RIGHT_MAIN, pm, acs, solid_flags) &&
++		    td->right_main_g.width > 0 && td->right_main_g.height > 0)
++		{
++			border_mp_render_into_pixmap(
++				td, td->cd, pm, acs, pixels, solid_flags,
++				stretch_flags, TBMP_RIGHT_MAIN, dest_pix, w,
++				&td->full_right_main_g, &td->layout.title_g, bs,
++				&td->right_main_g);
++		}
++		if (TBMP_HAS_PART(TBMP_UNDER_TEXT, pm, acs, solid_flags)  &&
++		    td->under_text_g.width > 0 && td->under_text_g.height > 0)
++		{
++			border_mp_render_into_pixmap(
++				td, td->cd, pm, acs, pixels, solid_flags,
++				stretch_flags, TBMP_UNDER_TEXT, dest_pix, w,
++				NULL, &td->layout.title_g, bs,
++				&td->under_text_g);
++		}
++		if (left_of_text_g.width > 0 && left_of_text_g.height > 0)
++		{
++			border_mp_render_into_pixmap(
++				td, td->cd, pm, acs, pixels, solid_flags,
++				stretch_flags, TBMP_LEFT_OF_TEXT, dest_pix, w,
++				NULL, &td->layout.title_g, bs, &left_of_text_g);
++		}
++		if (right_of_text_g.width > 0 && right_of_text_g.height > 0)
++		{
++			border_mp_render_into_pixmap(
++				td, td->cd, pm, acs, pixels, solid_flags,
++				stretch_flags, TBMP_RIGHT_OF_TEXT, dest_pix, w,
++				NULL, &td->layout.title_g, bs, &right_of_text_g);
++		}
++	}
++	if (left_end_g.width > 0 && left_end_g.height > 0)
++	{
++		border_mp_render_into_pixmap(
++			td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
++			TBMP_LEFT_END, dest_pix, w, NULL, &td->layout.title_g,
++			bs, &left_end_g);
++	}
++	if (right_end_g.width > 0 && right_end_g.height > 0)
++	{
++		border_mp_render_into_pixmap(
++			td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
++			TBMP_RIGHT_END, dest_pix, w, NULL, &td->layout.title_g,
++			bs, &right_end_g);
++	}
++
++	return;
++}
++
++/*
++ *
++ *  draw title bar and buttons
++ *
++ */
++static void border_draw_decor_to_pixmap(
++	FvwmWindow *fw, Pixmap dest_pix, Window w,
++	pixmap_background_type *solid_bg, rectangle *w_g,
++	DecorFace *df, titlebar_descr *td, ButtonState bs,
++	int use_title_style, int is_toggled, int left1right0)
++{
++	register DecorFaceType type = DFS_FACE_TYPE(df->style);
++	pixmap_background_type bg;
++	rectangle dest_g;
++	FvwmPicture *p;
++	int width,height;
++	int border;
++	int lr_just, tb_just;
++	common_decorations_type *cd;
++
++	cd = td->cd;
++	/* setup some default */
++	bg.pixmap.fra.mask = 0;
++	bg.pixmap.flags.is_stretched = 0;
++	bg.pixmap.flags.is_tiled = 0;
++	bg.flags.use_pixmap = 0;
++	bg.pixmap.g.x = 0;
++	bg.pixmap.g.y = 0;
++
++	if (DFS_BUTTON_RELIEF(df->style) == DFS_BUTTON_IS_FLAT)
++	{
++		border = 0;
++	}
++	else
++	{
++		border = HAS_MWM_BORDER(fw) ? 1 : 2;
++	}
++	dest_g.width = w_g->width;
++	dest_g.height = w_g->height;
++	dest_g.x = border;
++	dest_g.y = border;
++
++	switch (type)
++	{
++	case SimpleButton:
++		/* do nothing */
++		break;
++	case SolidButton:
++		/* overwrite with the default background */
++		dest_g.x = 0;
++		dest_g.y = 0;
++		border_fill_pixmap_background(dest_pix, &dest_g, solid_bg, cd);
++		break;
++	case VectorButton:
++	case DefaultVectorButton:
++		border_draw_vector_to_pixmap(
++			dest_pix, cd, is_toggled, &df->u.vector, w_g);
++		break;
++	case MiniIconButton:
++	case PixmapButton:
++	case ShrunkPixmapButton:
++	case StretchedPixmapButton:
++		if (w_g->width - 2*border <= 0 || w_g->height - 2*border <= 0)
++		{
++			break;
++		}
++		if (FMiniIconsSupported && type == MiniIconButton)
++		{
++			if (!fw->mini_icon)
++			{
++				break;
++			}
++			p = fw->mini_icon;
++			if (cd->cs >= 0)
++			{
++				bg.pixmap.fra.mask |= FRAM_HAVE_ICON_CSET;
++				bg.pixmap.fra.colorset = &Colorset[cd->cs];
++			}
++		}
++		else
++		{
++			p = df->u.p;
++		}
++		width = p->width;
++		height = p->height;
++		if ((type == ShrunkPixmapButton || type == MiniIconButton) &&
++		    (p->width > w_g->width - 2*border ||
++		     p->height > w_g->height - 2*border))
++		{
++			/* do so that the picture fit into the destination */
++			bg.pixmap.stretch_w = width =
++				min(w_g->width - 2*border, p->width);
++			bg.pixmap.stretch_h = height =
++				min(w_g->height - 2*border, p->height);
++			bg.pixmap.flags.is_stretched = 1;
++		}
++		else if (type == StretchedPixmapButton &&
++			 (p->width < w_g->width - 2*border ||
++			  p->height < w_g->height - 2*border))
++		{
++			/* do so that the picture fit into the destination */
++			bg.pixmap.stretch_w = width =
++				max(w_g->width - 2*border, p->width);
++			bg.pixmap.stretch_h = height =
++				max(w_g->height - 2*border, p->height);
++			bg.pixmap.flags.is_stretched = 1;
++		}
++		lr_just = DFS_H_JUSTIFICATION(df->style);
++		tb_just = DFS_V_JUSTIFICATION(df->style);
++		if (!td->td_is_rotated && fw->title_text_rotation != ROTATION_0)
++		{
++			if (fw->title_text_rotation == ROTATION_180)
++			{
++				switch (lr_just)
++				{
++				case JUST_LEFT:
++					lr_just = JUST_RIGHT;
++					break;
++				case JUST_RIGHT:
++					lr_just = JUST_LEFT;
++					break;
++				case JUST_CENTER:
++				default:
++					break;
++				}
++				switch (tb_just)
++				{
++				case JUST_TOP:
++					tb_just = JUST_BOTTOM;
++					break;
++				case JUST_BOTTOM:
++					tb_just = JUST_TOP;
++					break;
++				case JUST_CENTER:
++				default:
++					break;
++				}
++			}
++			else if (fw->title_text_rotation == ROTATION_90)
++			{
++				switch (lr_just)
++				{
++				case JUST_LEFT:
++					tb_just = JUST_TOP;
++					break;
++				case JUST_RIGHT:
++					tb_just = JUST_BOTTOM;
++					break;
++				case JUST_CENTER:
++				default:
++					tb_just = JUST_CENTER;
++					break;
++				}
++				switch (DFS_V_JUSTIFICATION(df->style))
++				{
++				case JUST_TOP:
++					lr_just = JUST_RIGHT;
++					break;
++				case JUST_BOTTOM:
++					lr_just = JUST_LEFT;
++					break;
++				case JUST_CENTER:
++				default:
++					lr_just = JUST_CENTER;
++					break;
++				}
++			}
++			else if (fw->title_text_rotation == ROTATION_270)
++			{
++				switch (lr_just)
++				{
++				case JUST_LEFT:
++					tb_just = JUST_BOTTOM;
++					break;
++				case JUST_RIGHT:
++					tb_just = JUST_TOP;
++					break;
++				case JUST_CENTER:
++				default:
++					tb_just = JUST_CENTER;
++					break;
++				}
++				switch (DFS_V_JUSTIFICATION(df->style))
++				{
++				case JUST_TOP:
++					lr_just = JUST_LEFT;
++					break;
++				case JUST_BOTTOM:
++					lr_just = JUST_RIGHT;
++					break;
++				case JUST_CENTER:
++				default:
++					lr_just = JUST_CENTER;
++					break;
++				}
++			}
++		}
++		switch (lr_just)
++		{
++		case JUST_LEFT:
++			dest_g.x = border;
++			break;
++		case JUST_RIGHT:
++			dest_g.x = (int)(w_g->width - width - border);
++			break;
++		case JUST_CENTER:
++		default:
++			/* round down */
++			dest_g.x = (int)(w_g->width - width) / 2;
++			break;
++		}
++		switch (tb_just)
++		{
++		case JUST_TOP:
++			dest_g.y = border;
++			break;
++		case JUST_BOTTOM:
++			dest_g.y = (int)(w_g->height - height - border);
++			break;
++		case JUST_CENTER:
++		default:
++			/* round down */
++			dest_g.y = (int)(w_g->height - height) / 2;
++			break;
++		}
++		if (dest_g.x < border)
++		{
++			dest_g.x = border;
++		}
++		if (dest_g.y < border)
++		{
++			dest_g.y = border;
++		}
++		bg.flags.use_pixmap = 1;
++		bg.pixmap.p = p->picture;
++		bg.pixmap.shape = p->mask;
++		bg.pixmap.alpha = p->alpha;
++		bg.pixmap.depth = p->depth;
++		bg.pixmap.g.width = p->width;
++		bg.pixmap.g.height = p->height;
++		border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd);
++		break;
++	case TiledPixmapButton:
++	case AdjustedPixmapButton:
++		if (w_g->width - 2*border <= 0 || w_g->height - 2*border <= 0)
++		{
++			break;
++		}
++		p = df->u.p;
++		if (type == TiledPixmapButton)
++		{
++			bg.pixmap.flags.is_tiled = 1;
++		}
++		else
++		{
++			bg.pixmap.stretch_w = width = w_g->width - 2*dest_g.x;
++			bg.pixmap.stretch_h = height = w_g->height - 2*dest_g.y;
++			bg.pixmap.flags.is_stretched = 1;
++		}
++		bg.flags.use_pixmap = 1;
++		bg.pixmap.p = p->picture;
++		bg.pixmap.shape = p->mask;
++		bg.pixmap.alpha = p->alpha;
++		bg.pixmap.depth = p->depth;
++		bg.pixmap.g.width = p->width;
++		bg.pixmap.g.height = p->height;
++		border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd);
++		break;
++	case MultiPixmap: /* for UseTitleStyle only */
++	{
++		int is_left = left1right0;
++		int part = TBMP_NONE;
++		int ap, cs;
++		unsigned int stretch;
++		Pixmap tmp = None;
++		FvwmPicture *full_pic = NULL;
++		rectangle g;
++		dynamic_common_decorations *dcd = &(cd->dynamic_cd);
++		FvwmPicture **pm;
++		FvwmAcs *acs;
++		Pixel *pixels;
++		unsigned short sf;
++
++		pm = df->u.mp.pixmaps;
++		acs = df->u.mp.acs;
++		pixels = df->u.mp.pixels;
++		sf = df->u.mp.solid_flags;
++		if (!border_mp_get_use_title_style_parts_and_geometry(
++			td, pm, acs, sf, is_left, &g, &part))
++		{
++			g.width = 0;
++			g.height = 0;
++			g.x = 0;
++			g.y = 0;
++		}
++
++		if (part == TBMP_NONE)
++		{
++			break;
++		}
++
++		if (sf & (1 << part))
++		{
++			bg.flags.use_pixmap = 0;
++			bg.pixel = pixels[part];
++			border_fill_pixmap_background(
++				dest_pix, &dest_g, &bg, cd);
++			break;
++		}
++		cs = acs[part].cs;
++		ap =  acs[part].alpha_percent;
++		if (CSET_IS_TRANSPARENT_PR(cs))
++		{
++			break;
++		}
++		if (cs >= 0)
++		{
++			bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA;
++			bg.pixmap.fra.added_alpha_percent = ap;
++		}
++		stretch = !!(df->u.mp.stretch_flags & (1 << part));
++		bg.flags.use_pixmap = 1;
++		dest_g.x = 0;
++		dest_g.y = 0;
++
++		if (cs >= 0 && use_title_style && g.width > 0 && g.height > 0 &&
++		    !CSET_IS_TRANSPARENT_ROOT(cs) &&
++		    (bg.pixmap.p = border_get_bar_pixmaps(
++			    dcd, &g, bs, cs, NULL, part, stretch, NULL)) != None)
++		{
++			bg.pixmap.g.width = g.width;
++			bg.pixmap.g.height = g.height;
++			bg.pixmap.flags.is_tiled = 1;
++			bg.pixmap.g.x = w_g->x - g.x;
++			bg.pixmap.g.y = w_g->y - g.y;
++			bg.pixmap.shape = None;
++			bg.pixmap.alpha = None;
++			bg.pixmap.depth = Pdepth;
++		}
++		else if (CSET_IS_TRANSPARENT_ROOT(cs))
++		{
++			tmp = border_create_root_transparent_pixmap(
++				td, w, w_g->width, w_g->height, cs);
++			bg.pixmap.p = tmp;
++			bg.pixmap.g.width = w_g->width;
++			bg.pixmap.g.height = w_g->height;
++			bg.pixmap.shape = None;
++			bg.pixmap.alpha = None;
++			bg.pixmap.depth = Pdepth;
++		}
++		else if (cs >= 0)
++		{
++			int bg_w, bg_h;
++
++			tmp = CreateBackgroundPixmap(
++				dpy, w, w_g->width,
++				w_g->height, &Colorset[cs],
++				Pdepth, Scr.BordersGC, False);
++			bg.pixmap.p = tmp;
++			GetWindowBackgroundPixmapSize(
++				&Colorset[cs], w_g->width,
++				w_g->height, &bg_w, &bg_h);
++			bg.pixmap.g.width = bg_w;
++			bg.pixmap.g.height = bg_h;
++			bg.pixmap.shape = None;
++			bg.pixmap.alpha = None;
++			bg.pixmap.depth = Pdepth;
++			bg.pixmap.flags.is_tiled = 1;
++		}
++		else if (pm[part] && g.width > 0 && g.height > 0 &&
++			 border_get_bar_pixmaps(
++				 dcd, &g, bs, -1, pm[part], part, stretch,
++				 &full_pic) != None && full_pic)
++		{
++			bg.pixmap.p = full_pic->picture;
++			bg.pixmap.shape = full_pic->mask;
++			bg.pixmap.alpha = full_pic->alpha;
++			bg.pixmap.depth = full_pic->depth;
++			bg.pixmap.g.width = full_pic->width;
++			bg.pixmap.g.height = full_pic->height;
++			bg.pixmap.g.x = w_g->x - g.x;
++			bg.pixmap.g.y = w_g->y - g.y;
++		}
++		else if (pm[part])
++		{
++			p = pm[part];
++			if (df->u.mp.stretch_flags & (1 << part))
++			{
++				bg.pixmap.flags.is_stretched = 1;
++			}
++			else
++			{
++				bg.pixmap.flags.is_tiled = 1;
++			}
++			bg.pixmap.p = p->picture;
++			bg.pixmap.shape = p->mask;
++			bg.pixmap.alpha = p->alpha;
++			bg.pixmap.depth = p->depth;
++			bg.pixmap.g.width = p->width;
++			bg.pixmap.g.height = p->height;
++			bg.pixmap.stretch_w = dest_g.width - dest_g.x;
++			bg.pixmap.stretch_h = dest_g.height - dest_g.y;
++		}
++		else
++		{
++			/* should not happen */
++			return;
++		}
++		if (bg.pixmap.p != None)
++		{
++			border_fill_pixmap_background(
++				dest_pix, &dest_g, &bg, cd);
++		}
++		if (tmp != None)
++		{
++			XFreePixmap(dpy, tmp);
++		}
++		break;
++	}
++	case ColorsetButton:
++	{
++		colorset_t *cs_t = &Colorset[df->u.acs.cs];
++		int cs = df->u.acs.cs;
++		Pixmap tmp = None;
++		int bg_w, bg_h;
++
++		if (CSET_IS_TRANSPARENT_PR(cs))
++		{
++			break;
++		}
++		dest_g.x = 0;
++		dest_g.y = 0;
++		if (use_title_style &&
++		    !CSET_IS_TRANSPARENT_ROOT(cs) &&
++		    (bg.pixmap.p = border_get_bar_pixmaps(
++			    &(cd->dynamic_cd), &(td->bar_g), bs, cs, NULL,
++			    TBMP_NONE, 0, NULL))
++		    != None)
++		{
++			bg.pixmap.g.width = td->bar_g.width;
++			bg.pixmap.g.height = td->bar_g.height;
++			bg.pixmap.g.x = w_g->x - td->bar_g.x;
++			bg.pixmap.g.y = w_g->y - td->bar_g.y;
++		}
++		else if (CSET_IS_TRANSPARENT_ROOT(cs))
++		{
++			tmp = border_create_root_transparent_pixmap(
++				td, w, w_g->width, w_g->height, cs);
++			if (tmp == None)
++			{
++				break;
++			}
++			bg.pixmap.p = tmp;
++			bg.pixmap.g.width = w_g->width;
++			bg.pixmap.g.height = w_g->height;
++			bg.pixmap.shape = None;
++			bg.pixmap.alpha = None;
++			bg.pixmap.depth = Pdepth;
++		}
++		else
++		{
++			tmp = CreateBackgroundPixmap(
++				dpy, w, w_g->width, w_g->height,
++				cs_t, Pdepth, Scr.BordersGC, False);
++			if (tmp == None)
++			{
++				break;
++			}
++			bg.pixmap.p = tmp;
++			GetWindowBackgroundPixmapSize(
++				cs_t, w_g->width, w_g->height,
++				&bg_w, &bg_h);
++			bg.pixmap.g.width = bg_w;
++			bg.pixmap.g.height = bg_h;
++			bg.pixmap.g.x = 0;
++			bg.pixmap.g.y = 0;
++		}
++		bg.flags.use_pixmap = 1;
++		bg.pixmap.shape = None;
++		bg.pixmap.alpha = None;
++		bg.pixmap.depth = Pdepth;
++		bg.pixmap.flags.is_tiled = 1;
++		bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA;
++		bg.pixmap.fra.added_alpha_percent = df->u.acs.alpha_percent;
++		border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd);
++		if (tmp)
++		{
++			XFreePixmap(dpy, tmp);
++		}
++		break;
++	}
++	case GradientButton:
++		/* draw the gradient into the pixmap */
++		CreateGradientPixmap(
++			dpy, dest_pix, Scr.TransMaskGC,
++			df->u.grad.gradient_type, 0, 0, df->u.grad.npixels,
++			df->u.grad.xcs, df->u.grad.do_dither,
++			&df->u.grad.d_pixels, &df->u.grad.d_npixels,
++			dest_pix, 0, 0, w_g->width, w_g->height, NULL);
++
++		break;
++
++	default:
++		fvwm_msg(ERR, "DrawButton", "unknown button type: %i", type);
++		break;
++	}
++
++	return;
++}
++
++static void border_set_button_pixmap(
++	FvwmWindow *fw, titlebar_descr *td, int button, Pixmap *dest_pix,
++	Window w)
++{
++	pixmap_background_type bg;
++	unsigned int mask;
++	int is_left_button;
++	int do_reverse_relief;
++	ButtonState bs;
++	DecorFace *df;
++	rectangle *button_g;
++	GC rgc;
++	GC sgc;
++	Bool free_bg_pixmap = False;
++	rectangle pix_g;
++
++	/* prepare variables */
++	mask = (1 << button);
++	if (td->has_an_upsidedown_rotation)
++	{
++		is_left_button = (button & 1);
++	}
++	else
++	{
++		is_left_button = !(button & 1);
++	}
++	button_g = &td->layout.button_g[button];
++	bs = td->tbstate.bstate[button];
++	df = &TB_STATE(GetDecor(fw, buttons[button]))[bs];
++	rgc = td->cd->relief_gc;
++	sgc = td->cd->shadow_gc;
++	/* prepare background, either from the window colour or from the
++	 * border style */
++	if (!DFS_USE_BORDER_STYLE(df->style))
++	{
++		/* fill with the button background colour */
++		bg.flags.use_pixmap = 0;
++		bg.pixel = td->cd->back_color;
++		pix_g.x = 0;
++		pix_g.y = 0;
++		pix_g.width = button_g->width;
++		pix_g.height = button_g->height;
++		border_fill_pixmap_background(*dest_pix, &pix_g, &bg, td->cd);
++	}
++	else
++	{
++		/* draw pixmap background inherited from border style */
++		rectangle relative_g;
++
++		relative_g.width = td->frame_g.width;
++		relative_g.height = td->frame_g.height;
++		relative_g.x = button_g->x;
++		relative_g.y = button_g->y;
++		border_get_border_background(
++			&bg, td->cd, button_g, &relative_g, &free_bg_pixmap, w);
++		bg.pixmap.g.x = 0;
++		bg.pixmap.g.y = 0;
++		/* set the geometry for drawing the Tiled pixmap;
++		 * FIXME: maybe add the relief as offset? */
++		pix_g.x = 0;
++		pix_g.y = 0;
++		pix_g.width = button_g->width;
++		pix_g.height = button_g->height;
++		border_fill_pixmap_background(*dest_pix, &pix_g, &bg, td->cd);
++		if (free_bg_pixmap && bg.pixmap.p)
++		{
++			XFreePixmap(dpy, bg.pixmap.p);
++		}
++	}
++
++	/* handle title style */
++	if (DFS_USE_TITLE_STYLE(df->style))
++	{
++		/* draw background inherited from title style */
++		DecorFace *tsdf;
++		Pixmap tmp;
++
++		if (td->draw_rotation != ROTATION_0)
++		{
++			tmp = CreateRotatedPixmap(
++				dpy, *dest_pix,
++				td->layout.button_g[button].width,
++				td->layout.button_g[button].height,
++				Pdepth, Scr.BordersGC, td->restore_rotation);
++			XFreePixmap(dpy, *dest_pix);
++			*dest_pix = tmp;
++			border_rotate_titlebar_descr(fw, td);
++			button_g = &td->layout.button_g[button];
++			is_left_button = !(button & 1);
++		}
++		for (tsdf = &TB_STATE(GetDecor(fw, titlebar))[bs]; tsdf != NULL;
++		     tsdf = tsdf->next)
++		{
++			bg.pixel = tsdf->u.back;
++			border_draw_decor_to_pixmap(
++				fw, *dest_pix, w, &bg, button_g, tsdf, td,
++				bs, True, (td->tbstate.toggled_bmask & mask),
++				is_left_button);
++		}
++		if (td->draw_rotation != ROTATION_0)
++		{
++			tmp = CreateRotatedPixmap(
++				dpy, *dest_pix,
++				td->layout.button_g[button].width,
++				td->layout.button_g[button].height,
++				Pdepth, Scr.BordersGC, td->draw_rotation);
++			XFreePixmap(dpy, *dest_pix);
++			*dest_pix = tmp;
++			border_rotate_titlebar_descr(fw, td);
++			button_g = &td->layout.button_g[button];
++			if (td->has_an_upsidedown_rotation)
++			{
++				is_left_button = (button & 1);
++			}
++			else
++			{
++				is_left_button = !(button & 1);
++			}
++		}
++	}
++	/* handle button style */
++	for ( ; df; df = df->next)
++	{
++		/* draw background from button style */
++		bg.pixel = df->u.back;
++		border_draw_decor_to_pixmap(
++			fw, *dest_pix, w, &bg, button_g, df, td, bs, False,
++			(td->tbstate.toggled_bmask & mask), is_left_button);
++	}
++	/* draw the button relief */
++	do_reverse_relief = !!(td->tbstate.pressed_bmask & mask);
++	switch (DFS_BUTTON_RELIEF(
++			TB_STATE(GetDecor(fw, buttons[button]))[bs].style))
++	{
++	case DFS_BUTTON_IS_SUNK:
++		do_reverse_relief ^= 1;
++		/* fall through*/
++	case DFS_BUTTON_IS_UP:
++		do_relieve_rectangle(
++			dpy, *dest_pix, 0, 0, button_g->width - 1,
++			button_g->height - 1,
++			(do_reverse_relief) ? sgc : rgc,
++			(do_reverse_relief) ? rgc : sgc,
++			td->cd->relief_width, True);
++		break;
++	default:
++		/* flat */
++		break;
++	}
++
++	return;
++}
++
++static void border_draw_one_button(
++	FvwmWindow *fw, titlebar_descr *td, int button)
++{
++	Pixmap p;
++
++	/* make a pixmap */
++	if (td->layout.button_g[button].x < 0 ||
++	    td->layout.button_g[button].y < 0)
++	{
++		return;
++	}
++
++	p = border_create_decor_pixmap(td->cd, &(td->layout.button_g[button]));
++	/* set the background tile */
++	border_set_button_pixmap(fw, td, button, &p, FW_W_BUTTON(fw, button));
++	/* apply the pixmap and destroy it */
++	border_set_part_background(FW_W_BUTTON(fw, button), p);
++	XFreePixmap(dpy, p);
++	if ((td->tbstate.clear_bmask & (1 << button)) != 0)
++	{
++		XClearWindow(dpy, FW_W_BUTTON(fw, button));
++	}
++
++	return;
++}
++
++static void border_draw_title_stick_lines(
++	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
++	Pixmap dest_pix)
++{
++	int i;
++	int num;
++	int min;
++	int max;
++	int left_x;
++	int left_w;
++	int right_x;
++	int right_w;
++	int under_text_length = 0;
++	int under_text_offset = 0;
++	int right_length = 0;
++	int left_length = 0;
++	rotation_t rotation;
++
++	if (!( (HAS_STICKY_STIPPLED_TITLE(fw) &&
++		(IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw)))
++	       || HAS_STIPPLED_TITLE(fw)))
++	{
++		return;
++	}
++	if (td->td_is_rotated)
++	{
++		rotation = td->restore_rotation;
++	}
++	else
++	{
++		rotation = ROTATION_0;
++	}
++	if (td->has_vt && td->under_text_g.height > 0)
++	{
++		under_text_length = td->under_text_g.height;
++		under_text_offset = td->under_text_g.y;
++		left_length = td->left_main_g.height - td->left_of_text_length
++			- td->left_end_length;
++		right_length = td->right_main_g.height -
++			td->right_of_text_length - td->right_end_length;
++
++	}
++	else if (!td->has_vt && td->under_text_g.width > 0)
++	{
++		under_text_length = td->under_text_g.width;
++		under_text_offset = td->under_text_g.x;
++		left_length = td->left_main_g.width - td->left_of_text_length
++			- td->left_end_length;
++		right_length = td->right_main_g.width -
++			td->right_of_text_length - td->right_end_length;
++	}
++
++	/* If the window is sticky either across pages or
++	 * desks and it has a stippled title, but nothing for
++	 * sticky_stippled_title, then don't bother drawing them, just
++	 * return immediately. -- Thomas Adam
++	 */
++	if ( (IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw)) &&
++	    (!HAS_STICKY_STIPPLED_TITLE(fw) && HAS_STIPPLED_TITLE(fw)) )
++	{
++		return;
++	}
++
++	num = (int)(fw->title_thickness / WINDOW_TITLE_STICK_VERT_DIST / 2) *
++		2 - 1;
++	min = fw->title_thickness / 2 - num * 2 + 1;
++	max = fw->title_thickness / 2 + num * 2 -
++		WINDOW_TITLE_STICK_VERT_DIST + 1;
++	left_x = WINDOW_TITLE_STICK_OFFSET + td->left_end_length;
++	left_w = ((under_text_length == 0)? td->offset:under_text_offset)
++		- left_x - WINDOW_TITLE_TO_STICK_GAP - td->left_of_text_length;
++	right_x = ((under_text_length == 0)?
++		   td->offset + td->length :
++		   under_text_offset + under_text_length)
++		+ td->right_of_text_length + WINDOW_TITLE_TO_STICK_GAP - 1;
++	right_w = fw->title_length - right_x - WINDOW_TITLE_STICK_OFFSET
++		- td->right_end_length;
++	/* an odd number of lines every WINDOW_TITLE_STICK_VERT_DIST pixels */
++	if (left_w < WINDOW_TITLE_STICK_MIN_WIDTH)
++	{
++		left_x = td->left_end_length +
++			((left_length > WINDOW_TITLE_STICK_MIN_WIDTH)?
++			 (left_length - WINDOW_TITLE_STICK_MIN_WIDTH)/2 : 0);
++		left_w = WINDOW_TITLE_STICK_MIN_WIDTH;
++	}
++	if (right_w < WINDOW_TITLE_STICK_MIN_WIDTH)
++	{
++		right_w = WINDOW_TITLE_STICK_MIN_WIDTH;
++		right_x = fw->title_length - WINDOW_TITLE_STICK_MIN_WIDTH - 1
++			- td->right_end_length -
++			((right_length > WINDOW_TITLE_STICK_MIN_WIDTH)?
++			 (right_length -
++			  WINDOW_TITLE_STICK_MIN_WIDTH)/2 : 0);
++	}
++	for (i = min; i <= max; i += WINDOW_TITLE_STICK_VERT_DIST)
++	{
++		if (left_w > 0)
++		{
++			do_relieve_rectangle_with_rotation(
++				dpy, dest_pix,
++				SWAP_ARGS(td->has_vt, left_x, i),
++				SWAP_ARGS(td->has_vt, left_w, 1),
++				tdd->sgc, tdd->rgc, 1, False, rotation);
++		}
++		if (right_w > 0)
++		{
++			do_relieve_rectangle_with_rotation(
++				dpy, dest_pix,
++				SWAP_ARGS(td->has_vt, right_x, i),
++				SWAP_ARGS(td->has_vt, right_w, 1),
++				tdd->sgc, tdd->rgc, 1, False, rotation);
++		}
++	}
++
++	return;
++}
++
++static void border_draw_title_mono(
++	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
++	FlocaleWinString *fstr, Pixmap dest_pix)
++{
++	int has_vt;
++
++	has_vt = HAS_VERTICAL_TITLE(fw);
++	XFillRectangle(
++		dpy, dest_pix, td->cd->relief_gc,
++		td->offset - 2, 0, td->length+4, fw->title_thickness);
++	if (fw->visible_name != (char *)NULL)
++	{
++		FlocaleDrawString(dpy, fw->title_font, fstr, 0);
++	}
++	/* for mono, we clear an area in the title bar where the window
++	 * title goes, so that its more legible. For color, no need */
++	do_relieve_rectangle(
++		dpy, dest_pix, 0, 0,
++		SWAP_ARGS(has_vt, td->offset - 3,
++			  fw->title_thickness - 1),
++		tdd->rgc, tdd->sgc, td->cd->relief_width, False);
++	do_relieve_rectangle(
++		dpy, dest_pix,
++		SWAP_ARGS(has_vt, td->offset + td->length + 2, 0),
++		SWAP_ARGS(has_vt, fw->title_length - td->length -
++			  td->offset - 3, fw->title_thickness - 1),
++		tdd->rgc, tdd->sgc, td->cd->relief_width, False);
++	XDrawLine(
++		dpy, dest_pix, tdd->sgc,
++		SWAP_ARGS(has_vt, 0, td->offset + td->length + 1),
++		SWAP_ARGS(has_vt, td->offset + td->length + 1,
++			  fw->title_thickness));
++
++	return;
++}
++
++static void border_draw_title_relief(
++	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
++	Pixmap dest_pix)
++{
++	int reverse = 0;
++	rotation_t rotation;
++
++	if (td->td_is_rotated)
++	{
++		rotation = td->restore_rotation;
++	}
++	else
++	{
++		rotation = ROTATION_0;
++	}
++	/* draw title relief */
++	switch (DFS_BUTTON_RELIEF(*tdd->tstyle))
++	{
++	case DFS_BUTTON_IS_SUNK:
++		reverse = 1;
++	case DFS_BUTTON_IS_UP:
++		do_relieve_rectangle_with_rotation(
++			dpy, dest_pix, 0, 0,
++			SWAP_ARGS(
++				td->has_vt, fw->title_length - 1,
++				fw->title_thickness - 1),
++			(reverse) ? tdd->sgc : tdd->rgc,
++			(reverse) ? tdd->rgc : tdd->sgc, td->cd->relief_width,
++			True, rotation);
++		break;
++	default:
++		/* flat */
++		break;
++	}
++
++	return;
++}
++
++static void border_draw_title_deep(
++	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
++	FlocaleWinString *fstr, Pixmap dest_pix, Window w)
++{
++	DecorFace *df;
++	pixmap_background_type bg;
++
++	bg.flags.use_pixmap = 0;
++	for (df = tdd->df; df != NULL; df = df->next)
++	{
++		if (df->style.face_type == MultiPixmap)
++		{
++			border_mp_draw_mp_titlebar(
++				fw, td, df, dest_pix, w);
++		}
++		else
++		{
++			bg.pixel = df->u.back;
++			border_draw_decor_to_pixmap(
++				fw, dest_pix, w, &bg, &td->layout.title_g, df,
++				td, td->tbstate.tstate, True, tdd->is_toggled,
++				1);
++		}
++	}
++	FlocaleDrawString(dpy, fw->title_font, &tdd->fstr, 0);
++
++	return;
++}
++
++static void border_get_titlebar_draw_descr(
++	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
++	Pixmap dest_pix)
++{
++	rectangle *title_g;
++
++	memset(tdd, 0, sizeof(*tdd));
++	/* prepare the gcs and variables */
++	if (td->tbstate.is_title_pressed)
++	{
++		tdd->rgc = td->cd->shadow_gc;
++		tdd->sgc = td->cd->relief_gc;
++	}
++	else
++	{
++		tdd->rgc = td->cd->relief_gc;
++		tdd->sgc = td->cd->shadow_gc;
++	}
++	NewFontAndColor(fw->title_font, td->cd->fore_color, td->cd->back_color);
++	title_g = &td->layout.title_g;
++	tdd->tstyle = &TB_STATE(
++		GetDecor(fw, titlebar))[td->tbstate.tstate].style;
++	tdd->df = &TB_STATE(GetDecor(fw, titlebar))[td->tbstate.tstate];
++
++	/* fetch the title string */
++	tdd->fstr.str = fw->visible_name;
++	tdd->fstr.win = dest_pix;
++	if (td->td_is_rotated)
++	{
++		tdd->fstr.flags.text_rotation = ROTATION_0;
++	}
++	else
++	{
++		tdd->fstr.flags.text_rotation = fw->title_text_rotation;
++	}
++	if (td->has_vt)
++	{
++		tdd->fstr.y = td->offset;
++		tdd->fstr.x = fw->title_text_offset + 1;
++	}
++	else
++	{
++		tdd->fstr.x = td->offset;
++		tdd->fstr.y = fw->title_text_offset + 1;
++	}
++	if (td->cd->cs >= 0)
++	{
++		tdd->fstr.colorset = &Colorset[td->cd->cs];
++		tdd->fstr.flags.has_colorset = 1;
++	}
++	tdd->fstr.gc = Scr.TitleGC;
++
++	return;
++}
++
++static void border_set_title_pixmap(
++	FvwmWindow *fw, titlebar_descr *td, Pixmap *dest_pix, Window w)
++{
++	pixmap_background_type bg;
++	title_draw_descr tdd;
++	FlocaleWinString fstr;
++	Bool free_bg_pixmap = False;
++	rectangle pix_g;
++
++	border_get_titlebar_draw_descr(fw, td, &tdd, *dest_pix);
++	/* prepare background, either from the window colour or from the
++	 * border style */
++	if (!DFS_USE_BORDER_STYLE(*tdd.tstyle))
++	{
++		/* fill with the button background colour */
++		bg.flags.use_pixmap = 0;
++		bg.pixel = td->cd->back_color;
++		pix_g.x = 0;
++		pix_g.y = 0;
++		pix_g.width = td->layout.title_g.width;
++		pix_g.height = td->layout.title_g.height;
++		border_fill_pixmap_background(
++			*dest_pix, &pix_g, &bg, td->cd);
++	}
++	else
++	{
++		/* draw pixmap background inherited from border style */
++		rectangle relative_g;
++		Pixmap tmp;
++
++		if (td->draw_rotation != ROTATION_0)
++		{
++			tmp = CreateRotatedPixmap(
++				dpy, *dest_pix,
++				td->layout.title_g.width,
++				td->layout.title_g.height,
++				Pdepth, Scr.BordersGC, td->restore_rotation);
++			XFreePixmap(dpy, *dest_pix);
++			*dest_pix = tmp;
++			border_rotate_titlebar_descr(fw, td);
++		}
++		relative_g.width = td->frame_g.width;
++		relative_g.height = td->frame_g.height;
++		relative_g.x = td->layout.title_g.x;
++		relative_g.y = td->layout.title_g.y;
++		border_get_border_background(
++			&bg, td->cd, &td->layout.title_g, &relative_g,
++			&free_bg_pixmap, w);
++		bg.pixmap.g.x = 0;
++		bg.pixmap.g.y = 0;
++		/* set the geometry for drawing the Tiled pixmap;
++		 * FIXME: maybe add the relief as offset? */
++		pix_g.x = 0;
++		pix_g.y = 0;
++		pix_g.width = td->layout.title_g.width;
++		pix_g.height = td->layout.title_g.height;
++		border_fill_pixmap_background(
++			*dest_pix, &pix_g, &bg, td->cd);
++		if (free_bg_pixmap && bg.pixmap.p)
++		{
++			XFreePixmap(dpy, bg.pixmap.p);
++		}
++		if (td->draw_rotation != ROTATION_0)
++		{
++			tmp = CreateRotatedPixmap(
++				dpy, *dest_pix,
++				td->layout.title_g.width,
++				td->layout.title_g.height,
++				Pdepth, Scr.BordersGC, td->draw_rotation);
++			XFreePixmap(dpy, *dest_pix);
++			*dest_pix = tmp;
++			border_rotate_titlebar_descr(fw, td);
++		}
++	}
++
++	if (Pdepth < 2)
++	{
++		border_draw_title_mono(fw, td, &tdd, &fstr, *dest_pix);
++	}
++	else
++	{
++		border_draw_title_deep(fw, td, &tdd, &fstr, *dest_pix, w);
++	}
++	border_draw_title_relief(fw, td, &tdd, *dest_pix);
++	border_draw_title_stick_lines(fw, td, &tdd, *dest_pix);
++
++	return;
++}
++
++static void border_draw_title(
++	FvwmWindow *fw, titlebar_descr *td)
++{
++	Pixmap p;
++
++	if (td->layout.title_g.x < 0 || td->layout.title_g.y < 0)
++	{
++		return;
++	}
++	if (td->draw_rotation != ROTATION_0)
++	{
++		border_rotate_titlebar_descr(fw, td);
++	}
++	/* make a pixmap */
++	p = border_create_decor_pixmap(td->cd, &(td->layout.title_g));
++	/* set the background tile */
++#if 0
++	fprintf(stderr,"drawing title\n");
++#endif
++	border_set_title_pixmap(fw, td, &p, FW_W_TITLE(fw));
++	if (td->draw_rotation != ROTATION_0)
++	{
++		Pixmap tmp;
++
++		tmp = CreateRotatedPixmap(
++			dpy, p, td->layout.title_g.width,
++			td->layout.title_g.height, Pdepth, Scr.BordersGC,
++			td->draw_rotation);
++		XFreePixmap(dpy, p);
++		p = tmp;
++		border_rotate_titlebar_descr(fw, td);
++	}
++	/* apply the pixmap and destroy it */
++	border_set_part_background(FW_W_TITLE(fw), p);
++	XFreePixmap(dpy, p);
++	if (td->tbstate.do_clear_title)
++	{
++		XClearWindow(dpy, FW_W_TITLE(fw));
++	}
++
++	return;
++}
++
++static void border_draw_buttons(
++	FvwmWindow *fw, titlebar_descr *td)
++{
++	int i;
++
++	/* draw everything in a big loop */
++#if 0
++	fprintf(stderr, "drawing buttons 0x%04x\n", td->tbstate.draw_bmask);
++#endif
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		unsigned int mask = (1 << i);
++
++		if ((td->tbstate.draw_bmask & mask) != 0)
++		{
++			border_draw_one_button(fw, td, i);
++		}
++	}
++	/* update the button states */
++	fw->decor_state.buttons_drawn |= td->tbstate.draw_bmask;
++	fw->decor_state.buttons_inverted = td->tbstate.pressed_bmask;
++	fw->decor_state.buttons_lit = td->tbstate.lit_bmask;
++	fw->decor_state.buttons_toggled = td->tbstate.toggled_bmask;
++
++	return;
++}
++
++static void border_setup_use_title_style(
++	FvwmWindow *fw, titlebar_descr *td)
++{
++	int i;
++	DecorFace *df, *tsdf;
++	ButtonState bs, tsbs;
++
++	/* use a full bar pixmap (for Colorset) or non window size pixmaps
++	 * (for MultiPixmap) under certain condition:
++	 * - for the buttons which use title style
++	 * - for title which have a button with UseTitle style
++	 */
++	tsbs = td->tbstate.tstate;
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		bs = td->tbstate.bstate[i];
++		df = &TB_STATE(GetDecor(fw, buttons[i]))[bs];
++		tsdf = &TB_STATE(GetDecor(fw, buttons[i]))[tsbs];
++		if (FW_W_BUTTON(fw, i) != None)
++		{
++			if (DFS_USE_TITLE_STYLE(df->style))
++			{
++				border_setup_bar_pixmaps(
++					td, &(td->cd->dynamic_cd),
++					&TB_STATE(GetDecor(fw, titlebar))[bs],
++					bs);
++			}
++			if (DFS_USE_TITLE_STYLE(tsdf->style))
++			{
++				border_setup_bar_pixmaps(
++					td, &(td->cd->dynamic_cd),
++					&TB_STATE(GetDecor(fw, titlebar))[tsbs],
++					tsbs);
++			}
++		}
++	}
++	return;
++}
++
++static void border_rotate_titlebar_descr(
++	FvwmWindow *fw, titlebar_descr *td)
++{
++	rotation_t rotation;
++	int i, tmpi;
++	static titlebar_descr saved_td;
++
++	if (td->draw_rotation == ROTATION_0)
++	{
++		return;
++	}
++	if (!td->has_been_saved)
++	{
++		td->has_been_saved = True;
++		memcpy(&saved_td, td, sizeof(titlebar_descr));
++	}
++	if (!td->td_is_rotated)
++	{
++		/* make the bar horizontal */
++		switch(td->draw_rotation)
++		{
++		case ROTATION_90: /* cw */
++			rotation = ROTATION_270;
++			break;
++		case ROTATION_270: /* ccw */
++			rotation = ROTATION_90;
++			break;
++		case ROTATION_180:
++			rotation = ROTATION_180;
++			break;
++		default:
++			return;
++		}
++		td->has_vt = 0;
++		td->has_an_upsidedown_rotation = 0;
++		td->td_is_rotated = 1;
++	}
++	else
++	{
++		/* restore */
++		memcpy(td, &saved_td, sizeof(titlebar_descr));
++		td->td_is_rotated = 0;
++		return;
++	}
++
++#define ROTATE_RECTANGLE(rot, r, vs_frame, vs_titlebar, vs_title) \
++	{ \
++		rectangle tr; \
++		tr.x = r->x; \
++		tr.y = r->y; \
++		tr.width = r->width; \
++		tr.height = r->height; \
++		switch(rot) \
++		{ \
++		case ROTATION_270: /* ccw */ \
++			tr.x = r->y; \
++			if (vs_frame) \
++			{ \
++				tr.y = td->frame_g.width - (r->x+r->width); \
++			} \
++			else if (vs_titlebar) \
++			{ \
++				tr.y = td->bar_g.width - \
++					(r->x+r->width); \
++			} \
++			else if (vs_title) \
++			{ \
++				tr.y = td->layout.title_g.width - \
++					(r->x+r->width); \
++			} \
++			else \
++			{ \
++				tr.y = r->x; \
++			} \
++			tr.width = r->height; \
++			tr.height = r->width; \
++			break; \
++		case ROTATION_90: /* cw */ \
++			if (vs_frame) \
++			{ \
++				tr.x = td->frame_g.height - (r->y+r->height); \
++			} \
++			else if (vs_titlebar) \
++			{ \
++				tr.x = td->bar_g.height - \
++					(r->y+r->height); \
++			} \
++			else if (vs_title) \
++			{ \
++				tr.x = td->layout.title_g.height - \
++					(r->y+r->height); \
++			} \
++			else \
++			{ \
++				tr.x = r->y; \
++			} \
++			tr.y = r->x; \
++			tr.width = r->height; \
++			tr.height = r->width; \
++			break; \
++		case ROTATION_180: \
++			if (vs_frame) \
++			{ \
++				tr.x = td->frame_g.width - (r->x+r->width); \
++			} \
++			else if (vs_titlebar) \
++			{ \
++				tr.x = td->bar_g.width - \
++					(r->x + r->width); \
++			} \
++			else if (vs_title) \
++			{ \
++				tr.x = td->layout.title_g.width - \
++					(r->x + r->width); \
++			} \
++			else \
++			{ \
++				tr.x = r->x; \
++			} \
++			break; \
++		case ROTATION_0: \
++			break; \
++		} \
++		r->x = tr.x; \
++		r->y = tr.y; \
++		r->width = tr.width; \
++		r->height = tr.height; \
++	}
++
++	switch(rotation)
++	{
++	case ROTATION_90:
++		td->offset =
++			td->layout.title_g.height - td->offset - td->length;
++		tmpi = td->left_end_length;
++		td->left_end_length = td->right_end_length;
++		td->right_end_length = tmpi;
++		tmpi = td->left_of_text_length;
++		td->left_of_text_length = td->right_of_text_length;
++		td->right_of_text_length = tmpi;
++		break;
++	case ROTATION_270:
++		break;
++	case ROTATION_180:
++		td->offset = td->layout.title_g.width - td->offset - td->length;
++		tmpi = td->left_end_length;
++		td->left_end_length = td->right_end_length;
++		td->right_end_length = tmpi;
++		tmpi = td->left_of_text_length;
++		td->left_of_text_length = td->right_of_text_length;
++		td->right_of_text_length = tmpi;
++		break;
++	case ROTATION_0:
++		break;
++	}
++
++	ROTATE_RECTANGLE(rotation, (&td->left_buttons_g), True, False, False)
++	ROTATE_RECTANGLE(rotation, (&td->right_buttons_g), True, False, False)
++	for (i=0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		ROTATE_RECTANGLE(
++			rotation, (&td->layout.button_g[i]), True, False, False)
++	}
++	ROTATE_RECTANGLE(rotation, (&td->under_text_g), False, False, True)
++	ROTATE_RECTANGLE(rotation, (&td->left_main_g), False, False, True)
++	ROTATE_RECTANGLE(rotation, (&td->right_main_g), False, False, True)
++	ROTATE_RECTANGLE(rotation, (&td->full_left_main_g), True, False, False)
++	ROTATE_RECTANGLE(rotation, (&td->full_right_main_g), True, False, False)
++	ROTATE_RECTANGLE(rotation, (&td->layout.title_g), True, False, False)
++	ROTATE_RECTANGLE(rotation, (&td->bar_g), True, False, False)
++	ROTATE_RECTANGLE(rotation, (&td->frame_g), False, False, False);
++
++#undef ROTATE_RECTANGLE
++}
++
++static void border_get_titlebar_descr_state(
++	FvwmWindow *fw, window_parts pressed_parts, int pressed_button,
++	clear_window_parts clear_parts, Bool do_hilight,
++	border_titlebar_state *tbstate)
++{
++	int i;
++
++	if ((pressed_parts & PART_BUTTONS) != PART_NONE && pressed_button >= 0)
++	{
++		tbstate->pressed_bmask = (1 << pressed_button);
++	}
++	else
++	{
++		tbstate->pressed_bmask = 0;
++	}
++	if ((clear_parts & CLEAR_BUTTONS) != CLEAR_NONE)
++	{
++		tbstate->clear_bmask = ~0;
++	}
++	else
++	{
++		tbstate->clear_bmask = 0;
++	}
++	tbstate->lit_bmask = (do_hilight == True) ? ~0 : 0;
++	if ((pressed_parts & PART_TITLE) != PART_NONE)
++	{
++		tbstate->is_title_pressed = 1;
++	}
++	else
++	{
++		tbstate->is_title_pressed = 0;
++	}
++	if ((clear_parts & CLEAR_TITLE) != CLEAR_NONE)
++	{
++		tbstate->do_clear_title = 1;
++	}
++	else
++	{
++		tbstate->do_clear_title = 0;
++	}
++	tbstate->is_title_lit = (do_hilight == True) ? 1 : 0;
++	tbstate->toggled_bmask = 0;
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		unsigned int mask = (1 << i);
++
++		if (is_button_toggled(fw, i))
++		{
++			tbstate->toggled_bmask |= mask;
++		}
++		tbstate->bstate[i] = border_flags_to_button_state(
++			tbstate->pressed_bmask & mask,
++			tbstate->lit_bmask & mask,
++			tbstate->toggled_bmask & mask);
++	}
++	tbstate->tstate = border_flags_to_button_state(
++		tbstate->is_title_pressed, tbstate->is_title_lit, 0);
++}
++
++static window_parts border_get_titlebar_descr(
++	common_decorations_type *cd, FvwmWindow *fw,
++	window_parts pressed_parts, int pressed_button,
++	window_parts force_draw_parts, clear_window_parts clear_parts,
++	rectangle *old_g, rectangle *new_g, Bool do_hilight,
++	titlebar_descr *ret_td)
++{
++	window_parts draw_parts;
++	int i;
++	DecorFace *df;
++	int is_start = 0;
++	JustificationType just;
++	int lbl = 0;
++	int rbl = 0;
++
++	ret_td->cd = cd;
++	ret_td->frame_g = *new_g;
++	if (old_g == NULL)
++	{
++		old_g = &fw->g.frame;
++	}
++	frame_get_titlebar_dimensions(fw, old_g, NULL, &ret_td->old_layout);
++	frame_get_titlebar_dimensions(fw, new_g, NULL, &ret_td->layout);
++
++	ret_td->has_vt = HAS_VERTICAL_TITLE(fw);
++	if (USE_TITLE_DECOR_ROTATION(fw))
++	{
++		ret_td->draw_rotation = fw->title_text_rotation;
++		switch(ret_td->draw_rotation)
++		{
++		case ROTATION_90:
++			ret_td->restore_rotation = ROTATION_270;
++			break;
++		case ROTATION_270: /* ccw */
++			ret_td->restore_rotation = ROTATION_90;
++			break;
++		case ROTATION_180:
++			ret_td->restore_rotation = ROTATION_180;
++			break;
++		default:
++			break;
++		}
++	}
++	if (fw->title_text_rotation == ROTATION_270 ||
++	    fw->title_text_rotation == ROTATION_180)
++	{
++		ret_td->has_an_upsidedown_rotation = True;
++	}
++	/* geometry of the title bar title + buttons */
++	if (!ret_td->has_vt)
++	{
++		ret_td->bar_g.width = new_g->width - 2 * fw->boundary_width;
++		ret_td->bar_g.height = ret_td->layout.title_g.height;
++		ret_td->bar_g.x = fw->boundary_width;
++		ret_td->bar_g.y = ret_td->layout.title_g.y;
++	}
++	else
++	{
++		ret_td->bar_g.width = ret_td->layout.title_g.width;
++		ret_td->bar_g.height = new_g->height - 2 * fw->boundary_width;
++		ret_td->bar_g.y = fw->boundary_width;
++		ret_td->bar_g.x = ret_td->layout.title_g.x;
++	}
++
++	/* buttons geometries */
++	if (ret_td->has_vt)
++	{
++		ret_td->left_buttons_g.width = ret_td->bar_g.width;
++		ret_td->right_buttons_g.width = ret_td->bar_g.width;
++	}
++	else
++	{
++		ret_td->left_buttons_g.height = ret_td->bar_g.height;
++		ret_td->right_buttons_g.height = ret_td->bar_g.width;
++	}
++
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		if (FW_W_BUTTON(fw, i) == None)
++		{
++			continue;
++		}
++		if (ret_td->has_vt)
++		{
++			if (i & 1)
++			{
++				rbl += ret_td->layout.button_g[i].height;
++			}
++			else
++			{
++				lbl += ret_td->layout.button_g[i].height;
++			}
++		}
++		else
++		{
++			if (i & 1)
++			{
++				rbl += ret_td->layout.button_g[i].width;
++			}
++			else
++			{
++				lbl += ret_td->layout.button_g[i].width;
++			}
++		}
++	}
++
++	if (ret_td->has_an_upsidedown_rotation)
++	{
++		if (ret_td->has_vt)
++		{
++			ret_td->left_buttons_g.height = rbl;
++			ret_td->right_buttons_g.height = lbl;
++			ret_td->right_buttons_g.y = fw->boundary_width;
++			ret_td->right_buttons_g.x = ret_td->bar_g.x;
++			ret_td->left_buttons_g.y = ret_td->layout.title_g.y +
++				ret_td->layout.title_g.height;
++			ret_td->left_buttons_g.x = ret_td->bar_g.x;
++		}
++		else
++		{
++			ret_td->left_buttons_g.width = rbl;
++			ret_td->right_buttons_g.width = lbl;
++			ret_td->right_buttons_g.x = fw->boundary_width;
++			ret_td->right_buttons_g.y = ret_td->bar_g.y;
++			ret_td->left_buttons_g.x = ret_td->layout.title_g.x +
++				ret_td->layout.title_g.width;
++			ret_td->left_buttons_g.y = ret_td->bar_g.y;
++		}
++	}
++	else
++	{
++		if (ret_td->has_vt)
++		{
++			ret_td->left_buttons_g.height = lbl;
++			ret_td->right_buttons_g.height = rbl;
++			ret_td->left_buttons_g.y = fw->boundary_width;
++			ret_td->left_buttons_g.x = ret_td->bar_g.x;
++			ret_td->right_buttons_g.y = ret_td->layout.title_g.y +
++				ret_td->layout.title_g.height;
++			ret_td->right_buttons_g.x = ret_td->bar_g.x;
++		}
++		else
++		{
++			ret_td->left_buttons_g.width = lbl;
++			ret_td->right_buttons_g.width = rbl;
++			ret_td->left_buttons_g.x = fw->boundary_width;
++			ret_td->left_buttons_g.y = ret_td->bar_g.y;
++			ret_td->right_buttons_g.x = ret_td->layout.title_g.x +
++				ret_td->layout.title_g.width;
++			ret_td->right_buttons_g.y = ret_td->bar_g.y;
++		}
++	}
++
++	/* initialise flags */
++	border_get_titlebar_descr_state(
++		fw, pressed_parts, pressed_button, clear_parts, do_hilight,
++		&(ret_td->tbstate));
++
++	/* get the title string length and position
++	 * This is not in "tdd" (titlebar_draw_descr), because these are needed
++	 * to draw the buttons with UseTitleStyle */
++	just = TB_JUSTIFICATION(GetDecor(fw, titlebar));
++	if (fw->visible_name != (char *)NULL)
++	{
++		ret_td->length = FlocaleTextWidth(
++			fw->title_font, fw->visible_name,
++			(ret_td->has_vt) ? -strlen(fw->visible_name) :
++			strlen(fw->visible_name));
++		if (ret_td->length > fw->title_length -
++		    2*MIN_WINDOW_TITLE_TEXT_OFFSET)
++		{
++			ret_td->length = fw->title_length -
++				2*MIN_WINDOW_TITLE_TEXT_OFFSET;
++			just = JUST_CENTER;
++		}
++		if (ret_td->length < 0)
++		{
++			ret_td->length = 0;
++		}
++	}
++	else
++	{
++		ret_td->length = 0;
++	}
++	if (ret_td->length == 0)
++	{
++		just = JUST_CENTER;
++	}
++	df = &TB_STATE(GetDecor(fw, titlebar))[ret_td->tbstate.tstate];
++	switch (just)
++	{
++	case JUST_LEFT:
++		is_start = 1;
++		/* fall through */
++	case JUST_RIGHT:
++		if (ret_td->has_an_upsidedown_rotation)
++		{
++			is_start = !is_start;
++		}
++		if (is_start)
++		{
++			if (WINDOW_TITLE_TEXT_OFFSET + ret_td->length <=
++			    fw->title_length)
++			{
++				ret_td->offset = WINDOW_TITLE_TEXT_OFFSET;
++			}
++			else
++			{
++				ret_td->offset =
++					fw->title_length - ret_td->length;
++			}
++		}
++		else
++		{
++			ret_td->offset = fw->title_length - ret_td->length -
++				WINDOW_TITLE_TEXT_OFFSET;
++		}
++		break;
++	case JUST_CENTER:
++	default:
++		ret_td->offset = (fw->title_length - ret_td->length) / 2;
++		break;
++	}
++
++	if (ret_td->offset < MIN_WINDOW_TITLE_TEXT_OFFSET)
++	{
++		ret_td->offset = MIN_WINDOW_TITLE_TEXT_OFFSET;
++	}
++
++	/* setup MultiPixmap */
++	border_mp_get_titlebar_descr(fw, ret_td, df);
++
++	/* determine the parts to draw */
++	draw_parts = border_get_tb_parts_to_draw(
++		fw, ret_td, old_g, new_g, force_draw_parts);
++
++	return draw_parts;
++}
++
++
++static void border_draw_titlebar(
++	common_decorations_type *cd, FvwmWindow *fw,
++	window_parts pressed_parts, int pressed_button,
++	window_parts force_draw_parts, clear_window_parts clear_parts,
++	rectangle *old_g, rectangle *new_g, Bool do_hilight)
++{
++	window_parts draw_parts;
++	titlebar_descr td;
++
++	if (!HAS_TITLE(fw))
++	{
++		/* just reset border states */
++		fw->decor_state.parts_drawn &= ~(PART_TITLE);
++		fw->decor_state.parts_lit &= ~(PART_TITLE);
++		fw->decor_state.parts_inverted &= ~(PART_TITLE);
++		fw->decor_state.buttons_drawn = 0;
++		fw->decor_state.buttons_lit = 0;
++		fw->decor_state.buttons_inverted = 0;
++		fw->decor_state.buttons_toggled = 0;
++		return;
++	}
++	memset(&td, 0, sizeof(td));
++	draw_parts = border_get_titlebar_descr(
++		cd, fw, pressed_parts, pressed_button, force_draw_parts,
++		clear_parts, old_g, new_g, do_hilight, &td);
++	if ((draw_parts & PART_TITLE) != PART_NONE ||
++	    (draw_parts & PART_BUTTONS) != PART_NONE)
++	{
++		/* set up UseTitleStyle Colorset */
++		border_setup_use_title_style(fw, &td);
++	}
++	if ((draw_parts & PART_TITLE) != PART_NONE)
++	{
++		border_draw_title(fw, &td);
++	}
++	if ((draw_parts & PART_BUTTONS) != PART_NONE)
++	{
++		border_draw_buttons(fw, &td);
++	}
++	border_free_bar_pixmaps(&(td.cd->dynamic_cd));
++
++	/* update the decor states */
++	fw->decor_state.parts_drawn |= draw_parts;
++	if (do_hilight)
++	{
++		fw->decor_state.parts_lit |= draw_parts;
++	}
++	else
++	{
++		fw->decor_state.parts_lit &= ~draw_parts;
++	}
++	fw->decor_state.parts_inverted &= ~draw_parts;
++	fw->decor_state.parts_inverted |= (draw_parts & pressed_parts);
++	if (draw_parts & PART_BUTTONS)
++	{
++		fw->decor_state.buttons_drawn |= td.tbstate.draw_bmask;
++		fw->decor_state.parts_lit = (do_hilight) ? ~0 : 0;
++		if (td.tbstate.pressed_bmask)
++		{
++			fw->decor_state.buttons_inverted =
++				td.tbstate.pressed_bmask;
++		}
++		else
++		{
++			fw->decor_state.buttons_inverted &=
++				~td.tbstate.draw_bmask;
++		}
++		fw->decor_state.buttons_toggled =
++			(fw->decor_state.buttons_toggled &
++			 ~td.tbstate.max_bmask) | td.tbstate.toggled_bmask;
++	}
++
++	return;
++}
++
++/*
++ *
++ * Redraws the windows borders
++ *
++ */
++static void border_draw_border_parts(
++	common_decorations_type *cd, FvwmWindow *fw,
++	window_parts pressed_parts, window_parts force_draw_parts,
++	clear_window_parts clear_parts, rectangle *old_g, rectangle *new_g,
++	Bool do_hilight)
++{
++	border_relief_descr br;
++	window_parts draw_parts;
++	Bool do_clear;
++
++	if (HAS_NO_BORDER(fw))
++	{
++		/* just reset border states */
++		fw->decor_state.parts_drawn &= ~(PART_FRAME | PART_HANDLES);
++		fw->decor_state.parts_lit &= ~(PART_FRAME | PART_HANDLES);
++		fw->decor_state.parts_inverted &= ~(PART_FRAME | PART_HANDLES);
++		return;
++	}
++	do_clear = (clear_parts & CLEAR_FRAME) ? True : False;
++	/* determine the parts to draw and the position to place them */
++	if (HAS_DEPRESSABLE_BORDER(fw))
++	{
++		pressed_parts &= PART_FRAME;
++	}
++	else
++	{
++		pressed_parts = PART_NONE;
++	}
++	force_draw_parts &= PART_FRAME;
++	memset(&br, 0, sizeof(br));
++	draw_parts = border_get_parts_and_pos_to_draw(
++		cd, fw, pressed_parts, force_draw_parts, old_g, new_g,
++		do_hilight, &br);
++	if ((draw_parts & PART_FRAME) != PART_NONE)
++	{
++		border_draw_all_border_parts(
++			cd, fw, &br, new_g, draw_parts, pressed_parts,
++			do_hilight, do_clear);
++	}
++	/* update the decor states */
++	fw->decor_state.parts_drawn |= draw_parts;
++	if (do_hilight)
++	{
++		fw->decor_state.parts_lit |= draw_parts;
++	}
++	else
++	{
++		fw->decor_state.parts_lit &= ~draw_parts;
++	}
++	fw->decor_state.parts_inverted &= ~draw_parts;
++	fw->decor_state.parts_inverted |= (draw_parts & pressed_parts);
++
++	return;
++}
++
++/* ---------------------------- interface functions ------------------------ */
++
++DecorFace *border_get_border_style(
++	FvwmWindow *fw, Bool has_focus)
++{
++	DecorFace *df;
++
++	if (has_focus == True)
++	{
++		df = &(GetDecor(fw, BorderStyle.active));
++	}
++	else
++	{
++		df = &(GetDecor(fw, BorderStyle.inactive));
++	}
++
++	return df;
++}
++
++int border_is_using_border_style(
++	FvwmWindow *fw, Bool has_focus)
++{
++	ButtonState bs;
++	int is_pressed;
++	int is_toggled;
++	int i;
++
++	/* title */
++	is_pressed = (FW_W_TITLE(fw) == PressedW);
++	bs = border_flags_to_button_state(is_pressed, has_focus, 0);
++	if (DFS_USE_BORDER_STYLE(TB_STATE(GetDecor(fw, titlebar))[bs].style))
++	{
++		return 1;
++	}
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		if (FW_W_BUTTON(fw, i) == None)
++		{
++			continue;
++		}
++		is_pressed = (FW_W_BUTTON(fw, i) == PressedW);
++		is_toggled = (is_button_toggled(fw, i) == True);
++		bs = border_flags_to_button_state(
++			is_pressed, (has_focus == True), is_toggled);
++		if (DFS_USE_BORDER_STYLE(
++			    TB_STATE(GetDecor(fw, buttons[i]))[bs].style))
++		{
++			return 1;
++		}
++	}
++
++	return 0;
++}
++
++int border_context_to_parts(
++	int context)
++{
++	if (context == C_FRAME || context == C_SIDEBAR ||
++	    context == (C_FRAME | C_SIDEBAR))
++	{
++		return PART_FRAME;
++	}
++	else if (context == C_F_TOPLEFT)
++	{
++		return PART_BORDER_NW;
++	}
++	else if (context == C_F_TOPRIGHT)
++	{
++		return PART_BORDER_NE;
++	}
++	else if (context == C_F_BOTTOMLEFT)
++	{
++		return PART_BORDER_SW;
++	}
++	else if (context == C_F_BOTTOMRIGHT)
++	{
++		return PART_BORDER_SE;
++	}
++	else if (context == C_SB_LEFT)
++	{
++		return PART_BORDER_W;
++	}
++	else if (context == C_SB_RIGHT)
++	{
++		return PART_BORDER_E;
++	}
++	else if (context == C_SB_TOP)
++	{
++		return PART_BORDER_N;
++	}
++	else if (context == C_SB_BOTTOM)
++	{
++		return PART_BORDER_S;
++	}
++	else if (context == C_TITLE)
++	{
++		return PART_TITLE;
++	}
++	else if (context & (C_LALL | C_RALL))
++	{
++		return PART_BUTTONS;
++	}
++
++	return PART_NONE;
++}
++
++void border_get_part_geometry(
++	FvwmWindow *fw, window_parts part, rectangle *sidebar_g,
++	rectangle *ret_g, Window *ret_w)
++{
++	int bw;
++
++	bw = fw->boundary_width;
++	/* ret_g->x and ret->y is just an offset relatively to the w,
++	 * maybe we can take the relief in account? */
++	switch (part)
++	{
++	case PART_BORDER_N:
++		ret_g->x = sidebar_g->x;
++		ret_g->y = 0;
++		*ret_w = FW_W_SIDE(fw, 0);
++		break;
++	case PART_BORDER_E:
++		ret_g->x = 2 * sidebar_g->x + sidebar_g->width - bw;
++		ret_g->y = sidebar_g->y;
++		*ret_w = FW_W_SIDE(fw, 1);
++		break;
++	case PART_BORDER_S:
++		ret_g->x = sidebar_g->x;
++		ret_g->y = 2 * sidebar_g->y + sidebar_g->height - bw;
++		*ret_w = FW_W_SIDE(fw, 2);
++		break;
++	case PART_BORDER_W:
++		ret_g->x = 0;
++		ret_g->y = sidebar_g->y;
++		*ret_w = FW_W_SIDE(fw, 3);
++		break;
++	case PART_BORDER_NW:
++		ret_g->x = 0;
++		ret_g->y = 0;
++		*ret_w = FW_W_CORNER(fw, 0);
++		break;
++	case PART_BORDER_NE:
++		ret_g->x = sidebar_g->x + sidebar_g->width;
++		ret_g->y = 0;
++		*ret_w = FW_W_CORNER(fw, 1);
++		break;
++	case PART_BORDER_SW:
++		ret_g->x = 0;
++		ret_g->y = sidebar_g->y + sidebar_g->height;
++		*ret_w = FW_W_CORNER(fw, 2);
++		break;
++	case PART_BORDER_SE:
++		ret_g->x = sidebar_g->x + sidebar_g->width;
++		ret_g->y = sidebar_g->y + sidebar_g->height;
++		*ret_w = FW_W_CORNER(fw, 3);
++		break;
++	default:
++		break;
++	}
++
++	switch (part)
++	{
++	case PART_BORDER_N:
++	case PART_BORDER_S:
++		ret_g->width = sidebar_g->width;
++		ret_g->height = bw;
++		break;
++	case PART_BORDER_E:
++	case PART_BORDER_W:
++		ret_g->width = bw;
++		ret_g->height = sidebar_g->height;
++		break;
++	case PART_BORDER_NW:
++	case PART_BORDER_NE:
++	case PART_BORDER_SW:
++	case PART_BORDER_SE:
++		ret_g->width = sidebar_g->x;
++		ret_g->height = sidebar_g->y;
++		break;
++	default:
++		return;
++	}
++
++	return;
++}
++
++int get_button_number(int context)
++{
++	int i;
++
++	for (i = 0; (C_L1 << i) & (C_LALL | C_RALL); i++)
++	{
++		if (context & (C_L1 << i))
++		{
++			return i;
++		}
++	}
++
++	return -1;
++}
++
++void border_draw_decorations(
++	FvwmWindow *fw, window_parts draw_parts, Bool has_focus, Bool do_force,
++	clear_window_parts clear_parts, rectangle *old_g, rectangle *new_g)
++{
++	common_decorations_type cd;
++	Bool do_redraw_titlebar = False;
++	window_parts pressed_parts;
++	window_parts force_parts;
++	int context;
++	int item;
++
++	if (fw == NULL)
++	{
++		return;
++	}
++	if (WAS_NEVER_DRAWN(fw))
++	{
++		/* force drawing everything */
++		do_force = True;
++		draw_parts = PART_ALL;
++		SET_WAS_NEVER_DRAWN(fw, 0);
++	}
++	memset(&cd, 0, sizeof(cd));
++
++	/* can't compare with True here, old code calls this with value "2" */
++	if (do_force != False)
++	{
++		force_parts = draw_parts;
++	}
++	else
++	{
++		force_parts = PART_NONE;
++	}
++	if (has_focus)
++	{
++		/* don't re-draw just for kicks */
++		if (Scr.Hilite != fw && Scr.Hilite != NULL)
++		{
++			FvwmWindow *t = Scr.Hilite;
++
++			Scr.Hilite = NULL;
++			/* make sure that the previously highlighted
++			 * window got unhighlighted */
++			border_draw_decorations(
++				t, PART_ALL, False, True, CLEAR_ALL, NULL,
++				NULL);
++		}
++		Scr.Hilite = fw;
++	}
++	else if (fw == Scr.Hilite)
++	{
++		Scr.Hilite = NULL;
++	}
++	if (fw->Desk != Scr.CurrentDesk)
++	{
++		return;
++	}
++	if (IS_ICONIFIED(fw))
++	{
++		DrawIconWindow(fw, True, True, True, False, NULL);
++		return;
++	}
++	/* calculate some values and flags */
++	if ((draw_parts & PART_TITLEBAR) && HAS_TITLE(fw))
++	{
++		do_redraw_titlebar = True;
++	}
++	get_common_decorations(
++		&cd, fw, draw_parts, has_focus, False, do_redraw_titlebar);
++	/* redraw */
++	context = frame_window_id_to_context(fw, PressedW, &item);
++	if ((context & (C_LALL | C_RALL)) == 0)
++	{
++		item = -1;
++	}
++	pressed_parts = border_context_to_parts(context);
++	if (new_g == NULL)
++	{
++		new_g = &fw->g.frame;
++	}
++	if (do_redraw_titlebar)
++	{
++		border_draw_titlebar(
++			&cd, fw, pressed_parts & PART_TITLEBAR, item,
++			force_parts & PART_TITLEBAR,
++			clear_parts, old_g, new_g, has_focus);
++	}
++	if (draw_parts & PART_FRAME)
++	{
++		Pixmap save_pix = cd.dynamic_cd.frame_pixmap;
++
++		memset(&cd, 0, sizeof(cd));
++		get_common_decorations(
++			&cd, fw, draw_parts, has_focus, True, True);
++		cd.dynamic_cd.frame_pixmap = save_pix;
++		border_draw_border_parts(
++			&cd, fw,
++			(pressed_parts & (PART_FRAME | PART_HANDLES)),
++			(force_parts & (PART_FRAME | PART_HANDLES)),
++			clear_parts, old_g, new_g, has_focus);
++	}
++	if (cd.dynamic_cd.frame_pixmap != None)
++	{
++		XFreePixmap(dpy, cd.dynamic_cd.frame_pixmap);
++	}
++	return;
++}
++
++void border_undraw_decorations(
++	FvwmWindow *fw)
++{
++	memset(&fw->decor_state, 0, sizeof(fw->decor_state));
++
++	return;
++}
++
++/*
++ *
++ *  redraw the decoration when style change
++ *
++ */
++void border_redraw_decorations(
++	FvwmWindow *fw)
++{
++	FvwmWindow *u = Scr.Hilite;
++
++	/* domivogt (6-Jun-2000): Don't check if the window is visible here.
++	 * If we do, some updates are not applied and when the window becomes
++	 * visible again, the X Server may not redraw the window. */
++	border_draw_decorations(
++		fw, PART_ALL, (Scr.Hilite == fw), True, CLEAR_ALL, NULL, NULL);
++	Scr.Hilite = u;
++
++	return;
++}
++
++/*
++ *
++ *  get the the root transparent parts of the decoration
++ *
++ */
++unsigned int border_get_transparent_decorations_part(FvwmWindow *fw)
++{
++	DecorFace *df,*tdf;
++	unsigned int draw_parts = PART_NONE;
++	int i;
++	window_parts pressed_parts;
++	int context;
++	int item;
++	border_titlebar_state tbstate;
++	Bool title_use_borderstyle = False;
++	Bool buttons_use_borderstyle = False;
++	Bool buttons_use_titlestyle = False;
++
++	context = frame_window_id_to_context(fw, PressedW, &item);
++	if ((context & (C_LALL | C_RALL)) == 0)
++	{
++		item = -1;
++	}
++	pressed_parts = border_context_to_parts(context);
++
++	memset(&tbstate, 0, sizeof(tbstate));
++	border_get_titlebar_descr_state(
++		fw, pressed_parts & PART_TITLEBAR, item,
++		CLEAR_ALL, (Scr.Hilite == fw), &tbstate);
++
++	for(i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		df = &TB_STATE(GetDecor(fw, buttons[i]))[tbstate.bstate[i]];
++
++		if (DFS_USE_TITLE_STYLE(df->style))
++		{
++			buttons_use_titlestyle = True;
++		}
++		if (DFS_USE_BORDER_STYLE(df->style))
++		{
++			buttons_use_borderstyle = True;
++		}
++		for(tdf = df; tdf != NULL; tdf = tdf->next)
++		{
++			if (DFS_FACE_TYPE(tdf->style) == ColorsetButton &&
++			    CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
++			{
++				draw_parts |= PART_BUTTONS;
++				break;
++			}
++		}
++	}
++
++	df = &TB_STATE(GetDecor(fw, titlebar))[tbstate.tstate];
++	if (DFS_USE_BORDER_STYLE(df->style))
++	{
++		title_use_borderstyle = True;
++	}
++	for(tdf = df; tdf != NULL; tdf = tdf->next)
++	{
++		if (DFS_FACE_TYPE(tdf->style) == ColorsetButton &&
++		    CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
++		{
++			draw_parts |= PART_TITLE;
++			break;
++		}
++		else if (DFS_FACE_TYPE(tdf->style) == MultiPixmap)
++		{
++			int i;
++
++			for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
++			{
++				if (CSET_IS_TRANSPARENT_ROOT(
++					tdf->u.mp.acs[i].cs))
++				{
++					draw_parts |= PART_TITLE;
++					break;
++				}
++			}
++		}
++	}
++
++	df = border_get_border_style(fw, (Scr.Hilite == fw));
++	if (DFS_FACE_TYPE(df->style) == ColorsetButton &&
++	    CSET_IS_TRANSPARENT_ROOT(df->u.acs.cs))
++	{
++		draw_parts |= PART_FRAME|PART_HANDLES;
++	}
++	if (draw_parts & PART_FRAME)
++	{
++		if (title_use_borderstyle)
++		{
++			draw_parts |= PART_TITLE;
++		}
++		if (buttons_use_borderstyle)
++		{
++			draw_parts |= PART_BUTTONS;
++		}
++	}
++	if ((draw_parts & PART_TITLE) && buttons_use_titlestyle)
++	{
++		draw_parts |= PART_BUTTONS;
++	}
++#if 0
++	fprintf(stderr,"Transparant Part: %u\n", draw_parts);
++#endif
++	return draw_parts;
++}
++
++/* ---------------------------- builtin commands --------------------------- */
++
++/*
++ *
++ *  Sets the allowed button states
++ *
++ */
++void CMD_ButtonState(F_CMD_ARGS)
++{
++	char *token;
++
++	while ((token = PeekToken(action, &action)))
++	{
++		static char first = True;
++		if (!token && first)
++		{
++			Scr.gs.use_active_down_buttons =
++				DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
++			Scr.gs.use_inactive_buttons =
++				DEFAULT_USE_INACTIVE_BUTTONS;
++			Scr.gs.use_inactive_down_buttons =
++				DEFAULT_USE_INACTIVE_DOWN_BUTTONS;
++			return;
++		}
++		first = False;
++		if (StrEquals("activedown", token))
++		{
++			Scr.gs.use_active_down_buttons = ParseToggleArgument(
++				action, &action,
++				DEFAULT_USE_ACTIVE_DOWN_BUTTONS, True);
++		}
++		else if (StrEquals("inactive", token))
++		{
++			Scr.gs.use_inactive_buttons = ParseToggleArgument(
++				action, &action,
++				DEFAULT_USE_INACTIVE_BUTTONS, True);
++		}
++		else if (StrEquals("inactivedown", token))
++		{
++			Scr.gs.use_inactive_down_buttons = ParseToggleArgument(
++				action, &action,
++				DEFAULT_USE_INACTIVE_DOWN_BUTTONS, True);
++		}
++		else
++		{
++			Scr.gs.use_active_down_buttons =
++				DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
++			Scr.gs.use_inactive_buttons =
++				DEFAULT_USE_INACTIVE_BUTTONS;
++			Scr.gs.use_inactive_down_buttons =
++				DEFAULT_USE_INACTIVE_DOWN_BUTTONS;
++			fvwm_msg(ERR, "cmd_button_state",
++				 "Unknown button state %s", token);
++			return;
++		}
++	}
++
++	return;
++}
++
++/*
++ *
++ *  Sets the border style (veliaa at rpi.edu)
++ *
++ */
++void CMD_BorderStyle(F_CMD_ARGS)
++{
++	char *parm;
++	char *prev;
++#ifdef USEDECOR
++	FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
++#else
++	FvwmDecor *decor = &Scr.DefaultDecor;
++#endif
++
++	Scr.flags.do_need_window_update = 1;
++	decor->flags.has_changed = 1;
++	for (prev = action; (parm = PeekToken(action, &action)); prev = action)
++	{
++		if (StrEquals(parm, "active") || StrEquals(parm, "inactive"))
++		{
++			int len;
++			char *end, *tmp;
++			DecorFace tmpdf, *df;
++
++			memset(&tmpdf.style, 0, sizeof(tmpdf.style));
++			DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
++			tmpdf.next = NULL;
++			if (FMiniIconsSupported)
++			{
++				tmpdf.u.p = NULL;
++			}
++			if (StrEquals(parm,"active"))
++			{
++				df = &decor->BorderStyle.active;
++			}
++			else
++			{
++				df = &decor->BorderStyle.inactive;
++			}
++			df->flags.has_changed = 1;
++			while (isspace(*action))
++			{
++				++action;
++			}
++			if (*action != '(')
++			{
++				if (!*action)
++				{
++					fvwm_msg(
++						ERR, "SetBorderStyle",
++						"error in %s border"
++						" specification", parm);
++					return;
++				}
++				while (isspace(*action))
++				{
++					++action;
++				}
++				if (ReadDecorFace(action, &tmpdf,-1,True))
++				{
++					FreeDecorFace(dpy, df);
++					*df = tmpdf;
++				}
++				break;
++			}
++			end = strchr(++action, ')');
++			if (!end)
++			{
++				fvwm_msg(
++					ERR, "SetBorderStyle",
++					"error in %s border specification",
++					parm);
++				return;
++			}
++			len = end - action + 1;
++			tmp = safemalloc(len);
++			strncpy(tmp, action, len - 1);
++			tmp[len - 1] = 0;
++			ReadDecorFace(tmp, df,-1,True);
++			free(tmp);
++			action = end + 1;
++		}
++		else if (strcmp(parm,"--")==0)
++		{
++			if (ReadDecorFace(
++				    prev, &decor->BorderStyle.active,-1,True))
++			{
++				ReadDecorFace(
++					prev, &decor->BorderStyle.inactive, -1,
++					False);
++			}
++			decor->BorderStyle.active.flags.has_changed = 1;
++			decor->BorderStyle.inactive.flags.has_changed = 1;
++			break;
++		}
++		else
++		{
++			DecorFace tmpdf;
++			memset(&tmpdf.style, 0, sizeof(tmpdf.style));
++			DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
++			tmpdf.next = NULL;
++			if (FMiniIconsSupported)
++			{
++				tmpdf.u.p = NULL;
++			}
++			if (ReadDecorFace(prev, &tmpdf,-1,True))
++			{
++				FreeDecorFace(dpy,&decor->BorderStyle.active);
++				decor->BorderStyle.active = tmpdf;
++				ReadDecorFace(
++					prev, &decor->BorderStyle.inactive, -1,
++					False);
++				decor->BorderStyle.active.flags.has_changed = 1;
++				decor->BorderStyle.inactive.flags.has_changed =
++					1;
++			}
++			break;
++		}
++	}
++
++	return;
++}
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/borders.h fvwm-2.5.21-05/fvwm/borders.h
+--- fvwm-2.5.21-04/fvwm/borders.h	2007-03-03 13:18:21.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/borders.h	2007-03-03 13:18:49.000000000 +0100
+@@ -29,21 +29,26 @@ typedef enum
+ 	PART_TITLE     = 0x100,
+ 	PART_BUTTONS   = 0x200,
+ 	PART_X_HANDLES = 0x400,
+ 	PART_Y_HANDLES = 0x800,
+ 	/* combinations of the above values */
+ 	PART_SIDES     = 0x0f,
+ 	PART_CORNERS   = 0xf0,
+ 	PART_FRAME     = 0xff,
+ 	PART_TITLEBAR  = 0x300,
+ 	PART_HANDLES   = 0xc00,
+-	PART_ALL       = 0xfff
++	PART_ALL       = 0xfff,
++
++	PART_TOP       = 0x31,
++	PART_BOTTOM    = 0xc2,
++	PART_LEFT      = 0x58,
++	PART_RIGHT     = 0xa4
+ } window_parts;
+ 
+ typedef enum
+ {
+ 	CLEAR_NONE     = 0x0,
+ 	CLEAR_FRAME    = 0x1,
+ 	CLEAR_TITLE    = 0x2,
+ 	CLEAR_BUTTONS  = 0x4,
+ 	CLEAR_ALL      = 0x7
+ } clear_window_parts;
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/fvwm.h fvwm-2.5.21-05/fvwm/fvwm.h
+--- fvwm-2.5.21-04/fvwm/fvwm.h	2007-03-03 13:18:21.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/fvwm.h	2007-03-03 13:18:49.000000000 +0100
+@@ -262,20 +262,21 @@ typedef struct
+ 		unsigned is_top_title_rotated : 1;
+ 		unsigned use_icon_position_hint : 1;
+ 		unsigned use_indexed_window_name : 1;
+ 		unsigned use_indexed_icon_name : 1;
+ #define WINDOWSHADE_LAZY          0
+ #define WINDOWSHADE_ALWAYS_LAZY   1
+ #define WINDOWSHADE_BUSY          2
+ #define WINDOWSHADE_LAZY_MASK   0x3
+ 		unsigned windowshade_laziness : 2;
+ 		unsigned use_title_decor_rotation : 1;
++		unsigned has_border_under_title : 1;
+ 		focus_policy_t focus_policy;
+ 	} s;
+ } common_flags_t;
+ 
+ typedef struct
+ {
+ 	common_flags_t common;
+ #define CR_MOTION_METHOD_AUTO        0
+ #define CR_MOTION_METHOD_USE_GRAV    1
+ #define CR_MOTION_METHOD_STATIC_GRAV 2
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/fvwm.h~ fvwm-2.5.21-05/fvwm/fvwm.h~
+--- fvwm-2.5.21-04/fvwm/fvwm.h~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/fvwm.h~	2007-03-03 13:18:42.000000000 +0100
+@@ -0,0 +1,909 @@
++/* -*-c-*- */
++/* This module is based on Twm, but has been siginificantly modified
++ * by Rob Nation */
++/*
++ *       Copyright 1988 by Evans & Sutherland Computer Corporation,
++ *                          Salt Lake City, Utah
++ *  Portions Copyright 1989 by the Massachusetts Institute of Technology
++ *                        Cambridge, Massachusetts
++ *
++ *                           All Rights Reserved
++ *
++ *    Permission to use, copy, modify, and distribute this software and
++ *    its documentation  for  any  purpose  and  without  fee is hereby
++ *    granted, provided that the above copyright notice appear  in  all
++ *    copies and that both  that  copyright  notice  and  this  permis-
++ *    sion  notice appear in supporting  documentation,  and  that  the
++ *    names of Evans & Sutherland and M.I.T. not be used in advertising
++ *    in publicity pertaining to distribution of the  software  without
++ *    specific, written prior permission.
++ *
++ *    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD
++ *    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-
++ *    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR
++ *    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-
++ *    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA
++ *    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ *    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE
++ *    OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef FVWM_H
++#define FVWM_H
++
++/* ---------------------------- included header files ---------------------- */
++
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++#include <X11/cursorfont.h>
++#include <X11/Intrinsic.h>
++#include "libs/PictureBase.h"
++#include "libs/Flocale.h"
++#include "window_flags.h"
++#include "condrc.h"
++
++/* ---------------------------- global definitions ------------------------- */
++
++#ifndef WithdrawnState
++#define WithdrawnState 0
++#endif
++
++/* ---------------------------- global macros ------------------------------ */
++
++/*
++ * Fvwm trivia: There were 97 commands in the fvwm command table
++ * when the F_CMD_ARGS macro was written.
++ * dje 12/19/98.
++ */
++
++/* Macro for args passed to fvwm commands... */
++#define F_CMD_ARGS \
++	cond_rc_t *cond_rc, const exec_context_t *exc, char *action
++#define F_PASS_ARGS cond_rc, exc, action
++#define FUNC_FLAGS_TYPE unsigned char
++
++/* access macros */
++#define FW_W_FRAME(fw)        ((fw)->wins.frame)
++#define FW_W_PARENT(fw)       ((fw)->wins.parent)
++#define FW_W_CLIENT(fw)       ((fw)->wins.client)
++#define FW_W(fw)              FW_W_CLIENT(fw)
++#define FW_W_TITLE(fw)        ((fw)->wins.title)
++#define FW_W_BUTTON(fw,i)     ((fw)->wins.button_w[(i)])
++#define FW_W_SIDE(fw,i)       ((fw)->wins.sides[(i)])
++#define FW_W_CORNER(fw,i)     ((fw)->wins.corners[(i)])
++#define FW_W_ICON_TITLE(fw)   ((fw)->wins.icon_title_w)
++#define FW_W_ICON_PIXMAP(fw)  ((fw)->wins.icon_pixmap_w)
++#define FW_W_TRANSIENTFOR(fw) ((fw)->wins.transientfor)
++
++/* ---------------------------- forward declarations ----------------------- */
++
++struct exec_context_t;
++
++#ifdef USEDECOR
++/* definition in screen.h */
++struct FvwmDecor;
++#endif
++
++/* ---------------------------- type definitions --------------------------- */
++
++/* This structure carries information about the initial window state and
++ * placement.  This information is gathered at various places: the (re)capture
++ * code, AddToWindow(), HandleMapRequestRaised(), ewmh_events.c and others.
++ *
++ * initial_state
++ *   The initial window state.  By default it carries the value DontCareState.
++ *   Other states can be set if
++ *    - an icon is recaptured or restarted with session management
++ *    - the StartIconic style is set
++ *    - GNOME, EWMH, foobar hints demand that the icon starts iconic
++ *   The final value is calculated in HandleMapRequestRaised().
++ *
++ * do_override_ppos
++ *   This flag is used in PlaceWindow().  If it is set, the position requested
++ *   by the program is ignored unconditionally.  This is used during the
++ *   initial capture and later recapture operations.
++ *
++ * is_iconified_by_parent
++ *   Preserves the information if the window is a transient window that was
++ *   iconified along with its transientfor window.  Set when the window is
++ *   recaptured and used in HandleMapRequestRaised() to set the according
++ *   window state flag.  Deleted afterwards.
++ *
++ * is_menu
++ *   Set in menus.c or in the recapture code if the new window is a tear off
++ *   menu.  Such windows get special treatment in AddWindow() and events.c.
++ *
++ * is_recapture
++ *   Set for the initial capture and later recaptures.
++ *
++ * default_icon_x/y
++ *   The icon position that was requested by the application in the icon
++ *   position hint.  May be overridden by a style (0/0 then).  Set in
++ *   HandleMapRequestRaised() and used in the icon placement code.
++ *
++ * initial_icon_x/y
++ *   The icon position that is forced during a restart with SM.  If set it
++ *   overrides all other methods of icon placement.  Set by session.c and used
++ *   in the icon placement code.
++ *
++ * use_initial_icon_xy
++ *   If set, the initial_icon_x/y values are used.  Other wise they are
++ *   ignored.
++ */
++typedef struct
++{
++	long initial_state;
++	struct
++	{
++		unsigned do_override_ppos : 1;
++		unsigned is_iconified_by_parent : 1;
++		unsigned is_menu : 1;
++		unsigned is_recapture : 1;
++		unsigned use_initial_icon_xy : 1;
++	} flags;
++	int initial_icon_x;
++	int initial_icon_y;
++	int default_icon_x;
++	int default_icon_y;
++} initial_window_options_t;
++
++/*
++  For 1 style statement, there can be any number of IconBoxes.
++  The name list points at the first one in the chain.
++*/
++typedef struct icon_boxes_struct
++{
++	struct icon_boxes_struct *next;       /* next icon_boxes or zero */
++	unsigned int use_count;
++	int IconBox[4];                       /* x/y x/y for iconbox */
++	int IconScreen;                       /* Xinerama screen */
++	short IconGrid[2];                    /* x incr, y incr */
++	char IconSign[4];                     /* because of -0, need to save */
++	unsigned is_orphan : 1;
++	unsigned IconFlags : 3;               /* some bits */
++	/* IconFill only takes 3 bits.  Defaults are top, left, vert co-ord
++	 * first eg: t l = 0,0,0; l t = 0,0,1; b r = 1,1,0 */
++#define ICONFILLBOT (1<<0)
++#define ICONFILLRGT (1<<1)
++#define ICONFILLHRZ (1<<2)
++} icon_boxes;
++
++typedef struct
++{
++	Pixel fore;
++	Pixel back;
++} ColorPair;
++
++typedef struct
++{
++	Pixel fore;
++	Pixel back;
++	Pixel hilight;
++	Pixel shadow;
++} color_quad;
++
++typedef struct
++{
++	int left;
++	int right;
++	int top;
++	int bottom;
++} ewmh_strut;
++
++typedef struct
++{
++	/* common flags (former flags in bits 0-12) */
++	unsigned is_sticky_across_pages : 1;
++	unsigned is_sticky_across_desks : 1;
++	unsigned has_icon_font : 1;
++	unsigned has_no_border : 1;
++	unsigned has_window_font : 1;
++	unsigned title_dir : 2;
++	unsigned user_states : 32;
++	/* static flags that do not change dynamically after the window has
++	 * been created */
++	struct
++	{
++		unsigned do_circulate_skip : 1;
++		unsigned do_circulate_skip_icon : 1;
++		unsigned do_circulate_skip_shaded : 1;
++		unsigned do_ewmh_donate_icon : 1;
++		unsigned do_ewmh_donate_mini_icon : 1;
++		unsigned do_ewmh_ignore_state_hints : 1;
++		unsigned do_ewmh_ignore_strut_hints : 1;
++		unsigned do_ewmh_mini_icon_override : 1;
++		unsigned do_ewmh_use_stacking_hints : 1;
++		unsigned do_ewmh_ignore_window_type : 1;
++		unsigned do_iconify_window_groups : 1;
++		unsigned do_ignore_gnome_hints : 1;
++		unsigned do_ignore_icon_boxes : 1;
++		unsigned do_ignore_restack : 1;
++		unsigned do_use_window_group_hint : 1;
++		unsigned do_lower_transient : 1;
++		unsigned do_not_show_on_map : 1;
++		unsigned do_raise_transient : 1;
++		unsigned do_resize_opaque : 1;
++		unsigned do_resize_outline_thin : 1;
++		unsigned do_shrink_windowshade : 1;
++		unsigned do_stack_transient_parent : 1;
++		unsigned do_window_list_skip : 1;
++		unsigned ewmh_maximize_mode : 2; /* see ewmh.h */
++		unsigned has_depressable_border : 1;
++		unsigned has_mwm_border : 1;
++		unsigned has_mwm_buttons : 1;
++		unsigned has_mwm_override : 1;
++		unsigned has_no_icon_title : 1;
++		unsigned has_override_size : 1;
++		unsigned has_stippled_title : 1;
++		unsigned has_stippled_icon_title : 1;
++		/* default has to be 0, therefore no_, not in macros */
++		unsigned has_no_sticky_stippled_title : 1;
++		unsigned has_no_sticky_stippled_icon_title : 1;
++		unsigned icon_override : 2;
++#define NO_ACTIVE_ICON_OVERRIDE 0
++#define ICON_OVERRIDE           1
++#define NO_ICON_OVERRIDE        2
++#define ICON_OVERRIDE_MASK    0x3
++		unsigned is_bottom_title_rotated : 1;
++		unsigned is_fixed : 1;
++		unsigned is_fixed_ppos : 1;
++		unsigned is_uniconifiable : 1;
++		unsigned is_unmaximizable : 1;
++		unsigned is_unclosable : 1;
++		unsigned is_maximize_fixed_size_disallowed : 1;
++		unsigned is_icon_sticky_across_pages : 1;
++		unsigned is_icon_sticky_across_desks : 1;
++		unsigned is_icon_suppressed : 1;
++		unsigned is_left_title_rotated_cw : 1; /* cw = clock wise */
++		unsigned is_lenient : 1;
++		unsigned is_size_fixed : 1;
++		unsigned is_psize_fixed : 1;
++		unsigned is_right_title_rotated_cw : 1;
++		unsigned is_top_title_rotated : 1;
++		unsigned use_icon_position_hint : 1;
++		unsigned use_indexed_window_name : 1;
++		unsigned use_indexed_icon_name : 1;
++#define WINDOWSHADE_LAZY          0
++#define WINDOWSHADE_ALWAYS_LAZY   1
++#define WINDOWSHADE_BUSY          2
++#define WINDOWSHADE_LAZY_MASK   0x3
++		unsigned windowshade_laziness : 2;
++		unsigned use_title_decor_rotation : 1;
++		focus_policy_t focus_policy;
++	} s;
++} common_flags_t;
++
++typedef struct
++{
++	common_flags_t common;
++#define CR_MOTION_METHOD_AUTO        0
++#define CR_MOTION_METHOD_USE_GRAV    1
++#define CR_MOTION_METHOD_STATIC_GRAV 2
++#define CR_MOTION_METHOD_MASK      0x3
++	unsigned cr_motion_method : 2;
++	unsigned was_cr_motion_method_detected : 1;
++	unsigned does_wm_delete_window : 1;
++	unsigned does_wm_take_focus : 1;
++	unsigned do_force_next_cr : 1;
++	unsigned do_force_next_pn : 1;
++	unsigned do_iconify_after_map : 1;
++	unsigned do_disable_constrain_size_fullscreen : 1;
++	/* Reuse this struct, don't free it, when destroying/recapturing
++	 * window. */
++	unsigned do_reuse_destroyed : 1;
++	/* Does it have resize handles? */
++	unsigned has_handles : 1;
++	/* Icon change is pending */
++	unsigned has_icon_changed : 1;
++	/* Is this decorated with title */
++	unsigned has_title : 1;
++	/* wm_normal_hints update is pending? */
++	unsigned has_new_wm_normal_hints : 1;
++	/* ChangeDecor was used for window */
++	unsigned is_decor_changed : 1;
++	/* Sent an XUnmapWindow for iconifying, but didn't receive an
++	 * UnmapNotify yet.*/
++	unsigned is_iconify_pending : 1;
++	/* window had the focus when the desk was switched. set if the window
++	 * was mapped and got focused but the focus change was not announced
++	 * to the modules yet. */
++	unsigned is_focused_on_other_desk : 1;
++	unsigned is_focus_change_broadcast_pending : 1;
++	/* is the window fully visible */
++	unsigned is_fully_visible : 1;
++	/* is it an icon now? */
++	unsigned is_iconified : 1;
++	/* To prevent iconified transients in a parent icon from counting for
++	 * Next */
++	unsigned is_iconified_by_parent : 1;
++	/* is the pointer over the icon? */
++	unsigned is_icon_entered : 1;
++	unsigned is_icon_font_loaded : 1;
++	/* has the icon been moved by the user? */
++	unsigned is_icon_moved : 1;
++	/* is the icon window supplied by the app? */
++	unsigned is_icon_ours : 1;
++	/* is the icon shaped? */
++	unsigned is_icon_shaped : 1;
++	/* was the icon unmapped, even though the window is still iconified
++	 * (Transients) */
++	unsigned is_icon_unmapped : 1;
++	/* temporary flag used in stack.c */
++	unsigned is_in_transient_subtree : 1;
++	/* is it mapped? */
++	unsigned is_mapped : 1;
++	/* Sent an XMapWindow, but didn't receive a MapNotify yet.*/
++	unsigned is_map_pending : 1;
++	/* is the window maximized? */
++	unsigned is_maximized : 1;
++	/* Set if the client changes its WM_NAME. The source of twm contains
++	 * an explanation why we need this information. */
++	unsigned is_name_changed : 1;
++	/* is the window partially visible */
++	unsigned is_partially_visible : 1;
++	/* is the icon pixmap ours to free? */
++	unsigned is_pixmap_ours : 1;
++	/* fvwm places the window itself */
++	unsigned is_placed_by_fvwm : 1;
++	/* mark window to be destroyed after last complex func has finished. */
++	unsigned is_scheduled_for_destroy : 1;
++	/* mark window to be raised after function execution. */
++	unsigned is_scheduled_for_raise : 1;
++	unsigned is_size_inc_set : 1;
++	unsigned is_style_deleted : 1;
++	/* the window is a torn out fvwm menu */
++	unsigned is_tear_off_menu : 1;
++	/* is it a transient window? */
++	unsigned is_transient : 1;
++	unsigned is_window_drawn_once : 1;
++	/* To prevent double move in MoveViewport.*/
++	unsigned is_viewport_moved : 1;
++	unsigned is_window_being_moved_opaque : 1;
++	unsigned is_window_font_loaded : 1;
++	unsigned is_window_shaded : 1;
++	unsigned used_title_dir_for_shading : 1;
++	unsigned shaded_dir : 3;
++	unsigned using_default_icon_font : 1;
++	unsigned using_default_window_font : 1;
++#define ICON_HINT_NEVER    0
++#define ICON_HINT_ONCE     1
++#define ICON_HINT_MULTIPLE 2
++	unsigned was_icon_hint_provided : 2;
++	unsigned was_icon_name_provided : 1;
++	unsigned was_never_drawn : 1;
++	unsigned has_ewmh_wm_name : 1;
++	unsigned has_ewmh_wm_icon_name : 1;
++#define EWMH_NO_ICON     0 /* the application does not provide an ewmh icon */
++#define EWMH_TRUE_ICON   1 /* the application does provide an ewmh icon */
++#define EWMH_FVWM_ICON   2 /* the ewmh icon has been set by fvwm */
++	unsigned has_ewmh_wm_icon_hint : 2;
++	/* says if the app have an ewmh icon of acceptable size for a mini
++	 * icon in its list of icons */
++	unsigned has_ewmh_mini_icon : 1;
++	unsigned has_ewmh_wm_pid : 1;
++	/* the ewmh icon is used as icon pixmap */
++	unsigned use_ewmh_icon : 1;
++	unsigned is_ewmh_modal : 1;
++	unsigned is_ewmh_fullscreen : 1;
++#define EWMH_STATE_UNDEFINED_HINT 0
++#define EWMH_STATE_NO_HINT        1
++#define EWMH_STATE_HAS_HINT       2
++	unsigned has_ewmh_init_fullscreen_state : 2;
++	unsigned has_ewmh_init_hidden_state : 2;
++	unsigned has_ewmh_init_maxhoriz_state : 2;
++	unsigned has_ewmh_init_maxvert_state : 2;
++	unsigned has_ewmh_init_modal_state : 2;
++	unsigned has_ewmh_init_shaded_state : 2;
++	unsigned has_ewmh_init_skip_pager_state : 2;
++	unsigned has_ewmh_init_skip_taskbar_state : 2;
++	unsigned has_ewmh_init_sticky_state : 2;
++	unsigned has_ewmh_init_wm_desktop : 2;
++} window_flags;
++
++
++/* Actions allowed by modules. */
++typedef struct action_flags
++{
++	unsigned is_movable : 1;
++	unsigned is_deletable : 1;
++	unsigned is_destroyable : 1;
++	unsigned is_closable : 1;
++	unsigned is_maximizable : 1;
++	unsigned is_resizable : 1;
++	unsigned is_iconifiable : 1;
++} action_flags;
++
++
++/* Window name data structure for window conditions: a list of lists
++   of names to match, the boolean operation on the matches being an
++   AND of ORs. */
++struct namelist			/* matches to names in this list are ORed */
++{
++	char *name;
++	struct namelist *next;
++};
++
++struct name_condition		/* matches to namelists in this list are
++				   ANDed, after possibly inverting each */
++{
++	Bool invert;
++	struct namelist *namelist;
++	struct name_condition *next;
++};
++
++/* Window mask for Circulate and Direction functions */
++typedef struct WindowConditionMask
++{
++	struct
++	{
++		unsigned do_accept_focus : 1;
++		unsigned do_check_desk : 1;
++		unsigned do_check_desk_and_global_page : 1;
++		unsigned do_check_desk_and_page : 1;
++		unsigned do_check_global_page : 1;
++		unsigned do_check_overlapped : 1;
++		unsigned do_check_page : 1;
++		unsigned do_not_check_screen : 1;
++		unsigned needs_current_desk : 1;
++		unsigned needs_current_desk_and_global_page : 1;
++		unsigned needs_current_desk_and_page : 1;
++		unsigned needs_current_global_page : 1;
++		unsigned needs_current_page : 1;
++#define NEEDS_ANY   0
++#define NEEDS_TRUE  1
++#define NEEDS_FALSE 2
++		unsigned needs_focus : 2;
++		unsigned needs_overlapped : 2;
++		unsigned needs_pointer : 2;
++		unsigned needs_same_layer : 1;
++		unsigned use_circulate_hit : 1;
++		unsigned use_circulate_hit_icon : 1;
++		unsigned use_circulate_hit_shaded : 1;
++		unsigned use_do_accept_focus : 1;
++	} my_flags;
++	window_flags flags;
++	window_flags flag_mask;
++	struct name_condition *name_condition;
++	int layer;
++	int placed_by_button_mask;
++	int placed_by_button_set_mask;
++} WindowConditionMask;
++
++/* only style.c and add_window.c are allowed to access this struct! */
++typedef struct
++{
++	common_flags_t common;
++	unsigned do_decorate_transient : 1;
++	/* old placement flags */
++#define PLACE_DUMB            0x0
++#define PLACE_SMART           0x1
++#define PLACE_CLEVER          0x2
++#define PLACE_CLEVERNESS_MASK 0x3
++#define PLACE_RANDOM          0x4
++	/* new placements value, try to get a minimal backward compatibility
++	 * with the old flags:
++	 * Dumb+Active = Manual,
++	 * Dumb+Random = Cascade,
++	 * Smart+Random = TileCascade,
++	 * Smart+Active = TileManual,
++	 * Random+Smart+Clever = MINOVERLAP which is the original Clever
++	 * placement code,
++	 * Active+Smart+Clever = MINOVERLAPPERCENT which is the "new" Clever
++	 * placement code and was the original Clever placement code. Now the
++	 * original placement code said:
++	 * Active/Random+Dumb+Clever = Active/Random+Dumb (with Dumb Clever is
++	 * ignored); These represent the not use value: 0x2=Active+Dumb+Clever,
++	 * 0x6=Random+Dumb+Clever */
++#define PLACE_MANUAL            0x0
++#define PLACE_TILEMANUAL        0x1
++#define PLACE_MANUAL_B          0x2
++#define PLACE_MINOVERLAPPERCENT 0x3
++#define PLACE_CASCADE           0x4
++#define PLACE_TILECASCADE       0x5
++#define PLACE_CASCADE_B         0x6
++#define PLACE_MINOVERLAP        0x7
++#define PLACE_CENTER            0x8
++#define PLACE_UNDERMOUSE        0x9
++#define PLACE_MASK              0xF
++	unsigned placement_mode : 4;
++	unsigned ewmh_placement_mode : 2; /* see ewmh.h */
++#define WS_CR_MOTION_METHOD_AUTO CR_MOTION_METHOD_AUTO
++#define WS_CR_MOTION_METHOD_USE_GRAV CR_MOTION_METHOD_USE_GRAV
++#define WS_CR_MOTION_METHOD_STATIC_GRAV CR_MOTION_METHOD_STATIC_GRAV
++#define WS_CR_MOTION_METHOD_MASK CR_MOTION_METHOD_MASK
++	unsigned ws_cr_motion_method : 2;
++	unsigned do_save_under : 1;
++	unsigned do_start_iconic : 1;
++	unsigned do_start_lowered : 1;
++	unsigned has_border_width : 1;
++	unsigned has_color_back : 1;
++	unsigned has_color_fore : 1;
++	unsigned has_color_back_hi : 1;
++	unsigned has_color_fore_hi : 1;
++	unsigned has_decor : 1;
++	unsigned has_handle_width : 1;
++	unsigned has_icon : 1;
++	unsigned has_icon_boxes : 1;
++	unsigned has_icon_size_limits : 1;
++	unsigned has_max_window_size : 1;
++	unsigned has_icon_background_padding : 1;
++	unsigned has_icon_background_relief : 1;
++	unsigned has_icon_title_relief : 1;
++	unsigned has_window_shade_steps : 1;
++	unsigned has_mini_icon : 1;
++	unsigned has_mwm_decor : 1;
++	unsigned has_mwm_functions : 1;
++	unsigned has_no_handles : 1;
++	unsigned has_no_title : 1;
++	unsigned has_ol_decor : 1;
++#if 0
++	unsigned has_condition_mask : 1;
++#endif
++	unsigned is_button_disabled : NUMBER_OF_TITLE_BUTTONS;
++	unsigned is_unmanaged : 1;
++#define BACKINGSTORE_DEFAULT 0
++#define BACKINGSTORE_ON      1
++#define BACKINGSTORE_OFF     2
++#define BACKINGSTORE_MASK  0x3
++	unsigned use_backing_store : 2;
++	unsigned use_parent_relative : 1;
++	unsigned use_colorset : 1;
++	unsigned use_colorset_hi : 1;
++	unsigned use_border_colorset : 1;
++	unsigned use_border_colorset_hi : 1;
++	unsigned use_icon_title_colorset : 1;
++	unsigned use_icon_title_colorset_hi : 1;
++	unsigned use_icon_background_colorset : 1;
++	unsigned use_layer : 1;
++	unsigned use_no_pposition : 1;
++	unsigned use_no_usposition : 1;
++	unsigned use_no_transient_pposition : 1;
++	unsigned use_no_transient_usposition : 1;
++	unsigned use_start_on_desk : 1;
++	unsigned use_start_on_page_for_transient : 1;
++	unsigned use_start_on_screen : 1;
++	unsigned manual_placement_honors_starts_on_page : 1;
++	unsigned capture_honors_starts_on_page : 1;
++	unsigned recapture_honors_starts_on_page : 1;
++	unsigned has_placement_penalty : 1;
++	unsigned has_placement_percentage_penalty : 1;
++} style_flags;
++
++typedef struct
++{
++	char *name;
++	XID window_id;
++	struct
++	{
++		unsigned has_name:1;
++		unsigned has_window_id:1;
++	} flags;
++} style_id_t;
++
++
++/* only style.c and add_window.c are allowed to access this struct! */
++typedef struct window_style
++{
++	struct window_style *next;
++	struct window_style *prev;
++	style_id_t id;
++#if 0
++	WindowConditionMask *condition_mask;
++#endif
++	char *icon_name;
++	char *mini_icon_name;
++#ifdef USEDECOR
++	char *decor_name;
++#endif
++	unsigned char min_icon_width;
++	unsigned char max_icon_width;
++	unsigned char min_icon_height;
++	unsigned char max_icon_height;
++#define ICON_RESIZE_TYPE_NONE      0x0
++#define ICON_RESIZE_TYPE_STRETCHED 0x1
++#define ICON_RESIZE_TYPE_ADJUSTED  0x2
++#define ICON_RESIZE_TYPE_SHRUNK    0x3
++#define ICON_RESIZE_TYPE_MASK      0x3
++	unsigned icon_resize_type : 2;
++	unsigned char icon_background_padding;
++	signed char icon_background_relief;
++	signed char icon_title_relief;
++	char *icon_font;
++	char *window_font;
++	char *fore_color_name;
++	char *back_color_name;
++	char *fore_color_name_hi;
++	char *back_color_name_hi;
++	int colorset;
++	int colorset_hi;
++	int border_colorset;
++	int border_colorset_hi;
++	int icon_title_colorset;
++	int icon_title_colorset_hi;
++	int icon_background_colorset;
++	short border_width;
++	/* resize handle width */
++	short handle_width;
++	int layer;
++	int start_desk;
++	int start_page_x;
++	int start_page_y;
++	int start_screen;
++	int max_window_width;
++	int max_window_height;
++	int shade_anim_steps;
++	icon_boxes *icon_boxes;
++	float norm_placement_penalty;
++	float placement_penalty[6];
++	int placement_percentage_penalty[4];
++	style_flags flags;
++	style_flags flag_default;
++	style_flags flag_mask;
++	style_flags change_mask;
++	unsigned has_style_changed : 1;
++} window_style;
++
++typedef struct window_g
++{
++	rectangle frame;
++	/* absolute geometry when not maximized */
++	rectangle normal;
++	/* maximized window geometry */
++	rectangle max;
++	/* defect between maximized geometry before and after
++	 * constraining size. */
++	size_rect max_defect;
++	/* original delta between normalized and maximized window,
++	 * used to keep unmaximized window at same screen position */
++	position max_offset;
++} window_g;
++
++/* for each window that is on the display, one of these structures
++ * is allocated and linked into a list
++ */
++typedef struct FvwmWindow
++{
++	/* name of the window */
++	FlocaleNameString name;
++	/* name of the icon */
++	FlocaleNameString icon_name;
++	char *visible_name;
++	char *visible_icon_name;
++	/* if non-null: Use this instead of any other names for matching
++	   styles */
++	char *style_name;
++	int name_count;
++	int icon_name_count;
++	/* next fvwm window */
++	struct FvwmWindow *next;
++	/* prev fvwm window */
++	struct FvwmWindow *prev;
++	/* next (lower) fvwm window in stacking order*/
++	struct FvwmWindow *stack_next;
++	/* prev (higher) fvwm window in stacking order */
++	struct FvwmWindow *stack_prev;
++	/* border width before reparenting */
++	struct
++	{
++		/* the frame window */
++		Window frame;
++		/* It looks like you HAVE to reparent the app window into a
++		 * window whose size = app window, or else you can't keep xv
++		 * and matlab happy at the same time! */
++		Window parent;
++		/* the child window */
++		Window client;
++		/* the title bar window and button windows */
++		Window title;
++		Window button_w[NUMBER_OF_TITLE_BUTTONS];
++		/* sides of the border */
++		Window sides[4];
++		/* corner pieces */
++		Window corners[4];
++		/* icon title window */
++		Window icon_title_w;
++		/* icon picture window */
++		Window icon_pixmap_w;
++		Window transientfor;
++	} wins;
++	window_flags flags;
++	struct
++	{
++		unsigned buttons_drawn : NUMBER_OF_TITLE_BUTTONS;
++		unsigned buttons_lit : NUMBER_OF_TITLE_BUTTONS;
++		unsigned buttons_inverted : NUMBER_OF_TITLE_BUTTONS;
++		unsigned buttons_toggled : NUMBER_OF_TITLE_BUTTONS;
++		unsigned parts_drawn : 12;
++		unsigned parts_lit : 12;
++		unsigned parts_inverted : 12;
++	} decor_state;
++	int nr_left_buttons;
++	int nr_right_buttons;
++#define BUTTON_INDEX(b) \
++	(((b) == 0) ? (NUMBER_OF_TITLE_BUTTONS - 1) : ((b) - 1))
++#ifdef USEDECOR
++	struct FvwmDecor *decor;
++#endif
++	/* is this a shaped window */
++	int wShaped;
++	Pixmap title_background_pixmap;
++
++	/* Note: if the type of this variable is changed, do update the
++	 * CONFIGARGSNEW macro in module_interface.c, libs/vpacket.h too! */
++	short boundary_width;
++	short unshaped_boundary_width;
++	short corner_width;
++	short visual_corner_width;
++
++	/* title font */
++	FlocaleFont *title_font;
++	/* /Y coordinate to draw the title name */
++	short title_text_offset;
++	short title_length;
++	/* Note: if the type of this variable is changed, do update the
++	 * CONFIGARGSNEW macro in module_interface.c, libs/vpacket.h and too!
++	 */
++	short title_thickness;
++	rotation_t title_text_rotation;
++	struct
++	{
++		/* geometry of the icon picture window */
++		rectangle picture_w_g;
++		/* geometry of the icon title window */
++		rectangle title_w_g;
++		/* width of the text in the icon title */
++		int title_text_width;
++	} icon_g;
++	short icon_border_width;
++
++	/* Drawable depth for the icon */
++	int iconDepth;
++	/* pixmap for the icon */
++	Pixmap iconPixmap;
++	/* pixmap for the icon mask */
++	Pixmap icon_maskPixmap;
++	Pixmap icon_alphaPixmap;
++	int icon_nalloc_pixels;
++	Pixel *icon_alloc_pixels;
++	int icon_no_limit;
++	FlocaleFont *icon_font;
++
++	/* some parts of the window attributes */
++	struct
++	{
++		int backing_store;
++		int border_width;
++		int depth;
++		int bit_gravity;
++		unsigned is_bit_gravity_stored : 1;
++		Visual *visual;
++		Colormap colormap;
++	} attr_backup;
++	/* normal hints */
++	XSizeHints hints;
++	struct
++	{
++		int width_inc;
++		int height_inc;
++	} orig_hints;
++	/* WM hints */
++	XWMHints *wmhints;
++	XClassHint class;
++	/* Tells which desktop this window is on */
++	/* Note: if the type of this variable is changed, do update the
++	 * CONFIGARGSNEW macro in module_interface.c, libs/vpacket.h and too!
++	 */
++	int Desk;
++	/* Where (if at all) was it focused */
++	int FocusDesk;
++	/* Desk to deiconify to, for StubbornIcons */
++	int DeIconifyDesk;
++
++	char *mini_pixmap_file;
++	FvwmPicture *mini_icon;
++	char *icon_bitmap_file;
++
++	struct window_g g;
++	long *mwm_hints;
++	int ol_hints;
++	int functions;
++	/* Colormap windows property */
++	Window *cmap_windows;
++	/* Should generally be 0 */
++	int number_cmap_windows;
++	color_quad colors;
++	color_quad hicolors;
++	color_quad border_colors;
++	color_quad border_hicolors;
++
++	int cs;
++	int cs_hi;
++	int border_cs;
++	int border_cs_hi;
++	int icon_title_cs;
++	int icon_title_cs_hi;
++	int icon_background_cs;
++
++	unsigned long buttons;
++	/* zero or more iconboxes */
++	icon_boxes *IconBoxes;
++
++	int default_layer;
++	/* Note: if the type of this variable is changed, do update the
++	 * CONFIGARGSNEW macro in module_interface.c, libs/vpacket.h and too!
++	 */
++	int layer;
++
++	unsigned char min_icon_width;
++	unsigned char max_icon_width;
++	unsigned char min_icon_height;
++	unsigned char max_icon_height;
++	unsigned short icon_resize_type;
++
++	unsigned char icon_background_padding;
++	char icon_background_relief;
++	char icon_title_relief;
++
++	int max_window_width;
++	int max_window_height;
++	int shade_anim_steps;
++	unsigned char grabbed_buttons;
++
++#define FM_NO_INPUT        0
++#define FM_PASSIVE         1
++#define FM_LOCALLY_ACTIVE  2
++#define FM_GLOBALLY_ACTIVE 3
++	unsigned char focus_model;
++
++	float placement_penalty[6];
++	int placement_percentage_penalty[4];
++
++	unsigned char placed_by_button;
++
++#define EWMH_WINDOW_TYPE_NONE_ID      0
++#define EWMH_WINDOW_TYPE_DESKTOP_ID   1
++#define EWMH_WINDOW_TYPE_DIALOG_ID    2
++#define EWMH_WINDOW_TYPE_DOCK_ID      3
++#define EWMH_WINDOW_TYPE_MENU_ID      4
++#define EWMH_WINDOW_TYPE_NORMAL_ID    5
++#define EWMH_WINDOW_TYPE_TOOLBAR_ID   6
++	/* Note: if the type of this variable is changed, do update the
++	 * CONFIGARGSNEW macro in module_interface.c, libs/vpacket.h and too!
++	 */
++	int ewmh_window_type;
++	/* icon geometry */
++	rectangle ewmh_icon_geometry;
++	/* for computing the working area */
++	ewmh_strut strut;
++	/* for the dynamic working area */
++	ewmh_strut dyn_strut;
++	/* memories for the icons we set on the */
++	int ewmh_icon_height;
++	/* _NET_WM_ICON */
++	int ewmh_icon_width;
++	int ewmh_mini_icon_height;
++	int ewmh_mini_icon_width;
++	/* memory for the initial _NET_WM_STATE */
++	/* Note: if the type of this variable is changed, do update the
++	 * CONFIGARGSNEW macro in module_interface.c, libs/vpacket.h and too!
++	 */
++	int ewmh_hint_layer;
++	int ewmh_normal_layer; /* for restoring non ewmh layer */
++	/* memory for the initial _NET_WM_STATE */
++	unsigned long ewmh_hint_desktop;
++
++	/* multi purpose scratch structure */
++	struct
++	{
++		void *p;
++		int i;
++	} scratch;
++} FvwmWindow;
++
++/* ---------------------------- exported variables (globals) --------------- */
++
++/* ---------------------------- interface functions ------------------------ */
++
++void SetMWM_INFO(Window window);
++
++#endif /* FVWM_H */
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/geometry.c fvwm-2.5.21-05/fvwm/geometry.c
+--- fvwm-2.5.21-04/fvwm/geometry.c	2007-03-03 13:18:21.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/geometry.c	2007-03-03 13:18:49.000000000 +0100
+@@ -39,20 +39,23 @@
+ /* ---------------------------- local macros ------------------------------- */
+ 
+ /* ---------------------------- imports ------------------------------------ */
+ 
+ /* ---------------------------- included code files ------------------------ */
+ 
+ /* ---------------------------- local types -------------------------------- */
+ 
+ /* ---------------------------- forward declarations ----------------------- */
+ 
++static void __get_window_borders(
++	const FvwmWindow *fw, size_borders *borders, Bool is_shaded);
++
+ /* ---------------------------- local variables ---------------------------- */
+ 
+ /* ---------------------------- exported variables (globals) --------------- */
+ 
+ /* ---------------------------- local functions ---------------------------- */
+ 
+ /* ---------------------------- interface functions ------------------------ */
+ 
+ /* Removes decorations from the source rectangle and moves it according to the
+  * gravity specification. */
+@@ -336,21 +339,22 @@ void get_icon_corner(
+ void get_shaded_geometry(
+ 	FvwmWindow *fw, rectangle *small_g, rectangle *big_g)
+ {
+ 	size_borders b;
+ 	/* this variable is necessary so the function can be called with
+ 	 * small_g == big_g */
+ 	int big_width = big_g->width;
+ 	int big_height = big_g->height;
+ 	int d;
+ 
+-	get_window_borders(fw, &b);
++	__get_window_borders(fw, &b, 1);
++	
+ 	*small_g = *big_g;
+ 	d = 0;
+ 	switch (SHADED_DIR(fw))
+ 	{
+ 	case DIR_S:
+ 	case DIR_SW:
+ 	case DIR_SE:
+ 		small_g->y = big_g->y + big_height - b.total_size.height;
+ 		d = 1;
+ 		/* fall through */
+@@ -462,37 +466,52 @@ void get_shaded_client_window_pos(
+ 		break;
+ 	}
+ 
+ 	return;
+ }
+ 
+ /* returns the dimensions of the borders */
+ void get_window_borders(
+ 	const FvwmWindow *fw, size_borders *borders)
+ {
++	__get_window_borders(fw, borders, 0);
++}
++
++static void __get_window_borders(
++	const FvwmWindow *fw, size_borders *borders, Bool is_shaded)
++{
++	int title_thickness;
++	
+ 	borders->top_left.width = fw->boundary_width;
+ 	borders->bottom_right.width = fw->boundary_width;
+ 	borders->top_left.height = fw->boundary_width;
+ 	borders->bottom_right.height = fw->boundary_width;
++
++	title_thickness = fw->title_thickness;
++	if (HAS_TITLE(fw) && HAS_BORDER_UNDER_TITLE(fw) && !is_shaded)
++	{
++		title_thickness += fw->boundary_width;
++	}
++	
+ 	switch (GET_TITLE_DIR(fw))
+ 	{
+ 	case DIR_N:
+-		borders->top_left.height += fw->title_thickness;
++		borders->top_left.height += title_thickness;
+ 		break;
+ 	case DIR_S:
+-		borders->bottom_right.height += fw->title_thickness;
++		borders->bottom_right.height += title_thickness;
+ 		break;
+ 	case DIR_W:
+-		borders->top_left.width += fw->title_thickness;
++		borders->top_left.width += title_thickness;
+ 		break;
+ 	case DIR_E:
+-		borders->bottom_right.width += fw->title_thickness;
++		borders->bottom_right.width += title_thickness;
+ 		break;
+ 	}
+ 	borders->total_size.width =
+ 		borders->top_left.width + borders->bottom_right.width;
+ 	borders->total_size.height =
+ 		borders->top_left.height + borders->bottom_right.height;
+ 
+ 	return;
+ }
+ 
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/geometry.c~ fvwm-2.5.21-05/fvwm/geometry.c~
+--- fvwm-2.5.21-04/fvwm/geometry.c~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/geometry.c~	2007-03-03 13:18:42.000000000 +0100
+@@ -0,0 +1,1383 @@
++/* -*-c-*- */
++/* This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* ---------------------------- included header files ---------------------- */
++
++#include "config.h"
++
++#include <stdio.h>
++
++#include "libs/fvwmlib.h"
++#include "libs/charmap.h"
++#include "libs/wcontext.h"
++#include "fvwm.h"
++#include "externs.h"
++#include "execcontext.h"
++#include "misc.h"
++#include "screen.h"
++#include "geometry.h"
++#include "module_interface.h"
++#include "borders.h"
++#include "icons.h"
++#include "add_window.h"
++
++/* ---------------------------- local definitions -------------------------- */
++
++/* ---------------------------- local macros ------------------------------- */
++
++/* ---------------------------- imports ------------------------------------ */
++
++/* ---------------------------- included code files ------------------------ */
++
++/* ---------------------------- local types -------------------------------- */
++
++/* ---------------------------- forward declarations ----------------------- */
++
++/* ---------------------------- local variables ---------------------------- */
++
++/* ---------------------------- exported variables (globals) --------------- */
++
++/* ---------------------------- local functions ---------------------------- */
++
++/* ---------------------------- interface functions ------------------------ */
++
++/* Removes decorations from the source rectangle and moves it according to the
++ * gravity specification. */
++void gravity_get_naked_geometry(
++	int gravity, FvwmWindow *t, rectangle *dest_g, rectangle *orig_g)
++{
++	int xoff;
++	int yoff;
++	size_borders b;
++
++	get_window_borders(t, &b);
++	gravity_get_offsets(gravity, &xoff, &yoff);
++	dest_g->x = orig_g->x + ((xoff + 1) * (orig_g->width - 1)) / 2;
++	dest_g->y = orig_g->y + ((yoff + 1) * (orig_g->height - 1)) / 2;
++	dest_g->width = orig_g->width - b.total_size.width;
++	dest_g->height = orig_g->height - b.total_size.height;
++
++	return;
++}
++
++/* Decorate the rectangle.  Resize and shift it according to gravity. */
++void gravity_add_decoration(
++	int gravity, FvwmWindow *t, rectangle *dest_g, rectangle *orig_g)
++{
++	size_borders b;
++
++	get_window_borders(t, &b);
++	*dest_g = *orig_g;
++	gravity_resize(
++		gravity, dest_g, b.total_size.width, b.total_size.height);
++
++	return;
++}
++
++void get_relative_geometry(rectangle *rel_g, rectangle *abs_g)
++{
++	rel_g->x = abs_g->x - Scr.Vx;
++	rel_g->y = abs_g->y - Scr.Vy;
++	rel_g->width = abs_g->width;
++	rel_g->height = abs_g->height;
++
++	return;
++}
++
++void get_absolute_geometry(rectangle *abs_g, rectangle *rel_g)
++{
++	abs_g->x = rel_g->x + Scr.Vx;
++	abs_g->y = rel_g->y + Scr.Vy;
++	abs_g->width = rel_g->width;
++	abs_g->height = rel_g->height;
++
++	return;
++}
++
++void gravity_translate_to_northwest_geometry(
++	int gravity, FvwmWindow *t, rectangle *dest_g, rectangle *orig_g)
++{
++	int xoff;
++	int yoff;
++
++	gravity_get_offsets(gravity, &xoff, &yoff);
++	dest_g->x = orig_g->x -
++		((xoff + 1) * (orig_g->width - 1 +
++			       2 * t->attr_backup.border_width)) / 2;
++	dest_g->y = orig_g->y -
++		((yoff + 1) * (orig_g->height - 1 +
++			       2 * t->attr_backup.border_width)) / 2;
++	dest_g->width = orig_g->width;
++	dest_g->height = orig_g->height;
++
++	return;
++}
++
++void gravity_translate_to_northwest_geometry_no_bw(
++	int gravity, FvwmWindow *t, rectangle *dest_g, rectangle *orig_g)
++{
++	int bw = t->attr_backup.border_width;
++
++	t->attr_backup.border_width = 0;
++	gravity_translate_to_northwest_geometry(gravity, t, dest_g, orig_g);
++	t->attr_backup.border_width = bw;
++
++	return;
++}
++
++void get_title_geometry(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	size_borders b;
++	size_borders nt;
++	int w;
++	int h;
++
++	get_window_borders(fw, &b);
++	get_window_borders_no_title(fw, &nt);
++	w = (ret_g->width > 0) ? ret_g->width : fw->g.frame.width;
++	h = (ret_g->height > 0) ? ret_g->height : fw->g.frame.height;
++	ret_g->x = nt.top_left.width;
++	ret_g->y = nt.top_left.height;
++	switch (GET_TITLE_DIR(fw))
++	{
++	case DIR_S:
++		ret_g->y = h - b.bottom_right.height;
++		/* fall through */
++	case DIR_N:
++		ret_g->width = w - b.total_size.width;
++		ret_g->height = fw->title_thickness;
++		break;
++	case DIR_E:
++		ret_g->x = w - b.bottom_right.width;
++		/* fall through */
++	case DIR_W:
++		ret_g->width = fw->title_thickness;
++		ret_g->height = h - b.total_size.height;
++		break;
++	default:
++		break;
++	}
++
++	return;
++}
++
++void get_title_gravity_factors(
++	FvwmWindow *fw, int *ret_fx, int *ret_fy)
++{
++	switch (GET_TITLE_DIR(fw))
++	{
++	case DIR_N:
++		*ret_fx = 0;
++		*ret_fy = 1;
++		break;
++	case DIR_S:
++		*ret_fx = 0;
++		*ret_fy = -1;
++		break;
++	case DIR_W:
++		*ret_fx = 1;
++		*ret_fy = 0;
++		break;
++	case DIR_E:
++		*ret_fx = -1;
++		*ret_fy = 0;
++		break;
++	}
++
++	return;
++}
++
++Bool get_title_button_geometry(
++	FvwmWindow *fw, rectangle *ret_g, int context)
++{
++	int bnum;
++
++	if (context & C_TITLE)
++	{
++		ret_g->width = 0;
++		ret_g->height = 0;
++		get_title_geometry(fw, ret_g);
++		ret_g->x += fw->g.frame.x;
++		ret_g->y += fw->g.frame.y;
++
++		return True;
++
++	}
++	bnum = get_button_number(context);
++	if (bnum < 0 || FW_W_BUTTON(fw, bnum) == None)
++	{
++		return False;
++	}
++	if (XGetGeometry(
++		dpy, FW_W_BUTTON(fw, bnum), &JunkRoot, &ret_g->x, &ret_g->y,
++		(unsigned int*)&ret_g->width, (unsigned int*)&ret_g->height,
++		(unsigned int*)&JunkBW, (unsigned int*)&JunkDepth) == 0)
++	{
++		return False;
++	}
++	XTranslateCoordinates(
++		dpy, FW_W_FRAME(fw), Scr.Root, ret_g->x, ret_g->y, &ret_g->x,
++		&ret_g->y, &JunkChild);
++
++	return True;
++}
++
++void get_title_font_size_and_offset(
++	FvwmWindow *fw, direction_t title_dir,
++	Bool is_left_title_rotated_cw, Bool is_right_title_rotated_cw,
++	Bool is_top_title_rotated, Bool is_bottom_title_rotated,
++	int *size, int *offset)
++{
++	int decor_size;
++	int extra_size;
++	int font_size;
++	int min_offset;
++	Bool is_rotated_cw, is_rotated;
++	rotation_t draw_rotation;
++
++	/* adjust font offset according to height specified in title style */
++	decor_size = fw->decor->title_height;
++	font_size = fw->title_font->height + EXTRA_TITLE_FONT_HEIGHT;
++	switch (title_dir)
++	{
++	case DIR_W:
++	case DIR_E:
++		is_rotated_cw = (title_dir == DIR_W) ?
++			is_left_title_rotated_cw : is_right_title_rotated_cw;
++		if (is_rotated_cw)
++		{
++			fw->title_text_rotation = ROTATION_90;
++		}
++		else
++		{
++			fw->title_text_rotation = ROTATION_270;
++		}
++		break;
++	case DIR_N:
++	case DIR_S:
++	default:
++		is_rotated = (title_dir == DIR_N) ?
++			is_top_title_rotated : is_bottom_title_rotated;
++		if (is_rotated)
++		{
++			fw->title_text_rotation = ROTATION_180;
++		}
++		else
++		{
++			fw->title_text_rotation = ROTATION_0;
++		}
++		break;
++	}
++	if (USE_TITLE_DECOR_ROTATION(fw))
++	{
++		draw_rotation = ROTATION_0;
++	}
++	else
++	{
++		draw_rotation = fw->title_text_rotation;
++	}
++	min_offset =  FlocaleGetMinOffset(
++		fw->title_font, draw_rotation);
++	extra_size = (decor_size > 0) ? decor_size - font_size : 0;
++	*offset = min_offset;
++	if (fw->decor->min_title_height > 0 &&
++	    font_size + extra_size < fw->decor->min_title_height)
++	{
++		extra_size = fw->decor->min_title_height - font_size;
++	}
++	if (extra_size > 0)
++	{
++		*offset += extra_size / 2;
++	}
++	*size = font_size + extra_size;
++
++	return;
++}
++
++void get_icon_corner(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	switch (GET_TITLE_DIR(fw))
++	{
++	case DIR_N:
++	case DIR_W:
++		ret_g->x = fw->g.frame.x;
++		ret_g->y = fw->g.frame.y;
++		break;
++	case DIR_S:
++		ret_g->x = fw->g.frame.x;
++		ret_g->y = fw->g.frame.y + fw->g.frame.height -
++			ret_g->height;
++		break;
++	case DIR_E:
++		ret_g->x = fw->g.frame.x + fw->g.frame.width -
++			ret_g->width;
++		ret_g->y = fw->g.frame.y;
++		break;
++	}
++
++	return;
++}
++
++void get_shaded_geometry(
++	FvwmWindow *fw, rectangle *small_g, rectangle *big_g)
++{
++	size_borders b;
++	/* this variable is necessary so the function can be called with
++	 * small_g == big_g */
++	int big_width = big_g->width;
++	int big_height = big_g->height;
++	int d;
++
++	get_window_borders(fw, &b);
++	*small_g = *big_g;
++	d = 0;
++	switch (SHADED_DIR(fw))
++	{
++	case DIR_S:
++	case DIR_SW:
++	case DIR_SE:
++		small_g->y = big_g->y + big_height - b.total_size.height;
++		d = 1;
++		/* fall through */
++	case DIR_N:
++	case DIR_NW:
++	case DIR_NE:
++		small_g->height = b.total_size.height;
++		if (small_g->height == 0)
++		{
++			small_g->height = 1;
++			small_g->y -= d;
++		}
++		break;
++	default:
++		break;
++	}
++	d = 0;
++	switch (SHADED_DIR(fw))
++	{
++	case DIR_E:
++	case DIR_NE:
++	case DIR_SE:
++		small_g->x = big_g->x + big_width - b.total_size.width;
++		d = 1;
++		/* fall through */
++	case DIR_W:
++	case DIR_NW:
++	case DIR_SW:
++		small_g->width = b.total_size.width;
++		if (small_g->width == 0)
++		{
++			small_g->width = 1;
++			small_g->x -= d;
++		}
++		break;
++	default:
++		break;
++	}
++
++	return;
++}
++
++void get_shaded_geometry_with_dir(
++	FvwmWindow *fw, rectangle *small_g, rectangle *big_g,
++	direction_t shade_dir)
++{
++	direction_t old_shade_dir;
++
++	old_shade_dir = SHADED_DIR(fw);
++	SET_SHADED_DIR(fw, shade_dir);
++	get_shaded_geometry(fw, small_g, big_g);
++	SET_SHADED_DIR(fw, old_shade_dir);
++
++	return;
++}
++
++void get_unshaded_geometry(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	if (IS_SHADED(fw))
++	{
++		if (IS_MAXIMIZED(fw))
++		{
++			*ret_g = fw->g.max;
++		}
++		else
++		{
++			*ret_g = fw->g.normal;
++		}
++		get_relative_geometry(ret_g, ret_g);
++	}
++	else
++	{
++		*ret_g = fw->g.frame;
++	}
++
++	return;
++}
++
++void get_shaded_client_window_pos(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	rectangle big_g;
++	size_borders b;
++
++	get_window_borders(fw, &b);
++	big_g = (IS_MAXIMIZED(fw)) ? fw->g.max : fw->g.normal;
++	get_relative_geometry(&big_g, &big_g);
++	switch (SHADED_DIR(fw))
++	{
++	case DIR_S:
++	case DIR_SW:
++	case DIR_SE:
++		ret_g->y = 1 - big_g.height + b.total_size.height;
++		break;
++	default:
++		ret_g->y = 0;
++		break;
++	}
++	switch (SHADED_DIR(fw))
++	{
++	case DIR_E:
++	case DIR_NE:
++	case DIR_SE:
++		ret_g->x = 1 - big_g.width + b.total_size.width;
++		break;
++	default:
++		ret_g->x = 0;
++		break;
++	}
++
++	return;
++}
++
++/* returns the dimensions of the borders */
++void get_window_borders(
++	const FvwmWindow *fw, size_borders *borders)
++{
++	borders->top_left.width = fw->boundary_width;
++	borders->bottom_right.width = fw->boundary_width;
++	borders->top_left.height = fw->boundary_width;
++	borders->bottom_right.height = fw->boundary_width;
++	switch (GET_TITLE_DIR(fw))
++	{
++	case DIR_N:
++		borders->top_left.height += fw->title_thickness;
++		break;
++	case DIR_S:
++		borders->bottom_right.height += fw->title_thickness;
++		break;
++	case DIR_W:
++		borders->top_left.width += fw->title_thickness;
++		break;
++	case DIR_E:
++		borders->bottom_right.width += fw->title_thickness;
++		break;
++	}
++	borders->total_size.width =
++		borders->top_left.width + borders->bottom_right.width;
++	borders->total_size.height =
++		borders->top_left.height + borders->bottom_right.height;
++
++	return;
++}
++
++/* returns the dimensions of the borders without the title */
++void get_window_borders_no_title(
++	const FvwmWindow *fw, size_borders *borders)
++{
++	borders->top_left.width = fw->boundary_width;
++	borders->bottom_right.width = fw->boundary_width;
++	borders->top_left.height = fw->boundary_width;
++	borders->bottom_right.height = fw->boundary_width;
++	borders->total_size.width =
++		borders->top_left.width + borders->bottom_right.width;
++	borders->total_size.height =
++		borders->top_left.height + borders->bottom_right.height;
++
++	return;
++}
++
++void set_window_border_size(
++	FvwmWindow *fw, int used_width)
++{
++	if (used_width <= 0)
++	{
++		fw->boundary_width = 0;
++		fw->unshaped_boundary_width = 0;
++	}
++	else
++	{
++		fw->unshaped_boundary_width = used_width;
++		fw->boundary_width = (fw->wShaped) ? 0 : used_width;
++	}
++
++	return;
++}
++
++/* Returns True if all window borders are only 1 pixel thick (or less). */
++Bool is_window_border_minimal(
++	FvwmWindow *fw)
++{
++	size_borders nt;
++
++	get_window_borders_no_title(fw, &nt);
++	if (nt.top_left.width > 1 || nt.top_left.height > 1 ||
++	    nt.bottom_right.width > 1 || nt.bottom_right.height > 1)
++	{
++		return False;
++	}
++
++	return True;
++}
++
++
++/* This function returns the geometry of the client window.  If the window is
++ * shaded, the unshaded geometry is used instead. */
++void get_client_geometry(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	size_borders borders;
++
++	get_unshaded_geometry(fw, ret_g);
++	get_window_borders(fw, &borders);
++	ret_g->x += borders.top_left.width;
++	ret_g->y += borders.top_left.height;
++	ret_g->width -= borders.total_size.width;
++	ret_g->height -= borders.total_size.height;
++
++	return;
++}
++
++/* update the frame_g according to the window's g.normal or g.max and shaded
++ * state */
++void update_relative_geometry(FvwmWindow *fw)
++{
++	get_relative_geometry(
++		&fw->g.frame,
++		(IS_MAXIMIZED(fw)) ? &fw->g.max : &fw->g.normal);
++	if (IS_SHADED(fw))
++	{
++		get_shaded_geometry(
++			fw, &fw->g.frame, &fw->g.frame);
++	}
++
++	return;
++}
++
++/* update the g.normal or g.max according to the window's current position */
++void update_absolute_geometry(FvwmWindow *fw)
++{
++	rectangle *dest_g;
++	rectangle frame_g;
++
++	/* store orig values in absolute coords */
++	dest_g = (IS_MAXIMIZED(fw)) ? &fw->g.max : &fw->g.normal;
++	frame_g = *dest_g;
++	dest_g->x = fw->g.frame.x + Scr.Vx;
++	dest_g->y = fw->g.frame.y + Scr.Vy;
++	dest_g->width = fw->g.frame.width;
++	dest_g->height = fw->g.frame.height;
++	if (IS_SHADED(fw))
++	{
++		switch (SHADED_DIR(fw))
++		{
++		case DIR_SW:
++		case DIR_S:
++		case DIR_SE:
++			dest_g->y += fw->g.frame.height - frame_g.height;
++			/* fall through */
++		case DIR_NW:
++		case DIR_N:
++		case DIR_NE:
++			dest_g->height = frame_g.height;
++			break;
++		}
++		switch (SHADED_DIR(fw))
++		{
++		case DIR_NE:
++		case DIR_E:
++		case DIR_SE:
++			dest_g->x += fw->g.frame.width - frame_g.width;
++			/* fall through */
++		case DIR_NW:
++		case DIR_W:
++		case DIR_SW:
++			dest_g->width = frame_g.width;
++			break;
++		}
++	}
++
++	return;
++}
++
++/* make sure a maximized window and it's normal version are never a page or
++ * more apart. */
++void maximize_adjust_offset(FvwmWindow *fw)
++{
++	int off_x;
++	int off_y;
++	int dh;
++	int dw;
++
++	if (!IS_MAXIMIZED(fw))
++	{
++		/* otherwise we might corrupt the g.normal */
++		return;
++	}
++	off_x = fw->g.normal.x - fw->g.max.x - fw->g.max_offset.x;
++	off_y = fw->g.normal.y - fw->g.max.y - fw->g.max_offset.y;
++	dw = Scr.MyDisplayWidth;
++	dh = Scr.MyDisplayHeight;
++	if (off_x >= dw)
++	{
++		fw->g.normal.x -= (off_x / dw) * dw;
++	}
++	else if (off_x <= -dw)
++	{
++		fw->g.normal.x += (-off_x / dw) * dw;
++	}
++	if (off_y >= dh)
++	{
++		fw->g.normal.y -= (off_y / dh) * dh;
++	}
++	else if (off_y <= -dh)
++	{
++		fw->g.normal.y += (-off_y / dh) * dh;
++	}
++
++	return;
++}
++
++/*
++ *
++ *  Procedure:
++ *      constrain_size - adjust the given width and height to account for the
++ *              constraints imposed by size hints
++ *
++ *      The general algorithm, especially the aspect ratio stuff, is
++ *      borrowed from uwm's CheckConsistency routine.
++ *
++ */
++#define MAKEMULT(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
++void constrain_size(
++	FvwmWindow *fw, const XEvent *e, int *widthp,
++	int *heightp, int xmotion, int ymotion, int flags)
++{
++	int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
++	int baseWidth, baseHeight;
++	int dwidth;
++	int dheight;
++	int roundUpX = 0;
++	int roundUpY = 0;
++	int old_w = 0;
++	int old_h = 0;
++	size_borders b;
++
++	if (DO_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw) == 1)
++	{
++		return;
++	}
++	if (HAS_NEW_WM_NORMAL_HINTS(fw))
++	{
++		/* get the latest size hints */
++		XSync(dpy, 0);
++		GetWindowSizeHints(fw);
++		SET_HAS_NEW_WM_NORMAL_HINTS(fw, 0);
++	}
++	if (IS_MAXIMIZED(fw) && (flags & CS_UPDATE_MAX_DEFECT))
++	{
++		*widthp += fw->g.max_defect.width;
++		*heightp += fw->g.max_defect.height;
++		old_w = *widthp;
++		old_h = *heightp;
++	}
++	dwidth = *widthp;
++	dheight = *heightp;
++	get_window_borders(fw, &b);
++	dwidth -= b.total_size.width;
++	dheight -= b.total_size.height;
++
++	minWidth = fw->hints.min_width;
++	minHeight = fw->hints.min_height;
++
++	maxWidth = fw->hints.max_width;
++	maxHeight =  fw->hints.max_height;
++
++	if (maxWidth > fw->max_window_width - b.total_size.width)
++	{
++		maxWidth = fw->max_window_width - b.total_size.width;
++	}
++	if (maxHeight > fw->max_window_height - b.total_size.height)
++	{
++		maxHeight =
++			fw->max_window_height - b.total_size.height;
++	}
++
++	baseWidth = fw->hints.base_width;
++	baseHeight = fw->hints.base_height;
++
++	xinc = fw->hints.width_inc;
++	yinc = fw->hints.height_inc;
++
++	/*
++	 * First, clamp to min and max values
++	 */
++	if (dwidth < minWidth)
++	{
++		dwidth = minWidth;
++	}
++	if (dheight < minHeight)
++	{
++		dheight = minHeight;
++	}
++	if (dwidth > maxWidth)
++	{
++		dwidth = maxWidth;
++	}
++	if (dheight > maxHeight)
++	{
++		dheight = maxHeight;
++	}
++
++	/*
++	 * Second, round to base + N * inc (up or down depending on resize type)
++	 * if rounding up store amount
++	 */
++	if (!(flags & CS_ROUND_UP))
++	{
++		dwidth = (((dwidth - baseWidth) / xinc) * xinc) + baseWidth;
++		dheight = (((dheight - baseHeight) / yinc) * yinc) + baseHeight;
++	}
++	else
++	{
++		roundUpX = dwidth;
++		roundUpY = dheight;
++		dwidth = (((dwidth - baseWidth + xinc - 1) / xinc) * xinc) +
++			baseWidth;
++		dheight = (((dheight - baseHeight + yinc - 1) / yinc) * yinc) +
++			baseHeight;
++		roundUpX = dwidth - roundUpX;
++		roundUpY = dheight - roundUpY;
++	}
++
++	/*
++	 * Step 2a: check we didn't move the edge off screen in interactive
++	 * moves
++	 */
++	if ((flags & CS_ROUND_UP) && e != NULL && e->type == MotionNotify)
++	{
++		if (xmotion > 0 && e->xmotion.x_root < roundUpX)
++		{
++			dwidth -= xinc;
++		}
++		else if (xmotion < 0 &&
++			 e->xmotion.x_root >= Scr.MyDisplayWidth - roundUpX)
++		{
++			dwidth -= xinc;
++		}
++		if (ymotion > 0 && e->xmotion.y_root < roundUpY)
++		{
++			dheight -= yinc;
++		}
++		else if (ymotion < 0 &&
++			 e->xmotion.y_root >= Scr.MyDisplayHeight - roundUpY)
++		{
++			dheight -= yinc;
++		}
++	}
++
++	/*
++	 * Step 2b: Check that we didn't violate min and max.
++	 */
++	if (dwidth < minWidth)
++	{
++		dwidth += xinc;
++	}
++	if (dheight < minHeight)
++	{
++		dheight += yinc;
++	}
++	if (dwidth > maxWidth)
++	{
++		dwidth -= xinc;
++	}
++	if (dheight > maxHeight)
++	{
++		dheight -= yinc;
++	}
++
++	/*
++	 * Third, adjust for aspect ratio
++	 */
++#define maxAspectX fw->hints.max_aspect.x
++#define maxAspectY fw->hints.max_aspect.y
++#define minAspectX fw->hints.min_aspect.x
++#define minAspectY fw->hints.min_aspect.y
++	/*
++	 * The math looks like this:
++	 *
++	 * minAspectX    dwidth     maxAspectX
++	 * ---------- <= ------- <= ----------
++	 * minAspectY    dheight    maxAspectY
++	 *
++	 * If that is multiplied out, then the width and height are
++	 * invalid in the following situations:
++	 *
++	 * minAspectX * dheight > minAspectY * dwidth
++	 * maxAspectX * dheight < maxAspectY * dwidth
++	 *
++	 */
++
++	if (fw->hints.flags & PAspect)
++	{
++		double odefect;
++		double defect;
++		double maxratio;
++		double minratio;
++		int ow;
++		int oh;
++
++		if (fw->hints.flags & PBaseSize)
++		{
++			/*
++			 * ICCCM 2 demands that aspect ratio should apply
++			 * to width - base_width. To prevent funny results,
++			 * we reset PBaseSize in GetWindowSizeHints, if
++			 * base is not smaller than min.
++			*/
++			dwidth -= baseWidth;
++			maxWidth -= baseWidth;
++			minWidth -= baseWidth;
++			dheight -= baseHeight;
++			maxHeight -= baseHeight;
++			minHeight -= baseHeight;
++		}
++		minratio = (double)minAspectX / (double)minAspectY;
++		maxratio = (double)maxAspectX / (double)maxAspectY;
++		do
++		{
++			ow = dwidth;
++			oh = dheight;
++			odefect = 0;
++			if (minAspectX * dheight > minAspectY * dwidth)
++			{
++				odefect =
++					minratio -
++					(double)dwidth / (double)dheight;
++			}
++			else if (maxAspectX * dheight < maxAspectY * dwidth)
++			{
++				odefect = (double)dwidth / (double)dheight -
++					maxratio;
++			}
++			if (
++				minAspectX * dheight > minAspectY * dwidth &&
++				xmotion == 0)
++			{
++				/* Change width to match */
++				delta = MAKEMULT(
++					minAspectX * dheight / minAspectY -
++					dwidth, xinc);
++				if (dwidth + delta <= maxWidth)
++				{
++					dwidth += delta;
++				}
++			}
++			if (minAspectX * dheight > minAspectY * dwidth)
++			{
++				delta = MAKEMULT(
++					dheight -
++					dwidth * minAspectY / minAspectX,
++					yinc);
++				if (dheight - delta >= minHeight)
++				{
++					dheight -= delta;
++				}
++				else
++				{
++					delta = MAKEMULT(
++						minAspectX * dheight /
++						minAspectY - dwidth, xinc);
++					if (dwidth + delta <= maxWidth)
++					{
++						dwidth += delta;
++					}
++				}
++			}
++
++			if (
++				maxAspectX * dheight < maxAspectY * dwidth &&
++				ymotion == 0)
++			{
++				delta = MAKEMULT(
++					dwidth * maxAspectY / maxAspectX -
++					dheight, yinc);
++				if (dheight + delta <= maxHeight)
++				{
++					dheight += delta;
++				}
++			}
++			if ((maxAspectX * dheight < maxAspectY * dwidth))
++			{
++				delta = MAKEMULT(
++					dwidth - maxAspectX*dheight/maxAspectY,
++					xinc);
++				if (dwidth - delta >= minWidth)
++				{
++					dwidth -= delta;
++				}
++				else
++				{
++					delta = MAKEMULT(
++						dwidth * maxAspectY /
++						maxAspectX - dheight, yinc);
++					if (dheight + delta <= maxHeight)
++					{
++						dheight += delta;
++					}
++				}
++			}
++			defect = 0;
++			if (minAspectX * dheight > minAspectY * dwidth)
++			{
++				defect =
++					minratio -
++					(double)dwidth / (double)dheight;
++			}
++			else if (maxAspectX * dheight < maxAspectY * dwidth)
++			{
++				defect =
++					(double)dwidth / (double)dheight -
++					maxratio;
++			}
++		} while (odefect > defect);
++		dwidth = ow;
++		dheight = oh;
++		if (fw->hints.flags & PBaseSize)
++		{
++			dwidth += baseWidth;
++			dheight += baseHeight;
++		}
++	}
++
++	/*
++	 * Fourth, account for border width and title height
++	 */
++	*widthp = dwidth + b.total_size.width;
++	*heightp = dheight + b.total_size.height;
++	if (IS_MAXIMIZED(fw) && (flags & CS_UPDATE_MAX_DEFECT))
++	{
++		/* update size defect for maximized window */
++		fw->g.max_defect.width = old_w - *widthp;
++		fw->g.max_defect.height = old_h - *heightp;
++	}
++
++	return;
++}
++
++/* This function does roughly the same as constrain_size, but takes into account
++ * that the window shifts according to gravity if constrain_size actually
++ * changes the width or height. The frame_g of the window is not changed. The
++ * target geometry is expected to be in *rect and will be retured through rect.
++ */
++void gravity_constrain_size(
++	int gravity, FvwmWindow *t, rectangle *rect, int flags)
++{
++	int new_width = rect->width;
++	int new_height = rect->height;
++
++	if (IS_MAXIMIZED(t) && (flags & CS_UPDATE_MAX_DEFECT))
++	{
++		gravity_resize(
++			gravity, rect, t->g.max_defect.width,
++			t->g.max_defect.height);
++		t->g.max_defect.width = 0;
++		t->g.max_defect.height = 0;
++		new_width = rect->width;
++		new_height = rect->height;
++	}
++	constrain_size(
++		t, NULL, &new_width, &new_height, 0, 0, flags);
++	if (rect->width != new_width || rect->height != new_height)
++	{
++		gravity_resize(
++			gravity, rect, new_width - rect->width,
++			new_height - rect->height);
++	}
++
++	return;
++}
++
++/* returns the icon title geometry if it is visible */
++Bool get_visible_icon_title_geometry(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	if (HAS_NO_ICON_TITLE(fw) || IS_ICON_UNMAPPED(fw) ||
++	    !IS_ICONIFIED(fw))
++	{
++		memset(ret_g, 0, sizeof(*ret_g));
++		return False;
++	}
++	*ret_g = fw->icon_g.title_w_g;
++
++	return True;
++}
++
++/* returns the icon title geometry if it the icon title window exists */
++Bool get_icon_title_geometry(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	if (HAS_NO_ICON_TITLE(fw))
++	{
++		memset(ret_g, 0, sizeof(*ret_g));
++		return False;
++	}
++	*ret_g = fw->icon_g.title_w_g;
++
++	return True;
++}
++
++/* returns the icon picture geometry if it is visible */
++Bool get_visible_icon_picture_geometry(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	if (fw->icon_g.picture_w_g.width == 0 ||
++	    IS_ICON_UNMAPPED(fw) || !IS_ICONIFIED(fw))
++	{
++		memset(ret_g, 0, sizeof(*ret_g));
++		return False;
++	}
++	*ret_g = fw->icon_g.picture_w_g;
++
++	return True;
++}
++
++/* returns the icon picture geometry if it is exists */
++Bool get_icon_picture_geometry(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	if (fw->icon_g.picture_w_g.width == 0)
++	{
++		memset(ret_g, 0, sizeof(*ret_g));
++		return False;
++	}
++	*ret_g = fw->icon_g.picture_w_g;
++
++	return True;
++}
++
++/* returns the icon geometry (unexpanded title plus pixmap) if it is visible */
++Bool get_visible_icon_geometry(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	if (IS_ICON_UNMAPPED(fw) || !IS_ICONIFIED(fw))
++	{
++		memset(ret_g, 0, sizeof(*ret_g));
++		return False;
++	}
++	if (fw->icon_g.picture_w_g.width > 0)
++	{
++		*ret_g = fw->icon_g.picture_w_g;
++		if (!HAS_NO_ICON_TITLE(fw))
++		{
++			ret_g->height += fw->icon_g.title_w_g.height;
++		}
++	}
++	else if (!HAS_NO_ICON_TITLE(fw))
++	{
++		*ret_g = fw->icon_g.title_w_g;
++	}
++	else
++	{
++		memset(ret_g, 0, sizeof(*ret_g));
++		return False;
++	}
++
++	return True;
++}
++
++/* returns the icon geometry (unexpanded title plus pixmap) if it exists */
++void get_icon_geometry(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	/* valid geometry? */
++	if (fw->icon_g.picture_w_g.width > 0)
++	{
++		*ret_g = fw->icon_g.picture_w_g;
++		if (!HAS_NO_ICON_TITLE(fw))
++		{
++			ret_g->height += fw->icon_g.title_w_g.height;
++		}
++	}
++	else if (fw->icon_g.title_w_g.width > 0)
++	{
++		*ret_g = fw->icon_g.title_w_g;
++	}
++	/* valid position? */
++	else if (fw->icon_g.picture_w_g.x != 0 || fw->icon_g.picture_w_g.y != 0)
++	{
++		*ret_g = fw->icon_g.picture_w_g;
++	}
++	else if (fw->icon_g.title_w_g.x != 0 || fw->icon_g.title_w_g.y != 0)
++	{
++		*ret_g = fw->icon_g.title_w_g;
++	}
++	else
++	{
++		memset(ret_g, 0, sizeof(*ret_g));
++	}
++
++	return;
++}
++
++/* Returns the visible geometry of a window or icon.  This can be used to test
++ * if this region overlaps other windows. */
++Bool get_visible_window_or_icon_geometry(
++	FvwmWindow *fw, rectangle *ret_g)
++{
++	if (IS_ICONIFIED(fw))
++	{
++		return get_visible_icon_geometry(fw, ret_g);
++	}
++	*ret_g = fw->g.frame;
++
++	return True;
++}
++
++void move_icon_to_position(
++	FvwmWindow *fw)
++{
++	Bool draw_picture_w = False;
++	Bool draw_title_w = False;
++
++	if (fw->icon_g.picture_w_g.width > 0)
++	{
++		int cs;
++
++		if (Scr.Hilite == fw)
++		{
++			cs = fw->cs_hi;
++		}
++		else
++		{
++			cs = fw->cs;
++		}
++		XMoveWindow(
++			dpy, FW_W_ICON_PIXMAP(fw),
++			fw->icon_g.picture_w_g.x,
++			fw->icon_g.picture_w_g.y);
++		if (fw->icon_alphaPixmap ||
++		    (cs >= 0 && Colorset[cs].icon_alpha_percent < 100) ||
++		    CSET_IS_TRANSPARENT(fw->icon_background_cs) ||
++		    (!IS_ICON_SHAPED(fw) && fw->icon_background_padding > 0))
++		{
++			draw_picture_w = True;
++		}
++	}
++	if (!HAS_NO_ICON_TITLE(fw))
++	{
++		int cs;
++		rectangle dummy;
++
++		if (Scr.Hilite == fw)
++		{
++			cs = fw->icon_title_cs_hi;
++		}
++		else
++		{
++			cs = fw->icon_title_cs;
++		}
++		XMoveWindow(
++			dpy, FW_W_ICON_TITLE(fw),
++			fw->icon_g.title_w_g.x,
++			fw->icon_g.title_w_g.y);
++		if (CSET_IS_TRANSPARENT(cs) &&
++		    !get_visible_icon_picture_geometry(fw, &dummy) &&
++		    get_visible_icon_title_geometry(fw, &dummy))
++		{
++			draw_title_w = True;
++		}
++	}
++
++	if (draw_title_w || draw_picture_w)
++	{
++		DrawIconWindow(
++			fw, draw_title_w, draw_picture_w, False, draw_picture_w,
++			NULL);
++	}
++
++	return;
++}
++
++void broadcast_icon_geometry(
++	FvwmWindow *fw, Bool do_force)
++{
++	rectangle g;
++	Bool rc;
++
++	rc = get_visible_icon_geometry(fw, &g);
++	if (rc == True && (!IS_ICON_UNMAPPED(fw) || do_force == True))
++	{
++		BroadcastPacket(
++			M_ICON_LOCATION, 7, (long)FW_W(fw),
++			(long)FW_W_FRAME(fw), (unsigned long)fw,
++			(long)g.x, (long)g.y, (long)g.width, (long)g.height);
++	}
++
++	return;
++}
++
++void modify_icon_position(
++	FvwmWindow *fw, int dx, int dy)
++{
++	if (fw->icon_g.picture_w_g.width > 0 || HAS_NO_ICON_TITLE(fw))
++	{
++		/* picture position is also valid if there is neither a picture
++		 * nor a title */
++		fw->icon_g.picture_w_g.x += dx;
++		fw->icon_g.picture_w_g.y += dy;
++	}
++	if (!HAS_NO_ICON_TITLE(fw))
++	{
++		fw->icon_g.title_w_g.x += dx;
++		fw->icon_g.title_w_g.y += dy;
++	}
++
++	return;
++}
++
++/* set the icon position to the specified value. take care of the actual icon
++ * layout */
++void set_icon_position(
++	FvwmWindow *fw, int x, int y)
++{
++	if (fw->icon_g.picture_w_g.width > 0)
++	{
++		fw->icon_g.picture_w_g.x = x;
++		fw->icon_g.picture_w_g.y = y;
++	}
++	else
++	{
++		fw->icon_g.picture_w_g.x = 0;
++		fw->icon_g.picture_w_g.y = 0;
++	}
++	if (!HAS_NO_ICON_TITLE(fw))
++	{
++		fw->icon_g.title_w_g.x = x;
++		fw->icon_g.title_w_g.y = y;
++	}
++	else
++	{
++		fw->icon_g.title_w_g.x = 0;
++		fw->icon_g.title_w_g.y = 0;
++	}
++	if (fw->icon_g.picture_w_g.width > 0 &&
++	    !HAS_NO_ICON_TITLE(fw))
++	{
++		fw->icon_g.title_w_g.x -=
++			(fw->icon_g.title_w_g.width -
++			 fw->icon_g.picture_w_g.width) / 2;
++		fw->icon_g.title_w_g.y +=
++			fw->icon_g.picture_w_g.height;
++	}
++	else if (fw->icon_g.picture_w_g.width <= 0 && HAS_NO_ICON_TITLE(fw))
++	{
++		/* In case there is no icon, fake the icon position so the
++		 * modules know where its window was iconified. */
++		fw->icon_g.picture_w_g.x = x;
++		fw->icon_g.picture_w_g.y = y;
++	}
++
++	return;
++}
++
++void set_icon_picture_size(
++	FvwmWindow *fw, int w, int h)
++{
++	if (fw->icon_g.picture_w_g.width > 0)
++	{
++		fw->icon_g.picture_w_g.width = w;
++		fw->icon_g.picture_w_g.height = h;
++	}
++	else
++	{
++		fw->icon_g.picture_w_g.width = 0;
++		fw->icon_g.picture_w_g.height = 0;
++	}
++
++	return;
++}
++
++void resize_icon_title_height(FvwmWindow *fw, int dh)
++{
++	if (!HAS_NO_ICON_TITLE(fw))
++	{
++		fw->icon_g.title_w_g.height += dh;
++	}
++
++	return;
++}
++
++void get_page_offset_rectangle(
++	int *ret_page_x, int *ret_page_y, rectangle *r)
++{
++	int xoff = Scr.Vx % Scr.MyDisplayWidth;
++	int yoff = Scr.Vy % Scr.MyDisplayHeight;
++
++	/* maximize on the page where the center of the window is */
++	*ret_page_x = truncate_to_multiple(
++		r->x + r->width / 2 + xoff, Scr.MyDisplayWidth) - xoff;
++	*ret_page_y = truncate_to_multiple(
++		r->y + r->height / 2 + yoff, Scr.MyDisplayHeight) - yoff;
++
++	return;
++}
++
++void get_page_offset(
++	int *ret_page_x, int *ret_page_y, FvwmWindow *fw)
++{
++	rectangle r;
++
++	r.x = fw->g.frame.x;
++	r.y = fw->g.frame.y;
++	r.width = fw->g.frame.width;
++	r.height = fw->g.frame.height;
++	get_page_offset_rectangle(ret_page_x, ret_page_y, &r);
++
++	return;
++}
++
++void get_page_offset_check_visible(
++	int *ret_page_x, int *ret_page_y, FvwmWindow *fw)
++{
++	if (IsRectangleOnThisPage(&fw->g.frame, fw->Desk))
++	{
++		/* maximize on visible page if any part of the window is
++		 * visible */
++		*ret_page_x = 0;
++		*ret_page_y = 0;
++	}
++	else
++	{
++		get_page_offset(ret_page_x, ret_page_y, fw);
++	}
++
++	return;
++}
++
++/* ---------------------------- builtin commands --------------------------- */
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/geometry.h fvwm-2.5.21-05/fvwm/geometry.h
+--- fvwm-2.5.21-04/fvwm/geometry.h	2007-03-03 13:18:21.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/geometry.h	2007-03-03 13:18:49.000000000 +0100
+@@ -37,20 +37,22 @@ void get_shaded_geometry_with_dir(
+ 	FvwmWindow *fw, rectangle *small_g, rectangle *big_g,
+ 	direction_t shade_dir);
+ void get_unshaded_geometry(
+ 	FvwmWindow *fw, rectangle *ret_g);
+ void get_shaded_client_window_pos(
+ 	FvwmWindow *fw, rectangle *ret_g);
+ void get_client_geometry(
+ 	FvwmWindow *fw, rectangle *ret_g);
+ void get_window_borders(
+ 	const FvwmWindow *fw, size_borders *borders);
++void get_window_borders_shaded(
++	const FvwmWindow *fw, size_borders *borders);
+ void get_window_borders_no_title(
+ 	const FvwmWindow *fw, size_borders *borders);
+ void set_window_border_size(
+ 	FvwmWindow *fw, int used_width);
+ Bool is_window_border_minimal(
+ 	FvwmWindow *fw);
+ void update_relative_geometry(FvwmWindow *fw);
+ void update_absolute_geometry(FvwmWindow *fw);
+ void maximize_adjust_offset(FvwmWindow *fw);
+ void constrain_size(
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/style.c fvwm-2.5.21-05/fvwm/style.c
+--- fvwm-2.5.21-04/fvwm/style.c	2007-03-03 13:18:21.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/style.c	2007-03-03 13:18:49.000000000 +0100
+@@ -2044,20 +2044,26 @@ static Bool style_parse_one_style_option
+ 				fvwm_msg(
+ 					ERR, "style_parse_on_estyle_option",
+ 					"Style BackColor requires color"
+ 					" argument");
+ 			}
+ 		}
+ 		else if (StrEquals(token, "Button"))
+ 		{
+ 			rest = style_parse_button_style(ps, rest, on);
+ 		}
++		else if (StrEquals(token, "BORDERUNDERTITLE"))
++		{
++			S_SET_HAS_BORDER_UNDER_TITLE(SCF(*ps), on);
++			S_SET_HAS_BORDER_UNDER_TITLE(SCM(*ps), 1);
++			S_SET_HAS_BORDER_UNDER_TITLE(SCC(*ps), 1);
++		}
+ 		else if (StrEquals(token, "BorderWidth"))
+ 		{
+ 			if (GetIntegerArguments(rest, &rest, val, 1))
+ 			{
+ 				SSET_BORDER_WIDTH(*ps, (short)*val);
+ 				ps->flags.has_border_width = 1;
+ 				ps->flag_mask.has_border_width = 1;
+ 				ps->change_mask.has_border_width = 1;
+ 			}
+ 			else
+@@ -4413,20 +4419,25 @@ void check_window_style_change(
+ 	if (S_TITLE_DIR(SCC(*ret_style)))
+ 	{
+ 		flags->do_update_title_dir = 1;
+ 	}
+ 
+ 	/* use_title_decor_rotation */
+ 	if (S_USE_TITLE_DECOR_ROTATION(SCC(*ret_style)))
+ 	{
+ 		flags->do_update_rotated_title = 1;
+ 	}
++	
++	if (S_HAS_BORDER_UNDER_TITLE(SCC(*ret_style)))
++	{
++		flags->do_redecorate = True;
++	}
+ 
+ 	/* has_mwm_border
+ 	 * has_mwm_buttons */
+ 	if (S_HAS_MWM_BORDER(SCC(*ret_style)) ||
+ 	    S_HAS_MWM_BUTTONS(SCC(*ret_style)))
+ 	{
+ 		flags->do_redecorate = 1;
+ 	}
+ 
+ 	/* has_icon_font */
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/style.c~ fvwm-2.5.21-05/fvwm/style.c~
+--- fvwm-2.5.21-04/fvwm/style.c~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/style.c~	2007-03-03 13:18:42.000000000 +0100
+@@ -0,0 +1,5168 @@
++/* -*-c-*- */
++/* This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*
++ * This module was all original code
++ * by Rob Nation
++ * Copyright 1993, Robert Nation
++ *     You may use this code for any purpose, as long as the original
++ *     copyright remains in the source code and all documentation
++ */
++
++/* code for parsing the fvwm style command */
++
++/* ---------------------------- included header files ---------------------- */
++
++#include "config.h"
++#include <stdio.h>
++
++#include "libs/fvwmlib.h"
++#include "libs/FScreen.h"
++#include "libs/charmap.h"
++#include "libs/modifiers.h"
++#include "fvwm.h"
++#include "execcontext.h"
++#include "misc.h"
++#include "screen.h"
++#include "update.h"
++#include "style.h"
++#include "colorset.h"
++#include "ewmh.h"
++#include "gnome.h"
++
++/* ---------------------------- local definitions -------------------------- */
++
++#define SAFEFREE( p )  {if (p) {free(p);(p)=NULL;}}
++
++/* ---------------------------- local macros ------------------------------- */
++
++/* ---------------------------- imports ------------------------------------ */
++
++/* ---------------------------- included code files ------------------------ */
++
++/* ---------------------------- local types -------------------------------- */
++
++/* ---------------------------- forward declarations ----------------------- */
++
++/* ---------------------------- local variables ---------------------------- */
++
++/* list of window names with attributes */
++static window_style *all_styles = NULL;
++static window_style *last_style_in_list = NULL;
++
++/* ---------------------------- exported variables (globals) --------------- */
++
++/* ---------------------------- local functions ---------------------------- */
++
++static int blockor(char *dest, char *blk1, char *blk2, int length)
++{
++	int i;
++	char result = 0;
++
++	for (i = 0; i < length; i++)
++	{
++		dest[i] = (blk1[i] | blk2[i]);
++		result |= dest[i];
++	}
++
++	return (result) ? 1 : 0;
++}
++
++static int blockand(char *dest, char *blk1, char *blk2, int length)
++{
++	int i;
++	char result = 0;
++
++	for (i = 0; i < length; i++)
++	{
++		dest[i] = (blk1[i] & blk2[i]);
++		result |= dest[i];
++	}
++
++	return (result) ? 1 : 0;
++}
++
++static int blockunmask(char *dest, char *blk1, char *blk2, int length)
++{
++	int i;
++	char result = (char)0xff;
++
++	for (i = 0; i < length; i++)
++	{
++		dest[i] = (blk1[i] & ~blk2[i]);
++		result |= dest[i];
++	}
++
++	return (result) ? 1 : 0;
++}
++
++static int blockissubset(char *sub, char *super, int length)
++{
++	int i;
++
++	for (i = 0; i < length; i++)
++	{
++		if ((sub[i] & super[i]) != sub[i])
++		{
++			return 0;
++		}
++	}
++
++	return 1;
++}
++
++static int blocksintersect(char *blk1, char *blk2, int length)
++{
++	int i;
++
++	for (i = 0; i < length; i++)
++	{
++		if (blk1[i] & blk2[i])
++		{
++			return 1;
++		}
++	}
++
++	return 0;
++}
++
++static int style_ids_are_equal(style_id_t *a, style_id_t *b)
++{
++	if (
++		SID_GET_HAS_NAME(*a) && SID_GET_HAS_NAME(*b) &&
++		!strcmp(SID_GET_NAME(*a), SID_GET_NAME(*b)))
++	{
++		return 1;
++	}
++	if (
++		SID_GET_HAS_WINDOW_ID(*a) && SID_GET_HAS_WINDOW_ID(*b) &&
++		SID_GET_WINDOW_ID(*a) == SID_GET_WINDOW_ID(*b))
++	{
++		return 1;
++	}
++
++	return 0;
++}
++
++static int style_id_equals_id(window_style *s, style_id_t* id)
++{
++	return style_ids_are_equal(&SGET_ID(*s), id);
++}
++
++static int styles_have_same_id(window_style* s, window_style* t)
++{
++	return style_ids_are_equal(&SGET_ID(*s), &SGET_ID(*t));
++}
++
++static int fw_match_style_id(FvwmWindow *fw, style_id_t s_id)
++{
++	if (SID_GET_HAS_NAME(s_id))
++	{
++		if (matchWildcards(SID_GET_NAME(s_id), fw->class.res_class) ==
++		    1)
++		{
++			return 1;
++		}
++		if (matchWildcards(SID_GET_NAME(s_id), fw->class.res_name) ==
++		    1)
++		{
++			return 1;
++		}
++		if (matchWildcards(SID_GET_NAME(s_id), fw->name.name) == 1)
++		{
++			return 1;
++		}
++		if (fw->style_name == NULL &&
++		    matchWildcards(SID_GET_NAME(s_id), fw->style_name) == 1)
++		{
++			return 1;
++		}
++	}
++	if (SID_GET_HAS_WINDOW_ID(s_id) &&
++	    SID_GET_WINDOW_ID(s_id) == (XID)FW_W(fw))
++	{
++		return 1;
++	}
++
++	return 0;
++}
++
++static int one_fw_can_match_both_ids(window_style *s, window_style *t)
++{
++	if (SGET_ID_HAS_WINDOW_ID(*s) && SGET_ID_HAS_WINDOW_ID(*t) &&
++	    SGET_WINDOW_ID(*s) != SGET_WINDOW_ID(*t))
++	{
++		return 0;
++	}
++
++	return 1;
++}
++
++static void remove_icon_boxes_from_style(window_style *pstyle)
++{
++	if (SHAS_ICON_BOXES(&pstyle->flags))
++	{
++		free_icon_boxes(SGET_ICON_BOXES(*pstyle));
++		pstyle->flags.has_icon_boxes = 0;
++		SSET_ICON_BOXES(*pstyle, NULL);
++	}
++
++	return;
++}
++
++static void copy_icon_boxes(icon_boxes **pdest, icon_boxes *src)
++{
++	icon_boxes *last = NULL;
++	icon_boxes *temp;
++
++	*pdest = NULL;
++	/* copy the icon boxes */
++	for ( ; src != NULL; src = src->next)
++	{
++		temp = (icon_boxes *)safemalloc(sizeof(icon_boxes));
++		memcpy(temp, src, sizeof(icon_boxes));
++		temp->next = NULL;
++		if (last != NULL)
++			last->next = temp;
++		else
++			*pdest = temp;
++		last = temp;
++	}
++}
++
++/* Check word after IconFill to see if its "Top,Bottom,Left,Right" */
++static int Get_TBLR(char *token, unsigned char *IconFill)
++{
++	/* init */
++	if (StrEquals(token, "B") ||
++	    StrEquals(token, "BOT")||
++	    StrEquals(token, "BOTTOM"))
++	{
++		/* turn on bottom and verical */
++		*IconFill = ICONFILLBOT | ICONFILLHRZ;
++	}
++	else if (StrEquals(token, "T") ||
++		 StrEquals(token, "TOP"))
++	{
++		/* turn on vertical */
++		*IconFill = ICONFILLHRZ;
++	}
++	else if (StrEquals(token, "R") ||
++		 StrEquals(token, "RGT") ||
++		 StrEquals(token, "RIGHT"))
++	{
++		/* turn on right bit */
++		*IconFill = ICONFILLRGT;
++	}
++	else if (StrEquals(token, "L") ||
++		 StrEquals(token, "LFT") ||
++		 StrEquals(token, "LEFT"))
++	{
++		*IconFill = 0;
++	}
++	else
++	{
++		/* anything else is bad */
++		return 0;
++	}
++
++	/* return OK */
++	return 1;
++}
++
++static void cleanup_style_defaults(window_style *style)
++{
++	int i;
++	char *dflt;
++	char *mask;
++
++	mask = (char *)&(style->flag_mask);
++	dflt = (char *)&(style->flag_default);
++	for (i = 0; i < sizeof(style_flags); i++)
++	{
++		dflt[i] &= ~mask[i];
++	}
++
++	return;
++}
++
++/* merge_styles - For a matching style, merge window_style to window_style
++ *
++ *  Returned Value:
++ *	merged matching styles in callers window_style.
++ *
++ *  Inputs:
++ *	merged_style - style resulting from the merge
++ *	add_style    - the style to be added into the merge_style
++ *	do_free_src_and_alloc_copy
++ *		     - free allocated parts of merge_style that are replaced
++ *		       from add_style.	Create a copy of of the replaced
++ *		       styles in allocated memory.
++ *
++ *  Note:
++ *	The only trick here is that on and off flags/buttons are
++ *	combined into the on flag/button. */
++static void merge_styles(
++	window_style *merged_style, window_style *add_style,
++	Bool do_free_src_and_alloc_copy)
++{
++	int i;
++	char *merge_flags;
++	char *add_flags;
++	char *merge_mask;
++	char *add_mask;
++	char *merge_dflt;
++	char *add_dflt;
++	char *merge_change_mask;
++	char *add_change_mask;
++
++	if (add_style->flag_mask.has_icon)
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_ICON_NAME(*merged_style));
++			SSET_ICON_NAME(
++				*merged_style, (SGET_ICON_NAME(*add_style)) ?
++				safestrdup(SGET_ICON_NAME(*add_style)) : NULL);
++		}
++		else
++		{
++			SSET_ICON_NAME(
++				*merged_style, SGET_ICON_NAME(*add_style));
++		}
++	}
++	if (FMiniIconsSupported && add_style->flag_mask.has_mini_icon)
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_MINI_ICON_NAME(*merged_style));
++			SSET_MINI_ICON_NAME(
++				*merged_style,
++				(SGET_MINI_ICON_NAME(*add_style)) ?
++				safestrdup(SGET_MINI_ICON_NAME(*add_style)) :
++				NULL);
++		}
++		else
++		{
++			SSET_MINI_ICON_NAME(
++				*merged_style, SGET_MINI_ICON_NAME(*add_style));
++		}
++	}
++#ifdef USEDECOR
++	if (add_style->flag_mask.has_decor)
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_DECOR_NAME(*merged_style));
++			SSET_DECOR_NAME(
++				*merged_style, (SGET_DECOR_NAME(*add_style)) ?
++				safestrdup(SGET_DECOR_NAME(*add_style)) : NULL);
++		}
++		else
++		{
++			SSET_DECOR_NAME(
++				*merged_style, SGET_DECOR_NAME(*add_style));
++		}
++	}
++#endif
++	if (S_HAS_ICON_FONT(SCF(*add_style)))
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_ICON_FONT(*merged_style));
++			SSET_ICON_FONT(
++				*merged_style, (SGET_ICON_FONT(*add_style)) ?
++				safestrdup(SGET_ICON_FONT(*add_style)) : NULL);
++		}
++		else
++		{
++			SSET_ICON_FONT(
++				*merged_style, SGET_ICON_FONT(*add_style));
++		}
++	}
++	if (S_HAS_WINDOW_FONT(SCF(*add_style)))
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_WINDOW_FONT(*merged_style));
++			SSET_WINDOW_FONT(
++				*merged_style, (SGET_WINDOW_FONT(*add_style)) ?
++				safestrdup(SGET_WINDOW_FONT(*add_style)) :
++				NULL);
++		}
++		else
++		{
++			SSET_WINDOW_FONT(
++				*merged_style, SGET_WINDOW_FONT(*add_style));
++		}
++	}
++	if (add_style->flags.use_start_on_desk)
++	{
++		SSET_START_DESK(*merged_style, SGET_START_DESK(*add_style));
++		SSET_START_PAGE_X(
++			*merged_style, SGET_START_PAGE_X(*add_style));
++		SSET_START_PAGE_Y(
++			*merged_style, SGET_START_PAGE_Y(*add_style));
++	}
++	if (add_style->flags.use_start_on_screen)
++	{
++		SSET_START_SCREEN
++			(*merged_style, SGET_START_SCREEN(*add_style));
++	}
++	if (add_style->flag_mask.has_color_fore)
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_FORE_COLOR_NAME(*merged_style));
++			SSET_FORE_COLOR_NAME(
++				*merged_style,
++				(SGET_FORE_COLOR_NAME(*add_style)) ?
++				safestrdup(SGET_FORE_COLOR_NAME(*add_style)) :
++				NULL);
++		}
++		else
++		{
++			SSET_FORE_COLOR_NAME(
++				*merged_style,
++				SGET_FORE_COLOR_NAME(*add_style));
++		}
++	}
++	if (add_style->flag_mask.has_color_back)
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_BACK_COLOR_NAME(*merged_style));
++			SSET_BACK_COLOR_NAME(
++				*merged_style,
++				(SGET_BACK_COLOR_NAME(*add_style)) ?
++				safestrdup(SGET_BACK_COLOR_NAME(*add_style)) :
++				NULL);
++		}
++		else
++		{
++			SSET_BACK_COLOR_NAME(
++				*merged_style,
++				SGET_BACK_COLOR_NAME(*add_style));
++		}
++	}
++	if (add_style->flag_mask.has_color_fore_hi)
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_FORE_COLOR_NAME_HI(*merged_style));
++			SSET_FORE_COLOR_NAME_HI(
++				*merged_style,
++				(SGET_FORE_COLOR_NAME_HI(*add_style)) ?
++				safestrdup(
++					SGET_FORE_COLOR_NAME_HI(*add_style)) :
++				NULL);
++		}
++		else
++		{
++			SSET_FORE_COLOR_NAME_HI(
++				*merged_style,
++				SGET_FORE_COLOR_NAME_HI(*add_style));
++		}
++	}
++	if (add_style->flag_mask.has_color_back_hi)
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_BACK_COLOR_NAME_HI(*merged_style));
++			SSET_BACK_COLOR_NAME_HI(
++				*merged_style,
++				(SGET_BACK_COLOR_NAME_HI(*add_style)) ?
++				safestrdup(
++					SGET_BACK_COLOR_NAME_HI(*add_style)) :
++				NULL);
++		}
++		else
++		{
++			SSET_BACK_COLOR_NAME_HI(
++				*merged_style,
++				SGET_BACK_COLOR_NAME_HI(*add_style));
++		}
++	}
++	if (add_style->flags.has_border_width)
++	{
++		SSET_BORDER_WIDTH(*merged_style, SGET_BORDER_WIDTH(*add_style));
++	}
++	if (add_style->flags.has_handle_width)
++	{
++		SSET_HANDLE_WIDTH(*merged_style, SGET_HANDLE_WIDTH(*add_style));
++	}
++	if (add_style->flags.has_icon_size_limits)
++	{
++		SSET_MIN_ICON_WIDTH(
++			*merged_style, SGET_MIN_ICON_WIDTH(*add_style));
++		SSET_MIN_ICON_HEIGHT(
++			*merged_style, SGET_MIN_ICON_HEIGHT(*add_style));
++		SSET_MAX_ICON_WIDTH(
++			*merged_style, SGET_MAX_ICON_WIDTH(*add_style));
++		SSET_MAX_ICON_HEIGHT(
++			*merged_style, SGET_MAX_ICON_HEIGHT(*add_style));
++		SSET_ICON_RESIZE_TYPE(
++			*merged_style, SGET_ICON_RESIZE_TYPE(*add_style));
++	}
++	if (add_style->flags.has_max_window_size)
++	{
++		SSET_MAX_WINDOW_WIDTH(
++			*merged_style, SGET_MAX_WINDOW_WIDTH(*add_style));
++		SSET_MAX_WINDOW_HEIGHT(
++			*merged_style, SGET_MAX_WINDOW_HEIGHT(*add_style));
++	}
++	if (add_style->flags.has_icon_background_relief)
++	{
++		SSET_ICON_BACKGROUND_RELIEF(
++			*merged_style, SGET_ICON_BACKGROUND_RELIEF(*add_style));
++	}
++	if (add_style->flags.has_icon_background_padding)
++	{
++		SSET_ICON_BACKGROUND_PADDING(
++			*merged_style, SGET_ICON_BACKGROUND_PADDING(*add_style));
++	}
++	if (add_style->flags.has_icon_title_relief)
++	{
++		SSET_ICON_TITLE_RELIEF(
++			*merged_style, SGET_ICON_TITLE_RELIEF(*add_style));
++	}
++	if (add_style->flags.has_window_shade_steps)
++	{
++		SSET_WINDOW_SHADE_STEPS(
++			*merged_style, SGET_WINDOW_SHADE_STEPS(*add_style));
++	}
++
++	/* Note:  Only one style cmd can define a window's iconboxes, the last one
++	 * encountered. */
++	if (SHAS_ICON_BOXES(&add_style->flag_mask))
++	{
++		/* If style has iconboxes */
++		/* copy it */
++		if (do_free_src_and_alloc_copy)
++		{
++			remove_icon_boxes_from_style(merged_style);
++			copy_icon_boxes(
++				&SGET_ICON_BOXES(*merged_style),
++				SGET_ICON_BOXES(*add_style));
++		}
++		else
++		{
++			SSET_ICON_BOXES(
++				*merged_style, SGET_ICON_BOXES(*add_style));
++		}
++	}
++	if (add_style->flags.use_layer)
++	{
++		SSET_LAYER(*merged_style, SGET_LAYER(*add_style));
++	}
++	if (add_style->flags.use_colorset)
++	{
++		SSET_COLORSET(*merged_style, SGET_COLORSET(*add_style));
++	}
++	if (add_style->flags.use_colorset_hi)
++	{
++		SSET_COLORSET_HI(*merged_style, SGET_COLORSET_HI(*add_style));
++	}
++	if (add_style->flags.use_border_colorset)
++	{
++		SSET_BORDER_COLORSET(
++			*merged_style, SGET_BORDER_COLORSET(*add_style));
++	}
++	if (add_style->flags.use_border_colorset_hi)
++	{
++		SSET_BORDER_COLORSET_HI(
++			*merged_style,SGET_BORDER_COLORSET_HI(*add_style));
++	}
++	if (add_style->flags.use_icon_title_colorset)
++	{
++		SSET_ICON_TITLE_COLORSET(
++			*merged_style,SGET_ICON_TITLE_COLORSET(*add_style));
++	}
++	if (add_style->flags.use_icon_title_colorset_hi)
++	{
++		SSET_ICON_TITLE_COLORSET_HI(
++			*merged_style,SGET_ICON_TITLE_COLORSET_HI(*add_style));
++	}
++	if (add_style->flags.use_icon_background_colorset)
++	{
++		SSET_ICON_BACKGROUND_COLORSET(
++			*merged_style,SGET_ICON_BACKGROUND_COLORSET(*add_style));
++	}
++	if (add_style->flags.has_placement_penalty)
++	{
++		SSET_NORMAL_PLACEMENT_PENALTY(
++			*merged_style,
++			SGET_NORMAL_PLACEMENT_PENALTY(*add_style));
++		SSET_ONTOP_PLACEMENT_PENALTY(
++			*merged_style,
++			SGET_ONTOP_PLACEMENT_PENALTY(*add_style));
++		SSET_ICON_PLACEMENT_PENALTY(
++			*merged_style, SGET_ICON_PLACEMENT_PENALTY(*add_style));
++		SSET_STICKY_PLACEMENT_PENALTY(
++			*merged_style,
++			SGET_STICKY_PLACEMENT_PENALTY(*add_style));
++		SSET_BELOW_PLACEMENT_PENALTY(
++			*merged_style,
++			SGET_BELOW_PLACEMENT_PENALTY(*add_style));
++		SSET_EWMH_STRUT_PLACEMENT_PENALTY(
++			*merged_style,
++			SGET_EWMH_STRUT_PLACEMENT_PENALTY(*add_style));
++	}
++	if (add_style->flags.has_placement_percentage_penalty)
++	{
++		SSET_99_PLACEMENT_PERCENTAGE_PENALTY(
++			*merged_style,
++			SGET_99_PLACEMENT_PERCENTAGE_PENALTY(*add_style));
++		SSET_95_PLACEMENT_PERCENTAGE_PENALTY(
++			*merged_style,
++			SGET_95_PLACEMENT_PERCENTAGE_PENALTY(*add_style));
++		SSET_85_PLACEMENT_PERCENTAGE_PENALTY(
++			*merged_style,
++			SGET_85_PLACEMENT_PERCENTAGE_PENALTY(*add_style));
++		SSET_75_PLACEMENT_PERCENTAGE_PENALTY(
++			*merged_style,
++			SGET_75_PLACEMENT_PERCENTAGE_PENALTY(*add_style));
++	}
++	/* merge the style flags */
++
++	/*** ATTENTION:
++	 ***	 This must be the last thing that is done in this function! */
++	merge_flags = (char *)&(merged_style->flags);
++	add_flags = (char *)&(add_style->flags);
++	merge_mask = (char *)&(merged_style->flag_mask);
++	add_mask = (char *)&(add_style->flag_mask);
++	merge_dflt = (char *)&(merged_style->flag_default);
++	add_dflt = (char *)&(add_style->flag_default);
++	merge_change_mask = (char *)&(merged_style->change_mask);
++	add_change_mask = (char *)&(add_style->change_mask);
++	for (i = 0; i < sizeof(style_flags); i++)
++	{
++		char m;
++
++		/* overwrite set styles */
++		merge_flags[i] |= (add_flags[i] & add_mask[i]);
++		merge_flags[i] &= (add_flags[i] | ~add_mask[i]);
++		/* overwrite default values */
++		m = add_dflt[i] & ~add_mask[i] & ~merge_mask[i];
++		merge_flags[i] |= (add_flags[i] & m);
++		merge_flags[i] &= (add_flags[i] | ~m);
++		/* overwrite even weaker default values */
++		m = ~add_dflt[i] & ~add_mask[i] & ~merge_dflt[i] &
++			~merge_mask[i];
++		merge_flags[i] |= (add_flags[i] & m);
++		merge_flags[i] &= (add_flags[i] | ~m);
++		/* other flags */
++		merge_change_mask[i] &= ~(add_mask[i]);
++		merge_change_mask[i] |= add_change_mask[i];
++		merge_mask[i] |= add_mask[i];
++		merge_dflt[i] |= add_dflt[i];
++		merge_dflt[i] &= ~merge_mask[i];
++	}
++	merged_style->has_style_changed |= add_style->has_style_changed;
++
++	return;
++}
++
++static void free_style(window_style *style)
++{
++	/* Free contents of style */
++	SAFEFREE(SGET_NAME(*style));
++	SAFEFREE(SGET_BACK_COLOR_NAME(*style));
++	SAFEFREE(SGET_FORE_COLOR_NAME(*style));
++	SAFEFREE(SGET_BACK_COLOR_NAME_HI(*style));
++	SAFEFREE(SGET_FORE_COLOR_NAME_HI(*style));
++	SAFEFREE(SGET_DECOR_NAME(*style));
++	SAFEFREE(SGET_ICON_FONT(*style));
++	SAFEFREE(SGET_WINDOW_FONT(*style));
++	SAFEFREE(SGET_ICON_NAME(*style));
++	SAFEFREE(SGET_MINI_ICON_NAME(*style));
++	remove_icon_boxes_from_style(style);
++
++	return;
++}
++
++/* Frees only selected members of a style; adjusts the flag_mask and
++ * change_mask appropriately. */
++static void free_style_mask(window_style *style, style_flags *mask)
++{
++	style_flags local_mask;
++	style_flags *pmask;
++
++	/* mask out all bits that are not set in the target style */
++	pmask =&local_mask;
++	blockand((char *)pmask, (char *)&style->flag_mask, (char *)mask,
++		 sizeof(style_flags));
++
++	/* Free contents of style */
++	if (pmask->has_color_back)
++	{
++		SAFEFREE(SGET_BACK_COLOR_NAME(*style));
++	}
++	if (pmask->has_color_fore)
++	{
++		SAFEFREE(SGET_FORE_COLOR_NAME(*style));
++	}
++	if (pmask->has_color_back_hi)
++	{
++		SAFEFREE(SGET_BACK_COLOR_NAME_HI(*style));
++	}
++	if (pmask->has_color_fore_hi)
++	{
++		SAFEFREE(SGET_FORE_COLOR_NAME_HI(*style));
++	}
++	if (pmask->has_decor)
++	{
++		SAFEFREE(SGET_DECOR_NAME(*style));
++	}
++	if (pmask->common.has_icon_font)
++	{
++		SAFEFREE(SGET_ICON_FONT(*style));
++	}
++	if (pmask->common.has_window_font)
++	{
++		SAFEFREE(SGET_WINDOW_FONT(*style));
++	}
++	if (pmask->has_icon)
++	{
++		SAFEFREE(SGET_ICON_NAME(*style));
++	}
++	if (pmask->has_mini_icon)
++	{
++		SAFEFREE(SGET_MINI_ICON_NAME(*style));
++	}
++	if (pmask->has_icon_boxes)
++	{
++		remove_icon_boxes_from_style(style);
++	}
++	/* remove styles from definitiion */
++	blockunmask((char *)&style->flag_mask, (char *)&style->flag_mask,
++		    (char *)pmask, sizeof(style_flags));
++	blockunmask((char *)&style->flag_default, (char *)&style->flag_default,
++		    (char *)pmask, sizeof(style_flags));
++	blockunmask((char *)&style->change_mask, (char *)&style->change_mask,
++		    (char *)pmask, sizeof(style_flags));
++
++	return;
++}
++
++static void add_style_to_list(window_style *new_style)
++{
++	/* This used to contain logic that returned if the style didn't contain
++	 * anything.    I don't see why we should bother. dje.
++	 *
++	 * used to merge duplicate entries, but that is no longer
++	 * appropriate since conflicting styles are possible, and the
++	 * last match should win! */
++
++	if (last_style_in_list != NULL)
++	{
++		/* not first entry in list chain this entry to the list */
++		SSET_NEXT_STYLE(*last_style_in_list, new_style);
++	}
++	else
++	{
++		/* first entry in list set the list root pointer. */
++		all_styles = new_style;
++	}
++	SSET_PREV_STYLE(*new_style, last_style_in_list);
++	SSET_NEXT_STYLE(*new_style, NULL);
++	last_style_in_list = new_style;
++	Scr.flags.do_need_style_list_update = 1;
++
++	return;
++} /* end function */
++
++static void remove_style_from_list(window_style *style, Bool do_free_style)
++{
++	window_style *prev;
++	window_style *next;
++
++	prev = SGET_PREV_STYLE(*style);
++	next = SGET_NEXT_STYLE(*style);
++	if (!prev)
++	{
++		/* first style in list */
++		all_styles = next;
++	}
++	else
++	{
++		/* not first style in list */
++		SSET_NEXT_STYLE(*prev, next);
++	}
++	if (!next)
++	{
++		/* last style in list */
++		last_style_in_list = prev;
++	}
++	else
++	{
++		SSET_PREV_STYLE(*next, prev);
++	}
++	if (do_free_style)
++	{
++		free_style(style);
++		free(style);
++	}
++}
++
++static int remove_all_of_style_from_list(style_id_t style_id)
++{
++	window_style *nptr = all_styles;
++	window_style *next;
++	int is_changed = 0;
++
++	/* loop though styles */
++	while (nptr)
++	{
++		next = SGET_NEXT_STYLE(*nptr);
++		/* Check if it's to be wiped */
++		if (style_id_equals_id(nptr, &style_id))
++		{
++			remove_style_from_list(nptr, True);
++			is_changed = 1;
++		}
++		/* move on */
++		nptr = next;
++	}
++
++	return is_changed;
++}
++
++static int __simplify_style_list(void)
++{
++	window_style *cur;
++	int has_modified;
++
++	/* Step 1:
++	 *   Remove styles that are completely overridden by later
++	 *   style definitions.  At the same time...
++	 * Step 2:
++	 *   Merge styles with the same name if there are no
++	 *   conflicting styles with other names set in between. */
++	for (
++		cur = last_style_in_list, has_modified = 0; cur;
++		cur = SGET_PREV_STYLE(*cur))
++	{
++		style_flags dummyflags;
++		/* incremental flags set in styles with the same name */
++		style_flags sumflags;
++		style_flags sumdflags;
++		/* incremental flags set in styles with other names */
++		style_flags interflags;
++		window_style *cmp;
++
++		memset(&interflags, 0, sizeof(style_flags));
++		memcpy(&sumflags, &cur->flag_mask, sizeof(style_flags));
++		memcpy(&sumdflags, &cur->flag_default, sizeof(style_flags));
++		cmp = SGET_PREV_STYLE(*cur);
++		while (cmp)
++		{
++			if (!styles_have_same_id(cur, cmp))
++			{
++				if (one_fw_can_match_both_ids(cur, cmp))
++				{
++					blockor((char *)&interflags,
++						(char *)&interflags,
++						(char *)&cmp->flag_mask,
++						sizeof(style_flags));
++					blockor((char *)&interflags,
++						(char *)&interflags,
++						(char *)&cmp->flag_default,
++						sizeof(style_flags));
++				}
++				cmp = SGET_PREV_STYLE(*cmp);
++				continue;
++			}
++			if (blockissubset(
++				    (char *)&cmp->flag_mask,
++				    (char *)&sumflags,
++				    sizeof(style_flags)) &&
++			    blockissubset(
++				    (char *)&cmp->flag_default,
++				    (char *)&sumdflags,
++				    sizeof(style_flags)))
++			{
++				/* The style is a subset of later style
++				 * definitions; nuke it */
++				window_style *tmp = SGET_PREV_STYLE(*cmp);
++				remove_style_from_list(cmp, True);
++				cmp = tmp;
++				has_modified = 1;
++				continue;
++			}
++			/* remove all styles that are overridden later from the
++			 * style */
++			blockor((char *)&dummyflags,
++				(char *)&sumdflags,
++				(char *)&sumflags,
++				sizeof(style_flags));
++			free_style_mask(cmp, &dummyflags);
++			if (
++				!blocksintersect(
++					(char *)&cmp->flag_mask,
++					(char *)&interflags,
++					sizeof(style_flags)) &&
++				!blocksintersect(
++					(char *)&cmp->flag_default,
++					(char *)&interflags,
++					sizeof(style_flags)))
++			{
++				/* merge old style into new style */
++				window_style *tmp = SGET_PREV_STYLE(*cmp);
++				window_style *prev = SGET_PREV_STYLE(*cur);
++				window_style *next = SGET_NEXT_STYLE(*cur);
++
++				/* Add the style to the set */
++				blockor((char *)&sumflags,
++					(char *)&sumflags,
++					(char *)&cmp->flag_mask,
++					sizeof(style_flags));
++				blockor((char *)&sumdflags,
++					(char *)&sumflags,
++					(char *)&cmp->flag_default,
++				sizeof(style_flags));
++				/* merge cmp into cur and delete it
++				 * afterwards */
++				merge_styles(cmp, cur, True);
++				free_style(cur);
++				memcpy(cur, cmp, sizeof(window_style));
++				/* restore fields overwritten by memcpy */
++				SSET_PREV_STYLE(*cur, prev);
++				SSET_NEXT_STYLE(*cur, next);
++				/* remove the style without freeing the
++				 * memory */
++				remove_style_from_list(cmp, False);
++				/* release the style structure */
++				free(cmp);
++				cmp = tmp;
++				has_modified = 1;
++			}
++			else if	(
++				!blocksintersect(
++					(char *)&cur->flag_mask,
++					(char *)&interflags,
++					sizeof(style_flags)) &&
++				!blocksintersect(
++					(char *)&cur->flag_default,
++					(char *)&interflags,
++					sizeof(style_flags)))
++			{
++				/* merge new style into old style */
++				window_style *tmp = SGET_PREV_STYLE(*cmp);
++
++				/* Add the style to the set */
++				blockor((char *)&sumflags,
++					(char *)&sumflags,
++					(char *)&cur->flag_mask,
++					sizeof(style_flags));
++				blockor((char *)&sumdflags,
++					(char *)&sumflags,
++					(char *)&cur->flag_default,
++					sizeof(style_flags));
++				/* merge cur into cmp and delete it
++				 * afterwards */
++				merge_styles(cmp, cur, True);
++				remove_style_from_list(cur, True);
++				cur = cmp;
++				cmp = tmp;
++				has_modified = 1;
++				memset(&interflags, 0, sizeof(style_flags));
++				continue;
++			}
++			else
++			{
++				/* Add it to the set of interfering styles. */
++				blockor((char *)&interflags,
++					(char *)&interflags,
++					(char *)&cmp->flag_mask,
++					sizeof(style_flags));
++				blockor((char *)&interflags,
++					(char *)&interflags,
++					(char *)&cmp->flag_default,
++					sizeof(style_flags));
++				cmp = SGET_PREV_STYLE(*cmp);
++			}
++		}
++	}
++
++	return has_modified;
++}
++
++static void style_set_old_focus_policy(window_style *ps, int policy)
++{
++	focus_policy_t fp;
++
++	switch (policy)
++	{
++	case 0:
++		/* ClickToFocus */
++		FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCF(*ps)), 1);
++		FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCF(*ps)), 1);
++		FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCF(*ps)), 1);
++		FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCF(*ps)), 1);
++		FPS_FOCUS_BY_PROGRAM(fp, 1);
++		FPS_GRAB_FOCUS(fp, 1);
++		FPS_RELEASE_FOCUS(fp, 1);
++		FPS_RAISE_FOCUSED_CLIENT_CLICK(fp, 1);
++		FPS_RAISE_UNFOCUSED_CLIENT_CLICK(fp, 1);
++		FPS_RAISE_FOCUSED_DECOR_CLICK(fp, 1);
++		FPS_RAISE_UNFOCUSED_DECOR_CLICK(fp, 1);
++		FPS_PASS_FOCUS_CLICK(fp, 1);
++		FPS_PASS_RAISE_CLICK(fp, 1);
++		FPS_ALLOW_FUNC_FOCUS_CLICK(fp, 1);
++		FPS_ALLOW_FUNC_RAISE_CLICK(fp, 1);
++		FPS_WARP_POINTER_ON_FOCUS_FUNC(fp, 0);
++		break;
++	case 1:
++		/* MouseFocus */
++		FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCF(*ps)), 1);
++		FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCF(*ps)), 1);
++		FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCF(*ps)), 1);
++		FPS_FOCUS_BY_PROGRAM(fp, 1);
++		FPS_GRAB_FOCUS(fp, 0);
++		FPS_RELEASE_FOCUS(fp, 0);
++		FPS_RAISE_FOCUSED_CLIENT_CLICK(fp, 0);
++		FPS_RAISE_UNFOCUSED_CLIENT_CLICK(fp, 0);
++		FPS_RAISE_FOCUSED_DECOR_CLICK(fp, 0);
++		FPS_RAISE_UNFOCUSED_DECOR_CLICK(fp, 0);
++		FPS_PASS_FOCUS_CLICK(fp, 1);
++		FPS_PASS_RAISE_CLICK(fp, 1);
++		FPS_ALLOW_FUNC_FOCUS_CLICK(fp, 0);
++		FPS_ALLOW_FUNC_RAISE_CLICK(fp, 0);
++		FPS_WARP_POINTER_ON_FOCUS_FUNC(fp, 1);
++		break;
++	case 2:
++		/* SloppyFocus */
++		FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCF(*ps)), 1);
++		FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCF(*ps)), 1);
++		FPS_FOCUS_BY_PROGRAM(fp, 1);
++		FPS_GRAB_FOCUS(fp, 0);
++		FPS_RELEASE_FOCUS(fp, 1);
++		FPS_RAISE_FOCUSED_CLIENT_CLICK(fp, 0);
++		FPS_RAISE_UNFOCUSED_CLIENT_CLICK(fp, 0);
++		FPS_RAISE_FOCUSED_DECOR_CLICK(fp, 0);
++		FPS_RAISE_UNFOCUSED_DECOR_CLICK(fp, 0);
++		FPS_PASS_FOCUS_CLICK(fp, 1);
++		FPS_PASS_RAISE_CLICK(fp, 1);
++		FPS_ALLOW_FUNC_FOCUS_CLICK(fp, 0);
++		FPS_ALLOW_FUNC_RAISE_CLICK(fp, 0);
++		FPS_WARP_POINTER_ON_FOCUS_FUNC(fp, 1);
++		break;
++	case 3:
++		/* NeverFocus */
++		FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCF(*ps)), 0);
++		FPS_FOCUS_BY_PROGRAM(fp, 1);
++		FPS_GRAB_FOCUS(fp, 0);
++		FPS_RELEASE_FOCUS(fp, 0);
++		FPS_RAISE_FOCUSED_CLIENT_CLICK(fp, 0);
++		FPS_RAISE_UNFOCUSED_CLIENT_CLICK(fp, 0);
++		FPS_RAISE_FOCUSED_DECOR_CLICK(fp, 0);
++		FPS_RAISE_UNFOCUSED_DECOR_CLICK(fp, 0);
++		FPS_PASS_FOCUS_CLICK(fp, 1);
++		FPS_PASS_RAISE_CLICK(fp, 1);
++		FPS_ALLOW_FUNC_FOCUS_CLICK(fp, 1);
++		FPS_ALLOW_FUNC_RAISE_CLICK(fp, 1);
++		FPS_WARP_POINTER_ON_FOCUS_FUNC(fp, 0);
++		break;
++	}
++	FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCM(*ps)), 1);
++	FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCC(*ps)), 1);
++	FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCM(*ps)), 1);
++	FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCC(*ps)), 1);
++	FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCM(*ps)), 1);
++	FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCC(*ps)), 1);
++	FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCM(*ps)), 1);
++	FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCC(*ps)), 1);
++	FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCM(*ps)), 1);
++	FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCC(*ps)), 1);
++	FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCM(*ps)), 1);
++	FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCC(*ps)), 1);
++
++	if (!FP_DO_FOCUS_BY_PROGRAM(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_FOCUS_BY_PROGRAM(
++			S_FOCUS_POLICY(SCF(*ps)), FP_DO_FOCUS_BY_PROGRAM(fp));
++		FPS_FOCUS_BY_PROGRAM(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_FOCUS_BY_PROGRAM(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_GRAB_FOCUS(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCF(*ps)), FP_DO_GRAB_FOCUS(fp));
++		FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_RELEASE_FOCUS(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_RELEASE_FOCUS(
++			S_FOCUS_POLICY(SCF(*ps)), FP_DO_RELEASE_FOCUS(fp));
++		FPS_RELEASE_FOCUS(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_RELEASE_FOCUS(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_RAISE_FOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_RAISE_FOCUSED_CLIENT_CLICK(
++			S_FOCUS_POLICY(SCF(*ps)),
++			FP_DO_RAISE_FOCUSED_CLIENT_CLICK(fp));
++		FPS_RAISE_FOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_RAISE_FOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_RAISE_UNFOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++			S_FOCUS_POLICY(SCF(*ps)),
++			FP_DO_RAISE_UNFOCUSED_CLIENT_CLICK(fp));
++		FPS_RAISE_UNFOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_RAISE_UNFOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_RAISE_FOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_RAISE_FOCUSED_DECOR_CLICK(
++			S_FOCUS_POLICY(SCF(*ps)),
++			FP_DO_RAISE_FOCUSED_DECOR_CLICK(fp));
++		FPS_RAISE_FOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_RAISE_FOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_RAISE_UNFOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_RAISE_UNFOCUSED_DECOR_CLICK(
++			S_FOCUS_POLICY(SCF(*ps)),
++			FP_DO_RAISE_UNFOCUSED_DECOR_CLICK(fp));
++		FPS_RAISE_UNFOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_RAISE_UNFOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_PASS_FOCUS_CLICK(
++			S_FOCUS_POLICY(SCF(*ps)), FP_DO_PASS_FOCUS_CLICK(fp));
++		FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_PASS_RAISE_CLICK(
++			S_FOCUS_POLICY(SCF(*ps)), FP_DO_PASS_RAISE_CLICK(fp));
++		FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_ALLOW_FUNC_FOCUS_CLICK(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_ALLOW_FUNC_FOCUS_CLICK(
++			S_FOCUS_POLICY(SCF(*ps)),
++			FP_DO_ALLOW_FUNC_FOCUS_CLICK(fp));
++		FPS_ALLOW_FUNC_FOCUS_CLICK(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_ALLOW_FUNC_FOCUS_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_ALLOW_FUNC_RAISE_CLICK(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_ALLOW_FUNC_RAISE_CLICK(
++			S_FOCUS_POLICY(SCF(*ps)),
++			FP_DO_ALLOW_FUNC_RAISE_CLICK(fp));
++		FPS_ALLOW_FUNC_RAISE_CLICK(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_ALLOW_FUNC_RAISE_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_WARP_POINTER_ON_FOCUS_FUNC(
++		    S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_WARP_POINTER_ON_FOCUS_FUNC(
++			S_FOCUS_POLICY(SCF(*ps)),
++			FP_DO_WARP_POINTER_ON_FOCUS_FUNC(fp));
++		FPS_WARP_POINTER_ON_FOCUS_FUNC(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_WARP_POINTER_ON_FOCUS_FUNC(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++	if (!FP_DO_SORT_WINDOWLIST_BY(S_FOCUS_POLICY(SCM(*ps))))
++	{
++		FPS_SORT_WINDOWLIST_BY(
++			S_FOCUS_POLICY(SCF(*ps)),
++			FP_DO_SORT_WINDOWLIST_BY(fp));
++		FPS_SORT_WINDOWLIST_BY(S_FOCUS_POLICY(SCD(*ps)), 1);
++		FPS_SORT_WINDOWLIST_BY(S_FOCUS_POLICY(SCC(*ps)), 1);
++	}
++
++	return;
++}
++
++static char *style_parse_button_style(
++	window_style *ps, char *button_string, int on)
++{
++	int button;
++	char *rest;
++
++	button = -1;
++	GetIntegerArguments(button_string, &rest, &button, 1);
++	button = BUTTON_INDEX(button);
++	if (button < 0 || button >= NUMBER_OF_TITLE_BUTTONS)
++	{
++		fvwm_msg(
++			ERR, "CMD_Style",
++			"Button and NoButton styles require an argument");
++	}
++	else
++	{
++		if (on)
++		{
++			ps->flags.is_button_disabled &= ~(1 << button);
++			ps->flag_mask.is_button_disabled |= (1 << button);
++			ps->change_mask.is_button_disabled |= (1 << button);
++		}
++		else
++		{
++			ps->flags.is_button_disabled |= (1 << button);
++			ps->flag_mask.is_button_disabled |= (1 << button);
++			ps->change_mask.is_button_disabled |= (1 << button);
++		}
++	}
++
++	return rest;
++}
++
++static Bool style_parse_focus_policy_style(
++	char *option, char *rest, char **ret_rest, Bool is_reversed,
++	focus_policy_t *f, focus_policy_t *m, focus_policy_t *c)
++{
++	char *optlist[] = {
++		"SortWindowlistByFocus",
++		"FocusClickButtons",
++		"FocusClickModifiers",
++		"ClickRaisesFocused",
++		"ClickDecorRaisesFocused",
++		"ClickIconRaisesFocused",
++		"ClickRaisesUnfocused",
++		"ClickDecorRaisesUnfocused",
++		"ClickIconRaisesUnfocused",
++		"ClickToFocus",
++		"ClickDecorToFocus",
++		"ClickIconToFocus",
++		"EnterToFocus",
++		"LeaveToUnfocus",
++		"FocusByProgram",
++		"FocusByFunction",
++		"FocusByFunctionWarpPointer",
++		"Lenient",
++		"PassFocusClick",
++		"PassRaiseClick",
++		"IgnoreFocusClickMotion",
++		"IgnoreRaiseClickMotion",
++		"AllowFocusClickFunction",
++		"AllowRaiseClickFunction",
++		"GrabFocus",
++		"GrabFocusTransient",
++		"OverrideGrabFocus",
++		"ReleaseFocus",
++		"ReleaseFocusTransient",
++		"OverrideReleaseFocus",
++		NULL
++	};
++	Bool found;
++	int val;
++	int index;
++	char *token;
++
++	if (ret_rest)
++	{
++		*ret_rest = rest;
++	}
++
++	found = True;
++	val = !is_reversed;
++	GetNextTokenIndex(option, optlist, 0, &index);
++	switch (index)
++	{
++	case 0:
++		/* SortWindowlistByFocus */
++		FPS_SORT_WINDOWLIST_BY(
++			*f, (val) ?
++			FPOL_SORT_WL_BY_FOCUS : FPOL_SORT_WL_BY_OPEN);
++		FPS_SORT_WINDOWLIST_BY(*m, 1);
++		FPS_SORT_WINDOWLIST_BY(*c, 1);
++		break;
++	case 1:
++		/* FocusClickButtons */
++		if (is_reversed)
++		{
++			found = False;
++			break;
++		}
++		token = PeekToken(rest, ret_rest);
++		val = 0;
++		for ( ; token != NULL && isdigit(*token); token++)
++		{
++			int button;
++			char s[2];
++
++			s[0] = *token;
++			s[1] = 0;
++			button = atoi(s);
++			if (button == 0)
++			{
++				val = ~0;
++			}
++			else if (button > NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
++			{
++				break;
++			}
++			else
++			{
++				val |= (1 << (button - 1));
++			}
++		}
++		if (token != NULL && *token != 0)
++		{
++			fvwm_msg(
++				ERR, "style_parse_focus_policy_style",
++				"illegal mouse button '%c'", *token);
++			val = DEF_FP_MOUSE_BUTTONS;
++		}
++		if (token == NULL)
++		{
++			val = DEF_FP_MOUSE_BUTTONS;
++		}
++		FPS_MOUSE_BUTTONS(*f, val);
++		FPS_MOUSE_BUTTONS(*m, ~0);
++		FPS_MOUSE_BUTTONS(*c, ~0);
++		break;
++	case 2:
++		/* FocusClickModifiers */
++		if (is_reversed)
++		{
++			found = False;
++			break;
++		}
++		token = PeekToken(rest, ret_rest);
++		if (token == NULL ||
++		    modifiers_string_to_modmask(token, &val) == 1)
++		{
++			val = DEF_FP_MODIFIERS;
++		}
++		if (val & AnyModifier)
++		{
++			val = FPOL_ANY_MODIFIER;
++		}
++		FPS_MODIFIERS(*f, val);
++		FPS_MODIFIERS(*m, ~0);
++		FPS_MODIFIERS(*c, ~0);
++		break;
++	case 3:
++		/* ClickRaisesFocused */
++		FPS_RAISE_FOCUSED_CLIENT_CLICK(*f, val);
++		FPS_RAISE_FOCUSED_CLIENT_CLICK(*m, 1);
++		FPS_RAISE_FOCUSED_CLIENT_CLICK(*c, 1);
++		break;
++	case 4:
++		/* ClickDecorRaisesFocused */
++		FPS_RAISE_FOCUSED_DECOR_CLICK(*f, val);
++		FPS_RAISE_FOCUSED_DECOR_CLICK(*m, 1);
++		FPS_RAISE_FOCUSED_DECOR_CLICK(*c, 1);
++		break;
++	case 5:
++		/* ClickIconRaisesFocused */
++		FPS_RAISE_FOCUSED_ICON_CLICK(*f, val);
++		FPS_RAISE_FOCUSED_ICON_CLICK(*m, 1);
++		FPS_RAISE_FOCUSED_ICON_CLICK(*c, 1);
++		break;
++	case 6:
++		/* ClickRaisesUnfocused */
++		FPS_RAISE_UNFOCUSED_CLIENT_CLICK(*f, val);
++		FPS_RAISE_UNFOCUSED_CLIENT_CLICK(*m, 1);
++		FPS_RAISE_UNFOCUSED_CLIENT_CLICK(*c, 1);
++		break;
++	case 7:
++		/* ClickDecorRaisesUnfocused */
++		FPS_RAISE_UNFOCUSED_DECOR_CLICK(*f, val);
++		FPS_RAISE_UNFOCUSED_DECOR_CLICK(*m, 1);
++		FPS_RAISE_UNFOCUSED_DECOR_CLICK(*c, 1);
++		break;
++	case 8:
++		/* ClickIconRaisesUnfocused */
++		FPS_RAISE_UNFOCUSED_ICON_CLICK(*f, val);
++		FPS_RAISE_UNFOCUSED_ICON_CLICK(*m, 1);
++		FPS_RAISE_UNFOCUSED_ICON_CLICK(*c, 1);
++		break;
++	case 9:
++		/* ClickToFocus */
++		FPS_FOCUS_CLICK_CLIENT(*f, val);
++		FPS_FOCUS_CLICK_CLIENT(*m, 1);
++		FPS_FOCUS_CLICK_CLIENT(*c, 1);
++		break;
++	case 10:
++		/* ClickDecorToFocus */
++		FPS_FOCUS_CLICK_DECOR(*f, val);
++		FPS_FOCUS_CLICK_DECOR(*m, 1);
++		FPS_FOCUS_CLICK_DECOR(*c, 1);
++		break;
++	case 11:
++		/* ClickIconToFocus */
++		FPS_FOCUS_CLICK_ICON(*f, val);
++		FPS_FOCUS_CLICK_ICON(*m, 1);
++		FPS_FOCUS_CLICK_ICON(*c, 1);
++		break;
++	case 12:
++		/* EnterToFocus */
++		FPS_FOCUS_ENTER(*f, val);
++		FPS_FOCUS_ENTER(*m, 1);
++		FPS_FOCUS_ENTER(*c, 1);
++		break;
++	case 13:
++		/* LeaveToUnfocus */
++		FPS_UNFOCUS_LEAVE(*f, val);
++		FPS_UNFOCUS_LEAVE(*m, 1);
++		FPS_UNFOCUS_LEAVE(*c, 1);
++		break;
++	case 14:
++		/* FocusByProgram */
++		FPS_FOCUS_BY_PROGRAM(*f, val);
++		FPS_FOCUS_BY_PROGRAM(*m, 1);
++		FPS_FOCUS_BY_PROGRAM(*c, 1);
++		break;
++	case 15:
++		/* FocusByFunction */
++		FPS_FOCUS_BY_FUNCTION(*f, val);
++		FPS_FOCUS_BY_FUNCTION(*m, 1);
++		FPS_FOCUS_BY_FUNCTION(*c, 1);
++		break;
++	case 16:
++		/* FocusByFunctionWarpPointer */
++		FPS_WARP_POINTER_ON_FOCUS_FUNC(*f, val);
++		FPS_WARP_POINTER_ON_FOCUS_FUNC(*m, 1);
++		FPS_WARP_POINTER_ON_FOCUS_FUNC(*c, 1);
++		break;
++	case 17:
++		/* Lenient */
++		FPS_LENIENT(*f, val);
++		FPS_LENIENT(*m, 1);
++		FPS_LENIENT(*c, 1);
++		break;
++	case 18:
++		/* PassFocusClick */
++		FPS_PASS_FOCUS_CLICK(*f, val);
++		FPS_PASS_FOCUS_CLICK(*m, 1);
++		FPS_PASS_FOCUS_CLICK(*c, 1);
++		break;
++	case 19:
++		/* PassRaiseClick */
++		FPS_PASS_RAISE_CLICK(*f, val);
++		FPS_PASS_RAISE_CLICK(*m, 1);
++		FPS_PASS_RAISE_CLICK(*c, 1);
++		break;
++	case 20:
++		/* IgnoreFocusClickMotion */
++		FPS_IGNORE_FOCUS_CLICK_MOTION(*f, val);
++		FPS_IGNORE_FOCUS_CLICK_MOTION(*m, 1);
++		FPS_IGNORE_FOCUS_CLICK_MOTION(*c, 1);
++		break;
++	case 21:
++		/* IgnoreRaiseClickMotion */
++		FPS_IGNORE_RAISE_CLICK_MOTION(*f, val);
++		FPS_IGNORE_RAISE_CLICK_MOTION(*m, 1);
++		FPS_IGNORE_RAISE_CLICK_MOTION(*c, 1);
++		break;
++	case 22:
++		/* AllowFocusClickFunction */
++		FPS_ALLOW_FUNC_FOCUS_CLICK(*f, val);
++		FPS_ALLOW_FUNC_FOCUS_CLICK(*m, 1);
++		FPS_ALLOW_FUNC_FOCUS_CLICK(*c, 1);
++		break;
++	case 23:
++		/* AllowRaiseClickFunction */
++		FPS_ALLOW_FUNC_RAISE_CLICK(*f, val);
++		FPS_ALLOW_FUNC_RAISE_CLICK(*m, 1);
++		FPS_ALLOW_FUNC_RAISE_CLICK(*c, 1);
++		break;
++	case 24:
++		/* GrabFocus */
++		FPS_GRAB_FOCUS(*f, val);
++		FPS_GRAB_FOCUS(*m, 1);
++		FPS_GRAB_FOCUS(*c, 1);
++		break;
++	case 25:
++		/* GrabFocusTransient */
++		FPS_GRAB_FOCUS_TRANSIENT(*f, val);
++		FPS_GRAB_FOCUS_TRANSIENT(*m, 1);
++		FPS_GRAB_FOCUS_TRANSIENT(*c, 1);
++		break;
++	case 26:
++		/* OverrideGrabFocus */
++		FPS_OVERRIDE_GRAB_FOCUS(*f, val);
++		FPS_OVERRIDE_GRAB_FOCUS(*m, 1);
++		FPS_OVERRIDE_GRAB_FOCUS(*c, 1);
++		break;
++	case 27:
++		/* ReleaseFocus */
++		FPS_RELEASE_FOCUS(*f, val);
++		FPS_RELEASE_FOCUS(*m, 1);
++		FPS_RELEASE_FOCUS(*c, 1);
++		break;
++	case 28:
++		/* ReleaseFocusTransient */
++		FPS_RELEASE_FOCUS_TRANSIENT(*f, val);
++		FPS_RELEASE_FOCUS_TRANSIENT(*m, 1);
++		FPS_RELEASE_FOCUS_TRANSIENT(*c, 1);
++		break;
++	case 29:
++		/* OverrideReleaseFocus */
++		FPS_OVERRIDE_RELEASE_FOCUS(*f, val);
++		FPS_OVERRIDE_RELEASE_FOCUS(*m, 1);
++		FPS_OVERRIDE_RELEASE_FOCUS(*c, 1);
++		break;
++	default:
++		found = False;
++		break;
++	}
++
++	return found;
++}
++
++static char *style_parse_icon_size_style(
++	char *option, char *rest, window_style *ps)
++{
++	int vals[4];
++	int i;
++
++	option = PeekToken(rest, NULL);
++	if (StrEquals(option, "Stretched"))
++	{
++		SSET_ICON_RESIZE_TYPE(*ps, ICON_RESIZE_TYPE_STRETCHED);
++		option = PeekToken(rest, &rest);
++	}
++	else if (StrEquals(option, "Adjusted"))
++	{
++		SSET_ICON_RESIZE_TYPE(*ps, ICON_RESIZE_TYPE_ADJUSTED);
++		option = PeekToken(rest, &rest);
++	}
++	else if (StrEquals(option, "Shrunk"))
++	{
++		SSET_ICON_RESIZE_TYPE(*ps, ICON_RESIZE_TYPE_SHRUNK);
++		option = PeekToken(rest, &rest);
++	}
++	else
++	{
++		SSET_ICON_RESIZE_TYPE(*ps, ICON_RESIZE_TYPE_NONE);
++	}
++
++	switch (GetIntegerArguments(rest, &rest, vals, 4))
++	{
++	case 0:
++		/* No arguments results in default values */
++		vals[0] = vals[1] = UNSPECIFIED_ICON_DIMENSION;
++		/* fall through */
++	case 2:
++		/* Max and min values are the same */
++		vals[2] = vals[0];
++		vals[3] = vals[1];
++		/* fall through */
++	case 4:
++		/* Validate values */
++		for (i = 0; i < 4; i++)
++		{
++			int use_default = 0;
++
++			if (vals[i] != UNSPECIFIED_ICON_DIMENSION &&
++			    (vals[i] < MIN_ALLOWABLE_ICON_DIMENSION ||
++			     vals[i] > MAX_ALLOWABLE_ICON_DIMENSION))
++			{
++				fvwm_msg(
++					ERR, "CMD_Style",
++					"IconSize dimension (%d) not in valid"
++					" range (%d-%d)",
++					 vals[i], MIN_ALLOWABLE_ICON_DIMENSION,
++					 MAX_ALLOWABLE_ICON_DIMENSION);
++				use_default = 1;
++			}
++
++			/* User requests default value for this dimension */
++			else if (vals[i] == UNSPECIFIED_ICON_DIMENSION)
++			{
++				use_default = 1;
++			}
++
++			if (use_default)
++			{
++				/* Set default value for this dimension.  The
++				 * first two indexes refer to min values, the
++				 * latter two to max values. */
++				vals[i] = i < 2 ? MIN_ALLOWABLE_ICON_DIMENSION :
++					MAX_ALLOWABLE_ICON_DIMENSION;
++			}
++		}
++		SSET_MIN_ICON_WIDTH(*ps, vals[0]);
++		SSET_MIN_ICON_HEIGHT(*ps, vals[1]);
++		SSET_MAX_ICON_WIDTH(*ps, vals[2]);
++		SSET_MAX_ICON_HEIGHT(*ps, vals[3]);
++
++		ps->flags.has_icon_size_limits = 1;
++		ps->flag_mask.has_icon_size_limits = 1;
++		ps->change_mask.has_icon_size_limits = 1;
++		break;
++	default:
++		fvwm_msg(
++			ERR, "CMD_Style",
++			"IconSize requires exactly 0, 2 or 4"
++			" numerical arguments");
++		break;
++	}
++
++	return rest;
++}
++
++static char *style_parse_icon_box_style(
++	icon_boxes **ret_ib, char *option, char *rest, window_style *ps)
++{
++	icon_boxes *IconBoxes = NULL;
++	Bool is_screen_given = False;
++	int val[4];
++	int num;
++	int i;
++
++	option = PeekToken(rest, NULL);
++	if (!option || StrEquals(option, "none"))
++	{
++		option = PeekToken(rest, &rest);
++		/* delete icon boxes from style */
++		if (SGET_ICON_BOXES(*ps))
++		{
++			remove_icon_boxes_from_style(ps);
++		}
++		(*ret_ib) = NULL;
++		if (option)
++		{
++			/* disable default icon box */
++			S_SET_DO_IGNORE_ICON_BOXES(SCF(*ps), 1);
++		}
++		else
++		{
++			/* use default icon box */
++			S_SET_DO_IGNORE_ICON_BOXES(SCF(*ps), 0);
++		}
++		S_SET_DO_IGNORE_ICON_BOXES(SCM(*ps), 1);
++		S_SET_DO_IGNORE_ICON_BOXES(SCC(*ps), 1);
++		ps->flags.has_icon_boxes = 0;
++		ps->flag_mask.has_icon_boxes = 1;
++		ps->change_mask.has_icon_boxes = 1;
++		return rest;
++	}
++
++	/* otherwise try to parse the icon box */
++	IconBoxes = (icon_boxes *)safemalloc(sizeof(icon_boxes));
++	/* clear it */
++	memset(IconBoxes, 0, sizeof(icon_boxes));
++	IconBoxes->IconScreen = FSCREEN_GLOBAL;
++	/* init grid x */
++	IconBoxes->IconGrid[0] = 3;
++	/* init grid y */
++	IconBoxes->IconGrid[1] = 3;
++
++	/* check for screen (for 4 numbers) */
++	if (StrEquals(option, "screen"))
++	{
++		is_screen_given = True;
++		option = PeekToken(rest, &rest); /* skip screen */
++		option = PeekToken(rest, &rest); /* get the screen spec */
++		IconBoxes->IconScreen =
++			FScreenGetScreenArgument(option, FSCREEN_SPEC_PRIMARY);
++	}
++
++	/* try for 4 numbers x y x y */
++	num = GetIntegerArguments(rest, NULL, val, 4);
++
++	/* if 4 numbers */
++	if (num == 4)
++	{
++		for (i = 0; i < 4; i++)
++		{
++			/* make sure the value fits into a short */
++			if (val[i] < -32768)
++			{
++				val[i] = -32768;
++			}
++			if (val[i] > 32767)
++			{
++				val[i] = 32767;
++			}
++			IconBoxes->IconBox[i] = val[i];
++			/* If leading minus sign */
++			option = PeekToken(rest, &rest);
++			if (option[0] == '-')
++			{
++				IconBoxes->IconSign[i]='-';
++			} /* end leading minus sign */
++		}
++		/* Note: here there is no test for valid co-ords, use geom */
++	}
++	else if  (is_screen_given)
++	{
++		/* screen-spec is given but not 4 numbers */
++		fvwm_msg(
++			ERR,"CMD_Style",
++			"IconBox requires 4 numbers if screen is given!"
++			" Invalid: <%s>.", option);
++		/* Drop the box */
++		free(IconBoxes);
++		/* forget about it */
++		IconBoxes = 0;
++	}
++	else
++	{
++		/* Not 4 numeric args dje */
++		/* bigger than =32767x32767+32767+32767 */
++		int geom_flags;
++		int l;
++		int width;
++		int height;
++
++		/* read in 1 word w/o advancing */
++		option = PeekToken(rest, NULL);
++		if (!option)
++		{
++			return rest;
++		}
++		l = strlen(option);
++		if (l > 0 && l < 24)
++		{
++			/* advance */
++			option = PeekToken(rest, &rest);
++			/* if word found, not too long */
++			geom_flags = FScreenParseGeometryWithScreen(
++				option, &IconBoxes->IconBox[0],
++				&IconBoxes->IconBox[1],	(unsigned int*)&width,
++				(unsigned int*)&height,
++				&IconBoxes->IconScreen);
++			if (width == 0 || !(geom_flags & WidthValue))
++			{
++				/* zero width is invalid */
++				fvwm_msg(
++					ERR,"CMD_Style",
++					"IconBox requires 4 numbers or"
++					" geometry! Invalid string <%s>.",
++					option);
++				/* Drop the box */
++				free(IconBoxes);
++				/* forget about it */
++				IconBoxes = 0;
++			}
++			else
++			{
++				/* got valid iconbox geom */
++				if (geom_flags & XNegative)
++				{
++					IconBoxes->IconBox[0] =
++						/* neg x coord */
++						IconBoxes->IconBox[0] -
++						width - 2;
++					/* save for later */
++					IconBoxes->IconSign[0]='-';
++					IconBoxes->IconSign[2]='-';
++				}
++				if (geom_flags & YNegative)
++				{
++					IconBoxes->IconBox[1] =
++						/* neg y coord */
++						IconBoxes->IconBox[1]
++						- height -2;
++					/* save for later */
++					IconBoxes->IconSign[1]='-';
++					IconBoxes->IconSign[3]='-';
++				}
++				/* x + wid = right x */
++				IconBoxes->IconBox[2] =
++					width + IconBoxes->IconBox[0];
++				/* y + height = bottom y */
++				IconBoxes->IconBox[3] =
++					height + IconBoxes->IconBox[1];
++			} /* end icon geom worked */
++		}
++		else
++		{
++			/* no word or too long; drop the box */
++			free(IconBoxes);
++			/* forget about it */
++			IconBoxes = 0;
++		} /* end word found, not too long */
++	} /* end not 4 args */
++	/* If we created an IconBox, put it in the chain. */
++	if (IconBoxes != 0)
++	{
++		/* no error */
++		if (SGET_ICON_BOXES(*ps) == 0)
++		{
++			/* first one, chain to root */
++			SSET_ICON_BOXES(*ps, IconBoxes);
++		}
++		else
++		{
++			/* else not first one, add to end of chain */
++			(*ret_ib)->next = IconBoxes;
++		} /* end not first one */
++		/* new current box. save for grid */
++		(*ret_ib) = IconBoxes;
++	} /* end no error */
++	S_SET_DO_IGNORE_ICON_BOXES(SCF(*ps), 0);
++	S_SET_DO_IGNORE_ICON_BOXES(SCM(*ps), 1);
++	S_SET_DO_IGNORE_ICON_BOXES(SCC(*ps), 1);
++	ps->flags.has_icon_boxes = !!(SGET_ICON_BOXES(*ps));
++	ps->flag_mask.has_icon_boxes = 1;
++	ps->change_mask.has_icon_boxes = 1;
++
++	return rest;
++}
++
++static char *style_parse_icon_grid_style(
++	char *option, char *rest, window_style *ps, icon_boxes *ib)
++{
++	int val[4];
++	int num;
++	int i;
++
++	/* The grid always affects the prior iconbox */
++	if (ib == 0)
++	{
++		/* If no current box */
++		fvwm_msg(
++			ERR,"CMD_Style",
++			"IconGrid must follow an IconBox in same Style"
++			" command");
++		return rest;
++	}
++	/* have a place to grid */
++	/* 2 ints */
++	num = GetIntegerArguments(rest, &rest, val, 2);
++	if (num != 2 || val[0] < 1 || val[1] < 1)
++	{
++		fvwm_msg(
++			ERR,"CMD_Style",
++			"IconGrid needs 2 numbers > 0. Got %d numbers."
++			" x=%d y=%d!", num, val[0], val[1]);
++		/* reset grid */
++		ib->IconGrid[0] = 3;
++		ib->IconGrid[1] = 3;
++	}
++	else
++	{
++		for (i = 0; i < 2; i++)
++		{
++			ib->IconGrid[i] = val[i];
++		}
++	} /* end bad grid */
++
++	return rest;
++}
++
++static char *style_parse_icon_fill_style(
++	char *option, char *rest, window_style *ps, icon_boxes *ib)
++{
++	/* first  type direction parsed */
++	unsigned char IconFill_1;
++	/* second type direction parsed */
++	unsigned char IconFill_2;
++
++	/* direction to fill iconbox */
++	/* The fill always affects the prior iconbox */
++	if (ib == 0)
++	{
++		/* If no current box */
++		fvwm_msg(
++			ERR,"CMD_Style",
++			"IconFill must follow an IconBox in same Style"
++			" command");
++		return rest;
++	}
++	/* have a place to fill */
++	option = PeekToken(rest, &rest);
++	/* top/bot/lft/rgt */
++	if (!option || Get_TBLR(option, &IconFill_1) == 0)
++	{
++		/* its wrong */
++		if (!option)
++		{
++			option = "(none)";
++		}
++		fvwm_msg(
++			ERR,"CMD_Style",
++			"IconFill must be followed by T|B|R|L, found"
++			" %s.", option);
++		return rest;
++	}
++	/* first word valid */
++
++	/* read in second word */
++	option = PeekToken(rest, &rest);
++	/* top/bot/lft/rgt */
++	if (!option || Get_TBLR(option, &IconFill_2) == 0)
++	{
++		/* its wrong */
++		if (!option)
++		{
++			option = "(none)";
++		}
++		fvwm_msg(
++			ERR,"CMD_Style",
++			"IconFill must be followed by T|B|R|L,"
++			" found %s.", option);
++		return rest;
++	}
++	if ((IconFill_1 & ICONFILLHRZ) == (IconFill_2 & ICONFILLHRZ))
++	{
++		fvwm_msg(
++			ERR, "CMD_Style",
++			"IconFill must specify a horizontal"
++			" and vertical direction.");
++		return rest;
++	}
++	/* Its valid! */
++	/* merge in flags */
++	ib->IconFlags |= IconFill_1;
++	/* ignore horiz in 2nd arg */
++	IconFill_2 &= ~ICONFILLHRZ;
++	/* merge in flags */
++	ib->IconFlags |= IconFill_2;
++
++	return rest;
++}
++
++static Bool style_parse_one_style_option(
++	char *token, char *rest, char **ret_rest, char *prefix,
++	window_style *ps, icon_boxes **cur_ib)
++{
++	window_style *add_style;
++	/* work area for button number */
++	int num;
++	int i;
++	int tmpno[3] = { -1, -1, -1 };
++	int val[4];
++	int spargs = 0;
++	Bool found;
++	int on;
++	char *token_l = NULL;
++
++	found = True;
++	on = 1;
++	while (token[0] == '!')
++	{
++		on ^= 1;
++		token++;
++	}
++	if (prefix != NULL && *prefix != 0)
++	{
++		int l;
++
++		l = strlen(prefix);
++		if (strncasecmp(token, prefix, l) != 0)
++		{
++			/* add missing prefix */
++			token_l = (char *)safemalloc(l + strlen(token) + 1);
++			strcpy(token_l, prefix);
++			strcat(token_l, token);
++			token = token_l;
++		}
++	}
++	switch (tolower(token[0]))
++	{
++	case 'a':
++		if (StrEquals(token, "ACTIVEPLACEMENT"))
++		{
++			ps->flags.placement_mode &= (~PLACE_RANDOM);
++			ps->flag_mask.placement_mode |= PLACE_RANDOM;
++			ps->change_mask.placement_mode |= PLACE_RANDOM;
++		}
++		else if (StrEquals(token, "ACTIVEPLACEMENTHONORSSTARTSONPAGE"))
++		{
++			ps->flags.manual_placement_honors_starts_on_page = on;
++			ps->flag_mask.manual_placement_honors_starts_on_page =
++				1;
++			ps->change_mask.manual_placement_honors_starts_on_page
++				= 1;
++		}
++		else if (StrEquals(
++				 token, "ACTIVEPLACEMENTIGNORESSTARTSONPAGE"))
++		{
++			ps->flags.manual_placement_honors_starts_on_page = !on;
++			ps->flag_mask.manual_placement_honors_starts_on_page =
++				1;
++			ps->change_mask.manual_placement_honors_starts_on_page
++				= 1;
++		}
++		else if (StrEquals(token, "AllowRestack"))
++		{
++			S_SET_DO_IGNORE_RESTACK(SCF(*ps), !on);
++			S_SET_DO_IGNORE_RESTACK(SCM(*ps), 1);
++			S_SET_DO_IGNORE_RESTACK(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "AllowMaximizeFixedSize"))
++		{
++			S_SET_MAXIMIZE_FIXED_SIZE_DISALLOWED(SCF(*ps), !on);
++			S_SET_MAXIMIZE_FIXED_SIZE_DISALLOWED(SCM(*ps), 1);
++			S_SET_MAXIMIZE_FIXED_SIZE_DISALLOWED(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'b':
++		if (StrEquals(token, "BackColor"))
++		{
++			rest = GetNextToken(rest, &token);
++			if (token)
++			{
++				SAFEFREE(SGET_BACK_COLOR_NAME(*ps));
++				SSET_BACK_COLOR_NAME(*ps, token);
++				ps->flags.has_color_back = 1;
++				ps->flag_mask.has_color_back = 1;
++				ps->change_mask.has_color_back = 1;
++				ps->flags.use_colorset = 0;
++				ps->flag_mask.use_colorset = 1;
++				ps->change_mask.use_colorset = 1;
++			}
++			else
++			{
++				fvwm_msg(
++					ERR, "style_parse_on_estyle_option",
++					"Style BackColor requires color"
++					" argument");
++			}
++		}
++		else if (StrEquals(token, "Button"))
++		{
++			rest = style_parse_button_style(ps, rest, on);
++		}
++		else if (StrEquals(token, "BorderWidth"))
++		{
++			if (GetIntegerArguments(rest, &rest, val, 1))
++			{
++				SSET_BORDER_WIDTH(*ps, (short)*val);
++				ps->flags.has_border_width = 1;
++				ps->flag_mask.has_border_width = 1;
++				ps->change_mask.has_border_width = 1;
++			}
++			else
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"Style BorderWidth requires width"
++					" argument");
++			}
++		}
++		else if (StrEquals(token, "BackingStore"))
++		{
++			ps->flags.use_backing_store = BACKINGSTORE_ON;
++			ps->flag_mask.use_backing_store = BACKINGSTORE_MASK;
++			ps->change_mask.use_backing_store = BACKINGSTORE_MASK;
++		}
++		else if (StrEquals(token, "BackingStoreOff"))
++		{
++			ps->flags.use_backing_store = BACKINGSTORE_OFF;
++			ps->flag_mask.use_backing_store = BACKINGSTORE_MASK;
++			ps->change_mask.use_backing_store = BACKINGSTORE_MASK;
++		}
++		else if (StrEquals(token, "BackingStoreWindowDefault"))
++		{
++			ps->flags.use_backing_store = BACKINGSTORE_DEFAULT;
++			ps->flag_mask.use_backing_store = BACKINGSTORE_MASK;
++			ps->change_mask.use_backing_store = BACKINGSTORE_MASK;
++		}
++		else if (StrEquals(token, "BorderColorset"))
++		{
++			*val = -1;
++			GetIntegerArguments(rest, &rest, val, 1);
++			SSET_BORDER_COLORSET(*ps, *val);
++			alloc_colorset(*val);
++			ps->flags.use_border_colorset = (*val >= 0);
++			ps->flag_mask.use_border_colorset = 1;
++			ps->change_mask.use_border_colorset = 1;
++		}
++		else if (StrEquals(token, "BottomTitleRotated"))
++		{
++			S_SET_IS_BOTTOM_TITLE_ROTATED(SCF(*ps), on);
++			S_SET_IS_BOTTOM_TITLE_ROTATED(SCM(*ps), 1);
++			S_SET_IS_BOTTOM_TITLE_ROTATED(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "BottomTitleNotRotated"))
++		{
++			S_SET_IS_BOTTOM_TITLE_ROTATED(SCF(*ps), !on);
++			S_SET_IS_BOTTOM_TITLE_ROTATED(SCM(*ps), 1);
++			S_SET_IS_BOTTOM_TITLE_ROTATED(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "Borders"))
++		{
++			S_SET_HAS_NO_BORDER(SCF(*ps), !on);
++			S_SET_HAS_NO_BORDER(SCM(*ps), 1);
++			S_SET_HAS_NO_BORDER(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'c':
++		if (StrEquals(token, "CenterPlacement"))
++		{
++			ps->flags.placement_mode = PLACE_CENTER;
++			ps->flag_mask.placement_mode = PLACE_MASK;
++			ps->change_mask.placement_mode = PLACE_MASK;
++		}
++		else if (StrEquals(token, "CascadePlacement"))
++		{
++			ps->flags.placement_mode = PLACE_CASCADE;
++			ps->flag_mask.placement_mode = PLACE_MASK;
++			ps->change_mask.placement_mode = PLACE_MASK;
++		}
++		else if (StrEquals(token, "CLEVERPLACEMENT"))
++		{
++			ps->flags.placement_mode |= PLACE_CLEVER;
++			ps->flag_mask.placement_mode |= PLACE_CLEVER;
++			ps->change_mask.placement_mode |= PLACE_CLEVER;
++		}
++		else if (StrEquals(token, "CleverPlacementOff"))
++		{
++			ps->flags.placement_mode &= (~PLACE_CLEVER);
++			ps->flag_mask.placement_mode |= PLACE_CLEVER;
++			ps->change_mask.placement_mode |= PLACE_CLEVER;
++		}
++		else if (StrEquals(token, "CaptureHonorsStartsOnPage"))
++		{
++			ps->flags.capture_honors_starts_on_page = on;
++			ps->flag_mask.capture_honors_starts_on_page = 1;
++			ps->change_mask.capture_honors_starts_on_page = 1;
++		}
++		else if (StrEquals(token, "CaptureIgnoresStartsonPage"))
++		{
++			ps->flags.capture_honors_starts_on_page = !on;
++			ps->flag_mask.capture_honors_starts_on_page = 1;
++			ps->change_mask.capture_honors_starts_on_page = 1;
++		}
++		else if (StrEquals(token, "ColorSet"))
++		{
++			*val = -1;
++			GetIntegerArguments(rest, &rest, val, 1);
++			if (*val < 0)
++			{
++				*val = -1;
++			}
++			SSET_COLORSET(*ps, *val);
++			alloc_colorset(*val);
++			ps->flags.use_colorset = (*val >= 0);
++			ps->flag_mask.use_colorset = 1;
++			ps->change_mask.use_colorset = 1;
++		}
++		else if (StrEquals(token, "Color"))
++		{
++			char c = 0;
++			char *next;
++
++			next = GetNextToken(rest, &token);
++			if (token == NULL)
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"Color Style requires a color"
++					" argument");
++				break;
++			}
++			if (strncasecmp(token, "rgb:", 4) == 0)
++			{
++				char *s;
++				int i;
++
++				/* spool to third '/' */
++				for (i = 0, s = token + 4; *s && i < 3; s++)
++				{
++					if (*s == '/')
++					{
++						i++;
++					}
++				}
++				s--;
++				if (i == 3)
++				{
++					*s = 0;
++					/* spool to third '/' in original
++					 * string too */
++					for (i = 0, s = rest; *s && i < 3; s++)
++					{
++						if (*s == '/')
++						{
++							i++;
++						}
++					}
++					next = s - 1;
++				}
++			}
++			else
++			{
++				free(token);
++				next = DoGetNextToken(
++					rest, &token, NULL, ",/", &c);
++			}
++			rest = next;
++			SAFEFREE(SGET_FORE_COLOR_NAME(*ps));
++			SSET_FORE_COLOR_NAME(*ps, token);
++			ps->flags.has_color_fore = 1;
++			ps->flag_mask.has_color_fore = 1;
++			ps->change_mask.has_color_fore = 1;
++			ps->flags.use_colorset = 0;
++			ps->flag_mask.use_colorset = 1;
++			ps->change_mask.use_colorset = 1;
++
++			/* skip over '/' */
++			if (c != '/')
++			{
++				while (rest && *rest &&
++				       isspace((unsigned char)*rest) &&
++				       *rest != ',' && *rest != '/')
++				{
++					rest++;
++				}
++				if (*rest == '/')
++				{
++					rest++;
++				}
++			}
++
++			rest=GetNextToken(rest, &token);
++			if (!token)
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"Color Style called with incomplete"
++					" color argument.");
++				break;
++			}
++			SAFEFREE(SGET_BACK_COLOR_NAME(*ps));
++			SSET_BACK_COLOR_NAME(*ps, token);
++			ps->flags.has_color_back = 1;
++			ps->flag_mask.has_color_back = 1;
++			ps->change_mask.has_color_back = 1;
++			break;
++		}
++		else if (StrEquals(token, "CirculateSkipIcon"))
++		{
++			S_SET_DO_CIRCULATE_SKIP_ICON(SCF(*ps), on);
++			S_SET_DO_CIRCULATE_SKIP_ICON(SCM(*ps), 1);
++			S_SET_DO_CIRCULATE_SKIP_ICON(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "CirculateSkipShaded"))
++		{
++			S_SET_DO_CIRCULATE_SKIP_SHADED(SCF(*ps), on);
++			S_SET_DO_CIRCULATE_SKIP_SHADED(SCM(*ps), 1);
++			S_SET_DO_CIRCULATE_SKIP_SHADED(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "CirculateHitShaded"))
++		{
++			S_SET_DO_CIRCULATE_SKIP_SHADED(SCF(*ps), !on);
++			S_SET_DO_CIRCULATE_SKIP_SHADED(SCM(*ps), 1);
++			S_SET_DO_CIRCULATE_SKIP_SHADED(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "CirculateHitIcon"))
++		{
++			S_SET_DO_CIRCULATE_SKIP_ICON(SCF(*ps), !on);
++			S_SET_DO_CIRCULATE_SKIP_ICON(SCM(*ps), 1);
++			S_SET_DO_CIRCULATE_SKIP_ICON(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "ClickToFocus"))
++		{
++			style_set_old_focus_policy(ps, 0);
++		}
++		else if (StrEquals(token, "ClickToFocusPassesClick"))
++		{
++			FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCF(*ps)), on);
++			FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++			FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCF(*ps)), on);
++			FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "ClickToFocusPassesClickOff"))
++		{
++			FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCF(*ps)), !on);
++			FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++			FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCF(*ps)), !on);
++			FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "ClickToFocusRaises"))
++		{
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCF(*ps)), on);
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCC(*ps)), 1);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCF(*ps)), on);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "ClickToFocusRaisesOff"))
++		{
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCF(*ps)), !on);
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCC(*ps)), 1);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCF(*ps)), !on);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "CirculateSkip"))
++		{
++			S_SET_DO_CIRCULATE_SKIP(SCF(*ps), on);
++			S_SET_DO_CIRCULATE_SKIP(SCM(*ps), 1);
++			S_SET_DO_CIRCULATE_SKIP(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "CirculateHit"))
++		{
++			S_SET_DO_CIRCULATE_SKIP(SCF(*ps), !on);
++			S_SET_DO_CIRCULATE_SKIP(SCM(*ps), 1);
++			S_SET_DO_CIRCULATE_SKIP(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "Closable"))
++		{
++			S_SET_IS_UNCLOSABLE(SCF(*ps), !on);
++			S_SET_IS_UNCLOSABLE(SCM(*ps), 1);
++			S_SET_IS_UNCLOSABLE(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'd':
++		if (StrEquals(token, "DepressableBorder"))
++		{
++			S_SET_HAS_DEPRESSABLE_BORDER(SCF(*ps), on);
++			S_SET_HAS_DEPRESSABLE_BORDER(SCM(*ps), 1);
++			S_SET_HAS_DEPRESSABLE_BORDER(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "DecorateTransient"))
++		{
++			ps->flags.do_decorate_transient = on;
++			ps->flag_mask.do_decorate_transient = 1;
++			ps->change_mask.do_decorate_transient = 1;
++		}
++		else if (StrEquals(token, "DumbPlacement"))
++		{
++			ps->flags.placement_mode &= (~PLACE_SMART);
++			ps->flag_mask.placement_mode |= PLACE_SMART;
++			ps->change_mask.placement_mode |= PLACE_SMART;
++		}
++		else if (StrEquals(token, "DONTRAISETRANSIENT"))
++		{
++			S_SET_DO_RAISE_TRANSIENT(SCF(*ps), !on);
++			S_SET_DO_RAISE_TRANSIENT(SCM(*ps), 1);
++			S_SET_DO_RAISE_TRANSIENT(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "DONTLOWERTRANSIENT"))
++		{
++			S_SET_DO_LOWER_TRANSIENT(SCF(*ps), !on);
++			S_SET_DO_LOWER_TRANSIENT(SCM(*ps), 1);
++			S_SET_DO_LOWER_TRANSIENT(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "DontStackTransientParent"))
++		{
++			S_SET_DO_STACK_TRANSIENT_PARENT(SCF(*ps), !on);
++			S_SET_DO_STACK_TRANSIENT_PARENT(SCM(*ps), 1);
++			S_SET_DO_STACK_TRANSIENT_PARENT(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'e':
++		if (StrEquals(token, "ExactWindowName"))
++		{
++			S_SET_USE_INDEXED_WINDOW_NAME(SCF(*ps), !on);
++			S_SET_USE_INDEXED_WINDOW_NAME(SCM(*ps), 1);
++			S_SET_USE_INDEXED_WINDOW_NAME(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "ExactIconName"))
++		{
++			S_SET_USE_INDEXED_ICON_NAME(SCF(*ps), !on);
++			S_SET_USE_INDEXED_ICON_NAME(SCM(*ps), 1);
++			S_SET_USE_INDEXED_ICON_NAME(SCC(*ps), 1);
++		}
++		else
++		{
++			found = EWMH_CMD_Style(token, ps, on);
++		}
++		break;
++
++	case 'f':
++		if (strncasecmp(token, "fp", 2) == 0)
++		{
++			/* parse focus policy options */
++			found = style_parse_focus_policy_style(
++				token + 2, rest, &rest, (on) ? False : True,
++				&S_FOCUS_POLICY(SCF(*ps)),
++				&S_FOCUS_POLICY(SCM(*ps)),
++				&S_FOCUS_POLICY(SCC(*ps)));
++		}
++		else if (StrEquals(token, "Font"))
++		{
++			SAFEFREE(SGET_WINDOW_FONT(*ps));
++			rest = GetNextToken(rest, &token);
++			SSET_WINDOW_FONT(*ps, token);
++			S_SET_HAS_WINDOW_FONT(SCF(*ps), (token != NULL));
++			S_SET_HAS_WINDOW_FONT(SCM(*ps), 1);
++			S_SET_HAS_WINDOW_FONT(SCC(*ps), 1);
++
++		}
++		else if (StrEquals(token, "ForeColor"))
++		{
++			rest = GetNextToken(rest, &token);
++			if (token)
++			{
++				SAFEFREE(SGET_FORE_COLOR_NAME(*ps));
++				SSET_FORE_COLOR_NAME(*ps, token);
++				ps->flags.has_color_fore = 1;
++				ps->flag_mask.has_color_fore = 1;
++				ps->change_mask.has_color_fore = 1;
++				ps->flags.use_colorset = 0;
++				ps->flag_mask.use_colorset = 1;
++				ps->change_mask.use_colorset = 1;
++			}
++			else
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"ForeColor Style needs color argument"
++					);
++			}
++		}
++		else if (StrEquals(token, "FVWMBUTTONS"))
++		{
++			S_SET_HAS_MWM_BUTTONS(SCF(*ps), !on);
++			S_SET_HAS_MWM_BUTTONS(SCM(*ps), 1);
++			S_SET_HAS_MWM_BUTTONS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "FVWMBORDER"))
++		{
++			S_SET_HAS_MWM_BORDER(SCF(*ps), !on);
++			S_SET_HAS_MWM_BORDER(SCM(*ps), 1);
++			S_SET_HAS_MWM_BORDER(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "FocusFollowsMouse"))
++		{
++			style_set_old_focus_policy(ps, 1);
++		}
++		else if (StrEquals(token, "FirmBorder"))
++		{
++			S_SET_HAS_DEPRESSABLE_BORDER(SCF(*ps), !on);
++			S_SET_HAS_DEPRESSABLE_BORDER(SCM(*ps), 1);
++			S_SET_HAS_DEPRESSABLE_BORDER(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "FixedPosition") ||
++			 StrEquals(token, "FixedUSPosition"))
++		{
++			S_SET_IS_FIXED(SCF(*ps), on);
++			S_SET_IS_FIXED(SCM(*ps), 1);
++			S_SET_IS_FIXED(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "FixedPPosition"))
++		{
++			S_SET_IS_FIXED_PPOS(SCF(*ps), on);
++			S_SET_IS_FIXED_PPOS(SCM(*ps), 1);
++			S_SET_IS_FIXED_PPOS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "FixedSize") ||
++			 StrEquals(token, "FixedUSSize"))
++		{
++			S_SET_IS_SIZE_FIXED(SCF(*ps), on);
++			S_SET_IS_SIZE_FIXED(SCM(*ps), 1);
++			S_SET_IS_SIZE_FIXED(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "FixedPSize"))
++		{
++			S_SET_IS_PSIZE_FIXED(SCF(*ps), on);
++			S_SET_IS_PSIZE_FIXED(SCM(*ps), 1);
++			S_SET_IS_PSIZE_FIXED(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'g':
++		if (StrEquals(token, "GrabFocusOff"))
++		{
++			FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCF(*ps)), !on);
++			FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "GrabFocus"))
++		{
++			FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCF(*ps)), on);
++			FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "GrabFocusTransientOff"))
++		{
++			FPS_GRAB_FOCUS_TRANSIENT(
++				S_FOCUS_POLICY(SCF(*ps)), !on);
++			FPS_GRAB_FOCUS_TRANSIENT(S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_GRAB_FOCUS_TRANSIENT(S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "GrabFocusTransient"))
++		{
++			FPS_GRAB_FOCUS_TRANSIENT(S_FOCUS_POLICY(SCF(*ps)), on);
++			FPS_GRAB_FOCUS_TRANSIENT(S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_GRAB_FOCUS_TRANSIENT(S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "GNOMEIgnoreHints"))
++		{
++			S_SET_DO_IGNORE_GNOME_HINTS(SCF(*ps), on);
++			S_SET_DO_IGNORE_GNOME_HINTS(SCM(*ps), 1);
++			S_SET_DO_IGNORE_GNOME_HINTS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "GNOMEUseHints"))
++		{
++			S_SET_DO_IGNORE_GNOME_HINTS(SCF(*ps), !on);
++			S_SET_DO_IGNORE_GNOME_HINTS(SCM(*ps), 1);
++			S_SET_DO_IGNORE_GNOME_HINTS(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'h':
++		if (StrEquals(token, "HintOverride"))
++		{
++			S_SET_HAS_MWM_OVERRIDE(SCF(*ps), on);
++			S_SET_HAS_MWM_OVERRIDE(SCM(*ps), 1);
++			S_SET_HAS_MWM_OVERRIDE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "Handles"))
++		{
++			ps->flags.has_no_handles = !on;
++			ps->flag_mask.has_no_handles = 1;
++			ps->change_mask.has_no_handles = 1;
++		}
++		else if (StrEquals(token, "HandleWidth"))
++		{
++			if (GetIntegerArguments(rest, &rest, val, 1))
++			{
++				SSET_HANDLE_WIDTH(*ps, (short)*val);
++				ps->flags.has_handle_width = 1;
++				ps->flag_mask.has_handle_width = 1;
++				ps->change_mask.has_handle_width = 1;
++			}
++			else
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"HandleWidth Style needs width"
++					" argument");
++			}
++		}
++		else if (StrEquals(token, "HilightFore"))
++		{
++			rest = GetNextToken(rest, &token);
++			if (token)
++			{
++				SAFEFREE(SGET_FORE_COLOR_NAME_HI(*ps));
++				SSET_FORE_COLOR_NAME_HI(*ps, token);
++				ps->flags.has_color_fore_hi = 1;
++				ps->flag_mask.has_color_fore_hi = 1;
++				ps->change_mask.has_color_fore_hi = 1;
++				ps->flags.use_colorset_hi = 0;
++				ps->flag_mask.use_colorset_hi = 1;
++				ps->change_mask.use_colorset_hi = 1;
++			}
++			else
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"HilightFore Style needs color"
++					" argument");
++			}
++		}
++		else if (StrEquals(token, "HilightBack"))
++		{
++			rest = GetNextToken(rest, &token);
++			if (token)
++			{
++				SAFEFREE(SGET_BACK_COLOR_NAME_HI(*ps));
++				SSET_BACK_COLOR_NAME_HI(*ps, token);
++				ps->flags.has_color_back_hi = 1;
++				ps->flag_mask.has_color_back_hi = 1;
++				ps->change_mask.has_color_back_hi = 1;
++				ps->flags.use_colorset_hi = 0;
++				ps->flag_mask.use_colorset_hi = 1;
++				ps->change_mask.use_colorset_hi = 1;
++			}
++			else
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"HilightBack Style needs color"
++					" argument");
++			}
++		}
++		else if (StrEquals(token, "HilightColorset"))
++		{
++			*val = -1;
++			GetIntegerArguments(rest, &rest, val, 1);
++			SSET_COLORSET_HI(*ps, *val);
++			alloc_colorset(*val);
++			ps->flags.use_colorset_hi = (*val >= 0);
++			ps->flag_mask.use_colorset_hi = 1;
++			ps->change_mask.use_colorset_hi = 1;
++		}
++		else if (StrEquals(token, "HilightBorderColorset"))
++		{
++			*val = -1;
++			GetIntegerArguments(rest, &rest, val, 1);
++			SSET_BORDER_COLORSET_HI(*ps, *val);
++			alloc_colorset(*val);
++			ps->flags.use_border_colorset_hi = (*val >= 0);
++			ps->flag_mask.use_border_colorset_hi = 1;
++			ps->change_mask.use_border_colorset_hi = 1;
++		}
++		else if (StrEquals(token, "HilightIconTitleColorset"))
++		{
++			*val = -1;
++			GetIntegerArguments(rest, &rest, val, 1);
++			SSET_ICON_TITLE_COLORSET_HI(*ps, *val);
++			alloc_colorset(*val);
++			ps->flags.use_icon_title_colorset_hi = (*val >= 0);
++			ps->flag_mask.use_icon_title_colorset_hi = 1;
++			ps->change_mask.use_icon_title_colorset_hi = 1;
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'i':
++		if (StrEquals(token, "Icon"))
++		{
++			if (on == 1)
++			{
++				rest = GetNextToken(rest, &token);
++
++				SAFEFREE(SGET_ICON_NAME(*ps));
++				SSET_ICON_NAME(*ps,token);
++				ps->flags.has_icon = (token != NULL);
++				ps->flag_mask.has_icon = 1;
++				ps->change_mask.has_icon = 1;
++
++				S_SET_IS_ICON_SUPPRESSED(SCF(*ps), 0);
++				S_SET_IS_ICON_SUPPRESSED(SCM(*ps), 1);
++				S_SET_IS_ICON_SUPPRESSED(SCC(*ps), 1);
++			}
++			else
++			{
++				S_SET_IS_ICON_SUPPRESSED(SCF(*ps), 1);
++				S_SET_IS_ICON_SUPPRESSED(SCM(*ps), 1);
++				S_SET_IS_ICON_SUPPRESSED(SCC(*ps), 1);
++			}
++		}
++		else if (StrEquals(token, "IconBackgroundColorset"))
++		{
++			*val = -1;
++			GetIntegerArguments(rest, &rest, val, 1);
++			SSET_ICON_BACKGROUND_COLORSET(*ps, *val);
++			alloc_colorset(*val);
++			ps->flags.use_icon_background_colorset = (*val >= 0);
++			ps->flag_mask.use_icon_background_colorset = 1;
++			ps->change_mask.use_icon_background_colorset = 1;
++		}
++		else if (StrEquals(token, "IconBackgroundPadding"))
++		{
++			*val = ICON_BACKGROUND_PADDING;
++			GetIntegerArguments(rest, &rest, val, 1);
++			if (*val < 0)
++			{
++				*val = 0;
++			}
++			else if (*val > 50)
++			{
++				*val = 50;
++			}
++			SSET_ICON_BACKGROUND_PADDING(*ps, (unsigned char)*val);
++			ps->flags.has_icon_background_padding = 1;
++			ps->flag_mask.has_icon_background_padding = 1;
++			ps->change_mask.has_icon_background_padding = 1;
++		}
++		else if (StrEquals(token, "IconBackgroundRelief"))
++		{
++			*val = ICON_RELIEF_WIDTH;
++			GetIntegerArguments(rest, &rest, val, 1);
++			if (*val < -50)
++			{
++				*val = -50;
++			}
++			else if (*val > 50)
++			{
++				*val = 50;
++			}
++			SSET_ICON_BACKGROUND_RELIEF(*ps, (signed char)*val);
++			ps->flags.has_icon_background_relief = 1;
++			ps->flag_mask.has_icon_background_relief = 1;
++			ps->change_mask.has_icon_background_relief = 1;
++		}
++		else if (StrEquals(token, "IconFont"))
++		{
++			SAFEFREE(SGET_ICON_FONT(*ps));
++			rest = GetNextToken(rest, &token);
++			SSET_ICON_FONT(*ps, token);
++			S_SET_HAS_ICON_FONT(SCF(*ps), (token != NULL));
++			S_SET_HAS_ICON_FONT(SCM(*ps), 1);
++			S_SET_HAS_ICON_FONT(SCC(*ps), 1);
++
++		}
++		else if (StrEquals(token, "IconOverride"))
++		{
++			S_SET_ICON_OVERRIDE(SCF(*ps), ICON_OVERRIDE);
++			S_SET_ICON_OVERRIDE(SCM(*ps), ICON_OVERRIDE_MASK);
++			S_SET_ICON_OVERRIDE(SCC(*ps), ICON_OVERRIDE_MASK);
++		}
++		else if (StrEquals(token, "IgnoreRestack"))
++		{
++			S_SET_DO_IGNORE_RESTACK(SCF(*ps), on);
++			S_SET_DO_IGNORE_RESTACK(SCM(*ps), 1);
++			S_SET_DO_IGNORE_RESTACK(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "IconTitle"))
++		{
++			S_SET_HAS_NO_ICON_TITLE(SCF(*ps), !on);
++			S_SET_HAS_NO_ICON_TITLE(SCM(*ps), 1);
++			S_SET_HAS_NO_ICON_TITLE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "IconTitleColorset"))
++		{
++			*val = -1;
++			GetIntegerArguments(rest,&rest, val, 1);
++			SSET_ICON_TITLE_COLORSET(*ps, *val);
++			alloc_colorset(*val);
++			ps->flags.use_icon_title_colorset = (*val >= 0);
++			ps->flag_mask.use_icon_title_colorset = 1;
++			ps->change_mask.use_icon_title_colorset = 1;
++		}
++		else if (StrEquals(token, "IconTitleRelief"))
++		{
++			*val = ICON_RELIEF_WIDTH;
++			GetIntegerArguments(rest, &rest, val, 1);
++			if (*val < -50)
++			{
++				*val = -50;
++			}
++			else if (*val > 50)
++			{
++				*val = 50;
++			}
++			SSET_ICON_TITLE_RELIEF(*ps, (signed char)*val);
++			ps->flags.has_icon_title_relief = 1;
++			ps->flag_mask.has_icon_title_relief = 1;
++			ps->change_mask.has_icon_title_relief = 1;
++		}
++		else if (StrEquals(token, "IconSize"))
++		{
++			rest = style_parse_icon_size_style(token, rest, ps);
++		}
++		else if (StrEquals(token, "IconBox"))
++		{
++			rest = style_parse_icon_box_style(cur_ib, token, rest,
++							  ps);
++		} /* end iconbox parameter */
++		else if (StrEquals(token, "ICONGRID"))
++		{
++			rest = style_parse_icon_grid_style(token, rest, ps,
++							   *cur_ib);
++		}
++		else if (StrEquals(token, "ICONFILL"))
++		{
++			rest = style_parse_icon_fill_style(token, rest, ps,
++						    *cur_ib);
++		} /* end iconfill */
++		else if (StrEquals(token, "IconifyWindowGroups"))
++		{
++			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCF(*ps), on);
++			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCM(*ps), 1);
++			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "IconifyWindowGroupsOff"))
++		{
++			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCF(*ps), !on);
++			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCM(*ps), 1);
++			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "Iconifiable"))
++		{
++			S_SET_IS_UNICONIFIABLE(SCF(*ps), !on);
++			S_SET_IS_UNICONIFIABLE(SCM(*ps), 1);
++			S_SET_IS_UNICONIFIABLE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "IndexedWindowName"))
++		{
++			S_SET_USE_INDEXED_WINDOW_NAME(SCF(*ps), on);
++			S_SET_USE_INDEXED_WINDOW_NAME(SCM(*ps), 1);
++			S_SET_USE_INDEXED_WINDOW_NAME(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "IndexedIconName"))
++		{
++			S_SET_USE_INDEXED_ICON_NAME(SCF(*ps), on);
++			S_SET_USE_INDEXED_ICON_NAME(SCM(*ps), 1);
++			S_SET_USE_INDEXED_ICON_NAME(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'j':
++		if (0)
++		{
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'k':
++		if (StrEquals(token, "KeepWindowGroupsOnDesk"))
++		{
++			S_SET_DO_USE_WINDOW_GROUP_HINT(SCF(*ps), on);
++			S_SET_DO_USE_WINDOW_GROUP_HINT(SCM(*ps), 1);
++			S_SET_DO_USE_WINDOW_GROUP_HINT(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'l':
++		if (StrEquals(token, "LeftTitleRotatedCW"))
++		{
++			S_SET_IS_LEFT_TITLE_ROTATED_CW(SCF(*ps), on);
++			S_SET_IS_LEFT_TITLE_ROTATED_CW(SCM(*ps), 1);
++			S_SET_IS_LEFT_TITLE_ROTATED_CW(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "LeftTitleRotatedCCW"))
++		{
++			S_SET_IS_LEFT_TITLE_ROTATED_CW(SCF(*ps), !on);
++			S_SET_IS_LEFT_TITLE_ROTATED_CW(SCM(*ps), 1);
++			S_SET_IS_LEFT_TITLE_ROTATED_CW(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "Lenience"))
++		{
++			FPS_LENIENT(S_FOCUS_POLICY(SCF(*ps)), on);
++			FPS_LENIENT(S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_LENIENT(S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "Layer"))
++		{
++			*val = -1;
++			if (GetIntegerArguments(rest, &rest, val, 1) &&
++			    *val < 0)
++			{
++				fvwm_msg(ERR, "style_parse_one_style_option",
++					 "Layer must be positive or zero.");
++			}
++			if (*val < 0)
++			{
++				SSET_LAYER(*ps, -9);
++				/* mark layer unset */
++				ps->flags.use_layer = 0;
++				ps->flag_mask.use_layer = 1;
++				ps->change_mask.use_layer = 1;
++			}
++			else
++			{
++				SSET_LAYER(*ps, *val);
++				ps->flags.use_layer = 1;
++				ps->flag_mask.use_layer = 1;
++				ps->change_mask.use_layer = 1;
++			}
++		}
++		else if (StrEquals(token, "LOWERTRANSIENT"))
++		{
++			S_SET_DO_LOWER_TRANSIENT(SCF(*ps), on);
++			S_SET_DO_LOWER_TRANSIENT(SCM(*ps), 1);
++			S_SET_DO_LOWER_TRANSIENT(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'm':
++		if (StrEquals(token, "ManualPlacement"))
++		{
++			ps->flags.placement_mode = PLACE_MANUAL;
++			ps->flag_mask.placement_mode = PLACE_MASK;
++			ps->change_mask.placement_mode = PLACE_MASK;
++		}
++		else if (StrEquals(token, "ManualPlacementHonorsStartsOnPage"))
++		{
++			ps->flags.manual_placement_honors_starts_on_page = on;
++			ps->flag_mask.manual_placement_honors_starts_on_page =
++				1;
++			ps->change_mask.manual_placement_honors_starts_on_page
++				= 1;
++		}
++		else if (StrEquals(
++				 token, "ManualPlacementIgnoresStartsOnPage"))
++		{
++			ps->flags.manual_placement_honors_starts_on_page = !on;
++			ps->flag_mask.manual_placement_honors_starts_on_page =
++				1;
++			ps->change_mask.manual_placement_honors_starts_on_page
++				= 1;
++		}
++		else if (StrEquals(token, "Maximizable"))
++		{
++			S_SET_IS_UNMAXIMIZABLE(SCF(*ps), !on);
++			S_SET_IS_UNMAXIMIZABLE(SCM(*ps), 1);
++			S_SET_IS_UNMAXIMIZABLE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "MinOverlapPlacement"))
++		{
++			ps->flags.placement_mode = PLACE_MINOVERLAP;
++			ps->flag_mask.placement_mode = PLACE_MASK;
++			ps->change_mask.placement_mode = PLACE_MASK;
++		}
++		else if (StrEquals(token, "MinOverlapPercentPlacement"))
++		{
++			ps->flags.placement_mode = PLACE_MINOVERLAPPERCENT;
++			ps->flag_mask.placement_mode = PLACE_MASK;
++			ps->change_mask.placement_mode = PLACE_MASK;
++		}
++		else if (StrEquals(token, "MinOverlapPlacementPenalties"))
++		{
++			float f[6] = {-1, -1, -1, -1, -1, -1};
++			Bool bad = False;
++
++			num = 0;
++			if (rest != NULL)
++			{
++				num = sscanf(
++					rest, "%f %f %f %f %f %f", &f[0],
++					&f[1], &f[2], &f[3], &f[4], &f[5]);
++				for (i=0; i < num; i++)
++				{
++					PeekToken(rest,&rest);
++					if (f[i] < 0)
++						bad = True;
++				}
++			}
++			if (bad)
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"Bad argument to MinOverlap"
++					"PlacementPenalties: %s", rest);
++				break;
++			}
++			SSET_NORMAL_PLACEMENT_PENALTY(*ps, 1);
++			SSET_ONTOP_PLACEMENT_PENALTY(
++				*ps, PLACEMENT_AVOID_ONTOP);
++			SSET_ICON_PLACEMENT_PENALTY(*ps, PLACEMENT_AVOID_ICON);
++			SSET_STICKY_PLACEMENT_PENALTY(
++				*ps, PLACEMENT_AVOID_STICKY);
++			SSET_BELOW_PLACEMENT_PENALTY(
++				*ps, PLACEMENT_AVOID_BELOW);
++			SSET_EWMH_STRUT_PLACEMENT_PENALTY(
++				*ps, PLACEMENT_AVOID_EWMH_STRUT);
++			for (i=0; i < num; i++)
++			{
++				(*ps).placement_penalty[i] = f[i];
++			}
++			ps->flags.has_placement_penalty = 1;
++			ps->flag_mask.has_placement_penalty = 1;
++			ps->change_mask.has_placement_penalty = 1;
++		}
++		else if (StrEquals(
++				 token, "MinOverlapPercentPlacementPenalties"))
++		{
++			Bool bad = False;
++
++			num = GetIntegerArguments(rest, &rest, val, 4);
++			for (i=0; i < num; i++)
++			{
++				if (val[i] < 0)
++					bad = True;
++			}
++			if (bad)
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"Bad argument to MinOverlapPercent"
++					"PlacementPenalties: %s", rest);
++				break;
++			}
++			SSET_99_PLACEMENT_PERCENTAGE_PENALTY(
++				*ps, PLACEMENT_AVOID_COVER_99);
++			SSET_95_PLACEMENT_PERCENTAGE_PENALTY(
++				*ps, PLACEMENT_AVOID_COVER_95);
++			SSET_85_PLACEMENT_PERCENTAGE_PENALTY(
++				*ps, PLACEMENT_AVOID_COVER_85);
++			SSET_75_PLACEMENT_PERCENTAGE_PENALTY(
++				*ps, PLACEMENT_AVOID_COVER_75);
++			for (i=0; i < num; i++)
++			{
++				(*ps).placement_percentage_penalty[i] = val[i];
++			}
++			ps->flags.has_placement_percentage_penalty = 1;
++			ps->flag_mask.has_placement_percentage_penalty = 1;
++			ps->change_mask.has_placement_percentage_penalty = 1;
++		}
++		else if (StrEquals(token, "MwmButtons"))
++		{
++			S_SET_HAS_MWM_BUTTONS(SCF(*ps), on);
++			S_SET_HAS_MWM_BUTTONS(SCM(*ps), 1);
++			S_SET_HAS_MWM_BUTTONS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "MiniIcon"))
++		{
++			if (!FMiniIconsSupported)
++			{
++				break;
++			}
++			rest = GetNextToken(rest, &token);
++			if (token)
++			{
++				SAFEFREE(SGET_MINI_ICON_NAME(*ps));
++				SSET_MINI_ICON_NAME(*ps, token);
++				ps->flags.has_mini_icon = 1;
++				ps->flag_mask.has_mini_icon = 1;
++				ps->change_mask.has_mini_icon = 1;
++			}
++			else
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"MiniIcon Style requires an Argument");
++			}
++		}
++		else if (StrEquals(token, "MwmBorder"))
++		{
++			S_SET_HAS_MWM_BORDER(SCF(*ps), on);
++			S_SET_HAS_MWM_BORDER(SCM(*ps), 1);
++			S_SET_HAS_MWM_BORDER(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "MwmDecor"))
++		{
++			ps->flags.has_mwm_decor = on;
++			ps->flag_mask.has_mwm_decor = 1;
++			ps->change_mask.has_mwm_decor = 1;
++		}
++		else if (StrEquals(token, "MwmFunctions"))
++		{
++			ps->flags.has_mwm_functions = on;
++			ps->flag_mask.has_mwm_functions = 1;
++			ps->change_mask.has_mwm_functions = 1;
++		}
++		else if (StrEquals(token, "MouseFocus"))
++		{
++			style_set_old_focus_policy(ps, 1);
++		}
++		else if (StrEquals(token, "MouseFocusClickRaises"))
++		{
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCF(*ps)), on);
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCC(*ps)), 1);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCF(*ps)), on);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "MouseFocusClickRaisesOff"))
++		{
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCF(*ps)), !on);
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_RAISE_FOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCC(*ps)), 1);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCF(*ps)), !on);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
++				S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "MaxWindowSize"))
++		{
++			int val1;
++			int val2;
++			int val1_unit;
++			int val2_unit;
++
++			num = GetTwoArguments(
++				rest, &val1, &val2, &val1_unit, &val2_unit);
++			rest = SkipNTokens(rest, num);
++			if (num != 2)
++			{
++				val1 = DEFAULT_MAX_MAX_WINDOW_WIDTH;
++				val2 = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
++			}
++			else
++			{
++				val1 = val1 * val1_unit / 100;
++				val2 = val2 * val2_unit / 100;
++			}
++			if (val1 < DEFAULT_MIN_MAX_WINDOW_WIDTH)
++			{
++				val1 = DEFAULT_MIN_MAX_WINDOW_WIDTH;
++			}
++			if (val1 > DEFAULT_MAX_MAX_WINDOW_WIDTH || val1 <= 0)
++			{
++				val1 = DEFAULT_MAX_MAX_WINDOW_WIDTH;
++			}
++			if (val2 < DEFAULT_MIN_MAX_WINDOW_HEIGHT)
++			{
++				val2 = DEFAULT_MIN_MAX_WINDOW_HEIGHT;
++			}
++			if (val2 > DEFAULT_MAX_MAX_WINDOW_HEIGHT || val2 <= 0)
++			{
++				val2 = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
++			}
++			SSET_MAX_WINDOW_WIDTH(*ps, val1);
++			SSET_MAX_WINDOW_HEIGHT(*ps, val2);
++			ps->flags.has_max_window_size = 1;
++			ps->flag_mask.has_max_window_size = 1;
++			ps->change_mask.has_max_window_size = 1;
++		}
++		else if (StrEquals(token, "MoveByProgramMethod"))
++		{
++			int i;
++			char *methodlist[] = {
++				"AutoDetect",
++				"UseGravity",
++				"IgnoreGravity",
++				NULL
++			};
++
++			i = GetTokenIndex(rest, methodlist, 0, &rest);
++			if (i == -1)
++			{
++				i = WS_CR_MOTION_METHOD_AUTO;
++			}
++			SCR_MOTION_METHOD(&ps->flags) = i;
++			SCR_MOTION_METHOD(&ps->flag_mask) =
++				WS_CR_MOTION_METHOD_MASK;
++			SCR_MOTION_METHOD(&ps->change_mask) =
++				WS_CR_MOTION_METHOD_MASK;
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'n':
++		if (StrEquals(token, "NoActiveIconOverride"))
++		{
++			S_SET_ICON_OVERRIDE(SCF(*ps), NO_ACTIVE_ICON_OVERRIDE);
++			S_SET_ICON_OVERRIDE(SCM(*ps), ICON_OVERRIDE_MASK);
++			S_SET_ICON_OVERRIDE(SCC(*ps), ICON_OVERRIDE_MASK);
++		}
++		else if (StrEquals(token, "NoIconOverride"))
++		{
++			S_SET_ICON_OVERRIDE(SCF(*ps), NO_ICON_OVERRIDE);
++			S_SET_ICON_OVERRIDE(SCM(*ps), ICON_OVERRIDE_MASK);
++			S_SET_ICON_OVERRIDE(SCC(*ps), ICON_OVERRIDE_MASK);
++		}
++		else if (StrEquals(token, "NoIconTitle"))
++		{
++			S_SET_HAS_NO_ICON_TITLE(SCF(*ps), on);
++			S_SET_HAS_NO_ICON_TITLE(SCM(*ps), 1);
++			S_SET_HAS_NO_ICON_TITLE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "NOICON"))
++		{
++			S_SET_IS_ICON_SUPPRESSED(SCF(*ps), on);
++			S_SET_IS_ICON_SUPPRESSED(SCM(*ps), 1);
++			S_SET_IS_ICON_SUPPRESSED(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "NOTITLE"))
++		{
++			ps->flags.has_no_title = on;
++			ps->flag_mask.has_no_title = 1;
++			ps->change_mask.has_no_title = 1;
++		}
++		else if (StrEquals(token, "NoPPosition"))
++		{
++			ps->flags.use_no_pposition = on;
++			ps->flag_mask.use_no_pposition = 1;
++			ps->change_mask.use_no_pposition = 1;
++		}
++		else if (StrEquals(token, "NoUSPosition"))
++		{
++			ps->flags.use_no_usposition = on;
++			ps->flag_mask.use_no_usposition = 1;
++			ps->change_mask.use_no_usposition = 1;
++		}
++		else if (StrEquals(token, "NoTransientPPosition"))
++		{
++			ps->flags.use_no_transient_pposition = on;
++			ps->flag_mask.use_no_transient_pposition = 1;
++			ps->change_mask.use_no_transient_pposition = 1;
++		}
++		else if (StrEquals(token, "NoTransientUSPosition"))
++		{
++			ps->flags.use_no_transient_usposition = on;
++			ps->flag_mask.use_no_transient_usposition = 1;
++			ps->change_mask.use_no_transient_usposition = 1;
++		}
++		else if (StrEquals(token, "NoIconPosition"))
++		{
++			S_SET_USE_ICON_POSITION_HINT(SCF(*ps), !on);
++			S_SET_USE_ICON_POSITION_HINT(SCM(*ps), 1);
++			S_SET_USE_ICON_POSITION_HINT(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "NakedTransient"))
++		{
++			ps->flags.do_decorate_transient = !on;
++			ps->flag_mask.do_decorate_transient = 1;
++			ps->change_mask.do_decorate_transient = 1;
++		}
++		else if (StrEquals(token, "NODECORHINT"))
++		{
++			ps->flags.has_mwm_decor = !on;
++			ps->flag_mask.has_mwm_decor = 1;
++			ps->change_mask.has_mwm_decor = 1;
++		}
++		else if (StrEquals(token, "NOFUNCHINT"))
++		{
++			ps->flags.has_mwm_functions = !on;
++			ps->flag_mask.has_mwm_functions = 1;
++			ps->change_mask.has_mwm_functions = 1;
++		}
++		else if (StrEquals(token, "NOOVERRIDE"))
++		{
++			S_SET_HAS_MWM_OVERRIDE(SCF(*ps), !on);
++			S_SET_HAS_MWM_OVERRIDE(SCM(*ps), 1);
++			S_SET_HAS_MWM_OVERRIDE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "NORESIZEOVERRIDE") ||
++			 StrEquals(token, "NORESIZEHINTOVERRIDE"))
++		{
++			S_SET_HAS_OVERRIDE_SIZE(SCF(*ps), !on);
++			S_SET_HAS_OVERRIDE_SIZE(SCM(*ps), 1);
++			S_SET_HAS_OVERRIDE_SIZE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "NOHANDLES"))
++		{
++			ps->flags.has_no_handles = on;
++			ps->flag_mask.has_no_handles = 1;
++			ps->change_mask.has_no_handles = 1;
++		}
++		else if (StrEquals(token, "NOLENIENCE"))
++		{
++			FPS_LENIENT(S_FOCUS_POLICY(SCF(*ps)), !on);
++			FPS_LENIENT(S_FOCUS_POLICY(SCM(*ps)), 1);
++			FPS_LENIENT(S_FOCUS_POLICY(SCC(*ps)), 1);
++		}
++		else if (StrEquals(token, "NoButton"))
++		{
++			rest = style_parse_button_style(ps, rest, !on);
++		}
++		else if (StrEquals(token, "NOOLDECOR"))
++		{
++			ps->flags.has_ol_decor = !on;
++			ps->flag_mask.has_ol_decor = 1;
++			ps->change_mask.has_ol_decor = 1;
++		}
++		else if (StrEquals(token, "NeverFocus"))
++		{
++			style_set_old_focus_policy(ps, 3);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'o':
++		if (StrEquals(token, "OLDECOR"))
++		{
++			ps->flags.has_ol_decor = on;
++			ps->flag_mask.has_ol_decor = 1;
++			ps->change_mask.has_ol_decor = 1;
++		}
++		else if (StrEquals(token, "Opacity"))
++		{
++			ps->flags.use_parent_relative = !on;
++			ps->flag_mask.use_parent_relative = 1;
++			ps->change_mask.use_parent_relative = 1;
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'p':
++		if (StrEquals(token, "ParentalRelativity"))
++		{
++			ps->flags.use_parent_relative = on;
++			ps->flag_mask.use_parent_relative = 1;
++			ps->change_mask.use_parent_relative = 1;
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'q':
++		if (0)
++		{
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'r':
++		if (StrEquals(token, "RAISETRANSIENT"))
++		{
++			S_SET_DO_RAISE_TRANSIENT(SCF(*ps), on);
++			S_SET_DO_RAISE_TRANSIENT(SCM(*ps), 1);
++			S_SET_DO_RAISE_TRANSIENT(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "RANDOMPLACEMENT"))
++		{
++			ps->flags.placement_mode |= PLACE_RANDOM;
++			ps->flag_mask.placement_mode |= PLACE_RANDOM;
++			ps->change_mask.placement_mode |= PLACE_RANDOM;
++		}
++		else if (StrEquals(token, "RECAPTUREHONORSSTARTSONPAGE"))
++		{
++			ps->flags.recapture_honors_starts_on_page = on;
++			ps->flag_mask.recapture_honors_starts_on_page = 1;
++			ps->change_mask.recapture_honors_starts_on_page = 1;
++		}
++		else if (StrEquals(token, "RECAPTUREIGNORESSTARTSONPAGE"))
++		{
++			ps->flags.recapture_honors_starts_on_page = !on;
++			ps->flag_mask.recapture_honors_starts_on_page = 1;
++			ps->change_mask.recapture_honors_starts_on_page = 1;
++		}
++		else if (StrEquals(token, "RESIZEHINTOVERRIDE"))
++		{
++			S_SET_HAS_OVERRIDE_SIZE(SCF(*ps), on);
++			S_SET_HAS_OVERRIDE_SIZE(SCM(*ps), 1);
++			S_SET_HAS_OVERRIDE_SIZE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "ResizeOpaque"))
++		{
++			S_SET_DO_RESIZE_OPAQUE(SCF(*ps), on);
++			S_SET_DO_RESIZE_OPAQUE(SCM(*ps), 1);
++			S_SET_DO_RESIZE_OPAQUE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "ResizeOutline"))
++		{
++			S_SET_DO_RESIZE_OPAQUE(SCF(*ps), !on);
++			S_SET_DO_RESIZE_OPAQUE(SCM(*ps), 1);
++			S_SET_DO_RESIZE_OPAQUE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "ResizeOutlineThin"))
++		{
++			S_SET_DO_RESIZE_OUTLINE_THIN(SCF(*ps), on);
++			S_SET_DO_RESIZE_OUTLINE_THIN(SCM(*ps), 1);
++			S_SET_DO_RESIZE_OUTLINE_THIN(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "RightTitleRotatedCW"))
++		{
++			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCF(*ps), on);
++			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCM(*ps), 1);
++			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "RightTitleRotatedCCW"))
++		{
++			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCF(*ps), !on);
++			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCM(*ps), 1);
++			S_SET_IS_RIGHT_TITLE_ROTATED_CW(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 's':
++		if (StrEquals(token, "SMARTPLACEMENT"))
++		{
++			ps->flags.placement_mode |= PLACE_SMART;
++			ps->flag_mask.placement_mode |= PLACE_SMART;
++			ps->change_mask.placement_mode |= PLACE_SMART;
++		}
++		else if (StrEquals(token, "SkipMapping"))
++		{
++			S_SET_DO_NOT_SHOW_ON_MAP(SCF(*ps), on);
++			S_SET_DO_NOT_SHOW_ON_MAP(SCM(*ps), 1);
++			S_SET_DO_NOT_SHOW_ON_MAP(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "ShowMapping"))
++		{
++			S_SET_DO_NOT_SHOW_ON_MAP(SCF(*ps), !on);
++			S_SET_DO_NOT_SHOW_ON_MAP(SCM(*ps), 1);
++			S_SET_DO_NOT_SHOW_ON_MAP(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "StackTransientParent"))
++		{
++			S_SET_DO_STACK_TRANSIENT_PARENT(SCF(*ps), on);
++			S_SET_DO_STACK_TRANSIENT_PARENT(SCM(*ps), 1);
++			S_SET_DO_STACK_TRANSIENT_PARENT(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "StickyIcon"))
++		{
++			S_SET_IS_ICON_STICKY_ACROSS_PAGES(SCF(*ps), on);
++			S_SET_IS_ICON_STICKY_ACROSS_PAGES(SCM(*ps), 1);
++			S_SET_IS_ICON_STICKY_ACROSS_PAGES(SCC(*ps), 1);
++			S_SET_IS_ICON_STICKY_ACROSS_DESKS(SCF(*ps), on);
++			S_SET_IS_ICON_STICKY_ACROSS_DESKS(SCM(*ps), 1);
++			S_SET_IS_ICON_STICKY_ACROSS_DESKS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "StickyAcrossPagesIcon"))
++		{
++			S_SET_IS_ICON_STICKY_ACROSS_PAGES(SCF(*ps), on);
++			S_SET_IS_ICON_STICKY_ACROSS_PAGES(SCM(*ps), 1);
++			S_SET_IS_ICON_STICKY_ACROSS_PAGES(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "StickyAcrossDesksIcon"))
++		{
++			S_SET_IS_ICON_STICKY_ACROSS_DESKS(SCF(*ps), on);
++			S_SET_IS_ICON_STICKY_ACROSS_DESKS(SCM(*ps), 1);
++			S_SET_IS_ICON_STICKY_ACROSS_DESKS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "SlipperyIcon"))
++		{
++			S_SET_IS_ICON_STICKY_ACROSS_PAGES(SCF(*ps), !on);
++			S_SET_IS_ICON_STICKY_ACROSS_PAGES(SCM(*ps), 1);
++			S_SET_IS_ICON_STICKY_ACROSS_PAGES(SCC(*ps), 1);
++			S_SET_IS_ICON_STICKY_ACROSS_DESKS(SCF(*ps), !on);
++			S_SET_IS_ICON_STICKY_ACROSS_DESKS(SCM(*ps), 1);
++			S_SET_IS_ICON_STICKY_ACROSS_DESKS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "SloppyFocus"))
++		{
++			style_set_old_focus_policy(ps, 2);
++		}
++		else if (StrEquals(token, "StartIconic"))
++		{
++			ps->flags.do_start_iconic = on;
++			ps->flag_mask.do_start_iconic = 1;
++			ps->change_mask.do_start_iconic = 1;
++		}
++		else if (StrEquals(token, "StartNormal"))
++		{
++			ps->flags.do_start_iconic = !on;
++			ps->flag_mask.do_start_iconic = 1;
++			ps->change_mask.do_start_iconic = 1;
++		}
++		else if (StrEquals(token, "StaysOnBottom"))
++		{
++			SSET_LAYER(
++				*ps, (on) ? Scr.BottomLayer : Scr.DefaultLayer);
++			ps->flags.use_layer = 1;
++			ps->flag_mask.use_layer = 1;
++			ps->change_mask.use_layer = 1;
++		}
++		else if (StrEquals(token, "StaysOnTop"))
++		{
++			SSET_LAYER(
++				*ps, (on) ? Scr.BottomLayer : Scr.DefaultLayer);
++			SSET_LAYER(*ps, Scr.TopLayer);
++			ps->flags.use_layer = 1;
++			ps->flag_mask.use_layer = 1;
++			ps->change_mask.use_layer = 1;
++		}
++		else if (StrEquals(token, "StaysPut"))
++		{
++			SSET_LAYER(*ps, Scr.DefaultLayer);
++			ps->flags.use_layer = 1;
++			ps->flag_mask.use_layer = 1;
++			ps->change_mask.use_layer = 1;
++		}
++		else if (StrEquals(token, "Sticky"))
++		{
++			S_SET_IS_STICKY_ACROSS_PAGES(SCF(*ps), on);
++			S_SET_IS_STICKY_ACROSS_PAGES(SCM(*ps), 1);
++			S_SET_IS_STICKY_ACROSS_PAGES(SCC(*ps), 1);
++			S_SET_IS_STICKY_ACROSS_DESKS(SCF(*ps), on);
++			S_SET_IS_STICKY_ACROSS_DESKS(SCM(*ps), 1);
++			S_SET_IS_STICKY_ACROSS_DESKS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "StickyAcrossPages"))
++		{
++			S_SET_IS_STICKY_ACROSS_PAGES(SCF(*ps), on);
++			S_SET_IS_STICKY_ACROSS_PAGES(SCM(*ps), 1);
++			S_SET_IS_STICKY_ACROSS_PAGES(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "StickyAcrossDesks"))
++		{
++			S_SET_IS_STICKY_ACROSS_DESKS(SCF(*ps), on);
++			S_SET_IS_STICKY_ACROSS_DESKS(SCM(*ps), 1);
++			S_SET_IS_STICKY_ACROSS_DESKS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "StickyStippledTitle"))
++		{
++			S_SET_HAS_NO_STICKY_STIPPLED_TITLE(SCF(*ps), !on);
++			S_SET_HAS_NO_STICKY_STIPPLED_TITLE(SCM(*ps), 1);
++			S_SET_HAS_NO_STICKY_STIPPLED_TITLE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "StickyStippledIconTitle"))
++		{
++			S_SET_HAS_NO_STICKY_STIPPLED_ICON_TITLE(SCF(*ps), !on);
++			S_SET_HAS_NO_STICKY_STIPPLED_ICON_TITLE(SCM(*ps), 1);
++			S_SET_HAS_NO_STICKY_STIPPLED_ICON_TITLE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "Slippery"))
++		{
++			S_SET_IS_STICKY_ACROSS_PAGES(SCF(*ps), !on);
++			S_SET_IS_STICKY_ACROSS_PAGES(SCM(*ps), 1);
++			S_SET_IS_STICKY_ACROSS_PAGES(SCC(*ps), 1);
++			S_SET_IS_STICKY_ACROSS_DESKS(SCF(*ps), !on);
++			S_SET_IS_STICKY_ACROSS_DESKS(SCM(*ps), 1);
++			S_SET_IS_STICKY_ACROSS_DESKS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "STARTSONDESK"))
++		{
++			spargs = GetIntegerArguments(rest, NULL, tmpno, 1);
++			if (spargs == 1)
++			{
++				PeekToken(rest,&rest);
++				ps->flags.use_start_on_desk = 1;
++				ps->flag_mask.use_start_on_desk = 1;
++				ps->change_mask.use_start_on_desk = 1;
++				/*  RBW - 11/20/1998 - allow for the special
++				 * case of -1  */
++				SSET_START_DESK(
++					*ps, (tmpno[0] > -1) ?
++					tmpno[0] + 1 : tmpno[0]);
++			}
++			else
++			{
++				fvwm_msg(ERR,"style_parse_one_style_option",
++					 "bad StartsOnDesk arg: %s", rest);
++			}
++		}
++		/* StartsOnPage is like StartsOnDesk-Plus */
++		else if (StrEquals(token, "STARTSONPAGE"))
++		{
++			char *ret_rest;
++			spargs = GetIntegerArguments(rest, &ret_rest,
++						     tmpno, 3);
++			if (spargs == 1 || spargs == 3)
++			{
++				/* We have a desk no., with or without page. */
++				/* RBW - 11/20/1998 - allow for the special
++				 * case of -1 */
++				/* Desk is now actual + 1 */
++				SSET_START_DESK(
++					*ps, (tmpno[0] > -1) ?
++					tmpno[0] + 1 : tmpno[0]);
++			}
++			if (spargs == 2 || spargs == 3)
++			{
++				if (spargs == 3)
++				{
++					/*  RBW - 11/20/1998 - allow for the
++					 * special case of -1  */
++					SSET_START_PAGE_X(
++						*ps, (tmpno[1] > -1) ?
++						tmpno[1] + 1 : tmpno[1]);
++					SSET_START_PAGE_Y(
++						*ps, (tmpno[2] > -1) ?
++						tmpno[2] + 1 : tmpno[2]);
++				}
++				else
++				{
++					SSET_START_PAGE_X(
++						*ps, (tmpno[0] > -1) ?
++						tmpno[0] + 1 : tmpno[0]);
++					SSET_START_PAGE_Y(
++						*ps, (tmpno[1] > -1) ?
++						tmpno[1] + 1 : tmpno[1]);
++				}
++			}
++			if (spargs < 1 || spargs > 3)
++			{
++				fvwm_msg(ERR, "style_parse_one_style_option",
++					 "bad StartsOnPage args: %s", rest);
++			}
++			else
++			{
++				ps->flags.use_start_on_desk = 1;
++				ps->flag_mask.use_start_on_desk = 1;
++				ps->change_mask.use_start_on_desk = 1;
++			}
++			rest = ret_rest;
++		}
++		else if (StrEquals(token, "STARTSONPAGEINCLUDESTRANSIENTS"))
++		{
++			ps->flags.use_start_on_page_for_transient = on;
++			ps->flag_mask.use_start_on_page_for_transient = 1;
++			ps->change_mask.use_start_on_page_for_transient = 1;
++		}
++		else if (StrEquals(token, "STARTSONPAGEIGNORESTRANSIENTS"))
++		{
++			ps->flags.use_start_on_page_for_transient = !on;
++			ps->flag_mask.use_start_on_page_for_transient = 1;
++			ps->change_mask.use_start_on_page_for_transient = 1;
++		}
++		else if (StrEquals(token, "StartsOnScreen"))
++		{
++			if (rest)
++			{
++				tmpno[0] = FScreenGetScreenArgument(rest, 'c');
++				PeekToken(rest,&rest);
++				ps->flags.use_start_on_screen = 1;
++				ps->flag_mask.use_start_on_screen = 1;
++				ps->change_mask.use_start_on_screen = 1;
++				SSET_START_SCREEN(*ps, tmpno[0]);
++			}
++			else
++			{
++				ps->flags.use_start_on_screen = 0;
++				ps->flag_mask.use_start_on_screen = 1;
++				ps->change_mask.use_start_on_screen = 1;
++			}
++		}
++		else if (StrEquals(token, "STARTSANYWHERE"))
++		{
++			ps->flags.use_start_on_desk = 0;
++			ps->flag_mask.use_start_on_desk = 1;
++			ps->change_mask.use_start_on_desk = 1;
++		}
++		else if (StrEquals(token, "STARTSLOWERED"))
++		{
++			ps->flags.do_start_lowered = on;
++			ps->flag_mask.do_start_lowered = 1;
++			ps->change_mask.do_start_lowered = 1;
++		}
++		else if (StrEquals(token, "STARTSRAISED"))
++		{
++			ps->flags.do_start_lowered = !on;
++			ps->flag_mask.do_start_lowered = 1;
++			ps->change_mask.do_start_lowered = 1;
++		}
++		else if (StrEquals(token, "SaveUnder"))
++		{
++			ps->flags.do_save_under = on;
++			ps->flag_mask.do_save_under = 1;
++			ps->change_mask.do_save_under = 1;
++		}
++		else if (StrEquals(token, "SaveUnderOff"))
++		{
++			ps->flags.do_save_under = !on;
++			ps->flag_mask.do_save_under = 1;
++			ps->change_mask.do_save_under = 1;
++		}
++		else if (StrEquals(token, "StippledTitle"))
++		{
++			S_SET_HAS_STIPPLED_TITLE(SCF(*ps), on);
++			S_SET_HAS_STIPPLED_TITLE(SCM(*ps), 1);
++			S_SET_HAS_STIPPLED_TITLE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "StippledTitleOff"))
++		{
++			S_SET_HAS_STIPPLED_TITLE(SCF(*ps), !on);
++			S_SET_HAS_STIPPLED_TITLE(SCM(*ps), 1);
++			S_SET_HAS_STIPPLED_TITLE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "StippledIconTitle"))
++		{
++			S_SET_HAS_STIPPLED_ICON_TITLE(SCF(*ps), on);
++			S_SET_HAS_STIPPLED_ICON_TITLE(SCM(*ps), 1);
++			S_SET_HAS_STIPPLED_ICON_TITLE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "ScatterWindowGroups"))
++		{
++			S_SET_DO_USE_WINDOW_GROUP_HINT(SCF(*ps), !on);
++			S_SET_DO_USE_WINDOW_GROUP_HINT(SCM(*ps), 1);
++			S_SET_DO_USE_WINDOW_GROUP_HINT(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "State"))
++		{
++			unsigned int mask;
++			unsigned int states;
++
++			spargs = GetIntegerArguments(rest, NULL, tmpno, 1);
++			if (spargs == 1 && tmpno[0] >= 0 && tmpno[0] <= 31)
++			{
++				PeekToken(rest,&rest);
++				states = S_USER_STATES(SCF(*ps));
++				mask = (1 << tmpno[0]);
++				if (on)
++				{
++					states |= mask;
++				}
++				else
++				{
++					states &= ~mask;
++				}
++				S_SET_USER_STATES(SCF(*ps), states);
++				S_ADD_USER_STATES(SCM(*ps), mask);
++				S_ADD_USER_STATES(SCC(*ps), mask);
++			}
++			else
++			{
++				fvwm_msg(
++					ERR,"style_parse_one_style_option",
++					"bad State arg: %s", rest);
++			}
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 't':
++		if (StrEquals(token, "TileCascadePlacement"))
++		{
++			ps->flags.placement_mode = PLACE_TILECASCADE;
++			ps->flag_mask.placement_mode = PLACE_MASK;
++			ps->change_mask.placement_mode = PLACE_MASK;
++		}
++		else if (StrEquals(token, "TileManualPlacement"))
++		{
++			ps->flags.placement_mode = PLACE_TILEMANUAL;
++			ps->flag_mask.placement_mode = PLACE_MASK;
++			ps->change_mask.placement_mode = PLACE_MASK;
++		}
++		else if (StrEquals(token, "Title"))
++		{
++			ps->flags.has_no_title = !on;
++			ps->flag_mask.has_no_title = 1;
++			ps->change_mask.has_no_title = 1;
++		}
++		else if (StrEquals(token, "TitleAtBottom"))
++		{
++			S_SET_TITLE_DIR(SCF(*ps), DIR_S);
++			S_SET_TITLE_DIR(SCM(*ps), DIR_MAJOR_MASK);
++			S_SET_TITLE_DIR(SCC(*ps), DIR_MAJOR_MASK);
++		}
++		else if (StrEquals(token, "TitleAtTop"))
++		{
++			S_SET_TITLE_DIR(SCF(*ps), DIR_N);
++			S_SET_TITLE_DIR(SCM(*ps), DIR_MAJOR_MASK);
++			S_SET_TITLE_DIR(SCC(*ps), DIR_MAJOR_MASK);
++		}
++		else if (StrEquals(token, "TitleAtLeft"))
++		{
++			S_SET_TITLE_DIR(SCF(*ps), DIR_W);
++			S_SET_TITLE_DIR(SCM(*ps), DIR_MAJOR_MASK);
++			S_SET_TITLE_DIR(SCC(*ps), DIR_MAJOR_MASK);
++		}
++		else if (StrEquals(token, "TitleAtRight"))
++		{
++			S_SET_TITLE_DIR(SCF(*ps), DIR_E);
++			S_SET_TITLE_DIR(SCM(*ps), DIR_MAJOR_MASK);
++			S_SET_TITLE_DIR(SCC(*ps), DIR_MAJOR_MASK);
++		}
++		else if (StrEquals(token, "TopTitleRotated"))
++		{
++			S_SET_IS_TOP_TITLE_ROTATED(SCF(*ps), on);
++			S_SET_IS_TOP_TITLE_ROTATED(SCM(*ps), 1);
++			S_SET_IS_TOP_TITLE_ROTATED(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "TopTitleNotRotated"))
++		{
++			S_SET_IS_TOP_TITLE_ROTATED(SCF(*ps), !on);
++			S_SET_IS_TOP_TITLE_ROTATED(SCM(*ps), 1);
++			S_SET_IS_TOP_TITLE_ROTATED(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'u':
++		if (StrEquals(token, "UnderMousePlacement"))
++		{
++			ps->flags.placement_mode = PLACE_UNDERMOUSE;
++			ps->flag_mask.placement_mode = PLACE_MASK;
++			ps->change_mask.placement_mode = PLACE_MASK;
++		}
++		else if (StrEquals(token, "UsePPosition"))
++		{
++			ps->flags.use_no_pposition = !on;
++			ps->flag_mask.use_no_pposition = 1;
++			ps->change_mask.use_no_pposition = 1;
++		}
++		else if (StrEquals(token, "UseUSPosition"))
++		{
++			ps->flags.use_no_usposition = !on;
++			ps->flag_mask.use_no_usposition = 1;
++			ps->change_mask.use_no_usposition = 1;
++		}
++		else if (StrEquals(token, "UseTransientPPosition"))
++		{
++			ps->flags.use_no_transient_pposition = !on;
++			ps->flag_mask.use_no_transient_pposition = 1;
++			ps->change_mask.use_no_transient_pposition = 1;
++		}
++		else if (StrEquals(token, "UseTransientUSPosition"))
++		{
++			ps->flags.use_no_transient_usposition = !on;
++			ps->flag_mask.use_no_transient_usposition = 1;
++			ps->change_mask.use_no_transient_usposition = 1;
++		}
++		else if (StrEquals(token, "UseIconPosition"))
++		{
++			S_SET_USE_ICON_POSITION_HINT(SCF(*ps), on);
++			S_SET_USE_ICON_POSITION_HINT(SCM(*ps), 1);
++			S_SET_USE_ICON_POSITION_HINT(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "UseTitleDecorRotation"))
++		{
++			S_SET_USE_TITLE_DECOR_ROTATION(SCF(*ps), on);
++			S_SET_USE_TITLE_DECOR_ROTATION(SCM(*ps), 1);
++			S_SET_USE_TITLE_DECOR_ROTATION(SCC(*ps), 1);
++		}
++#ifdef USEDECOR
++		else if (StrEquals(token, "UseDecor"))
++		{
++			SAFEFREE(SGET_DECOR_NAME(*ps));
++			rest = GetNextToken(rest, &token);
++			SSET_DECOR_NAME(*ps, token);
++			ps->flags.has_decor = (token != NULL);
++			ps->flag_mask.has_decor = 1;
++			ps->change_mask.has_decor = 1;
++		}
++#endif
++		else if (StrEquals(token, "UseStyle"))
++		{
++			int hit;
++
++			token = PeekToken(rest, &rest);
++			if (!token)
++			{
++				fvwm_msg(ERR, "style_parse_one_style_option",
++					 "UseStyle needs an argument");
++				break;
++			}
++			hit = 0;
++			/* changed to accum multiple Style definitions
++			 * (veliaa at rpi.edu) */
++			for (add_style = all_styles; add_style;
++			     add_style = SGET_NEXT_STYLE(*add_style))
++			{
++				if (SGET_ID_HAS_NAME(*add_style) &&
++				    StrEquals(token, SGET_NAME(*add_style)))
++				{
++					/* match style */
++					hit = 1;
++					merge_styles(ps, add_style, True);
++				} /* end found matching style */
++			} /* end looking at all styles */
++			/* move forward one word */
++			if (!hit)
++			{
++				fvwm_msg(
++					ERR, "style_parse_one_style_option",
++					"UseStyle: %s style not found", token);
++			}
++		}
++		else if (StrEquals(token, "Unmanaged"))
++		{
++			ps->flags.is_unmanaged = on;
++			ps->flag_mask.is_unmanaged = 1;
++			ps->change_mask.is_unmanaged = 1;
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'v':
++		if (StrEquals(token, "VariablePosition") ||
++		    StrEquals(token, "VariableUSPosition"))
++		{
++			S_SET_IS_FIXED(SCF(*ps), !on);
++			S_SET_IS_FIXED(SCM(*ps), 1);
++			S_SET_IS_FIXED(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "VariablePPosition"))
++		{
++			S_SET_IS_FIXED_PPOS(SCF(*ps), !on);
++			S_SET_IS_FIXED_PPOS(SCM(*ps), 1);
++			S_SET_IS_FIXED_PPOS(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "VariableSize") ||
++			 StrEquals(token, "VariableUSSize"))
++		{
++			S_SET_IS_SIZE_FIXED(SCF(*ps), !on);
++			S_SET_IS_SIZE_FIXED(SCM(*ps), 1);
++			S_SET_IS_SIZE_FIXED(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "VariablePSize"))
++		{
++			S_SET_IS_PSIZE_FIXED(SCF(*ps), !on);
++			S_SET_IS_PSIZE_FIXED(SCM(*ps), 1);
++			S_SET_IS_PSIZE_FIXED(SCC(*ps), 1);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'w':
++		if (StrEquals(token, "WindowListSkip"))
++		{
++			S_SET_DO_WINDOW_LIST_SKIP(SCF(*ps), on);
++			S_SET_DO_WINDOW_LIST_SKIP(SCM(*ps), 1);
++			S_SET_DO_WINDOW_LIST_SKIP(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "WindowListHit"))
++		{
++			S_SET_DO_WINDOW_LIST_SKIP(SCF(*ps), !on);
++			S_SET_DO_WINDOW_LIST_SKIP(SCM(*ps), 1);
++			S_SET_DO_WINDOW_LIST_SKIP(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "WindowShadeSteps"))
++		{
++			int n = 0;
++			int val = 0;
++			int unit = 0;
++
++			n = GetOnePercentArgument(rest, &val, &unit);
++			if (n != 1)
++			{
++				val = 0;
++			}
++			else
++			{
++				PeekToken(rest,&rest);
++			}
++			/* we have a 'pixel' suffix if unit != 0; negative
++			 * values mean pixels */
++			val = (unit != 0) ? -val : val;
++			ps->flags.has_window_shade_steps = 1;
++			ps->flag_mask.has_window_shade_steps = 1;
++			ps->change_mask.has_window_shade_steps = 1;
++			SSET_WINDOW_SHADE_STEPS(*ps, val);
++		}
++		else if (StrEquals(token, "WindowShadeScrolls"))
++		{
++			S_SET_DO_SHRINK_WINDOWSHADE(SCF(*ps), !on);
++			S_SET_DO_SHRINK_WINDOWSHADE(SCM(*ps), 1);
++			S_SET_DO_SHRINK_WINDOWSHADE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "WindowShadeShrinks"))
++		{
++			S_SET_DO_SHRINK_WINDOWSHADE(SCF(*ps), on);
++			S_SET_DO_SHRINK_WINDOWSHADE(SCM(*ps), 1);
++			S_SET_DO_SHRINK_WINDOWSHADE(SCC(*ps), 1);
++		}
++		else if (StrEquals(token, "WindowShadeLazy"))
++		{
++			S_SET_WINDOWSHADE_LAZINESS(SCF(*ps), WINDOWSHADE_LAZY);
++			S_SET_WINDOWSHADE_LAZINESS(
++				SCM(*ps), WINDOWSHADE_LAZY_MASK);
++			S_SET_WINDOWSHADE_LAZINESS(
++				SCC(*ps), WINDOWSHADE_LAZY_MASK);
++		}
++		else if (StrEquals(token, "WindowShadeAlwaysLazy"))
++		{
++			S_SET_WINDOWSHADE_LAZINESS(
++				SCF(*ps), WINDOWSHADE_ALWAYS_LAZY);
++			S_SET_WINDOWSHADE_LAZINESS(
++				SCM(*ps), WINDOWSHADE_LAZY_MASK);
++			S_SET_WINDOWSHADE_LAZINESS(
++				SCC(*ps), WINDOWSHADE_LAZY_MASK);
++		}
++		else if (StrEquals(token, "WindowShadeBusy"))
++		{
++			S_SET_WINDOWSHADE_LAZINESS(SCF(*ps), WINDOWSHADE_BUSY);
++			S_SET_WINDOWSHADE_LAZINESS(
++				SCM(*ps), WINDOWSHADE_LAZY_MASK);
++			S_SET_WINDOWSHADE_LAZINESS(
++				SCC(*ps), WINDOWSHADE_LAZY_MASK);
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	case 'x':
++	case 'y':
++	case 'z':
++		if (0)
++		{
++		}
++		else
++		{
++			found = False;
++		}
++		break;
++
++	default:
++		found = False;
++		break;
++	}
++	if (ret_rest)
++	{
++		*ret_rest = rest;
++	}
++	if (token_l != NULL)
++	{
++		free(token_l);
++	}
++
++	return found;
++}
++
++static
++void parse_and_set_window_style(char *action, char *prefix, window_style *ps)
++{
++	char *line;
++	char *option;
++	char *token;
++	char *rest;
++	Bool found;
++	/* which current boxes to chain to */
++	icon_boxes *cur_ib = NULL;
++
++	while (isspace((unsigned char)*action))
++	{
++		action++;
++	}
++	line = action;
++	while (action && *action && *action != '\n')
++	{
++		action = GetNextFullOption(action, &option);
++		if (!option)
++		{
++			break;
++		}
++		token = PeekToken(option, &rest);
++		if (!token)
++		{
++			free(option);
++			break;
++		}
++
++		/* It might make more sense to capture the whole word, fix its
++		 * case, and use strcmp, but there aren't many caseless compares
++		 * because of this "switch" on the first letter. */
++		found = style_parse_one_style_option(
++			token, rest, &rest, prefix, ps, &cur_ib);
++
++		if (found == False)
++		{
++			fvwm_msg(
++				ERR, "style_parse_and_set_window_style",
++				"Bad style option: %s", option);
++			/* Can't return here since all malloced memory will be
++			 * lost. Ignore rest of line instead. */
++			/* No, I think we /can/ return here. In fact, /not/
++			 * bombing out leaves a half-done style in the list!
++			 * N.Bird 07-Sep-1999 */
++			/* domivogt (01-Oct-1999): Which is exactly what we
++			 * want! Why should all the styles be thrown away if a
++			 * single one is mis-spelled? Let's just continue
++			 * parsing styles. */
++		}
++		else
++		{
++			rest = SkipSpaces(rest,NULL,0);
++			if (*rest)
++			{
++				fvwm_msg(WARN,
++					 "style_parse_and_set_window_style",
++					 "Unconsumed argument in %s: %s",
++					 option, rest);
++			}
++		}
++		free(option);
++	} /* end while still stuff on command */
++
++	return;
++}
++
++/* Process a style command.  First built up in a temp area.
++ * If valid, added to the list in a malloced area.
++ *
++ *		      *** Important note ***
++ *
++ * Remember that *all* styles need a flag, flag_mask and change_mask.
++ * It is not enough to add the code for new styles in this function.
++ * There *must* be corresponding code in handle_new_window_style()
++ * and merge_styles() too.  And don't forget that allocated memory
++ * must be freed in ProcessDestroyStyle().
++ */
++
++static void __style_command(F_CMD_ARGS, char *prefix, Bool is_window_style)
++{
++	/* temp area to build name list */
++	window_style *ps;
++
++	ps = (window_style *)safemalloc(sizeof(window_style));
++	/* init temp window_style area */
++	memset(ps, 0, sizeof(window_style));
++	/* init default focus policy */
++	fpol_init_default_fp(&S_FOCUS_POLICY(SCF(*ps)));
++	/* mark style as changed */
++	ps->has_style_changed = 1;
++	/* set global flag */
++	Scr.flags.do_need_window_update = 1;
++	/* default StartsOnPage behavior for initial capture */
++	ps->flags.capture_honors_starts_on_page = 1;
++
++	if (!is_window_style)
++	{
++		/* parse style name */
++		action = GetNextToken(action, &SGET_NAME(*ps));
++		/* in case there was no argument! */
++		if (SGET_NAME(*ps) == NULL)
++		{
++			free(ps);
++			return;
++		}
++		SSET_ID_HAS_NAME(*ps, True);
++	}
++	else
++	{
++		SSET_WINDOW_ID(*ps, (XID)FW_W(exc->w.fw));
++		SSET_ID_HAS_WINDOW_ID(*ps, True);
++		CopyString(&SGET_NAME(*ps), ""); /* safe */
++	}
++
++	if (action == NULL)
++	{
++		free(SGET_NAME(*ps));
++		free(ps);
++		return;
++	}
++
++	parse_and_set_window_style(action, prefix, ps);
++
++	/* capture default icons */
++	if (SGET_ID_HAS_NAME(*ps) && StrEquals(SGET_NAME(*ps), "*"))
++	{
++		if (ps->flags.has_icon == 1)
++		{
++			if (Scr.DefaultIcon)
++			{
++				free(Scr.DefaultIcon);
++			}
++			Scr.DefaultIcon = SGET_ICON_NAME(*ps);
++			ps->flags.has_icon = 0;
++			ps->flag_mask.has_icon = 0;
++			ps->change_mask.has_icon = 1;
++			SSET_ICON_NAME(*ps, NULL);
++		}
++	}
++	if (last_style_in_list && styles_have_same_id(ps, last_style_in_list))
++	{
++		/* merge with previous style */
++		merge_styles(last_style_in_list, ps, True);
++		free_style(ps);
++		free(ps);
++	}
++	else
++	{
++		/* add temp name list to list */
++		add_style_to_list(ps);
++		cleanup_style_defaults(ps);
++	}
++
++	return;
++}
++
++/* ---------------------------- interface functions ------------------------ */
++
++/* Compare two flag structures passed as byte arrays. Only compare bits set in
++ * the mask.
++ *
++ *  Returned Value:
++ *	zero if the flags are the same
++ *	non-zero otherwise
++ *
++ *  Inputs:
++ *	flags1 - first byte array of flags to compare
++ *	flags2 - second byte array of flags to compare
++ *	mask   - byte array of flags to be considered for the comparison
++ *	len    - number of bytes to compare */
++Bool blockcmpmask(char *blk1, char *blk2, char *mask, int length)
++{
++	int i;
++
++	for (i = 0; i < length; i++)
++	{
++		if ((blk1[i] & mask[i]) != (blk2[i] & mask[i]))
++		{
++			/* flags are not the same, return 1 */
++			return False;
++		}
++	}
++	return True;
++}
++
++void free_icon_boxes(icon_boxes *ib)
++{
++	icon_boxes *temp;
++
++	for ( ; ib != NULL; ib = temp)
++	{
++		temp = ib->next;
++		if (ib->use_count == 0)
++		{
++			free(ib);
++		}
++		else
++		{
++			/* we can't delete the icon box yet, it is still in use
++			 */
++			ib->is_orphan = True;
++		}
++	}
++
++	return;
++}
++
++void simplify_style_list(void)
++{
++	/* one pass through the style list, then process other events first */
++	Scr.flags.do_need_style_list_update = __simplify_style_list();
++
++	return;
++}
++
++/* lookup_style - look through a list for a window name, or class
++ *
++ *  Returned Value:
++ *	merged matching styles in callers window_style.
++ *
++ *  Inputs:
++ *	fw     - FvwmWindow structure to match against
++ *	styles - callers return area
++ */
++void lookup_style(FvwmWindow *fw, window_style *styles)
++{
++	window_style *nptr;
++
++	/* clear callers return area */
++	memset(styles, 0, sizeof(window_style));
++
++	/* look thru all styles in order defined. */
++	for (nptr = all_styles; nptr != NULL; nptr = SGET_NEXT_STYLE(*nptr))
++	{
++		if (fw_match_style_id(fw, SGET_ID(*nptr)))
++		{
++			merge_styles(styles, nptr, False);
++		}
++	}
++	if (!DO_IGNORE_GNOME_HINTS(fw))
++	{
++		window_style gnome_style;
++
++		/* use GNOME hints if not overridden by user with
++		 * GNOMEIgnoreHitns */
++		memset(&gnome_style, 0, sizeof(window_style));
++		GNOME_GetStyle(fw, &gnome_style);
++		merge_styles(&gnome_style, styles, False);
++		memcpy(styles, &gnome_style, sizeof(window_style));
++	}
++	EWMH_GetStyle(fw, styles);
++
++	return;
++}
++
++/* This function sets the style update flags as necessary */
++void check_window_style_change(
++	FvwmWindow *t, update_win *flags, window_style *ret_style)
++{
++	int i;
++	char *wf;
++	char *sf;
++	char *sc;
++
++	lookup_style(t, ret_style);
++	if (!ret_style->has_style_changed && !IS_STYLE_DELETED(t))
++	{
++		/* nothing to do */
++		return;
++	}
++
++	/* do_ignore_gnome_hints
++	 *
++	 * must handle these first because they may alter the style */
++	if (S_DO_IGNORE_GNOME_HINTS(SCC(*ret_style)) &&
++	    !S_DO_IGNORE_GNOME_HINTS(SCF(*ret_style)))
++	{
++		GNOME_GetStyle(t, ret_style);
++		/* may need further treatment for some styles */
++		flags->do_update_gnome_styles = 1;
++	}
++
++	/*** common style flags ***/
++
++	wf = (char *)(&FW_COMMON_STATIC_FLAGS(t));
++	sf = (char *)(&SCFS(*ret_style));
++	if (IS_STYLE_DELETED(t))
++	{
++		/* update all styles */
++		memset(flags, 0xff, sizeof(*flags));
++		SET_STYLE_DELETED(t, 0);
++		/* copy the static common window flags */
++		for (i = 0; i < sizeof(SCFS(*ret_style)); i++)
++		{
++			wf[i] = sf[i];
++		}
++
++		return;
++	}
++	/* All static common styles can simply be copied. For some there is
++	 * additional work to be done below. */
++	sc = (char *)(&SCCS(*ret_style));
++	for (i = 0; i < sizeof(SCFS(*ret_style)); i++)
++	{
++		wf[i] = (wf[i] & ~sc[i]) | (sf[i] & sc[i]);
++		sf[i] = wf[i];
++	}
++
++	/* is_sticky
++	 * is_icon_sticky */
++	if (S_IS_STICKY_ACROSS_PAGES(SCC(*ret_style)) ||
++	    S_IS_STICKY_ACROSS_DESKS(SCC(*ret_style)))
++	{
++		flags->do_update_stick = 1;
++	}
++	else if (S_IS_ICON_STICKY_ACROSS_PAGES(SCC(*ret_style)) &&
++		 IS_ICONIFIED(t) && !IS_STICKY_ACROSS_PAGES(t))
++	{
++		flags->do_update_stick_icon = 1;
++	}
++	else if (S_IS_ICON_STICKY_ACROSS_DESKS(SCC(*ret_style)) &&
++		 IS_ICONIFIED(t) && !IS_STICKY_ACROSS_DESKS(t))
++	{
++		flags->do_update_stick_icon = 1;
++	}
++
++	/* focus policy */
++	if (fpol_is_policy_changed(&S_FOCUS_POLICY(SCC(*ret_style))))
++	{
++		flags->do_setup_focus_policy = 1;
++	}
++
++	/* is_left_title_rotated_cw
++	 * is_right_title_rotated_cw
++	 * is_top_title_rotated
++	 * is_bottom_title_rotated */
++	if (S_IS_LEFT_TITLE_ROTATED_CW(SCC(*ret_style)) ||
++	    S_IS_RIGHT_TITLE_ROTATED_CW(SCC(*ret_style)) ||
++	    S_IS_TOP_TITLE_ROTATED(SCC(*ret_style)) ||
++	    S_IS_BOTTOM_TITLE_ROTATED(SCC(*ret_style)))
++	{
++		flags->do_update_title_text_dir = 1;
++	}
++
++	/* title_dir */
++	if (S_TITLE_DIR(SCC(*ret_style)))
++	{
++		flags->do_update_title_dir = 1;
++	}
++
++	/* use_title_decor_rotation */
++	if (S_USE_TITLE_DECOR_ROTATION(SCC(*ret_style)))
++	{
++		flags->do_update_rotated_title = 1;
++	}
++
++	/* has_mwm_border
++	 * has_mwm_buttons */
++	if (S_HAS_MWM_BORDER(SCC(*ret_style)) ||
++	    S_HAS_MWM_BUTTONS(SCC(*ret_style)))
++	{
++		flags->do_redecorate = 1;
++	}
++
++	/* has_icon_font */
++	if (S_HAS_ICON_FONT(SCC(*ret_style)))
++	{
++		flags->do_update_icon_font = 1;
++	}
++
++	/* has_window_font */
++	if (S_HAS_WINDOW_FONT(SCC(*ret_style)))
++	{
++		flags->do_update_window_font = 1;
++	}
++
++	/* has_stippled_title */
++	if (S_HAS_STIPPLED_TITLE(SCC(*ret_style)) ||
++	    S_HAS_NO_STICKY_STIPPLED_TITLE(SCC(*ret_style)) ||
++	    S_HAS_STIPPLED_ICON_TITLE(SCC(*ret_style)) ||
++	    S_HAS_NO_STICKY_STIPPLED_ICON_TITLE(SCC(*ret_style)))
++	{
++		flags->do_redraw_decoration = 1;
++	}
++
++	/* has_no_icon_title
++	 * is_icon_suppressed
++	 *
++	 * handled below */
++
++	/*** private style flags ***/
++
++	/* nothing to do for these flags (only used when mapping new windows):
++	 *
++	 *   do_place_random
++	 *   do_place_smart
++	 *   do_start_lowered
++	 *   use_no_pposition
++	 *   use_no_usposition
++	 *   use_no_transient_pposition
++	 *   use_no_transient_usposition
++	 *   use_start_on_desk
++	 *   use_start_on_page_for_transient
++	 *   use_start_on_screen
++	 *   manual_placement_honors_starts_on_page
++	 *   capture_honors_starts_on_page
++	 *   recapture_honors_starts_on_page
++	 *   use_layer
++	 *   ewmh_placement_mode
++	 */
++
++	/* not implemented yet:
++	 *
++	 *   handling the 'usestyle' style
++	 */
++
++	/* do_window_list_skip */
++	if (S_DO_WINDOW_LIST_SKIP(SCC(*ret_style)))
++	{
++		flags->do_update_modules_flags = 1;
++		flags->do_update_ewmh_state_hints = 1;
++	}
++
++	/* has_icon
++	 * icon_override */
++	if (ret_style->change_mask.has_icon ||
++	    S_ICON_OVERRIDE(SCC(*ret_style)))
++	{
++		flags->do_update_icon_font = 1;
++		flags->do_update_icon = 1;
++	}
++
++	/* has_icon_background_padding
++	 * has_icon_background_relief
++	 * has_icon_title_relief */
++	if (ret_style->change_mask.has_icon_background_padding ||
++	    ret_style->change_mask.has_icon_background_relief ||
++	    ret_style->change_mask.has_icon_title_relief)
++	{
++		flags->do_update_icon = 1;
++	}
++
++	/* has_no_icon_title
++	 * is_icon_suppressed */
++	if (S_HAS_NO_ICON_TITLE(SCC(*ret_style)) ||
++	    S_IS_ICON_SUPPRESSED(SCC(*ret_style)))
++	{
++		flags->do_update_icon_font = 1;
++		flags->do_update_icon_title = 1;
++		flags->do_update_icon = 1;
++		flags->do_update_modules_flags = 1;
++	}
++
++	/* has_icon_size_limits */
++	if (ret_style->change_mask.has_icon_size_limits)
++	{
++		flags->do_update_icon_size_limits = 1;
++		flags->do_update_icon = 1;
++	}
++
++	/*   has_icon_boxes */
++	if (ret_style->change_mask.has_icon_boxes)
++	{
++		flags->do_update_icon_boxes = 1;
++		flags->do_update_icon = 1;
++	}
++
++	/* do_ewmh_donate_icon */
++	if (S_DO_EWMH_DONATE_ICON(SCC(*ret_style)))
++	{
++		flags->do_update_ewmh_icon = 1;
++	}
++
++	/* has_mini_icon
++	 * do_ewmh_mini_icon_override */
++	if (FMiniIconsSupported && (ret_style->change_mask.has_mini_icon ||
++	    S_DO_EWMH_MINI_ICON_OVERRIDE(SCC(*ret_style))))
++	{
++		flags->do_update_mini_icon = 1;
++		flags->do_update_ewmh_mini_icon = 1;
++		flags->do_redecorate = 1;
++	}
++
++	/* do_ewmh_donate_mini_icon */
++	if (FMiniIconsSupported && S_DO_EWMH_DONATE_MINI_ICON(SCC(*ret_style)))
++	{
++		flags->do_update_ewmh_mini_icon = 1;
++	}
++
++	/* has_max_window_size */
++	if (ret_style->change_mask.has_max_window_size)
++	{
++		flags->do_resize_window = 1;
++		flags->do_update_ewmh_allowed_actions = 1;
++		flags->do_update_modules_flags = 1;
++	}
++
++	/* has_color_back
++	 * has_color_fore
++	 * use_colorset
++	 * use_border_colorset */
++	if (ret_style->change_mask.has_color_fore ||
++	    ret_style->change_mask.has_color_back ||
++	    ret_style->change_mask.use_colorset ||
++	    ret_style->change_mask.use_border_colorset)
++	{
++		flags->do_update_window_color = 1;
++	}
++	/* has_color_back_hi
++	 * has_color_fore_hi
++	 * use_colorset_hi
++	 * use_border_colorset_hi */
++	if (ret_style->change_mask.has_color_fore_hi ||
++	    ret_style->change_mask.has_color_back_hi ||
++	    ret_style->change_mask.use_colorset_hi ||
++	    ret_style->change_mask.use_border_colorset_hi)
++	{
++		flags->do_update_window_color_hi = 1;
++	}
++
++	/* use_icon_title_colorset */
++	if (ret_style->change_mask.use_icon_title_colorset)
++	{
++		flags->do_update_icon_title_cs = 1;
++	}
++
++	/* use_icon_title_colorset_hi */
++	if (ret_style->change_mask.use_icon_title_colorset_hi)
++	{
++		flags->do_update_icon_title_cs_hi = 1;
++	}
++
++	/* use_icon_title_colorset */
++	if (ret_style->change_mask.use_icon_title_colorset)
++	{
++		flags->do_update_icon_title_cs = 1;
++	}
++
++	/* use_icon_background_colorset */
++	if (ret_style->change_mask.use_icon_background_colorset)
++	{
++		flags->do_update_icon_background_cs = 1;
++	}
++
++	/* has_decor */
++	if (ret_style->change_mask.has_decor)
++	{
++		flags->do_redecorate = 1;
++		flags->do_update_window_font_height = 1;
++	}
++
++	/* has_no_title */
++	if (ret_style->change_mask.has_no_title)
++	{
++		flags->do_redecorate = 1;
++		flags->do_update_window_font = 1;
++	}
++
++	/* do_decorate_transient */
++	if (ret_style->change_mask.do_decorate_transient)
++	{
++		flags->do_redecorate_transient = 1;
++	}
++
++	/* has_ol_decor */
++	if (ret_style->change_mask.has_ol_decor)
++	{
++		/* old decor overrides 'has_no_icon_title'! */
++		flags->do_update_icon_font = 1;
++		flags->do_update_icon_title = 1;
++		flags->do_update_icon = 1;
++		flags->do_redecorate = 1;
++	}
++
++	/* has_no_border
++	 * has_border_width
++	 * has_handle_width
++	 * has_mwm_decor
++	 * has_mwm_functions
++	 * has_no_handles
++	 * is_button_disabled */
++	if (S_HAS_NO_BORDER(SCC(*ret_style)) ||
++	    ret_style->change_mask.has_border_width ||
++	    ret_style->change_mask.has_handle_width ||
++	    ret_style->change_mask.has_mwm_decor ||
++	    ret_style->change_mask.has_mwm_functions ||
++	    ret_style->change_mask.has_no_handles ||
++	    ret_style->change_mask.is_button_disabled)
++	{
++		flags->do_redecorate = 1;
++		flags->do_update_ewmh_allowed_actions = 1;
++		flags->do_update_modules_flags = 1;
++	}
++
++	if (ret_style->change_mask.do_save_under ||
++	    ret_style->change_mask.use_backing_store ||
++	    ret_style->change_mask.use_parent_relative)
++	{
++		flags->do_update_frame_attributes = 1;
++	}
++
++	if (ret_style->change_mask.use_parent_relative &&
++	    ret_style->flags.use_parent_relative)
++	{
++		/* needed only for Opacity -> ParentalRelativity */
++		flags->do_refresh = 1;
++	}
++
++	/* has_placement_penalty
++	 * has_placement_percentage_penalty */
++	if (ret_style->change_mask.has_placement_penalty ||
++	    ret_style->change_mask.has_placement_percentage_penalty)
++	{
++		flags->do_update_placement_penalty = 1;
++	}
++
++	/* do_ewmh_ignore_strut_hints */
++	if (S_DO_EWMH_IGNORE_STRUT_HINTS(SCC(*ret_style)))
++	{
++		flags->do_update_working_area = 1;
++	}
++
++	/* do_ewmh_ignore_state_hints */
++	if (S_DO_EWMH_IGNORE_STATE_HINTS(SCC(*ret_style)))
++	{
++		flags->do_update_ewmh_state_hints = 1;
++		flags->do_update_modules_flags = 1;
++	}
++
++	/* do_ewmh_use_staking_hints */
++	if (S_DO_EWMH_USE_STACKING_HINTS(SCC(*ret_style)))
++	{
++		flags->do_update_ewmh_stacking_hints = 1;
++	}
++
++	/*  use_indexed_window_name */
++	if (S_USE_INDEXED_WINDOW_NAME(SCC(*ret_style)))
++	{
++		flags->do_update_visible_window_name = 1;
++		flags->do_redecorate = 1;
++	}
++
++	/*  use_indexed_icon_name */
++	if (S_USE_INDEXED_ICON_NAME(SCC(*ret_style)))
++	{
++		flags->do_update_visible_icon_name = 1;
++		flags->do_update_icon_title = 1;
++	}
++
++	/*  is_fixed */
++	if (S_IS_FIXED(SCC(*ret_style)) ||
++	    S_IS_FIXED_PPOS(SCC(*ret_style)) ||
++	    S_IS_SIZE_FIXED(SCC(*ret_style)) ||
++	    S_IS_PSIZE_FIXED(SCC(*ret_style)) ||
++	    S_HAS_OVERRIDE_SIZE(SCC(*ret_style)))
++	{
++		flags->do_update_ewmh_allowed_actions = 1;
++		flags->do_update_modules_flags = 1;
++	}
++
++	/* cr_motion_method */
++	if (SCR_MOTION_METHOD(&ret_style->change_mask))
++	{
++		flags->do_update_cr_motion_method = 1;
++	}
++
++	return;
++}
++
++/* Mark all styles as unchanged. */
++void reset_style_changes(void)
++{
++	window_style *temp;
++
++	for (temp = all_styles; temp != NULL; temp = SGET_NEXT_STYLE(*temp))
++	{
++		temp->has_style_changed = 0;
++		memset(&SCCS(*temp), 0, sizeof(SCCS(*temp)));
++		memset(&(temp->change_mask), 0, sizeof(temp->change_mask));
++	}
++
++	return;
++}
++
++/* Mark styles as updated if their colorset changed. */
++void update_style_colorset(int colorset)
++{
++	window_style *temp;
++
++	for (temp = all_styles; temp != NULL; temp = SGET_NEXT_STYLE(*temp))
++	{
++		if (SUSE_COLORSET(&temp->flags) &&
++		    SGET_COLORSET(*temp) == colorset)
++		{
++			temp->has_style_changed = 1;
++			temp->change_mask.use_colorset = 1;
++			Scr.flags.do_need_window_update = 1;
++		}
++		if (SUSE_COLORSET_HI(&temp->flags) &&
++		    SGET_COLORSET_HI(*temp) == colorset)
++		{
++			temp->has_style_changed = 1;
++			temp->change_mask.use_colorset_hi = 1;
++			Scr.flags.do_need_window_update = 1;
++		}
++		if (SUSE_BORDER_COLORSET(&temp->flags) &&
++		    SGET_BORDER_COLORSET(*temp) == colorset)
++		{
++			temp->has_style_changed = 1;
++			temp->change_mask.use_border_colorset = 1;
++			Scr.flags.do_need_window_update = 1;
++		}
++		if (SUSE_BORDER_COLORSET_HI(&temp->flags) &&
++		    SGET_BORDER_COLORSET_HI(*temp) == colorset)
++		{
++			temp->has_style_changed = 1;
++			temp->change_mask.use_border_colorset_hi = 1;
++			Scr.flags.do_need_window_update = 1;
++		}
++		if (SUSE_ICON_TITLE_COLORSET(&temp->flags) &&
++		    SGET_ICON_TITLE_COLORSET(*temp) == colorset)
++		{
++			temp->has_style_changed = 1;
++			temp->change_mask.use_icon_title_colorset = 1;
++			Scr.flags.do_need_window_update = 1;
++		}
++		if (SUSE_ICON_TITLE_COLORSET_HI(&temp->flags) &&
++		    SGET_ICON_TITLE_COLORSET_HI(*temp) == colorset)
++		{
++			temp->has_style_changed = 1;
++			temp->change_mask.use_icon_title_colorset_hi = 1;
++			Scr.flags.do_need_window_update = 1;
++		}
++		if (SUSE_ICON_BACKGROUND_COLORSET(&temp->flags) &&
++		    SGET_ICON_BACKGROUND_COLORSET(*temp) == colorset)
++		{
++			temp->has_style_changed = 1;
++			temp->change_mask.use_icon_background_colorset = 1;
++			Scr.flags.do_need_window_update = 1;
++		}
++	}
++
++	return;
++}
++
++/* Update fore and back colours for a specific window */
++void update_window_color_style(FvwmWindow *fw, window_style *pstyle)
++{
++	int cs = Scr.DefaultColorset;
++
++	if (SUSE_COLORSET(&pstyle->flags))
++	{
++		cs = SGET_COLORSET(*pstyle);
++		fw->cs = cs;
++	}
++	else
++	{
++		fw->cs = -1;
++	}
++	if (SGET_FORE_COLOR_NAME(*pstyle) != NULL &&
++	   !SUSE_COLORSET(&pstyle->flags))
++	{
++		fw->colors.fore = GetColor(SGET_FORE_COLOR_NAME(*pstyle));
++	}
++	else
++	{
++		fw->colors.fore = Colorset[cs].fg;
++	}
++	if (SGET_BACK_COLOR_NAME(*pstyle) != NULL &&
++	   !SUSE_COLORSET(&pstyle->flags))
++	{
++		fw->colors.back = GetColor(SGET_BACK_COLOR_NAME(*pstyle));
++		fw->colors.shadow = GetShadow(fw->colors.back);
++		fw->colors.hilight = GetHilite(fw->colors.back);
++	}
++	else
++	{
++		fw->colors.hilight = Colorset[cs].hilite;
++		fw->colors.shadow = Colorset[cs].shadow;
++		fw->colors.back = Colorset[cs].bg;
++	}
++	if (SUSE_BORDER_COLORSET(&pstyle->flags))
++	{
++		cs = SGET_BORDER_COLORSET(*pstyle);
++		fw->border_cs = cs;
++		fw->border_colors.hilight = Colorset[cs].hilite;
++		fw->border_colors.shadow = Colorset[cs].shadow;
++		fw->border_colors.back = Colorset[cs].bg;
++	}
++	else
++	{
++		fw->border_cs = -1;
++		fw->border_colors.hilight = fw->colors.hilight;
++		fw->border_colors.shadow = fw->colors.shadow;
++		fw->border_colors.back = fw->colors.back;
++	}
++}
++
++void update_window_color_hi_style(FvwmWindow *fw, window_style *pstyle)
++{
++	int cs = Scr.DefaultColorset;
++
++	if (SUSE_COLORSET_HI(&pstyle->flags))
++	{
++		cs = SGET_COLORSET_HI(*pstyle);
++		fw->cs_hi = cs;
++	}
++	else
++	{
++		fw->cs_hi = -1;
++	}
++	if (SGET_FORE_COLOR_NAME_HI(*pstyle) != NULL &&
++	   !SUSE_COLORSET_HI(&pstyle->flags))
++	{
++		fw->hicolors.fore = GetColor(SGET_FORE_COLOR_NAME_HI(*pstyle));
++	}
++	else
++	{
++		fw->hicolors.fore = Colorset[cs].fg;
++	}
++	if (SGET_BACK_COLOR_NAME_HI(*pstyle) != NULL &&
++	   !SUSE_COLORSET_HI(&pstyle->flags))
++	{
++		fw->hicolors.back = GetColor(SGET_BACK_COLOR_NAME_HI(*pstyle));
++		fw->hicolors.shadow = GetShadow(fw->hicolors.back);
++		fw->hicolors.hilight = GetHilite(fw->hicolors.back);
++	}
++	else
++	{
++		fw->hicolors.hilight = Colorset[cs].hilite;
++		fw->hicolors.shadow = Colorset[cs].shadow;
++		fw->hicolors.back = Colorset[cs].bg;
++	}
++	if (SUSE_BORDER_COLORSET_HI(&pstyle->flags))
++	{
++		cs = SGET_BORDER_COLORSET_HI(*pstyle);
++		fw->border_cs_hi = cs;
++		fw->border_hicolors.hilight = Colorset[cs].hilite;
++		fw->border_hicolors.shadow = Colorset[cs].shadow;
++		fw->border_hicolors.back = Colorset[cs].bg;
++	}
++	else
++	{
++		fw->border_cs_hi = -1;
++		fw->border_hicolors.hilight = fw->hicolors.hilight;
++		fw->border_hicolors.shadow = fw->hicolors.shadow;
++		fw->border_hicolors.back = fw->hicolors.back;
++	}
++}
++
++void update_icon_title_cs_style(FvwmWindow *fw, window_style *pstyle)
++{
++	if (SUSE_ICON_TITLE_COLORSET(&pstyle->flags))
++	{
++		fw->icon_title_cs = SGET_ICON_TITLE_COLORSET(*pstyle);
++	}
++	else
++	{
++		fw->icon_title_cs = -1;
++	}
++}
++
++void update_icon_title_cs_hi_style(FvwmWindow *fw, window_style *pstyle)
++{
++	if (SUSE_ICON_TITLE_COLORSET_HI(&pstyle->flags))
++	{
++		fw->icon_title_cs_hi = SGET_ICON_TITLE_COLORSET_HI(*pstyle);
++	}
++	else
++	{
++		fw->icon_title_cs_hi = -1;
++	}
++}
++
++void update_icon_background_cs_style(FvwmWindow *fw, window_style *pstyle)
++{
++	if (SUSE_ICON_BACKGROUND_COLORSET(&pstyle->flags))
++	{
++		fw->icon_background_cs =
++			SGET_ICON_BACKGROUND_COLORSET(*pstyle);
++	}
++	else
++	{
++		fw->icon_background_cs = -1;
++	}
++}
++
++void style_destroy_style(style_id_t s_id)
++{
++	FvwmWindow *t;
++
++	if (remove_all_of_style_from_list(s_id))
++	{
++		/* compact the current list of styles */
++		Scr.flags.do_need_style_list_update = 1;
++	}
++	else
++	{
++		return;
++	}
++	/* mark windows for update */
++	for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
++	{
++		if (fw_match_style_id(t, s_id))
++		{
++			SET_STYLE_DELETED(t, 1);
++			Scr.flags.do_need_window_update = 1;
++		}
++	}
++
++	return;
++}
++
++void print_styles(int verbose)
++{
++	window_style *nptr;
++	int count = 0;
++	int mem = 0;
++
++	fprintf(stderr,"Info on fvwm Styles:\n");
++	if (verbose)
++	{
++		fprintf(stderr,"  List of Styles Names:\n");
++	}
++	for (nptr = all_styles; nptr != NULL; nptr = SGET_NEXT_STYLE(*nptr))
++	{
++		count++;
++		if (SGET_ID_HAS_NAME(*nptr))
++		{
++			mem += strlen(SGET_NAME(*nptr));
++			if (verbose)
++			{
++				fprintf(stderr,"    * %s\n", SGET_NAME(*nptr));
++			}
++		}
++		else
++		{
++			mem++;
++			if (verbose)
++			{
++				fprintf(stderr,"    * 0x%lx\n",
++					(unsigned long)SGET_WINDOW_ID(*nptr));
++			}
++		}
++		if (SGET_BACK_COLOR_NAME(*nptr))
++		{
++			mem += strlen(SGET_BACK_COLOR_NAME(*nptr));
++			if (verbose > 1)
++			{
++				fprintf(
++					stderr,"        Back Color: %s\n",
++					SGET_BACK_COLOR_NAME(*nptr));
++			}
++		}
++		if (SGET_FORE_COLOR_NAME(*nptr))
++		{
++			mem += strlen(SGET_FORE_COLOR_NAME(*nptr));
++			if (verbose > 1)
++			{
++				fprintf(
++					stderr,"        Fore Color: %s\n",
++					SGET_FORE_COLOR_NAME(*nptr));
++			}
++		}
++		if (SGET_BACK_COLOR_NAME_HI(*nptr))
++		{
++			mem += strlen(SGET_BACK_COLOR_NAME_HI(*nptr));
++			if (verbose > 1)
++			{
++				fprintf(
++					stderr,"        Back Color hi: %s\n",
++					SGET_BACK_COLOR_NAME_HI(*nptr));
++			}
++		}
++		if (SGET_FORE_COLOR_NAME_HI(*nptr))
++		{
++			mem += strlen(SGET_FORE_COLOR_NAME_HI(*nptr));
++			if (verbose > 1)
++			{
++				fprintf(
++					stderr,"        Fore Color hi: %s\n",
++					SGET_FORE_COLOR_NAME_HI(*nptr));
++			}
++		}
++		if (SGET_DECOR_NAME(*nptr))
++		{
++			mem += strlen(SGET_DECOR_NAME(*nptr));
++			if (verbose > 1)
++			{
++				fprintf(
++					stderr,"        Decor: %s\n",
++					SGET_DECOR_NAME(*nptr));
++			}
++		}
++		if (SGET_WINDOW_FONT(*nptr))
++		{
++			mem += strlen(SGET_WINDOW_FONT(*nptr));
++			if (verbose > 1)
++			{
++				fprintf(
++					stderr,"        Window Font: %s\n",
++					SGET_WINDOW_FONT(*nptr));
++			}
++		}
++		if (SGET_ICON_FONT(*nptr))
++		{
++			mem += strlen(SGET_ICON_FONT(*nptr));
++			if (verbose > 1)
++			{
++				fprintf(
++					stderr,"        Icon Font: %s\n",
++					SGET_ICON_FONT(*nptr));
++			}
++		}
++		if (SGET_ICON_NAME(*nptr))
++		{
++			mem += strlen(SGET_ICON_NAME(*nptr));
++			if (verbose > 1)
++			{
++				fprintf(
++					stderr,"        Icon Name: %s\n",
++					SGET_ICON_NAME(*nptr));
++			}
++		}
++		if (SGET_MINI_ICON_NAME(*nptr))
++		{
++			mem += strlen(SGET_MINI_ICON_NAME(*nptr));
++			if (verbose > 1)
++			{
++				fprintf(
++					stderr,"        MiniIcon Name: %s\n",
++					SGET_MINI_ICON_NAME(*nptr));
++			}
++		}
++		if (SGET_ICON_BOXES(*nptr))
++		{
++			mem += sizeof(icon_boxes);
++		}
++	}
++	fprintf(stderr,"  Number of styles: %d, Memory Used: %d bits\n",
++		count, (int)(count*sizeof(window_style) + mem));
++
++	return;
++}
++
++/* ---------------------------- builtin commands --------------------------- */
++
++void CMD_Style(F_CMD_ARGS)
++{
++	__style_command(F_PASS_ARGS, NULL, False);
++
++	return;
++}
++
++void CMD_WindowStyle(F_CMD_ARGS)
++{
++	__style_command(F_PASS_ARGS, NULL, True);
++
++	return;
++}
++
++void CMD_FocusStyle(F_CMD_ARGS)
++{
++	__style_command(F_PASS_ARGS, "FP", False);
++
++	return;
++}
++
++void CMD_DestroyStyle(F_CMD_ARGS)
++{
++	char *name;
++	style_id_t s_id;
++
++	/* parse style name */
++	name = PeekToken(action, &action);
++
++	/* in case there was no argument! */
++	if (name == NULL)
++		return;
++
++	memset(&s_id, 0, sizeof(style_id_t));
++	SID_SET_NAME(s_id, name);
++	SID_SET_HAS_NAME(s_id, True);
++
++	/* Do it */
++	style_destroy_style(s_id);
++	return;
++}
++
++void CMD_DestroyWindowStyle(F_CMD_ARGS)
++{
++	style_id_t s_id;
++
++	memset(&s_id, 0, sizeof(style_id_t));
++	SID_SET_WINDOW_ID(s_id, (XID)FW_W(exc->w.fw));
++	SID_SET_HAS_WINDOW_ID(s_id, True);
++
++	/* Do it */
++	style_destroy_style(s_id);
++	return;
++}
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/style.h fvwm-2.5.21-05/fvwm/style.h
+--- fvwm-2.5.21-04/fvwm/style.h	2007-03-03 13:18:21.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/style.h	2007-03-03 13:18:49.000000000 +0100
+@@ -328,20 +328,24 @@
+ #define S_SET_USE_INDEXED_ICON_NAME(c,x) \
+ 	((c).s.use_indexed_icon_name = !!(x))
+ #define S_WINDOWSHADE_LAZINESS(c) \
+ 	((c).s.windowshade_laziness)
+ #define S_SET_WINDOWSHADE_LAZINESS(c,x) \
+ 	((c).s.windowshade_laziness = (x))
+ #define S_USE_TITLE_DECOR_ROTATION(c) \
+ 	((c).s.use_title_decor_rotation)
+ #define S_SET_USE_TITLE_DECOR_ROTATION(c,x) \
+ 	((c).s.use_title_decor_rotation = !!(x))
++#define S_HAS_BORDER_UNDER_TITLE(c) \
++	((c).s.has_border_under_title)
++#define S_SET_HAS_BORDER_UNDER_TITLE(c,x) \
++	((c).s.has_border_under_title = !!(x))
+ #define S_DO_EWMH_MINI_ICON_OVERRIDE(c) \
+ 	((c).s.do_ewmh_mini_icon_override)
+ #define S_SET_DO_EWMH_MINI_ICON_OVERRIDE(c,x) \
+ 	((c).s.do_ewmh_mini_icon_override = !!(x))
+ #define S_DO_EWMH_DONATE_ICON(c) \
+ 	((c).s.do_ewmh_donate_icon)
+ #define S_SET_DO_EWMH_DONATE_ICON(c,x) \
+ 	((c).s.do_ewmh_donate_icon = !!(x))
+ #define S_DO_EWMH_DONATE_MINI_ICON(c) \
+ 	((c).s.do_ewmh_donate_mini_icon)
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/style.h~ fvwm-2.5.21-05/fvwm/style.h~
+--- fvwm-2.5.21-04/fvwm/style.h~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/style.h~	2007-03-03 13:18:42.000000000 +0100
+@@ -0,0 +1,617 @@
++/* -*-c-*- */
++
++#ifndef _STYLE_
++#define _STYLE_
++
++/* access to the special flags of a style */
++/* call these with a pointer to a style_flags struct */
++#define SDO_DECORATE_TRANSIENT(sf) \
++	((sf)->do_decorate_transient)
++#define SDO_SAVE_UNDER(sf) \
++	((sf)->do_save_under)
++#define SDO_START_LOWERED(sf) \
++	((sf)->do_start_lowered)
++#define SHAS_BORDER_WIDTH(sf) \
++	((sf)->has_border_width)
++#define SHAS_COLOR_BACK(sf) \
++	((sf)->has_color_back)
++#define SHAS_COLOR_FORE(sf) \
++	((sf)->has_color_fore)
++#define SHAS_HANDLE_WIDTH(sf) \
++	((sf)->has_handle_width)
++#define SHAS_ICON(sf) \
++	((sf)->has_icon)
++#define SHAS_ICON_BOXES(sf) \
++	((sf)->has_icon_boxes)
++#define SHAS_ICON_SIZE_LIMITS(sf) \
++	((sf)->has_icon_size_limits)
++#define SHAS_ICON_BACKGROUND_PADDING(sf) \
++	((sf)->has_icon_background_padding)
++#define SHAS_ICON_BACKGROUND_RELIEF(sf) \
++	((sf)->has_icon_background_relief)
++#define SHAS_ICON_TITLE_RELIEF(sf) \
++	((sf)->has_icon_title_relief)
++#define SHAS_MAX_WINDOW_SIZE(sf) \
++	((sf)->has_max_window_size)
++#define SHAS_WINDOW_SHADE_STEPS(sf) \
++	((sf)->has_window_shade_steps)
++#define SHAS_MINI_ICON(sf) \
++	((sf)->has_mini_icon)
++#define SHAS_MWM_DECOR(sf) \
++	((sf)->has_mwm_decor)
++#define SHAS_MWM_FUNCTIONS(sf) \
++	((sf)->has_mwm_functions)
++#define SHAS_NO_HANDLES(sf) \
++	((sf)->has_no_handles)
++#define SHAS_NO_TITLE(sf) \
++	((sf)->has_no_title)
++#define SHAS_OL_DECOR(sf) \
++	((sf)->has_ol_decor)
++#define SIS_BUTTON_DISABLED(sf) \
++	((sf)->is_button_disabled)
++#define SIS_UNMANAGED(sf) \
++	((sf)->is_unmanaged)
++#define SPLACEMENT_MODE(sf) \
++	((sf)->placement_mode)
++#define SEWMH_PLACEMENT_MODE(sf) \
++	((sf)->ewmh_placement_mode)
++#define SUSE_BACKING_STORE(sf) \
++	((sf)->use_backing_store)
++#define SUSE_PARENT_RELATIVE(sf) \
++	((sf)->use_parent_relative)
++#define SUSE_COLORSET(sf) \
++	((sf)->use_colorset)
++#define SUSE_COLORSET_HI(sf) \
++	((sf)->use_colorset_hi)
++#define SUSE_BORDER_COLORSET(sf) \
++	((sf)->use_border_colorset)
++#define SUSE_BORDER_COLORSET_HI(sf) \
++	((sf)->use_border_colorset_hi)
++#define SUSE_ICON_TITLE_COLORSET(sf) \
++	((sf)->use_icon_title_colorset)
++#define SUSE_ICON_TITLE_COLORSET_HI(sf) \
++	((sf)->use_icon_title_colorset_hi)
++#define SUSE_ICON_BACKGROUND_COLORSET(sf) \
++	((sf)->use_icon_background_colorset)
++#define SUSE_LAYER(sf) \
++	((sf)->use_layer)
++#define SUSE_NO_PPOSITION(sf) \
++	((sf)->use_no_pposition)
++#define SUSE_NO_USPOSITION(sf) \
++	((sf)->use_no_usposition)
++#define SUSE_NO_TRANSIENT_PPOSITION(sf) \
++	((sf)->use_no_transient_pposition)
++#define SUSE_NO_TRANSIENT_USPOSITION(sf) \
++	((sf)->use_no_transient_usposition)
++#define SUSE_START_ON_DESK(sf) \
++	((sf)->use_start_on_desk)
++#define SUSE_START_ON_PAGE_FOR_TRANSIENT(sf) \
++	((sf)->use_start_on_page_for_transient)
++#define SUSE_START_ON_SCREEN(sf) \
++	((sf)->use_start_on_screen)
++#define SMANUAL_PLACEMENT_HONORS_STARTS_ON_PAGE(sf) \
++	((sf)->manual_placement_honors_starts_on_page)
++#define SCAPTURE_HONORS_STARTS_ON_PAGE(sf) \
++	((sf)->capture_honors_starts_on_page)
++#define SRECAPTURE_HONORS_STARTS_ON_PAGE(sf) \
++	((sf)->recapture_honors_starts_on_page)
++#define SHAS_PLACEMENT_PENALTY(sf) \
++	((sf)->has_placement_penalty)
++#define SHAS_PLACEMENT_PERCENTAGE_PENALTY(sf) \
++	((sf)->has_placement_percentage_penalty)
++#define SCR_MOTION_METHOD(sf) \
++	((sf)->ws_cr_motion_method)
++
++/* access the various copies of the common flags structure. */
++#define SCF(st) \
++	((st).flags.common)
++#define SCFS(st) \
++	((st).flags.common.s)
++#define SCM(st) \
++	((st).flag_mask.common)
++#define SCMS(st) \
++	((st).flag_mask.common.s)
++#define SCD(st) \
++	((st).flag_default.common)
++#define SCDS(st) \
++	((st).flag_default.common.s)
++#define SCC(st) \
++	((st).change_mask.common)
++#define SCCS(st) \
++	((st).change_mask.common.s)
++#define SFC(sf) \
++	((sf).common)
++
++/* access to common flags */
++#define S_FOCUS_POLICY(c) \
++	((c).s.focus_policy)
++#define S_TITLE_DIR(c) \
++	((c).title_dir)
++#define S_SET_TITLE_DIR(c,x) \
++	((c).title_dir = (x))
++#define S_USER_STATES(c) \
++	((c).user_states)
++#define S_SET_USER_STATES(c,x) \
++	((c).user_states = (x))
++#define S_ADD_USER_STATES(c,x) \
++	((c).user_states = ((c).user_states | (x)))
++#define S_IS_STICKY_ACROSS_PAGES(c) \
++	((c).is_sticky_across_pages)
++#define S_SET_IS_STICKY_ACROSS_PAGES(c,x) \
++	((c).is_sticky_across_pages = !!(x))
++#define S_IS_STICKY_ACROSS_DESKS(c) \
++	((c).is_sticky_across_desks)
++#define S_SET_IS_STICKY_ACROSS_DESKS(c,x) \
++	((c).is_sticky_across_desks = !!(x))
++#define S_DO_CIRCULATE_SKIP(c) \
++	((c).s.do_circulate_skip)
++#define S_SET_DO_CIRCULATE_SKIP(c,x) \
++	((c).s.do_circulate_skip = !!(x))
++#define S_DO_CIRCULATE_SKIP_ICON(c) \
++	((c).s.do_circulate_skip_icon)
++#define S_SET_DO_CIRCULATE_SKIP_ICON(c,x) \
++	((c).s.do_circulate_skip_icon = !!(x))
++#define S_DO_CIRCULATE_SKIP_SHADED(c) \
++	((c).s.do_circulate_skip_shaded)
++#define S_SET_DO_CIRCULATE_SKIP_SHADED(c,x) \
++	((c).s.do_circulate_skip_shaded = !!(x))
++#define S_DO_ICONIFY_WINDOW_GROUPS(c) \
++	((c).s.do_iconify_window_groups)
++#define S_SET_DO_ICONIFY_WINDOW_GROUPS(c,x) \
++	((c).s.do_iconify_window_groups = !!(x))
++#define S_DO_IGNORE_GNOME_HINTS(c) \
++	((c).s.do_ignore_gnome_hints)
++#define S_SET_DO_IGNORE_GNOME_HINTS(c,x) \
++	((c).s.do_ignore_gnome_hints = !!(x))
++#define S_DO_IGNORE_ICON_BOXES(c) \
++	((c).s.do_ignore_icon_boxes)
++#define S_SET_DO_IGNORE_ICON_BOXES(c,x) \
++	((c).s.do_ignore_icon_boxes = !!(x))
++#define S_DO_IGNORE_RESTACK(c) \
++	((c).s.do_ignore_restack)
++#define S_SET_DO_IGNORE_RESTACK(c,x) \
++	((c).s.do_ignore_restack = !!(x))
++#define S_DO_USE_WINDOW_GROUP_HINT(c) \
++	((c).s.do_use_window_group_hint)
++#define S_SET_DO_USE_WINDOW_GROUP_HINT(c,x) \
++	((c).s.do_use_window_group_hint = !!(x))
++#define S_DO_LOWER_TRANSIENT(c) \
++	((c).s.do_lower_transient)
++#define S_SET_DO_LOWER_TRANSIENT(c,x) \
++	((c).s.do_lower_transient = !!(x))
++#define S_DO_NOT_SHOW_ON_MAP(c) \
++	((c).s.do_not_show_on_map)
++#define S_SET_DO_NOT_SHOW_ON_MAP(c,x) \
++	((c).s.do_not_show_on_map = !!(x))
++#define S_DO_RAISE_TRANSIENT(c) \
++	((c).s.do_raise_transient)
++#define S_SET_DO_RAISE_TRANSIENT(c,x) \
++	((c).s.do_raise_transient = !!(x))
++#define S_DO_RESIZE_OPAQUE(c) \
++	((c).s.do_resize_opaque)
++#define S_SET_DO_RESIZE_OPAQUE(c,x) \
++	((c).s.do_resize_opaque = !!(x))
++#define S_DO_RESIZE_OUTLINE_THIN(c) \
++	((c).s.do_resize_outline_thin)
++#define S_SET_DO_RESIZE_OUTLINE_THIN(c,x) \
++	((c).s.do_resize_outline_thin = !!(x))
++#define S_DO_SHRINK_WINDOWSHADE(c) \
++	((c).s.do_shrink_windowshade)
++#define S_SET_DO_SHRINK_WINDOWSHADE(c,x) \
++	((c).s.do_shrink_windowshade = !!(x))
++#define S_DO_STACK_TRANSIENT_PARENT(c) \
++	((c).s.do_stack_transient_parent)
++#define S_SET_DO_STACK_TRANSIENT_PARENT(c,x) \
++	((c).s.do_stack_transient_parent = !!(x))
++#define S_DO_WINDOW_LIST_SKIP(c) \
++	((c).s.do_window_list_skip)
++#define S_SET_DO_WINDOW_LIST_SKIP(c,x) \
++	((c).s.do_window_list_skip = !!(x))
++#define S_HAS_NO_BORDER(c) \
++	((c).has_no_border)
++#define S_SET_HAS_NO_BORDER(c,x) \
++	((c).has_no_border = !!(x))
++#define S_HAS_DEPRESSABLE_BORDER(c) \
++	((c).s.has_depressable_border)
++#define S_SET_HAS_DEPRESSABLE_BORDER(c,x) \
++	((c).s.has_depressable_border = !!(x))
++#define S_HAS_ICON_FONT(c) \
++	((c).has_icon_font)
++#define S_SET_HAS_ICON_FONT(c,x) \
++	((c).has_icon_font = !!(x))
++#define S_HAS_MWM_BORDER(c) \
++	((c).s.has_mwm_border)
++#define S_SET_HAS_MWM_BORDER(c,x) \
++	((c).s.has_mwm_border = !!(x))
++#define S_HAS_MWM_BUTTONS(c) \
++	((c).s.has_mwm_buttons)
++#define S_SET_HAS_MWM_BUTTONS(c,x) \
++	((c).s.has_mwm_buttons = !!(x))
++#define S_HAS_MWM_OVERRIDE(c) \
++	((c).s.has_mwm_override)
++#define S_SET_HAS_MWM_OVERRIDE(c,x) \
++	((c).s.has_mwm_override = !!(x))
++#define S_HAS_NO_STICKY_STIPPLED_ICON_TITLE(c) \
++	((c).s.has_no_sticky_stippled_icon_title)
++#define S_SET_HAS_NO_STICKY_STIPPLED_ICON_TITLE(c,x) \
++	((c).s.has_no_sticky_stippled_icon_title = !!(x))
++#define S_HAS_NO_ICON_TITLE(c) \
++	((c).s.has_no_icon_title)
++#define S_SET_HAS_NO_ICON_TITLE(c,x) \
++	((c).s.has_no_icon_title = !!(x))
++#define S_HAS_OVERRIDE_SIZE(c) \
++	((c).s.has_override_size)
++#define S_SET_HAS_OVERRIDE_SIZE(c,x) \
++	((c).s.has_override_size = !!(x))
++#define S_HAS_STIPPLED_TITLE(c) \
++	((c).s.has_stippled_title)
++#define S_SET_HAS_STIPPLED_TITLE(c,x) \
++	((c).s.has_stippled_title = !!(x))
++#define S_HAS_NO_STICKY_STIPPLED_TITLE(c) \
++	((c).s.has_no_sticky_stippled_title)
++#define S_SET_HAS_NO_STICKY_STIPPLED_TITLE(c,x) \
++	((c).s.has_no_sticky_stippled_title = !!(x))
++#define S_HAS_STIPPLED_ICON_TITLE(c) \
++	((c).s.has_stippled_icon_title)
++#define S_SET_HAS_STIPPLED_ICON_TITLE(c,x) \
++	((c).s.has_stippled_icon_title = !!(x))
++#define S_HAS_WINDOW_FONT(c) \
++	((c).has_window_font)
++#define S_SET_HAS_WINDOW_FONT(c,x) \
++	((c).has_window_font = !!(x))
++#define S_ICON_OVERRIDE(c) \
++	((c).s.icon_override)
++#define S_SET_ICON_OVERRIDE(c,x) \
++	((c).s.icon_override = (x))
++#define S_IS_BOTTOM_TITLE_ROTATED(c) \
++	((c).s.is_bottom_title_rotated)
++#define S_SET_IS_BOTTOM_TITLE_ROTATED(c,x) \
++	((c).s.is_bottom_title_rotated = !!(x))
++#define S_IS_FIXED(c) \
++	((c).s.is_fixed)
++#define S_SET_IS_FIXED(c,x) \
++	((c).s.is_fixed = !!(x))
++#define S_IS_FIXED_PPOS(c) \
++	((c).s.is_fixed_ppos)
++#define S_SET_IS_FIXED_PPOS(c,x) \
++	((c).s.is_fixed_ppos = !!(x))
++#define S_SET_IS_UNICONIFIABLE(c,x) \
++	((c).s.is_uniconifiable = !!(x))
++#define S_SET_IS_UNMAXIMIZABLE(c,x) \
++	((c).s.is_unmaximizable = !!(x))
++#define S_SET_IS_UNCLOSABLE(c,x) \
++	((c).s.is_unclosable = !!(x))
++#define S_SET_MAXIMIZE_FIXED_SIZE_DISALLOWED(c,x) \
++	((c).s.is_maximize_fixed_size_disallowed = !!(x))
++#define S_IS_ICON_STICKY_ACROSS_PAGES(c) \
++	((c).s.is_icon_sticky_across_pages)
++#define S_SET_IS_ICON_STICKY_ACROSS_PAGES(c,x) \
++	((c).s.is_icon_sticky_across_pages = !!(x))
++#define S_IS_ICON_STICKY_ACROSS_DESKS(c) \
++	((c).s.is_icon_sticky_across_desks)
++#define S_SET_IS_ICON_STICKY_ACROSS_DESKS(c,x) \
++	((c).s.is_icon_sticky_across_desks = !!(x))
++#define S_IS_ICON_SUPPRESSED(c) \
++	((c).s.is_icon_suppressed)
++#define S_SET_IS_ICON_SUPPRESSED(c,x) \
++	((c).s.is_icon_suppressed = !!(x))
++#define S_IS_LEFT_TITLE_ROTATED_CW(c) \
++	((c).s.is_left_title_rotated_cw)
++#define S_SET_IS_LEFT_TITLE_ROTATED_CW(c,x) \
++	((c).s.is_left_title_rotated_cw = !!(x))
++#define S_IS_SIZE_FIXED(c) \
++	((c).s.is_size_fixed)
++#define S_SET_IS_SIZE_FIXED(c,x) \
++	((c).s.is_size_fixed = !!(x))
++#define S_IS_PSIZE_FIXED(c) \
++	((c).s.is_psize_fixed)
++#define S_SET_IS_PSIZE_FIXED(c,x) \
++	((c).s.is_psize_fixed = !!(x))
++#define S_IS_RIGHT_TITLE_ROTATED_CW(c) \
++	((c).s.is_right_title_rotated_cw)
++#define S_SET_IS_RIGHT_TITLE_ROTATED_CW(c,x) \
++	((c).s.is_right_title_rotated_cw = !!(x))
++#define S_IS_TOP_TITLE_ROTATED(c) \
++	((c).s.is_top_title_rotated)
++#define S_SET_IS_TOP_TITLE_ROTATED(c,x) \
++	((c).s.is_top_title_rotated = !!(x))
++#define S_USE_ICON_POSITION_HINT(c) \
++	((c).s.use_icon_position_hint)
++#define S_SET_USE_ICON_POSITION_HINT(c,x) \
++	((c).s.use_icon_position_hint = !!(x))
++#define S_USE_INDEXED_WINDOW_NAME(c) \
++	((c).s.use_indexed_window_name)
++#define S_SET_USE_INDEXED_WINDOW_NAME(c,x) \
++	((c).s.use_indexed_window_name = !!(x))
++#define S_USE_INDEXED_ICON_NAME(c) \
++	((c).s.use_indexed_icon_name)
++#define S_SET_USE_INDEXED_ICON_NAME(c,x) \
++	((c).s.use_indexed_icon_name = !!(x))
++#define S_WINDOWSHADE_LAZINESS(c) \
++	((c).s.windowshade_laziness)
++#define S_SET_WINDOWSHADE_LAZINESS(c,x) \
++	((c).s.windowshade_laziness = (x))
++#define S_USE_TITLE_DECOR_ROTATION(c) \
++	((c).s.use_title_decor_rotation)
++#define S_SET_USE_TITLE_DECOR_ROTATION(c,x) \
++	((c).s.use_title_decor_rotation = !!(x))
++#define S_DO_EWMH_MINI_ICON_OVERRIDE(c) \
++	((c).s.do_ewmh_mini_icon_override)
++#define S_SET_DO_EWMH_MINI_ICON_OVERRIDE(c,x) \
++	((c).s.do_ewmh_mini_icon_override = !!(x))
++#define S_DO_EWMH_DONATE_ICON(c) \
++	((c).s.do_ewmh_donate_icon)
++#define S_SET_DO_EWMH_DONATE_ICON(c,x) \
++	((c).s.do_ewmh_donate_icon = !!(x))
++#define S_DO_EWMH_DONATE_MINI_ICON(c) \
++	((c).s.do_ewmh_donate_mini_icon)
++#define S_SET_DO_EWMH_DONATE_MINI_ICON(c,x) \
++	((c).s.do_ewmh_donate_mini_icon = !!(x))
++#define S_DO_EWMH_USE_STACKING_HINTS(c) \
++	((c).s.do_ewmh_use_stacking_hints)
++#define S_SET_DO_EWMH_USE_STACKING_HINTS(c,x) \
++	((c).s.do_ewmh_use_stacking_hints = !!(x))
++#define S_DO_EWMH_IGNORE_STRUT_HINTS(c) \
++	((c).s.do_ewmh_ignore_strut_hints)
++#define S_SET_DO_EWMH_IGNORE_STRUT_HINTS(c,x) \
++	((c).s.do_ewmh_ignore_strut_hints = !!(x))
++#define S_DO_EWMH_IGNORE_STATE_HINTS(c) \
++	((c).s.do_ewmh_ignore_state_hints)
++#define S_SET_DO_EWMH_IGNORE_STATE_HINTS(c,x) \
++	((c).s.do_ewmh_ignore_state_hints = !!(x))
++#define S_DO_EWMH_IGNORE_WINDOW_TYPE(c) \
++	((c).s.do_ewmh_ignore_window_type)
++#define S_SET_DO_EWMH_IGNORE_WINDOW_TYPE(c,x) \
++	((c).s.do_ewmh_ignore_window_type = !!(x))
++#define S_EWMH_MAXIMIZE_MODE(c) \
++	((c).s.ewmh_maximize_mode)
++#define S_SET_EWMH_MAXIMIZE_MODE(c,x) \
++	((c).s.ewmh_maximize_mode = (x))
++
++/* access to style_id */
++#define SID_GET_NAME(id) \
++	((id).name)
++#define SID_SET_NAME(id,x) \
++	((id).name = (x))
++#define SID_GET_WINDOW_ID(id) \
++	((id).window_id)
++#define SID_SET_WINDOW_ID(id,x) \
++	((id).window_id = (x))
++#define SID_SET_HAS_NAME(id,x) \
++	((id).flags.has_name = !!(x))
++#define SID_GET_HAS_NAME(id) \
++	((id).flags.has_name)
++#define SID_SET_HAS_WINDOW_ID(id,x) \
++	((id).flags.has_window_id = !!(x))
++#define SID_GET_HAS_WINDOW_ID(id) \
++	((id).flags.has_window_id)
++
++/* access to other parts of a style (call with the style itself) */
++#define SGET_NEXT_STYLE(s) \
++	((s).next)
++#define SSET_NEXT_STYLE(s,x) \
++	((s).next = (x))
++#define SGET_PREV_STYLE(s) \
++	((s).prev)
++#define SSET_PREV_STYLE(s,x) \
++	((s).prev = (x))
++#define SGET_ID(s) \
++	((s).id)
++#define SGET_NAME(s) \
++	SID_GET_NAME(SGET_ID(s))
++#define SSET_NAME(s,x) \
++	SID_SET_NAME(SGET_ID(s),x)
++#define SGET_WINDOW_ID(s) \
++	SID_GET_WINDOW_ID(SGET_ID(s))
++#define SSET_WINDOW_ID(s,x) \
++	SID_SET_WINDOW_ID(SGET_ID(s),x)
++#define SSET_ID_HAS_NAME(s,x) \
++        SID_SET_HAS_NAME(SGET_ID(s), x)
++#define SGET_ID_HAS_NAME(s) \
++	SID_GET_HAS_NAME(SGET_ID(s))
++#define SSET_ID_HAS_WINDOW_ID(s,x) \
++	SID_SET_HAS_WINDOW_ID(SGET_ID(s),x)
++#define SGET_ID_HAS_WINDOW_ID(s) \
++	SID_GET_HAS_WINDOW_ID(SGET_ID(s))
++#define SGET_ICON_NAME(s) \
++	((s).icon_name)
++#define SSET_ICON_NAME(s,x) \
++	((s).icon_name = (x))
++#define SGET_MINI_ICON_NAME(s) \
++	((s).mini_icon_name)
++#define SSET_MINI_ICON_NAME(s,x) \
++	((s).mini_icon_name = (x))
++#ifdef USEDECOR
++#define SGET_DECOR_NAME(s) \
++	((s).decor_name)
++#define SSET_DECOR_NAME(s,x) \
++	((s).decor_name = (x))
++#endif
++#define SGET_FORE_COLOR_NAME(s) \
++	((s).fore_color_name)
++#define SSET_FORE_COLOR_NAME(s,x) \
++	((s).fore_color_name = (x))
++#define SGET_BACK_COLOR_NAME(s) \
++	((s).back_color_name)
++#define SSET_BACK_COLOR_NAME(s,x) \
++	((s).back_color_name = (x))
++#define SGET_FORE_COLOR_NAME_HI(s) \
++	((s).fore_color_name_hi)
++#define SSET_FORE_COLOR_NAME_HI(s,x) \
++	((s).fore_color_name_hi = (x))
++#define SGET_BACK_COLOR_NAME_HI(s) \
++	((s).back_color_name_hi)
++#define SSET_BACK_COLOR_NAME_HI(s,x) \
++	((s).back_color_name_hi = (x))
++#define SGET_ICON_FONT(s) \
++	((s).icon_font)
++#define SSET_ICON_FONT(s,x) \
++	((s).icon_font = (x))
++#define SGET_WINDOW_FONT(s) \
++	((s).window_font)
++#define SSET_WINDOW_FONT(s,x) \
++	((s).window_font = (x))
++#define SGET_COLORSET(s) \
++	((s).colorset)
++#define SSET_COLORSET(s,x) \
++	((s).colorset = (x))
++#define SSET_BORDER_COLORSET(s,x) \
++	((s).border_colorset = (x))
++#define SGET_BORDER_COLORSET(s) \
++	((s).border_colorset)
++#define SGET_COLORSET_HI(s) \
++	((s).colorset_hi)
++#define SSET_COLORSET_HI(s,x) \
++	((s).colorset_hi = (x))
++#define SGET_BORDER_COLORSET_HI(s) \
++	((s).border_colorset_hi)
++#define SSET_BORDER_COLORSET_HI(s,x) \
++	((s).border_colorset_hi = (x))
++#define SSET_ICON_TITLE_COLORSET(s,x) \
++	((s).icon_title_colorset = (x))
++#define SGET_ICON_TITLE_COLORSET(s) \
++	((s).icon_title_colorset)
++#define SSET_ICON_TITLE_COLORSET_HI(s,x) \
++	((s).icon_title_colorset_hi = (x))
++#define SGET_ICON_TITLE_COLORSET_HI(s) \
++	((s).icon_title_colorset_hi)
++#define SSET_ICON_BACKGROUND_COLORSET(s,x) \
++	((s).icon_background_colorset = (x))
++#define SGET_ICON_BACKGROUND_COLORSET(s) \
++	((s).icon_background_colorset)
++#define SGET_FLAGS_POINTER(s) \
++	(&((s).flags))
++#define SGET_BORDER_WIDTH(s) \
++	((s).border_width)
++#define SSET_BORDER_WIDTH(s,x) \
++	((s).border_width = (x))
++#define SGET_HANDLE_WIDTH(s) \
++	((s).handle_width)
++#define SSET_HANDLE_WIDTH(s,x) \
++	((s).handle_width = (x))
++#define SGET_LAYER(s) \
++	((s).layer)
++#define SSET_LAYER(s,x) \
++	((s).layer = (x))
++#define SGET_START_DESK(s) \
++	((s).start_desk)
++#define SSET_START_DESK(s,x) \
++	((s).start_desk = (x))
++#define SGET_START_PAGE_X(s) \
++	((s).start_page_x)
++#define SSET_START_PAGE_X(s,x) \
++	((s).start_page_x = (x))
++#define SGET_START_PAGE_Y(s) \
++	((s).start_page_y)
++#define SSET_START_PAGE_Y(s,x) \
++	((s).start_page_y = (x))
++#define SGET_START_SCREEN(s) \
++	((s).start_screen)
++#define SSET_START_SCREEN(s,x) \
++	((s).start_screen = (x))
++#define SGET_MIN_ICON_WIDTH(s) \
++	((s).min_icon_width)
++#define SSET_MIN_ICON_WIDTH(s,x) \
++	((s).min_icon_width = (x))
++#define SGET_MIN_ICON_HEIGHT(s) \
++	((s).min_icon_height)
++#define SSET_MIN_ICON_HEIGHT(s,x) \
++	((s).min_icon_height = (x))
++#define SGET_MAX_ICON_WIDTH(s) \
++	((s).max_icon_width)
++#define SSET_MAX_ICON_WIDTH(s,x) \
++	((s).max_icon_width = (x))
++#define SGET_MAX_ICON_HEIGHT(s) \
++	((s).max_icon_height)
++#define SSET_MAX_ICON_HEIGHT(s,x) \
++	((s).max_icon_height = (x))
++#define SGET_ICON_RESIZE_TYPE(s) \
++	((s).icon_resize_type)
++#define SSET_ICON_RESIZE_TYPE(s,x) \
++	((s).icon_resize_type = (x))
++#define SGET_ICON_BACKGROUND_RELIEF(s) \
++	((s).icon_background_relief)
++#define SSET_ICON_BACKGROUND_RELIEF(s,x) \
++	((s).icon_background_relief = (x))
++#define SGET_ICON_BACKGROUND_PADDING(s) \
++	((s).icon_background_padding)
++#define SSET_ICON_BACKGROUND_PADDING(s,x) \
++	((s).icon_background_padding = (x))
++#define SGET_ICON_TITLE_RELIEF(s) \
++	((s).icon_title_relief)
++#define SSET_ICON_TITLE_RELIEF(s,x) \
++	((s).icon_title_relief = (x))
++#define SGET_MAX_WINDOW_WIDTH(s) \
++	((s).max_window_width)
++#define SSET_MAX_WINDOW_WIDTH(s,x) \
++	((s).max_window_width = (x))
++#define SGET_MAX_WINDOW_HEIGHT(s) \
++	((s).max_window_height)
++#define SSET_MAX_WINDOW_HEIGHT(s,x) \
++	((s).max_window_height = (x))
++#define SGET_WINDOW_SHADE_STEPS(s) \
++	((s).shade_anim_steps)
++#define SSET_WINDOW_SHADE_STEPS(s,x) \
++	((s).shade_anim_steps = (x))
++#define SGET_ICON_BOXES(s) \
++	((s).icon_boxes)
++#define SSET_ICON_BOXES(s,x) \
++	((s).icon_boxes = (x))
++#define SGET_NORMAL_PLACEMENT_PENALTY(s) \
++	((s).placement_penalty[0])
++#define SGET_ONTOP_PLACEMENT_PENALTY(s) \
++	((s).placement_penalty[1])
++#define SGET_ICON_PLACEMENT_PENALTY(s) \
++	((s).placement_penalty[2])
++#define SGET_STICKY_PLACEMENT_PENALTY(s) \
++	((s).placement_penalty[3])
++#define SGET_BELOW_PLACEMENT_PENALTY(s) \
++	((s).placement_penalty[4])
++#define SGET_EWMH_STRUT_PLACEMENT_PENALTY(s) \
++	((s).placement_penalty[5])
++#define SSET_NORMAL_PLACEMENT_PENALTY(s,x) \
++	((s).placement_penalty[0] = (x))
++#define SSET_ONTOP_PLACEMENT_PENALTY(s,x) \
++	((s).placement_penalty[1] = (x))
++#define SSET_ICON_PLACEMENT_PENALTY(s,x) \
++	((s).placement_penalty[2] = (x))
++#define SSET_STICKY_PLACEMENT_PENALTY(s,x) \
++	((s).placement_penalty[3] = (x))
++#define SSET_BELOW_PLACEMENT_PENALTY(s,x) \
++	((s).placement_penalty[4] = (x))
++#define SSET_EWMH_STRUT_PLACEMENT_PENALTY(s,x) \
++	((s).placement_penalty[5] = (x))
++#define SGET_99_PLACEMENT_PERCENTAGE_PENALTY(s) \
++	((s).placement_percentage_penalty[0])
++#define SGET_95_PLACEMENT_PERCENTAGE_PENALTY(s) \
++	((s).placement_percentage_penalty[1])
++#define SGET_85_PLACEMENT_PERCENTAGE_PENALTY(s) \
++	((s).placement_percentage_penalty[2])
++#define SGET_75_PLACEMENT_PERCENTAGE_PENALTY(s) \
++	((s).placement_percentage_penalty[3])
++#define SSET_99_PLACEMENT_PERCENTAGE_PENALTY(s,x) \
++	((s).placement_percentage_penalty[0] = (x))
++#define SSET_95_PLACEMENT_PERCENTAGE_PENALTY(s,x) \
++	((s).placement_percentage_penalty[1] = (x))
++#define SSET_85_PLACEMENT_PERCENTAGE_PENALTY(s,x) \
++	((s).placement_percentage_penalty[2] = (x))
++#define SSET_75_PLACEMENT_PERCENTAGE_PENALTY(s,x) \
++	((s).placement_percentage_penalty[3] = (x))
++
++/* function prototypes */
++void lookup_style(FvwmWindow *fw, window_style *styles);
++Bool blockcmpmask(char *blk1, char *blk2, char *mask, int length);
++void check_window_style_change(
++	FvwmWindow *t, update_win *flags, window_style *ret_style);
++void reset_style_changes(void);
++void update_style_colorset(int colorset);
++void update_window_color_style(FvwmWindow *fw, window_style *style);
++void update_window_color_hi_style(FvwmWindow *fw, window_style *style);
++void update_icon_title_cs_style(FvwmWindow *fw, window_style *pstyle);
++void update_icon_title_cs_hi_style(FvwmWindow *fw, window_style *pstyle);
++void update_icon_background_cs_style(FvwmWindow *fw, window_style *pstyle);
++void free_icon_boxes(icon_boxes *ib);
++void style_destroy_style(style_id_t s_id);
++void print_styles(int verbose);
++
++#endif /* _STYLE_ */
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/window_flags.h fvwm-2.5.21-05/fvwm/window_flags.h
+--- fvwm-2.5.21-04/fvwm/window_flags.h	2007-03-03 13:18:21.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/window_flags.h	2007-03-03 13:18:49.000000000 +0100
+@@ -321,20 +321,26 @@
+ #define SET_IS_BOTTOM_TITLE_ROTATED(fw,x) \
+ 	(fw)->flags.common.s.is_bottom_title_rotated = !!(x)
+ #define SETM_IS_BOTTOM_TITLE_ROTATED(fw,x) \
+ 	(fw)->flag_mask.common.s.is_bottom_title_rotated = !!(x)
+ #define USE_TITLE_DECOR_ROTATION(fw) \
+ 	((fw)->flags.common.s.use_title_decor_rotation)
+ #define SET_USE_TITLE_DECOR_ROTATION(fw,x) \
+ 	(fw)->flags.common.s.use_title_decor_rotation = !!(x)
+ #define SETM_USE_TITLE_DECOR_ROTATION(fw,x) \
+ 	(fw)->flag_mask.common.s.use_title_decor_rotation = !!(x)
++#define HAS_BORDER_UNDER_TITLE(fw) \
++	((fw)->flags.common.s.has_border_under_title)
++#define SET_HAS_BORDER_UNDER_TITLE(fw,x) \
++	(fw)->flags.common.s.has_border_under_title = !!(x)
++#define SETM_HAS_BORDER_UNDER_TITLE(fw,x) \
++	(fw)->flag_mask.common.s.has_border_under_title = !!(x)
+ 
+ /* access to the special flags of a window */
+ #define DO_REUSE_DESTROYED(fw) \
+ 	((fw)->flags.do_reuse_destroyed)
+ #define SET_DO_REUSE_DESTROYED(fw,x) \
+ 	(fw)->flags.do_reuse_destroyed = !!(x)
+ #define SETM_DO_REUSE_DESTROYED(fw,x) \
+ 	(fw)->flag_mask.do_reuse_destroyed = !!(x)
+ #define HAS_NO_BORDER(fw) \
+ 	((fw)->flags.common.has_no_border)
+diff -U10 -Naupr fvwm-2.5.21-04/fvwm/window_flags.h~ fvwm-2.5.21-05/fvwm/window_flags.h~
+--- fvwm-2.5.21-04/fvwm/window_flags.h~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-05/fvwm/window_flags.h~	2007-03-03 13:18:42.000000000 +0100
+@@ -0,0 +1,752 @@
++/* -*-c-*- */
++
++#ifndef _WINDOW_FLAGS_
++#define _WINDOW_FLAGS_
++
++#include "focus_policy.h"
++
++/* access to the common flags of a window */
++#define FW_COMMON_FLAGS(fw) \
++	((fw)->flags.common)
++#define FW_COMMON_STATIC_FLAGS(fw) \
++	((fw)->flags.common.s)
++#define FW_FOCUS_POLICY(fw) \
++	((fw)->flags.common.s.focus_policy)
++
++#define DO_LOWER_TRANSIENT(fw) \
++	((fw)->flags.common.s.do_lower_transient)
++#define DO_NOT_SHOW_ON_MAP(fw) \
++	((fw)->flags.common.s.do_not_show_on_map)
++#define DO_RAISE_TRANSIENT(fw) \
++	((fw)->flags.common.s.do_raise_transient)
++#define DO_RESIZE_OPAQUE(fw) \
++	((fw)->flags.common.s.do_resize_opaque)
++#define DO_RESIZE_OUTLINE_THIN(fw) \
++	((fw)->flags.common.s.do_resize_outline_thin)
++#define DO_SHRINK_WINDOWSHADE(fw) \
++	((fw)->flags.common.s.do_shrink_windowshade)
++#define SET_DO_SHRINK_WINDOWSHADE(fw,x) \
++	(fw)->flags.common.s.do_shrink_windowshade = !!(x)
++#define SETM_DO_SHRINK_WINDOWSHADE(fw,x) \
++	(fw)->flag_mask.common.s.do_shrink_windowshade = !!(x)
++#define DO_SKIP_CIRCULATE(fw) \
++	((fw)->flags.common.s.do_circulate_skip)
++#define SET_DO_SKIP_CIRCULATE(fw,x) \
++	(fw)->flags.common.s.do_circulate_skip = !!(x)
++#define SETM_DO_SKIP_CIRCULATE(fw,x) \
++	(fw)->flag_mask.common.s.do_circulate_skip = !!(x)
++#define DO_SKIP_ICON_CIRCULATE(fw) \
++	((fw)->flags.common.s.do_circulate_skip_icon)
++#define SET_DO_SKIP_ICON_CIRCULATE(fw,x) \
++	(fw)->flags.common.s.do_circulate_skip_icon = !!(x)
++#define SETM_DO_SKIP_ICON_CIRCULATE(fw,x) \
++	(fw)->flag_mask.common.s.do_circulate_skip_icon = !!(x)
++#define DO_SKIP_SHADED_CIRCULATE(fw) \
++	((fw)->flags.common.s.do_circulate_skip_shaded)
++#define SET_DO_SKIP_SHADED_CIRCULATE(fw,x) \
++	(fw)->flags.common.s.do_circulate_skip_shaded = !!(x)
++#define SETM_DO_SKIP_SHADED_CIRCULATE(fw,x) \
++	(fw)->flag_mask.common.s.do_circulate_skip_shaded = !!(x)
++#define DO_SKIP_WINDOW_LIST(fw) \
++	((fw)->flags.common.s.do_window_list_skip)
++#define SET_DO_SKIP_WINDOW_LIST(fw,x) \
++	(fw)->flags.common.s.do_window_list_skip = !!(x)
++#define SETM_DO_SKIP_WINDOW_LIST(fw,x) \
++	(fw)->flag_mask.common.s.do_window_list_skip = !!(x)
++#define DO_STACK_TRANSIENT_PARENT(fw) \
++	((fw)->flags.common.s.do_stack_transient_parent)
++#define GET_TITLE_DIR(fw) \
++	((fw)->flags.common.title_dir)
++#define HAS_TITLE_DIR(fw,x) \
++	((fw)->flags.common.title_dir == x)
++#define SET_TITLE_DIR(fw,x) \
++	((fw)->flags.common.title_dir = x)
++#define SETM_TITLE_DIR(fw,x) \
++	((fw)->flag_mask.common.title_dir = ((x) ? DIR_MAJOR_MASK : 0))
++#define SET_USER_STATES(fw, mask) \
++	((fw)->flags.common.user_states |= (mask))
++#define CLEAR_USER_STATES(fw, mask) \
++	((fw)->flags.common.user_states &= ~(mask))
++#define TOGGLE_USER_STATES(fw, mask) \
++	((fw)->flags.common.user_states ^= (mask))
++#define SETM_USER_STATES(fw, mask) \
++	((fw)->flag_mask.common.user_states |= (mask))
++#define GET_USER_STATES(fw) \
++	((fw)->flags.common.user_states)
++#define GETM_USER_STATES(fw) \
++	((fw)->flag_mask.common.user_states)
++#define HAS_VERTICAL_TITLE(fw) \
++	((HAS_TITLE_DIR(fw,DIR_W) || HAS_TITLE_DIR(fw,DIR_E)))
++#define HAS_STIPPLED_TITLE(fw) \
++	((fw)->flags.common.s.has_stippled_title)
++#define SET_HAS_STIPPLED_TITLE(fw,x) \
++	(fw)->flags.common.s.has_stippled_title = !!(x)
++#define SETM_HAS_STIPPLED_TITLE(fw,x) \
++	(fw)->flag_mask.common.s.has_stippled_title = !!(x)
++#define HAS_STICKY_STIPPLED_TITLE(fw) \
++	!((fw)->flags.common.s.has_no_sticky_stippled_title)
++#define SET_HAS_STICKY_STIPPLED_TITLE(fw,x) \
++	(fw)->flags.common.s.has_no_sticky_stippled_title = !(x)
++#define SETM_HAS_STICKY_STIPPLED_TITLE(fw,x) \
++	(fw)->flag_mask.common.s.has_no_sticky_stippled_title = !!(x)
++#define HAS_STICKY_STIPPLED_ICON_TITLE(fw) \
++	!((fw)->flags.common.s.has_no_sticky_stippled_icon_title)
++#define SET_HAS_STICKY_STIPPLED_ICON_TITLE(fw,x) \
++	(fw)->flags.common.s.has_no_sticky_stippled_icon_title = !(x)
++#define SETM_HAS_STICKY_STIPPLED_ICON_TITLE(fw,x) \
++	(fw)->flag_mask.common.s.has_no_sticky_stippled_icon_title = !!(x)
++#define HAS_STIPPLED_ICON_TITLE(fw) \
++	((fw)->flags.common.s.has_stippled_icon_title)
++#define SET_HAS_STIPPLED_ICON_TITLE(fw,x) \
++	(fw)->flags.common.s.has_stippled_icon_title = !!(x)
++#define SETM_HAS_STIPPLED_ICON_TITLE(fw,x) \
++	(fw)->flag_mask.common.s.has_stippled_icon_title = !!(x)
++#define ICON_OVERRIDE_MODE(fw) \
++	((fw)->flags.common.s.icon_override)
++#define SET_ICON_OVERRIDE_MODE(fw,x) \
++	(fw)->flags.common.s.icon_override = ((x) & ICON_OVERRIDE_MASK)
++#define SETM_ICON_OVERRIDE_MODE(fw,x) \
++	(fw)->flag_mask.common.s.icon_override = ((x) ? ICON_OVERRIDE_MASK : 0)
++#define IS_ICON_STICKY_ACROSS_PAGES(fw) \
++	((fw)->flags.common.s.is_icon_sticky_across_pages)
++#define SET_ICON_STICKY_ACROSS_PAGES(fw,x) \
++	(fw)->flags.common.s.is_icon_sticky_across_pages = !!(x)
++#define SETM_ICON_STICKY_ACROSS_PAGES(fw,x) \
++	(fw)->flag_mask.common.s.is_icon_sticky_across_pages = !!(x)
++#define IS_ICON_STICKY_ACROSS_DESKS(fw) \
++	((fw)->flags.common.s.is_icon_sticky_across_desks)
++#define SET_ICON_STICKY_ACROSS_DESKS(fw,x) \
++	(fw)->flags.common.s.is_icon_sticky_across_desks = !!(x)
++#define SETM_ICON_STICKY_ACROSS_DESKS(fw,x) \
++	(fw)->flag_mask.common.s.is_icon_sticky_across_desks = !!(x)
++#define USE_ICON_POSITION_HINT(fw) \
++	((fw)->flags.common.s.use_icon_position_hint)
++#define SET_USE_ICON_POSITION_HINT(fw,x) \
++	(fw)->flags.common.s.use_icon_position_hint = !!(x)
++#define SETM_USE_ICON_POSITION_HINT(fw,x) \
++	(fw)->flag_mask.common.s.use_icon_position_hint = !!(x)
++#define USE_INDEXED_WINDOW_NAME(fw) \
++	((fw)->flags.common.s.use_indexed_window_name)
++#define SET_USE_INDEXED_WINDOW_NAME(fw,x) \
++	(fw)->flags.common.s.use_indexed_window_name = !!(x)
++#define SETM_USE_INDEXED_WINDOW_NAME(fw,x) \
++	(fw)->flag_mask.common.s.use_indexed_window_name = !!(x)
++#define USE_INDEXED_ICON_NAME(fw) \
++	((fw)->flags.common.s.use_indexed_icon_name)
++#define SET_USE_INDEXED_ICON_NAME(fw,x) \
++	(fw)->flags.common.s.use_indexed_icon_name = !!(x)
++#define SETM_USE_INDEXED_ICON_NAME(fw,x) \
++	(fw)->flag_mask.common.s.use_indexed_icon_name = !!(x)
++#define WINDOWSHADE_LAZINESS(fw) \
++	((fw)->flags.common.s.windowshade_laziness)
++#define SET_WINDOWSHADE_LAZINESS(fw,x) \
++	(fw)->flags.common.s.windowshade_laziness = \
++	((x) & WINDOWSHADE_LAZY_MASK)
++#define SETM_WINDOWSHADE_LAZINESS(fw,x) \
++	(fw)->flag_mask.common.s.windowshade_laziness = \
++	((x) ? WINDOWSHADE_LAZY_MASK : 0)
++#define DO_EWMH_MINI_ICON_OVERRIDE(fw) \
++	((fw)->flags.common.s.do_ewmh_mini_icon_override)
++#define SET_DO_EWMH_MINI_ICON_OVERRIDE(fw,x) \
++	(fw)->flags.common.s.do_ewmh_mini_icon_override = !!(x)
++#define SETM_DO_EWMH_MINI_ICON_OVERRIDE(fw,x) \
++	(fw)->flag_mask.common.s.do_ewmh_mini_icon_override = !!(x)
++#define DO_EWMH_DONATE_ICON(fw) \
++	((fw)->flags.common.s.do_ewmh_donate_icon)
++#define SET_DO_EWMH_DONATE_ICON(fw,x) \
++	(fw)->flags.common.s.do_ewmh_donate_icon = !!(x)
++#define SETM_DO_EWMH_DONATE_ICON(fw,x) \
++	(fw)->flag_mask.common.s.do_ewmh_donate_icon = !!(x)
++#define DO_EWMH_DONATE_MINI_ICON(fw) \
++	((fw)->flags.common.s.do_ewmh_donate_mini_icon)
++#define SET_DO_EWMH_DONATE_MINI_ICON(fw,x) \
++	(fw)->flags.common.s.do_ewmh_donate_mini_icon = !!(x)
++#define SETM_DO_EWMH_DONATE_MINI_ICON(fw,x) \
++	(fw)->flag_mask.common.s.do_ewmh_donate_mini_icon = !!(x)
++#define DO_EWMH_USE_STACKING_HINTS(fw) \
++	((fw)->flags.common.s.do_ewmh_use_stacking_hints)
++#define SET_DO_EWMH_USE_STACKING_HINTS(fw,x) \
++	(fw)->flags.common.s.do_ewmh_use_stacking_hints = !!(x)
++#define SETM_DO_EWMH_USE_STACKING_HINTS(fw,x) \
++	(fw)->flag_mask.common.s.do_ewmh_use_stacking_hints = !!(x)
++#define DO_EWMH_IGNORE_STRUT_HINTS(fw) \
++	((fw)->flags.common.s.do_ewmh_ignore_strut_hints)
++#define SET_DO_EWMH_IGNORE_STRUT_HINTS(fw,x) \
++	(fw)->flags.common.s.do_ewmh_ignore_strut_hints = !!(x)
++#define SETM_DO_EWMH_IGNORE_STRUT_HINTS(fw,x) \
++	(fw)->flag_mask.common.s.do_ewmh_ignore_strut_hints = !!(x)
++#define DO_EWMH_IGNORE_STATE_HINTS(fw) \
++	((fw)->flags.common.s.do_ewmh_ignore_state_hints)
++#define SET_DO_EWMH_IGNORE_STATE_HINTS(fw,x) \
++	(fw)->flags.common.s.do_ewmh_ignore_state_hints = !!(x)
++#define SETM_DO_EWMH_IGNORE_STATE_HINTS(fw,x) \
++	(fw)->flag_mask.common.s.do_ewmh_ignore_state_hints = !!(x)
++#define DO_EWMH_IGNORE_WINDOW_TYPE(fw) \
++	((fw)->flags.common.s.do_ewmh_ignore_window_type)
++#define SET_DO_EWMH_IGNORE_WINDOW_TYPE(fw,x) \
++	(fw)->flags.common.s.do_ewmh_ignore_window_type = !!(x)
++#define SETM_DO_EWMH_IGNORE_WINDOW_TYPE(fw,x) \
++	(fw)->flag_mask.common.s.do_ewmh_ignore_window_type = !!(x)
++#define EWMH_MAXIMIZE_MODE(fw) \
++	((fw)->flags.common.s.ewmh_maximize_mode)
++#define SET_EWMH_MAXIMIZE_MODE(fw,x) \
++	(fw)->flags.common.s.ewmh_maximize_mode = (x)
++#define SETM_EWMH_MAXIMIZE_MODE(fw,x) \
++	(fw)->flag_mask.common.s.ewmh_maximize_mode = (x)
++#define IS_ICON_SUPPRESSED(fw) \
++	((fw)->flags.common.s.is_icon_suppressed)
++#define SET_ICON_SUPPRESSED(fw,x) \
++	(fw)->flags.common.s.is_icon_suppressed = !!(x)
++#define SETM_ICON_SUPPRESSED(fw,x) \
++	(fw)->flag_mask.common.s.is_icon_suppressed = !!(x)
++#define IS_STICKY_ACROSS_PAGES(fw) \
++	((fw)->flags.common.is_sticky_across_pages)
++#define SET_STICKY_ACROSS_PAGES(fw,x) \
++	(fw)->flags.common.is_sticky_across_pages = !!(x)
++#define SETM_STICKY_ACROSS_PAGES(fw,x) \
++	(fw)->flag_mask.common.is_sticky_across_pages = !!(x)
++#define IS_STICKY_ACROSS_DESKS(fw) \
++	((fw)->flags.common.is_sticky_across_desks)
++#define SET_STICKY_ACROSS_DESKS(fw,x) \
++	(fw)->flags.common.is_sticky_across_desks = !!(x)
++#define SETM_STICKY_ACROSS_DESKS(fw,x) \
++	(fw)->flag_mask.common.is_sticky_across_desks = !!(x)
++#define HAS_ICON_FONT(fw) \
++	((fw)->flags.common.has_icon_font)
++#define SET_HAS_ICON_FONT(fw,x) \
++	(fw)->flags.common.has_icon_font = !!(x)
++#define SETM_HAS_ICON_FONT(fw,x) \
++	(fw)->flag_mask.common.has_icon_font = !!(x)
++#define HAS_NO_ICON_TITLE(fw) \
++	((fw)->flags.common.s.has_no_icon_title)
++#define SET_HAS_NO_ICON_TITLE(fw,x) \
++	(fw)->flags.common.s.has_no_icon_title = !!(x)
++#define SETM_HAS_NO_ICON_TITLE(fw,x) \
++	(fw)->flag_mask.common.s.has_no_icon_title = !!(x)
++#define HAS_WINDOW_FONT(fw) \
++	((fw)->flags.common.has_window_font)
++#define SET_HAS_WINDOW_FONT(fw,x) \
++	(fw)->flags.common.has_window_font = !!(x)
++#define SETM_HAS_WINDOW_FONT(fw,x) \
++	(fw)->flag_mask.common.has_window_font = !!(x)
++#define HAS_MWM_BORDER(fw) \
++	((fw)->flags.common.s.has_mwm_border)
++#define HAS_MWM_BUTTONS(fw) \
++	((fw)->flags.common.s.has_mwm_buttons)
++#define HAS_MWM_OVERRIDE_HINTS(fw) \
++	((fw)->flags.common.s.has_mwm_override)
++#define HAS_OVERRIDE_SIZE_HINTS(fw) \
++	((fw)->flags.common.s.has_override_size)
++#define DO_ICONIFY_WINDOW_GROUPS(fw) \
++	((fw)->flags.common.s.do_iconify_window_groups)
++#define DO_IGNORE_GNOME_HINTS(fw) \
++	((fw)->flags.common.s.do_ignore_gnome_hints)
++#define DO_IGNORE_RESTACK(fw) \
++	((fw)->flags.common.s.do_ignore_restack)
++#define DO_IGNORE_ICON_BOXES(fw) \
++	((fw)->flags.common.s.do_ignore_icon_boxes)
++#define DO_USE_WINDOW_GROUP_HINT(fw) \
++	((fw)->flags.common.s.do_use_window_group_hint)
++#define IS_FIXED(fw) \
++	((fw)->flags.common.s.is_fixed)
++#define SET_FIXED(fw,x) \
++	(fw)->flags.common.s.is_fixed = !!(x)
++#define SETM_FIXED(fw,x) \
++	(fw)->flag_mask.common.s.is_fixed = !!(x)
++#define IS_FIXED_PPOS(fw) \
++	((fw)->flags.common.s.is_fixed_ppos)
++#define SET_FIXED_PPOS(fw,x) \
++	(fw)->flags.common.s.is_fixed_ppos = !!(x)
++#define SETM_FIXED_PPOS(fw,x) \
++	(fw)->flag_mask.common.s.is_fixed_ppos = !!(x)
++#define IS_SIZE_FIXED(fw) \
++	((fw)->flags.common.s.is_size_fixed)
++#define SET_SIZE_FIXED(fw,x) \
++	(fw)->flags.common.s.is_size_fixed = !!(x)
++#define SETM_SIZE_FIXED(fw,x) \
++	(fw)->flag_mask.common.s.is_size_fixed = !!(x)
++#define IS_PSIZE_FIXED(fw) \
++	((fw)->flags.common.s.is_psize_fixed)
++#define SET_PSIZE_FIXED(fw,x) \
++	(fw)->flags.common.s.is_psize_fixed = !!(x)
++#define SETM_PSIZE_FIXED(fw,x) \
++	(fw)->flag_mask.common.s.is_psize_fixed = !!(x)
++#define IS_UNICONIFIABLE(fw) \
++	((fw)->flags.common.s.is_uniconifiable)
++#define SET_IS_UNICONIFIABLE(fw,x) \
++	(fw)->flags.common.s.is_uniconifiable = !!(x)
++#define SETM_IS_UNICONIFIABLE(fw,x) \
++	(fw)->flag_mask.common.s.is_uniconifiable = !!(x)
++#define IS_UNMAXIMIZABLE(fw) \
++	((fw)->flags.common.s.is_unmaximizable)
++#define SET_IS_UNMAXIMIZABLE(fw,x) \
++	(fw)->flags.common.s.is_unmaximizable = !!(x)
++#define SETM_IS_UNMAXIMIZABLE(fw,x) \
++	(fw)->flag_mask.common.s.is_unmaximizable = !!(x)
++#define IS_UNCLOSABLE(fw) \
++	((fw)->flags.common.s.is_unclosable)
++#define SET_IS_UNCLOSABLE(fw,x) \
++	(fw)->flags.common.s.is_unclosable = !!(x)
++#define SETM_IS_UNCLOSABLE(fw,x) \
++	(fw)->flag_mask.common.s.is_unclosable = !!(x)
++#define IS_MAXIMIZE_FIXED_SIZE_DISALLOWED(fw) \
++	((fw)->flags.common.s.is_maximize_fixed_size_disallowed)
++#define SET_MAXIMIZE_FIXED_SIZE_DISALLOWED(fw,x) \
++	(fw)->flags.common.s.is_maximize_fixed_size_disallowed = !!(x)
++#define SETM_MAXIMIZE_FIXED_SIZE_DISALLOWED(fw,x) \
++	(fw)->flag_mask.common.s.is_maximize_fixed_size_disallowed = !!(x)
++#define HAS_DEPRESSABLE_BORDER(fw) \
++	((fw)->flags.common.s.has_depressable_border)
++
++#define IS_LEFT_TITLE_ROTATED_CW(fw) \
++	((fw)->flags.common.s.is_left_title_rotated_cw)
++#define SET_IS_LEFT_TITLE_ROTATED_CW(fw,x) \
++	(fw)->flags.common.s.is_left_title_rotated_cw = !!(x)
++#define SETM_IS_LEFT_TITLE_ROTATED_CW(fw,x) \
++	(fw)->flag_mask.common.s.is_left_title_rotated_cw = !!(x)
++#define IS_RIGHT_TITLE_ROTATED_CW(fw) \
++	((fw)->flags.common.s.is_right_title_rotated_cw)
++#define SET_IS_RIGHT_TITLE_ROTATED_CW(fw,x) \
++	(fw)->flags.common.s.is_right_title_rotated_cw = !!(x)
++#define SETM_IS_RIGHT_TITLE_ROTATED_CW(fw,x) \
++	(fw)->flag_mask.common.s.is_right_title_rotated_cw = !!(x)
++#define IS_BOTTOM_TITLE_ROTATED(fw) \
++	((fw)->flags.common.s.is_bottom_title_rotated)
++#define SET_IS_BOTTOM_TITLE_ROTATED(fw,x) \
++	(fw)->flags.common.s.is_bottom_title_rotated = !!(x)
++#define SETM_IS_BOTTOM_TITLE_ROTATED(fw,x) \
++	(fw)->flag_mask.common.s.is_bottom_title_rotated = !!(x)
++#define IS_BOTTOM_TITLE_ROTATED(fw) \
++	((fw)->flags.common.s.is_bottom_title_rotated)
++#define SET_IS_BOTTOM_TITLE_ROTATED(fw,x) \
++	(fw)->flags.common.s.is_bottom_title_rotated = !!(x)
++#define SETM_IS_BOTTOM_TITLE_ROTATED(fw,x) \
++	(fw)->flag_mask.common.s.is_bottom_title_rotated = !!(x)
++#define USE_TITLE_DECOR_ROTATION(fw) \
++	((fw)->flags.common.s.use_title_decor_rotation)
++#define SET_USE_TITLE_DECOR_ROTATION(fw,x) \
++	(fw)->flags.common.s.use_title_decor_rotation = !!(x)
++#define SETM_USE_TITLE_DECOR_ROTATION(fw,x) \
++	(fw)->flag_mask.common.s.use_title_decor_rotation = !!(x)
++
++/* access to the special flags of a window */
++#define DO_REUSE_DESTROYED(fw) \
++	((fw)->flags.do_reuse_destroyed)
++#define SET_DO_REUSE_DESTROYED(fw,x) \
++	(fw)->flags.do_reuse_destroyed = !!(x)
++#define SETM_DO_REUSE_DESTROYED(fw,x) \
++	(fw)->flag_mask.do_reuse_destroyed = !!(x)
++#define HAS_NO_BORDER(fw) \
++	((fw)->flags.common.has_no_border)
++#define SET_HAS_NO_BORDER(fw,x) \
++	(fw)->flags.common.has_no_border = !!(x)
++#define SETM_HAS_NO_BORDER(fw,x) \
++	(fw)->flag_mask.common.has_no_border = !!(x)
++#define HAS_HANDLES(fw) \
++	((fw)->flags.has_handles)
++#define SET_HAS_HANDLES(fw,x) \
++	(fw)->flags.has_handles = !!(x)
++#define SETM_HAS_HANDLES(fw,x) \
++	(fw)->flag_mask.has_handles = !!(x)
++#define HAS_ICON_CHANGED(fw) \
++	((fw)->flags.has_icon_changed)
++#define SET_HAS_ICON_CHANGED(fw,x) \
++	(fw)->flags.has_icon_changed = !!(x)
++#define SETM_HAS_ICON_CHANGED(fw,x) \
++	(fw)->flag_mask.has_icon_changed = !!(x)
++#define HAS_TITLE(fw) \
++	((fw)->flags.has_title)
++#define SET_HAS_TITLE(fw,x) \
++	(fw)->flags.has_title = !!(x)
++#define SETM_HAS_TITLE(fw,x) \
++	(fw)->flag_mask.has_title = !!(x)
++#define HAS_NEW_WM_NORMAL_HINTS(fw) \
++	((fw)->flags.has_new_wm_normal_hints)
++#define SET_HAS_NEW_WM_NORMAL_HINTS(fw,x) \
++	(fw)->flags.has_new_wm_normal_hints = !!(x)
++#define SETM_HAS_NEW_WM_NORMAL_HINTS(fw,x) \
++	(fw)->flag_mask.has_new_wm_normal_hints = !!(x)
++#define IS_MAPPED(fw) \
++	((fw)->flags.is_mapped)
++#define SET_MAPPED(fw,x) \
++	(fw)->flags.is_mapped = !!(x)
++#define SETM_MAPPED(fw,x) \
++	(fw)->flag_mask.is_mapped = !!(x)
++#define IS_DECOR_CHANGED(fw) \
++	((fw)->flags.is_decor_changed)
++#define SET_DECOR_CHANGED(fw,x) \
++	(fw)->flags.is_decor_changed = !!(x)
++#define SETM_DECOR_CHANGED(fw,x) \
++	(fw)->flag_mask.is_decor_changed = !!(x)
++#define IS_ICON_FONT_LOADED(fw) \
++	((fw)->flags.is_icon_font_loaded)
++#define SET_ICON_FONT_LOADED(fw,x) \
++	(fw)->flags.is_icon_font_loaded = !!(x)
++#define SETM_ICON_FONT_LOADED(fw,x) \
++	(fw)->flag_mask.is_icon_font_loaded = !!(x)
++#define IS_ICONIFIED(fw) \
++	((fw)->flags.is_iconified)
++#define SET_ICONIFIED(fw,x) \
++	(fw)->flags.is_iconified = !!(x)
++#define SETM_ICONIFIED(fw,x) \
++	(fw)->flag_mask.is_iconified = !!(x)
++#define IS_ICONIFIED_BY_PARENT(fw) \
++	((fw)->flags.is_iconified_by_parent)
++#define SET_ICONIFIED_BY_PARENT(fw,x) \
++	(fw)->flags.is_iconified_by_parent = !!(x)
++#define SETM_ICONIFIED_BY_PARENT(fw,x) \
++	(fw)->flag_mask.is_iconified_by_parent = !!(x)
++#define IS_ICON_ENTERED(fw) \
++	((fw)->flags.is_icon_entered)
++#define SET_ICON_ENTERED(fw,x) \
++	(fw)->flags.is_icon_entered = !!(x)
++#define SETM_ICON_ENTERED(fw,x) \
++	(fw)->flag_mask.is_icon_entered = !!(x)
++#define IS_ICON_OURS(fw) \
++	((fw)->flags.is_icon_ours)
++#define SET_ICON_OURS(fw,x) \
++	(fw)->flags.is_icon_ours = !!(x)
++#define SETM_ICON_OURS(fw,x) \
++	(fw)->flag_mask.is_icon_ours = !!(x)
++#define IS_ICON_SHAPED(fw) \
++	((fw)->flags.is_icon_shaped)
++#define SET_ICON_SHAPED(fw,x) \
++	(fw)->flags.is_icon_shaped = !!(x)
++#define SETM_ICON_SHAPED(fw,x) \
++	(fw)->flag_mask.is_icon_shaped = !!(x)
++#define IS_ICON_MOVED(fw) \
++	((fw)->flags.is_icon_moved)
++#define SET_ICON_MOVED(fw,x) \
++	(fw)->flags.is_icon_moved = !!(x)
++#define SETM_ICON_MOVED(fw,x) \
++	(fw)->flag_mask.is_icon_moved = !!(x)
++#define IS_ICON_UNMAPPED(fw) \
++	((fw)->flags.is_icon_unmapped)
++#define SET_ICON_UNMAPPED(fw,x) \
++	(fw)->flags.is_icon_unmapped = !!(x)
++#define SETM_ICON_UNMAPPED(fw,x) \
++	(fw)->flag_mask.is_icon_unmapped = !!(x)
++#define IS_IN_TRANSIENT_SUBTREE(fw) \
++	((fw)->flags.is_in_transient_subtree)
++#define SET_IN_TRANSIENT_SUBTREE(fw,x) \
++	(fw)->flags.is_in_transient_subtree = !!(x)
++#define IS_MAP_PENDING(fw) \
++	((fw)->flags.is_map_pending)
++#define SET_MAP_PENDING(fw,x) \
++	(fw)->flags.is_map_pending = !!(x)
++#define SETM_MAP_PENDING(fw,x) \
++	(fw)->flag_mask.is_map_pending = !!(x)
++#define IS_MAXIMIZED(fw) \
++	((fw)->flags.is_maximized)
++#define SET_MAXIMIZED(fw,x) \
++	(fw)->flags.is_maximized = !!(x)
++#define SETM_MAXIMIZED(fw,x) \
++	(fw)->flag_mask.is_maximized = !!(x)
++#define IS_NAME_CHANGED(fw) \
++	((fw)->flags.is_name_changed)
++#define SET_NAME_CHANGED(fw,x) \
++	(fw)->flags.is_name_changed = !!(x)
++#define SETM_NAME_CHANGED(fw,x) \
++	(fw)->flag_mask.is_name_changed = !!(x)
++#define IS_PIXMAP_OURS(fw) \
++	((fw)->flags.is_pixmap_ours)
++#define SET_PIXMAP_OURS(fw,x) \
++	(fw)->flags.is_pixmap_ours = !!(x)
++#define SETM_PIXMAP_OURS(fw,x) \
++	(fw)->flag_mask.is_pixmap_ours = !!(x)
++#define IS_PLACED_BY_FVWM(fw) \
++	((fw)->flags.is_placed_by_fvwm)
++#define SET_PLACED_BY_FVWM(fw,x) \
++	(fw)->flags.is_placed_by_fvwm = (x)
++#define SETM_PLACED_BY_FVWM(fw,x) \
++	(fw)->flag_mask.is_placed_by_fvwm = (x)
++#define IS_SCHEDULED_FOR_DESTROY(fw) \
++	((fw)->flags.is_scheduled_for_destroy)
++#define SET_SCHEDULED_FOR_DESTROY(fw,x) \
++	(fw)->flags.is_scheduled_for_destroy = !!(x)
++#define IS_SCHEDULED_FOR_RAISE(fw) \
++	((fw)->flags.is_scheduled_for_raise)
++#define SET_SCHEDULED_FOR_RAISE(fw,x) \
++	(fw)->flags.is_scheduled_for_raise = !!(x)
++#define IS_SHADED(fw) \
++	((fw)->flags.is_window_shaded)
++#define USED_TITLE_DIR_FOR_SHADING(fw) \
++	((fw)->flags.used_title_dir_for_shading)
++#define SET_USED_TITLE_DIR_FOR_SHADING(fw,x) \
++	((fw)->flags.used_title_dir_for_shading = !!(x))
++#define SHADED_DIR(fw) \
++	((fw)->flags.shaded_dir)
++#define SET_SHADED(fw,x) \
++	(fw)->flags.is_window_shaded = !!(x)
++#define SET_SHADED_DIR(fw,x) \
++	(fw)->flags.shaded_dir = (x)
++#define SETM_SHADED(fw,x) \
++	(fw)->flag_mask.is_window_shaded = !!(x)
++#define IS_TEAR_OFF_MENU(fw) \
++	((fw)->flags.is_tear_off_menu)
++#define SET_TEAR_OFF_MENU(fw,x) \
++	(fw)->flags.is_tear_off_menu = !!(x)
++#define SETM_TEAR_OFF_MENU(fw,x) \
++	(fw)->flag_mask.is_tear_off_menu = !!(x)
++#define IS_TRANSIENT(fw) \
++	((fw)->flags.is_transient)
++#define SET_TRANSIENT(fw,x) \
++	(fw)->flags.is_transient = !!(x)
++#define SETM_TRANSIENT(fw,x) \
++	(fw)->flag_mask.is_transient = !!(x)
++#define IS_ICONIFY_PENDING(fw) \
++	((fw)->flags.is_iconify_pending)
++#define SET_ICONIFY_PENDING(fw,x) \
++	(fw)->flags.is_iconify_pending = !!(x)
++#define SETM_ICONIFY_PENDING(fw,x) \
++	(fw)->flag_mask.is_iconify_pending = !!(x)
++#define DO_ICONIFY_AFTER_MAP(fw) \
++	((fw)->flags.do_iconify_after_map)
++#define SET_ICONIFY_AFTER_MAP(fw,x) \
++	(fw)->flags.do_iconify_after_map = !!(x)
++#define SETM_ICONIFY_AFTER_MAP(fw,x) \
++	(fw)->flag_mask.do_iconify_after_map = !!(x)
++#define DO_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw) \
++	((fw)->flags.do_disable_constrain_size_fullscreen)
++#define SET_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw,x) \
++	(fw)->flags.do_disable_constrain_size_fullscreen = !!(x)
++#define SETM_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw,x) \
++	(fw)->flag_mask.do_disable_constrain_size_fullscreen = !!(x)
++#define IS_SIZE_INC_SET(fw) \
++	((fw)->flags.is_size_inc_set)
++#define SET_SIZE_INC_SET(fw,x) \
++	(fw)->flags.is_size_inc_set = !!(x)
++#define SETM_SIZE_INC_SET(fw,x) \
++	(fw)->flag_mask.is_size_inc_set = !!(x)
++#define IS_STYLE_DELETED(fw) \
++	((fw)->flags.is_style_deleted)
++#define SET_STYLE_DELETED(fw,x) \
++	(fw)->flags.is_style_deleted = !!(x)
++#define SETM_STYLE_DELETED(fw,x) \
++	(fw)->flag_mask.is_style_deleted = !!(x)
++#define IS_VIEWPORT_MOVED(fw) \
++	((fw)->flags.is_viewport_moved)
++#define SET_VIEWPORT_MOVED(fw,x) \
++	(fw)->flags.is_viewport_moved = !!(x)
++#define SETM_VIEWPORT_MOVED(fw,x) \
++	(fw)->flag_mask.is_viewport_moved = !!(x)
++#define IS_VIEWPORT_MOVED(fw) \
++	((fw)->flags.is_viewport_moved)
++#define IS_FOCUS_CHANGE_BROADCAST_PENDING(fw) \
++	((fw)->flags.is_focus_change_broadcast_pending)
++#define SET_FOCUS_CHANGE_BROADCAST_PENDING(fw,x) \
++	(fw)->flags.is_focus_change_broadcast_pending = !!(x)
++#define SETM_FOCUS_CHANGE_BROADCAST_PENDING(fw,x) \
++	(fw)->flag_mask.is_focus_change_broadcast_pending = !!(x)
++#define IS_FULLY_VISIBLE(fw) \
++	((fw)->flags.is_fully_visible)
++#define SET_FULLY_VISIBLE(fw,x) \
++	(fw)->flags.is_fully_visible = !!(x)
++#define SETM_FULLY_VISIBLE(fw,x) \
++	(fw)->flag_mask.is_fully_visible = !!(x)
++#define IS_PARTIALLY_VISIBLE(fw) \
++	((fw)->flags.is_partially_visible)
++#define SET_PARTIALLY_VISIBLE(fw,x) \
++	(fw)->flags.is_partially_visible = !!(x)
++#define SETM_PARTIALLY_VISIBLE(fw,x) \
++	(fw)->flag_mask.is_partially_visible = !!(x)
++#define IS_WINDOW_DRAWN_ONCE(fw) \
++	((fw)->flags.is_window_drawn_once)
++#define SET_WINDOW_DRAWN_ONCE(fw,x) \
++	(fw)->flags.is_window_drawn_once = !!(x)
++#define SETM_WINDOW_DRAWN_ONCE(fw,x) \
++	(fw)->flag_mask.is_window_drawn_once = !!(x)
++#define IS_WINDOW_BEING_MOVED_OPAQUE(fw) \
++	((fw)->flags.is_window_being_moved_opaque)
++#define SET_WINDOW_BEING_MOVED_OPAQUE(fw,x) \
++	(fw)->flags.is_window_being_moved_opaque = !!(x)
++#define SETM_WINDOW_BEING_MOVED_OPAQUE(fw,x) \
++	(fw)->flag_mask.is_window_being_moved_opaque = !!(x)
++#define IS_WINDOW_BORDER_DRAWN(fw) \
++	((fw)->flags.is_window_border_drawn)
++#define SET_WINDOW_BORDER_DRAWN(fw,x) \
++	(fw)->flags.is_window_border_drawn = !!(x)
++#define SETM_WINDOW_BORDER_DRAWN(fw,x) \
++	(fw)->flag_mask.is_window_border_drawn = !!(x)
++#define IS_WINDOW_FONT_LOADED(fw) \
++	((fw)->flags.is_window_font_loaded)
++#define SET_WINDOW_FONT_LOADED(fw,x) \
++	(fw)->flags.is_window_font_loaded = !!(x)
++#define SETM_WINDOW_FONT_LOADED(fw,x) \
++	(fw)->flag_mask.is_window_font_loaded = !!(x)
++#define CR_MOTION_METHOD(fw) \
++	((fw)->flags.cr_motion_method)
++#define SET_CR_MOTION_METHOD(fw,x) \
++	(fw)->flags.cr_motion_method = ((x) & CR_MOTION_METHOD_MASK)
++#define SETM_CR_MOTION_METHOD(fw,x) \
++	(fw)->flag_mask.cr_motion_method = ((x) ? CR_MOTION_METHOD_MASK : 0)
++#define WAS_CR_MOTION_METHOD_DETECTED(fw) \
++	((fw)->flags.was_cr_motion_method_detected)
++#define SET_CR_MOTION_METHOD_DETECTED(fw,x) \
++	(fw)->flags.was_cr_motion_method_detected = !!(x)
++#define SETM_CR_MOTION_METHOD_DETECTED(fw,x) \
++	(fw)->flag_mask.was_cr_motion_method_detected = !!(x)
++#define WM_DELETES_WINDOW(fw) \
++	((fw)->flags.does_wm_delete_window)
++#define SET_WM_DELETES_WINDOW(fw,x) \
++	(fw)->flags.does_wm_delete_window = !!(x)
++#define SETM_WM_DELETES_WINDOW(fw,x) \
++	(fw)->flag_mask.does_wm_delete_window = !!(x)
++#define WM_TAKES_FOCUS(fw) \
++	((fw)->flags.does_wm_take_focus)
++#define SET_WM_TAKES_FOCUS(fw,x) \
++	(fw)->flags.does_wm_take_focus = !!(x)
++#define SETM_WM_TAKES_FOCUS(fw,x) \
++	(fw)->flag_mask.does_wm_take_focus = !!(x)
++#define DO_FORCE_NEXT_CR(fw) \
++	((fw)->flags.do_force_next_cr)
++#define SET_FORCE_NEXT_CR(fw,x) \
++	(fw)->flags.do_force_next_cr = !!(x)
++#define SETM_FORCE_NEXT_CR(fw,x) \
++	(fw)->flag_mask.do_force_next_cr = !!(x)
++#define DO_FORCE_NEXT_PN(fw) \
++	((fw)->flags.do_force_next_pn)
++#define SET_FORCE_NEXT_PN(fw,x) \
++	(fw)->flags.do_force_next_pn = !!(x)
++#define SETM_FORCE_NEXT_PN(fw,x) \
++	(fw)->flag_mask.do_force_next_pn = !!(x)
++#define USING_DEFAULT_WINDOW_FONT(fw) \
++	((fw)->flags.using_default_window_font)
++#define SET_USING_DEFAULT_WINDOW_FONT(fw,x) \
++	(fw)->flags.using_default_window_font = !!(x)
++#define SETM_USING_DEFAULT_WINDOW_FONT(fw,x) \
++	(fw)->flag_mask.using_default_window_font = !!(x)
++#define USING_DEFAULT_ICON_FONT(fw) \
++	((fw)->flags.using_default_icon_font)
++#define SET_USING_DEFAULT_ICON_FONT(fw,x) \
++	(fw)->flags.using_default_icon_font = !!(x)
++#define SETM_USING_DEFAULT_ICON_FONT(fw,x) \
++	(fw)->flag_mask.using_default_icon_font = !!(x)
++#define WAS_ICON_HINT_PROVIDED(fw) \
++	((fw)->flags.was_icon_hint_provided)
++#define SET_WAS_ICON_HINT_PROVIDED(fw,x) \
++	(fw)->flags.was_icon_hint_provided = (x)
++#define SETM_WAS_ICON_HINT_PROVIDED(fw,x) \
++	(fw)->flag_mask.was_icon_hint_provided = (x)
++#define WAS_ICON_NAME_PROVIDED(fw) \
++	((fw)->flags.was_icon_name_provided)
++#define SET_WAS_ICON_NAME_PROVIDED(fw,x) \
++	(fw)->flags.was_icon_name_provided = (x)
++#define SETM_WAS_ICON_NAME_PROVIDED(fw,x) \
++	(fw)->flag_mask.was_icon_name_provided = (x)
++#define WAS_NEVER_DRAWN(fw) \
++	((fw)->flags.was_never_drawn)
++#define SET_WAS_NEVER_DRAWN(fw,x) \
++	(fw)->flags.was_never_drawn = (x)
++#define SETM_WAS_NEVER_DRAWN(fw,x) \
++	(fw)->flag_mask.was_never_drawn = (x)
++#define HAS_EWMH_WM_NAME(fw) \
++	((fw)->flags.has_ewmh_wm_name)
++#define SET_HAS_EWMH_WM_NAME(fw,x) \
++	(fw)->flags.has_ewmh_wm_name = !!(x)
++#define SETM_HAS_EWMH_WM_NAME(fw,x) \
++	(fw)->flag_mask.has_ewmh_wm_name = !!(x)
++#define HAS_EWMH_WM_ICON_NAME(fw) \
++	((fw)->flags.has_ewmh_wm_icon_name)
++#define SET_HAS_EWMH_WM_ICON_NAME(fw,x) \
++	(fw)->flags.has_ewmh_wm_icon_name = !!(x)
++#define SETM_HAS_EWMH_WM_ICON_NAME(fw,x) \
++	(fw)->flag_mask.has_ewmh_wm_icon_name = !!(x)
++#define HAS_EWMH_WM_ICON_HINT(fw) \
++	((fw)->flags.has_ewmh_wm_icon_hint)
++#define SET_HAS_EWMH_WM_ICON_HINT(fw,x) \
++	(fw)->flags.has_ewmh_wm_icon_hint = (x)
++#define SETM_HAS_EWMH_WM_ICON_HINT(fw,x) \
++	(fw)->flag_mask.has_ewmh_wm_icon_hint = (x)
++#define USE_EWMH_ICON(fw) \
++	((fw)->flags.use_ewmh_icon)
++#define SET_USE_EWMH_ICON(fw,x) \
++	(fw)->flags.use_ewmh_icon = !!(x)
++#define SETM_USE_EWMH_ICON(fw,x) \
++	(fw)->flag_mask.use_ewmh_icon = !!(x)
++#define HAS_EWMH_MINI_ICON(fw) \
++	((fw)->flags.has_ewmh_mini_icon)
++#define SET_HAS_EWMH_MINI_ICON(fw,x) \
++	(fw)->flags.has_ewmh_mini_icon = !!(x)
++#define SETM_HAS_EWMH_MINI_ICON(fw,x) \
++	(fw)->flag_mask.has_ewmh_mini_icon = !!(x)
++#define HAS_EWMH_WM_PID(fw) \
++	((fw)->flags.has_ewmh_wm_pid)
++#define SET_HAS_EWMH_WM_PID(fw,x) \
++	(fw)->flags.has_ewmh_wm_pid = !!(x)
++#define SETM_HAS_EWMH_WM_PID(fw,x) \
++	(fw)->flag_mask.has_ewmh_wm_pid = !!(x)
++#define IS_EWMH_MODAL(fw) \
++	((fw)->flags.is_ewmh_modal)
++#define SET_EWMH_MODAL(fw,x) \
++	(fw)->flags.is_ewmh_modal = !!(x)
++#define SETM_EWMH_MODAL(fw,x) \
++	(fw)->flag_mask.is_ewmh_modal = !!(x)
++#define IS_EWMH_FULLSCREEN(fw) \
++	((fw)->flags.is_ewmh_fullscreen)
++#define SET_EWMH_FULLSCREEN(fw,x) \
++	(fw)->flags.is_ewmh_fullscreen = !!(x)
++#define SETM_EWMH_FULLSCREEN(fw,x) \
++	(fw)->flag_mask.is_ewmh_fullscreen = !!(x)
++#define SET_HAS_EWMH_INIT_FULLSCREEN_STATE(fw,x) \
++	(fw)->flags.has_ewmh_init_fullscreen_state = (x)
++#define SETM_HAS_EWMH_INIT_FULLSCREEN_STATE(fw,x) \
++	(fw)->flag_mask.has_ewmh_init_fullscreen_state = (x)
++#define HAS_EWMH_INIT_FULLSCREEN_STATE(fw) \
++	((fw)->flags.has_ewmh_init_fullscreen_state)
++#define SET_HAS_EWMH_INIT_HIDDEN_STATE(fw,x) \
++	(fw)->flags.has_ewmh_init_hidden_state = (x)
++#define SETM_HAS_EWMH_INIT_HIDDEN_STATE(fw,x) \
++	(fw)->flag_mask.has_ewmh_init_hidden_state = (x)
++#define HAS_EWMH_INIT_HIDDEN_STATE(fw) \
++	((fw)->flags.has_ewmh_init_hidden_state)
++#define SET_HAS_EWMH_INIT_MAXHORIZ_STATE(fw,x) \
++	(fw)->flags.has_ewmh_init_maxhoriz_state = (x)
++#define SETM_HAS_EWMH_INIT_MAXHORIZ_STATE(fw,x) \
++	(fw)->flag_mask.has_ewmh_init_maxhoriz_state = (x)
++#define HAS_EWMH_INIT_MAXHORIZ_STATE(fw) \
++	((fw)->flags.has_ewmh_init_maxhoriz_state)
++#define SET_HAS_EWMH_INIT_MAXVERT_STATE(fw,x) \
++	(fw)->flags.has_ewmh_init_maxvert_state = (x)
++#define SETM_HAS_EWMH_INIT_MAXVERT_STATE(fw,x) \
++	(fw)->flag_mask.has_ewmh_init_maxvert_state = (x)
++#define HAS_EWMH_INIT_MAXVERT_STATE(fw) \
++	((fw)->flags.has_ewmh_init_maxvert_state)
++#define SET_HAS_EWMH_INIT_MODAL_STATE(fw,x) \
++	(fw)->flags.has_ewmh_init_modal_state = (x)
++#define SETM_HAS_EWMH_INIT_MODAL_STATE(fw,x) \
++	(fw)->flag_mask.has_ewmh_init_modal_state = (x)
++#define HAS_EWMH_INIT_MODAL_STATE(fw) \
++	((fw)->flags.has_ewmh_init_modal_state)
++#define SET_HAS_EWMH_INIT_SHADED_STATE(fw,x) \
++	(fw)->flags.has_ewmh_init_shaded_state = (x)
++#define SETM_HAS_EWMH_INIT_SHADED_STATE(fw,x) \
++	(fw)->flag_mask.has_ewmh_init_shaded_state = (x)
++#define HAS_EWMH_INIT_SHADED_STATE(fw) \
++	((fw)->flags.has_ewmh_init_shaded_state)
++#define SET_HAS_EWMH_INIT_SKIP_PAGER_STATE(fw,x) \
++	(fw)->flags.has_ewmh_init_skip_pager_state = (x)
++#define SETM_HAS_EWMH_INIT_SKIP_PAGER_STATE(fw,x) \
++	(fw)->flag_mask.has_ewmh_init_skip_pager_state = (x)
++#define HAS_EWMH_INIT_SKIP_PAGER_STATE(fw) \
++	((fw)->flags.has_ewmh_init_skip_pager_state)
++#define SET_HAS_EWMH_INIT_SKIP_TASKBAR_STATE(fw,x) \
++	(fw)->flags.has_ewmh_init_skip_taskbar_state = (x)
++#define SETM_HAS_EWMH_INIT_SKIP_TASKBAR_STATE(fw,x) \
++	(fw)->flag_mask.has_ewmh_init_skip_taskbar_state = (x)
++#define HAS_EWMH_INIT_SKIP_TASKBAR_STATE(fw) \
++	((fw)->flags.has_ewmh_init_skip_taskbar_state)
++#define SET_HAS_EWMH_INIT_STICKY_STATE(fw,x) \
++	(fw)->flags.has_ewmh_init_sticky_state = (x)
++#define SETM_HAS_EWMH_INIT_STICKY_STATE(fw,x) \
++	(fw)->flag_mask.has_ewmh_init_sticky_state = (x)
++#define HAS_EWMH_INIT_STICKY_STATE(fw) \
++	((fw)->flags.has_ewmh_init_sticky_state)
++#define SET_HAS_EWMH_INIT_WM_DESKTOP(fw,x) \
++	(fw)->flags.has_ewmh_init_wm_desktop = (x)
++#define SETM_HAS_EWMH_INIT_WM_DESKTOP(fw,x) \
++	(fw)->flag_mask.has_ewmh_init_wm_desktop = (x)
++#define HAS_EWMH_INIT_WM_DESKTOP(fw) \
++	((fw)->flags.has_ewmh_init_wm_desktop)
++
++#endif /* _WINDOW_FLAGS_ */
diff --git a/windowmanagers/fvwm/patches/06-InactiveFont.patch b/windowmanagers/fvwm/patches/06-InactiveFont.patch
new file mode 100644
index 0000000..6bf36ad
--- /dev/null
+++ b/windowmanagers/fvwm/patches/06-InactiveFont.patch
@@ -0,0 +1,4386 @@
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/add_window.c fvwm-2.5.21-06/fvwm/add_window.c
+--- fvwm-2.5.21-05/fvwm/add_window.c	2007-03-03 13:18:42.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/add_window.c	2007-03-03 13:19:10.000000000 +0100
+@@ -628,20 +628,32 @@ static void destroy_window_font(FvwmWind
+ 	{
+ 		FlocaleUnloadFont(dpy, fw->title_font);
+ 	}
+ 	SET_WINDOW_FONT_LOADED(fw, 0);
+ 	/* Fall back to default font. There are some race conditions when a
+ 	 * window is destroyed and recaptured where an invalid font might be
+ 	 * accessed  otherwise. */
+ 	fw->title_font = Scr.DefaultFont;
+ 	SET_USING_DEFAULT_WINDOW_FONT(fw, 1);
+ 
++	if (IS_INACTIVE_WINDOW_FONT_LOADED(fw) && !USING_DEFAULT_INACTIVE_WINDOW_FONT(fw) &&
++	    fw->title_font != Scr.DefaultFont)
++	{
++		FlocaleUnloadFont(dpy, fw->title_font);
++	}
++	SET_INACTIVE_WINDOW_FONT_LOADED(fw, 0);
++	/* Fall back to default font. There are some race conditions when a
++	 * window is destroyed and recaptured where an invalid font might be
++	 * accessed  otherwise. */
++	fw->title_font = Scr.DefaultFont;
++	SET_USING_DEFAULT_INACTIVE_WINDOW_FONT(fw, 1);
++	
+ 	return;
+ }
+ 
+ static void destroy_icon_font(FvwmWindow *fw)
+ {
+ 	if (IS_ICON_FONT_LOADED(fw) && !USING_DEFAULT_ICON_FONT(fw) &&
+ 	    fw->icon_font != Scr.DefaultFont)
+ 	{
+ 		FlocaleUnloadFont(dpy, fw->icon_font);
+ 	}
+@@ -1669,20 +1681,39 @@ void setup_window_font(
+ 		}
+ 		else
+ 		{
+ 			/* no explicit font or failed to load, use default font
+ 			 * instead */
+ 			fw->title_font = Scr.DefaultFont;
+ 			SET_USING_DEFAULT_WINDOW_FONT(fw, 1);
+ 		}
+ 		SET_WINDOW_FONT_LOADED(fw, 1);
+ 	}
++	/* load inactive font */
++	if (!IS_INACTIVE_WINDOW_FONT_LOADED(fw))
++	{
++		if (S_HAS_INACTIVE_WINDOW_FONT(SCF(*pstyle)) &&
++		    SGET_INACTIVE_WINDOW_FONT(*pstyle) &&
++		    (fw->inactive_title_font =
++		     FlocaleLoadFont(dpy, SGET_INACTIVE_WINDOW_FONT(*pstyle), "FVWM")))
++		{
++			SET_USING_DEFAULT_INACTIVE_WINDOW_FONT(fw, 0);
++		}
++		else
++		{
++			/* no explicit font or failed to load, use active title font
++			 * instead */
++			fw->inactive_title_font = fw->title_font;
++			SET_USING_DEFAULT_INACTIVE_WINDOW_FONT(fw, 1);
++		}
++		SET_INACTIVE_WINDOW_FONT_LOADED(fw, 1);
++	}
+ 	setup_title_geometry(fw, pstyle);
+ 
+ 	return;
+ }
+ 
+ void setup_icon_font(
+ 	FvwmWindow *fw, window_style *pstyle, Bool do_destroy)
+ {
+ 	int height = 0;
+ 
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/add_window.c~ fvwm-2.5.21-06/fvwm/add_window.c~
+--- fvwm-2.5.21-05/fvwm/add_window.c~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/add_window.c~	2007-03-03 13:19:02.000000000 +0100
+@@ -0,0 +1,3515 @@
++/* -*-c-*- */
++/* This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++/* This module is based on Twm, but has been siginificantly modified
++ * by Rob Nation
++ */
++/*
++ *       Copyright 1988 by Evans & Sutherland Computer Corporation,
++ *                          Salt Lake City, Utah
++ *  Portions Copyright 1989 by the Massachusetts Institute of Technology
++ *                        Cambridge, Massachusetts
++ *
++ *                           All Rights Reserved
++ *
++ *    Permission to use, copy, modify, and distribute this software and
++ *    its documentation  for  any  purpose  and  without  fee is hereby
++ *    granted, provided that the above copyright notice appear  in  all
++ *    copies and that both  that  copyright  notice  and  this  permis-
++ *    sion  notice appear in supporting  documentation,  and  that  the
++ *    names of Evans & Sutherland and M.I.T. not be used in advertising
++ *    in publicity pertaining to distribution of the  software  without
++ *    specific, written prior permission.
++ *
++ *    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD
++ *    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-
++ *    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR
++ *    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-
++ *    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA
++ *    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ *    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE
++ *    OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* ---------------------------- included header files ---------------------- */
++
++#include "config.h"
++
++#include <stdio.h>
++
++#include "libs/fvwmlib.h"
++#include "libs/FShape.h"
++#include "libs/FScreen.h"
++#include "libs/Picture.h"
++#include "libs/PictureUtils.h"
++#include "libs/charmap.h"
++#include "libs/wcontext.h"
++#include "fvwm.h"
++#include "externs.h"
++#include "cursor.h"
++#include "execcontext.h"
++#include "commands.h"
++#include "bindings.h"
++#include "misc.h"
++#include "screen.h"
++#include "add_window.h"
++#include "events.h"
++#include "eventhandler.h"
++#include "eventmask.h"
++#include "module_interface.h"
++#include "stack.h"
++#include "update.h"
++#include "style.h"
++#include "icons.h"
++#include "gnome.h"
++#include "ewmh.h"
++#include "focus.h"
++#include "placement.h"
++#include "geometry.h"
++#include "session.h"
++#include "move_resize.h"
++#include "borders.h"
++#include "frame.h"
++#include "colormaps.h"
++#include "decorations.h"
++#include "functions.h"
++
++/* ---------------------------- local definitions -------------------------- */
++
++/* ---------------------------- local macros ------------------------------- */
++
++/* ---------------------------- imports ------------------------------------ */
++
++/* ---------------------------- included code files ------------------------ */
++
++/* ---------------------------- local types -------------------------------- */
++
++/* ---------------------------- forward declarations ----------------------- */
++
++/* ---------------------------- local variables ---------------------------- */
++
++/* ---------------------------- exported variables (globals) --------------- */
++
++char NoName[] = "Untitled"; /* name if no name in XA_WM_NAME */
++char NoClass[] = "NoClass"; /* Class if no res_class in class hints */
++char NoResource[] = "NoResource"; /* Class if no res_name in class hints */
++
++/* ---------------------------- local functions ---------------------------- */
++
++static void delete_client_context(FvwmWindow *fw)
++{
++	FvwmWindow *cw;
++
++	/* We can not simply delete the context.  X might have reused the
++	 * window structure so we would delete the context that was established
++	 * by another FvwmWindow structure in the mean time. */
++	if (XFindContext(
++		    dpy, FW_W(fw), FvwmContext, (caddr_t *)&cw) !=
++	    XCNOENT && cw == fw)
++	{
++		XDeleteContext(dpy, FW_W(fw), FvwmContext);
++	}
++
++	return;
++}
++
++/*
++ *
++ *  Procedure:
++ *      CaptureOneWindow
++ *      CaptureAllWindows
++ *
++ *   Decorates windows at start-up and during recaptures
++ *
++ */
++
++static void CaptureOneWindow(
++	const exec_context_t *exc, FvwmWindow *fw, Window window,
++	Window keep_on_top_win, Window parent_win, Bool is_recapture)
++{
++	Window w;
++	unsigned long data[1];
++	initial_window_options_t win_opts;
++	evh_args_t ea;
++	exec_context_changes_t ecc;
++	XEvent e;
++
++	if (fw == NULL)
++	{
++		return;
++	}
++	if (IS_SCHEDULED_FOR_DESTROY(fw))
++	{
++		/* Fvwm might crash in complex functions if we really try to
++		 * the dying window here because AddWindow() may fail and leave
++		 * a destroyed window in some structures.  By the way, it is
++		 * pretty useless to recapture a window that will vanish in a
++		 * moment. */
++		return;
++	}
++	/* Grab the server to make sure the window does not die during the
++	 * recapture. */
++	MyXGrabServer(dpy);
++	if (
++		!XGetGeometry(
++			dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
++			(unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
++			(unsigned int*)&JunkBW, (unsigned int*)&JunkDepth))
++	{
++		/* The window has already died, do not recapture it! */
++		MyXUngrabServer(dpy);
++		return;
++	}
++	if (XFindContext(dpy, window, FvwmContext, (caddr_t *)&fw) != XCNOENT)
++	{
++		Bool is_mapped = IS_MAPPED(fw);
++
++		memset(&win_opts, 0, sizeof(win_opts));
++		win_opts.initial_state = DontCareState;
++		win_opts.flags.do_override_ppos = 1;
++		win_opts.flags.is_recapture = 1;
++		if (IS_ICONIFIED(fw))
++		{
++			win_opts.initial_state = IconicState;
++			win_opts.flags.is_iconified_by_parent =
++				IS_ICONIFIED_BY_PARENT(fw);
++		}
++		else
++		{
++			win_opts.initial_state = NormalState;
++			win_opts.flags.is_iconified_by_parent = 0;
++			if (Scr.CurrentDesk != fw->Desk)
++			{
++				SetMapStateProp(fw, NormalState);
++			}
++		}
++		data[0] = (unsigned long) fw->Desk;
++		XChangeProperty(
++			dpy, FW_W(fw), _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32,
++			PropModeReplace, (unsigned char *) data, 1);
++
++		/* are all these really needed ? */
++		/* EWMH_SetWMDesktop(fw); */
++		GNOME_SetHints(fw);
++		GNOME_SetDesk(fw);
++		GNOME_SetLayer(fw);
++		GNOME_SetWinArea(fw);
++
++		XSelectInput(dpy, FW_W(fw), NoEventMask);
++		w = FW_W(fw);
++		XUnmapWindow(dpy, FW_W_FRAME(fw));
++		border_undraw_decorations(fw);
++		RestoreWithdrawnLocation(fw, is_recapture, parent_win);
++		SET_DO_REUSE_DESTROYED(fw, 1); /* RBW - 1999/03/20 */
++		destroy_window(fw);
++		win_opts.flags.is_menu =
++			(is_recapture && fw != NULL && IS_TEAR_OFF_MENU(fw));
++
++
++		fev_make_null_event(&e, dpy);
++		e.xmaprequest.window = w;
++		e.xmaprequest.parent = Scr.Root;
++		ecc.x.etrigger = &e;
++		ecc.w.fw = NULL;
++		ecc.w.w = w;
++		ecc.w.wcontext = C_ROOT;
++		ea.exc = exc_clone_context(
++			exc, &ecc, ECC_ETRIGGER | ECC_FW | ECC_W |
++			ECC_WCONTEXT);
++		HandleMapRequestKeepRaised(&ea, keep_on_top_win, fw, &win_opts);
++		exc_destroy_context(ea.exc);
++
++		/* HandleMapRequestKeepRaised may have destroyed the fw if the
++		 * window vanished while in AddWindow(), so don't access fw
++		 * anymore before checking if it is a valid window. */
++		if (check_if_fvwm_window_exists(fw))
++		{
++			if (!fFvwmInStartup)
++			{
++				SET_MAP_PENDING(fw, 0);
++				SET_MAPPED(fw, is_mapped);
++			}
++		}
++	}
++	MyXUngrabServer(dpy);
++
++	return;
++}
++
++/* Put a transparent window all over the screen to hide what happens below. */
++static void hide_screen(
++	Bool do_hide, Window *ret_hide_win, Window *ret_parent_win)
++{
++	static Bool is_hidden = False;
++	static Window hide_win = None;
++	static Window parent_win = None;
++	XSetWindowAttributes xswa;
++	unsigned long valuemask;
++
++	if (do_hide == is_hidden)
++	{
++		/* nothing to do */
++		if (ret_hide_win)
++		{
++			*ret_hide_win = hide_win;
++		}
++		if (ret_parent_win)
++		{
++			*ret_parent_win = parent_win;
++		}
++
++		return;
++	}
++	is_hidden = do_hide;
++	if (do_hide)
++	{
++		xswa.override_redirect = True;
++		xswa.cursor = Scr.FvwmCursors[CRS_WAIT];
++		xswa.backing_store = NotUseful;
++		xswa.save_under = False;
++		xswa.background_pixmap = None;
++		valuemask = CWOverrideRedirect | CWCursor | CWSaveUnder |
++			CWBackingStore | CWBackPixmap;
++		hide_win = XCreateWindow(
++			dpy, Scr.Root, 0, 0, Scr.MyDisplayWidth,
++			Scr.MyDisplayHeight, 0, Pdepth, InputOutput,
++			Pvisual, valuemask, &xswa);
++		if (hide_win)
++		{
++			/* When recapturing, all windows are reparented to this
++			 * window. If they are reparented to the root window,
++			 * they will flash over the hide_win with XFree.  So
++			 * reparent them to an unmapped window that looks like
++			 * the root window. */
++			parent_win = XCreateWindow(
++				dpy, Scr.Root, 0, 0, Scr.MyDisplayWidth,
++				Scr.MyDisplayHeight, 0, CopyFromParent,
++				InputOutput, CopyFromParent, valuemask, &xswa);
++			if (!parent_win)
++			{
++				XDestroyWindow(dpy, hide_win);
++				hide_win = None;
++			}
++			else
++			{
++				XMapWindow(dpy, hide_win);
++				XFlush(dpy);
++			}
++		}
++	}
++	else
++	{
++		if (hide_win != None)
++		{
++			XDestroyWindow(dpy, hide_win);
++		}
++		if (parent_win != None)
++		{
++			XDestroyWindow(dpy, parent_win);
++		}
++		XFlush(dpy);
++		hide_win = None;
++		parent_win = None;
++	}
++	if (ret_hide_win)
++	{
++		*ret_hide_win = hide_win;
++	}
++	if (ret_parent_win)
++	{
++		*ret_parent_win = parent_win;
++	}
++
++	return;
++}
++
++/*
++ *
++ *  Procedure:
++ *      MappedNotOverride - checks to see if we should really
++ *              put a fvwm frame on the window
++ *
++ *  Returned Value:
++ *      1   - go ahead and frame the window
++ *      0   - don't frame the window
++ *
++ *  Inputs:
++ *      w       - the window to check
++ *
++ */
++
++static int MappedNotOverride(
++	Window w, initial_window_options_t *win_opts)
++{
++	XWindowAttributes wa;
++	Atom atype;
++	int aformat;
++	unsigned long nitems, bytes_remain;
++	unsigned char *prop;
++
++	win_opts->initial_state = DontCareState;
++	if ((w==Scr.NoFocusWin)||(!XGetWindowAttributes(dpy, w, &wa)))
++	{
++		return 0;
++	}
++	if (XGetWindowProperty(
++		    dpy,w,_XA_WM_STATE,0L,3L,False,_XA_WM_STATE,
++		    &atype,&aformat,&nitems,&bytes_remain,&prop)==Success)
++	{
++		if (prop != NULL)
++		{
++			win_opts->initial_state = *(long *)prop;
++			XFree(prop);
++		}
++	}
++	if (wa.override_redirect == True)
++	{
++		XSelectInput(dpy, w, XEVMASK_ORW);
++		XFlush(dpy);
++	}
++
++	return (((win_opts->initial_state == IconicState) ||
++		 (wa.map_state != IsUnmapped)) &&
++		(wa.override_redirect != True));
++}
++
++static void do_recapture(F_CMD_ARGS, Bool fSingle)
++{
++	FvwmWindow *fw = exc->w.fw;
++
++	MyXGrabServer(dpy);
++	if (fSingle)
++	{
++		CaptureOneWindow(
++			exc, fw, FW_W(fw), None, None, True);
++	}
++	else
++	{
++		CaptureAllWindows(exc, True);
++	}
++	/* Throw away queued up events. We don't want user input during a
++	 * recapture.  The window the user clicks in might disapper at the very
++	 * same moment and the click goes through to the root window. Not good
++	 */
++	XAllowEvents(dpy, AsyncPointer, CurrentTime);
++	discard_events(
++		ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|\
++		PointerMotionMask|KeyPressMask|KeyReleaseMask);
++#ifdef DEBUG_STACK_RING
++	verify_stack_ring_consistency();
++#endif
++	MyXUngrabServer(dpy);
++
++	return;
++}
++
++static void setup_window_structure(
++	FvwmWindow **pfw, Window w, FvwmWindow *ReuseWin)
++{
++	FvwmWindow save_state;
++	FvwmWindow *savewin = NULL;
++
++	/*
++	  Allocate space for the FvwmWindow struct, or reuse an
++	  old one (on Recapture).
++	*/
++	if (ReuseWin == NULL)
++	{
++		*pfw = (FvwmWindow *)safemalloc(sizeof(FvwmWindow));
++	}
++	else
++	{
++		*pfw = ReuseWin;
++		savewin = &save_state;
++		memcpy(savewin, ReuseWin, sizeof(FvwmWindow));
++	}
++
++	/*
++	  RBW - 1999/05/28 - modify this when we implement the preserving of
++	  various states across a Recapture. The Destroy function in misc.c may
++	  also need tweaking, depending on what you want to preserve.
++	  For now, just zap any old information, except the desk.
++	*/
++	memset(*pfw, '\0', sizeof(FvwmWindow));
++	FW_W(*pfw) = w;
++	if (savewin != NULL)
++	{
++		(*pfw)->Desk = savewin->Desk;
++		SET_SHADED(*pfw, IS_SHADED(savewin));
++		SET_USED_TITLE_DIR_FOR_SHADING(
++			*pfw, USED_TITLE_DIR_FOR_SHADING(savewin));
++		SET_SHADED_DIR(*pfw, SHADED_DIR(savewin));
++		SET_NAME_CHANGED(*pfw,IS_NAME_CHANGED(savewin));
++		(*pfw)->placed_by_button = savewin->placed_by_button;
++		SET_PLACED_BY_FVWM(*pfw, IS_PLACED_BY_FVWM(savewin));
++		SET_HAS_EWMH_WM_ICON_HINT(*pfw, HAS_EWMH_WM_ICON_HINT(savewin));
++		(*pfw)->ewmh_mini_icon_width = savewin->ewmh_mini_icon_width;
++		(*pfw)->ewmh_mini_icon_height = savewin->ewmh_mini_icon_height;
++		(*pfw)->ewmh_icon_width = savewin->ewmh_icon_width;
++		(*pfw)->ewmh_icon_height = savewin->ewmh_icon_height;
++		(*pfw)->ewmh_hint_desktop = savewin->ewmh_hint_desktop;
++		/* restore ewmh state */
++		EWMH_SetWMState(savewin, True);
++		SET_HAS_EWMH_INIT_WM_DESKTOP(
++			*pfw, HAS_EWMH_INIT_WM_DESKTOP(savewin));
++		SET_HAS_EWMH_INIT_FULLSCREEN_STATE(
++			*pfw, HAS_EWMH_INIT_FULLSCREEN_STATE(savewin));
++		SET_HAS_EWMH_INIT_HIDDEN_STATE(
++			*pfw, HAS_EWMH_INIT_HIDDEN_STATE(savewin));
++		SET_HAS_EWMH_INIT_MAXHORIZ_STATE(
++			*pfw, HAS_EWMH_INIT_MAXHORIZ_STATE(savewin));
++		SET_HAS_EWMH_INIT_MAXVERT_STATE(
++			*pfw, HAS_EWMH_INIT_MAXVERT_STATE(savewin));
++		SET_HAS_EWMH_INIT_SHADED_STATE(
++			*pfw, HAS_EWMH_INIT_SHADED_STATE(savewin));
++		SET_HAS_EWMH_INIT_STICKY_STATE(
++			*pfw, HAS_EWMH_INIT_STICKY_STATE(savewin));
++		CLEAR_USER_STATES(*pfw, ~0);
++		SET_USER_STATES(*pfw, GET_USER_STATES(savewin));
++	}
++	else
++	{
++		/* make sure that new windows *remember* being shaded with
++		 * title dir last */
++		SET_USED_TITLE_DIR_FOR_SHADING(*pfw,1);
++	}
++
++	(*pfw)->cmap_windows = (Window *)NULL;
++	if (FMiniIconsSupported)
++	{
++		(*pfw)->mini_pixmap_file = NULL;
++		(*pfw)->mini_icon = NULL;
++	}
++
++	return;
++}
++
++static void setup_window_name_count(FvwmWindow *fw)
++{
++	FvwmWindow *t;
++	int count = 0;
++	Bool done = False;
++
++	if (!fw->name.name)
++	{
++		done = True;
++	}
++
++	if (fw->icon_name.name &&
++	    strcmp(fw->name.name, fw->icon_name.name) == 0)
++	{
++		count = fw->icon_name_count;
++	}
++
++	while (!done)
++	{
++		done = True;
++		for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
++		{
++			if (t == fw)
++			{
++				continue;
++			}
++			if ((t->name.name &&
++			     strcmp(t->name.name, fw->name.name) == 0 &&
++			     t->name_count == count) ||
++			    (t->icon_name.name &&
++			     strcmp(t->icon_name.name, fw->name.name) == 0 &&
++			     t->icon_name_count == count))
++			{
++				count++;
++				done = False;
++			}
++		}
++	}
++	fw->name_count = count;
++
++	return;
++}
++
++static void setup_icon_name_count(FvwmWindow *fw)
++{
++	FvwmWindow *t;
++	int count = 0;
++	Bool done = False;
++
++	if (!fw->icon_name.name)
++	{
++		done = True;
++	}
++	if (fw->name.name &&
++	    strcmp(fw->name.name, fw->icon_name.name) == 0)
++	{
++		count = fw->name_count;
++	}
++
++	while (!done)
++	{
++		done = True;
++		for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
++		{
++			if (t == fw)
++			{
++				continue;
++			}
++			if ((t->icon_name.name &&
++			     strcmp(t->icon_name.name,
++				    fw->icon_name.name) == 0 &&
++			     t->icon_name_count == count) ||
++			    (t->name.name &&
++			     strcmp(t->name.name, fw->icon_name.name) == 0 &&
++			     t->name_count == count))
++			{
++				count++;
++				done = False;
++			}
++		}
++	}
++	fw->icon_name_count = count;
++
++	return;
++}
++
++static void setup_class_and_resource(FvwmWindow *fw)
++{
++	/* removing NoClass change for now... */
++	fw->class.res_name = NoResource;
++	fw->class.res_class = NoClass;
++	XGetClassHint(dpy, FW_W(fw), &fw->class);
++	if (fw->class.res_name == NULL)
++	{
++		fw->class.res_name = NoResource;
++	}
++	if (fw->class.res_class == NULL)
++	{
++		fw->class.res_class = NoClass;
++	}
++	FetchWmProtocols (fw);
++	FetchWmColormapWindows (fw);
++
++	return;
++}
++
++static void setup_window_attr(
++	FvwmWindow *fw, XWindowAttributes *ret_attr)
++{
++	if (XGetWindowAttributes(dpy, FW_W(fw), ret_attr) == 0)
++	{
++		/* can't happen because fvwm has grabbed the server and does
++		 * not destroy the window itself */
++	}
++	fw->attr_backup.backing_store = ret_attr->backing_store;
++	fw->attr_backup.border_width = ret_attr->border_width;
++	fw->attr_backup.depth = ret_attr->depth;
++	fw->attr_backup.bit_gravity = ret_attr->bit_gravity;
++	fw->attr_backup.is_bit_gravity_stored = 0;
++	fw->attr_backup.visual = ret_attr->visual;
++	fw->attr_backup.colormap = ret_attr->colormap;
++
++	return;
++}
++
++static void destroy_window_font(FvwmWindow *fw)
++{
++	if (IS_WINDOW_FONT_LOADED(fw) && !USING_DEFAULT_WINDOW_FONT(fw) &&
++	    fw->title_font != Scr.DefaultFont)
++	{
++		FlocaleUnloadFont(dpy, fw->title_font);
++	}
++	SET_WINDOW_FONT_LOADED(fw, 0);
++	/* Fall back to default font. There are some race conditions when a
++	 * window is destroyed and recaptured where an invalid font might be
++	 * accessed  otherwise. */
++	fw->title_font = Scr.DefaultFont;
++	SET_USING_DEFAULT_WINDOW_FONT(fw, 1);
++
++	return;
++}
++
++static void destroy_icon_font(FvwmWindow *fw)
++{
++	if (IS_ICON_FONT_LOADED(fw) && !USING_DEFAULT_ICON_FONT(fw) &&
++	    fw->icon_font != Scr.DefaultFont)
++	{
++		FlocaleUnloadFont(dpy, fw->icon_font);
++	}
++	SET_ICON_FONT_LOADED(fw, 0);
++	/* Fall back to default font (see comment above). */
++	fw->icon_font = Scr.DefaultFont;
++	SET_USING_DEFAULT_ICON_FONT(fw, 1);
++
++	return;
++}
++
++static void adjust_fvwm_internal_windows(FvwmWindow *fw)
++{
++	if (fw == Scr.Hilite)
++	{
++		Scr.Hilite = NULL;
++	}
++	update_last_screen_focus_window(fw);
++	restore_focus_after_unmap(fw, False);
++	frame_destroyed_frame(FW_W(fw));
++	if (FW_W(fw) == Scr.StolenFocusWin)
++	{
++		Scr.StolenFocusWin = None;
++	}
++	if (Scr.focus_in_pending_window == fw)
++	{
++		Scr.focus_in_pending_window = NULL;
++	}
++	if (Scr.cascade_window == fw)
++	{
++		Scr.cascade_window = NULL;
++	}
++
++	return;
++}
++
++static void broadcast_mini_icon(FvwmWindow *fw)
++{
++	if (!FMiniIconsSupported)
++	{
++		return;
++	}
++	if (fw->mini_pixmap_file && fw->mini_icon)
++	{
++		BroadcastFvwmPicture(
++			M_MINI_ICON,
++			FW_W(fw), FW_W_FRAME(fw), (unsigned long)fw,
++			fw->mini_icon, fw->mini_pixmap_file);
++	}
++
++	return;
++}
++
++static void setup_mini_icon(FvwmWindow *fw, window_style *pstyle)
++{
++	FvwmPictureAttributes fpa;
++
++	if (!FMiniIconsSupported)
++	{
++		return;
++	}
++	if (SHAS_MINI_ICON(&pstyle->flags))
++	{
++		fw->mini_pixmap_file = SGET_MINI_ICON_NAME(*pstyle);
++	}
++	else
++	{
++		fw->mini_pixmap_file = NULL;
++	}
++	if (fw->mini_pixmap_file)
++	{
++		fpa.mask = 0;
++		fw->mini_icon = PCacheFvwmPicture(
++			dpy, Scr.NoFocusWin, NULL, fw->mini_pixmap_file, fpa);
++	}
++	else
++	{
++		fw->mini_icon = NULL;
++	}
++
++	return;
++}
++
++/*
++ * Copy icon size limits from window_style structure to FvwmWindow
++ * structure.
++ */
++void setup_icon_size_limits(FvwmWindow *fw, window_style *pstyle)
++{
++	if (SHAS_ICON_SIZE_LIMITS(&pstyle->flags))
++	{
++		fw->min_icon_width = SGET_MIN_ICON_WIDTH(*pstyle);
++		fw->min_icon_height = SGET_MIN_ICON_HEIGHT(*pstyle);
++		fw->max_icon_width = SGET_MAX_ICON_WIDTH(*pstyle);
++		fw->max_icon_height = SGET_MAX_ICON_HEIGHT(*pstyle);
++		fw->icon_resize_type = SGET_ICON_RESIZE_TYPE(*pstyle);
++	}
++	else
++	{
++		fw->min_icon_width = MIN_ALLOWABLE_ICON_DIMENSION;
++		fw->min_icon_height = MIN_ALLOWABLE_ICON_DIMENSION;
++		fw->max_icon_width = MAX_ALLOWABLE_ICON_DIMENSION;
++		fw->max_icon_height = MAX_ALLOWABLE_ICON_DIMENSION;
++		fw->icon_resize_type = ICON_RESIZE_TYPE_NONE;
++	}
++
++	return;
++}
++
++void setup_icon_background_parameters(FvwmWindow *fw, window_style *pstyle)
++{
++	if (SHAS_ICON_BACKGROUND_PADDING(&pstyle->flags))
++	{
++		fw->icon_background_padding =
++			SGET_ICON_BACKGROUND_PADDING(*pstyle);
++	}
++	else
++	{
++		fw->icon_background_padding = ICON_BACKGROUND_PADDING;
++	}
++	if (SHAS_ICON_BACKGROUND_RELIEF(&pstyle->flags))
++	{
++		fw->icon_background_relief =
++			SGET_ICON_BACKGROUND_RELIEF(*pstyle);
++	}
++	else
++	{
++		fw->icon_background_relief = ICON_RELIEF_WIDTH;
++	}
++	return;
++}
++
++void setup_icon_title_parameters(FvwmWindow *fw, window_style *pstyle)
++{
++	if (SHAS_ICON_TITLE_RELIEF(&pstyle->flags))
++	{
++		fw->icon_title_relief =
++			SGET_ICON_TITLE_RELIEF(*pstyle);
++	}
++	else
++	{
++		fw->icon_title_relief = ICON_RELIEF_WIDTH;
++	}
++	return;
++}
++
++static void setup_frame_window(
++	FvwmWindow *fw)
++{
++	XSetWindowAttributes attributes;
++	int valuemask;
++
++	valuemask = CWBackingStore | CWBackPixmap | CWEventMask | CWSaveUnder;
++	attributes.backing_store = NotUseful;
++	attributes.background_pixmap = None;
++	attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
++	attributes.event_mask = XEVMASK_FRAMEW_CAPTURE;
++	attributes.save_under = False;
++	/* create the frame window, child of root, grandparent of client */
++	FW_W_FRAME(fw) = XCreateWindow(
++		dpy, Scr.Root, fw->g.frame.x, fw->g.frame.y,
++		fw->g.frame.width, fw->g.frame.height, 0, CopyFromParent,
++		InputOutput, CopyFromParent, valuemask | CWCursor, &attributes);
++	XSaveContext(dpy, FW_W(fw), FvwmContext, (caddr_t) fw);
++	XSaveContext(dpy, FW_W_FRAME(fw), FvwmContext, (caddr_t) fw);
++
++	return;
++}
++
++static void setup_title_window(
++	FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes)
++{
++	valuemask |= CWCursor | CWEventMask;
++	pattributes->cursor = Scr.FvwmCursors[CRS_TITLE];
++	pattributes->event_mask = XEVMASK_TITLEW;
++
++	FW_W_TITLE(fw) = XCreateWindow(
++		dpy, FW_W_FRAME(fw), 0, 0, 1, 1, 0, Pdepth, InputOutput,
++		Pvisual, valuemask, pattributes);
++	XSaveContext(dpy, FW_W_TITLE(fw), FvwmContext, (caddr_t) fw);
++
++	return;
++}
++
++static void destroy_title_window(FvwmWindow *fw, Bool do_only_delete_context)
++{
++	if (!do_only_delete_context)
++	{
++		XDestroyWindow(dpy, FW_W_TITLE(fw));
++		FW_W_TITLE(fw) = None;
++	}
++	XDeleteContext(dpy, FW_W_TITLE(fw), FvwmContext);
++	XFlush(dpy);
++	FW_W_TITLE(fw) = None;
++
++	return;
++}
++
++static void change_title_window(
++	FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes)
++{
++	if (HAS_TITLE(fw) && FW_W_TITLE(fw) == None)
++	{
++		setup_title_window(fw, valuemask, pattributes);
++	}
++	else if (!HAS_TITLE(fw) && FW_W_TITLE(fw) != None)
++	{
++		destroy_title_window(fw, False);
++	}
++
++	return;
++}
++
++static void setup_button_windows(
++	FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes,
++	short buttons)
++{
++	int i;
++	Bool has_button;
++	Bool is_deleted = False;
++
++	valuemask |= CWCursor | CWEventMask;
++	pattributes->cursor = Scr.FvwmCursors[CRS_SYS];
++	pattributes->event_mask = XEVMASK_BUTTONW;
++
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		has_button = (((!(i & 1) && i / 2 < Scr.nr_left_buttons) ||
++			       ( (i & 1) && i / 2 < Scr.nr_right_buttons)) &&
++			      (buttons & (1 << i)));
++		if (FW_W_BUTTON(fw, i) == None && has_button)
++		{
++			FW_W_BUTTON(fw, i) =
++				XCreateWindow(
++					dpy, FW_W_FRAME(fw), 0, 0, 1, 1, 0,
++					Pdepth, InputOutput, Pvisual,
++					valuemask, pattributes);
++			XSaveContext(
++				dpy, FW_W_BUTTON(fw, i), FvwmContext,
++				(caddr_t)fw);
++		}
++		else if (FW_W_BUTTON(fw, i) != None && !has_button)
++		{
++			/* destroy the current button window */
++			XDestroyWindow(dpy, FW_W_BUTTON(fw, i));
++			XDeleteContext(dpy, FW_W_BUTTON(fw, i), FvwmContext);
++			is_deleted = True;
++			FW_W_BUTTON(fw, i) = None;
++		}
++	}
++	if (is_deleted == True)
++	{
++		XFlush(dpy);
++	}
++
++	return;
++}
++
++static void destroy_button_windows(FvwmWindow *fw, Bool do_only_delete_context)
++{
++	int i;
++	Bool is_deleted = False;
++
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		if (FW_W_BUTTON(fw, i) != None)
++		{
++			if (!do_only_delete_context)
++			{
++				XDestroyWindow(dpy, FW_W_BUTTON(fw, i));
++				FW_W_BUTTON(fw, i) = None;
++			}
++			XDeleteContext(dpy, FW_W_BUTTON(fw, i), FvwmContext);
++			is_deleted = True;
++			FW_W_BUTTON(fw, i) = None;
++		}
++	}
++	if (is_deleted == True)
++	{
++		XFlush(dpy);
++	}
++
++	return;
++}
++
++static void change_button_windows(
++	FvwmWindow *fw, int valuemask, XSetWindowAttributes *pattributes,
++	short buttons)
++{
++	if (HAS_TITLE(fw))
++	{
++		setup_button_windows(
++			fw, valuemask, pattributes, buttons);
++	}
++	else
++	{
++		destroy_button_windows(fw, False);
++	}
++
++	return;
++}
++
++static void setup_parent_window(FvwmWindow *fw)
++{
++	size_borders b;
++
++	XSetWindowAttributes attributes;
++	int valuemask;
++
++	valuemask = CWBackingStore | CWBackPixmap | CWCursor | CWEventMask |
++		CWSaveUnder;
++	attributes.backing_store = NotUseful;
++	attributes.background_pixmap = None;
++	attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
++	attributes.event_mask = XEVMASK_PARENTW;
++	attributes.save_under = False;
++
++	/* This window is exactly the same size as the client for the benefit
++	 * of some clients */
++	get_window_borders(fw, &b);
++	FW_W_PARENT(fw) = XCreateWindow(
++		dpy, FW_W_FRAME(fw), b.top_left.width, b.top_left.height,
++		fw->g.frame.width - b.total_size.width,
++		fw->g.frame.height - b.total_size.height,
++		0, CopyFromParent, InputOutput, CopyFromParent, valuemask,
++		&attributes);
++
++	XSaveContext(dpy, FW_W_PARENT(fw), FvwmContext, (caddr_t) fw);
++
++	return;
++}
++
++static void setup_resize_handle_cursors(FvwmWindow *fw)
++{
++	unsigned long valuemask;
++	XSetWindowAttributes attributes;
++	int i;
++
++	if (HAS_NO_BORDER(fw))
++	{
++		return;
++	}
++	valuemask = CWCursor;
++	attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
++
++	for (i = 0; i < 4; i++)
++	{
++		if (HAS_HANDLES(fw))
++		{
++			attributes.cursor = Scr.FvwmCursors[CRS_TOP_LEFT + i];
++		}
++		XChangeWindowAttributes(
++			dpy, FW_W_CORNER(fw, i), valuemask, &attributes);
++		if (HAS_HANDLES(fw))
++		{
++			attributes.cursor = Scr.FvwmCursors[CRS_TOP + i];
++		}
++		XChangeWindowAttributes(
++			dpy, FW_W_SIDE(fw, i), valuemask, &attributes);
++	}
++
++	return;
++}
++
++static void setup_resize_handle_windows(FvwmWindow *fw)
++{
++	unsigned long valuemask;
++	XSetWindowAttributes attributes;
++	int i;
++	int c_grav[4] = {
++		NorthWestGravity,
++		NorthEastGravity,
++		SouthWestGravity,
++		SouthEastGravity
++	};
++	int s_grav[4] = {
++		NorthWestGravity,
++		NorthEastGravity,
++		SouthWestGravity,
++		NorthWestGravity
++	};
++
++	if (HAS_NO_BORDER(fw))
++	{
++		return;
++	}
++	valuemask = CWEventMask | CWBackingStore | CWSaveUnder | CWWinGravity |
++		CWBorderPixel | CWColormap;
++	attributes.event_mask = XEVMASK_BORDERW;
++	attributes.backing_store = NotUseful;
++	attributes.save_under = False;
++	attributes.border_pixel = 0;
++	attributes.colormap = Pcmap;
++	/* Just dump the windows any old place and let frame_setup_window take
++	 * care of the mess */
++	for (i = 0; i < 4; i++)
++	{
++		attributes.win_gravity = c_grav[i];
++		FW_W_CORNER(fw, i) = XCreateWindow(
++			dpy, FW_W_FRAME(fw), -1, -1, 1, 1, 0, Pdepth,
++			InputOutput, Pvisual, valuemask, &attributes);
++		XSaveContext(
++			dpy, FW_W_CORNER(fw, i), FvwmContext, (caddr_t)fw);
++		attributes.win_gravity = s_grav[i];
++		FW_W_SIDE(fw, i) = XCreateWindow(
++			dpy, FW_W_FRAME(fw), -1, -1, 1, 1, 0, Pdepth,
++			InputOutput, Pvisual, valuemask, &attributes);
++		XSaveContext(dpy, FW_W_SIDE(fw, i), FvwmContext, (caddr_t)fw);
++	}
++	setup_resize_handle_cursors(fw);
++
++	return;
++}
++
++static void destroy_resize_handle_windows(
++	FvwmWindow *fw, Bool do_only_delete_context)
++{
++	int i;
++
++	for (i = 0; i < 4 ; i++)
++	{
++		XDeleteContext(dpy, FW_W_SIDE(fw, i), FvwmContext);
++		XDeleteContext(dpy, FW_W_CORNER(fw, i), FvwmContext);
++		if (!do_only_delete_context)
++		{
++			XDestroyWindow(dpy, FW_W_SIDE(fw, i));
++			XDestroyWindow(dpy, FW_W_CORNER(fw, i));
++			FW_W_SIDE(fw, i) = None;
++			FW_W_CORNER(fw, i) = None;
++		}
++	}
++	XFlush(dpy);
++
++	return;
++}
++
++static void change_resize_handle_windows(FvwmWindow *fw)
++{
++	if (!HAS_NO_BORDER(fw) && FW_W_SIDE(fw, 0) == None)
++	{
++		setup_resize_handle_windows(fw);
++	}
++	else if (HAS_NO_BORDER(fw) && FW_W_SIDE(fw, 0) != None)
++	{
++		destroy_resize_handle_windows(fw, False);
++	}
++	else
++	{
++		setup_resize_handle_cursors(fw);
++	}
++
++	return;
++}
++
++static void setup_frame_stacking(FvwmWindow *fw)
++{
++	int i;
++	int n;
++	Window w[10 + NUMBER_OF_TITLE_BUTTONS];
++
++	/* Stacking order (top to bottom):
++	 *  - Parent window
++	 *  - Title and buttons
++	 *  - Corner handles
++	 *  - Side handles
++	 */
++	n = 0;
++	if (!IS_SHADED(fw))
++	{
++		w[n] = FW_W_PARENT(fw);
++		n++;
++	}
++	if (HAS_TITLE(fw))
++	{
++		for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i += 2)
++		{
++			if (FW_W_BUTTON(fw, i) != None)
++			{
++				w[n] = FW_W_BUTTON(fw, i);
++				n++;
++			}
++		}
++		for (i = 2 * NR_RIGHT_BUTTONS - 1; i > 0; i -= 2)
++		{
++			if (FW_W_BUTTON(fw, i) != None)
++			{
++				w[n] = FW_W_BUTTON(fw, i);
++				n++;
++			}
++		}
++		if (FW_W_TITLE(fw) != None)
++		{
++			w[n] = FW_W_TITLE(fw);
++			n++;
++		}
++	}
++	for (i = 0; i < 4; i++)
++	{
++		if (FW_W_CORNER(fw, i) != None)
++		{
++			w[n] = FW_W_CORNER(fw, i);
++			n++;
++		}
++	}
++	for (i = 0; i < 4; i++)
++	{
++		if (FW_W_SIDE(fw, i) != None)
++		{
++			w[n] = FW_W_SIDE(fw, i);
++			n++;
++		}
++	}
++	if (IS_SHADED(fw))
++	{
++		w[n] = FW_W_PARENT(fw);
++		n++;
++	}
++	XRestackWindows(dpy, w, n);
++
++	return;
++}
++
++static void get_default_window_attributes(
++	FvwmWindow *fw, unsigned long *pvaluemask,
++	XSetWindowAttributes *pattributes)
++{
++	*pvaluemask |= CWBackingStore | CWCursor | CWSaveUnder | CWBorderPixel |
++		CWColormap | CWBackPixmap;
++	pattributes->background_pixel = 0;
++	pattributes->background_pixmap = None;
++	pattributes->backing_store = NotUseful;
++	pattributes->cursor = Scr.FvwmCursors[CRS_DEFAULT];
++	pattributes->save_under = False;
++	pattributes->border_pixel = 0;
++	pattributes->colormap = Pcmap;
++
++	return;
++}
++
++static void setup_auxiliary_windows(
++	FvwmWindow *fw, Bool setup_frame_and_parent, short buttons)
++{
++	unsigned long valuemask_save = 0;
++	XSetWindowAttributes attributes;
++
++	get_default_window_attributes(fw, &valuemask_save, &attributes);
++
++	if (setup_frame_and_parent)
++	{
++		setup_frame_window(fw);
++		setup_parent_window(fw);
++	}
++	setup_resize_handle_windows(fw);
++	if (HAS_TITLE(fw))
++	{
++		setup_title_window(fw, valuemask_save, &attributes);
++		setup_button_windows(fw, valuemask_save, &attributes, buttons);
++	}
++	setup_frame_stacking(fw);
++	XMapSubwindows (dpy, FW_W_FRAME(fw));
++
++	return;
++}
++
++static void destroy_auxiliary_windows(
++	FvwmWindow *fw, Bool destroy_frame_and_parent)
++{
++	if (destroy_frame_and_parent)
++	{
++		XDeleteContext(dpy, FW_W_FRAME(fw), FvwmContext);
++		XDeleteContext(dpy, FW_W_PARENT(fw), FvwmContext);
++		delete_client_context(fw);
++		XDestroyWindow(dpy, FW_W_FRAME(fw));
++	}
++	if (HAS_TITLE(fw))
++	{
++		destroy_title_window(fw, True);
++	}
++	if (HAS_TITLE(fw))
++	{
++		destroy_button_windows(fw, True);
++	}
++	if (!HAS_NO_BORDER(fw))
++	{
++		destroy_resize_handle_windows(fw, True);
++	}
++	XFlush(dpy);
++
++	return;
++}
++
++static void setup_icon(FvwmWindow *fw, window_style *pstyle)
++{
++	increase_icon_hint_count(fw);
++	/* find a suitable icon pixmap */
++	if ((fw->wmhints) && (fw->wmhints->flags & IconWindowHint))
++	{
++		if (SHAS_ICON(&pstyle->flags) &&
++		    S_ICON_OVERRIDE(SCF(*pstyle)) == ICON_OVERRIDE)
++		{
++			ICON_DBG((stderr,"si: iwh ignored '%s'\n",
++				  fw->name.name));
++			fw->icon_bitmap_file = SGET_ICON_NAME(*pstyle);
++		}
++		else
++		{
++			ICON_DBG((stderr,"si: using iwh '%s'\n",
++				  fw->name.name));
++			fw->icon_bitmap_file = NULL;
++		}
++	}
++	else if ((fw->wmhints) && (fw->wmhints->flags & IconPixmapHint))
++	{
++		if (SHAS_ICON(&pstyle->flags) &&
++		    S_ICON_OVERRIDE(SCF(*pstyle)) != NO_ICON_OVERRIDE)
++		{
++			ICON_DBG((stderr,"si: iph ignored '%s'\n",
++				  fw->name.name));
++			fw->icon_bitmap_file = SGET_ICON_NAME(*pstyle);
++		}
++		else
++		{
++			ICON_DBG((stderr,"si: using iph '%s'\n",
++				  fw->name.name));
++			fw->icon_bitmap_file = NULL;
++		}
++	}
++	else if (SHAS_ICON(&pstyle->flags))
++	{
++		/* an icon was specified */
++		ICON_DBG((stderr,"si: using style '%s'\n", fw->name.name));
++		fw->icon_bitmap_file = SGET_ICON_NAME(*pstyle);
++	}
++	else
++	{
++		/* use default icon */
++		ICON_DBG((stderr,"si: using default '%s'\n", fw->name.name));
++		fw->icon_bitmap_file = Scr.DefaultIcon;
++	}
++
++	/* icon name */
++	if (!EWMH_WMIconName(fw, NULL, NULL, 0))
++	{
++		fw->icon_name.name = NoName;
++		fw->icon_name.name_list = NULL;
++		FlocaleGetNameProperty(
++			XGetWMIconName, dpy, FW_W(fw), &(fw->icon_name));
++	}
++	if (fw->icon_name.name == NoName)
++	{
++		fw->icon_name.name = fw->name.name;
++		SET_WAS_ICON_NAME_PROVIDED(fw, 0);
++	}
++	setup_visible_name(fw, True);
++
++
++	/* wait until the window is iconified and the icon window is mapped
++	 * before creating the icon window
++	 */
++	FW_W_ICON_TITLE(fw) = None;
++
++	EWMH_SetVisibleName(fw, True);
++	BroadcastWindowIconNames(fw, False, True);
++	if (fw->icon_bitmap_file != NULL &&
++	    fw->icon_bitmap_file != Scr.DefaultIcon)
++	{
++		BroadcastName(M_ICON_FILE,FW_W(fw),FW_W_FRAME(fw),
++			      (unsigned long)fw,fw->icon_bitmap_file);
++	}
++
++	return;
++}
++
++static void destroy_icon(FvwmWindow *fw)
++{
++	free_window_names(fw, False, True);
++	if (IS_PIXMAP_OURS(fw))
++	{
++		XFreePixmap(dpy, fw->iconPixmap);
++		fw->iconPixmap = None;
++		if (fw->icon_maskPixmap != None)
++		{
++			XFreePixmap(dpy, fw->icon_maskPixmap);
++			fw->icon_maskPixmap = None;
++		}
++		if (fw->icon_alphaPixmap != None)
++		{
++			XFreePixmap(dpy, fw->icon_alphaPixmap);
++			fw->icon_alphaPixmap = None;
++		}
++		if (fw->icon_alloc_pixels != NULL)
++		{
++			if (fw->icon_nalloc_pixels != 0)
++			{
++				PictureFreeColors(
++					dpy, Pcmap, fw->icon_alloc_pixels,
++					fw->icon_nalloc_pixels, 0,
++					fw->icon_no_limit);
++			}
++			free(fw->icon_alloc_pixels);
++			fw->icon_alloc_pixels = NULL;
++			fw->icon_nalloc_pixels = 0;
++			fw->icon_no_limit = 0;
++		}
++	}
++	if (FW_W_ICON_TITLE(fw))
++	{
++		XDestroyWindow(dpy, FW_W_ICON_TITLE(fw));
++		XDeleteContext(dpy, FW_W_ICON_TITLE(fw), FvwmContext);
++		XFlush(dpy);
++	}
++	if (FW_W_ICON_PIXMAP(fw) != None)
++	{
++		if (IS_ICON_OURS(fw))
++		{
++			XDestroyWindow(dpy, FW_W_ICON_PIXMAP(fw));
++		}
++		else
++		{
++			XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw));
++		}
++		XDeleteContext(dpy, FW_W_ICON_PIXMAP(fw), FvwmContext);
++	}
++	clear_icon(fw);
++	XFlush(dpy);
++
++	return;
++}
++
++static void setup_icon_boxes(FvwmWindow *fw, window_style *pstyle)
++{
++	icon_boxes *ib;
++
++	/* copy iconboxes ptr (if any) */
++	if (SHAS_ICON_BOXES(&pstyle->flags))
++	{
++		fw->IconBoxes = SGET_ICON_BOXES(*pstyle);
++		for (ib = fw->IconBoxes; ib; ib = ib->next)
++		{
++			ib->use_count++;
++		}
++	}
++	else
++	{
++		fw->IconBoxes = NULL;
++	}
++
++	return;
++}
++
++static void destroy_icon_boxes(FvwmWindow *fw)
++{
++	if (fw->IconBoxes)
++	{
++		fw->IconBoxes->use_count--;
++		if (fw->IconBoxes->use_count == 0 && fw->IconBoxes->is_orphan)
++		{
++			/* finally destroy the icon box */
++			free_icon_boxes(fw->IconBoxes);
++			fw->IconBoxes = NULL;
++		}
++	}
++
++	return;
++}
++
++static void setup_layer(FvwmWindow *fw, window_style *pstyle)
++{
++	FvwmWindow *tf;
++	int layer;
++
++	if (SUSE_LAYER(&pstyle->flags))
++	{
++		/* use layer from style */
++		layer = SGET_LAYER(*pstyle);
++	}
++	else if ((tf = get_transientfor_fvwmwindow(fw)) != NULL)
++	{
++		/* inherit layer from transientfor window */
++		layer = get_layer(tf);
++	}
++	else
++	{
++		/* use default layer */
++		layer = Scr.DefaultLayer;
++	}
++	set_default_layer(fw, layer);
++	set_layer(fw, layer);
++
++	return;
++}
++
++static void destroy_mini_icon(FvwmWindow *fw)
++{
++	if (fw->mini_icon)
++	{
++		PDestroyFvwmPicture(dpy, fw->mini_icon);
++		fw->mini_icon = 0;
++	}
++
++	return;
++}
++
++static void setup_key_and_button_grabs(FvwmWindow *fw)
++{
++#ifdef BUGS_ARE_COOL
++	/* dv (29-May-2001): If keys are grabbed separately for C_WINDOW and
++	 * the other contexts, new windows have problems when bindings are
++	 * removed.  Therefore, grab all keys in a single pass through the
++	 * list. */
++	GrabAllWindowKeys(
++		dpy, FW_W_FRAME(fw), Scr.AllBindings,
++		C_WINDOW|C_TITLE|C_RALL|C_LALL|C_SIDEBAR, GetUnusedModifiers(),
++		True);
++#endif
++	GrabAllWindowKeys(
++		dpy, FW_W_FRAME(fw), Scr.AllBindings,
++		C_TITLE|C_RALL|C_LALL|C_SIDEBAR|C_WINDOW, GetUnusedModifiers(),
++		True);
++	setup_focus_policy(fw);
++
++	return;
++}
++
++static void __add_window_handle_x_resources(FvwmWindow *fw)
++{
++	int client_argc = 0;
++	char **client_argv = NULL;
++	XrmValue rm_value;
++	XrmDatabase db = NULL;
++	static XrmOptionDescRec table [] = {
++		{"-xrn", NULL, XrmoptionResArg, (caddr_t) NULL},
++		{"-xrm", NULL, XrmoptionResArg, (caddr_t) NULL},
++	};
++	/* Get global X resources */
++	MergeXResources(dpy, &db, False);
++	/* Find out if the client requested a specific style on the command
++	 * line.
++	 */
++	if (XGetCommand(dpy, FW_W(fw), &client_argv, &client_argc))
++	{
++		if (client_argc > 0 && client_argv != NULL)
++		{
++			/* command line takes precedence over all */
++			MergeCmdLineResources(
++				&db, table, 2, fw->class.res_name,
++				&client_argc, client_argv, True);
++		}
++	}
++
++
++	/* parse the database values */
++	if (GetResourceString(db, "fvwmstyle", fw->class.res_name, &rm_value)
++	    && rm_value.size != 0)
++	{
++		char *style_name;
++		int name_len;
++		style_name = rm_value.addr;
++		name_len = rm_value.size-1;
++		/* Trim spaces at the start of the name */
++		while (name_len>0 && isspace(*style_name))
++		{
++			style_name++;
++			name_len--;
++		}
++		/* Trim spaces at the end of the name */
++		while (name_len>0 && isspace(*(style_name+name_len-1)))
++		{
++			name_len--;
++		}
++		if (name_len>0) {
++			fw->style_name = (char*)safemalloc(sizeof(char)*
++							   (name_len+1));
++			memcpy(fw->style_name,style_name,name_len);
++			fw->style_name[name_len] = 0;
++		}
++	}
++	XFreeStringList(client_argv);
++	XrmDestroyDatabase(db);
++	return;
++}
++
++/* ---------------------------- interface functions ------------------------ */
++
++void setup_visible_name(FvwmWindow *fw, Bool is_icon)
++{
++	char *ext_name;
++	char *name;
++	int count;
++	int len;
++
++	if (fw == NULL)
++	{
++		/* should never happen */
++		return;
++	}
++
++	if (is_icon)
++	{
++		if (fw->visible_icon_name != NULL &&
++		    fw->visible_icon_name != fw->icon_name.name &&
++		    fw->visible_icon_name != fw->name.name &&
++		    fw->visible_icon_name != NoName)
++		{
++			free(fw->visible_icon_name);
++			fw->visible_icon_name = NULL;
++		}
++		name = fw->icon_name.name;
++		setup_icon_name_count(fw);
++		count = fw->icon_name_count;
++	}
++	else
++	{
++		if (fw->visible_name != NULL &&
++		    fw->visible_name != fw->name.name &&
++		    fw->visible_name != NoName)
++		{
++			free(fw->visible_name);
++			fw->visible_name = NULL;
++		}
++		name = fw->name.name;
++		setup_window_name_count(fw);
++		count = fw->name_count;
++	}
++
++	if (name == NULL)
++	{
++		return; /* should never happen */
++	}
++
++	if (count > MAX_WINDOW_NAME_NUMBER - 1)
++	{
++		count = MAX_WINDOW_NAME_NUMBER - 1;
++	}
++
++	if (count != 0 &&
++	    ((is_icon && USE_INDEXED_ICON_NAME(fw)) ||
++	     (!is_icon && USE_INDEXED_WINDOW_NAME(fw))))
++	{
++		len = strlen(name);
++		count++;
++		ext_name = (char *)safemalloc(
++			len + MAX_WINDOW_NAME_NUMBER_DIGITS + 4);
++		sprintf(ext_name,"%s (%d)", name, count);
++	}
++	else
++	{
++		ext_name = name;
++	}
++
++	if (is_icon)
++	{
++		fw->visible_icon_name = ext_name;
++	}
++	else
++	{
++		fw->visible_name = ext_name;
++	}
++
++	return;
++}
++
++void setup_window_name(FvwmWindow *fw)
++{
++	if (!EWMH_WMName(fw, NULL, NULL, 0))
++	{
++		fw->name.name = NoName;
++		fw->name.name_list = NULL;
++		FlocaleGetNameProperty(XGetWMName, dpy, FW_W(fw), &(fw->name));
++	}
++
++	return;
++}
++
++void setup_wm_hints(FvwmWindow *fw)
++{
++	fw->wmhints = XGetWMHints(dpy, FW_W(fw));
++	set_focus_model(fw);
++
++	return;
++}
++
++void setup_title_geometry(
++	FvwmWindow *fw, window_style *pstyle)
++{
++	int width;
++	int offset;
++
++	get_title_font_size_and_offset(
++		fw, S_TITLE_DIR(SCF(*pstyle)),
++		S_IS_LEFT_TITLE_ROTATED_CW(SCF(*pstyle)),
++		S_IS_RIGHT_TITLE_ROTATED_CW(SCF(*pstyle)),
++		S_IS_TOP_TITLE_ROTATED(SCF(*pstyle)),
++		S_IS_BOTTOM_TITLE_ROTATED(SCF(*pstyle)),
++		&width, &offset);
++	fw->title_thickness = width;
++	fw->title_text_offset = offset;
++	fw->corner_width = fw->title_thickness + fw->boundary_width;
++	if (!HAS_TITLE(fw))
++	{
++		fw->title_thickness = 0;
++	}
++
++	return;
++}
++
++void setup_window_font(
++	FvwmWindow *fw, window_style *pstyle, Bool do_destroy)
++{
++	/* get rid of old font */
++	if (do_destroy)
++	{
++		destroy_window_font(fw);
++		/* destroy_window_font resets the IS_WINDOW_FONT_LOADED flag */
++	}
++	/* load new font */
++	if (!IS_WINDOW_FONT_LOADED(fw))
++	{
++		if (S_HAS_WINDOW_FONT(SCF(*pstyle)) &&
++		    SGET_WINDOW_FONT(*pstyle) &&
++		    (fw->title_font =
++		     FlocaleLoadFont(dpy, SGET_WINDOW_FONT(*pstyle), "FVWM")))
++		{
++			SET_USING_DEFAULT_WINDOW_FONT(fw, 0);
++		}
++		else
++		{
++			/* no explicit font or failed to load, use default font
++			 * instead */
++			fw->title_font = Scr.DefaultFont;
++			SET_USING_DEFAULT_WINDOW_FONT(fw, 1);
++		}
++		SET_WINDOW_FONT_LOADED(fw, 1);
++	}
++	setup_title_geometry(fw, pstyle);
++
++	return;
++}
++
++void setup_icon_font(
++	FvwmWindow *fw, window_style *pstyle, Bool do_destroy)
++{
++	int height = 0;
++
++	if (IS_ICON_SUPPRESSED(fw) || HAS_NO_ICON_TITLE(fw))
++	{
++		if (IS_ICON_FONT_LOADED(fw))
++		{
++			destroy_icon_font(fw);
++			/* destroy_icon_font resets the IS_ICON_FONT_LOADED
++			 * flag */
++		}
++		return;
++	}
++	/* get rid of old font */
++	if (do_destroy && IS_ICON_FONT_LOADED(fw))
++	{
++		destroy_icon_font(fw);
++		/* destroy_icon_font resets the IS_ICON_FONT_LOADED flag */
++	}
++	/* load new font */
++	if (!IS_ICON_FONT_LOADED(fw))
++	{
++		if (S_HAS_ICON_FONT(SCF(*pstyle)) && SGET_ICON_FONT(*pstyle) &&
++		    (fw->icon_font =
++		     FlocaleLoadFont(dpy, SGET_ICON_FONT(*pstyle), "FVWM")))
++		{
++			SET_USING_DEFAULT_ICON_FONT(fw, 0);
++		}
++		else
++		{
++			/* no explicit font or failed to load, use default font
++			 * instead */
++			fw->icon_font = Scr.DefaultFont;
++			SET_USING_DEFAULT_ICON_FONT(fw, 1);
++		}
++		SET_ICON_FONT_LOADED(fw, 1);
++	}
++	/* adjust y position of existing icons */
++	height = (IS_ICON_FONT_LOADED(fw)) ? fw->icon_font->height : 0;
++	if (height)
++	{
++		resize_icon_title_height(fw, height - fw->icon_font->height);
++		/* this repositions the icon even if the window is not
++		 * iconified */
++		DrawIconWindow(fw, True, True, False, False, NULL);
++	}
++
++	return;
++}
++
++void setup_style_and_decor(
++	FvwmWindow *fw, window_style *pstyle, short *buttons)
++{
++	/* first copy the static styles into the window struct */
++	memcpy(&(FW_COMMON_FLAGS(fw)), &(SCF(*pstyle)),
++	       sizeof(common_flags_t));
++	fw->wShaped = None;
++	if (FShapesSupported)
++	{
++		int i;
++		unsigned int u;
++		Bool b;
++		int boundingShaped;
++
++		/* suppress compiler warnings w/o shape extension */
++		i = 0;
++		u = 0;
++		b = False;
++
++		FShapeSelectInput(dpy, FW_W(fw), FShapeNotifyMask);
++		if (FShapeQueryExtents(
++			    dpy, FW_W(fw), &boundingShaped, &i, &i, &u, &u, &b,
++			    &i, &i, &u, &u))
++		{
++			fw->wShaped = boundingShaped;
++		}
++	}
++
++#ifdef USEDECOR
++	/* search for a UseDecor tag in the style */
++	if (!IS_DECOR_CHANGED(fw))
++	{
++		FvwmDecor *decor = &Scr.DefaultDecor;
++
++		for (; decor; decor = decor->next)
++		{
++			if (StrEquals(SGET_DECOR_NAME(*pstyle), decor->tag))
++			{
++				fw->decor = decor;
++				break;
++			}
++		}
++	}
++	if (fw->decor == NULL)
++	{
++		fw->decor = &Scr.DefaultDecor;
++	}
++#endif
++
++	GetMwmHints(fw);
++	GetOlHints(fw);
++
++	fw->buttons = SIS_BUTTON_DISABLED(&pstyle->flags);
++	SelectDecor(fw, pstyle, buttons);
++
++	if (IS_TRANSIENT(fw) && !pstyle->flags.do_decorate_transient)
++	{
++		SET_HAS_HANDLES(fw, 0);
++		SET_HAS_TITLE(fw, 0);
++	}
++	/* set boundary width to zero for shaped windows */
++	if (FHaveShapeExtension)
++	{
++		if (fw->wShaped)
++		{
++			set_window_border_size(fw, fw->unshaped_boundary_width);
++			SET_HAS_NO_BORDER(fw, 1);
++			SET_HAS_HANDLES(fw, 0);
++		}
++	}
++
++	/****** window colors ******/
++	update_window_color_style(fw, pstyle);
++	update_window_color_hi_style(fw, pstyle);
++
++	/***** icons colorsets *****/
++	update_icon_title_cs_style(fw, pstyle);
++	update_icon_title_cs_hi_style(fw, pstyle);
++	update_icon_background_cs_style(fw, pstyle);
++
++	/***** icons title/background parameters ****/
++	setup_icon_background_parameters(fw, pstyle);
++	setup_icon_title_parameters(fw, pstyle);
++
++	/****** window shading ******/
++	fw->shade_anim_steps = pstyle->shade_anim_steps;
++
++	/****** GNOME style hints ******/
++	if (!S_DO_IGNORE_GNOME_HINTS(SCF(*pstyle)))
++	{
++		GNOME_GetStyle(fw, pstyle);
++	}
++
++	/* ConfigureNotify motion method */
++	if (SCR_MOTION_METHOD(&pstyle->flag_mask))
++	{
++		CR_MOTION_METHOD(fw) = SCR_MOTION_METHOD(&pstyle->flags);
++	}
++
++	return;
++}
++
++void change_icon_boxes(FvwmWindow *fw, window_style *pstyle)
++{
++	destroy_icon_boxes(fw);
++	setup_icon_boxes(fw, pstyle);
++
++	return;
++}
++
++void setup_frame_size_limits(FvwmWindow *fw, window_style *pstyle)
++{
++	if (SHAS_MAX_WINDOW_SIZE(&pstyle->flags))
++	{
++		fw->max_window_width = SGET_MAX_WINDOW_WIDTH(*pstyle);
++		fw->max_window_height = SGET_MAX_WINDOW_HEIGHT(*pstyle);
++	}
++	else
++	{
++		fw->max_window_width = DEFAULT_MAX_MAX_WINDOW_WIDTH;
++		fw->max_window_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
++	}
++
++	return;
++}
++
++void setup_placement_penalty(FvwmWindow *fw, window_style *pstyle)
++{
++	int i;
++
++	if (!SHAS_PLACEMENT_PENALTY(&pstyle->flags))
++	{
++		SSET_NORMAL_PLACEMENT_PENALTY(*pstyle, 1);
++		SSET_ONTOP_PLACEMENT_PENALTY(*pstyle, PLACEMENT_AVOID_ONTOP);
++		SSET_ICON_PLACEMENT_PENALTY(*pstyle, PLACEMENT_AVOID_ICON);
++		SSET_STICKY_PLACEMENT_PENALTY(*pstyle, PLACEMENT_AVOID_STICKY);
++		SSET_BELOW_PLACEMENT_PENALTY(*pstyle, PLACEMENT_AVOID_BELOW);
++		SSET_EWMH_STRUT_PLACEMENT_PENALTY(
++			*pstyle, PLACEMENT_AVOID_EWMH_STRUT);
++	}
++	if (!SHAS_PLACEMENT_PERCENTAGE_PENALTY(&pstyle->flags))
++	{
++		SSET_99_PLACEMENT_PERCENTAGE_PENALTY(
++			*pstyle, PLACEMENT_AVOID_COVER_99);
++		SSET_95_PLACEMENT_PERCENTAGE_PENALTY(
++			*pstyle, PLACEMENT_AVOID_COVER_95);
++		SSET_85_PLACEMENT_PERCENTAGE_PENALTY(
++			*pstyle, PLACEMENT_AVOID_COVER_85);
++		SSET_75_PLACEMENT_PERCENTAGE_PENALTY(
++			*pstyle, PLACEMENT_AVOID_COVER_75);
++	}
++	for (i = 0; i < 6; i++)
++	{
++		fw->placement_penalty[i] = (*pstyle).placement_penalty[i];
++	}
++	for (i = 0; i < 4; i++)
++	{
++		fw->placement_percentage_penalty[i] =
++			(*pstyle).placement_percentage_penalty[i];
++	}
++
++	return;
++}
++
++void setup_frame_attributes(
++	FvwmWindow *fw, window_style *pstyle)
++{
++	XSetWindowAttributes xswa;
++
++	/* Backing_store is controlled on the client, borders, title & buttons
++	 */
++	switch (pstyle->flags.use_backing_store)
++	{
++	case BACKINGSTORE_DEFAULT:
++		xswa.backing_store = fw->attr_backup.backing_store;
++		break;
++	case BACKINGSTORE_ON:
++		xswa.backing_store = Scr.use_backing_store;
++		break;
++	case BACKINGSTORE_OFF:
++	default:
++		xswa.backing_store = NotUseful;
++		break;
++	}
++	/* parent_relative is applied to the frame and the parent */
++	xswa.background_pixmap = pstyle->flags.use_parent_relative
++		? ParentRelative : None;
++	/* Save_under is only useful on the frame */
++	xswa.save_under = pstyle->flags.do_save_under
++		? Scr.flags.do_save_under : NotUseful;
++	XChangeWindowAttributes(dpy, FW_W(fw), CWBackingStore, &xswa);
++	XChangeWindowAttributes(
++		dpy, FW_W_PARENT(fw), CWBackPixmap | CWBackingStore, &xswa);
++	XChangeWindowAttributes(
++		dpy, FW_W_FRAME(fw),
++		CWBackPixmap | CWBackingStore | CWSaveUnder, &xswa);
++
++	return;
++}
++
++void change_auxiliary_windows(FvwmWindow *fw, short buttons)
++{
++	unsigned long valuemask_save = 0;
++	XSetWindowAttributes attributes;
++
++	get_default_window_attributes(fw, &valuemask_save, &attributes);
++	change_title_window(fw, valuemask_save, &attributes);
++	change_button_windows(fw, valuemask_save, &attributes, buttons);
++	change_resize_handle_windows(fw);
++	setup_frame_stacking(fw);
++	XMapSubwindows (dpy, FW_W_FRAME(fw));
++
++	return;
++}
++
++void increase_icon_hint_count(FvwmWindow *fw)
++{
++	if (fw->wmhints &&
++	    (fw->wmhints->flags & (IconWindowHint | IconPixmapHint)))
++	{
++		switch (WAS_ICON_HINT_PROVIDED(fw))
++		{
++		case ICON_HINT_NEVER:
++			SET_WAS_ICON_HINT_PROVIDED(fw, ICON_HINT_ONCE);
++			break;
++		case ICON_HINT_ONCE:
++			SET_WAS_ICON_HINT_PROVIDED(fw, ICON_HINT_MULTIPLE);
++			break;
++		case ICON_HINT_MULTIPLE:
++		default:
++			break;
++		}
++		ICON_DBG((stderr,"icon hint count++ (%d) '%s'\n",
++			  (int)WAS_ICON_HINT_PROVIDED(fw), fw->name.name));
++	}
++
++	return;
++}
++
++void change_icon(FvwmWindow *fw, window_style *pstyle)
++{
++	destroy_icon(fw);
++	setup_icon(fw, pstyle);
++
++	return;
++}
++
++void change_mini_icon(FvwmWindow *fw, window_style *pstyle)
++{
++	FvwmPicture *old_mi = fw->mini_icon;
++	destroy_mini_icon(fw);
++	setup_mini_icon(fw, pstyle);
++	broadcast_mini_icon(fw);
++	if (old_mi != NULL && fw->mini_icon == 0)
++	{
++		/* this case is not handled in setup_mini_icon, so we must
++		 * broadcast here explicitly */
++		BroadcastFvwmPicture(
++			M_MINI_ICON, FW_W(fw), FW_W_FRAME(fw),
++			(unsigned long)fw, NULL, "");
++	}
++
++	return;
++}
++
++void setup_focus_policy(FvwmWindow *fw)
++{
++	focus_grab_buttons(fw);
++
++	return;
++}
++
++Bool validate_transientfor(FvwmWindow *fw)
++{
++	XWindowAttributes wa;
++	FvwmWindow *cw;
++	Window w;
++
++	w = FW_W_TRANSIENTFOR(fw);
++	if (w == None || w == FW_W(fw) || w == IS_EWMH_DESKTOP(w))
++	{
++		FW_W_TRANSIENTFOR(fw) = Scr.Root;
++		return False;
++	}
++	else if (XFindContext(dpy, w, FvwmContext, (caddr_t *)&cw) != XCNOENT)
++	{
++		if (cw == fw)
++		{
++			/* It's a transient of itself, ignore the hint */
++			FW_W_TRANSIENTFOR(fw) = Scr.Root;
++			return False;
++		}
++	}
++	else if (!XGetWindowAttributes(dpy, w, &wa) ||
++		 wa.map_state != IsViewable)
++	{
++		/* transientfor does not exist or is not viewable or unmapped */
++		FW_W_TRANSIENTFOR(fw) = Scr.Root;
++		return False;
++	}
++
++	return True;
++}
++
++Bool setup_transientfor(FvwmWindow *fw)
++{
++	Bool rc;
++
++	rc = XGetTransientForHint(dpy, FW_W(fw), &FW_W_TRANSIENTFOR(fw));
++	SET_TRANSIENT(fw, rc);
++	if (rc == False)
++	{
++		FW_W_TRANSIENTFOR(fw) = Scr.Root;
++	}
++	validate_transientfor(fw);
++
++	return rc;
++}
++
++/*
++ *
++ *  Procedure:
++ *      AddWindow - add a new window to the fvwm list
++ *
++ */
++FvwmWindow *AddWindow(
++	const exec_context_t *exc, FvwmWindow *ReuseWin,
++	initial_window_options_t * win_opts)
++{
++	/* new fvwm window structure */
++	register FvwmWindow *fw;
++	FvwmWindow *tmp;
++	/* mask for create windows */
++	unsigned long valuemask;
++	/* attributes for create windows */
++	XSetWindowAttributes attributes;
++	XWindowAttributes wattr;
++	/* area for merged styles */
++	window_style style;
++	/* used for faster access */
++	style_flags *sflags;
++	short buttons;
++	Bool used_sm = False;
++	Bool do_resize_too = False;
++	size_borders b;
++	frame_move_resize_args mr_args;
++	mwtsm_state_args state_args;
++	Window w = exc->w.w;
++	const exec_context_t *exc2;
++	exec_context_changes_t ecc;
++
++	/****** init window structure ******/
++	setup_window_structure(&tmp, w, ReuseWin);
++	fw = tmp;
++
++	/****** Make sure the client window still exists.  We don't want to
++	 * leave an orphan frame window if it doesn't.  Since we now have the
++	 * server grabbed, the window can't disappear later without having been
++	 * reparented, so we'll get a DestroyNotify for it.  We won't have
++	 * gotten one for anything up to here, however. ******/
++	MyXGrabServer(dpy);
++	if (XGetGeometry(
++		    dpy, w, &JunkRoot, &JunkX, &JunkY,
++		    (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
++		    (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth) == 0)
++	{
++		if (Scr.bo.do_display_new_window_names)
++		{
++			fvwm_msg(INFO, "AddWindow", "new window disappeared");
++		}
++		free(fw);
++		MyXUngrabServer(dpy);
++		return NULL;
++	}
++
++	/****** window name ******/
++	setup_window_name(fw);
++	setup_class_and_resource(fw);
++
++	/****** style setup ******/
++	__add_window_handle_x_resources(fw);
++	/* get merged styles */
++	lookup_style(fw, &style);
++	sflags = SGET_FLAGS_POINTER(style);
++	if (SIS_UNMANAGED(sflags))
++	{
++		if (Scr.bo.do_display_new_window_names)
++		{
++			fvwm_msg(
++				INFO, "AddWindow", "new window is unmanaged:\n"
++				"  name:      %s\n"
++				"  icon name: (unknown)\n"
++				"  resource:  %s\n"
++				"  class:     %s",
++				fw->name.name, fw->class.res_name,
++				fw->class.res_class);
++		}
++		free_window_names(fw, True, True);
++		if (fw->style_name)
++		{
++			free(fw->style_name);
++		}
++		free(fw);
++		MyXUngrabServer(dpy);
++		return AW_UNMANAGED;
++	}
++
++	/****** window attributes and hints ******/
++	setup_window_attr(fw, &wattr);
++	setup_wm_hints(fw);
++
++	/****** basic style and decor ******/
++	/* If the window is in the NoTitle list, or is a transient, dont
++	 * decorate it.  If its a transient, and DecorateTransients was
++	 * specified, decorate anyway. */
++	setup_transientfor(fw);
++	if (win_opts->flags.is_menu)
++	{
++		SET_TEAR_OFF_MENU(fw, 1);
++	}
++	fw->decor = NULL;
++	setup_style_and_decor(fw, &style, &buttons);
++
++	/****** fonts ******/
++	setup_window_font(fw, &style, False);
++	setup_icon_font(fw, &style, False);
++
++	/***** visible window name ****/
++	setup_visible_name(fw, False);
++	EWMH_SetVisibleName(fw, False);
++	if (Scr.bo.do_display_new_window_names)
++	{
++		fvwm_msg(
++			INFO, "AddWindow", "new window:\n"
++			"  name:      %s\n"
++			"  icon name: %s\n"
++			"  resource:  %s\n"
++			"  class:     %s",
++			fw->name.name, (fw->icon_name.name == NULL) ?
++			"(unknown)" : fw->icon_name.name, fw->class.res_name,
++			fw->class.res_class);
++	}
++
++	/****** state setup ******/
++	setup_icon_boxes(fw, &style);
++	SET_ICONIFIED(fw, 0);
++	SET_ICON_UNMAPPED(fw, 0);
++	SET_MAXIMIZED(fw, 0);
++	/*
++	 * Reparenting generates an UnmapNotify event, followed by a MapNotify.
++	 * Set the map state to 0 to prevent a transition back to
++	 * WithdrawnState in HandleUnmapNotify.  Map state gets set corrected
++	 * again in HandleMapNotify.
++	 */
++	SET_MAPPED(fw, 0);
++
++	/****** window list and stack ring ******/
++	/* add the window to the end of the fvwm list */
++	fw->next = Scr.FvwmRoot.next;
++	fw->prev = &Scr.FvwmRoot;
++	while (fw->next != NULL)
++	{
++		fw->prev = fw->next;
++		fw->next = fw->next->next;
++	}
++	/* fw->prev points to the last window in the list, fw->next is
++	 * NULL. Now fix the last window to point to fw */
++	fw->prev->next = fw;
++	/*
++	 * RBW - 11/13/1998 - add it into the stacking order chain also.
++	 * This chain is anchored at both ends on Scr.FvwmRoot, there are
++	 * no null pointers.
++	 */
++	add_window_to_stack_ring_after(fw, &Scr.FvwmRoot);
++
++	/****** calculate frame size ******/
++	fw->hints.win_gravity = NorthWestGravity;
++	GetWindowSizeHints(fw);
++
++	/****** border width ******/
++	XSetWindowBorderWidth(dpy, FW_W(fw), 0);
++
++	/****** icon size limits ******/
++	setup_icon_size_limits(fw, &style);
++
++	/***** placement penalities *****/
++	setup_placement_penalty(fw, &style);
++	/*
++	 * MatchWinToSM changes fw->attr and the stacking order.
++	 * Thus it is important have this call *after* PlaceWindow and the
++	 * stacking order initialization.
++	 */
++	get_window_borders(fw, &b);
++	memset(&state_args, 0, sizeof(state_args));
++	used_sm = MatchWinToSM(fw, &state_args, win_opts);
++	if (used_sm)
++	{
++		/* read the requested absolute geometry */
++		gravity_translate_to_northwest_geometry_no_bw(
++			fw->hints.win_gravity, fw, &fw->g.normal,
++			&fw->g.normal);
++		gravity_resize(
++			fw->hints.win_gravity, &fw->g.normal,
++			b.total_size.width, b.total_size.height);
++		fw->g.frame = fw->g.normal;
++		fw->g.frame.x -= Scr.Vx;
++		fw->g.frame.y -= Scr.Vy;
++
++		/****** calculate frame size ******/
++		setup_frame_size_limits(fw, &style);
++		constrain_size(
++			fw, NULL, &fw->g.frame.width,
++			&fw->g.frame.height, 0, 0, 0);
++
++		/****** maximize ******/
++		if (state_args.do_max)
++		{
++			SET_MAXIMIZED(fw, 1);
++			constrain_size(
++				fw, NULL, &fw->g.max.width, &fw->g.max.height,
++				0, 0, CS_UPDATE_MAX_DEFECT);
++			get_relative_geometry(&fw->g.frame, &fw->g.max);
++		}
++		else
++		{
++			get_relative_geometry(&fw->g.frame, &fw->g.normal);
++		}
++	}
++	else
++	{
++		rectangle attr_g;
++
++		if (IS_SHADED(fw))
++		{
++			state_args.do_shade = 1;
++			state_args.used_title_dir_for_shading =
++				USED_TITLE_DIR_FOR_SHADING(fw);
++			state_args.shade_dir = SHADED_DIR(fw);
++			SET_SHADED(fw, 0);
++		}
++		/* Tentative size estimate */
++		fw->g.frame.width = wattr.width + b.total_size.width;
++		fw->g.frame.height = wattr.height + b.total_size.height;
++
++		/****** calculate frame size ******/
++		setup_frame_size_limits(fw, &style);
++
++		/****** layer ******/
++		setup_layer(fw, &style);
++
++		/****** window placement ******/
++		attr_g.x = wattr.x;
++		attr_g.y = wattr.y;
++		attr_g.width = wattr.width;
++		attr_g.height = wattr.height;
++		do_resize_too = setup_window_placement(
++			fw, &style, &attr_g, win_opts, PLACE_INITIAL);
++		wattr.x = attr_g.x;
++		wattr.y = attr_g.y;
++
++		/* set up geometry */
++		fw->g.frame.x = wattr.x;
++		fw->g.frame.y = wattr.y;
++		fw->g.frame.width = wattr.width + b.total_size.width;
++		fw->g.frame.height = wattr.height + b.total_size.height;
++		gravity_constrain_size(
++			fw->hints.win_gravity, fw, &fw->g.frame, 0);
++		update_absolute_geometry(fw);
++	}
++
++	/****** auxiliary window setup ******/
++	setup_auxiliary_windows(fw, True, buttons);
++
++	/****** 'backing store' and 'save under' window setup ******/
++	setup_frame_attributes(fw, &style);
++
++	/****** reparent the window ******/
++	XReparentWindow(dpy, FW_W(fw), FW_W_PARENT(fw), 0, 0);
++
++	/****** select events ******/
++	valuemask = CWEventMask | CWDontPropagate;
++	if (IS_TEAR_OFF_MENU(fw))
++	{
++		attributes.event_mask = XEVMASK_TEAR_OFF_MENUW;
++	}
++	else
++	{
++		attributes.event_mask = XEVMASK_CLIENTW;
++	}
++	attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
++	XChangeWindowAttributes(dpy, FW_W(fw), valuemask, &attributes);
++	/****** make sure the window is not destroyed when fvwm dies ******/
++	if (!IS_TEAR_OFF_MENU(fw))
++	{
++		/* menus were created by fvwm itself, don't add them to the
++		 * save set */
++		XAddToSaveSet(dpy, FW_W(fw));
++	}
++
++	/****** now we can sefely ungrab the server ******/
++	MyXUngrabServer(dpy);
++
++	/* need to set up the mini icon before drawing */
++	if (FMiniIconsSupported)
++	{
++		setup_mini_icon(fw, &style);
++	}
++
++	/****** arrange the frame ******/
++
++	if (is_resizing_event_pending(fw) == True)
++	{
++		SET_FORCE_NEXT_CR(fw, 1);
++		SET_FORCE_NEXT_PN(fw, 1);
++		mr_args = frame_create_move_resize_args(
++			fw, FRAME_MR_FORCE_SETUP_NO_W | FRAME_MR_DONT_DRAW,
++			NULL, &fw->g.frame, 0, DIR_NONE);
++	}
++	else
++	{
++		mr_args = frame_create_move_resize_args(
++			fw, FRAME_MR_FORCE_SETUP | FRAME_MR_DONT_DRAW, NULL,
++			&fw->g.frame, 0, DIR_NONE);
++	}
++	frame_move_resize(fw, mr_args);
++	frame_free_move_resize_args(fw, mr_args);
++	/* draw later */
++	SET_WAS_NEVER_DRAWN(fw, 1);
++
++	/****** grab keys and buttons ******/
++	setup_key_and_button_grabs(fw);
++
++	/****** inform modules of new window ******/
++	BroadcastConfig(M_ADD_WINDOW,fw);
++	BroadcastWindowIconNames(fw, True, False);
++
++	/****** place the window in the stack ring ******/
++	if (!position_new_window_in_stack_ring(fw, SDO_START_LOWERED(sflags)))
++	{
++		XWindowChanges xwc;
++		xwc.sibling = FW_W_FRAME(get_next_window_in_stack_ring(fw));
++		xwc.stack_mode = Above;
++		XConfigureWindow(
++			dpy, FW_W_FRAME(fw), CWSibling|CWStackMode, &xwc);
++	}
++
++	/* these are sent and broadcast before res_{class,name} for the benefit
++	 * of FvwmIconBox which can't handle M_ICON_FILE after M_RES_NAME */
++	/****** icon and mini icon ******/
++	/* migo (20-Jan-2000): the logic is to unset this flag on NULL values */
++	SET_WAS_ICON_NAME_PROVIDED(fw, 1);
++	setup_icon(fw, &style);
++	if (FMiniIconsSupported)
++	{
++		broadcast_mini_icon(fw);
++	}
++	BroadcastName(M_RES_CLASS,FW_W(fw),FW_W_FRAME(fw),
++		      (unsigned long)fw,fw->class.res_class);
++	BroadcastName(M_RES_NAME,FW_W(fw),FW_W_FRAME(fw),
++		      (unsigned long)fw,fw->class.res_name);
++
++	/****** stick window ******/
++	if (!(fw->hints.flags & USPosition) || used_sm)
++	{
++		int stick_page;
++		int stick_desk;
++
++		stick_page = is_window_sticky_across_pages(fw);
++		stick_desk = is_window_sticky_across_desks(fw);
++		if ((stick_page &&
++		     !IsRectangleOnThisPage(&fw->g.frame, Scr.CurrentDesk)) ||
++		    (stick_desk && fw->Desk != Scr.CurrentDesk))
++		{
++			/* If it's sticky and the user didn't ask for an
++			 * explicit position, force it on screen now.  Don't do
++			 * that with USPosition because we have to assume the
++			 * user knows what (s)he is doing.  This is necessary
++			 * e.g. if we want a sticky 'panel' in FvwmButtons but
++			 * don't want to see when it's mapped in the void. */
++			ecc.w.fw = fw;
++			ecc.w.w = FW_W_FRAME(fw);
++			ecc.w.wcontext = C_FRAME;
++			exc2 = exc_clone_context(
++				exc, &ecc, ECC_FW | ECC_W | ECC_WCONTEXT);
++			SET_STICKY_ACROSS_PAGES(fw, 0);
++			SET_STICKY_ACROSS_DESKS(fw, 0);
++			handle_stick(
++				NULL, exc2, "", stick_page, stick_desk, 1, 0);
++			exc_destroy_context(exc2);
++		}
++	}
++
++	/****** resize window ******/
++	if (do_resize_too)
++	{
++		XEvent e;
++
++		memset(&e, 0, sizeof(e));
++		FWarpPointer(
++			dpy, Scr.Root, Scr.Root, 0, 0, Scr.MyDisplayWidth,
++			Scr.MyDisplayHeight,
++			fw->g.frame.x + (fw->g.frame.width>>1),
++			fw->g.frame.y + (fw->g.frame.height>>1));
++		e.xany.type = ButtonPress;
++		e.xbutton.button = 1;
++		e.xbutton.state = Button1Mask;
++		e.xbutton.x_root = fw->g.frame.x + (fw->g.frame.width>>1);
++		e.xbutton.y_root = fw->g.frame.y + (fw->g.frame.height>>1);
++		e.xbutton.x = (fw->g.frame.width>>1);
++		e.xbutton.y = (fw->g.frame.height>>1);
++		e.xbutton.subwindow = None;
++		e.xany.window = FW_W(fw);
++		fev_fake_event(&e);
++		ecc.x.etrigger = &e;
++		ecc.w.fw = fw;
++		ecc.w.wcontext = C_WINDOW;
++		exc2 = exc_clone_context(
++			exc, &ecc, ECC_ETRIGGER | ECC_FW | ECC_WCONTEXT);
++		CMD_Resize(NULL, exc2, "");
++		exc_destroy_context(exc2);
++	}
++
++	/****** window colormap ******/
++	ReInstallActiveColormap();
++
++	/****** ewmh setup *******/
++	EWMH_WindowInit(fw);
++
++	/****** gnome setup ******/
++	/* set GNOME hints on the window from flags set on fw */
++	GNOME_SetHints(fw);
++	GNOME_SetLayer(fw);
++	GNOME_SetDesk(fw);
++	GNOME_SetWinArea(fw);
++
++	/****** windowshade ******/
++	if (state_args.do_shade)
++	{
++		rectangle big_g;
++		rectangle new_g;
++		frame_move_resize_args mr_args;
++
++		if (state_args.used_title_dir_for_shading)
++		{
++			state_args.shade_dir = GET_TITLE_DIR(fw);
++		}
++		big_g = (IS_MAXIMIZED(fw)) ? fw->g.max : fw->g.frame;
++		new_g = big_g;
++		get_shaded_geometry_with_dir(
++			fw, &new_g, &new_g, state_args.shade_dir);
++		mr_args = frame_create_move_resize_args(
++			fw, FRAME_MR_SHRINK | FRAME_MR_DONT_DRAW, &big_g,
++			&new_g, 0, state_args.shade_dir);
++		frame_move_resize(fw, mr_args);
++		SET_SHADED(fw, 1);
++		SET_SHADED_DIR(fw, state_args.shade_dir);
++		frame_free_move_resize_args(fw, mr_args);
++	}
++	if (!IS_SHADED(fw) && !IS_ICONIFIED(fw))
++	{
++		/* TK always wants some special treatment: If the window is
++		 * simply mapped, the tk menus come up at funny Y coordinates.
++		 * Tell it it's geometry *again* to work around this problem. */
++		SendConfigureNotify(
++			fw, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width,
++			fw->g.frame.height, 0, False);
++	}
++	if (HAS_EWMH_INIT_MAXVERT_STATE(fw) == EWMH_STATE_HAS_HINT ||
++	    HAS_EWMH_INIT_MAXHORIZ_STATE(fw) == EWMH_STATE_HAS_HINT)
++	{
++		int h;
++		int v;
++		char cmd[256];
++
++		if (is_function_allowed(F_MAXIMIZE, NULL, fw, True, False))
++		{
++			h = (HAS_EWMH_INIT_MAXHORIZ_STATE(fw) ==
++			     EWMH_STATE_HAS_HINT) ? 100 : 0;
++			v = (HAS_EWMH_INIT_MAXVERT_STATE(fw) ==
++			     EWMH_STATE_HAS_HINT) ? 100 : 0;
++			sprintf(cmd,"Maximize on %i %i", h, v);
++			execute_function_override_window(
++				NULL, NULL, cmd, 0, fw);
++		}
++	}
++	if (HAS_EWMH_INIT_FULLSCREEN_STATE(fw) == EWMH_STATE_HAS_HINT)
++	{
++		EWMH_fullscreen(fw);
++	}
++	if (!XGetGeometry(
++		    dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
++		    (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
++		    (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth))
++	{
++		/* The window has disappeared somehow.  For some reason we do
++		 * not always get a DestroyNotify on the window, so make sure
++		 * it is destroyed. */
++		destroy_window(fw);
++		fw = NULL;
++	}
++
++	return fw;
++}
++
++
++/*
++ *
++ *  Procedure:
++ *      FetchWMProtocols - finds out which protocols the window supports
++ *
++ *  Inputs:
++ *      tmp - the fvwm window structure to use
++ *
++ */
++void FetchWmProtocols(FvwmWindow *tmp)
++{
++	Atom *protocols = NULL, *ap;
++	unsigned long *l_protocols;
++	int i, n;
++	Atom atype;
++	int aformat;
++	unsigned long bytes_remain,nitems;
++
++	if (tmp == NULL)
++	{
++		return;
++	}
++	/* First, try the Xlib function to read the protocols.
++	 * This is what Twm uses. */
++	if (XGetWMProtocols (dpy, FW_W(tmp), &protocols, &n))
++	{
++		for (i = 0, ap = protocols; i < n; i++, ap++)
++		{
++			if (*ap == (Atom)_XA_WM_TAKE_FOCUS)
++			{
++				SET_WM_TAKES_FOCUS(tmp, 1);
++				set_focus_model(tmp);
++			}
++			if (*ap == (Atom)_XA_WM_DELETE_WINDOW)
++			{
++				SET_WM_DELETES_WINDOW(tmp, 1);
++			}
++		}
++		if (protocols)
++		{
++			XFree((char *)protocols);
++		}
++	}
++	else
++	{
++		/* Next, read it the hard way. mosaic from Coreldraw needs to
++		 * be read in this way. */
++		if ((XGetWindowProperty(
++			     dpy, FW_W(tmp), _XA_WM_PROTOCOLS, 0L, 10L, False,
++			     _XA_WM_PROTOCOLS, &atype, &aformat, &nitems,
++			     &bytes_remain,
++			     (unsigned char **)&l_protocols)) == Success)
++		{
++			for (i = 0; i < nitems; i++)
++			{
++				ap = &(l_protocols[i]);
++				if (*ap == (Atom)_XA_WM_TAKE_FOCUS)
++				{
++					SET_WM_TAKES_FOCUS(tmp, 1);
++					set_focus_model(tmp);
++				}
++				if (*ap == (Atom)_XA_WM_DELETE_WINDOW)
++				{
++					SET_WM_DELETES_WINDOW(tmp, 1);
++				}
++			}
++			if (protocols)
++			{
++				XFree((char *)protocols);
++			}
++		}
++	}
++
++	return;
++}
++
++
++
++/*
++ *
++ *  Procedure:
++ *      GetWindowSizeHints - gets application supplied size info
++ *
++ *  Inputs:
++ *      tmp - the fvwm window structure to use
++ *
++ */
++
++void GetWindowSizeHints(FvwmWindow *fw)
++{
++	long supplied = 0;
++	char *broken_cause ="";
++	XSizeHints orig_hints;
++	Status rc;
++
++	fw->orig_hints.width_inc = 1;
++	fw->orig_hints.height_inc = 1;
++	rc = XGetWMNormalHints(dpy, FW_W(fw), &orig_hints, &supplied);
++	if (rc == 0)
++	{
++		fw->hints.flags = 0;
++		memset(&orig_hints, 0, sizeof(orig_hints));
++	}
++	else
++	{
++		fw->hints = orig_hints;
++		if (fw->hints.flags & PResizeInc)
++		{
++			fw->orig_hints.width_inc = fw->hints.width_inc;
++			fw->orig_hints.height_inc = fw->hints.height_inc;
++		}
++		if (HAS_OVERRIDE_SIZE_HINTS(fw))
++		{
++			/* ignore the WMNormal hints */
++			fw->hints.flags &= ~(PMinSize | PMaxSize | PResizeInc);
++			fw->hints.min_width = 0;
++			fw->hints.min_height = 0;
++			fw->hints.max_width = 0;
++			fw->hints.max_height = 0;
++			fw->hints.width_inc = 1;
++			fw->hints.height_inc = 1;
++		}
++	}
++
++	/* Beat up our copy of the hints, so that all important field are
++	 * filled in! */
++	if (fw->hints.flags & PResizeInc)
++	{
++		SET_SIZE_INC_SET(fw, 1);
++		if (fw->hints.width_inc <= 0)
++		{
++			if (fw->hints.width_inc < 0 ||
++			    (fw->hints.width_inc == 0 &&
++			     (fw->hints.flags & PMinSize) &&
++			     (fw->hints.flags & PMaxSize) &&
++			     fw->hints.min_width != fw->hints.max_width))
++			{
++				broken_cause = "width_inc";
++			}
++			fw->hints.width_inc = 1;
++			SET_SIZE_INC_SET(fw, 0);
++		}
++		if (fw->hints.height_inc <= 0)
++		{
++			if (fw->hints.height_inc < 0 ||
++			    (fw->hints.height_inc == 0 &&
++			     (fw->hints.flags & PMinSize) &&
++			     (fw->hints.flags & PMaxSize) &&
++			     fw->hints.min_height != fw->hints.max_height))
++			{
++				if (!*broken_cause)
++				{
++					broken_cause = "height_inc";
++				}
++			}
++			fw->hints.height_inc = 1;
++			SET_SIZE_INC_SET(fw, 0);
++		}
++	}
++	else
++	{
++		SET_SIZE_INC_SET(fw, 0);
++		fw->hints.width_inc = 1;
++		fw->hints.height_inc = 1;
++	}
++
++	if (fw->hints.flags & PMinSize)
++	{
++		if (fw->hints.min_width < 0 && !*broken_cause)
++		{
++			broken_cause = "min_width";
++		}
++		if (fw->hints.min_height < 0 && !*broken_cause)
++		{
++			broken_cause = "min_height";
++		}
++	}
++	else
++	{
++		if (fw->hints.flags & PBaseSize)
++		{
++			fw->hints.min_width = fw->hints.base_width;
++			fw->hints.min_height = fw->hints.base_height;
++		}
++		else
++		{
++			fw->hints.min_width = 1;
++			fw->hints.min_height = 1;
++		}
++	}
++	if (fw->hints.min_width <= 0)
++	{
++		fw->hints.min_width = 1;
++	}
++	if (fw->hints.min_height <= 0)
++	{
++		fw->hints.min_height = 1;
++	}
++
++	if (fw->hints.flags & PMaxSize)
++	{
++		if (fw->hints.max_width < fw->hints.min_width)
++		{
++			fw->hints.max_width = DEFAULT_MAX_MAX_WINDOW_WIDTH;
++			if (!*broken_cause)
++			{
++				broken_cause = "max_width";
++			}
++		}
++		if (fw->hints.max_height < fw->hints.min_height)
++		{
++			fw->hints.max_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
++			if (!*broken_cause)
++			{
++				broken_cause = "max_height";
++			}
++		}
++	}
++	else
++	{
++		fw->hints.max_width = DEFAULT_MAX_MAX_WINDOW_WIDTH;
++		fw->hints.max_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
++	}
++
++	/*
++	 * ICCCM says that PMinSize is the default if no PBaseSize is given,
++	 * and vice-versa.
++	 */
++
++	if (fw->hints.flags & PBaseSize)
++	{
++		if (fw->hints.base_width < 0)
++		{
++			fw->hints.base_width = 0;
++			if (!*broken_cause)
++			{
++				broken_cause = "base_width";
++			}
++		}
++		if (fw->hints.base_height < 0)
++		{
++			fw->hints.base_height = 0;
++			if (!*broken_cause)
++			{
++				broken_cause = "base_height";
++			}
++		}
++		if ((fw->hints.base_width > fw->hints.min_width) ||
++		    (fw->hints.base_height > fw->hints.min_height))
++		{
++			/* In this case, doing the aspect ratio calculation
++			   for window_size - base_size as prescribed by the
++			   ICCCM is going to fail.
++			   Resetting the flag disables the use of base_size
++			   in aspect ratio calculation while it is still used
++			   for grid sizing.
++			*/
++			fw->hints.flags &= ~PBaseSize;
++#if 0
++			/* Keep silent about this, since the Xlib manual
++			 * actually recommends making min <= base <= max ! */
++			broken_cause = "";
++#endif
++		}
++	}
++	else
++	{
++		if (fw->hints.flags & PMinSize)
++		{
++			fw->hints.base_width = fw->hints.min_width;
++			fw->hints.base_height = fw->hints.min_height;
++		}
++		else
++		{
++			fw->hints.base_width = 0;
++			fw->hints.base_height = 0;
++		}
++	}
++
++	if (!(fw->hints.flags & PWinGravity))
++	{
++		fw->hints.win_gravity = NorthWestGravity;
++	}
++
++	if ((fw->hints.flags & PMaxSize) &&
++	    ((fw->hints.flags & PMinSize) || (fw->hints.flags & PBaseSize)))
++	{
++		if (fw->hints.max_width < fw->hints.base_width)
++		{
++			fw->hints.max_width = DEFAULT_MAX_MAX_WINDOW_WIDTH;
++			if (!*broken_cause)
++			{
++				broken_cause = "max_width";
++			}
++		}
++		if (fw->hints.max_height < fw->hints.base_height)
++		{
++			fw->hints.max_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
++			if (!*broken_cause)
++			{
++				broken_cause = "max_height";
++			}
++		}
++	}
++
++	if (fw->hints.flags & PAspect)
++	{
++		/*
++		** check to make sure min/max aspect ratios look valid
++		*/
++#define maxAspectX fw->hints.max_aspect.x
++#define maxAspectY fw->hints.max_aspect.y
++#define minAspectX fw->hints.min_aspect.x
++#define minAspectY fw->hints.min_aspect.y
++
++
++		/*
++		** The math looks like this:
++		**
++		**   minAspectX    maxAspectX
++		**   ---------- <= ----------
++		**   minAspectY    maxAspectY
++		**
++		** If that is multiplied out, this must be satisfied:
++		**
++		**   minAspectX * maxAspectY <=  maxAspectX * minAspectY
++		**
++		** So, what to do if this isn't met?  Ignoring it entirely
++		** seems safest.
++		**
++		*/
++
++		/* We also ignore people who put negative entries into
++		 * their aspect ratios. They deserve it.
++		 *
++		 * We cast to double here, since the values may be large.
++		 */
++		if ((maxAspectX < 0) || (maxAspectY < 0) ||
++		    (minAspectX < 0) || (minAspectY < 0) ||
++		    (((double)minAspectX * (double)maxAspectY) >
++		     ((double)maxAspectX * (double)minAspectY)))
++		{
++			if (!*broken_cause)
++			{
++				broken_cause = "aspect ratio";
++			}
++			fw->hints.flags &= ~PAspect;
++			fvwm_msg(
++				WARN, "GetWindowSizeHints",
++				"The applicaton window (window id %#lx)\n"
++				"  \"%s\" has broken aspect ratio: "
++				"%d/%d - %d/%d\n"
++				"    fvwm is ignoring this aspect ratio.  ",
++				FW_W(fw), fw->name.name, minAspectX,
++				minAspectY, maxAspectX, maxAspectY);
++			fvwm_msg_report_app();
++		}
++		else
++		{
++			/* protect against overflow */
++			if ((maxAspectX > 65536) || (maxAspectY > 65536))
++			{
++				double ratio =
++					(double) maxAspectX /
++					(double) maxAspectY;
++				if (ratio > 1.0)
++				{
++					maxAspectX = 65536;
++					maxAspectY = 65536 / ratio;
++				}
++				else
++				{
++					maxAspectX = 65536 * ratio;
++					maxAspectY = 65536;
++				}
++			}
++			if ((minAspectX > 65536) || (minAspectY > 65536))
++			{
++				double ratio =
++					(double) minAspectX /
++					(double) minAspectY;
++				if (ratio > 1.0)
++				{
++					minAspectX = 65536;
++					minAspectY = 65536 / ratio;
++				}
++				else
++				{
++					minAspectX = 65536 * ratio;
++					minAspectY = 65536;
++				}
++			}
++		}
++	}
++
++	if (*broken_cause != 0)
++	{
++		fvwm_msg(
++			WARN, "GetWindowSizeHints",
++			"The application window (id %#lx)\n"
++			"  \"%s\" has broken size hints (%s).\n"
++			"    fvwm is ignoring those hints.  "
++			"  hint override = %d, flags = %lx\n"
++			"  min_width = %d, min_height = %d, "
++			"max_width = %d, max_height = %d\n"
++			"  width_inc = %d, height_inc = %d\n"
++			"  min_aspect = %d/%d, max_aspect = %d/%d\n"
++			"  base_width = %d, base_height = %d\n"
++			"  win_gravity = %d\n",
++			FW_W(fw), fw->name.name, broken_cause,
++			HAS_OVERRIDE_SIZE_HINTS(fw),
++			orig_hints.flags,
++			orig_hints.min_width, orig_hints.min_height,
++			orig_hints.max_width, orig_hints.max_height,
++			orig_hints.width_inc, orig_hints.height_inc,
++			orig_hints.min_aspect.x, orig_hints.min_aspect.y,
++			orig_hints.max_aspect.x, orig_hints.max_aspect.y,
++			orig_hints.base_width, orig_hints.base_height,
++			orig_hints.win_gravity);
++		fvwm_msg_report_app();
++	}
++
++	return;
++}
++
++/*
++ *
++ * Releases dynamically allocated space used to store window/icon names
++ *
++ */
++void free_window_names(FvwmWindow *fw, Bool nukename, Bool nukeicon)
++{
++	if (!fw)
++	{
++		return;
++	}
++
++	if (nukename)
++	{
++		if (fw->visible_name && fw->visible_name != fw->name.name &&
++		    fw->visible_name != NoName)
++		{
++			free(fw->visible_name);
++		}
++		fw->visible_name = NoName;
++		if (fw->name.name)
++		{
++			if (fw->icon_name.name == fw->name.name)
++			{
++				fw->icon_name.name = NoName;
++			}
++			if (fw->visible_icon_name == fw->name.name)
++			{
++				fw->visible_icon_name = fw->icon_name.name;
++			}
++			if (fw->name.name != NoName)
++			{
++				FlocaleFreeNameProperty(&(fw->name));
++				fw->visible_name = NULL;
++			}
++		}
++	}
++	if (nukeicon)
++	{
++		if (fw->visible_icon_name &&
++		    fw->visible_icon_name != fw->name.name &&
++		    fw->visible_icon_name != fw->icon_name.name &&
++		    fw->visible_icon_name != NoName)
++		{
++			free(fw->visible_icon_name);
++		}
++		fw->visible_icon_name = NoName;
++		if (fw->icon_name.name)
++		{
++			if ((fw->icon_name.name != fw->name.name) &&
++			    fw->icon_name.name != NoName)
++			{
++				FlocaleFreeNameProperty(&(fw->icon_name));
++				fw->visible_icon_name = NULL;
++			}
++		}
++	}
++
++	return;
++}
++
++
++
++/*
++ *
++ * Handles destruction of a window
++ *
++ */
++void destroy_window(FvwmWindow *fw)
++{
++	/* Warning, this is also called by HandleUnmapNotify; if it ever needs
++	 * to look at the event, HandleUnmapNotify will have to mash the
++	 * UnmapNotify into a DestroyNotify. */
++	if (!fw)
++	{
++		return;
++	}
++
++	/* remove window style */
++	if (!IS_SCHEDULED_FOR_DESTROY(fw) && !DO_REUSE_DESTROYED(fw))
++	{
++		style_id_t s_id;
++
++		memset(&s_id, 0, sizeof(style_id_t));
++		SID_SET_WINDOW_ID(s_id, (XID)FW_W(fw));
++		SID_SET_HAS_WINDOW_ID(s_id, True);
++
++		style_destroy_style(s_id);
++	}
++
++	/****** remove from window list ******/
++	/* if the window is sheduled fro destroy the window has been already
++	 * removed from list */
++	if (!IS_SCHEDULED_FOR_DESTROY(fw))
++	{
++		/* first, remove the window from the list of all windows! */
++		if (fw->prev != NULL)
++		{
++			fw->prev->next = fw->next;
++		}
++		if (fw->next != NULL)
++		{
++			fw->next->prev = fw->prev;
++		}
++		fw->next = NULL;
++		fw->prev = NULL;
++
++		/****** also remove it from the stack ring ******/
++
++		/*
++		 * RBW - 11/13/1998 - new: have to unhook the stacking order
++		 chain also. There's always a prev and next, since this is a
++		 ring anchored on Scr.FvwmRoot
++		*/
++		remove_window_from_stack_ring(fw);
++	}
++
++	/****** check if we have to delay window destruction ******/
++
++	if ((Scr.flags.is_executing_complex_function ||
++	     Scr.flags.is_executing_menu_function) &&
++	    !DO_REUSE_DESTROYED(fw))
++	{
++		if (IS_SCHEDULED_FOR_DESTROY(fw))
++		{
++			return;
++		}
++		/* mark window for destruction */
++		SET_SCHEDULED_FOR_DESTROY(fw, 1);
++		Scr.flags.is_window_scheduled_for_destroy = 1;
++		/* this is necessary in case the application destroys the
++		 * client window and a new window is created with the same
++		 * window id */
++		delete_client_context(fw);
++		XFlush(dpy);
++		/* unmap the the window to fake that it was already removed */
++		if (IS_ICONIFIED(fw))
++		{
++			if (FW_W_ICON_TITLE(fw))
++			{
++				XUnmapWindow(dpy, FW_W_ICON_TITLE(fw));
++			}
++			if (FW_W_ICON_PIXMAP(fw) != None)
++			{
++				XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw));
++			}
++		}
++		else
++		{
++			XUnmapWindow(dpy, FW_W_FRAME(fw));
++		}
++		adjust_fvwm_internal_windows(fw);
++		BroadcastPacket(
++			M_DESTROY_WINDOW, 3, (long)FW_W(fw),
++			(long)FW_W_FRAME(fw), (unsigned long)fw);
++		EWMH_DestroyWindow(fw);
++		focus_grab_buttons_on_layer(fw->layer);
++		Scr.FWScheduledForDestroy = flist_append_obj(
++			Scr.FWScheduledForDestroy, fw);
++		return;
++	}
++
++	/****** unmap the frame ******/
++
++	XUnmapWindow(dpy, FW_W_FRAME(fw));
++	XFlush(dpy);
++	/* already done above? */
++	if (!IS_SCHEDULED_FOR_DESTROY(fw))
++	{
++		SET_SCHEDULED_FOR_DESTROY(fw, 1);
++		adjust_fvwm_internal_windows(fw);
++		BroadcastPacket(
++			M_DESTROY_WINDOW, 3, (long)FW_W(fw),
++			(long)FW_W_FRAME(fw), (unsigned long)fw);
++		EWMH_DestroyWindow(fw);
++	}
++	focus_grab_buttons_on_layer(fw->layer);
++
++	/****** destroy auxiliary windows ******/
++
++	destroy_auxiliary_windows(fw, True);
++
++	/****** destroy icon ******/
++
++	destroy_icon_boxes(fw);
++	destroy_icon(fw);
++
++	/****** destroy mini icon ******/
++
++#ifdef MINI_ICON
++	destroy_mini_icon(fw);
++#endif
++
++	/****** free strings ******/
++
++	free_window_names(fw, True, True);
++
++	if (fw->style_name)
++	{
++		free(fw->style_name);
++		fw->style_name = NULL;
++	}
++	if (fw->class.res_name && fw->class.res_name != NoResource)
++	{
++		XFree ((char *)fw->class.res_name);
++		fw->class.res_name = NoResource;
++	}
++	if (fw->class.res_class && fw->class.res_class != NoClass)
++	{
++		XFree ((char *)fw->class.res_class);
++		fw->class.res_class = NoClass;
++	}
++	if (fw->mwm_hints)
++	{
++		XFree((char *)fw->mwm_hints);
++		fw->mwm_hints = NULL;
++	}
++
++	/****** free fonts ******/
++
++	destroy_window_font(fw);
++	destroy_icon_font(fw);
++
++	/****** free wmhints ******/
++
++	if (fw->wmhints)
++	{
++		XFree ((char *)fw->wmhints);
++		fw->wmhints = NULL;
++	}
++
++	/****** free colormap windows ******/
++
++	if (fw->cmap_windows != (Window *)NULL)
++	{
++		XFree((void *)fw->cmap_windows);
++		fw->cmap_windows = NULL;
++	}
++
++	/****** throw away the structure ******/
++
++	/*  Recapture reuses this struct, so don't free it.  */
++	if (!DO_REUSE_DESTROYED(fw))
++	{
++		free((char *)fw);
++	}
++
++	/****** cleanup ******/
++
++	XFlush(dpy);
++
++	return;
++}
++
++
++/*
++ *
++ *  Procedure:
++ *      RestoreWithdrawnLocation
++ *
++ *  Puts windows back where they were before fvwm took over
++ *
++ */
++void RestoreWithdrawnLocation(
++	FvwmWindow *fw, Bool is_restart_or_recapture, Window parent)
++{
++	int w2,h2;
++	unsigned int mask;
++	XWindowChanges xwc;
++	rectangle naked_g;
++	rectangle unshaded_g;
++	XSetWindowAttributes xswa;
++
++	if (!fw)
++	{
++		return;
++	}
++
++	/* always get the latest size hints in case the application changed
++	 * the gravity and we do not yet know about it */
++	XSync(dpy, 0);
++	GetWindowSizeHints(fw);
++	SET_HAS_NEW_WM_NORMAL_HINTS(fw, 0);
++	get_unshaded_geometry(fw, &unshaded_g);
++	gravity_get_naked_geometry(
++		fw->hints.win_gravity, fw, &naked_g, &unshaded_g);
++	gravity_translate_to_northwest_geometry(
++		fw->hints.win_gravity, fw, &naked_g, &naked_g);
++	xwc.x = naked_g.x;
++	xwc.y = naked_g.y;
++	xwc.width = naked_g.width;
++	xwc.height = naked_g.height;
++	xwc.border_width = fw->attr_backup.border_width;
++	mask = (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
++
++	/* We can not assume that the window is currently on the screen.
++	 * Although this is normally the case, it is not always true.  The
++	 * most common example is when the user does something in an
++	 * application which will, after some amount of computational delay,
++	 * cause the window to be unmapped, but then switches screens before
++	 * this happens.  The XTranslateCoordinates call above will set the
++	 * window coordinates to either be larger than the screen, or negative.
++	 * This will result in the window being placed in odd, or even
++	 * unviewable locations when the window is remapped.  The following
++	 * code forces the "relative" location to be within the bounds of the
++	 * display.
++	 *
++	 * gpw -- 11/11/93
++	 *
++	 * Unfortunately, this does horrendous things during re-starts,
++	 * hence the "if (restart)" clause (RN)
++	 *
++	 * Also, fixed so that it only does this stuff if a window is more than
++	 * half off the screen. (RN)
++	 */
++
++	if (!is_restart_or_recapture)
++	{
++		/* Don't mess with it if its partially on the screen now */
++		if (unshaded_g.x < 0 || unshaded_g.y < 0 ||
++		    unshaded_g.x >= Scr.MyDisplayWidth ||
++		    unshaded_g.y >= Scr.MyDisplayHeight)
++		{
++			w2 = (unshaded_g.width >> 1);
++			h2 = (unshaded_g.height >> 1);
++			if ( xwc.x < -w2 || xwc.x > Scr.MyDisplayWidth - w2)
++			{
++				xwc.x = xwc.x % Scr.MyDisplayWidth;
++				if (xwc.x < -w2)
++				{
++					xwc.x += Scr.MyDisplayWidth;
++				}
++			}
++			if (xwc.y < -h2 || xwc.y > Scr.MyDisplayHeight - h2)
++			{
++				xwc.y = xwc.y % Scr.MyDisplayHeight;
++				if (xwc.y < -h2)
++				{
++					xwc.y += Scr.MyDisplayHeight;
++				}
++			}
++		}
++	}
++
++	/* restore initial backing store setting on window */
++	xswa.backing_store = fw->attr_backup.backing_store;
++	XChangeWindowAttributes(dpy, FW_W(fw), CWBackingStore, &xswa);
++	/* reparent to root window */
++	XReparentWindow(
++		dpy, FW_W(fw), (parent == None) ? Scr.Root : parent, xwc.x,
++		xwc.y);
++
++	if (IS_ICONIFIED(fw) && !IS_ICON_SUPPRESSED(fw))
++	{
++		if (FW_W_ICON_TITLE(fw))
++		{
++			XUnmapWindow(dpy, FW_W_ICON_TITLE(fw));
++		}
++		if (FW_W_ICON_PIXMAP(fw))
++		{
++			XUnmapWindow(dpy, FW_W_ICON_PIXMAP(fw));
++		}
++	}
++
++	XConfigureWindow(dpy, FW_W(fw), mask, &xwc);
++	if (!is_restart_or_recapture)
++	{
++		/* must be initial capture */
++		XFlush(dpy);
++	}
++
++	return;
++}
++
++
++/*
++ *
++ *  Procedure:
++ *      Reborder - Removes fvwm border windows
++ *
++ */
++void Reborder(void)
++{
++	FvwmWindow *fw;
++
++	/* put a border back around all windows */
++	MyXGrabServer (dpy);
++
++	/* force reinstall */
++	InstallWindowColormaps (&Scr.FvwmRoot);
++
++	/* RBW - 05/15/1998
++	 * Grab the last window and work backwards: preserve stacking order on
++	 * restart. */
++	for (fw = get_prev_window_in_stack_ring(&Scr.FvwmRoot);
++	     fw != &Scr.FvwmRoot; fw = get_prev_window_in_stack_ring(fw))
++	{
++		if (!IS_ICONIFIED(fw) && Scr.CurrentDesk != fw->Desk)
++		{
++			XMapWindow(dpy, FW_W(fw));
++			SetMapStateProp(fw, NormalState);
++		}
++		RestoreWithdrawnLocation (fw, True, Scr.Root);
++		XUnmapWindow(dpy,FW_W_FRAME(fw));
++		XDestroyWindow(dpy,FW_W_FRAME(fw));
++	}
++
++	MyXUngrabServer (dpy);
++	FOCUS_RESET();
++	XFlush(dpy);
++
++	return;
++}
++
++void CaptureAllWindows(const exec_context_t *exc, Bool is_recapture)
++{
++	int i,j;
++	unsigned int nchildren;
++	Window root, parent, *children;
++	initial_window_options_t win_opts;
++	FvwmWindow *fw;
++
++	MyXGrabServer(dpy);
++	if (!XQueryTree(dpy, Scr.Root, &root, &parent, &children, &nchildren))
++	{
++		MyXUngrabServer(dpy);
++		return;
++	}
++	memset(&win_opts, 0, sizeof(win_opts));
++	win_opts.flags.do_override_ppos = 1;
++	win_opts.flags.is_recapture = 1;
++	if (!(Scr.flags.are_windows_captured)) /* initial capture? */
++	{
++		evh_args_t ea;
++		exec_context_changes_t ecc;
++		XEvent e;
++
++		/* weed out icon windows */
++		for (i = 0; i < nchildren; i++)
++		{
++			if (children[i])
++			{
++				XWMHints *wmhintsp = XGetWMHints(
++					dpy, children[i]);
++
++				if (wmhintsp &&
++				    wmhintsp->flags & IconWindowHint)
++				{
++					for (j = 0; j < nchildren; j++)
++					{
++						if (children[j] ==
++						    wmhintsp->icon_window)
++						{
++							children[j] = None;
++							break;
++						}
++					}
++				}
++				if (wmhintsp)
++				{
++					XFree ((char *) wmhintsp);
++				}
++			}
++		}
++		/* map all of the non-override, non-icon windows */
++		e.type = MapRequest;
++		ecc.x.etrigger = &e;
++		for (i = 0; i < nchildren; i++)
++		{
++
++			if (children[i] &&
++			    MappedNotOverride(children[i], &win_opts))
++			{
++				XUnmapWindow(dpy, children[i]);
++				e.xmaprequest.window = children[i];
++				e.xmaprequest.parent = Scr.Root;
++				ecc.w.fw = NULL;
++				ecc.w.w = children[i];
++				ecc.w.wcontext = C_ROOT;
++				ea.exc = exc_clone_context(
++					exc, &ecc, ECC_ETRIGGER | ECC_FW |
++					ECC_W | ECC_WCONTEXT);
++				HandleMapRequestKeepRaised(
++					&ea, None, NULL, &win_opts);
++				exc_destroy_context(ea.exc);
++			}
++		}
++		Scr.flags.are_windows_captured = 1;
++	}
++	else /* must be recapture */
++	{
++		Window keep_on_top_win;
++		Window parent_win;
++		Window focus_w;
++		FvwmWindow *t;
++
++		t = get_focus_window();
++		focus_w = (t) ? FW_W(t) : None;
++		hide_screen(True, &keep_on_top_win, &parent_win);
++		/* reborder all windows */
++		for (i=0;i<nchildren;i++)
++		{
++			if (XFindContext(
++				    dpy, children[i], FvwmContext,
++				    (caddr_t *)&fw) != XCNOENT)
++			{
++				CaptureOneWindow(
++					exc, fw, children[i], keep_on_top_win,
++					parent_win, is_recapture);
++			}
++		}
++		hide_screen(False, NULL, NULL);
++		/* find the window that had the focus and focus it again */
++		if (focus_w)
++		{
++			for (t = Scr.FvwmRoot.next; t && FW_W(t) != focus_w;
++			     t = t->next)
++			{
++				;
++			}
++			if (t)
++			{
++				SetFocusWindow(t, True, FOCUS_SET_FORCE);
++			}
++		}
++	}
++	if (nchildren > 0)
++	{
++		XFree((char *)children);
++	}
++	MyXUngrabServer(dpy);
++
++	return;
++}
++
++/* ---------------------------- builtin commands --------------------------- */
++
++void CMD_Recapture(F_CMD_ARGS)
++{
++	do_recapture(F_PASS_ARGS, False);
++
++	return;
++}
++
++void CMD_RecaptureWindow(F_CMD_ARGS)
++{
++	do_recapture(F_PASS_ARGS, True);
++
++	return;
++}
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/borders.c fvwm-2.5.21-06/fvwm/borders.c
+--- fvwm-2.5.21-05/fvwm/borders.c	2007-03-03 13:18:49.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/borders.c	2007-03-03 13:19:10.000000000 +0100
+@@ -3516,31 +3516,32 @@ static void border_draw_title_stick_line
+ 				SWAP_ARGS(td->has_vt, right_w, 1),
+ 				tdd->sgc, tdd->rgc, 1, False, rotation);
+ 		}
+ 	}
+ 
+ 	return;
+ }
+ 
+ static void border_draw_title_mono(
+ 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
+-	FlocaleWinString *fstr, Pixmap dest_pix)
++	FlocaleWinString *fstr, Pixmap dest_pix, Bool do_hilight)
+ {
+ 	int has_vt;
+ 
+ 	has_vt = HAS_VERTICAL_TITLE(fw);
+ 	XFillRectangle(
+ 		dpy, dest_pix, td->cd->relief_gc,
+ 		td->offset - 2, 0, td->length+4, fw->title_thickness);
+ 	if (fw->visible_name != (char *)NULL)
+ 	{
+-		FlocaleDrawString(dpy, fw->title_font, fstr, 0);
++		FlocaleDrawString(dpy, do_hilight ? fw->title_font :
++			fw->inactive_title_font, fstr, 0);
+ 	}
+ 	/* for mono, we clear an area in the title bar where the window
+ 	 * title goes, so that its more legible. For color, no need */
+ 	do_relieve_rectangle(
+ 		dpy, dest_pix, 0, 0,
+ 		SWAP_ARGS(has_vt, td->offset - 3,
+ 			  fw->title_thickness - 1),
+ 		tdd->rgc, tdd->sgc, td->cd->relief_width, False);
+ 	do_relieve_rectangle(
+ 		dpy, dest_pix,
+@@ -3590,21 +3591,21 @@ static void border_draw_title_relief(
+ 	default:
+ 		/* flat */
+ 		break;
+ 	}
+ 
+ 	return;
+ }
+ 
+ static void border_draw_title_deep(
+ 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
+-	FlocaleWinString *fstr, Pixmap dest_pix, Window w)
++	FlocaleWinString *fstr, Pixmap dest_pix, Window w, Bool do_hilight)
+ {
+ 	DecorFace *df;
+ 	pixmap_background_type bg;
+ 
+ 	bg.flags.use_pixmap = 0;
+ 	for (df = tdd->df; df != NULL; df = df->next)
+ 	{
+ 		if (df->style.face_type == MultiPixmap)
+ 		{
+ 			border_mp_draw_mp_titlebar(
+@@ -3612,44 +3613,46 @@ static void border_draw_title_deep(
+ 		}
+ 		else
+ 		{
+ 			bg.pixel = df->u.back;
+ 			border_draw_decor_to_pixmap(
+ 				fw, dest_pix, w, &bg, &td->layout.title_g, df,
+ 				td, td->tbstate.tstate, True, tdd->is_toggled,
+ 				1);
+ 		}
+ 	}
+-	FlocaleDrawString(dpy, fw->title_font, &tdd->fstr, 0);
++	FlocaleDrawString(dpy, do_hilight ? fw->title_font :
++		fw->inactive_title_font, &tdd->fstr, 0);
+ 
+ 	return;
+ }
+ 
+ static void border_get_titlebar_draw_descr(
+ 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
+-	Pixmap dest_pix)
++	Pixmap dest_pix, Bool do_hilight)
+ {
+ 	rectangle *title_g;
+ 
+ 	memset(tdd, 0, sizeof(*tdd));
+ 	/* prepare the gcs and variables */
+ 	if (td->tbstate.is_title_pressed)
+ 	{
+ 		tdd->rgc = td->cd->shadow_gc;
+ 		tdd->sgc = td->cd->relief_gc;
+ 	}
+ 	else
+ 	{
+ 		tdd->rgc = td->cd->relief_gc;
+ 		tdd->sgc = td->cd->shadow_gc;
+ 	}
+-	NewFontAndColor(fw->title_font, td->cd->fore_color, td->cd->back_color);
++	NewFontAndColor(do_hilight ? fw->title_font : fw->inactive_title_font,
++		td->cd->fore_color, td->cd->back_color);
+ 	title_g = &td->layout.title_g;
+ 	tdd->tstyle = &TB_STATE(
+ 		GetDecor(fw, titlebar))[td->tbstate.tstate].style;
+ 	tdd->df = &TB_STATE(GetDecor(fw, titlebar))[td->tbstate.tstate];
+ 
+ 	/* fetch the title string */
+ 	tdd->fstr.str = fw->visible_name;
+ 	tdd->fstr.win = dest_pix;
+ 	if (td->td_is_rotated)
+ 	{
+@@ -3673,29 +3676,29 @@ static void border_get_titlebar_draw_des
+ 	{
+ 		tdd->fstr.colorset = &Colorset[td->cd->cs];
+ 		tdd->fstr.flags.has_colorset = 1;
+ 	}
+ 	tdd->fstr.gc = Scr.TitleGC;
+ 
+ 	return;
+ }
+ 
+ static void border_set_title_pixmap(
+-	FvwmWindow *fw, titlebar_descr *td, Pixmap *dest_pix, Window w)
++	FvwmWindow *fw, titlebar_descr *td, Pixmap *dest_pix, Window w, Bool do_hilight)
+ {
+ 	pixmap_background_type bg;
+ 	title_draw_descr tdd;
+ 	FlocaleWinString fstr;
+ 	Bool free_bg_pixmap = False;
+ 	rectangle pix_g;
+ 
+-	border_get_titlebar_draw_descr(fw, td, &tdd, *dest_pix);
++	border_get_titlebar_draw_descr(fw, td, &tdd, *dest_pix, do_hilight);
+ 	/* prepare background, either from the window colour or from the
+ 	 * border style */
+ 	if (!DFS_USE_BORDER_STYLE(*tdd.tstyle))
+ 	{
+ 		/* fill with the button background colour */
+ 		bg.flags.use_pixmap = 0;
+ 		bg.pixel = td->cd->back_color;
+ 		pix_g.x = 0;
+ 		pix_g.y = 0;
+ 		pix_g.width = td->layout.title_g.width;
+@@ -3749,52 +3752,52 @@ static void border_set_title_pixmap(
+ 				td->layout.title_g.height,
+ 				Pdepth, Scr.BordersGC, td->draw_rotation);
+ 			XFreePixmap(dpy, *dest_pix);
+ 			*dest_pix = tmp;
+ 			border_rotate_titlebar_descr(fw, td);
+ 		}
+ 	}
+ 
+ 	if (Pdepth < 2)
+ 	{
+-		border_draw_title_mono(fw, td, &tdd, &fstr, *dest_pix);
++		border_draw_title_mono(fw, td, &tdd, &fstr, *dest_pix, do_hilight);
+ 	}
+ 	else
+ 	{
+-		border_draw_title_deep(fw, td, &tdd, &fstr, *dest_pix, w);
++		border_draw_title_deep(fw, td, &tdd, &fstr, *dest_pix, w, do_hilight);
+ 	}
+ 	border_draw_title_relief(fw, td, &tdd, *dest_pix);
+ 	border_draw_title_stick_lines(fw, td, &tdd, *dest_pix);
+ 
+ 	return;
+ }
+ 
+ static void border_draw_title(
+-	FvwmWindow *fw, titlebar_descr *td)
++	FvwmWindow *fw, titlebar_descr *td, Bool do_hilight)
+ {
+ 	Pixmap p;
+ 
+ 	if (td->layout.title_g.x < 0 || td->layout.title_g.y < 0)
+ 	{
+ 		return;
+ 	}
+ 	if (td->draw_rotation != ROTATION_0)
+ 	{
+ 		border_rotate_titlebar_descr(fw, td);
+ 	}
+ 	/* make a pixmap */
+ 	p = border_create_decor_pixmap(td->cd, &(td->layout.title_g));
+ 	/* set the background tile */
+ #if 0
+ 	fprintf(stderr,"drawing title\n");
+ #endif
+-	border_set_title_pixmap(fw, td, &p, FW_W_TITLE(fw));
++	border_set_title_pixmap(fw, td, &p, FW_W_TITLE(fw), do_hilight);
+ 	if (td->draw_rotation != ROTATION_0)
+ 	{
+ 		Pixmap tmp;
+ 
+ 		tmp = CreateRotatedPixmap(
+ 			dpy, p, td->layout.title_g.width,
+ 			td->layout.title_g.height, Pdepth, Scr.BordersGC,
+ 			td->draw_rotation);
+ 		XFreePixmap(dpy, p);
+ 		p = tmp;
+@@ -4269,23 +4272,23 @@ static window_parts border_get_titlebar_
+ 		fw, pressed_parts, pressed_button, clear_parts, do_hilight,
+ 		&(ret_td->tbstate));
+ 
+ 	/* get the title string length and position
+ 	 * This is not in "tdd" (titlebar_draw_descr), because these are needed
+ 	 * to draw the buttons with UseTitleStyle */
+ 	just = TB_JUSTIFICATION(GetDecor(fw, titlebar));
+ 	if (fw->visible_name != (char *)NULL)
+ 	{
+ 		ret_td->length = FlocaleTextWidth(
+-			fw->title_font, fw->visible_name,
+-			(ret_td->has_vt) ? -strlen(fw->visible_name) :
+-			strlen(fw->visible_name));
++			do_hilight ? fw->title_font : fw->inactive_title_font,
++			fw->visible_name, (ret_td->has_vt) ?
++			-strlen(fw->visible_name) : strlen(fw->visible_name));
+ 		if (ret_td->length > fw->title_length -
+ 		    2*MIN_WINDOW_TITLE_TEXT_OFFSET)
+ 		{
+ 			ret_td->length = fw->title_length -
+ 				2*MIN_WINDOW_TITLE_TEXT_OFFSET;
+ 			just = JUST_CENTER;
+ 		}
+ 		if (ret_td->length < 0)
+ 		{
+ 			ret_td->length = 0;
+@@ -4377,21 +4380,21 @@ static void border_draw_titlebar(
+ 		cd, fw, pressed_parts, pressed_button, force_draw_parts,
+ 		clear_parts, old_g, new_g, do_hilight, &td);
+ 	if ((draw_parts & PART_TITLE) != PART_NONE ||
+ 	    (draw_parts & PART_BUTTONS) != PART_NONE)
+ 	{
+ 		/* set up UseTitleStyle Colorset */
+ 		border_setup_use_title_style(fw, &td);
+ 	}
+ 	if ((draw_parts & PART_TITLE) != PART_NONE)
+ 	{
+-		border_draw_title(fw, &td);
++		border_draw_title(fw, &td, do_hilight);
+ 	}
+ 	if ((draw_parts & PART_BUTTONS) != PART_NONE)
+ 	{
+ 		border_draw_buttons(fw, &td);
+ 	}
+ 	border_free_bar_pixmaps(&(td.cd->dynamic_cd));
+ 
+ 	/* update the decor states */
+ 	fw->decor_state.parts_drawn |= draw_parts;
+ 	if (do_hilight)
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/borders.c~ fvwm-2.5.21-06/fvwm/borders.c~
+--- fvwm-2.5.21-05/fvwm/borders.c~	2007-03-03 13:18:42.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/borders.c~	2007-03-03 13:19:02.000000000 +0100
+@@ -4590,20 +4590,21 @@ int border_context_to_parts(
+ 	}
+ 
+ 	return PART_NONE;
+ }
+ 
+ void border_get_part_geometry(
+ 	FvwmWindow *fw, window_parts part, rectangle *sidebar_g,
+ 	rectangle *ret_g, Window *ret_w)
+ {
+ 	int bw;
++	Bool title;
+ 
+ 	bw = fw->boundary_width;
+ 	/* ret_g->x and ret->y is just an offset relatively to the w,
+ 	 * maybe we can take the relief in account? */
+ 	switch (part)
+ 	{
+ 	case PART_BORDER_N:
+ 		ret_g->x = sidebar_g->x;
+ 		ret_g->y = 0;
+ 		*ret_w = FW_W_SIDE(fw, 0);
+@@ -4660,21 +4661,46 @@ void border_get_part_geometry(
+ 		ret_g->height = sidebar_g->height;
+ 		break;
+ 	case PART_BORDER_NW:
+ 	case PART_BORDER_NE:
+ 	case PART_BORDER_SW:
+ 	case PART_BORDER_SE:
+ 		ret_g->width = sidebar_g->x;
+ 		ret_g->height = sidebar_g->y;
+ 		break;
+ 	default:
+-		return;
++		break;
++	}
++
++	if (HAS_BORDER_UNDER_TITLE(fw))
++	{
++		title = False;
++		switch (GET_TITLE_DIR(fw))
++		{
++		case DIR_N: title = part & PART_TOP; break;
++		case DIR_E: title = part & PART_RIGHT; break;
++		case DIR_S: title = part & PART_BOTTOM; break;
++		case DIR_W: title = part & PART_LEFT; break;
++		}
++		if (title)
++		{
++			ret_g->width = max(ret_g->width, 2 * bw + fw->title_thickness);
++			ret_g->height = max(ret_g->height, 2 * bw + fw->title_thickness);
++			if (part & PART_RIGHT)
++			{
++				ret_g->x = 2 * sidebar_g->x + sidebar_g->width - ret_g->width;
++			}
++			if (part & PART_BOTTOM)
++			{
++				ret_g->y = 2 * sidebar_g->y + sidebar_g->height - ret_g->height;
++			}
++		}
+ 	}
+ 
+ 	return;
+ }
+ 
+ int get_button_number(int context)
+ {
+ 	int i;
+ 
+ 	for (i = 0; (C_L1 << i) & (C_LALL | C_RALL); i++)
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/fvwm.h fvwm-2.5.21-06/fvwm/fvwm.h
+--- fvwm-2.5.21-05/fvwm/fvwm.h	2007-03-03 13:18:49.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/fvwm.h	2007-03-03 13:19:10.000000000 +0100
+@@ -191,20 +191,21 @@ typedef struct
+ } ewmh_strut;
+ 
+ typedef struct
+ {
+ 	/* common flags (former flags in bits 0-12) */
+ 	unsigned is_sticky_across_pages : 1;
+ 	unsigned is_sticky_across_desks : 1;
+ 	unsigned has_icon_font : 1;
+ 	unsigned has_no_border : 1;
+ 	unsigned has_window_font : 1;
++	unsigned has_inactive_window_font : 1;
+ 	unsigned title_dir : 2;
+ 	unsigned user_states : 32;
+ 	/* static flags that do not change dynamically after the window has
+ 	 * been created */
+ 	struct
+ 	{
+ 		unsigned do_circulate_skip : 1;
+ 		unsigned do_circulate_skip_icon : 1;
+ 		unsigned do_circulate_skip_shaded : 1;
+ 		unsigned do_ewmh_donate_icon : 1;
+@@ -354,25 +355,27 @@ typedef struct
+ 	unsigned is_style_deleted : 1;
+ 	/* the window is a torn out fvwm menu */
+ 	unsigned is_tear_off_menu : 1;
+ 	/* is it a transient window? */
+ 	unsigned is_transient : 1;
+ 	unsigned is_window_drawn_once : 1;
+ 	/* To prevent double move in MoveViewport.*/
+ 	unsigned is_viewport_moved : 1;
+ 	unsigned is_window_being_moved_opaque : 1;
+ 	unsigned is_window_font_loaded : 1;
++	unsigned is_inactive_window_font_loaded : 1;
+ 	unsigned is_window_shaded : 1;
+ 	unsigned used_title_dir_for_shading : 1;
+ 	unsigned shaded_dir : 3;
+ 	unsigned using_default_icon_font : 1;
+ 	unsigned using_default_window_font : 1;
++	unsigned using_default_inactive_window_font : 1;
+ #define ICON_HINT_NEVER    0
+ #define ICON_HINT_ONCE     1
+ #define ICON_HINT_MULTIPLE 2
+ 	unsigned was_icon_hint_provided : 2;
+ 	unsigned was_icon_name_provided : 1;
+ 	unsigned was_never_drawn : 1;
+ 	unsigned has_ewmh_wm_name : 1;
+ 	unsigned has_ewmh_wm_icon_name : 1;
+ #define EWMH_NO_ICON     0 /* the application does not provide an ewmh icon */
+ #define EWMH_TRUE_ICON   1 /* the application does provide an ewmh icon */
+@@ -604,20 +607,21 @@ typedef struct window_style
+ #define ICON_RESIZE_TYPE_STRETCHED 0x1
+ #define ICON_RESIZE_TYPE_ADJUSTED  0x2
+ #define ICON_RESIZE_TYPE_SHRUNK    0x3
+ #define ICON_RESIZE_TYPE_MASK      0x3
+ 	unsigned icon_resize_type : 2;
+ 	unsigned char icon_background_padding;
+ 	signed char icon_background_relief;
+ 	signed char icon_title_relief;
+ 	char *icon_font;
+ 	char *window_font;
++	char *inactive_window_font;
+ 	char *fore_color_name;
+ 	char *back_color_name;
+ 	char *fore_color_name_hi;
+ 	char *back_color_name_hi;
+ 	int colorset;
+ 	int colorset_hi;
+ 	int border_colorset;
+ 	int border_colorset_hi;
+ 	int icon_title_colorset;
+ 	int icon_title_colorset_hi;
+@@ -731,20 +735,21 @@ typedef struct FvwmWindow
+ 
+ 	/* Note: if the type of this variable is changed, do update the
+ 	 * CONFIGARGSNEW macro in module_interface.c, libs/vpacket.h too! */
+ 	short boundary_width;
+ 	short unshaped_boundary_width;
+ 	short corner_width;
+ 	short visual_corner_width;
+ 
+ 	/* title font */
+ 	FlocaleFont *title_font;
++	FlocaleFont *inactive_title_font;
+ 	/* /Y coordinate to draw the title name */
+ 	short title_text_offset;
+ 	short title_length;
+ 	/* Note: if the type of this variable is changed, do update the
+ 	 * CONFIGARGSNEW macro in module_interface.c, libs/vpacket.h and too!
+ 	 */
+ 	short title_thickness;
+ 	rotation_t title_text_rotation;
+ 	struct
+ 	{
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/fvwm.h~ fvwm-2.5.21-06/fvwm/fvwm.h~
+--- fvwm-2.5.21-05/fvwm/fvwm.h~	2007-03-03 13:18:42.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/fvwm.h~	2007-03-03 13:19:02.000000000 +0100
+@@ -262,20 +262,21 @@ typedef struct
+ 		unsigned is_top_title_rotated : 1;
+ 		unsigned use_icon_position_hint : 1;
+ 		unsigned use_indexed_window_name : 1;
+ 		unsigned use_indexed_icon_name : 1;
+ #define WINDOWSHADE_LAZY          0
+ #define WINDOWSHADE_ALWAYS_LAZY   1
+ #define WINDOWSHADE_BUSY          2
+ #define WINDOWSHADE_LAZY_MASK   0x3
+ 		unsigned windowshade_laziness : 2;
+ 		unsigned use_title_decor_rotation : 1;
++		unsigned has_border_under_title : 1;
+ 		focus_policy_t focus_policy;
+ 	} s;
+ } common_flags_t;
+ 
+ typedef struct
+ {
+ 	common_flags_t common;
+ #define CR_MOTION_METHOD_AUTO        0
+ #define CR_MOTION_METHOD_USE_GRAV    1
+ #define CR_MOTION_METHOD_STATIC_GRAV 2
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/style.c fvwm-2.5.21-06/fvwm/style.c
+--- fvwm-2.5.21-05/fvwm/style.c	2007-03-03 13:18:49.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/style.c	2007-03-03 13:19:10.000000000 +0100
+@@ -402,20 +402,36 @@ static void merge_styles(
+ 				*merged_style, (SGET_WINDOW_FONT(*add_style)) ?
+ 				safestrdup(SGET_WINDOW_FONT(*add_style)) :
+ 				NULL);
+ 		}
+ 		else
+ 		{
+ 			SSET_WINDOW_FONT(
+ 				*merged_style, SGET_WINDOW_FONT(*add_style));
+ 		}
+ 	}
++	if (S_HAS_INACTIVE_WINDOW_FONT(SCF(*add_style)))
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_INACTIVE_WINDOW_FONT(*merged_style));
++			SSET_INACTIVE_WINDOW_FONT(
++				*merged_style, (SGET_INACTIVE_WINDOW_FONT(*add_style)) ?
++				safestrdup(SGET_INACTIVE_WINDOW_FONT(*add_style)) :
++				NULL);
++		}
++		else
++		{
++			SSET_INACTIVE_WINDOW_FONT(
++				*merged_style, SGET_INACTIVE_WINDOW_FONT(*add_style));
++		}
++	}
+ 	if (add_style->flags.use_start_on_desk)
+ 	{
+ 		SSET_START_DESK(*merged_style, SGET_START_DESK(*add_style));
+ 		SSET_START_PAGE_X(
+ 			*merged_style, SGET_START_PAGE_X(*add_style));
+ 		SSET_START_PAGE_Y(
+ 			*merged_style, SGET_START_PAGE_Y(*add_style));
+ 	}
+ 	if (add_style->flags.use_start_on_screen)
+ 	{
+@@ -728,20 +744,24 @@ static void free_style_mask(window_style
+ 		SAFEFREE(SGET_DECOR_NAME(*style));
+ 	}
+ 	if (pmask->common.has_icon_font)
+ 	{
+ 		SAFEFREE(SGET_ICON_FONT(*style));
+ 	}
+ 	if (pmask->common.has_window_font)
+ 	{
+ 		SAFEFREE(SGET_WINDOW_FONT(*style));
+ 	}
++	if (pmask->common.has_inactive_window_font)
++	{
++		SAFEFREE(SGET_INACTIVE_WINDOW_FONT(*style));
++	}
+ 	if (pmask->has_icon)
+ 	{
+ 		SAFEFREE(SGET_ICON_NAME(*style));
+ 	}
+ 	if (pmask->has_mini_icon)
+ 	{
+ 		SAFEFREE(SGET_MINI_ICON_NAME(*style));
+ 	}
+ 	if (pmask->has_icon_boxes)
+ 	{
+@@ -2832,20 +2852,29 @@ static Bool style_parse_one_style_option
+ 			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCF(*ps), !on);
+ 			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCM(*ps), 1);
+ 			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCC(*ps), 1);
+ 		}
+ 		else if (StrEquals(token, "Iconifiable"))
+ 		{
+ 			S_SET_IS_UNICONIFIABLE(SCF(*ps), !on);
+ 			S_SET_IS_UNICONIFIABLE(SCM(*ps), 1);
+ 			S_SET_IS_UNICONIFIABLE(SCC(*ps), 1);
+ 		}
++		else if (StrEquals(token, "InactiveFont"))
++		{
++			SAFEFREE(SGET_INACTIVE_WINDOW_FONT(*ps));
++			rest = GetNextToken(rest, &token);
++			SSET_INACTIVE_WINDOW_FONT(*ps, token);
++			S_SET_HAS_INACTIVE_WINDOW_FONT(SCF(*ps), (token != NULL));
++			S_SET_HAS_INACTIVE_WINDOW_FONT(SCM(*ps), 1);
++			S_SET_HAS_INACTIVE_WINDOW_FONT(SCC(*ps), 1);
++		}
+ 		else if (StrEquals(token, "IndexedWindowName"))
+ 		{
+ 			S_SET_USE_INDEXED_WINDOW_NAME(SCF(*ps), on);
+ 			S_SET_USE_INDEXED_WINDOW_NAME(SCM(*ps), 1);
+ 			S_SET_USE_INDEXED_WINDOW_NAME(SCC(*ps), 1);
+ 		}
+ 		else if (StrEquals(token, "IndexedIconName"))
+ 		{
+ 			S_SET_USE_INDEXED_ICON_NAME(SCF(*ps), on);
+ 			S_SET_USE_INDEXED_ICON_NAME(SCM(*ps), 1);
+@@ -4445,20 +4474,26 @@ void check_window_style_change(
+ 	{
+ 		flags->do_update_icon_font = 1;
+ 	}
+ 
+ 	/* has_window_font */
+ 	if (S_HAS_WINDOW_FONT(SCC(*ret_style)))
+ 	{
+ 		flags->do_update_window_font = 1;
+ 	}
+ 
++	/* has_inactive_window_font */
++	if (S_HAS_INACTIVE_WINDOW_FONT(SCC(*ret_style)))
++	{
++		flags->do_update_window_font = True;
++	}
++
+ 	/* has_stippled_title */
+ 	if (S_HAS_STIPPLED_TITLE(SCC(*ret_style)) ||
+ 	    S_HAS_NO_STICKY_STIPPLED_TITLE(SCC(*ret_style)) ||
+ 	    S_HAS_STIPPLED_ICON_TITLE(SCC(*ret_style)) ||
+ 	    S_HAS_NO_STICKY_STIPPLED_ICON_TITLE(SCC(*ret_style)))
+ 	{
+ 		flags->do_redraw_decoration = 1;
+ 	}
+ 
+ 	/* has_no_icon_title
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/style.c~ fvwm-2.5.21-06/fvwm/style.c~
+--- fvwm-2.5.21-05/fvwm/style.c~	2007-03-03 13:18:42.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/style.c~	2007-03-03 13:19:02.000000000 +0100
+@@ -2044,20 +2044,26 @@ static Bool style_parse_one_style_option
+ 				fvwm_msg(
+ 					ERR, "style_parse_on_estyle_option",
+ 					"Style BackColor requires color"
+ 					" argument");
+ 			}
+ 		}
+ 		else if (StrEquals(token, "Button"))
+ 		{
+ 			rest = style_parse_button_style(ps, rest, on);
+ 		}
++		else if (StrEquals(token, "BORDERUNDERTITLE"))
++		{
++			S_SET_HAS_BORDER_UNDER_TITLE(SCF(*ps), on);
++			S_SET_HAS_BORDER_UNDER_TITLE(SCM(*ps), 1);
++			S_SET_HAS_BORDER_UNDER_TITLE(SCC(*ps), 1);
++		}
+ 		else if (StrEquals(token, "BorderWidth"))
+ 		{
+ 			if (GetIntegerArguments(rest, &rest, val, 1))
+ 			{
+ 				SSET_BORDER_WIDTH(*ps, (short)*val);
+ 				ps->flags.has_border_width = 1;
+ 				ps->flag_mask.has_border_width = 1;
+ 				ps->change_mask.has_border_width = 1;
+ 			}
+ 			else
+@@ -4413,20 +4419,25 @@ void check_window_style_change(
+ 	if (S_TITLE_DIR(SCC(*ret_style)))
+ 	{
+ 		flags->do_update_title_dir = 1;
+ 	}
+ 
+ 	/* use_title_decor_rotation */
+ 	if (S_USE_TITLE_DECOR_ROTATION(SCC(*ret_style)))
+ 	{
+ 		flags->do_update_rotated_title = 1;
+ 	}
++	
++	if (S_HAS_BORDER_UNDER_TITLE(SCC(*ret_style)))
++	{
++		flags->do_redecorate = True;
++	}
+ 
+ 	/* has_mwm_border
+ 	 * has_mwm_buttons */
+ 	if (S_HAS_MWM_BORDER(SCC(*ret_style)) ||
+ 	    S_HAS_MWM_BUTTONS(SCC(*ret_style)))
+ 	{
+ 		flags->do_redecorate = 1;
+ 	}
+ 
+ 	/* has_icon_font */
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/style.h fvwm-2.5.21-06/fvwm/style.h
+--- fvwm-2.5.21-05/fvwm/style.h	2007-03-03 13:18:49.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/style.h	2007-03-03 13:19:10.000000000 +0100
+@@ -252,20 +252,24 @@
+ #define S_SET_HAS_NO_STICKY_STIPPLED_TITLE(c,x) \
+ 	((c).s.has_no_sticky_stippled_title = !!(x))
+ #define S_HAS_STIPPLED_ICON_TITLE(c) \
+ 	((c).s.has_stippled_icon_title)
+ #define S_SET_HAS_STIPPLED_ICON_TITLE(c,x) \
+ 	((c).s.has_stippled_icon_title = !!(x))
+ #define S_HAS_WINDOW_FONT(c) \
+ 	((c).has_window_font)
+ #define S_SET_HAS_WINDOW_FONT(c,x) \
+ 	((c).has_window_font = !!(x))
++#define S_HAS_INACTIVE_WINDOW_FONT(c) \
++	((c).has_inactive_window_font)
++#define S_SET_HAS_INACTIVE_WINDOW_FONT(c,x) \
++	((c).has_inactive_window_font = !!(x))
+ #define S_ICON_OVERRIDE(c) \
+ 	((c).s.icon_override)
+ #define S_SET_ICON_OVERRIDE(c,x) \
+ 	((c).s.icon_override = (x))
+ #define S_IS_BOTTOM_TITLE_ROTATED(c) \
+ 	((c).s.is_bottom_title_rotated)
+ #define S_SET_IS_BOTTOM_TITLE_ROTATED(c,x) \
+ 	((c).s.is_bottom_title_rotated = !!(x))
+ #define S_IS_FIXED(c) \
+ 	((c).s.is_fixed)
+@@ -448,20 +452,24 @@
+ #define SSET_BACK_COLOR_NAME_HI(s,x) \
+ 	((s).back_color_name_hi = (x))
+ #define SGET_ICON_FONT(s) \
+ 	((s).icon_font)
+ #define SSET_ICON_FONT(s,x) \
+ 	((s).icon_font = (x))
+ #define SGET_WINDOW_FONT(s) \
+ 	((s).window_font)
+ #define SSET_WINDOW_FONT(s,x) \
+ 	((s).window_font = (x))
++#define SGET_INACTIVE_WINDOW_FONT(s) \
++	((s).inactive_window_font)
++#define SSET_INACTIVE_WINDOW_FONT(s,x) \
++	((s).inactive_window_font = (x))
+ #define SGET_COLORSET(s) \
+ 	((s).colorset)
+ #define SSET_COLORSET(s,x) \
+ 	((s).colorset = (x))
+ #define SSET_BORDER_COLORSET(s,x) \
+ 	((s).border_colorset = (x))
+ #define SGET_BORDER_COLORSET(s) \
+ 	((s).border_colorset)
+ #define SGET_COLORSET_HI(s) \
+ 	((s).colorset_hi)
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/style.h~ fvwm-2.5.21-06/fvwm/style.h~
+--- fvwm-2.5.21-05/fvwm/style.h~	2007-03-03 13:18:42.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/style.h~	2007-03-03 13:19:02.000000000 +0100
+@@ -328,20 +328,24 @@
+ #define S_SET_USE_INDEXED_ICON_NAME(c,x) \
+ 	((c).s.use_indexed_icon_name = !!(x))
+ #define S_WINDOWSHADE_LAZINESS(c) \
+ 	((c).s.windowshade_laziness)
+ #define S_SET_WINDOWSHADE_LAZINESS(c,x) \
+ 	((c).s.windowshade_laziness = (x))
+ #define S_USE_TITLE_DECOR_ROTATION(c) \
+ 	((c).s.use_title_decor_rotation)
+ #define S_SET_USE_TITLE_DECOR_ROTATION(c,x) \
+ 	((c).s.use_title_decor_rotation = !!(x))
++#define S_HAS_BORDER_UNDER_TITLE(c) \
++	((c).s.has_border_under_title)
++#define S_SET_HAS_BORDER_UNDER_TITLE(c,x) \
++	((c).s.has_border_under_title = !!(x))
+ #define S_DO_EWMH_MINI_ICON_OVERRIDE(c) \
+ 	((c).s.do_ewmh_mini_icon_override)
+ #define S_SET_DO_EWMH_MINI_ICON_OVERRIDE(c,x) \
+ 	((c).s.do_ewmh_mini_icon_override = !!(x))
+ #define S_DO_EWMH_DONATE_ICON(c) \
+ 	((c).s.do_ewmh_donate_icon)
+ #define S_SET_DO_EWMH_DONATE_ICON(c,x) \
+ 	((c).s.do_ewmh_donate_icon = !!(x))
+ #define S_DO_EWMH_DONATE_MINI_ICON(c) \
+ 	((c).s.do_ewmh_donate_mini_icon)
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/window_flags.h fvwm-2.5.21-06/fvwm/window_flags.h
+--- fvwm-2.5.21-05/fvwm/window_flags.h	2007-03-03 13:18:49.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/window_flags.h	2007-03-03 13:19:10.000000000 +0100
+@@ -573,20 +573,26 @@
+ #define SET_WINDOW_BORDER_DRAWN(fw,x) \
+ 	(fw)->flags.is_window_border_drawn = !!(x)
+ #define SETM_WINDOW_BORDER_DRAWN(fw,x) \
+ 	(fw)->flag_mask.is_window_border_drawn = !!(x)
+ #define IS_WINDOW_FONT_LOADED(fw) \
+ 	((fw)->flags.is_window_font_loaded)
+ #define SET_WINDOW_FONT_LOADED(fw,x) \
+ 	(fw)->flags.is_window_font_loaded = !!(x)
+ #define SETM_WINDOW_FONT_LOADED(fw,x) \
+ 	(fw)->flag_mask.is_window_font_loaded = !!(x)
++#define IS_INACTIVE_WINDOW_FONT_LOADED(fw) \
++	((fw)->flags.is_inactive_window_font_loaded)
++#define SET_INACTIVE_WINDOW_FONT_LOADED(fw,x) \
++	(fw)->flags.is_inactive_window_font_loaded = !!(x)
++#define SETM_INACTIVE_WINDOW_FONT_LOADED(fw,x) \
++	(fw)->flag_mask.is_inactive_window_font_loaded = !!(x)
+ #define CR_MOTION_METHOD(fw) \
+ 	((fw)->flags.cr_motion_method)
+ #define SET_CR_MOTION_METHOD(fw,x) \
+ 	(fw)->flags.cr_motion_method = ((x) & CR_MOTION_METHOD_MASK)
+ #define SETM_CR_MOTION_METHOD(fw,x) \
+ 	(fw)->flag_mask.cr_motion_method = ((x) ? CR_MOTION_METHOD_MASK : 0)
+ #define WAS_CR_MOTION_METHOD_DETECTED(fw) \
+ 	((fw)->flags.was_cr_motion_method_detected)
+ #define SET_CR_MOTION_METHOD_DETECTED(fw,x) \
+ 	(fw)->flags.was_cr_motion_method_detected = !!(x)
+@@ -615,20 +621,26 @@
+ #define SET_FORCE_NEXT_PN(fw,x) \
+ 	(fw)->flags.do_force_next_pn = !!(x)
+ #define SETM_FORCE_NEXT_PN(fw,x) \
+ 	(fw)->flag_mask.do_force_next_pn = !!(x)
+ #define USING_DEFAULT_WINDOW_FONT(fw) \
+ 	((fw)->flags.using_default_window_font)
+ #define SET_USING_DEFAULT_WINDOW_FONT(fw,x) \
+ 	(fw)->flags.using_default_window_font = !!(x)
+ #define SETM_USING_DEFAULT_WINDOW_FONT(fw,x) \
+ 	(fw)->flag_mask.using_default_window_font = !!(x)
++#define USING_DEFAULT_INACTIVE_WINDOW_FONT(fw) \
++	((fw)->flags.using_default_inactive_window_font)
++#define SET_USING_DEFAULT_INACTIVE_WINDOW_FONT(fw,x) \
++	(fw)->flags.using_default_inactive_window_font = !!(x)
++#define SETM_USING_DEFAULT_INACTIVE_WINDOW_FONT(fw,x) \
++	(fw)->flag_mask.using_default_inactive_window_font = !!(x)
+ #define USING_DEFAULT_ICON_FONT(fw) \
+ 	((fw)->flags.using_default_icon_font)
+ #define SET_USING_DEFAULT_ICON_FONT(fw,x) \
+ 	(fw)->flags.using_default_icon_font = !!(x)
+ #define SETM_USING_DEFAULT_ICON_FONT(fw,x) \
+ 	(fw)->flag_mask.using_default_icon_font = !!(x)
+ #define WAS_ICON_HINT_PROVIDED(fw) \
+ 	((fw)->flags.was_icon_hint_provided)
+ #define SET_WAS_ICON_HINT_PROVIDED(fw,x) \
+ 	(fw)->flags.was_icon_hint_provided = (x)
+diff -U10 -Naupr fvwm-2.5.21-05/fvwm/window_flags.h~ fvwm-2.5.21-06/fvwm/window_flags.h~
+--- fvwm-2.5.21-05/fvwm/window_flags.h~	2007-03-03 13:18:42.000000000 +0100
++++ fvwm-2.5.21-06/fvwm/window_flags.h~	2007-03-03 13:19:02.000000000 +0100
+@@ -321,20 +321,26 @@
+ #define SET_IS_BOTTOM_TITLE_ROTATED(fw,x) \
+ 	(fw)->flags.common.s.is_bottom_title_rotated = !!(x)
+ #define SETM_IS_BOTTOM_TITLE_ROTATED(fw,x) \
+ 	(fw)->flag_mask.common.s.is_bottom_title_rotated = !!(x)
+ #define USE_TITLE_DECOR_ROTATION(fw) \
+ 	((fw)->flags.common.s.use_title_decor_rotation)
+ #define SET_USE_TITLE_DECOR_ROTATION(fw,x) \
+ 	(fw)->flags.common.s.use_title_decor_rotation = !!(x)
+ #define SETM_USE_TITLE_DECOR_ROTATION(fw,x) \
+ 	(fw)->flag_mask.common.s.use_title_decor_rotation = !!(x)
++#define HAS_BORDER_UNDER_TITLE(fw) \
++	((fw)->flags.common.s.has_border_under_title)
++#define SET_HAS_BORDER_UNDER_TITLE(fw,x) \
++	(fw)->flags.common.s.has_border_under_title = !!(x)
++#define SETM_HAS_BORDER_UNDER_TITLE(fw,x) \
++	(fw)->flag_mask.common.s.has_border_under_title = !!(x)
+ 
+ /* access to the special flags of a window */
+ #define DO_REUSE_DESTROYED(fw) \
+ 	((fw)->flags.do_reuse_destroyed)
+ #define SET_DO_REUSE_DESTROYED(fw,x) \
+ 	(fw)->flags.do_reuse_destroyed = !!(x)
+ #define SETM_DO_REUSE_DESTROYED(fw,x) \
+ 	(fw)->flag_mask.do_reuse_destroyed = !!(x)
+ #define HAS_NO_BORDER(fw) \
+ 	((fw)->flags.common.has_no_border)
diff --git a/windowmanagers/fvwm/patches/07-FluxboxHandles.patch b/windowmanagers/fvwm/patches/07-FluxboxHandles.patch
new file mode 100644
index 0000000..fa0c2bd
--- /dev/null
+++ b/windowmanagers/fvwm/patches/07-FluxboxHandles.patch
@@ -0,0 +1,1470 @@
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/add_window.c fvwm-2.5.21-07/fvwm/add_window.c
+--- fvwm-2.5.21-06/fvwm/add_window.c	2007-03-03 13:19:10.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/add_window.c	2007-03-03 13:19:35.000000000 +0100
+@@ -1634,31 +1634,36 @@ void setup_wm_hints(FvwmWindow *fw)
+ 	set_focus_model(fw);
+ 
+ 	return;
+ }
+ 
+ void setup_title_geometry(
+ 	FvwmWindow *fw, window_style *pstyle)
+ {
+ 	int width;
+ 	int offset;
++	style_flags *sflags = &(pstyle->flags);
+ 
+ 	get_title_font_size_and_offset(
+ 		fw, S_TITLE_DIR(SCF(*pstyle)),
+ 		S_IS_LEFT_TITLE_ROTATED_CW(SCF(*pstyle)),
+ 		S_IS_RIGHT_TITLE_ROTATED_CW(SCF(*pstyle)),
+ 		S_IS_TOP_TITLE_ROTATED(SCF(*pstyle)),
+ 		S_IS_BOTTOM_TITLE_ROTATED(SCF(*pstyle)),
+ 		&width, &offset);
+ 	fw->title_thickness = width;
+ 	fw->title_text_offset = offset;
+ 	fw->corner_width = fw->title_thickness + fw->boundary_width;
++	if (SHAS_CORNER_WIDTH(sflags))
++	{
++		fw->corner_width = SGET_CORNER_WIDTH(*pstyle);
++	}
+ 	if (!HAS_TITLE(fw))
+ 	{
+ 		fw->title_thickness = 0;
+ 	}
+ 
+ 	return;
+ }
+ 
+ void setup_window_font(
+ 	FvwmWindow *fw, window_style *pstyle, Bool do_destroy)
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/add_window.c~ fvwm-2.5.21-07/fvwm/add_window.c~
+--- fvwm-2.5.21-06/fvwm/add_window.c~	2007-03-03 13:19:02.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/add_window.c~	2007-03-03 13:19:27.000000000 +0100
+@@ -628,20 +628,32 @@ static void destroy_window_font(FvwmWind
+ 	{
+ 		FlocaleUnloadFont(dpy, fw->title_font);
+ 	}
+ 	SET_WINDOW_FONT_LOADED(fw, 0);
+ 	/* Fall back to default font. There are some race conditions when a
+ 	 * window is destroyed and recaptured where an invalid font might be
+ 	 * accessed  otherwise. */
+ 	fw->title_font = Scr.DefaultFont;
+ 	SET_USING_DEFAULT_WINDOW_FONT(fw, 1);
+ 
++	if (IS_INACTIVE_WINDOW_FONT_LOADED(fw) && !USING_DEFAULT_INACTIVE_WINDOW_FONT(fw) &&
++	    fw->title_font != Scr.DefaultFont)
++	{
++		FlocaleUnloadFont(dpy, fw->title_font);
++	}
++	SET_INACTIVE_WINDOW_FONT_LOADED(fw, 0);
++	/* Fall back to default font. There are some race conditions when a
++	 * window is destroyed and recaptured where an invalid font might be
++	 * accessed  otherwise. */
++	fw->title_font = Scr.DefaultFont;
++	SET_USING_DEFAULT_INACTIVE_WINDOW_FONT(fw, 1);
++	
+ 	return;
+ }
+ 
+ static void destroy_icon_font(FvwmWindow *fw)
+ {
+ 	if (IS_ICON_FONT_LOADED(fw) && !USING_DEFAULT_ICON_FONT(fw) &&
+ 	    fw->icon_font != Scr.DefaultFont)
+ 	{
+ 		FlocaleUnloadFont(dpy, fw->icon_font);
+ 	}
+@@ -1669,20 +1681,39 @@ void setup_window_font(
+ 		}
+ 		else
+ 		{
+ 			/* no explicit font or failed to load, use default font
+ 			 * instead */
+ 			fw->title_font = Scr.DefaultFont;
+ 			SET_USING_DEFAULT_WINDOW_FONT(fw, 1);
+ 		}
+ 		SET_WINDOW_FONT_LOADED(fw, 1);
+ 	}
++	/* load inactive font */
++	if (!IS_INACTIVE_WINDOW_FONT_LOADED(fw))
++	{
++		if (S_HAS_INACTIVE_WINDOW_FONT(SCF(*pstyle)) &&
++		    SGET_INACTIVE_WINDOW_FONT(*pstyle) &&
++		    (fw->inactive_title_font =
++		     FlocaleLoadFont(dpy, SGET_INACTIVE_WINDOW_FONT(*pstyle), "FVWM")))
++		{
++			SET_USING_DEFAULT_INACTIVE_WINDOW_FONT(fw, 0);
++		}
++		else
++		{
++			/* no explicit font or failed to load, use active title font
++			 * instead */
++			fw->inactive_title_font = fw->title_font;
++			SET_USING_DEFAULT_INACTIVE_WINDOW_FONT(fw, 1);
++		}
++		SET_INACTIVE_WINDOW_FONT_LOADED(fw, 1);
++	}
+ 	setup_title_geometry(fw, pstyle);
+ 
+ 	return;
+ }
+ 
+ void setup_icon_font(
+ 	FvwmWindow *fw, window_style *pstyle, Bool do_destroy)
+ {
+ 	int height = 0;
+ 
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/borders.c fvwm-2.5.21-07/fvwm/borders.c
+--- fvwm-2.5.21-06/fvwm/borders.c	2007-03-03 13:19:10.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/borders.c	2007-03-03 13:19:35.000000000 +0100
+@@ -1377,20 +1377,38 @@ static void border_fill_pixmap_backgroun
+ 	{
+ 		XFreePixmap(dpy, shape);
+ 	}
+ 	if (alpha && alpha != bg->pixmap.alpha)
+ 	{
+ 		XFreePixmap(dpy, alpha);
+ 	}
+ 	return;
+ }
+ 
++static void border_fill_fluxbox_handle(
++	Pixmap dest_pix, rectangle *dest_g, common_decorations_type *cd, Bool corner)
++{
++	corner = False;
++	/* Main Color */
++	XFillRectangle(
++		dpy, dest_pix, corner ? cd->shadow_gc : cd->relief_gc, dest_g->x + 1, dest_g->y + 1,
++		dest_g->width - dest_g->x - 3, dest_g->height - dest_g->y - 2);
++	/* Right Shadow */
++	XFillRectangle(
++		dpy, dest_pix, cd->shadow_gc, dest_g->x + dest_g->width - 2, dest_g->y + 1,
++		1, dest_g->height - dest_g->y - 2);
++	/* Bottom Shadow */
++	XFillRectangle(
++		dpy, dest_pix, cd->shadow_gc, dest_g->x + 1, dest_g->height - 2,
++		dest_g->width - dest_g->x - 3, 1);
++}
++
+ /* create a root transparent colorset bg, we take in account a possible
+  * drawing rotation */
+ static Pixmap border_create_root_transparent_pixmap(
+ 	titlebar_descr *td, Window w, int width, int height, int cs)
+ {
+ 	int my_w, my_h;
+ 	Pixmap p;
+ 
+ 	if (!CSET_IS_TRANSPARENT_ROOT(cs))
+ 	{
+@@ -1592,26 +1610,42 @@ static void border_draw_one_border_part(
+ 		bg.pixmap.g.x = 0;
+ 		bg.pixmap.g.y = 0;
+ 	}
+ 	/* set the geometry for drawing the Tiled pixmap; maybe add the relief
+ 	 * as offset? */
+ 	pix_g.x = 0;
+ 	pix_g.y = 0;
+ 	pix_g.width = part_g.width;
+ 	pix_g.height = part_g.height;
+ 	border_fill_pixmap_background(p, &pix_g, &bg, cd);
++	if (HAS_FLUXBOX_HANDLES(fw) && (part & PART_BOTTOM))
++	{
++		pix_g.y = part_g.height - fw->boundary_width;
++		if (part != PART_BORDER_S)
++		{
++			pix_g.width++;
++		}
++		if (part == PART_BORDER_SE)
++		{
++			pix_g.x--;
++		}
++		if (fw->boundary_width > 2)
++		{
++			border_fill_fluxbox_handle(p, &pix_g, cd, !(part & PART_BORDER_S));
++		}
++	}
+ 	if (free_bg_pixmap && bg.pixmap.p)
+ 	{
+ 		XFreePixmap(dpy, bg.pixmap.p);
+ 	}
+ 	/* draw the relief over the background */
+-	if (!br->relief.is_flat)
++	if (!br->relief.is_flat && !HAS_FLUXBOX_HANDLES(fw))
+ 	{
+ 		border_draw_part_relief(br, frame_g, &part_g, p, is_inverted);
+ 		/* draw the handle marks */
+ 		if (br->marks.has_x_marks || br->marks.has_y_marks)
+ 		{
+ 			border_draw_part_marks(br, &part_g, part, p);
+ 		}
+ 	}
+ 	/* apply the pixmap and destroy it */
+ 	border_set_part_background(w, p);
+@@ -4121,20 +4155,23 @@ static window_parts border_get_titlebar_
+ 	rectangle *old_g, rectangle *new_g, Bool do_hilight,
+ 	titlebar_descr *ret_td)
+ {
+ 	window_parts draw_parts;
+ 	int i;
+ 	DecorFace *df;
+ 	int is_start = 0;
+ 	JustificationType just;
+ 	int lbl = 0;
+ 	int rbl = 0;
++	int bw;
++
++	bw = HAS_FLUXBOX_HANDLES(fw) ? 1 : fw->boundary_width;
+ 
+ 	ret_td->cd = cd;
+ 	ret_td->frame_g = *new_g;
+ 	if (old_g == NULL)
+ 	{
+ 		old_g = &fw->g.frame;
+ 	}
+ 	frame_get_titlebar_dimensions(fw, old_g, NULL, &ret_td->old_layout);
+ 	frame_get_titlebar_dimensions(fw, new_g, NULL, &ret_td->layout);
+ 
+@@ -4158,30 +4195,30 @@ static window_parts border_get_titlebar_
+ 		}
+ 	}
+ 	if (fw->title_text_rotation == ROTATION_270 ||
+ 	    fw->title_text_rotation == ROTATION_180)
+ 	{
+ 		ret_td->has_an_upsidedown_rotation = True;
+ 	}
+ 	/* geometry of the title bar title + buttons */
+ 	if (!ret_td->has_vt)
+ 	{
+-		ret_td->bar_g.width = new_g->width - 2 * fw->boundary_width;
++		ret_td->bar_g.width = new_g->width - 2 * bw;
+ 		ret_td->bar_g.height = ret_td->layout.title_g.height;
+-		ret_td->bar_g.x = fw->boundary_width;
++		ret_td->bar_g.x = bw;
+ 		ret_td->bar_g.y = ret_td->layout.title_g.y;
+ 	}
+ 	else
+ 	{
+ 		ret_td->bar_g.width = ret_td->layout.title_g.width;
+-		ret_td->bar_g.height = new_g->height - 2 * fw->boundary_width;
+-		ret_td->bar_g.y = fw->boundary_width;
++		ret_td->bar_g.height = new_g->height - 2 * bw;
++		ret_td->bar_g.y = bw;
+ 		ret_td->bar_g.x = ret_td->layout.title_g.x;
+ 	}
+ 
+ 	/* buttons geometries */
+ 	if (ret_td->has_vt)
+ 	{
+ 		ret_td->left_buttons_g.width = ret_td->bar_g.width;
+ 		ret_td->right_buttons_g.width = ret_td->bar_g.width;
+ 	}
+ 	else
+@@ -4219,54 +4256,54 @@ static window_parts border_get_titlebar_
+ 			}
+ 		}
+ 	}
+ 
+ 	if (ret_td->has_an_upsidedown_rotation)
+ 	{
+ 		if (ret_td->has_vt)
+ 		{
+ 			ret_td->left_buttons_g.height = rbl;
+ 			ret_td->right_buttons_g.height = lbl;
+-			ret_td->right_buttons_g.y = fw->boundary_width;
++			ret_td->right_buttons_g.y = bw;
+ 			ret_td->right_buttons_g.x = ret_td->bar_g.x;
+ 			ret_td->left_buttons_g.y = ret_td->layout.title_g.y +
+ 				ret_td->layout.title_g.height;
+ 			ret_td->left_buttons_g.x = ret_td->bar_g.x;
+ 		}
+ 		else
+ 		{
+ 			ret_td->left_buttons_g.width = rbl;
+ 			ret_td->right_buttons_g.width = lbl;
+-			ret_td->right_buttons_g.x = fw->boundary_width;
++			ret_td->right_buttons_g.x = bw;
+ 			ret_td->right_buttons_g.y = ret_td->bar_g.y;
+ 			ret_td->left_buttons_g.x = ret_td->layout.title_g.x +
+ 				ret_td->layout.title_g.width;
+ 			ret_td->left_buttons_g.y = ret_td->bar_g.y;
+ 		}
+ 	}
+ 	else
+ 	{
+ 		if (ret_td->has_vt)
+ 		{
+ 			ret_td->left_buttons_g.height = lbl;
+ 			ret_td->right_buttons_g.height = rbl;
+-			ret_td->left_buttons_g.y = fw->boundary_width;
++			ret_td->left_buttons_g.y = bw;
+ 			ret_td->left_buttons_g.x = ret_td->bar_g.x;
+ 			ret_td->right_buttons_g.y = ret_td->layout.title_g.y +
+ 				ret_td->layout.title_g.height;
+ 			ret_td->right_buttons_g.x = ret_td->bar_g.x;
+ 		}
+ 		else
+ 		{
+ 			ret_td->left_buttons_g.width = lbl;
+ 			ret_td->right_buttons_g.width = rbl;
+-			ret_td->left_buttons_g.x = fw->boundary_width;
++			ret_td->left_buttons_g.x = bw;
+ 			ret_td->left_buttons_g.y = ret_td->bar_g.y;
+ 			ret_td->right_buttons_g.x = ret_td->layout.title_g.x +
+ 				ret_td->layout.title_g.width;
+ 			ret_td->right_buttons_g.y = ret_td->bar_g.y;
+ 		}
+ 	}
+ 
+ 	/* initialise flags */
+ 	border_get_titlebar_descr_state(
+ 		fw, pressed_parts, pressed_button, clear_parts, do_hilight,
+@@ -4595,38 +4632,42 @@ int border_context_to_parts(
+ 	return PART_NONE;
+ }
+ 
+ void border_get_part_geometry(
+ 	FvwmWindow *fw, window_parts part, rectangle *sidebar_g,
+ 	rectangle *ret_g, Window *ret_w)
+ {
+ 	int bw;
+ 	Bool title;
+ 
+-	bw = fw->boundary_width;
++	bw = HAS_FLUXBOX_HANDLES(fw) ? 1 : fw->boundary_width;
+ 	/* ret_g->x and ret->y is just an offset relatively to the w,
+ 	 * maybe we can take the relief in account? */
+ 	switch (part)
+ 	{
+ 	case PART_BORDER_N:
+ 		ret_g->x = sidebar_g->x;
+ 		ret_g->y = 0;
+ 		*ret_w = FW_W_SIDE(fw, 0);
+ 		break;
+ 	case PART_BORDER_E:
+ 		ret_g->x = 2 * sidebar_g->x + sidebar_g->width - bw;
+ 		ret_g->y = sidebar_g->y;
+ 		*ret_w = FW_W_SIDE(fw, 1);
+ 		break;
+ 	case PART_BORDER_S:
+ 		ret_g->x = sidebar_g->x;
+ 		ret_g->y = 2 * sidebar_g->y + sidebar_g->height - bw;
++		if (HAS_FLUXBOX_HANDLES(fw))
++		{
++			ret_g->y = 2 * sidebar_g->y + sidebar_g->height - fw->boundary_width;
++		}
+ 		*ret_w = FW_W_SIDE(fw, 2);
+ 		break;
+ 	case PART_BORDER_W:
+ 		ret_g->x = 0;
+ 		ret_g->y = sidebar_g->y;
+ 		*ret_w = FW_W_SIDE(fw, 3);
+ 		break;
+ 	case PART_BORDER_NW:
+ 		ret_g->x = 0;
+ 		ret_g->y = 0;
+@@ -4647,23 +4688,28 @@ void border_get_part_geometry(
+ 		ret_g->y = sidebar_g->y + sidebar_g->height;
+ 		*ret_w = FW_W_CORNER(fw, 3);
+ 		break;
+ 	default:
+ 		break;
+ 	}
+ 
+ 	switch (part)
+ 	{
+ 	case PART_BORDER_N:
++		ret_g->height = bw;
+ 	case PART_BORDER_S:
+ 		ret_g->width = sidebar_g->width;
+ 		ret_g->height = bw;
++		if (HAS_FLUXBOX_HANDLES(fw))
++		{
++			ret_g->height = fw->boundary_width;
++		}
+ 		break;
+ 	case PART_BORDER_E:
+ 	case PART_BORDER_W:
+ 		ret_g->width = bw;
+ 		ret_g->height = sidebar_g->height;
+ 		break;
+ 	case PART_BORDER_NW:
+ 	case PART_BORDER_NE:
+ 	case PART_BORDER_SW:
+ 	case PART_BORDER_SE:
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/borders.c~ fvwm-2.5.21-07/fvwm/borders.c~
+--- fvwm-2.5.21-06/fvwm/borders.c~	2007-03-03 13:19:02.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/borders.c~	2007-03-03 13:19:27.000000000 +0100
+@@ -3516,31 +3516,32 @@ static void border_draw_title_stick_line
+ 				SWAP_ARGS(td->has_vt, right_w, 1),
+ 				tdd->sgc, tdd->rgc, 1, False, rotation);
+ 		}
+ 	}
+ 
+ 	return;
+ }
+ 
+ static void border_draw_title_mono(
+ 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
+-	FlocaleWinString *fstr, Pixmap dest_pix)
++	FlocaleWinString *fstr, Pixmap dest_pix, Bool do_hilight)
+ {
+ 	int has_vt;
+ 
+ 	has_vt = HAS_VERTICAL_TITLE(fw);
+ 	XFillRectangle(
+ 		dpy, dest_pix, td->cd->relief_gc,
+ 		td->offset - 2, 0, td->length+4, fw->title_thickness);
+ 	if (fw->visible_name != (char *)NULL)
+ 	{
+-		FlocaleDrawString(dpy, fw->title_font, fstr, 0);
++		FlocaleDrawString(dpy, do_hilight ? fw->title_font :
++			fw->inactive_title_font, fstr, 0);
+ 	}
+ 	/* for mono, we clear an area in the title bar where the window
+ 	 * title goes, so that its more legible. For color, no need */
+ 	do_relieve_rectangle(
+ 		dpy, dest_pix, 0, 0,
+ 		SWAP_ARGS(has_vt, td->offset - 3,
+ 			  fw->title_thickness - 1),
+ 		tdd->rgc, tdd->sgc, td->cd->relief_width, False);
+ 	do_relieve_rectangle(
+ 		dpy, dest_pix,
+@@ -3590,21 +3591,21 @@ static void border_draw_title_relief(
+ 	default:
+ 		/* flat */
+ 		break;
+ 	}
+ 
+ 	return;
+ }
+ 
+ static void border_draw_title_deep(
+ 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
+-	FlocaleWinString *fstr, Pixmap dest_pix, Window w)
++	FlocaleWinString *fstr, Pixmap dest_pix, Window w, Bool do_hilight)
+ {
+ 	DecorFace *df;
+ 	pixmap_background_type bg;
+ 
+ 	bg.flags.use_pixmap = 0;
+ 	for (df = tdd->df; df != NULL; df = df->next)
+ 	{
+ 		if (df->style.face_type == MultiPixmap)
+ 		{
+ 			border_mp_draw_mp_titlebar(
+@@ -3612,44 +3613,46 @@ static void border_draw_title_deep(
+ 		}
+ 		else
+ 		{
+ 			bg.pixel = df->u.back;
+ 			border_draw_decor_to_pixmap(
+ 				fw, dest_pix, w, &bg, &td->layout.title_g, df,
+ 				td, td->tbstate.tstate, True, tdd->is_toggled,
+ 				1);
+ 		}
+ 	}
+-	FlocaleDrawString(dpy, fw->title_font, &tdd->fstr, 0);
++	FlocaleDrawString(dpy, do_hilight ? fw->title_font :
++		fw->inactive_title_font, &tdd->fstr, 0);
+ 
+ 	return;
+ }
+ 
+ static void border_get_titlebar_draw_descr(
+ 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
+-	Pixmap dest_pix)
++	Pixmap dest_pix, Bool do_hilight)
+ {
+ 	rectangle *title_g;
+ 
+ 	memset(tdd, 0, sizeof(*tdd));
+ 	/* prepare the gcs and variables */
+ 	if (td->tbstate.is_title_pressed)
+ 	{
+ 		tdd->rgc = td->cd->shadow_gc;
+ 		tdd->sgc = td->cd->relief_gc;
+ 	}
+ 	else
+ 	{
+ 		tdd->rgc = td->cd->relief_gc;
+ 		tdd->sgc = td->cd->shadow_gc;
+ 	}
+-	NewFontAndColor(fw->title_font, td->cd->fore_color, td->cd->back_color);
++	NewFontAndColor(do_hilight ? fw->title_font : fw->inactive_title_font,
++		td->cd->fore_color, td->cd->back_color);
+ 	title_g = &td->layout.title_g;
+ 	tdd->tstyle = &TB_STATE(
+ 		GetDecor(fw, titlebar))[td->tbstate.tstate].style;
+ 	tdd->df = &TB_STATE(GetDecor(fw, titlebar))[td->tbstate.tstate];
+ 
+ 	/* fetch the title string */
+ 	tdd->fstr.str = fw->visible_name;
+ 	tdd->fstr.win = dest_pix;
+ 	if (td->td_is_rotated)
+ 	{
+@@ -3673,29 +3676,29 @@ static void border_get_titlebar_draw_des
+ 	{
+ 		tdd->fstr.colorset = &Colorset[td->cd->cs];
+ 		tdd->fstr.flags.has_colorset = 1;
+ 	}
+ 	tdd->fstr.gc = Scr.TitleGC;
+ 
+ 	return;
+ }
+ 
+ static void border_set_title_pixmap(
+-	FvwmWindow *fw, titlebar_descr *td, Pixmap *dest_pix, Window w)
++	FvwmWindow *fw, titlebar_descr *td, Pixmap *dest_pix, Window w, Bool do_hilight)
+ {
+ 	pixmap_background_type bg;
+ 	title_draw_descr tdd;
+ 	FlocaleWinString fstr;
+ 	Bool free_bg_pixmap = False;
+ 	rectangle pix_g;
+ 
+-	border_get_titlebar_draw_descr(fw, td, &tdd, *dest_pix);
++	border_get_titlebar_draw_descr(fw, td, &tdd, *dest_pix, do_hilight);
+ 	/* prepare background, either from the window colour or from the
+ 	 * border style */
+ 	if (!DFS_USE_BORDER_STYLE(*tdd.tstyle))
+ 	{
+ 		/* fill with the button background colour */
+ 		bg.flags.use_pixmap = 0;
+ 		bg.pixel = td->cd->back_color;
+ 		pix_g.x = 0;
+ 		pix_g.y = 0;
+ 		pix_g.width = td->layout.title_g.width;
+@@ -3749,52 +3752,52 @@ static void border_set_title_pixmap(
+ 				td->layout.title_g.height,
+ 				Pdepth, Scr.BordersGC, td->draw_rotation);
+ 			XFreePixmap(dpy, *dest_pix);
+ 			*dest_pix = tmp;
+ 			border_rotate_titlebar_descr(fw, td);
+ 		}
+ 	}
+ 
+ 	if (Pdepth < 2)
+ 	{
+-		border_draw_title_mono(fw, td, &tdd, &fstr, *dest_pix);
++		border_draw_title_mono(fw, td, &tdd, &fstr, *dest_pix, do_hilight);
+ 	}
+ 	else
+ 	{
+-		border_draw_title_deep(fw, td, &tdd, &fstr, *dest_pix, w);
++		border_draw_title_deep(fw, td, &tdd, &fstr, *dest_pix, w, do_hilight);
+ 	}
+ 	border_draw_title_relief(fw, td, &tdd, *dest_pix);
+ 	border_draw_title_stick_lines(fw, td, &tdd, *dest_pix);
+ 
+ 	return;
+ }
+ 
+ static void border_draw_title(
+-	FvwmWindow *fw, titlebar_descr *td)
++	FvwmWindow *fw, titlebar_descr *td, Bool do_hilight)
+ {
+ 	Pixmap p;
+ 
+ 	if (td->layout.title_g.x < 0 || td->layout.title_g.y < 0)
+ 	{
+ 		return;
+ 	}
+ 	if (td->draw_rotation != ROTATION_0)
+ 	{
+ 		border_rotate_titlebar_descr(fw, td);
+ 	}
+ 	/* make a pixmap */
+ 	p = border_create_decor_pixmap(td->cd, &(td->layout.title_g));
+ 	/* set the background tile */
+ #if 0
+ 	fprintf(stderr,"drawing title\n");
+ #endif
+-	border_set_title_pixmap(fw, td, &p, FW_W_TITLE(fw));
++	border_set_title_pixmap(fw, td, &p, FW_W_TITLE(fw), do_hilight);
+ 	if (td->draw_rotation != ROTATION_0)
+ 	{
+ 		Pixmap tmp;
+ 
+ 		tmp = CreateRotatedPixmap(
+ 			dpy, p, td->layout.title_g.width,
+ 			td->layout.title_g.height, Pdepth, Scr.BordersGC,
+ 			td->draw_rotation);
+ 		XFreePixmap(dpy, p);
+ 		p = tmp;
+@@ -4269,23 +4272,23 @@ static window_parts border_get_titlebar_
+ 		fw, pressed_parts, pressed_button, clear_parts, do_hilight,
+ 		&(ret_td->tbstate));
+ 
+ 	/* get the title string length and position
+ 	 * This is not in "tdd" (titlebar_draw_descr), because these are needed
+ 	 * to draw the buttons with UseTitleStyle */
+ 	just = TB_JUSTIFICATION(GetDecor(fw, titlebar));
+ 	if (fw->visible_name != (char *)NULL)
+ 	{
+ 		ret_td->length = FlocaleTextWidth(
+-			fw->title_font, fw->visible_name,
+-			(ret_td->has_vt) ? -strlen(fw->visible_name) :
+-			strlen(fw->visible_name));
++			do_hilight ? fw->title_font : fw->inactive_title_font,
++			fw->visible_name, (ret_td->has_vt) ?
++			-strlen(fw->visible_name) : strlen(fw->visible_name));
+ 		if (ret_td->length > fw->title_length -
+ 		    2*MIN_WINDOW_TITLE_TEXT_OFFSET)
+ 		{
+ 			ret_td->length = fw->title_length -
+ 				2*MIN_WINDOW_TITLE_TEXT_OFFSET;
+ 			just = JUST_CENTER;
+ 		}
+ 		if (ret_td->length < 0)
+ 		{
+ 			ret_td->length = 0;
+@@ -4377,21 +4380,21 @@ static void border_draw_titlebar(
+ 		cd, fw, pressed_parts, pressed_button, force_draw_parts,
+ 		clear_parts, old_g, new_g, do_hilight, &td);
+ 	if ((draw_parts & PART_TITLE) != PART_NONE ||
+ 	    (draw_parts & PART_BUTTONS) != PART_NONE)
+ 	{
+ 		/* set up UseTitleStyle Colorset */
+ 		border_setup_use_title_style(fw, &td);
+ 	}
+ 	if ((draw_parts & PART_TITLE) != PART_NONE)
+ 	{
+-		border_draw_title(fw, &td);
++		border_draw_title(fw, &td, do_hilight);
+ 	}
+ 	if ((draw_parts & PART_BUTTONS) != PART_NONE)
+ 	{
+ 		border_draw_buttons(fw, &td);
+ 	}
+ 	border_free_bar_pixmaps(&(td.cd->dynamic_cd));
+ 
+ 	/* update the decor states */
+ 	fw->decor_state.parts_drawn |= draw_parts;
+ 	if (do_hilight)
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/fvwm.h fvwm-2.5.21-07/fvwm/fvwm.h
+--- fvwm-2.5.21-06/fvwm/fvwm.h	2007-03-03 13:19:10.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/fvwm.h	2007-03-03 13:19:35.000000000 +0100
+@@ -264,20 +264,21 @@ typedef struct
+ 		unsigned use_icon_position_hint : 1;
+ 		unsigned use_indexed_window_name : 1;
+ 		unsigned use_indexed_icon_name : 1;
+ #define WINDOWSHADE_LAZY          0
+ #define WINDOWSHADE_ALWAYS_LAZY   1
+ #define WINDOWSHADE_BUSY          2
+ #define WINDOWSHADE_LAZY_MASK   0x3
+ 		unsigned windowshade_laziness : 2;
+ 		unsigned use_title_decor_rotation : 1;
+ 		unsigned has_border_under_title : 1;
++		unsigned has_fluxbox_handles : 1;
+ 		focus_policy_t focus_policy;
+ 	} s;
+ } common_flags_t;
+ 
+ typedef struct
+ {
+ 	common_flags_t common;
+ #define CR_MOTION_METHOD_AUTO        0
+ #define CR_MOTION_METHOD_USE_GRAV    1
+ #define CR_MOTION_METHOD_STATIC_GRAV 2
+@@ -519,20 +520,21 @@ typedef struct
+ 	unsigned do_save_under : 1;
+ 	unsigned do_start_iconic : 1;
+ 	unsigned do_start_lowered : 1;
+ 	unsigned has_border_width : 1;
+ 	unsigned has_color_back : 1;
+ 	unsigned has_color_fore : 1;
+ 	unsigned has_color_back_hi : 1;
+ 	unsigned has_color_fore_hi : 1;
+ 	unsigned has_decor : 1;
+ 	unsigned has_handle_width : 1;
++	unsigned has_corner_width : 1;
+ 	unsigned has_icon : 1;
+ 	unsigned has_icon_boxes : 1;
+ 	unsigned has_icon_size_limits : 1;
+ 	unsigned has_max_window_size : 1;
+ 	unsigned has_icon_background_padding : 1;
+ 	unsigned has_icon_background_relief : 1;
+ 	unsigned has_icon_title_relief : 1;
+ 	unsigned has_window_shade_steps : 1;
+ 	unsigned has_mini_icon : 1;
+ 	unsigned has_mwm_decor : 1;
+@@ -622,20 +624,21 @@ typedef struct window_style
+ 	int colorset;
+ 	int colorset_hi;
+ 	int border_colorset;
+ 	int border_colorset_hi;
+ 	int icon_title_colorset;
+ 	int icon_title_colorset_hi;
+ 	int icon_background_colorset;
+ 	short border_width;
+ 	/* resize handle width */
+ 	short handle_width;
++	short corner_width;
+ 	int layer;
+ 	int start_desk;
+ 	int start_page_x;
+ 	int start_page_y;
+ 	int start_screen;
+ 	int max_window_width;
+ 	int max_window_height;
+ 	int shade_anim_steps;
+ 	icon_boxes *icon_boxes;
+ 	float norm_placement_penalty;
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/fvwm.h~ fvwm-2.5.21-07/fvwm/fvwm.h~
+--- fvwm-2.5.21-06/fvwm/fvwm.h~	2007-03-03 13:19:02.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/fvwm.h~	2007-03-03 13:19:27.000000000 +0100
+@@ -191,20 +191,21 @@ typedef struct
+ } ewmh_strut;
+ 
+ typedef struct
+ {
+ 	/* common flags (former flags in bits 0-12) */
+ 	unsigned is_sticky_across_pages : 1;
+ 	unsigned is_sticky_across_desks : 1;
+ 	unsigned has_icon_font : 1;
+ 	unsigned has_no_border : 1;
+ 	unsigned has_window_font : 1;
++	unsigned has_inactive_window_font : 1;
+ 	unsigned title_dir : 2;
+ 	unsigned user_states : 32;
+ 	/* static flags that do not change dynamically after the window has
+ 	 * been created */
+ 	struct
+ 	{
+ 		unsigned do_circulate_skip : 1;
+ 		unsigned do_circulate_skip_icon : 1;
+ 		unsigned do_circulate_skip_shaded : 1;
+ 		unsigned do_ewmh_donate_icon : 1;
+@@ -354,25 +355,27 @@ typedef struct
+ 	unsigned is_style_deleted : 1;
+ 	/* the window is a torn out fvwm menu */
+ 	unsigned is_tear_off_menu : 1;
+ 	/* is it a transient window? */
+ 	unsigned is_transient : 1;
+ 	unsigned is_window_drawn_once : 1;
+ 	/* To prevent double move in MoveViewport.*/
+ 	unsigned is_viewport_moved : 1;
+ 	unsigned is_window_being_moved_opaque : 1;
+ 	unsigned is_window_font_loaded : 1;
++	unsigned is_inactive_window_font_loaded : 1;
+ 	unsigned is_window_shaded : 1;
+ 	unsigned used_title_dir_for_shading : 1;
+ 	unsigned shaded_dir : 3;
+ 	unsigned using_default_icon_font : 1;
+ 	unsigned using_default_window_font : 1;
++	unsigned using_default_inactive_window_font : 1;
+ #define ICON_HINT_NEVER    0
+ #define ICON_HINT_ONCE     1
+ #define ICON_HINT_MULTIPLE 2
+ 	unsigned was_icon_hint_provided : 2;
+ 	unsigned was_icon_name_provided : 1;
+ 	unsigned was_never_drawn : 1;
+ 	unsigned has_ewmh_wm_name : 1;
+ 	unsigned has_ewmh_wm_icon_name : 1;
+ #define EWMH_NO_ICON     0 /* the application does not provide an ewmh icon */
+ #define EWMH_TRUE_ICON   1 /* the application does provide an ewmh icon */
+@@ -604,20 +607,21 @@ typedef struct window_style
+ #define ICON_RESIZE_TYPE_STRETCHED 0x1
+ #define ICON_RESIZE_TYPE_ADJUSTED  0x2
+ #define ICON_RESIZE_TYPE_SHRUNK    0x3
+ #define ICON_RESIZE_TYPE_MASK      0x3
+ 	unsigned icon_resize_type : 2;
+ 	unsigned char icon_background_padding;
+ 	signed char icon_background_relief;
+ 	signed char icon_title_relief;
+ 	char *icon_font;
+ 	char *window_font;
++	char *inactive_window_font;
+ 	char *fore_color_name;
+ 	char *back_color_name;
+ 	char *fore_color_name_hi;
+ 	char *back_color_name_hi;
+ 	int colorset;
+ 	int colorset_hi;
+ 	int border_colorset;
+ 	int border_colorset_hi;
+ 	int icon_title_colorset;
+ 	int icon_title_colorset_hi;
+@@ -731,20 +735,21 @@ typedef struct FvwmWindow
+ 
+ 	/* Note: if the type of this variable is changed, do update the
+ 	 * CONFIGARGSNEW macro in module_interface.c, libs/vpacket.h too! */
+ 	short boundary_width;
+ 	short unshaped_boundary_width;
+ 	short corner_width;
+ 	short visual_corner_width;
+ 
+ 	/* title font */
+ 	FlocaleFont *title_font;
++	FlocaleFont *inactive_title_font;
+ 	/* /Y coordinate to draw the title name */
+ 	short title_text_offset;
+ 	short title_length;
+ 	/* Note: if the type of this variable is changed, do update the
+ 	 * CONFIGARGSNEW macro in module_interface.c, libs/vpacket.h and too!
+ 	 */
+ 	short title_thickness;
+ 	rotation_t title_text_rotation;
+ 	struct
+ 	{
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/geometry.c fvwm-2.5.21-07/fvwm/geometry.c
+--- fvwm-2.5.21-06/fvwm/geometry.c	2007-03-03 13:19:02.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/geometry.c	2007-03-03 13:19:35.000000000 +0100
+@@ -473,30 +473,32 @@ void get_shaded_client_window_pos(
+ void get_window_borders(
+ 	const FvwmWindow *fw, size_borders *borders)
+ {
+ 	__get_window_borders(fw, borders, 0);
+ }
+ 
+ static void __get_window_borders(
+ 	const FvwmWindow *fw, size_borders *borders, Bool is_shaded)
+ {
+ 	int title_thickness;
++	int bw;
+ 	
+-	borders->top_left.width = fw->boundary_width;
+-	borders->bottom_right.width = fw->boundary_width;
+-	borders->top_left.height = fw->boundary_width;
++	bw = HAS_FLUXBOX_HANDLES(fw) ? 1 : fw->boundary_width;
++	borders->top_left.width = bw;
++	borders->bottom_right.width = bw;
++	borders->top_left.height = bw;
+ 	borders->bottom_right.height = fw->boundary_width;
+ 
+ 	title_thickness = fw->title_thickness;
+ 	if (HAS_TITLE(fw) && HAS_BORDER_UNDER_TITLE(fw) && !is_shaded)
+ 	{
+-		title_thickness += fw->boundary_width;
++		title_thickness += bw;
+ 	}
+ 	
+ 	switch (GET_TITLE_DIR(fw))
+ 	{
+ 	case DIR_N:
+ 		borders->top_left.height += title_thickness;
+ 		break;
+ 	case DIR_S:
+ 		borders->bottom_right.height += title_thickness;
+ 		break;
+@@ -512,23 +514,27 @@ static void __get_window_borders(
+ 	borders->total_size.height =
+ 		borders->top_left.height + borders->bottom_right.height;
+ 
+ 	return;
+ }
+ 
+ /* returns the dimensions of the borders without the title */
+ void get_window_borders_no_title(
+ 	const FvwmWindow *fw, size_borders *borders)
+ {
+-	borders->top_left.width = fw->boundary_width;
+-	borders->bottom_right.width = fw->boundary_width;
+-	borders->top_left.height = fw->boundary_width;
++	int bw;
++
++	bw = HAS_FLUXBOX_HANDLES(fw) ? 1 : fw->boundary_width;
++
++	borders->top_left.width = bw;
++	borders->bottom_right.width = bw;
++	borders->top_left.height = bw;
+ 	borders->bottom_right.height = fw->boundary_width;
+ 	borders->total_size.width =
+ 		borders->top_left.width + borders->bottom_right.width;
+ 	borders->total_size.height =
+ 		borders->top_left.height + borders->bottom_right.height;
+ 
+ 	return;
+ }
+ 
+ void set_window_border_size(
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/geometry.c~ fvwm-2.5.21-07/fvwm/geometry.c~
+--- fvwm-2.5.21-06/fvwm/geometry.c~	2007-03-03 13:19:02.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/geometry.c~	2007-03-03 13:19:27.000000000 +0100
+@@ -39,20 +39,23 @@
+ /* ---------------------------- local macros ------------------------------- */
+ 
+ /* ---------------------------- imports ------------------------------------ */
+ 
+ /* ---------------------------- included code files ------------------------ */
+ 
+ /* ---------------------------- local types -------------------------------- */
+ 
+ /* ---------------------------- forward declarations ----------------------- */
+ 
++static void __get_window_borders(
++	const FvwmWindow *fw, size_borders *borders, Bool is_shaded);
++
+ /* ---------------------------- local variables ---------------------------- */
+ 
+ /* ---------------------------- exported variables (globals) --------------- */
+ 
+ /* ---------------------------- local functions ---------------------------- */
+ 
+ /* ---------------------------- interface functions ------------------------ */
+ 
+ /* Removes decorations from the source rectangle and moves it according to the
+  * gravity specification. */
+@@ -336,21 +339,22 @@ void get_icon_corner(
+ void get_shaded_geometry(
+ 	FvwmWindow *fw, rectangle *small_g, rectangle *big_g)
+ {
+ 	size_borders b;
+ 	/* this variable is necessary so the function can be called with
+ 	 * small_g == big_g */
+ 	int big_width = big_g->width;
+ 	int big_height = big_g->height;
+ 	int d;
+ 
+-	get_window_borders(fw, &b);
++	__get_window_borders(fw, &b, 1);
++	
+ 	*small_g = *big_g;
+ 	d = 0;
+ 	switch (SHADED_DIR(fw))
+ 	{
+ 	case DIR_S:
+ 	case DIR_SW:
+ 	case DIR_SE:
+ 		small_g->y = big_g->y + big_height - b.total_size.height;
+ 		d = 1;
+ 		/* fall through */
+@@ -462,37 +466,52 @@ void get_shaded_client_window_pos(
+ 		break;
+ 	}
+ 
+ 	return;
+ }
+ 
+ /* returns the dimensions of the borders */
+ void get_window_borders(
+ 	const FvwmWindow *fw, size_borders *borders)
+ {
++	__get_window_borders(fw, borders, 0);
++}
++
++static void __get_window_borders(
++	const FvwmWindow *fw, size_borders *borders, Bool is_shaded)
++{
++	int title_thickness;
++	
+ 	borders->top_left.width = fw->boundary_width;
+ 	borders->bottom_right.width = fw->boundary_width;
+ 	borders->top_left.height = fw->boundary_width;
+ 	borders->bottom_right.height = fw->boundary_width;
++
++	title_thickness = fw->title_thickness;
++	if (HAS_TITLE(fw) && HAS_BORDER_UNDER_TITLE(fw) && !is_shaded)
++	{
++		title_thickness += fw->boundary_width;
++	}
++	
+ 	switch (GET_TITLE_DIR(fw))
+ 	{
+ 	case DIR_N:
+-		borders->top_left.height += fw->title_thickness;
++		borders->top_left.height += title_thickness;
+ 		break;
+ 	case DIR_S:
+-		borders->bottom_right.height += fw->title_thickness;
++		borders->bottom_right.height += title_thickness;
+ 		break;
+ 	case DIR_W:
+-		borders->top_left.width += fw->title_thickness;
++		borders->top_left.width += title_thickness;
+ 		break;
+ 	case DIR_E:
+-		borders->bottom_right.width += fw->title_thickness;
++		borders->bottom_right.width += title_thickness;
+ 		break;
+ 	}
+ 	borders->total_size.width =
+ 		borders->top_left.width + borders->bottom_right.width;
+ 	borders->total_size.height =
+ 		borders->top_left.height + borders->bottom_right.height;
+ 
+ 	return;
+ }
+ 
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/style.c fvwm-2.5.21-07/fvwm/style.c
+--- fvwm-2.5.21-06/fvwm/style.c	2007-03-03 13:19:10.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/style.c	2007-03-03 13:19:35.000000000 +0100
+@@ -513,20 +513,24 @@ static void merge_styles(
+ 		}
+ 	}
+ 	if (add_style->flags.has_border_width)
+ 	{
+ 		SSET_BORDER_WIDTH(*merged_style, SGET_BORDER_WIDTH(*add_style));
+ 	}
+ 	if (add_style->flags.has_handle_width)
+ 	{
+ 		SSET_HANDLE_WIDTH(*merged_style, SGET_HANDLE_WIDTH(*add_style));
+ 	}
++	if (add_style->flags.has_corner_width)
++	{
++		SSET_CORNER_WIDTH(*merged_style, SGET_CORNER_WIDTH(*add_style));
++	}
+ 	if (add_style->flags.has_icon_size_limits)
+ 	{
+ 		SSET_MIN_ICON_WIDTH(
+ 			*merged_style, SGET_MIN_ICON_WIDTH(*add_style));
+ 		SSET_MIN_ICON_HEIGHT(
+ 			*merged_style, SGET_MIN_ICON_HEIGHT(*add_style));
+ 		SSET_MAX_ICON_WIDTH(
+ 			*merged_style, SGET_MAX_ICON_WIDTH(*add_style));
+ 		SSET_MAX_ICON_HEIGHT(
+ 			*merged_style, SGET_MAX_ICON_HEIGHT(*add_style));
+@@ -2280,20 +2284,34 @@ static Bool style_parse_one_style_option
+ 					" color argument.");
+ 				break;
+ 			}
+ 			SAFEFREE(SGET_BACK_COLOR_NAME(*ps));
+ 			SSET_BACK_COLOR_NAME(*ps, token);
+ 			ps->flags.has_color_back = 1;
+ 			ps->flag_mask.has_color_back = 1;
+ 			ps->change_mask.has_color_back = 1;
+ 			break;
+ 		}
++		else if (StrEquals(token, "CornerWidth"))
++		{
++			if (GetIntegerArguments(rest, &rest, val, 1))
++			{
++				SSET_CORNER_WIDTH(*ps, (short)*val);
++				ps->flags.has_corner_width = 1;
++			}
++			else
++			{
++				ps->flags.has_corner_width = 0;
++			}
++			ps->flag_mask.has_corner_width = 1;
++			ps->change_mask.has_corner_width = 1;
++		}		
+ 		else if (StrEquals(token, "CirculateSkipIcon"))
+ 		{
+ 			S_SET_DO_CIRCULATE_SKIP_ICON(SCF(*ps), on);
+ 			S_SET_DO_CIRCULATE_SKIP_ICON(SCM(*ps), 1);
+ 			S_SET_DO_CIRCULATE_SKIP_ICON(SCC(*ps), 1);
+ 		}
+ 		else if (StrEquals(token, "CirculateSkipShaded"))
+ 		{
+ 			S_SET_DO_CIRCULATE_SKIP_SHADED(SCF(*ps), on);
+ 			S_SET_DO_CIRCULATE_SKIP_SHADED(SCM(*ps), 1);
+@@ -2496,20 +2514,26 @@ static Bool style_parse_one_style_option
+ 			S_SET_HAS_MWM_BUTTONS(SCF(*ps), !on);
+ 			S_SET_HAS_MWM_BUTTONS(SCM(*ps), 1);
+ 			S_SET_HAS_MWM_BUTTONS(SCC(*ps), 1);
+ 		}
+ 		else if (StrEquals(token, "FVWMBORDER"))
+ 		{
+ 			S_SET_HAS_MWM_BORDER(SCF(*ps), !on);
+ 			S_SET_HAS_MWM_BORDER(SCM(*ps), 1);
+ 			S_SET_HAS_MWM_BORDER(SCC(*ps), 1);
+ 		}
++		else if (StrEquals(token, "FluxboxHandles"))
++		{
++			S_SET_HAS_FLUXBOX_HANDLES(SCF(*ps), on);
++			S_SET_HAS_FLUXBOX_HANDLES(SCM(*ps), 1);
++			S_SET_HAS_FLUXBOX_HANDLES(SCC(*ps), 1);
++		}
+ 		else if (StrEquals(token, "FocusFollowsMouse"))
+ 		{
+ 			style_set_old_focus_policy(ps, 1);
+ 		}
+ 		else if (StrEquals(token, "FirmBorder"))
+ 		{
+ 			S_SET_HAS_DEPRESSABLE_BORDER(SCF(*ps), !on);
+ 			S_SET_HAS_DEPRESSABLE_BORDER(SCM(*ps), 1);
+ 			S_SET_HAS_DEPRESSABLE_BORDER(SCC(*ps), 1);
+ 		}
+@@ -4448,20 +4472,26 @@ void check_window_style_change(
+ 	if (S_TITLE_DIR(SCC(*ret_style)))
+ 	{
+ 		flags->do_update_title_dir = 1;
+ 	}
+ 
+ 	/* use_title_decor_rotation */
+ 	if (S_USE_TITLE_DECOR_ROTATION(SCC(*ret_style)))
+ 	{
+ 		flags->do_update_rotated_title = 1;
+ 	}
++
++	/* has_fluxbox_handles */
++	if (S_HAS_FLUXBOX_HANDLES(SCC(*ret_style)))
++	{
++		flags->do_redecorate = True;
++	}
+ 	
+ 	if (S_HAS_BORDER_UNDER_TITLE(SCC(*ret_style)))
+ 	{
+ 		flags->do_redecorate = True;
+ 	}
+ 
+ 	/* has_mwm_border
+ 	 * has_mwm_buttons */
+ 	if (S_HAS_MWM_BORDER(SCC(*ret_style)) ||
+ 	    S_HAS_MWM_BUTTONS(SCC(*ret_style)))
+@@ -4698,20 +4728,26 @@ void check_window_style_change(
+ 	    ret_style->change_mask.has_mwm_decor ||
+ 	    ret_style->change_mask.has_mwm_functions ||
+ 	    ret_style->change_mask.has_no_handles ||
+ 	    ret_style->change_mask.is_button_disabled)
+ 	{
+ 		flags->do_redecorate = 1;
+ 		flags->do_update_ewmh_allowed_actions = 1;
+ 		flags->do_update_modules_flags = 1;
+ 	}
+ 
++	/* has_corner_width */
++	if (ret_style->change_mask.has_corner_width)
++	{
++		flags->do_redecorate = True;
++	}
++
+ 	if (ret_style->change_mask.do_save_under ||
+ 	    ret_style->change_mask.use_backing_store ||
+ 	    ret_style->change_mask.use_parent_relative)
+ 	{
+ 		flags->do_update_frame_attributes = 1;
+ 	}
+ 
+ 	if (ret_style->change_mask.use_parent_relative &&
+ 	    ret_style->flags.use_parent_relative)
+ 	{
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/style.c~ fvwm-2.5.21-07/fvwm/style.c~
+--- fvwm-2.5.21-06/fvwm/style.c~	2007-03-03 13:19:02.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/style.c~	2007-03-03 13:19:27.000000000 +0100
+@@ -402,20 +402,36 @@ static void merge_styles(
+ 				*merged_style, (SGET_WINDOW_FONT(*add_style)) ?
+ 				safestrdup(SGET_WINDOW_FONT(*add_style)) :
+ 				NULL);
+ 		}
+ 		else
+ 		{
+ 			SSET_WINDOW_FONT(
+ 				*merged_style, SGET_WINDOW_FONT(*add_style));
+ 		}
+ 	}
++	if (S_HAS_INACTIVE_WINDOW_FONT(SCF(*add_style)))
++	{
++		if (do_free_src_and_alloc_copy)
++		{
++			SAFEFREE(SGET_INACTIVE_WINDOW_FONT(*merged_style));
++			SSET_INACTIVE_WINDOW_FONT(
++				*merged_style, (SGET_INACTIVE_WINDOW_FONT(*add_style)) ?
++				safestrdup(SGET_INACTIVE_WINDOW_FONT(*add_style)) :
++				NULL);
++		}
++		else
++		{
++			SSET_INACTIVE_WINDOW_FONT(
++				*merged_style, SGET_INACTIVE_WINDOW_FONT(*add_style));
++		}
++	}
+ 	if (add_style->flags.use_start_on_desk)
+ 	{
+ 		SSET_START_DESK(*merged_style, SGET_START_DESK(*add_style));
+ 		SSET_START_PAGE_X(
+ 			*merged_style, SGET_START_PAGE_X(*add_style));
+ 		SSET_START_PAGE_Y(
+ 			*merged_style, SGET_START_PAGE_Y(*add_style));
+ 	}
+ 	if (add_style->flags.use_start_on_screen)
+ 	{
+@@ -728,20 +744,24 @@ static void free_style_mask(window_style
+ 		SAFEFREE(SGET_DECOR_NAME(*style));
+ 	}
+ 	if (pmask->common.has_icon_font)
+ 	{
+ 		SAFEFREE(SGET_ICON_FONT(*style));
+ 	}
+ 	if (pmask->common.has_window_font)
+ 	{
+ 		SAFEFREE(SGET_WINDOW_FONT(*style));
+ 	}
++	if (pmask->common.has_inactive_window_font)
++	{
++		SAFEFREE(SGET_INACTIVE_WINDOW_FONT(*style));
++	}
+ 	if (pmask->has_icon)
+ 	{
+ 		SAFEFREE(SGET_ICON_NAME(*style));
+ 	}
+ 	if (pmask->has_mini_icon)
+ 	{
+ 		SAFEFREE(SGET_MINI_ICON_NAME(*style));
+ 	}
+ 	if (pmask->has_icon_boxes)
+ 	{
+@@ -2832,20 +2852,29 @@ static Bool style_parse_one_style_option
+ 			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCF(*ps), !on);
+ 			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCM(*ps), 1);
+ 			S_SET_DO_ICONIFY_WINDOW_GROUPS(SCC(*ps), 1);
+ 		}
+ 		else if (StrEquals(token, "Iconifiable"))
+ 		{
+ 			S_SET_IS_UNICONIFIABLE(SCF(*ps), !on);
+ 			S_SET_IS_UNICONIFIABLE(SCM(*ps), 1);
+ 			S_SET_IS_UNICONIFIABLE(SCC(*ps), 1);
+ 		}
++		else if (StrEquals(token, "InactiveFont"))
++		{
++			SAFEFREE(SGET_INACTIVE_WINDOW_FONT(*ps));
++			rest = GetNextToken(rest, &token);
++			SSET_INACTIVE_WINDOW_FONT(*ps, token);
++			S_SET_HAS_INACTIVE_WINDOW_FONT(SCF(*ps), (token != NULL));
++			S_SET_HAS_INACTIVE_WINDOW_FONT(SCM(*ps), 1);
++			S_SET_HAS_INACTIVE_WINDOW_FONT(SCC(*ps), 1);
++		}
+ 		else if (StrEquals(token, "IndexedWindowName"))
+ 		{
+ 			S_SET_USE_INDEXED_WINDOW_NAME(SCF(*ps), on);
+ 			S_SET_USE_INDEXED_WINDOW_NAME(SCM(*ps), 1);
+ 			S_SET_USE_INDEXED_WINDOW_NAME(SCC(*ps), 1);
+ 		}
+ 		else if (StrEquals(token, "IndexedIconName"))
+ 		{
+ 			S_SET_USE_INDEXED_ICON_NAME(SCF(*ps), on);
+ 			S_SET_USE_INDEXED_ICON_NAME(SCM(*ps), 1);
+@@ -4445,20 +4474,26 @@ void check_window_style_change(
+ 	{
+ 		flags->do_update_icon_font = 1;
+ 	}
+ 
+ 	/* has_window_font */
+ 	if (S_HAS_WINDOW_FONT(SCC(*ret_style)))
+ 	{
+ 		flags->do_update_window_font = 1;
+ 	}
+ 
++	/* has_inactive_window_font */
++	if (S_HAS_INACTIVE_WINDOW_FONT(SCC(*ret_style)))
++	{
++		flags->do_update_window_font = True;
++	}
++
+ 	/* has_stippled_title */
+ 	if (S_HAS_STIPPLED_TITLE(SCC(*ret_style)) ||
+ 	    S_HAS_NO_STICKY_STIPPLED_TITLE(SCC(*ret_style)) ||
+ 	    S_HAS_STIPPLED_ICON_TITLE(SCC(*ret_style)) ||
+ 	    S_HAS_NO_STICKY_STIPPLED_ICON_TITLE(SCC(*ret_style)))
+ 	{
+ 		flags->do_redraw_decoration = 1;
+ 	}
+ 
+ 	/* has_no_icon_title
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/style.h fvwm-2.5.21-07/fvwm/style.h
+--- fvwm-2.5.21-06/fvwm/style.h	2007-03-03 13:19:10.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/style.h	2007-03-03 13:19:35.000000000 +0100
+@@ -12,20 +12,22 @@
+ #define SDO_START_LOWERED(sf) \
+ 	((sf)->do_start_lowered)
+ #define SHAS_BORDER_WIDTH(sf) \
+ 	((sf)->has_border_width)
+ #define SHAS_COLOR_BACK(sf) \
+ 	((sf)->has_color_back)
+ #define SHAS_COLOR_FORE(sf) \
+ 	((sf)->has_color_fore)
+ #define SHAS_HANDLE_WIDTH(sf) \
+ 	((sf)->has_handle_width)
++#define SHAS_CORNER_WIDTH(sf) \
++	((sf)->has_corner_width)
+ #define SHAS_ICON(sf) \
+ 	((sf)->has_icon)
+ #define SHAS_ICON_BOXES(sf) \
+ 	((sf)->has_icon_boxes)
+ #define SHAS_ICON_SIZE_LIMITS(sf) \
+ 	((sf)->has_icon_size_limits)
+ #define SHAS_ICON_BACKGROUND_PADDING(sf) \
+ 	((sf)->has_icon_background_padding)
+ #define SHAS_ICON_BACKGROUND_RELIEF(sf) \
+ 	((sf)->has_icon_background_relief)
+@@ -336,20 +338,24 @@
+ #define S_SET_WINDOWSHADE_LAZINESS(c,x) \
+ 	((c).s.windowshade_laziness = (x))
+ #define S_USE_TITLE_DECOR_ROTATION(c) \
+ 	((c).s.use_title_decor_rotation)
+ #define S_SET_USE_TITLE_DECOR_ROTATION(c,x) \
+ 	((c).s.use_title_decor_rotation = !!(x))
+ #define S_HAS_BORDER_UNDER_TITLE(c) \
+ 	((c).s.has_border_under_title)
+ #define S_SET_HAS_BORDER_UNDER_TITLE(c,x) \
+ 	((c).s.has_border_under_title = !!(x))
++#define S_HAS_FLUXBOX_HANDLES(c) \
++	((c).s.has_fluxbox_handles)
++#define S_SET_HAS_FLUXBOX_HANDLES(c,x) \
++	((c).s.has_fluxbox_handles = !!(x))
+ #define S_DO_EWMH_MINI_ICON_OVERRIDE(c) \
+ 	((c).s.do_ewmh_mini_icon_override)
+ #define S_SET_DO_EWMH_MINI_ICON_OVERRIDE(c,x) \
+ 	((c).s.do_ewmh_mini_icon_override = !!(x))
+ #define S_DO_EWMH_DONATE_ICON(c) \
+ 	((c).s.do_ewmh_donate_icon)
+ #define S_SET_DO_EWMH_DONATE_ICON(c,x) \
+ 	((c).s.do_ewmh_donate_icon = !!(x))
+ #define S_DO_EWMH_DONATE_MINI_ICON(c) \
+ 	((c).s.do_ewmh_donate_mini_icon)
+@@ -494,20 +500,24 @@
+ #define SGET_FLAGS_POINTER(s) \
+ 	(&((s).flags))
+ #define SGET_BORDER_WIDTH(s) \
+ 	((s).border_width)
+ #define SSET_BORDER_WIDTH(s,x) \
+ 	((s).border_width = (x))
+ #define SGET_HANDLE_WIDTH(s) \
+ 	((s).handle_width)
+ #define SSET_HANDLE_WIDTH(s,x) \
+ 	((s).handle_width = (x))
++#define SGET_CORNER_WIDTH(s) \
++	((s).corner_width)
++#define SSET_CORNER_WIDTH(s,x) \
++	((s).corner_width = (x))
+ #define SGET_LAYER(s) \
+ 	((s).layer)
+ #define SSET_LAYER(s,x) \
+ 	((s).layer = (x))
+ #define SGET_START_DESK(s) \
+ 	((s).start_desk)
+ #define SSET_START_DESK(s,x) \
+ 	((s).start_desk = (x))
+ #define SGET_START_PAGE_X(s) \
+ 	((s).start_page_x)
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/style.h~ fvwm-2.5.21-07/fvwm/style.h~
+--- fvwm-2.5.21-06/fvwm/style.h~	2007-03-03 13:19:02.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/style.h~	2007-03-03 13:19:27.000000000 +0100
+@@ -252,20 +252,24 @@
+ #define S_SET_HAS_NO_STICKY_STIPPLED_TITLE(c,x) \
+ 	((c).s.has_no_sticky_stippled_title = !!(x))
+ #define S_HAS_STIPPLED_ICON_TITLE(c) \
+ 	((c).s.has_stippled_icon_title)
+ #define S_SET_HAS_STIPPLED_ICON_TITLE(c,x) \
+ 	((c).s.has_stippled_icon_title = !!(x))
+ #define S_HAS_WINDOW_FONT(c) \
+ 	((c).has_window_font)
+ #define S_SET_HAS_WINDOW_FONT(c,x) \
+ 	((c).has_window_font = !!(x))
++#define S_HAS_INACTIVE_WINDOW_FONT(c) \
++	((c).has_inactive_window_font)
++#define S_SET_HAS_INACTIVE_WINDOW_FONT(c,x) \
++	((c).has_inactive_window_font = !!(x))
+ #define S_ICON_OVERRIDE(c) \
+ 	((c).s.icon_override)
+ #define S_SET_ICON_OVERRIDE(c,x) \
+ 	((c).s.icon_override = (x))
+ #define S_IS_BOTTOM_TITLE_ROTATED(c) \
+ 	((c).s.is_bottom_title_rotated)
+ #define S_SET_IS_BOTTOM_TITLE_ROTATED(c,x) \
+ 	((c).s.is_bottom_title_rotated = !!(x))
+ #define S_IS_FIXED(c) \
+ 	((c).s.is_fixed)
+@@ -448,20 +452,24 @@
+ #define SSET_BACK_COLOR_NAME_HI(s,x) \
+ 	((s).back_color_name_hi = (x))
+ #define SGET_ICON_FONT(s) \
+ 	((s).icon_font)
+ #define SSET_ICON_FONT(s,x) \
+ 	((s).icon_font = (x))
+ #define SGET_WINDOW_FONT(s) \
+ 	((s).window_font)
+ #define SSET_WINDOW_FONT(s,x) \
+ 	((s).window_font = (x))
++#define SGET_INACTIVE_WINDOW_FONT(s) \
++	((s).inactive_window_font)
++#define SSET_INACTIVE_WINDOW_FONT(s,x) \
++	((s).inactive_window_font = (x))
+ #define SGET_COLORSET(s) \
+ 	((s).colorset)
+ #define SSET_COLORSET(s,x) \
+ 	((s).colorset = (x))
+ #define SSET_BORDER_COLORSET(s,x) \
+ 	((s).border_colorset = (x))
+ #define SGET_BORDER_COLORSET(s) \
+ 	((s).border_colorset)
+ #define SGET_COLORSET_HI(s) \
+ 	((s).colorset_hi)
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/window_flags.h fvwm-2.5.21-07/fvwm/window_flags.h
+--- fvwm-2.5.21-06/fvwm/window_flags.h	2007-03-03 13:19:10.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/window_flags.h	2007-03-03 13:19:35.000000000 +0100
+@@ -327,20 +327,26 @@
+ #define SET_USE_TITLE_DECOR_ROTATION(fw,x) \
+ 	(fw)->flags.common.s.use_title_decor_rotation = !!(x)
+ #define SETM_USE_TITLE_DECOR_ROTATION(fw,x) \
+ 	(fw)->flag_mask.common.s.use_title_decor_rotation = !!(x)
+ #define HAS_BORDER_UNDER_TITLE(fw) \
+ 	((fw)->flags.common.s.has_border_under_title)
+ #define SET_HAS_BORDER_UNDER_TITLE(fw,x) \
+ 	(fw)->flags.common.s.has_border_under_title = !!(x)
+ #define SETM_HAS_BORDER_UNDER_TITLE(fw,x) \
+ 	(fw)->flag_mask.common.s.has_border_under_title = !!(x)
++#define HAS_FLUXBOX_HANDLES(fw) \
++	((fw)->flags.common.s.has_fluxbox_handles && (fw->flags.has_handles))
++#define SET_HAS_FLUXBOX_HANDLES(fw,x) \
++	(fw)->flags.common.s.has_fluxbox_handles = !!(x)
++#define SETM_HAS_FLUXBOX_HANDLES(fw,x) \
++	(fw)->flag_mask.common.s.has_fluxbox_handles = !!(x)
+ 
+ /* access to the special flags of a window */
+ #define DO_REUSE_DESTROYED(fw) \
+ 	((fw)->flags.do_reuse_destroyed)
+ #define SET_DO_REUSE_DESTROYED(fw,x) \
+ 	(fw)->flags.do_reuse_destroyed = !!(x)
+ #define SETM_DO_REUSE_DESTROYED(fw,x) \
+ 	(fw)->flag_mask.do_reuse_destroyed = !!(x)
+ #define HAS_NO_BORDER(fw) \
+ 	((fw)->flags.common.has_no_border)
+diff -U10 -Naupr fvwm-2.5.21-06/fvwm/window_flags.h~ fvwm-2.5.21-07/fvwm/window_flags.h~
+--- fvwm-2.5.21-06/fvwm/window_flags.h~	2007-03-03 13:19:02.000000000 +0100
++++ fvwm-2.5.21-07/fvwm/window_flags.h~	2007-03-03 13:19:27.000000000 +0100
+@@ -573,20 +573,26 @@
+ #define SET_WINDOW_BORDER_DRAWN(fw,x) \
+ 	(fw)->flags.is_window_border_drawn = !!(x)
+ #define SETM_WINDOW_BORDER_DRAWN(fw,x) \
+ 	(fw)->flag_mask.is_window_border_drawn = !!(x)
+ #define IS_WINDOW_FONT_LOADED(fw) \
+ 	((fw)->flags.is_window_font_loaded)
+ #define SET_WINDOW_FONT_LOADED(fw,x) \
+ 	(fw)->flags.is_window_font_loaded = !!(x)
+ #define SETM_WINDOW_FONT_LOADED(fw,x) \
+ 	(fw)->flag_mask.is_window_font_loaded = !!(x)
++#define IS_INACTIVE_WINDOW_FONT_LOADED(fw) \
++	((fw)->flags.is_inactive_window_font_loaded)
++#define SET_INACTIVE_WINDOW_FONT_LOADED(fw,x) \
++	(fw)->flags.is_inactive_window_font_loaded = !!(x)
++#define SETM_INACTIVE_WINDOW_FONT_LOADED(fw,x) \
++	(fw)->flag_mask.is_inactive_window_font_loaded = !!(x)
+ #define CR_MOTION_METHOD(fw) \
+ 	((fw)->flags.cr_motion_method)
+ #define SET_CR_MOTION_METHOD(fw,x) \
+ 	(fw)->flags.cr_motion_method = ((x) & CR_MOTION_METHOD_MASK)
+ #define SETM_CR_MOTION_METHOD(fw,x) \
+ 	(fw)->flag_mask.cr_motion_method = ((x) ? CR_MOTION_METHOD_MASK : 0)
+ #define WAS_CR_MOTION_METHOD_DETECTED(fw) \
+ 	((fw)->flags.was_cr_motion_method_detected)
+ #define SET_CR_MOTION_METHOD_DETECTED(fw,x) \
+ 	(fw)->flags.was_cr_motion_method_detected = !!(x)
+@@ -615,20 +621,26 @@
+ #define SET_FORCE_NEXT_PN(fw,x) \
+ 	(fw)->flags.do_force_next_pn = !!(x)
+ #define SETM_FORCE_NEXT_PN(fw,x) \
+ 	(fw)->flag_mask.do_force_next_pn = !!(x)
+ #define USING_DEFAULT_WINDOW_FONT(fw) \
+ 	((fw)->flags.using_default_window_font)
+ #define SET_USING_DEFAULT_WINDOW_FONT(fw,x) \
+ 	(fw)->flags.using_default_window_font = !!(x)
+ #define SETM_USING_DEFAULT_WINDOW_FONT(fw,x) \
+ 	(fw)->flag_mask.using_default_window_font = !!(x)
++#define USING_DEFAULT_INACTIVE_WINDOW_FONT(fw) \
++	((fw)->flags.using_default_inactive_window_font)
++#define SET_USING_DEFAULT_INACTIVE_WINDOW_FONT(fw,x) \
++	(fw)->flags.using_default_inactive_window_font = !!(x)
++#define SETM_USING_DEFAULT_INACTIVE_WINDOW_FONT(fw,x) \
++	(fw)->flag_mask.using_default_inactive_window_font = !!(x)
+ #define USING_DEFAULT_ICON_FONT(fw) \
+ 	((fw)->flags.using_default_icon_font)
+ #define SET_USING_DEFAULT_ICON_FONT(fw,x) \
+ 	(fw)->flags.using_default_icon_font = !!(x)
+ #define SETM_USING_DEFAULT_ICON_FONT(fw,x) \
+ 	(fw)->flag_mask.using_default_icon_font = !!(x)
+ #define WAS_ICON_HINT_PROVIDED(fw) \
+ 	((fw)->flags.was_icon_hint_provided)
+ #define SET_WAS_ICON_HINT_PROVIDED(fw,x) \
+ 	(fw)->flags.was_icon_hint_provided = (x)
diff --git a/windowmanagers/fvwm/patches/08-RoundedCorners.patch b/windowmanagers/fvwm/patches/08-RoundedCorners.patch
new file mode 100644
index 0000000..6c7a48f
--- /dev/null
+++ b/windowmanagers/fvwm/patches/08-RoundedCorners.patch
@@ -0,0 +1,3477 @@
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/add_window.c fvwm-2.5.21-08/fvwm/add_window.c
+--- fvwm-2.5.21-07/fvwm/add_window.c	2007-03-03 13:19:35.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/add_window.c	2007-03-03 13:20:06.000000000 +0100
+@@ -2563,20 +2563,22 @@ FvwmWindow *AddWindow(
+ 		    (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
+ 		    (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth))
+ 	{
+ 		/* The window has disappeared somehow.  For some reason we do
+ 		 * not always get a DestroyNotify on the window, so make sure
+ 		 * it is destroyed. */
+ 		destroy_window(fw);
+ 		fw = NULL;
+ 	}
+ 
++	frame_make_rounded_corners(fw);
++
+ 	return fw;
+ }
+ 
+ 
+ /*
+  *
+  *  Procedure:
+  *      FetchWMProtocols - finds out which protocols the window supports
+  *
+  *  Inputs:
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/add_window.c~ fvwm-2.5.21-08/fvwm/add_window.c~
+--- fvwm-2.5.21-07/fvwm/add_window.c~	2007-03-03 13:19:27.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/add_window.c~	2007-03-03 13:19:57.000000000 +0100
+@@ -1634,31 +1634,36 @@ void setup_wm_hints(FvwmWindow *fw)
+ 	set_focus_model(fw);
+ 
+ 	return;
+ }
+ 
+ void setup_title_geometry(
+ 	FvwmWindow *fw, window_style *pstyle)
+ {
+ 	int width;
+ 	int offset;
++	style_flags *sflags = &(pstyle->flags);
+ 
+ 	get_title_font_size_and_offset(
+ 		fw, S_TITLE_DIR(SCF(*pstyle)),
+ 		S_IS_LEFT_TITLE_ROTATED_CW(SCF(*pstyle)),
+ 		S_IS_RIGHT_TITLE_ROTATED_CW(SCF(*pstyle)),
+ 		S_IS_TOP_TITLE_ROTATED(SCF(*pstyle)),
+ 		S_IS_BOTTOM_TITLE_ROTATED(SCF(*pstyle)),
+ 		&width, &offset);
+ 	fw->title_thickness = width;
+ 	fw->title_text_offset = offset;
+ 	fw->corner_width = fw->title_thickness + fw->boundary_width;
++	if (SHAS_CORNER_WIDTH(sflags))
++	{
++		fw->corner_width = SGET_CORNER_WIDTH(*pstyle);
++	}
+ 	if (!HAS_TITLE(fw))
+ 	{
+ 		fw->title_thickness = 0;
+ 	}
+ 
+ 	return;
+ }
+ 
+ void setup_window_font(
+ 	FvwmWindow *fw, window_style *pstyle, Bool do_destroy)
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/frame.c fvwm-2.5.21-08/fvwm/frame.c
+--- fvwm-2.5.21-07/fvwm/frame.c	2007-03-03 13:19:27.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/frame.c	2007-03-03 13:20:06.000000000 +0100
+@@ -428,20 +428,22 @@ static void __frame_setup_window(
+ 	{
+ 		SendConfigureNotify(
+ 			fw, new_g.x, new_g.y, new_g.width, new_g.height, 0,
+ 			True);
+ 	}
+ 	/* get things updated */
+ 	XFlush(dpy);
+ 	/* inform the modules of the change */
+ 	BroadcastConfig(M_CONFIGURE_WINDOW,fw);
+ 
++	frame_make_rounded_corners(fw);
++
+ 	return;
+ }
+ 
+ static void frame_reparent_hide_windows(
+ 	Window w)
+ {
+ 	int i;
+ 
+ 	hide_wins.parent = w;
+ 	for (i = 0; i < 4 ; i++)
+@@ -1952,20 +1954,21 @@ void frame_free_move_resize_args(
+ 		FOCUS_SET(mra->w_with_focus);
+ 	}
+ 	if (mra->flags.do_update_shape)
+ 	{
+ 		/* unset shape */
+ 		FShapeCombineMask(
+ 			dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0, None,
+ 			FShapeSet);
+ 	}
+ 	frame_setup_shape(fw, mra->end_g.width, mra->end_g.height, fw->wShaped);
++	frame_make_rounded_corners(fw);
+ 	if (mra->flags.do_restore_gravity)
+ 	{
+ 		mra->grav.client_grav = fw->hints.win_gravity;
+ 		frame_set_decor_gravities(
+ 			fw, &mra->grav,
+ 			(mra->flags.do_set_bit_gravity) ? 2 : 0);
+ 	}
+ 	else
+ 	{
+ 		frame_restore_client_gravities(fw);
+@@ -2073,20 +2076,224 @@ void frame_force_setup_window(
+ 
+ 	g.x = x;
+ 	g.y = y;
+ 	g.width = w;
+ 	g.height = h;
+ 	__frame_setup_window(fw, &g, do_send_configure_notify, True, False);
+ 
+ 	return;
+ }
+ 
++void draw_rounded_mask(Window win, int width, int height, Bool slightlyrounded, window_parts draw_parts, int col)
++{
++	Pixmap pm;
++	GC gc;
++    rectangle rect;
++	int w,h;
++	unsigned long valuemask;
++	int x;
++	int lstart, lend;
++	int l0[] = { 0, 1, 0, 1, 2, 3 };
++	int l1[] = { 1, 2, 1, 2, 3, 5 };
++	int l2[] = { 2, 1, 5, 3, 2, 1 };
++	int l3[] = { 1, 1, 1, 1, 1, 2 };
++
++	if (slightlyrounded)
++	{
++		lstart = 0;
++		lend = 2;
++	}
++	else
++	{
++		lstart = 2;
++		lend = 6;
++	}
++
++    XGetGeometry(
++        dpy, win, &JunkRoot, &rect.x, &rect.y,
++        &rect.width, &rect.height, &JunkBW, &JunkDepth);
++
++	w = rect.width;
++	h = rect.height;
++	pm = XCreatePixmap(dpy, win, width, height, 1);
++	gc = Scr.MonoGC;
++	XSetForeground(dpy, gc, !col);
++	XFillRectangle(dpy, pm, gc, 0, 0, w, h);
++	XSetForeground(dpy, gc, col);
++
++	/* Draw a rounded shape on the corners of the pixmap */
++	for (x = lstart; x < lend; x++)
++	{
++ 		if (draw_parts & PART_BORDER_NW)
++ 		{
++			XFillRectangle(dpy, pm, gc, 0, l0[x], l2[x], l3[x]);
++ 		}
++ 		if (draw_parts & PART_BORDER_NE)
++ 		{
++			XFillRectangle(dpy, pm, gc, w-l2[x], l0[x], l2[x], l3[x]);
++		}
++  		if (draw_parts & PART_BORDER_SW)
++ 		{
++			XFillRectangle(dpy, pm, gc, 0, h-l1[x], l2[x], l3[x]);
++		}
++ 		if (draw_parts & PART_BORDER_SE)
++ 		{
++			XFillRectangle(dpy, pm, gc, w-l2[x], h-l1[x], l2[x], l3[x]);
++		}
++	}
++
++	FShapeCombineMask(dpy, win, ShapeBounding, 0, 0, pm, col==1 ? ShapeSubtract : ShapeSet);
++
++	XFreePixmap(dpy, pm);
++}
++
++static void frame_draw_rounded_mask(FvwmWindow *fw, Window win, window_parts draw_parts, int col)
++{
++	draw_rounded_mask(win, fw->g.frame.width, fw->g.frame.height,
++		HAS_SLIGHTLY_ROUNDED_CORNERS(fw), IS_MAXIMIZED(fw)?0:draw_parts, col);
++}
++
++/* Returns a corner corrected for rotation of the titlebar (ie button 1 is always NW) */
++#define SWAP_CORNER(PART) corner = corner & (PART) ? corner ^ (PART) : corner
++static window_parts __get_corner(window_parts corner, FvwmWindow *fw)
++{
++	int dir;
++		
++	dir = GET_TITLE_DIR(fw);
++
++	/* Flip horizontally (relative to tb) if the titlebar is rotated */
++	if ((dir == DIR_N && IS_TOP_TITLE_ROTATED(fw))
++		|| (dir == DIR_S && !IS_BOTTOM_TITLE_ROTATED(fw))
++		|| (dir == DIR_W && IS_LEFT_TITLE_ROTATED_CW(fw))
++		|| (dir == DIR_E && !IS_RIGHT_TITLE_ROTATED_CW(fw)))
++	{
++		SWAP_CORNER(PART_BORDER_NE | PART_BORDER_NW);
++	}
++
++	/* Swap SE/SW so that shift left goes in a clockwise order */
++	SWAP_CORNER(PART_BORDER_SW | PART_BORDER_SE);
++
++	/* Rotate clockwise depending on dir */
++	corner <<= dir;
++	if (corner > PART_BORDER_SE)
++	{
++		corner = corner >> 4;
++	}
++	
++	/* Swap SE/SW back */
++	SWAP_CORNER(PART_BORDER_SW | PART_BORDER_SE);
++
++	return corner;
++}
++ 
++void frame_make_rounded_corners(FvwmWindow *fw)
++{
++	rectangle rect;
++	window_parts draw_parts;
++	window_parts mask;
++	int x;
++	FvwmWindow *left_button = 0;
++	FvwmWindow *right_button = 0;
++
++	if (!fw || !FShapesSupported)
++	{
++		return;
++	}
++  
++	window_parts corner_nw = __get_corner(PART_BORDER_NW, fw);
++	window_parts corner_ne = __get_corner(PART_BORDER_NE, fw);
++	window_parts corner_se = __get_corner(PART_BORDER_SE, fw);
++	window_parts corner_sw = __get_corner(PART_BORDER_SW, fw);
++ 
++	for (x = 9;x>=0;x--)
++	{
++		if (FW_W_BUTTON(fw, x) != None)
++		{
++			if (x%2 == 0)
++			{
++				left_button = FW_W_BUTTON(fw, x);
++			}
++			else
++			{
++				right_button = FW_W_BUTTON(fw, x);
++			}
++		}
++	}
++ 
++ 	mask = 0;
++ 	if (HAS_ROUNDED_CORNERS_TOP(fw))
++  	{
++ 		mask |= corner_ne | corner_nw;
++  	}
++ 	if (HAS_ROUNDED_CORNERS_BOTTOM(fw))
++  	{
++ 		mask |= corner_se | corner_sw;
++  	}
++ 
++	/* Draw mask on each corner of the window. This involves the frame, title,
++	 * buttons and parent wins depending on the window configuration */
++ 	rect = fw->g.frame;
++ 	frame_draw_rounded_mask(fw, FW_W_FRAME(fw), mask, 1);
++	if (HAS_TITLE(fw))
++	{
++		draw_parts = 0;
++		if (!left_button)
++		{
++			draw_parts |= corner_nw;
++		}
++		if (!right_button)
++		{
++			draw_parts |= corner_ne;
++		}
++		if (IS_SHADED(fw))
++		{
++			if (!left_button)
++			{
++				draw_parts |= corner_sw;
++			}
++			else
++			{
++				frame_draw_rounded_mask(fw, left_button, mask & (corner_nw|corner_sw), 0);
++			}
++			if (!right_button)
++			{
++				draw_parts |= corner_se;
++			}
++			else
++			{
++				frame_draw_rounded_mask(fw, right_button, mask & (corner_ne|corner_se), 0);
++			}
++		}
++		frame_draw_rounded_mask(fw, FW_W_TITLE(fw), mask & draw_parts, 0);
++  
++		if (!IS_SHADED(fw))
++		{
++			frame_draw_rounded_mask(fw, FW_W_PARENT(fw), mask & (corner_sw|corner_se), 0);
++  
++			if (left_button)
++			{
++				frame_draw_rounded_mask(fw, left_button, mask & corner_nw, 0);
++			}
++			if (right_button)
++			{
++				frame_draw_rounded_mask(fw, right_button, mask & corner_ne, 0);
++			}
++		}
++	}
++	else
++	{
++		frame_draw_rounded_mask(fw, FW_W_PARENT(fw), mask & PART_CORNERS, 0);
++	}
++  
++	XFlush(dpy);
++}
++
+ /****************************************************************************
+  *
+  * Sets up the shaped window borders
+  *
+  ****************************************************************************/
+ void frame_setup_shape(FvwmWindow *fw, int w, int h, int shape_mode)
+ {
+ 	XRectangle rect;
+ 	rectangle r;
+ 	size_borders b;
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/frame.c~ fvwm-2.5.21-08/fvwm/frame.c~
+--- fvwm-2.5.21-07/fvwm/frame.c~	1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/frame.c~	2007-03-03 13:19:57.000000000 +0100
+@@ -0,0 +1,2136 @@
++/* -*-c-*- */
++/* This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* ---------------------------- included header files ---------------------- */
++
++#include "config.h"
++
++#include <stdio.h>
++#include <signal.h>
++
++#include "libs/fvwmlib.h"
++#include "libs/FShape.h"
++#include "libs/charmap.h"
++#include "libs/wcontext.h"
++#include "fvwm.h"
++#include "externs.h"
++#include "execcontext.h"
++#include "events.h"
++#include "misc.h"
++#include "screen.h"
++#include "geometry.h"
++#include "module_interface.h"
++#include "focus.h"
++#include "borders.h"
++#include "frame.h"
++#include "gnome.h"
++#include "ewmh.h"
++
++/* ---------------------------- local definitions -------------------------- */
++
++/* ---------------------------- local macros ------------------------------- */
++
++/* ---------------------------- imports ------------------------------------ */
++
++/* ---------------------------- included code files ------------------------ */
++
++/* ---------------------------- local types -------------------------------- */
++
++typedef struct
++{
++	int decor_grav;
++	int title_grav;
++	int lbutton_grav;
++	int rbutton_grav;
++	int parent_grav;
++	int client_grav;
++} frame_decor_gravities_type;
++
++typedef struct
++{
++	/* filled when args are created */
++	frame_move_resize_mode mode;
++	frame_decor_gravities_type grav;
++	size_borders b_g;
++	size_borders b_no_title_g;
++	rectangle curr_sidebar_g;
++	rectangle start_g;
++	rectangle end_g;
++	rectangle delta_g;
++	rectangle current_g;
++	rectangle client_g;
++	int anim_steps;
++	Window w_with_focus;
++	int current_step;
++	int curr_titlebar_compression;
++	direction_t shade_dir;
++	window_parts trans_parts;
++	struct
++	{
++		unsigned do_force : 1;
++		unsigned do_not_configure_client : 1;
++		unsigned do_not_draw : 1;
++		unsigned do_restore_gravity : 1;
++		unsigned do_set_bit_gravity : 1;
++		unsigned do_update_shape : 1;
++		unsigned had_handles : 1;
++		unsigned is_lazy_shading : 1;
++		unsigned is_setup : 1;
++		unsigned is_shading : 1;
++		unsigned was_moved : 1;
++	} flags;
++	/* used during the animation */
++	int next_titlebar_compression;
++	rectangle next_sidebar_g;
++	rectangle next_g;
++	rectangle dstep_g;
++	size_rect parent_s;
++	int minimal_w_offset;
++	int minimal_h_offset;
++	struct
++	{
++		/* cleared before each step */
++		unsigned do_hide_parent : 1;
++		unsigned do_unhide_parent : 1;
++		unsigned is_hidden : 1;
++		unsigned was_hidden : 1;
++	} step_flags;
++} mr_args_internal;
++
++/* ---------------------------- forward declarations ----------------------- */
++
++/* ---------------------------- local variables ---------------------------- */
++
++/* windows used to hide animation steps */
++static struct
++{
++	Window parent;
++	Window w[4];
++} hide_wins;
++
++/* ---------------------------- exported variables (globals) --------------- */
++
++/* ---------------------------- local functions ---------------------------- */
++
++#if 0
++static void print_g(char *text, rectangle *g)
++{
++	if (g == NULL)
++	{
++		fprintf(stderr, "%s: (null)", (text == NULL) ? "" : text);
++	}
++	else
++	{
++		fprintf(stderr, "%s: %4d %4d %4dx%4d (%4d - %4d %4d - %4d)\n",
++			(text == NULL) ? "" : text,
++			g->x, g->y, g->width, g->height,
++			g->x, g->x + g->width - 1, g->y, g->y + g->height - 1);
++	}
++}
++#endif
++
++static void combine_gravities(
++	frame_decor_gravities_type *ret_grav,
++	frame_decor_gravities_type *grav_x,
++	frame_decor_gravities_type *grav_y)
++{
++	ret_grav->decor_grav = gravity_combine_xy_grav(
++		grav_x->decor_grav, grav_y->decor_grav);
++	ret_grav->title_grav = gravity_combine_xy_grav(
++		grav_x->title_grav, grav_y->title_grav);
++	ret_grav->lbutton_grav = gravity_combine_xy_grav(
++		grav_x->lbutton_grav, grav_y->lbutton_grav);
++	ret_grav->rbutton_grav = gravity_combine_xy_grav(
++		grav_x->rbutton_grav, grav_y->rbutton_grav);
++	ret_grav->parent_grav = gravity_combine_xy_grav(
++		grav_x->parent_grav, grav_y->parent_grav);
++	ret_grav->client_grav = gravity_combine_xy_grav(
++		grav_x->client_grav, grav_y->client_grav);
++
++	return;
++}
++
++static void get_resize_decor_gravities_one_axis(
++	frame_decor_gravities_type *ret_grav, direction_t title_dir,
++	frame_move_resize_mode axis_mode, direction_t neg_dir,
++	direction_t pos_dir, int is_moving)
++{
++
++	int title_grav;
++	int neg_grav;
++	int pos_grav;
++
++	title_grav = gravity_dir_to_grav(title_dir);
++	neg_grav = gravity_dir_to_grav(neg_dir);
++	pos_grav = gravity_dir_to_grav(pos_dir);
++	if (title_dir != DIR_NONE)
++	{
++		ret_grav->decor_grav = title_grav;
++		ret_grav->lbutton_grav = title_grav;
++		ret_grav->title_grav = title_grav;
++		ret_grav->rbutton_grav = title_grav;
++	}
++	else
++	{
++		ret_grav->decor_grav = neg_grav;
++		ret_grav->lbutton_grav = neg_grav;
++		ret_grav->title_grav = neg_grav;
++		ret_grav->rbutton_grav = pos_grav;
++	}
++	switch (axis_mode)
++	{
++	case FRAME_MR_SCROLL:
++		ret_grav->client_grav = (is_moving) ? neg_grav : pos_grav;
++		break;
++	case FRAME_MR_SHRINK:
++		ret_grav->client_grav = (is_moving) ? pos_grav : neg_grav;
++		break;
++	case FRAME_MR_OPAQUE:
++	case FRAME_MR_FORCE_SETUP:
++	case FRAME_MR_FORCE_SETUP_NO_W:
++	case FRAME_MR_SETUP:
++	case FRAME_MR_SETUP_BY_APP:
++		ret_grav->client_grav = neg_grav;
++		break;
++	case FRAME_MR_DONT_DRAW:
++		/* can not happen, just a dummy to keep -Wall happy */
++		break;
++	}
++	ret_grav->parent_grav = ret_grav->client_grav;
++
++	return;
++}
++
++static void frame_get_titlebar_dimensions_only(
++	FvwmWindow *fw, rectangle *frame_g, size_borders *bs,
++	rectangle *ret_titlebar_g)
++{
++	if (!HAS_TITLE(fw))
++	{
++		return;
++	}
++	switch (GET_TITLE_DIR(fw))
++	{
++	case DIR_W:
++	case DIR_E:
++		ret_titlebar_g->x = (GET_TITLE_DIR(fw) == DIR_W) ?
++			bs->top_left.width :
++			frame_g->width - bs->bottom_right.width -
++			fw->title_thickness;
++		ret_titlebar_g->y = bs->top_left.height;
++		ret_titlebar_g->width = fw->title_thickness;
++		ret_titlebar_g->height =
++			frame_g->height - bs->total_size.height;
++		break;
++	case DIR_N:
++	case DIR_S:
++	default: /* default makes gcc4 happy */
++		ret_titlebar_g->y = (GET_TITLE_DIR(fw) == DIR_N) ?
++			bs->top_left.height :
++			frame_g->height - bs->bottom_right.height -
++			fw->title_thickness;
++		ret_titlebar_g->x = bs->top_left.width;
++		ret_titlebar_g->width = frame_g->width - bs->total_size.width;
++		ret_titlebar_g->height = fw->title_thickness;
++		break;
++	}
++
++	return;
++}
++
++static void frame_setup_border(
++	FvwmWindow *fw, rectangle *frame_g, window_parts setup_parts,
++	rectangle *diff_g)
++{
++	XWindowChanges xwc;
++	Window w;
++	window_parts part;
++	rectangle sidebar_g;
++	rectangle part_g;
++	Bool dummy;
++
++	if (HAS_NO_BORDER(fw))
++	{
++		return;
++	}
++	frame_get_sidebar_geometry(
++		fw, NULL, frame_g, &sidebar_g, &dummy, &dummy);
++	for (part = PART_BORDER_N; (part & PART_FRAME);
++	     part <<= 1)
++	{
++		if ((part & PART_FRAME & setup_parts) == PART_NONE)
++		{
++			continue;
++		}
++		border_get_part_geometry(fw, part, &sidebar_g, &part_g, &w);
++		if (part_g.width <= 0 || part_g.height <= 0)
++		{
++			xwc.x = -1;
++			xwc.y = -1;
++			xwc.width = 1;
++			xwc.height = 1;
++		}
++		else
++		{
++			xwc.x = part_g.x;
++			xwc.y = part_g.y;
++			xwc.width = part_g.width;
++			xwc.height = part_g.height;
++		}
++		if (diff_g != NULL)
++		{
++			if (part == PART_BORDER_NE || part == PART_BORDER_E ||
++			    part == PART_BORDER_SE)
++			{
++				xwc.x -= diff_g->width;
++			}
++			if (part == PART_BORDER_SW || part == PART_BORDER_S ||
++			    part == PART_BORDER_SE)
++			{
++				xwc.y -= diff_g->height;
++			}
++		}
++		XConfigureWindow(dpy, w, CWWidth | CWHeight | CWX | CWY, &xwc);
++	}
++
++	return;
++}
++
++static void frame_setup_titlebar(
++	FvwmWindow *fw, rectangle *frame_g, window_parts setup_parts,
++	rectangle *diff_g)
++{
++	frame_title_layout_t title_layout;
++	int i;
++
++	if (!HAS_TITLE(fw))
++	{
++		return;
++	}
++	frame_get_titlebar_dimensions(fw, frame_g, diff_g, &title_layout);
++	/* configure buttons */
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		if (FW_W_BUTTON(fw, i) != None && (setup_parts & PART_BUTTONS))
++		{
++			XMoveResizeWindow(
++				dpy, FW_W_BUTTON(fw, i),
++				title_layout.button_g[i].x,
++				title_layout.button_g[i].y,
++				title_layout.button_g[i].width,
++				title_layout.button_g[i].height);
++		}
++	}
++	/* configure title */
++	if (setup_parts & PART_TITLE)
++	{
++		XMoveResizeWindow(
++			dpy, FW_W_TITLE(fw),
++			title_layout.title_g.x, title_layout.title_g.y,
++			title_layout.title_g.width,
++			title_layout.title_g.height);
++	}
++
++	return;
++}
++
++static void __frame_setup_window(
++	FvwmWindow *fw, rectangle *frame_g, Bool do_send_configure_notify,
++	Bool do_force, Bool is_application_request)
++{
++	frame_move_resize_args mr_args;
++	Bool is_resized = False;
++	Bool is_moved = False;
++	rectangle new_g;
++
++	new_g = *frame_g;
++	/* sanity checks */
++	if (new_g.width < 1)
++	{
++		new_g.width = 1;
++	}
++	if (new_g.height < 1)
++	{
++		new_g.height = 1;
++	}
++	/* set some flags */
++	if (new_g.width != fw->g.frame.width ||
++	    new_g.height != fw->g.frame.height)
++	{
++		is_resized = True;
++	}
++	if (new_g.x != fw->g.frame.x || new_g.y != fw->g.frame.y)
++	{
++		is_moved = True;
++	}
++	/* setup the window */
++	if (is_resized || do_force)
++	{
++		frame_move_resize_mode mode;
++
++		if (is_application_request)
++		{
++			mode = FRAME_MR_SETUP_BY_APP;
++		}
++		else if (do_force)
++		{
++			mode = FRAME_MR_FORCE_SETUP;
++		}
++		else
++		{
++			mode = FRAME_MR_SETUP;
++		}
++		mr_args = frame_create_move_resize_args(
++			fw, mode, NULL, &new_g, 0, DIR_NONE);
++		frame_move_resize(fw, mr_args);
++		((mr_args_internal *)mr_args)->flags.was_moved = 0;
++		frame_free_move_resize_args(fw, mr_args);
++		fw->g.frame = *frame_g;
++	}
++	else if (is_moved)
++	{
++		unsigned int draw_parts = PART_NONE;
++
++		/* inform the application of the change
++		 *
++		 * According to the July 27, 1988 ICCCM draft, we should send a
++		 * synthetic ConfigureNotify event to the client if the window
++		 * was moved but not resized. */
++		XMoveWindow(dpy, FW_W_FRAME(fw), frame_g->x, frame_g->y);
++		fw->g.frame = *frame_g;
++		if ((draw_parts = border_get_transparent_decorations_part(fw))
++		    != PART_NONE)
++		{
++			border_draw_decorations(
++				fw, draw_parts,
++				((fw == get_focus_window())) ? True : False,
++				True, CLEAR_ALL, NULL, NULL);
++		}
++		fw->g.frame = *frame_g;
++		do_send_configure_notify = True;
++	}
++	/* must not send events to shaded windows because this might cause them
++	 * to look at their current geometry */
++	if (do_send_configure_notify && !IS_SHADED(fw))
++	{
++		SendConfigureNotify(
++			fw, new_g.x, new_g.y, new_g.width, new_g.height, 0,
++			True);
++	}
++	/* get things updated */
++	XFlush(dpy);
++	/* inform the modules of the change */
++	BroadcastConfig(M_CONFIGURE_WINDOW,fw);
++
++	return;
++}
++
++static void frame_reparent_hide_windows(
++	Window w)
++{
++	int i;
++
++	hide_wins.parent = w;
++	for (i = 0; i < 4 ; i++)
++	{
++		if (w == Scr.Root)
++		{
++			XUnmapWindow(dpy, hide_wins.w[i]);
++		}
++		XReparentWindow(dpy, hide_wins.w[i], w, -1, -1);
++	}
++	if (w != Scr.Root)
++	{
++		XRaiseWindow(dpy, hide_wins.w[0]);
++		XRestackWindows(dpy, hide_wins.w, 4);
++	}
++
++	return;
++}
++
++/* Returns True if the frame is so small that the parent window would have a
++ * width or height smaller than one pixel. */
++static Bool frame_is_parent_hidden(
++	FvwmWindow *fw, rectangle *frame_g)
++{
++	size_borders b;
++
++	get_window_borders(fw, &b);
++	if (frame_g->width <= b.total_size.width ||
++	    frame_g->height <= b.total_size.height)
++	{
++		return True;
++	}
++
++	return False;
++}
++
++/* Returns the number of pixels that the title bar is too short to accomodate
++ * all the title buttons and a title window that has at least a length of one
++ * pixel. */
++static int frame_get_titlebar_compression(
++	FvwmWindow *fw, rectangle *frame_g)
++{
++	size_borders b;
++	int space;
++	int need_space;
++
++	if (!HAS_TITLE(fw))
++	{
++		return 0;
++	}
++	get_window_borders(fw, &b);
++	if (HAS_VERTICAL_TITLE(fw))
++	{
++		space = frame_g->height - b.total_size.height;
++	}
++	else
++	{
++		space = frame_g->width - b.total_size.width;
++	}
++	need_space = (fw->nr_left_buttons + fw->nr_right_buttons) *
++		fw->title_thickness + MIN_WINDOW_TITLE_LENGTH;
++	if (space < need_space)
++	{
++		return need_space - space;
++	}
++
++	return 0;
++}
++
++/* Calculates the gravities for the various parts of the decor through ret_grav.
++ * This can be passed to frame_set_decor_gravities.
++ *
++ * title_dir
++ *   The direction of the title in the frame.
++ * rmode
++ *   The mode for the resize operation
++ */
++static void frame_get_resize_decor_gravities(
++	frame_decor_gravities_type *ret_grav, direction_t title_dir,
++	frame_move_resize_mode rmode, rectangle *delta_g)
++{
++	frame_decor_gravities_type grav_x;
++	frame_decor_gravities_type grav_y;
++	direction_t title_dir_x;
++	direction_t title_dir_y;
++
++	gravity_split_xy_dir(&title_dir_x, &title_dir_y, title_dir);
++	get_resize_decor_gravities_one_axis(
++		&grav_x, title_dir_x, rmode, DIR_W, DIR_E, (delta_g->x != 0));
++	get_resize_decor_gravities_one_axis(
++		&grav_y, title_dir_y, rmode, DIR_N, DIR_S, (delta_g->y != 0));
++	combine_gravities(ret_grav, &grav_x, &grav_y);
++
++	return;
++}
++
++/* sets the gravity for the various parts of the window */
++static void frame_set_decor_gravities(
++	FvwmWindow *fw, frame_decor_gravities_type *grav,
++	int do_set1_restore2_bit_gravity)
++{
++	int valuemask;
++	XSetWindowAttributes xcwa;
++	int i;
++	Bool button_reverted = False;
++
++	/* using bit gravity can reduce redrawing dramatically */
++	valuemask = CWWinGravity;
++	xcwa.win_gravity = grav->client_grav;
++	if (do_set1_restore2_bit_gravity == 1)
++	{
++		XWindowAttributes xwa;
++
++		if (!fw->attr_backup.is_bit_gravity_stored &&
++		    XGetWindowAttributes(dpy, FW_W(fw), &xwa))
++		{
++			fw->attr_backup.bit_gravity = xwa.bit_gravity;
++		}
++		fw->attr_backup.is_bit_gravity_stored = 1;
++		valuemask |= CWBitGravity;
++		xcwa.bit_gravity = grav->client_grav;
++	}
++	else if (do_set1_restore2_bit_gravity == 2)
++	{
++		fw->attr_backup.is_bit_gravity_stored = 0;
++		valuemask |= CWBitGravity;
++		xcwa.bit_gravity = fw->attr_backup.bit_gravity;
++	}
++	XChangeWindowAttributes(dpy, FW_W(fw), valuemask, &xcwa);
++	xcwa.win_gravity = grav->parent_grav;
++	valuemask = CWWinGravity;
++	XChangeWindowAttributes(dpy, FW_W_PARENT(fw), valuemask, &xcwa);
++	if (!HAS_TITLE(fw))
++	{
++		return;
++	}
++	xcwa.win_gravity = grav->title_grav;
++	XChangeWindowAttributes(dpy, FW_W_TITLE(fw), valuemask, &xcwa);
++	if (fw->title_text_rotation == ROTATION_270 ||
++	    fw->title_text_rotation == ROTATION_180)
++	{
++		button_reverted = True;
++	}
++	if (button_reverted)
++	{
++		xcwa.win_gravity = grav->rbutton_grav;
++	}
++	else
++	{
++		xcwa.win_gravity = grav->lbutton_grav;
++	}
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i += 2)
++	{
++		if (FW_W_BUTTON(fw, i))
++		{
++			XChangeWindowAttributes(
++				dpy, FW_W_BUTTON(fw, i), valuemask, &xcwa);
++		}
++	}
++	if (button_reverted)
++	{
++		xcwa.win_gravity = grav->lbutton_grav;
++	}
++	else
++	{
++		xcwa.win_gravity = grav->rbutton_grav;
++	}
++	for (i = 1; i < NUMBER_OF_TITLE_BUTTONS; i += 2)
++	{
++		if (FW_W_BUTTON(fw, i))
++		{
++			XChangeWindowAttributes(
++				dpy, FW_W_BUTTON(fw, i), valuemask, &xcwa);
++		}
++	}
++
++	return;
++}
++
++/* Just restore the win and bit gravities on the client window. */
++static void frame_restore_client_gravities(FvwmWindow *fw)
++{
++	XSetWindowAttributes xcwa;
++	long valuemask;
++
++	valuemask = CWWinGravity;
++	if (fw->attr_backup.is_bit_gravity_stored)
++	{
++		fw->attr_backup.is_bit_gravity_stored = 0;
++		xcwa.bit_gravity = fw->attr_backup.bit_gravity;
++		valuemask |= CWBitGravity;
++	}
++	xcwa.win_gravity = fw->hints.win_gravity;
++	XChangeWindowAttributes(dpy, FW_W(fw), valuemask, &xcwa);
++
++	return;
++}
++
++/* Prepares the structure for the next animation step. */
++static void frame_next_move_resize_args(
++	frame_move_resize_args mr_args)
++{
++	mr_args_internal *mra;
++
++	mra = (mr_args_internal *)mr_args;
++	mra->curr_sidebar_g = mra->next_sidebar_g;
++	mra->current_g = mra->next_g;
++	mra->step_flags.was_hidden = mra->step_flags.is_hidden;
++	mra->curr_titlebar_compression = mra->next_titlebar_compression;
++
++	return;
++}
++
++static rectangle *frame_get_hidden_pos(
++	FvwmWindow *fw, mr_args_internal *mra, Bool do_unhide,
++	rectangle *ret_hidden_g)
++{
++	rectangle *target_g;
++	direction_t dir_x;
++	direction_t dir_y;
++
++	if (do_unhide == False)
++	{
++		gravity_split_xy_dir(&dir_x, &dir_y, mra->shade_dir);
++		ret_hidden_g->x = (dir_x == DIR_E) ?
++		-mra->client_g.width + mra->parent_s.width : 0;
++		ret_hidden_g->y = (dir_y == DIR_S) ?
++			-mra->client_g.height + mra->parent_s.height : 0;
++		target_g = &mra->next_g;
++	}
++	else
++	{
++		gravity_split_xy_dir(&dir_x, &dir_y, SHADED_DIR(fw));
++		if (mra->mode == FRAME_MR_SCROLL)
++		{
++			ret_hidden_g->x = (dir_x == DIR_W) ?
++				-mra->client_g.width + mra->parent_s.width : 0;
++			ret_hidden_g->y = (dir_y == DIR_N) ?
++				-mra->client_g.height + mra->parent_s.height :
++				0;
++		}
++		else
++		{
++			ret_hidden_g->x = (dir_x == DIR_E) ?
++				-mra->client_g.width + mra->parent_s.width : 0;
++			ret_hidden_g->y = (dir_y == DIR_S) ?
++				-mra->client_g.height + mra->parent_s.height :
++				0;
++		}
++		target_g = &mra->next_g;
++	}
++
++	return target_g;
++}
++
++static void frame_update_hidden_window_pos(
++	FvwmWindow *fw, mr_args_internal *mra, Bool do_unhide)
++{
++	rectangle *target_g;
++	rectangle hidden_g;
++
++	target_g = frame_get_hidden_pos(fw, mra, do_unhide, &hidden_g);
++	XMoveResizeWindow(
++		dpy, FW_W_PARENT(fw), mra->b_g.top_left.width,
++		mra->b_g.top_left.height,
++		max(1, target_g->width - mra->b_g.total_size.width),
++		max(1, target_g->height - mra->b_g.total_size.height));
++	XMoveResizeWindow(
++		dpy, FW_W(fw), hidden_g.x, hidden_g.y, mra->client_g.width,
++		mra->client_g.height);
++	mra->flags.was_moved = 1;
++
++	return;
++}
++
++static void frame_prepare_animation_shape(
++	FvwmWindow *fw, mr_args_internal *mra, int parent_x, int parent_y)
++{
++	rectangle parent_g;
++	rectangle client_g;
++
++	if (!FShapesSupported)
++	{
++		return;
++	}
++	parent_g.x = parent_x;
++	parent_g.y = parent_y;
++	parent_g.width = mra->parent_s.width;
++	parent_g.height = mra->parent_s.height;
++	gravity_move_resize_parent_child(
++		mra->grav.parent_grav, &mra->dstep_g, &parent_g);
++	client_g = mra->client_g;
++	frame_get_hidden_pos(fw, mra, True, &client_g);
++	client_g.x += parent_g.x;
++	client_g.y += parent_g.y;
++	FShapeCombineShape(
++		dpy, Scr.NoFocusWin, FShapeBounding, client_g.x, client_g.y,
++		FW_W(fw), FShapeBounding, FShapeSet);
++	if (HAS_TITLE(fw))
++	{
++		rectangle tb_g;
++		XRectangle rect;
++
++		frame_get_titlebar_dimensions_only(
++			fw, &mra->next_g, &mra->b_no_title_g, &tb_g);
++		/* windows w/ titles */
++		rect.x = tb_g.x;
++		rect.y = tb_g.y;
++		rect.width = tb_g.width;
++		rect.height = tb_g.height;
++		FShapeCombineRectangles(
++			dpy, Scr.NoFocusWin, FShapeBounding, 0, 0, &rect, 1,
++			FShapeUnion, Unsorted);
++	}
++
++	return;
++}
++
++static void frame_mrs_prepare_vars(
++	FvwmWindow *fw, mr_args_internal *mra)
++{
++	Bool dummy;
++	int i;
++
++	/* preparations */
++	i = mra->current_step;
++	mra->next_g = mra->start_g;
++	mra->next_g.x += (mra->delta_g.x * i) / mra->anim_steps;
++	mra->next_g.y += (mra->delta_g.y * i) / mra->anim_steps;
++	mra->next_g.width += (mra->delta_g.width * i) / mra->anim_steps;
++	mra->next_g.height += (mra->delta_g.height * i) / mra->anim_steps;
++	frame_get_sidebar_geometry(
++		fw, NULL, &mra->next_g, &mra->next_sidebar_g, &dummy, &dummy);
++	fvwmrect_subtract_rectangles(
++		&mra->dstep_g, &mra->next_g, &mra->current_g);
++	mra->next_titlebar_compression =
++		frame_get_titlebar_compression(fw, &mra->next_g);
++	mra->step_flags.is_hidden =
++		(frame_is_parent_hidden(fw, &mra->next_g) == True);
++	mra->step_flags.do_hide_parent =
++		((!mra->step_flags.was_hidden || mra->flags.do_force) &&
++		 mra->step_flags.is_hidden);
++	mra->step_flags.do_unhide_parent =
++		((mra->step_flags.was_hidden || mra->flags.do_force) &&
++		 !mra->step_flags.is_hidden);
++	/* get the parent's dimensions */
++	mra->parent_s.width = mra->next_g.width - mra->b_g.total_size.width;
++	if (mra->parent_s.width < 1)
++	{
++		mra->minimal_w_offset = 1 - mra->parent_s.width;
++		mra->parent_s.width = 1;
++	}
++	else
++	{
++		mra->minimal_w_offset = 0;
++	}
++	mra->parent_s.height = mra->next_g.height - mra->b_g.total_size.height;
++	if (mra->parent_s.height < 1)
++	{
++		mra->minimal_h_offset = 1 - mra->parent_s.height;
++		mra->parent_s.height = 1;
++	}
++	else
++	{
++		mra->minimal_h_offset = 0;
++	}
++
++	return;
++}
++
++static void frame_mrs_hide_changing_parts(
++	mr_args_internal *mra)
++{
++	int l_add;
++	int t_add;
++	int r_add;
++	int b_add;
++	int w;
++	int h;
++
++	t_add = 0;
++	l_add = 0;
++	b_add = 0;
++	r_add = 0;
++	if (mra->mode == FRAME_MR_SHRINK)
++	{
++		if (mra->dstep_g.x > 0)
++		{
++			l_add = mra->dstep_g.x;
++		}
++		if (mra->dstep_g.y > 0)
++		{
++			t_add = mra->dstep_g.y;
++		}
++	}
++	else if (mra->mode == FRAME_MR_SCROLL)
++	{
++		if (mra->dstep_g.x == 0 && mra->dstep_g.width < 0)
++		{
++			l_add = -mra->dstep_g.width;
++		}
++		if (mra->dstep_g.y == 0 && mra->dstep_g.height < 0)
++		{
++			t_add = -mra->dstep_g.height;
++		}
++	}
++	if (l_add > 0)
++	{
++		l_add -= mra->minimal_w_offset;
++	}
++	else
++	{
++		r_add = (mra->dstep_g.width < 0) ? -mra->dstep_g.width : 0;
++		r_add -= mra->minimal_w_offset;
++	}
++	if (t_add > 0)
++	{
++		t_add -= mra->minimal_h_offset;
++	}
++	else
++	{
++		b_add = (mra->dstep_g.height < 0) ? -mra->dstep_g.height : 0;
++		b_add -= mra->minimal_h_offset;
++	}
++	/* cover top border */
++	w = mra->current_g.width;
++	h = mra->b_g.top_left.height + t_add;
++	if (w > 0 && h > 0)
++	{
++		XMoveResizeWindow(dpy, hide_wins.w[0], 0, 0, w, h);
++		XMapWindow(dpy, hide_wins.w[0]);
++	}
++	/* cover left border */
++	w = mra->b_g.top_left.width + l_add;
++	h = mra->current_g.height;
++	if (w > 0 && h > 0)
++	{
++		XMoveResizeWindow(dpy, hide_wins.w[1], 0, 0, w, h);
++		XMapWindow(dpy, hide_wins.w[1]);
++	}
++	/* cover bottom border and possibly part of the client */
++	w = mra->current_g.width;
++	h = mra->b_g.bottom_right.height + b_add;
++	if (w > 0 && h > 0)
++	{
++		XMoveResizeWindow(
++			dpy, hide_wins.w[2], 0, mra->current_g.height -
++			mra->b_g.bottom_right.height - b_add, w, h);
++		XMapWindow(dpy, hide_wins.w[2]);
++	}
++	/* cover right border and possibly part of the client */
++	w = mra->b_g.bottom_right.width + r_add;
++	h = mra->current_g.height;
++	if (w > 0 && h > 0)
++	{
++		XMoveResizeWindow(
++			dpy, hide_wins.w[3], mra->current_g.width -
++			mra->b_g.bottom_right.width - r_add, 0, w, h);
++		XMapWindow(dpy, hide_wins.w[3]);
++	}
++
++	return;
++}
++
++static void frame_mrs_hide_unhide_parent(
++	FvwmWindow *fw, mr_args_internal *mra)
++{
++	XSetWindowAttributes xswa;
++
++	if (mra->step_flags.do_unhide_parent)
++	{
++		Window w[2];
++
++		/* update the hidden position of the client */
++		frame_update_hidden_window_pos(fw, mra, True);
++		w[0] = hide_wins.w[3];
++		w[1] = FW_W_PARENT(fw);
++		XRestackWindows(dpy, w, 2);
++	}
++	else if (mra->step_flags.do_hide_parent)
++	{
++		/* When the parent gets hidden, unmap it automatically, lower
++		 * it while hidden, then remap it.  Necessary to eliminate
++		 * flickering. */
++		xswa.win_gravity = UnmapGravity;
++		XChangeWindowAttributes(
++			dpy, FW_W_PARENT(fw), CWWinGravity, &xswa);
++	}
++
++	return;
++}
++
++static void frame_mrs_hide_unhide_parent2(
++	FvwmWindow *fw, mr_args_internal *mra)
++{
++	XSetWindowAttributes xswa;
++
++	/* finish hiding the parent */
++	if (mra->step_flags.do_hide_parent)
++	{
++		xswa.win_gravity = mra->grav.parent_grav;
++		XChangeWindowAttributes(
++			dpy, FW_W_PARENT(fw), CWWinGravity, &xswa);
++		/* update the hidden position of the client */
++		frame_update_hidden_window_pos(fw, mra, False);
++		XLowerWindow(dpy, FW_W_PARENT(fw));
++		XMapWindow(dpy, FW_W_PARENT(fw));
++	}
++
++	return;
++}
++
++static void frame_mrs_setup_draw_decorations(
++	FvwmWindow *fw, mr_args_internal *mra)
++{
++	window_parts setup_parts;
++
++	/* setup the title bar and the border */
++	setup_parts = PART_TITLE;
++	if (mra->curr_titlebar_compression != mra->next_titlebar_compression ||
++	    mra->mode == FRAME_MR_FORCE_SETUP)
++	{
++		setup_parts |= PART_BUTTONS;
++	}
++	frame_setup_titlebar(fw, &mra->next_g, setup_parts, &mra->dstep_g);
++	frame_setup_border(fw, &mra->next_g, PART_ALL, &mra->dstep_g);
++	/* draw the border and the titlebar */
++	if (mra->flags.do_not_draw == 1)
++	{
++		/* nothing */
++	}
++	else if (!mra->flags.is_shading || !mra->flags.is_lazy_shading)
++	{
++		/* draw as usual */
++		border_draw_decorations(
++			fw, PART_ALL,
++			(mra->w_with_focus != None) ? True : False,
++			(mra->flags.do_force) ? True : False, CLEAR_ALL,
++			&mra->current_g, &mra->next_g);
++	}
++	else /* lazy shading */
++	{
++		/* Lazy shading relies on the proper window gravities and does
++		 * not redraw the decorations during the animation.  Only draw
++		 * on the first step. */
++		if (mra->current_step == 1)
++		{
++			rectangle lazy_g;
++
++			/* Use the larger width and height values from the
++			 * current and the final geometry to get proper
++			 * decorations. */
++			lazy_g.x = mra->current_g.x;
++			lazy_g.y = mra->current_g.y;
++			lazy_g.width = max(
++				mra->current_g.width, mra->end_g.width);
++			lazy_g.height = max(
++				mra->current_g.height, mra->end_g.height);
++			border_draw_decorations(
++				fw, PART_ALL,
++				(mra->w_with_focus != None) ? True : False,
++				True, CLEAR_ALL, &mra->current_g, &lazy_g);
++		}
++	}
++
++	return;
++}
++
++static void frame_mrs_resize_move_windows(
++	FvwmWindow *fw, mr_args_internal *mra)
++{
++	/* setup the parent, the frame and the client window */
++	if (!mra->flags.is_shading)
++	{
++		if (!mra->step_flags.is_hidden &&
++		    !mra->flags.do_not_configure_client)
++		{
++			XMoveResizeWindow(
++				dpy, FW_W(fw), 0, 0, mra->parent_s.width,
++				mra->parent_s.height);
++			mra->client_g.width = mra->parent_s.width;
++			mra->client_g.height = mra->parent_s.height;
++		}
++		else
++		{
++			XMoveWindow(dpy, FW_W(fw), 0, 0);
++		}
++		mra->flags.was_moved = 1;
++#if 0
++		/* reduces flickering */
++		/* dv (11-Aug-2002): ... and slows down large scripts
++		 * dramatically.  Rather let it flicker */
++		if (mra->flags.is_setup)
++		{
++			usleep(1000);
++		}
++#endif
++		XSync(dpy, 0);
++		XMoveResizeWindow(
++			dpy, FW_W_PARENT(fw), mra->b_g.top_left.width,
++			mra->b_g.top_left.height, mra->parent_s.width,
++			mra->parent_s.height);
++	}
++	else
++	{
++		int x;
++		int y;
++
++		x = mra->b_g.top_left.width;
++		y = mra->b_g.top_left.height;
++		if (mra->mode == FRAME_MR_SCROLL)
++		{
++			if (mra->dstep_g.x == 0)
++			{
++				x -= mra->dstep_g.width -
++					mra->minimal_w_offset;
++			}
++			if (mra->dstep_g.y == 0)
++			{
++				y -= mra->dstep_g.height -
++					mra->minimal_h_offset;;
++			}
++		}
++		else if (mra->mode == FRAME_MR_SHRINK)
++		{
++			x += mra->dstep_g.x;
++			y += mra->dstep_g.y;
++		}
++		if (x > 0)
++		{
++			x -= mra->minimal_w_offset;
++		}
++		else if (x < 0)
++		{
++			x += mra->minimal_w_offset;
++		}
++		if (y > 0)
++		{
++			y -= mra->minimal_h_offset;
++		}
++		else if (y < 0)
++		{
++			y += mra->minimal_h_offset;
++		}
++		XMoveResizeWindow(
++			dpy, FW_W_PARENT(fw), x, y, mra->parent_s.width,
++			mra->parent_s.height);
++		if (mra->flags.do_update_shape)
++		{
++			/* Step 1: apply the union of the old and new shapes.
++			 * This way so that the client stays visible - rather
++			 * let the background show through than force an
++			 * Expose event. */
++			frame_prepare_animation_shape(fw, mra, x, y);
++			FShapeCombineShape(
++				dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0,
++				Scr.NoFocusWin, FShapeBounding, FShapeUnion);
++		}
++	}
++	XMoveResizeWindow(
++		dpy, FW_W_FRAME(fw), mra->next_g.x, mra->next_g.y,
++		mra->next_g.width, mra->next_g.height);
++	if (mra->flags.do_update_shape)
++	{
++		/* Step 2: clip the previous shape. */
++		FShapeCombineShape(
++			dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0,
++			Scr.NoFocusWin, FShapeBounding, FShapeSet);
++	}
++
++	return;
++}
++
++static void frame_move_resize_step(
++	FvwmWindow *fw, mr_args_internal *mra)
++{
++	frame_mrs_prepare_vars(fw, mra);
++	frame_mrs_hide_changing_parts(mra);
++	frame_mrs_hide_unhide_parent(fw, mra);
++	frame_mrs_setup_draw_decorations(fw, mra);
++	frame_mrs_resize_move_windows(fw, mra);
++	frame_mrs_hide_unhide_parent2(fw, mra);
++	fw->g.frame = mra->next_g;
++
++	return;
++}
++
++
++static void frame_has_handles_and_tiled_border(
++	FvwmWindow *fw, int *ret_has_handles, int *ret_has_tiled_border)
++{
++	DecorFace *df;
++
++	*ret_has_handles = 1;
++	if (!HAS_HANDLES(fw))
++	{
++		*ret_has_handles = 0;
++	}
++	df = border_get_border_style(fw, (fw == Scr.Hilite) ? True : False);
++	if (DFS_HAS_HIDDEN_HANDLES(df->style))
++	{
++		*ret_has_handles = 0;
++	}
++	*ret_has_tiled_border =
++		(DFS_FACE_TYPE(df->style) == TiledPixmapButton) ||
++		(DFS_FACE_TYPE(df->style) == ColorsetButton &&
++		 !CSET_IS_TRANSPARENT_PR(df->u.acs.cs) &&
++		 CSET_HAS_PIXMAP(df->u.acs.cs));
++
++	return;
++}
++
++static int frame_get_shading_laziness(
++	FvwmWindow *fw, mr_args_internal *mra)
++{
++	int has_handles;
++	int has_tiled_pixmap_border;
++	int using_border_style;
++
++	if (!mra->flags.is_shading || mra->anim_steps <= 2)
++	{
++		return 0;
++	}
++	frame_has_handles_and_tiled_border(
++		fw, &has_handles, &has_tiled_pixmap_border);
++	if (HAS_TITLE(fw) && has_tiled_pixmap_border)
++	{
++		using_border_style = border_is_using_border_style(
++			fw, (fw == Scr.Hilite) ? True : False);
++	}
++	else
++	{
++		using_border_style = 0;
++	}
++	switch (WINDOWSHADE_LAZINESS(fw))
++	{
++	case WINDOWSHADE_ALWAYS_LAZY:
++		return 1;
++	case WINDOWSHADE_BUSY:
++		if (has_handles)
++		{
++			return 0;
++		}
++		/* fall through */
++	case WINDOWSHADE_LAZY:
++	default:
++		if (has_tiled_pixmap_border && !HAS_NO_BORDER(fw))
++		{
++			return 0;
++		}
++		else if (has_tiled_pixmap_border && HAS_TITLE(fw) &&
++			 using_border_style)
++		{
++			return 0;
++		}
++		return 1;
++	}
++}
++
++void frame_reshape_border(FvwmWindow *fw)
++{
++	int grav;
++	int off_x = 0;
++	int off_y = 0;
++	rectangle naked_g;
++	rectangle *new_g;
++
++	/* calculate the new offsets */
++	if (!IS_MAXIMIZED(fw))
++	{
++		grav = fw->hints.win_gravity;
++		new_g = &fw->g.normal;
++	}
++	else
++	{
++		/* maximized windows are always considered to have
++		 * NorthWestGravity */
++		grav = NorthWestGravity;
++		new_g = &fw->g.max;
++		off_x = fw->g.normal.x - fw->g.max.x;
++		off_y = fw->g.normal.y - fw->g.max.y;
++	}
++	gravity_get_naked_geometry(grav, fw, &naked_g, new_g);
++	gravity_translate_to_northwest_geometry_no_bw(
++		grav, fw, &naked_g, &naked_g);
++	set_window_border_size(fw, fw->unshaped_boundary_width);
++	gravity_add_decoration(grav, fw, new_g, &naked_g);
++	if (IS_MAXIMIZED(fw))
++	{
++		/* prevent random paging when unmaximizing after the border
++		 * width has changed */
++		fw->g.max_offset.x += fw->g.normal.x - fw->g.max.x - off_x;
++		fw->g.max_offset.y += fw->g.normal.y - fw->g.max.y - off_y;
++	}
++	if (IS_SHADED(fw))
++	{
++		get_unshaded_geometry(fw, new_g);
++		if (USED_TITLE_DIR_FOR_SHADING(fw))
++		{
++			SET_SHADED_DIR(fw, GET_TITLE_DIR(fw));
++		}
++		get_shaded_geometry(fw, &fw->g.frame, new_g);
++		frame_force_setup_window(
++			fw, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width,
++			fw->g.frame.height, False);
++	}
++	else
++	{
++		get_relative_geometry(new_g, new_g);
++		frame_force_setup_window(
++			fw, new_g->x, new_g->y, new_g->width, new_g->height,
++			True);
++	}
++
++	return;
++}
++
++/* ---------------------------- interface functions ------------------------ */
++
++/* Initialise structures local to frame.c */
++void frame_init(void)
++{
++	XSetWindowAttributes xswa;
++	unsigned long valuemask;
++	int i;
++
++	xswa.override_redirect = True;
++	xswa.backing_store = NotUseful;
++	xswa.save_under = False;
++	xswa.win_gravity = UnmapGravity;
++	xswa.background_pixmap = None;
++	valuemask = CWOverrideRedirect | CWSaveUnder | CWBackingStore |
++		CWBackPixmap | CWWinGravity;
++	hide_wins.parent = Scr.Root;
++	for (i = 0; i < 4; i++)
++	{
++		hide_wins.w[i] = XCreateWindow(
++			dpy, Scr.Root, -1, -1, 1, 1, 0, CopyFromParent,
++			InputOutput, CopyFromParent, valuemask, &xswa);
++		if (hide_wins.w[i] == None)
++		{
++			fvwm_msg(ERR, "frame_init",
++				 "Could not create internal windows. Exiting");
++			MyXUngrabServer(dpy);
++			exit(1);
++		}
++	}
++
++	return;
++}
++
++Bool is_frame_hide_window(
++	Window w)
++{
++	int i;
++
++	if (w == None)
++	{
++		return False;
++	}
++	for (i = 0; i < 4; i++)
++	{
++		if (w == hide_wins.w[i])
++		{
++			return True;
++		}
++	}
++
++	return False;
++}
++
++void frame_destroyed_frame(
++	Window frame_w)
++{
++	if (hide_wins.parent == frame_w)
++	{
++		/* Oops, the window containing the hide windows was destroyed!
++		 * Let it die and create them from scratch. */
++		frame_init();
++	}
++
++	return;
++}
++
++void frame_get_titlebar_dimensions(
++	FvwmWindow *fw, rectangle *frame_g, rectangle *diff_g,
++	frame_title_layout_t *title_layout)
++{
++	size_borders b;
++	int i;
++	int tb_length;
++	int tb_thick;
++	int tb_x;
++	int tb_y;
++	int tb_w;
++	int tb_h;
++	int b_length;
++	int b_w;
++	int b_h;
++	int t_length;
++	int t_w;
++	int t_h;
++	int br_sub;
++	int nbuttons;
++	int nbuttons_big;
++	int *padd_coord;
++	int *b_l;
++	Bool revert_button = False;
++
++	if (!HAS_TITLE(fw))
++	{
++		return;
++	}
++	get_window_borders_no_title(fw, &b);
++	if (HAS_VERTICAL_TITLE(fw))
++	{
++		tb_length = frame_g->height - b.total_size.height;
++	}
++	else
++	{
++		tb_length = frame_g->width - b.total_size.width;
++	}
++	/* find out the length of the title and the buttons */
++	tb_thick = fw->title_thickness;
++	nbuttons = fw->nr_left_buttons + fw->nr_right_buttons;
++	nbuttons_big = 0;
++	b_length = tb_thick;
++	t_length = tb_length - nbuttons * b_length;
++	if (nbuttons > 0 && t_length < MIN_WINDOW_TITLE_LENGTH)
++	{
++		int diff = MIN_WINDOW_TITLE_LENGTH - t_length;
++		int pixels = diff / nbuttons;
++
++		b_length -= pixels;
++		t_length += nbuttons * pixels;
++		nbuttons_big = nbuttons - (MIN_WINDOW_TITLE_LENGTH - t_length);
++		t_length = MIN_WINDOW_TITLE_LENGTH;
++	}
++	if (b_length < MIN_WINDOW_TITLEBUTTON_LENGTH)
++	{
++		/* don't draw the buttons */
++		nbuttons = 0;
++		nbuttons_big = 0;
++		b_length = 0;
++		t_length = tb_length;
++	}
++	if (t_length < 0)
++	{
++		t_length = 0;
++	}
++	fw->title_length = t_length;
++	/* prepare variables */
++	if (HAS_VERTICAL_TITLE(fw))
++	{
++		tb_y = b.top_left.height;
++		br_sub = (diff_g != NULL) ? diff_g->height : 0;
++		if (GET_TITLE_DIR(fw) == DIR_W)
++		{
++			tb_x = b.top_left.width;
++		}
++		else
++		{
++			tb_x = frame_g->width - b.bottom_right.width -
++				tb_thick;
++			if (diff_g != NULL)
++			{
++				tb_x -= diff_g->width;
++			}
++		}
++		padd_coord = &tb_y;
++		b_w = tb_thick;
++		b_h = b_length;
++		t_w = tb_thick;
++		t_h = t_length;
++		b_l = &b_h;
++		tb_w = tb_thick;
++		tb_h = tb_length;
++	}
++	else
++	{
++		tb_x = b.top_left.width;
++		br_sub = (diff_g != NULL) ? diff_g->width : 0;
++		if (GET_TITLE_DIR(fw) == DIR_N)
++		{
++			tb_y = b.top_left.height;
++		}
++		else
++		{
++			tb_y = frame_g->height - b.bottom_right.height -
++				tb_thick;
++			if (diff_g != NULL)
++			{
++				tb_y -= diff_g->height;
++			}
++		}
++		padd_coord = &tb_x;
++		b_w = b_length;
++		b_h = tb_thick;
++		t_w = t_length;
++		t_h = tb_thick;
++		b_l = &b_w;
++		tb_w = tb_length;
++		tb_h = tb_thick;
++	}
++	if (fw->title_text_rotation == ROTATION_270 ||
++	    fw->title_text_rotation == ROTATION_180)
++	{
++		revert_button = True;
++	}
++
++	/* configure left buttons */
++	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++	{
++		if ((revert_button && !(i & 1)) ||
++		    (!revert_button && (i & 1)) || FW_W_BUTTON(fw, i) == None)
++		{
++			continue;
++		}
++		if (b_length <= 0)
++		{
++			title_layout->button_g[i].x = -1;
++			title_layout->button_g[i].y = -1;
++			title_layout->button_g[i].width = 1;
++			title_layout->button_g[i].height = 1;
++		}
++		else
++		{
++			title_layout->button_g[i].x = tb_x;
++			title_layout->button_g[i].y = tb_y;
++			title_layout->button_g[i].width = b_w;
++			title_layout->button_g[i].height = b_h;
++		}
++		*padd_coord += b_length;
++		nbuttons_big--;
++		if (nbuttons_big == 0)
++		{
++			b_length--;
++			(*b_l)--;
++		}
++	}
++	/* configure title */
++	if (t_length == 0)
++	{
++		title_layout->title_g.x = -1;
++		title_layout->title_g.y = -1;
++		title_layout->title_g.width = 1;
++		title_layout->title_g.height = 1;
++	}
++	else
++	{
++		title_layout->title_g.x = tb_x;
++		title_layout->title_g.y = tb_y;
++		title_layout->title_g.width = t_w;
++		title_layout->title_g.height = t_h;
++	}
++	*padd_coord += t_length;
++	/* configure right buttons */
++	*padd_coord -= br_sub;
++	for (i = NUMBER_OF_TITLE_BUTTONS-1; i > -1; i--)
++	{
++		if ((revert_button && (i & 1)) ||
++		    (!revert_button && !(i & 1)) || FW_W_BUTTON(fw, i) == None)
++		{
++			continue;
++		}
++		if (b_length <= 0)
++		{
++			title_layout->button_g[i].x = -1;
++			title_layout->button_g[i].y = -1;
++			title_layout->button_g[i].width = 1;
++			title_layout->button_g[i].height = 1;
++		}
++		else
++		{
++			title_layout->button_g[i].x = tb_x;
++			title_layout->button_g[i].y = tb_y;
++			title_layout->button_g[i].width = b_w;
++			title_layout->button_g[i].height = b_h;
++		}
++		*padd_coord += b_length;
++		nbuttons_big--;
++		if (nbuttons_big == 0)
++		{
++			b_length--;
++			(*b_l)--;
++		}
++	}
++
++	return;
++}
++
++void frame_get_sidebar_geometry(
++	FvwmWindow *fw, DecorFaceStyle *borderstyle, rectangle *frame_g,
++	rectangle *ret_g, Bool *ret_has_x_marks, Bool *ret_has_y_marks)
++{
++	int min_w;
++	size_borders b;
++
++	ret_g->x = 0;
++	ret_g->y = 0;
++	ret_g->width = 0;
++	ret_g->height = 0;
++	*ret_has_x_marks = False;
++	*ret_has_y_marks = False;
++	if (HAS_NO_BORDER(fw))
++	{
++		return;
++	}
++	/* get the corner size */
++	if (!HAS_HANDLES(fw))
++	{
++		*ret_has_x_marks = False;
++		*ret_has_y_marks = False;
++	}
++	else if (borderstyle == NULL)
++	{
++		if (fw->decor_state.parts_drawn & PART_X_HANDLES)
++		{
++			*ret_has_x_marks = True;
++		}
++		if (fw->decor_state.parts_drawn & PART_Y_HANDLES)
++		{
++			*ret_has_y_marks = True;
++		}
++	}
++	else if (!DFS_HAS_HIDDEN_HANDLES(*borderstyle))
++	{
++		*ret_has_x_marks = True;
++		*ret_has_y_marks = True;
++	}
++	ret_g->x = fw->corner_width;
++	ret_g->y = fw->corner_width;
++	min_w = 2 * fw->corner_width + 4;
++	/* limit by available space, remove handle marks if necessary */
++	if (frame_g->width < min_w)
++	{
++		ret_g->x = frame_g->width / 3;
++		*ret_has_y_marks = False;
++	}
++	if (frame_g->height < min_w)
++	{
++		ret_g->y = frame_g->height / 3;
++		*ret_has_x_marks = False;
++	}
++	get_window_borders_no_title(fw, &b);
++	if (ret_g->x < b.top_left.width)
++	{
++		ret_g->x = b.top_left.width;
++	}
++	if (ret_g->y < b.top_left.height)
++	{
++		ret_g->y = b.top_left.height;
++	}
++	/* length of the side bars */
++	ret_g->width = frame_g->width - 2 * ret_g->x;
++	ret_g->height = frame_g->height - 2 * ret_g->y;
++
++	return;
++}
++
++int frame_window_id_to_context(
++	FvwmWindow *fw, Window w, int *ret_num)
++{
++	int context = C_ROOT;
++
++	*ret_num = -1;
++	if (fw == NULL || w == None)
++	{
++		return C_ROOT;
++	}
++	if (w == FW_W_TITLE(fw))
++	{
++		context = C_TITLE;
++	}
++	else if (Scr.EwmhDesktop &&
++		 (w == FW_W(Scr.EwmhDesktop) ||
++		  w == FW_W_PARENT(Scr.EwmhDesktop) ||
++		  w == FW_W_FRAME(Scr.EwmhDesktop)))
++	{
++		context = C_EWMH_DESKTOP;
++	}
++	else if (w == FW_W(fw) || w == FW_W_PARENT(fw) || w == FW_W_FRAME(fw))
++	{
++		context = C_WINDOW;
++	}
++	else if (w == FW_W_ICON_TITLE(fw) || w == FW_W_ICON_PIXMAP(fw))
++	{
++		context = C_ICON;
++	}
++	else if (w == FW_W_CORNER(fw, 0))
++	{
++		*ret_num = 0;
++		context = C_F_TOPLEFT;
++	}
++	else if (w == FW_W_CORNER(fw, 1))
++	{
++		*ret_num = 1;
++		context = C_F_TOPRIGHT;
++	}
++	else if (w == FW_W_CORNER(fw, 2))
++	{
++		*ret_num = 2;
++		context = C_F_BOTTOMLEFT;
++	}
++	else if (w == FW_W_CORNER(fw, 3))
++	{
++		*ret_num = 3;
++		context = C_F_BOTTOMRIGHT;
++	}
++	else if (w == FW_W_SIDE(fw, 0))
++	{
++		*ret_num = 0;
++		context = C_SB_TOP;
++	}
++	else if (w == FW_W_SIDE(fw, 1))
++	{
++		*ret_num = 1;
++		context = C_SB_RIGHT;
++	}
++	else if (w == FW_W_SIDE(fw, 2))
++	{
++		*ret_num = 2;
++		context = C_SB_BOTTOM;
++	}
++	else if (w == FW_W_SIDE(fw, 3))
++	{
++		*ret_num = 3;
++		context = C_SB_LEFT;
++	}
++	else
++	{
++		int i;
++
++		for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++		{
++			if (w == FW_W_BUTTON(fw, i) &&
++			    ((!(i & 1) && i / 2 < Scr.nr_left_buttons) ||
++			     ( (i & 1) && i / 2 < Scr.nr_right_buttons)))
++			{
++				context = (1 << i) * C_L1;
++				*ret_num = i;
++				break;
++			}
++		}
++	}
++	if (!HAS_HANDLES(fw) && (context & (C_SIDEBAR | C_FRAME)))
++	{
++		context = C_SIDEBAR;
++	}
++
++	return context;
++}
++
++/* Creates a structure that must be passed to frame_move_resize().  The
++ * structure *must* be deleted with frame_free_move_resize_args() as soon as the
++ * move or resize operation is finished.  Prepares the window for a move/resize
++ * operation.
++ *
++ * Arguments:
++ *   fw
++ *     The window to move or resize.
++ *   mr_mode
++ *     The mode of operation:
++ *       FRAME_MR_SETUP: setup the frame
++ *       FRAME_MR_FORCE_SETUP: same, but forces all updates
++ *       FRAME_MR_OPAQUE: resize the frame in an opaque fashion
++ *       FRAME_MR_SHRINK: shrink the client window (useful for shading only)
++ *       FRAME_MR_SCROLL: scroll the client window (useful for shading only)
++ *   start_g
++ *     The initial geometry of the frame.  If a NULL pointer is passed, the
++ *     frame_g member of the window is used instead.
++ *   end_g
++ *     The desired new geometry of the frame.
++ *   anim_steps
++ *     The number of animation steps in between
++ *       = 0: The operation is finished in a single step.
++ *       > 0: The given number of steps are drawn in between.
++ *       < 0: Each step resizes the window by the given number of pixels.
++ *            (the sign of the number is flipped first).
++ *     This argument is used only with FRAME_MR_SHRINK and FRAME_MR_SCROLL.
++ */
++frame_move_resize_args frame_create_move_resize_args(
++	FvwmWindow *fw, frame_move_resize_mode mr_mode,
++	rectangle *start_g, rectangle *end_g, int anim_steps, int shade_dir)
++{
++	mr_args_internal *mra;
++	Bool dummy;
++	Bool rc;
++	int whdiff;
++	int xydiff;
++	int diff;
++
++	/* set some variables */
++	mra = (mr_args_internal *)safecalloc(1, sizeof(mr_args_internal));
++	memset(mra, 0, sizeof(*mra));
++	if (mr_mode & FRAME_MR_DONT_DRAW)
++	{
++		mr_mode &= ~FRAME_MR_DONT_DRAW;
++		mra->flags.do_not_draw = 1;
++	}
++	else
++	{
++		mra->flags.do_not_draw = 0;
++	}
++	if (mr_mode == FRAME_MR_SETUP_BY_APP)
++	{
++		mr_mode = FRAME_MR_SETUP;
++		mra->flags.do_set_bit_gravity = 0;
++	}
++	else
++	{
++		mra->flags.do_set_bit_gravity = 1;
++	}
++	if (mr_mode == FRAME_MR_FORCE_SETUP_NO_W)
++	{
++		mr_mode = FRAME_MR_FORCE_SETUP;
++		mra->flags.do_not_configure_client = 1;
++	}
++	mra->mode = mr_mode;
++	mra->shade_dir = (direction_t)shade_dir;
++	mra->w_with_focus = (fw == get_focus_window()) ? FW_W(fw) : None;
++
++	/* calculate various geometries */
++	if (!IS_SHADED(fw))
++	{
++		rc = XGetGeometry(
++			dpy, FW_W(fw), &JunkRoot, &mra->client_g.x,
++			&mra->client_g.y, (unsigned int*)&mra->client_g.width,
++			(unsigned int*)&mra->client_g.height,
++			(unsigned int*)&JunkBW,	(unsigned int*)&JunkDepth);
++		if (rc == True)
++		{
++			rc = XTranslateCoordinates(
++				dpy, FW_W_PARENT(fw), Scr.Root,
++				mra->client_g.x, mra->client_g.y,
++				&mra->client_g.x, &mra->client_g.y,
++				&JunkChild);
++		}
++		if (rc == False)
++		{
++			/* Can only happen if the window died */
++			get_client_geometry(fw, &mra->client_g);
++		}
++	}
++	else
++	{
++		/* If the window was reisez while shaded the client window
++		 * will not have been resized. Use the frame to get the
++		 * geometry */
++		get_client_geometry(fw, &mra->client_g);
++	}
++	get_window_borders(fw, &mra->b_g);
++	get_window_borders_no_title(fw, &mra->b_no_title_g);
++	mra->start_g = (start_g != NULL) ? *start_g : fw->g.frame;
++	frame_get_sidebar_geometry(
++		fw, NULL, &mra->start_g, &mra->curr_sidebar_g, &dummy, &dummy);
++	mra->end_g = *end_g;
++	mra->current_g = mra->start_g;
++	mra->next_g = mra->end_g;
++	mra->curr_titlebar_compression =
++		frame_get_titlebar_compression(fw, &mra->start_g);
++	fvwmrect_subtract_rectangles(
++		&mra->delta_g, &mra->end_g, &mra->start_g);
++
++	/* calcuate the number of animation steps */
++	switch (mra->mode)
++	{
++	case FRAME_MR_SHRINK:
++	case FRAME_MR_SCROLL:
++		whdiff = max(abs(mra->delta_g.width), abs(mra->delta_g.height));
++		xydiff = max(abs(mra->delta_g.x), abs(mra->delta_g.y));
++		diff = max(whdiff, xydiff);
++		if (diff == 0)
++		{
++			mra->anim_steps = 0;
++		}
++		else if (anim_steps < 0)
++		{
++			mra->anim_steps = -(diff - 1) / anim_steps;
++		}
++		else if (anim_steps > 0 && anim_steps >= diff)
++		{
++			mra->anim_steps = diff - 1;
++		}
++		else
++		{
++			mra->anim_steps = anim_steps;
++		}
++		mra->anim_steps++;
++		break;
++	case FRAME_MR_FORCE_SETUP:
++	case FRAME_MR_SETUP:
++	case FRAME_MR_OPAQUE:
++	default:
++		mra->anim_steps = 1;
++		break;
++	}
++
++	/* various flags */
++	mra->flags.was_moved = 0;
++	mra->step_flags.was_hidden =
++		(frame_is_parent_hidden(fw, &mra->start_g) == True);
++	mra->flags.is_setup =
++		(mra->mode == FRAME_MR_FORCE_SETUP ||
++		 mra->mode == FRAME_MR_SETUP);
++	mra->flags.do_force = (mra->mode == FRAME_MR_FORCE_SETUP);
++	mra->flags.is_shading =
++		!(mra->flags.is_setup || mra->mode == FRAME_MR_OPAQUE);
++	mra->flags.do_update_shape =
++		(FShapesSupported && mra->flags.is_shading && fw->wShaped);
++	/* Lazy shading does not draw the hadle marks.  Disable them in the
++	 * window flags if necessary.  Restores the marks when mr_args are
++	 * freed.  Lazy shading is considerably faster but causes funny looks
++	 * if either the border uses a tiled pixmap background. */
++	mra->flags.had_handles = HAS_HANDLES(fw);
++	mra->flags.is_lazy_shading = frame_get_shading_laziness(fw, mra);
++	mra->trans_parts = border_get_transparent_decorations_part(fw);
++	if (mra->flags.is_lazy_shading)
++	{
++		SET_HAS_HANDLES(fw, 0);
++	}
++
++	/* Set gravities for the window parts. */
++	frame_get_resize_decor_gravities(
++		&mra->grav, GET_TITLE_DIR(fw), mra->mode, &mra->delta_g);
++	if (mra->flags.is_setup && mra->delta_g.x == 0 && mra->delta_g.y == 0 &&
++	    mra->delta_g.width == 0 && mra->delta_g.height == 0)
++	{
++		frame_decor_gravities_type grav;
++
++		/* The caller has already set the frame geometry.  Use
++		 * StaticGravity so the sub windows are not moved to funny
++		 * places. */
++		grav.decor_grav = StaticGravity;
++		grav.title_grav = StaticGravity;
++		grav.lbutton_grav = StaticGravity;
++		grav.rbutton_grav = StaticGravity;
++		grav.parent_grav = StaticGravity;
++		grav.client_grav = StaticGravity;
++		frame_set_decor_gravities(
++			fw, &grav, (mra->flags.do_set_bit_gravity) ? 1 : 0);
++		mra->flags.do_restore_gravity = 1;
++		mra->flags.do_force = 1;
++	}
++	else
++	{
++		frame_set_decor_gravities(
++			fw, &mra->grav,
++			(mra->flags.do_set_bit_gravity) ? 1 : 0);
++	}
++	frame_reparent_hide_windows(FW_W_FRAME(fw));
++
++	return (frame_move_resize_args)mra;
++}
++
++/* Changes the final_geometry in a frame_move_resize_args structure.  This is
++ * useful during opaque resize operations to avoid creating and destroying the
++ * args for each animation step.
++ *
++ * If FRAME_MR_SHRINK or  FRAME_MR_SCROLL was used to greate the mr_args, the
++ * function does nothing.
++ */
++void frame_update_move_resize_args(
++	frame_move_resize_args mr_args, rectangle *end_g)
++{
++	mr_args_internal *mra;
++
++	mra = (mr_args_internal *)mr_args;
++	mra->end_g = *end_g;
++	fvwmrect_subtract_rectangles(
++		&mra->delta_g, &mra->end_g, &mra->start_g);
++
++	return;
++}
++
++/* Destroys the structure allocated with frame_create_move_resize_args().  Does
++ * some clean up operations on the modified window first. */
++void frame_free_move_resize_args(
++	FvwmWindow *fw, frame_move_resize_args mr_args)
++{
++	mr_args_internal *mra;
++
++	mra = (mr_args_internal *)mr_args;
++	SET_HAS_HANDLES(fw, mra->flags.had_handles);
++	fw->g.frame = mra->end_g;
++	if (mra->flags.is_lazy_shading)
++	{
++		border_draw_decorations(
++			fw, PART_ALL,
++			(mra->w_with_focus != None) ? True : False, True,
++			CLEAR_ALL, &mra->current_g, &mra->end_g);
++	}
++	else if (mra->trans_parts != PART_NONE)
++	{
++		border_draw_decorations(
++			fw, mra->trans_parts,
++			(mra->w_with_focus != None) ? True : False, True,
++			CLEAR_ALL, &mra->current_g, &mra->end_g);
++	}
++	update_absolute_geometry(fw);
++	frame_reparent_hide_windows(Scr.NoFocusWin);
++	if (mra->w_with_focus != None)
++	{
++		/* domivogt (28-Dec-1999): For some reason the XMoveResize() on
++		 * the frame window removes the input focus from the client
++		 * window.  I have no idea why, but if we explicitly restore
++		 * the focus here everything works fine. */
++		FOCUS_SET(mra->w_with_focus);
++	}
++	if (mra->flags.do_update_shape)
++	{
++		/* unset shape */
++		FShapeCombineMask(
++			dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0, None,
++			FShapeSet);
++	}
++	frame_setup_shape(fw, mra->end_g.width, mra->end_g.height, fw->wShaped);
++	if (mra->flags.do_restore_gravity)
++	{
++		mra->grav.client_grav = fw->hints.win_gravity;
++		frame_set_decor_gravities(
++			fw, &mra->grav,
++			(mra->flags.do_set_bit_gravity) ? 2 : 0);
++	}
++	else
++	{
++		frame_restore_client_gravities(fw);
++	}
++	if (!IS_SHADED(fw) && mra->flags.was_moved)
++	{
++		SendConfigureNotify(
++			fw, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width,
++			fw->g.frame.height, 0, True);
++		mra->flags.was_moved = 0;
++	}
++	focus_grab_buttons_on_layer(fw->layer);
++	/* free the memory */
++	free(mr_args);
++
++	return;
++}
++
++void frame_move_resize(
++	FvwmWindow *fw, frame_move_resize_args mr_args)
++{
++	mr_args_internal *mra;
++	Bool is_grabbed = False;
++	int i;
++
++	mra = (mr_args_internal *)mr_args;
++	/* freeze the cursor shape; otherwise it may flash to a different shape
++	 * during the animation */
++	if (mra->anim_steps > 1)
++	{
++		is_grabbed = GrabEm(None, GRAB_FREEZE_CURSOR);
++	}
++	/* animation */
++	for (i = 1; i <= mra->anim_steps; i++, frame_next_move_resize_args(mra))
++	{
++		mra->current_step = i;
++		frame_move_resize_step(fw, mra);
++	}
++	if (is_grabbed == True)
++	{
++		UngrabEm(GRAB_FREEZE_CURSOR);
++	}
++
++	return;
++}
++
++/***********************************************************************
++ *
++ *  Procedure:
++ *      frame_setup_window - set window sizes
++ *
++ *  Inputs:
++ *      fw - the FvwmWindow pointer
++ *      x       - the x coordinate of the upper-left outer corner of the frame
++ *      y       - the y coordinate of the upper-left outer corner of the frame
++ *      w       - the width of the frame window w/o border
++ *      h       - the height of the frame window w/o border
++ *
++ *  Special Considerations:
++ *      This routine will check to make sure the window is not completely
++ *      off the display, if it is, it'll bring some of it back on.
++ *
++ *      The fw->frame_XXX variables should NOT be updated with the
++ *      values of x,y,w,h prior to calling this routine, since the new
++ *      values are compared against the old to see whether a synthetic
++ *      ConfigureNotify event should be sent.  (It should be sent if the
++ *      window was moved but not resized.)
++ *
++ ************************************************************************/
++void frame_setup_window(
++	FvwmWindow *fw, int x, int y, int w, int h,
++	Bool do_send_configure_notify)
++{
++	rectangle g;
++
++	g.x = x;
++	g.y = y;
++	g.width = w;
++	g.height = h;
++	__frame_setup_window(fw, &g, do_send_configure_notify, False, False);
++
++	return;
++}
++
++void frame_setup_window_app_request(
++	FvwmWindow *fw, int x, int y, int w, int h,
++	Bool do_send_configure_notify)
++{
++	rectangle g;
++
++	g.x = x;
++	g.y = y;
++	g.width = w;
++	g.height = h;
++	__frame_setup_window(fw, &g, do_send_configure_notify, False, True);
++
++	return;
++}
++
++void frame_force_setup_window(
++	FvwmWindow *fw, int x, int y, int w, int h,
++	Bool do_send_configure_notify)
++{
++	rectangle g;
++
++	g.x = x;
++	g.y = y;
++	g.width = w;
++	g.height = h;
++	__frame_setup_window(fw, &g, do_send_configure_notify, True, False);
++
++	return;
++}
++
++/****************************************************************************
++ *
++ * Sets up the shaped window borders
++ *
++ ****************************************************************************/
++void frame_setup_shape(FvwmWindow *fw, int w, int h, int shape_mode)
++{
++	XRectangle rect;
++	rectangle r;
++	size_borders b;
++
++	if (!FShapesSupported)
++	{
++		return;
++	}
++	if (fw->wShaped != shape_mode)
++	{
++		fw->wShaped = shape_mode;
++		frame_reshape_border(fw);
++	}
++	if (!shape_mode)
++	{
++		/* unset shape */
++		FShapeCombineMask(
++			dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0, None,
++			FShapeSet);
++	}
++	else
++	{
++		/* shape the window */
++		get_window_borders(fw, &b);
++		FShapeCombineShape(
++			dpy, FW_W_FRAME(fw), FShapeBounding, b.top_left.width,
++			b.top_left.height, FW_W(fw), FShapeBounding, FShapeSet);
++		if (FW_W_TITLE(fw))
++		{
++			/* windows w/ titles */
++			r.width = w;
++			r.height = h;
++			get_title_geometry(fw, &r);
++			rect.x = r.x;
++			rect.y = r.y;
++			rect.width = r.width;
++			rect.height = r.height;
++			FShapeCombineRectangles(
++				dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0,
++				&rect, 1, FShapeUnion, Unsorted);
++		}
++	}
++
++	return;
++}
++
++/* ---------------------------- builtin commands --------------------------- */
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/frame.h fvwm-2.5.21-08/fvwm/frame.h
+--- fvwm-2.5.21-07/fvwm/frame.h	2007-03-03 13:19:27.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/frame.h	2007-03-03 13:20:06.000000000 +0100
+@@ -1,17 +1,19 @@
+ /* -*-c-*- */
+ 
+ #ifndef FRAME_H
+ #define FRAME_H
+ 
+ /* ---------------------------- included header files ---------------------- */
+ 
++#include "borders.h"
++
+ /* ---------------------------- global definitions ------------------------- */
+ 
+ /* ---------------------------- global macros ------------------------------ */
+ 
+ /* ---------------------------- type definitions --------------------------- */
+ 
+ typedef enum
+ {
+ 	FRAME_MR_SETUP,
+ 	FRAME_MR_SETUP_BY_APP,
+@@ -64,12 +66,14 @@ void frame_setup_window(
+ 	FvwmWindow *fw, int x, int y, int w, int h,
+ 	Bool do_send_configure_notify);
+ void frame_setup_window_app_request(
+ 	FvwmWindow *fw, int x, int y, int w, int h,
+ 	Bool do_send_configure_notify);
+ void frame_force_setup_window(
+ 	FvwmWindow *fw, int x, int y, int w, int h,
+ 	Bool do_send_configure_notify);
+ void frame_setup_shape(
+ 	FvwmWindow *fw, int w, int h, int shape_mode);
++void frame_make_rounded_corners(FvwmWindow *fw);
++void draw_rounded_mask(Window win, int width, int height, Bool slightlyrounded, window_parts draw_parts, int col);
+ 
+ #endif /* FRAME_H */
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/fvwm.h fvwm-2.5.21-08/fvwm/fvwm.h
+--- fvwm-2.5.21-07/fvwm/fvwm.h	2007-03-03 13:19:35.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/fvwm.h	2007-03-03 13:20:06.000000000 +0100
+@@ -265,20 +265,23 @@ typedef struct
+ 		unsigned use_indexed_window_name : 1;
+ 		unsigned use_indexed_icon_name : 1;
+ #define WINDOWSHADE_LAZY          0
+ #define WINDOWSHADE_ALWAYS_LAZY   1
+ #define WINDOWSHADE_BUSY          2
+ #define WINDOWSHADE_LAZY_MASK   0x3
+ 		unsigned windowshade_laziness : 2;
+ 		unsigned use_title_decor_rotation : 1;
+ 		unsigned has_border_under_title : 1;
+ 		unsigned has_fluxbox_handles : 1;
++		unsigned has_rounded_corners_top : 1;
++		unsigned has_rounded_corners_bottom : 1;
++		unsigned has_slightly_rounded_corners : 1;
+ 		focus_policy_t focus_policy;
+ 	} s;
+ } common_flags_t;
+ 
+ typedef struct
+ {
+ 	common_flags_t common;
+ #define CR_MOTION_METHOD_AUTO        0
+ #define CR_MOTION_METHOD_USE_GRAV    1
+ #define CR_MOTION_METHOD_STATIC_GRAV 2
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/menus.c fvwm-2.5.21-08/fvwm/menus.c
+--- fvwm-2.5.21-07/fvwm/menus.c	2007-03-03 13:19:27.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/menus.c	2007-03-03 13:20:06.000000000 +0100
+@@ -56,20 +56,21 @@
+ #include "move_resize.h"
+ #include "menudim.h"
+ #include "menuitem.h"
+ #include "menuroot.h"
+ #include "menustyle.h"
+ #include "bindings.h"
+ #include "menubindings.h"
+ #include "menugeometry.h"
+ #include "menuparameters.h"
+ #include "menus.h"
++#include "frame.h"
+ 
+ /* ---------------------------- local definitions -------------------------- */
+ 
+ /* used in float to int arithmetic */
+ #define ROUNDING_ERROR_TOLERANCE  0.005
+ 
+ /* ---------------------------- local macros ------------------------------- */
+ 
+ /* ---------------------------- imports ------------------------------------ */
+ 
+@@ -2956,20 +2957,27 @@ static int do_menus_overlap(
+ 		x_overlap = x - prior_x;
+ 		if (x <= prior_x)
+ 		{
+ 			x_overlap--;
+ 		}
+ 	}
+ 
+ 	return x_overlap;
+ }
+ 
++static void menu_make_rounded_corners(MenuRoot *mr)
++{
++	draw_rounded_mask(MR_WINDOW(mr), MR_WIDTH(mr), MR_HEIGHT(mr),
++		MST_HAS_SLIGHTLY_ROUNDED_CORNERS(mr),
++		MST_HAS_ROUNDED_CORNERS(mr)?PART_CORNERS:0, 0);
++}
++
+ /*
+  *
+  *  Procedure:
+  *      pop_menu_up - pop up a pull down menu
+  *
+  *  Inputs:
+  *      x, y      - location of upper left of menu
+  *      do_warp_to_item - warp pointer to the first item after title
+  *      pops      - pointer to the menu options for new menu
+  *
+@@ -3532,20 +3540,22 @@ static int pop_menu_up(
+ 	else
+ 	{
+ 		/* sub menus of tear off menus need LeaveNotify */
+ 		event_mask = XEVMASK_TEAR_OFF_SUBMENUW;
+ 	}
+ 
+ 	/*
+ 	 * Pop up the menu
+ 	 */
+ 
++	menu_make_rounded_corners(mr);
++
+ 	XMoveWindow(dpy, MR_WINDOW(mr), x, y);
+ 	XSelectInput(dpy, MR_WINDOW(mr), event_mask);
+ 	XMapRaised(dpy, MR_WINDOW(mr));
+ 	if (popdown_window)
+ 		XUnmapWindow(dpy, popdown_window);
+ 	XFlush(dpy);
+ 	MR_MAPPED_COPIES(mr)++;
+ 	MST_USAGE_COUNT(mr)++;
+ 	if (ret_overlap)
+ 	{
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/menus.c~ fvwm-2.5.21-08/fvwm/menus.c~
+--- fvwm-2.5.21-07/fvwm/menus.c~	2007-03-03 13:19:27.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/menus.c~	2007-03-03 13:19:57.000000000 +0100
+@@ -1456,20 +1456,24 @@ static Bool size_menu_vertically(MenuSiz
+ 	{
+ 		Bool last_item_has_relief =
+ 			(MI_PREV_ITEM(mi)) ?
+ 			MI_IS_SELECTABLE(MI_PREV_ITEM(mi)) : False;
+ 		Bool has_mini_icon = False;
+ 		int separator_height;
+ 
+ 		separator_height = (last_item_has_relief) ?
+ 			MENU_SEPARATOR_HEIGHT + relief_thickness :
+ 			MENU_SEPARATOR_TOTAL_HEIGHT;
++		if (MST_DO_FLAT_SEPARATOR(msp->menu))
++		{
++			separator_height += 1;
++		}
+ 		MI_Y_OFFSET(mi) = y;
+ 		if (MI_IS_TITLE(mi))
+ 		{
+ 			MI_HEIGHT(mi) = MST_PTITLEFONT(msp->menu)->height +
+ 				MST_TITLE_GAP_ABOVE(msp->menu) +
+ 				MST_TITLE_GAP_BELOW(msp->menu);
+ 		}
+ 		else if (MI_IS_SEPARATOR(mi))
+ 		{
+ 			/* Separator */
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/menustyle.c fvwm-2.5.21-08/fvwm/menustyle.c
+--- fvwm-2.5.21-07/fvwm/menustyle.c	2007-03-03 13:19:27.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/menustyle.c	2007-03-03 13:20:06.000000000 +0100
+@@ -396,20 +396,21 @@ static int menustyle_get_styleopt_index(
+ 		"MenuColorset", "ActiveColorset", "GreyedColorset",
+ 		"SelectOnRelease",
+ 		"PopdownImmediately", "PopdownDelayed",
+ 		"PopdownDelay",
+ 		"PopupActiveArea",
+ 		"PopupIgnore", "PopupClose",
+ 		"MouseWheel", "ScrollOffPage",
+ 		"TrianglesUseFore",
+ 		"TitleColorset", "HilightTitleBack",
+ 		"TitleFont", "FlatSeparators",
++		"RoundedCorners", "SlightlyRoundedCorners",
+ 		NULL
+ 	};
+ 
+ 	return GetTokenIndex(option, optlist, 0, NULL);
+ }
+ 
+ static void change_or_make_gc(GC *gc, unsigned long gcm, XGCValues *gcv)
+ {
+ 	if (*gc != None)
+ 	{
+@@ -1561,20 +1562,26 @@ MenuStyle *menustyle_parse_style(F_CMD_A
+ 			else
+ 			{
+ 				ST_PTITLEFONT(tmpms) = new_font;
+ 				ST_USING_DEFAULT_TITLEFONT(tmpms) = False;
+ 			}
+ 			has_gc_changed = True;
+ 			break;
+ 		case 62: /* FlatSeparators */
+ 			ST_DO_FLAT_SEPARATOR(tmpms) = on;
+ 			break;
++		case 63: /* RoundedCorners */
++			ST_HAS_ROUNDED_CORNERS(tmpms) = on;
++			break;
++		case 64: /* SlightlyRoundedCorners */
++			ST_HAS_SLIGHTLY_ROUNDED_CORNERS(tmpms) = on;
++			break;
+ 
+ #if 0
+ 		case 99: /* PositionHints */
+ 			/* to be implemented */
+ 			break;
+ #endif
+ 
+ 		default:
+ 			fvwm_msg(ERR, "NewMenuStyle", "unknown option '%s'",
+ 				 poption);
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/menustyle.c~ fvwm-2.5.21-08/fvwm/menustyle.c~
+--- fvwm-2.5.21-07/fvwm/menustyle.c~	2007-03-03 13:19:27.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/menustyle.c~	2007-03-03 13:19:57.000000000 +0100
+@@ -395,21 +395,21 @@ static int menustyle_get_styleopt_index(
+ 		"VerticalTitleSpacing",
+ 		"MenuColorset", "ActiveColorset", "GreyedColorset",
+ 		"SelectOnRelease",
+ 		"PopdownImmediately", "PopdownDelayed",
+ 		"PopdownDelay",
+ 		"PopupActiveArea",
+ 		"PopupIgnore", "PopupClose",
+ 		"MouseWheel", "ScrollOffPage",
+ 		"TrianglesUseFore",
+ 		"TitleColorset", "HilightTitleBack",
+-		"TitleFont",
++		"TitleFont", "FlatSeparators",
+ 		NULL
+ 	};
+ 
+ 	return GetTokenIndex(option, optlist, 0, NULL);
+ }
+ 
+ static void change_or_make_gc(GC *gc, unsigned long gcm, XGCValues *gcv)
+ {
+ 	if (*gc != None)
+ 	{
+@@ -870,20 +870,21 @@ MenuStyle *menustyle_parse_style(F_CMD_A
+ 			ST_HAS_ACTIVE_FORE(tmpms) = 0;
+ 			ST_HAS_ACTIVE_BACK(tmpms) = 0;
+ 			ST_DO_POPUP_AS(tmpms) = MDP_POST_MENU;
+ 			ST_DOUBLE_CLICK_TIME(tmpms) = DEFAULT_MENU_CLICKTIME;
+ 			ST_POPUP_DELAY(tmpms) = DEFAULT_POPUP_DELAY;
+ 			ST_POPDOWN_DELAY(tmpms) = DEFAULT_POPDOWN_DELAY;
+ 			ST_MOUSE_WHEEL(tmpms) = MMW_POINTER;
+ 			ST_SCROLL_OFF_PAGE(tmpms) = 1;
+ 			ST_DO_HILIGHT_TITLE_BACK(tmpms) = 0;
+ 			ST_USING_DEFAULT_TITLEFONT(tmpms) = True;
++			ST_DO_FLAT_SEPARATOR(tmpms) = 0;
+ 			has_gc_changed = True;
+ 			option = "fvwm";
+ 		}
+ 		else
+ 		{
+ 			/* Read next option specification (delimited by a comma
+ 			 * or \0). */
+ 			args = action;
+ 			action = GetQuotedString(
+ 				action, &optstring, ",", NULL, NULL, NULL);
+@@ -1557,21 +1558,23 @@ MenuStyle *menustyle_parse_style(F_CMD_A
+ 				ST_PTITLEFONT(tmpms) = Scr.DefaultFont;
+ 				ST_USING_DEFAULT_TITLEFONT(tmpms) = True;
+ 			}
+ 			else
+ 			{
+ 				ST_PTITLEFONT(tmpms) = new_font;
+ 				ST_USING_DEFAULT_TITLEFONT(tmpms) = False;
+ 			}
+ 			has_gc_changed = True;
+ 			break;
+-
++		case 62: /* FlatSeparators */
++			ST_DO_FLAT_SEPARATOR(tmpms) = on;
++			break;
+ 
+ #if 0
+ 		case 99: /* PositionHints */
+ 			/* to be implemented */
+ 			break;
+ #endif
+ 
+ 		default:
+ 			fvwm_msg(ERR, "NewMenuStyle", "unknown option '%s'",
+ 				 poption);
+@@ -1811,20 +1814,22 @@ void menustyle_copy(MenuStyle *origms, M
+ 	/* PopdownDelay */
+ 	ST_POPDOWN_DELAY(destms) = ST_POPDOWN_DELAY(origms);
+ 	/* Scroll */
+ 	ST_MOUSE_WHEEL(destms) = ST_MOUSE_WHEEL(origms);
+ 	/* ScrollOffPage */
+ 	ST_SCROLL_OFF_PAGE(destms) = ST_SCROLL_OFF_PAGE(origms);
+ 	/* TrianglesUseFore */
+ 	ST_TRIANGLES_USE_FORE(destms) = ST_TRIANGLES_USE_FORE(origms);
+ 	/* Title */
+ 	ST_DO_HILIGHT_TITLE_BACK(destms) = ST_DO_HILIGHT_TITLE_BACK(origms);
++	/* FlatSeparators */
++	ST_DO_FLAT_SEPARATOR(destms) = ST_DO_FLAT_SEPARATOR(origms);
+ 
+ 	menustyle_update(destms);
+ 
+ 	return;
+ }
+ 
+ /* ---------------------------- builtin commands --------------------------- */
+ 
+ void CMD_CopyMenuStyle(F_CMD_ARGS)
+ {
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/menustyle.h fvwm-2.5.21-08/fvwm/menustyle.h
+--- fvwm-2.5.21-07/fvwm/menustyle.h	2007-03-03