[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