Skip to Content.
Sympa Menu

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

sm-commit AT lists.ibiblio.org

Subject: Source Mage code commit list

List archive

Chronological Thread  
  • From: Florian Franzmann <scm AT mail.sourcemage.org>
  • To: sm-commit AT lists.ibiblio.org
  • Subject: [SM-Commit] GIT changes to master grimoire by Florian Franzmann (32ae7949fc150fa81867eccdf34d531e3acfab93)
  • Date: Sat, 3 Mar 2007 07:03:54 -0600

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 13:19:27.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/menustyle.h 2007-03-03 13:20:06.000000000 +0100
+@@ -18,20 +18,24 @@
+ /* 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_HAS_ROUNDED_CORNERS(s) ((s)->look.flags.has_rounded_corners)
++#define MST_HAS_ROUNDED_CORNERS(m)
((m)->s->ms->look.flags.has_rounded_corners)
++#define ST_HAS_SLIGHTLY_ROUNDED_CORNERS(s)
((s)->look.flags.has_slightly_rounded_corners)
++#define MST_HAS_SLIGHTLY_ROUNDED_CORNERS(m)
((m)->s->ms->look.flags.has_slightly_rounded_corners)
+ #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)
+@@ -271,20 +275,22 @@ typedef struct MenuLook
+ 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;
++ unsigned has_rounded_corners : 1;
++ unsigned has_slightly_rounded_corners : 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 -U10 -Naupr fvwm-2.5.21-07/fvwm/style.c fvwm-2.5.21-08/fvwm/style.c
+--- fvwm-2.5.21-07/fvwm/style.c 2007-03-03 13:19:35.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/style.c 2007-03-03 13:20:06.000000000 +0100
+@@ -3479,20 +3479,41 @@ static Bool style_parse_one_style_option
+ 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 if (StrEquals(token, "RoundedCorners"))
++ {
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCF(*ps), on);
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCM(*ps), 1);
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCC(*ps), 1);
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCF(*ps), on);
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCM(*ps), 1);
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCC(*ps), 1);
++ }
++ else if (StrEquals(token, "RoundedCornersTop"))
++ {
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCF(*ps), on);
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCM(*ps), 1);
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCC(*ps), 1);
++ }
++ else if (StrEquals(token, "RoundedCornersBottom"))
++ {
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCF(*ps), on);
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCM(*ps), 1);
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCC(*ps), 1);
++ }
+ else
+ {
+ found = False;
+ }
+ break;
+
+ case 's':
+ if (StrEquals(token, "SMARTPLACEMENT"))
+ {
+ ps->flags.placement_mode |= PLACE_SMART;
+@@ -3613,20 +3634,26 @@ static Bool style_parse_one_style_option
+ 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, "SlightlyRoundedCorners"))
++ {
++ S_SET_HAS_SLIGHTLY_ROUNDED_CORNERS(SCF(*ps), on);
++ S_SET_HAS_SLIGHTLY_ROUNDED_CORNERS(SCM(*ps), 1);
++ S_SET_HAS_SLIGHTLY_ROUNDED_CORNERS(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"))
+@@ -4478,20 +4505,28 @@ void check_window_style_change(
+ 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;
+ }
++
++ /* has_rounded_corners */
++ if (S_HAS_ROUNDED_CORNERS_TOP(SCC(*ret_style))
++ || S_HAS_ROUNDED_CORNERS_BOTTOM(SCC(*ret_style))
++ || S_HAS_SLIGHTLY_ROUNDED_CORNERS(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)))
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/style.c~ fvwm-2.5.21-08/fvwm/style.c~
+--- fvwm-2.5.21-07/fvwm/style.c~ 2007-03-03 13:19:27.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/style.c~ 2007-03-03 13:19:57.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-07/fvwm/style.h fvwm-2.5.21-08/fvwm/style.h
+--- fvwm-2.5.21-07/fvwm/style.h 2007-03-03 13:19:35.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/style.h 2007-03-03 13:20:06.000000000 +0100
+@@ -342,20 +342,32 @@
+ #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_HAS_ROUNDED_CORNERS_TOP(c) \
++ ((c).s.has_rounded_corners_top)
++#define S_SET_HAS_ROUNDED_CORNERS_TOP(c,x) \
++ ((c).s.has_rounded_corners_top = !!(x))
++#define S_HAS_ROUNDED_CORNERS_BOTTOM(c) \
++ ((c).s.has_rounded_corners_bottom)
++#define S_SET_HAS_ROUNDED_CORNERS_BOTTOM(c,x) \
++ ((c).s.has_rounded_corners_bottom = !!(x))
++#define S_HAS_SLIGHTLY_ROUNDED_CORNERS(c) \
++ ((c).s.has_slightly_rounded_corners)
++#define S_SET_HAS_SLIGHTLY_ROUNDED_CORNERS(c,x) \
++ ((c).s.has_slightly_rounded_corners = !!(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-07/fvwm/window_flags.h
fvwm-2.5.21-08/fvwm/window_flags.h
+--- fvwm-2.5.21-07/fvwm/window_flags.h 2007-03-03 13:19:35.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/window_flags.h 2007-03-03 13:20:06.000000000 +0100
+@@ -309,44 +309,62 @@
+ #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 IS_TOP_TITLE_ROTATED(fw) \
++ ((fw)->flags.common.s.is_top_title_rotated)
++#define SET_IS_TOP_TITLE_ROTATED(fw,x) \
++ (fw)->flags.common.s.is_top_title_rotated = !!(x)
++#define SETM_IS_TOP_TITLE_ROTATED(fw,x) \
++ (fw)->flag_mask.common.s.is_top_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)
+ #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)
++#define HAS_ROUNDED_CORNERS_TOP(fw) \
++ ((fw)->flags.common.s.has_rounded_corners_top)
++#define SET_HAS_ROUNDED_CORNERS_TOP(fw,x) \
++ (fw)->flags.common.s.has_rounded_corners_top = !!(x)
++#define SETM_HAS_ROUNDED_CORNERS_TOP(fw,x) \
++ (fw)->flag_mask.common.s.has_rounded_corners_top = !!(x)
++#define HAS_ROUNDED_CORNERS_BOTTOM(fw) \
++ ((fw)->flags.common.s.has_rounded_corners_bottom)
++#define SET_HAS_ROUNDED_CORNERS_BOTTOM(fw,x) \
++ (fw)->flags.common.s.has_rounded_corners_bottom = !!(x)
++#define SETM_HAS_ROUNDED_CORNERS_BOTTOM(fw,x) \
++ (fw)->flag_mask.common.s.has_rounded_corners_bottom = !!(x)
++#define HAS_SLIGHTLY_ROUNDED_CORNERS(fw) \
++ ((fw)->flags.common.s.has_slightly_rounded_corners)
++#define SET_HAS_SLIGHTLY_ROUNDED_CORNERS_BOTTOM(fw,x) \
++ (fw)->flags.common.s.has_slightly_rounded_corners = !!(x)
++#define SETM_HAS_SLIGHTLY_ROUNDED_CORNERS(fw,x) \
++ (fw)->flag_mask.common.s.has_slightly_rounded_corners = !!(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-07/fvwm/windowshade.c
fvwm-2.5.21-08/fvwm/windowshade.c
+--- fvwm-2.5.21-07/fvwm/windowshade.c 2007-03-03 13:19:27.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/windowshade.c 2007-03-03 13:20:06.000000000 +0100
+@@ -204,20 +204,21 @@ void CMD_WindowShade(F_CMD_ARGS)
+ * animation. */
+ SET_SHADED(fw, toggle);
+ if (toggle == 1)
+ {
+ SET_SHADED_DIR(fw, shade_dir);
+ }
+ frame_free_move_resize_args(fw, mr_args);
+ border_draw_decorations(
+ fw, PART_TITLEBAR, (fw == get_focus_window()) ? True : False,
+ 0, CLEAR_BUTTONS, NULL, NULL);
++ frame_make_rounded_corners(fw);
+ /* update hints and inform modules */
+ BroadcastConfig(M_CONFIGURE_WINDOW, fw);
+ BroadcastPacket(
+ (toggle == 1) ? M_WINDOWSHADE : M_DEWINDOWSHADE, 3,
+ (long)FW_W(fw), (long)FW_W_FRAME(fw), (unsigned long)fw);
+ FlushAllMessageQueues();
+ XFlush(dpy);
+ EWMH_SetWMState(fw, False);
+ GNOME_SetHints(fw);
+ GNOME_SetWinArea(fw);
+diff -U10 -Naupr fvwm-2.5.21-07/fvwm/windowshade.c~
fvwm-2.5.21-08/fvwm/windowshade.c~
+--- fvwm-2.5.21-07/fvwm/windowshade.c~ 1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-08/fvwm/windowshade.c~ 2007-03-03 13:19:57.000000000 +0100
+@@ -0,0 +1,248 @@
++/* -*-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 "fvwm.h"
++#include "externs.h"
++#include "execcontext.h"
++#include "misc.h"
++#include "commands.h"
++#include "screen.h"
++#include "module_list.h"
++#include "module_interface.h"
++#include "geometry.h"
++#include "gnome.h"
++#include "ewmh.h"
++#include "borders.h"
++#include "frame.h"
++#include "focus.h"
++
++/* ---------------------------- local definitions
-------------------------- */
++
++/* ---------------------------- local macros
------------------------------- */
++
++/* ---------------------------- imports
------------------------------------ */
++
++/* ---------------------------- included code files
------------------------ */
++
++/* ---------------------------- local types
-------------------------------- */
++
++/* ---------------------------- forward declarations
----------------------- */
++
++/* ---------------------------- local variables
---------------------------- */
++
++/* ---------------------------- exported variables (globals)
--------------- */
++
++/* ---------------------------- local functions
---------------------------- */
++
++/* ---------------------------- interface functions
------------------------ */
++
++/* ---------------------------- builtin commands
--------------------------- */
++
++/*
++ *
++ * WindowShade -- shades or unshades a window (veliaa AT rpi.edu)
++ *
++ * Args: 1 -- shade, 2 -- unshade No Arg: toggle
++ *
++ */
++void CMD_WindowShade(F_CMD_ARGS)
++{
++ direction_t shade_dir;
++ int toggle;
++ frame_move_resize_mode resize_mode;
++ rectangle start_g;
++ rectangle end_g;
++ frame_move_resize_args mr_args;
++ char *token;
++ char *naction;
++ Bool do_force_shading;
++ Bool has_dir;
++ FvwmWindow * const fw = exc->w.fw;
++
++ if (IS_ICONIFIED(fw) || IS_EWMH_FULLSCREEN(fw))
++ {
++ return;
++ }
++ token = PeekToken(action, &naction);
++ if (StrEquals("shadeagain", token))
++ {
++ do_force_shading = True;
++ action = naction;
++ token = PeekToken(action, &naction);
++ }
++ else
++ {
++ do_force_shading = False;
++ }
++ /* parse arguments */
++ if (StrEquals("Last", token))
++ {
++ /* last given instead of a direction will make
++ * fvwm to reuse the last used shading direction.
++ * A new, nevershaded window will have
++ * USED_TITLE_DIR_FOR_SHADING set (in add_window.c:
++ * setup_window_structure)
++ */
++ action = naction;
++ if (!USED_TITLE_DIR_FOR_SHADING(fw))
++ {
++ shade_dir = SHADED_DIR(fw);
++ }
++ else
++ {
++ shade_dir = DIR_NONE;
++ }
++ }
++ else
++ {
++ /* parse normal direction if last was not given */
++ shade_dir = gravity_parse_dir_argument(action, NULL, -1);
++ }
++
++ if (shade_dir >= 0 && shade_dir <= DIR_MASK)
++ {
++ has_dir = True;
++ toggle = (!IS_SHADED(fw) || SHADED_DIR(fw) != shade_dir);
++ }
++ else
++ {
++ has_dir = False;
++ toggle = ParseToggleArgument(action, NULL, -1, 0);
++ if (toggle == -1 &&
++ GetIntegerArguments(action, NULL, &toggle, 1) > 0)
++ {
++ if (toggle == 1)
++ {
++ toggle = 1;
++ }
++ else if (toggle == 2)
++ {
++ toggle = 0;
++ }
++ else
++ {
++ toggle = -1;
++ }
++ }
++ if (toggle == -1)
++ {
++ toggle = !(IS_SHADED(fw));
++ }
++ if (!IS_SHADED(fw) && toggle == 1)
++ {
++ shade_dir = GET_TITLE_DIR(fw);
++ }
++ else if (IS_SHADED(fw) && toggle == 0)
++ {
++ shade_dir = SHADED_DIR(fw);
++ }
++ else
++ {
++ shade_dir = -1;
++ }
++ }
++ if (!IS_SHADED(fw) && toggle == 0)
++ {
++ /* nothing to do */
++ return;
++ }
++ if (IS_SHADED(fw) && toggle == 1)
++ {
++ if (has_dir == False)
++ {
++ /* nothing to do */
++ return;
++ }
++ else if (do_force_shading == False)
++ {
++ toggle = 0;
++ }
++ else if (shade_dir == SHADED_DIR(fw))
++ {
++ return;
++ }
++ }
++
++ if (toggle == 1)
++ {
++ SET_USED_TITLE_DIR_FOR_SHADING(fw, !has_dir);
++ }
++ /* draw the animation */
++ start_g = fw->g.frame;
++ get_unshaded_geometry(fw, &end_g);
++ if (toggle == 1)
++ {
++ get_shaded_geometry_with_dir(fw, &end_g, &end_g, shade_dir);
++ }
++ resize_mode = (DO_SHRINK_WINDOWSHADE(fw)) ?
++ FRAME_MR_SHRINK : FRAME_MR_SCROLL;
++ mr_args = frame_create_move_resize_args(
++ fw, resize_mode, &start_g, &end_g, fw->shade_anim_steps,
++ shade_dir);
++ frame_move_resize(fw, mr_args);
++ /* Set the new shade value before destroying the args but after the
++ * animation. */
++ SET_SHADED(fw, toggle);
++ if (toggle == 1)
++ {
++ SET_SHADED_DIR(fw, shade_dir);
++ }
++ frame_free_move_resize_args(fw, mr_args);
++ border_draw_decorations(
++ fw, PART_TITLEBAR, (fw == get_focus_window()) ? True : False,
++ 0, CLEAR_BUTTONS, NULL, NULL);
++ /* update hints and inform modules */
++ BroadcastConfig(M_CONFIGURE_WINDOW, fw);
++ BroadcastPacket(
++ (toggle == 1) ? M_WINDOWSHADE : M_DEWINDOWSHADE, 3,
++ (long)FW_W(fw), (long)FW_W_FRAME(fw), (unsigned long)fw);
++ FlushAllMessageQueues();
++ XFlush(dpy);
++ EWMH_SetWMState(fw, False);
++ GNOME_SetHints(fw);
++ GNOME_SetWinArea(fw);
++
++ return;
++}
++
++/* set the number or size of shade animation steps, N => steps, Np =>
pixels */
++void CMD_WindowShadeAnimate(F_CMD_ARGS)
++{
++ char *buf;
++
++ if (!action)
++ {
++ action = "";
++ }
++ fvwm_msg(
++ ERR, "CMD_WindowShadeAnimate",
++ "The WindowShadeAnimate command is obsolete. "
++ "Please use 'Style * WindowShadeSteps %s' instead.", action);
++ buf = safemalloc(strlen(action) + 32);
++ sprintf(buf, "* WindowShadeSteps %s", action);
++ action = buf;
++ CMD_Style(F_PASS_ARGS);
++ free(buf);
++
++ return;
++}
diff --git a/windowmanagers/fvwm/patches/09-TopBorder.patch
b/windowmanagers/fvwm/patches/09-TopBorder.patch
new file mode 100644
index 0000000..e3ee3f6
--- /dev/null
+++ b/windowmanagers/fvwm/patches/09-TopBorder.patch
@@ -0,0 +1,649 @@
+diff -U10 -Naupr fvwm-2.5.21-08/fvwm/fvwm.h fvwm-2.5.21-09/fvwm/fvwm.h
+--- fvwm-2.5.21-08/fvwm/fvwm.h 2007-03-03 13:20:06.000000000 +0100
++++ fvwm-2.5.21-09/fvwm/fvwm.h 2007-03-03 13:20:24.000000000 +0100
+@@ -268,20 +268,21 @@ typedef struct
+ #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;
++ unsigned has_no_top_border : 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-08/fvwm/fvwm.h~ fvwm-2.5.21-09/fvwm/fvwm.h~
+--- fvwm-2.5.21-08/fvwm/fvwm.h~ 2007-03-03 13:19:57.000000000 +0100
++++ fvwm-2.5.21-09/fvwm/fvwm.h~ 2007-03-03 13:20:16.000000000 +0100
+@@ -264,20 +264,24 @@ 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;
++ 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
+@@ -519,20 +523,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 +627,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-08/fvwm/geometry.c
fvwm-2.5.21-09/fvwm/geometry.c
+--- fvwm-2.5.21-08/fvwm/geometry.c 2007-03-03 13:19:57.000000000 +0100
++++ fvwm-2.5.21-09/fvwm/geometry.c 2007-03-03 13:20:24.000000000 +0100
+@@ -473,69 +473,97 @@ 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 *title_border = NULL;
+ 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;
+
+ title_thickness = fw->title_thickness;
+ if (HAS_TITLE(fw) && HAS_BORDER_UNDER_TITLE(fw) && !is_shaded)
+ {
+ title_thickness += bw;
+ }
+
+ switch (GET_TITLE_DIR(fw))
+ {
+ case DIR_N:
+- borders->top_left.height += title_thickness;
++ title_border = &borders->top_left.height;
+ break;
+ case DIR_S:
+- borders->bottom_right.height += title_thickness;
++ title_border = &borders->bottom_right.height;
+ break;
+ case DIR_W:
+- borders->top_left.width += title_thickness;
++ title_border = &borders->top_left.width;
+ break;
+ case DIR_E:
+- borders->bottom_right.width += title_thickness;
++ title_border = &borders->bottom_right.width;
+ break;
+ }
++
++ if (HAS_NO_TOP_BORDER(fw))
++ {
++ *title_border = 1;
++ }
++ *title_border += title_thickness;
++
+ 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)
+ {
+ 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;
++
++ if (HAS_NO_TOP_BORDER(fw))
++ {
++ switch (GET_TITLE_DIR(fw))
++ {
++ case DIR_N:
++ borders->top_left.height = 1;
++ break;
++ case DIR_S:
++ borders->bottom_right.height = 1;
++ break;
++ case DIR_W:
++ borders->top_left.width = 1;
++ break;
++ case DIR_E:
++ borders->bottom_right.width = 1;
++ 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;
+ }
+
+ void set_window_border_size(
+ FvwmWindow *fw, int used_width)
+diff -U10 -Naupr fvwm-2.5.21-08/fvwm/geometry.c~
fvwm-2.5.21-09/fvwm/geometry.c~
+--- fvwm-2.5.21-08/fvwm/geometry.c~ 2007-03-03 13:19:57.000000000 +0100
++++ fvwm-2.5.21-09/fvwm/geometry.c~ 2007-03-03 13:20:16.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-08/fvwm/style.c fvwm-2.5.21-09/fvwm/style.c
+--- fvwm-2.5.21-08/fvwm/style.c 2007-03-03 13:20:06.000000000 +0100
++++ fvwm-2.5.21-09/fvwm/style.c 2007-03-03 13:20:24.000000000 +0100
+@@ -3885,20 +3885,26 @@ static Bool style_parse_one_style_option
+ 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, "TopBorder"))
++ {
++ S_SET_HAS_NO_TOP_BORDER(SCF(*ps), !on);
++ S_SET_HAS_NO_TOP_BORDER(SCM(*ps), 1);
++ S_SET_HAS_NO_TOP_BORDER(SCC(*ps), 1);
++ }
+ 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);
+@@ -4519,20 +4525,25 @@ void check_window_style_change(
+ || S_HAS_SLIGHTLY_ROUNDED_CORNERS(SCC(*ret_style)))
+ {
+ flags->do_redecorate = True;
+ }
+
+ if (S_HAS_BORDER_UNDER_TITLE(SCC(*ret_style)))
+ {
+ flags->do_redecorate = True;
+ }
+
++ if (S_HAS_NO_TOP_BORDER(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 */
+ if (S_HAS_ICON_FONT(SCC(*ret_style)))
+diff -U10 -Naupr fvwm-2.5.21-08/fvwm/style.c~ fvwm-2.5.21-09/fvwm/style.c~
+--- fvwm-2.5.21-08/fvwm/style.c~ 2007-03-03 13:19:57.000000000 +0100
++++ fvwm-2.5.21-09/fvwm/style.c~ 2007-03-03 13:20:16.000000000 +0100
+@@ -3479,20 +3479,41 @@ static Bool style_parse_one_style_option
+ 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 if (StrEquals(token, "RoundedCorners"))
++ {
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCF(*ps), on);
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCM(*ps), 1);
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCC(*ps), 1);
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCF(*ps), on);
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCM(*ps), 1);
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCC(*ps), 1);
++ }
++ else if (StrEquals(token, "RoundedCornersTop"))
++ {
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCF(*ps), on);
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCM(*ps), 1);
++ S_SET_HAS_ROUNDED_CORNERS_TOP(SCC(*ps), 1);
++ }
++ else if (StrEquals(token, "RoundedCornersBottom"))
++ {
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCF(*ps), on);
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCM(*ps), 1);
++ S_SET_HAS_ROUNDED_CORNERS_BOTTOM(SCC(*ps), 1);
++ }
+ else
+ {
+ found = False;
+ }
+ break;
+
+ case 's':
+ if (StrEquals(token, "SMARTPLACEMENT"))
+ {
+ ps->flags.placement_mode |= PLACE_SMART;
+@@ -3613,20 +3634,26 @@ static Bool style_parse_one_style_option
+ 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, "SlightlyRoundedCorners"))
++ {
++ S_SET_HAS_SLIGHTLY_ROUNDED_CORNERS(SCF(*ps), on);
++ S_SET_HAS_SLIGHTLY_ROUNDED_CORNERS(SCM(*ps), 1);
++ S_SET_HAS_SLIGHTLY_ROUNDED_CORNERS(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"))
+@@ -4478,20 +4505,28 @@ void check_window_style_change(
+ 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;
+ }
++
++ /* has_rounded_corners */
++ if (S_HAS_ROUNDED_CORNERS_TOP(SCC(*ret_style))
++ || S_HAS_ROUNDED_CORNERS_BOTTOM(SCC(*ret_style))
++ || S_HAS_SLIGHTLY_ROUNDED_CORNERS(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)))
+diff -U10 -Naupr fvwm-2.5.21-08/fvwm/style.h fvwm-2.5.21-09/fvwm/style.h
+--- fvwm-2.5.21-08/fvwm/style.h 2007-03-03 13:20:06.000000000 +0100
++++ fvwm-2.5.21-09/fvwm/style.h 2007-03-03 13:20:24.000000000 +0100
+@@ -354,20 +354,25 @@
+ #define S_SET_HAS_ROUNDED_CORNERS_TOP(c,x) \
+ ((c).s.has_rounded_corners_top = !!(x))
+ #define S_HAS_ROUNDED_CORNERS_BOTTOM(c) \
+ ((c).s.has_rounded_corners_bottom)
+ #define S_SET_HAS_ROUNDED_CORNERS_BOTTOM(c,x) \
+ ((c).s.has_rounded_corners_bottom = !!(x))
+ #define S_HAS_SLIGHTLY_ROUNDED_CORNERS(c) \
+ ((c).s.has_slightly_rounded_corners)
+ #define S_SET_HAS_SLIGHTLY_ROUNDED_CORNERS(c,x) \
+ ((c).s.has_slightly_rounded_corners = !!(x))
++#define S_HAS_NO_TOP_BORDER(c) \
++ ((c).s.has_no_top_border)
++#define S_SET_HAS_NO_TOP_BORDER(c,x) \
++ ((c).s.has_no_top_border = !!(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-08/fvwm/style.h~ fvwm-2.5.21-09/fvwm/style.h~
+--- fvwm-2.5.21-08/fvwm/style.h~ 2007-03-03 13:19:57.000000000 +0100
++++ fvwm-2.5.21-09/fvwm/style.h~ 2007-03-03 13:20:16.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,36 @@
+ #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_HAS_ROUNDED_CORNERS_TOP(c) \
++ ((c).s.has_rounded_corners_top)
++#define S_SET_HAS_ROUNDED_CORNERS_TOP(c,x) \
++ ((c).s.has_rounded_corners_top = !!(x))
++#define S_HAS_ROUNDED_CORNERS_BOTTOM(c) \
++ ((c).s.has_rounded_corners_bottom)
++#define S_SET_HAS_ROUNDED_CORNERS_BOTTOM(c,x) \
++ ((c).s.has_rounded_corners_bottom = !!(x))
++#define S_HAS_SLIGHTLY_ROUNDED_CORNERS(c) \
++ ((c).s.has_slightly_rounded_corners)
++#define S_SET_HAS_SLIGHTLY_ROUNDED_CORNERS(c,x) \
++ ((c).s.has_slightly_rounded_corners = !!(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 +512,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-08/fvwm/window_flags.h
fvwm-2.5.21-09/fvwm/window_flags.h
+--- fvwm-2.5.21-08/fvwm/window_flags.h 2007-03-03 13:20:06.000000000 +0100
++++ fvwm-2.5.21-09/fvwm/window_flags.h 2007-03-03 13:20:24.000000000 +0100
+@@ -351,20 +351,26 @@
+ #define SET_HAS_ROUNDED_CORNERS_BOTTOM(fw,x) \
+ (fw)->flags.common.s.has_rounded_corners_bottom = !!(x)
+ #define SETM_HAS_ROUNDED_CORNERS_BOTTOM(fw,x) \
+ (fw)->flag_mask.common.s.has_rounded_corners_bottom = !!(x)
+ #define HAS_SLIGHTLY_ROUNDED_CORNERS(fw) \
+ ((fw)->flags.common.s.has_slightly_rounded_corners)
+ #define SET_HAS_SLIGHTLY_ROUNDED_CORNERS_BOTTOM(fw,x) \
+ (fw)->flags.common.s.has_slightly_rounded_corners = !!(x)
+ #define SETM_HAS_SLIGHTLY_ROUNDED_CORNERS(fw,x) \
+ (fw)->flag_mask.common.s.has_slightly_rounded_corners = !!(x)
++#define HAS_NO_TOP_BORDER(fw) \
++ ((fw)->flags.common.s.has_no_top_border)
++#define SET_HAS_NO_TOP_BORDER(fw,x) \
++ (fw)->flags.common.s.has_no_top_border = !!(x)
++#define SETM_HAS_NO_TOP_BORDER(fw,x) \
++ (fw)->flag_mask.common.s.has_no_top_border = !!(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-08/fvwm/window_flags.h~
fvwm-2.5.21-09/fvwm/window_flags.h~
+--- fvwm-2.5.21-08/fvwm/window_flags.h~ 2007-03-03 13:19:57.000000000
+0100
++++ fvwm-2.5.21-09/fvwm/window_flags.h~ 2007-03-03 13:20:16.000000000
+0100
+@@ -309,38 +309,62 @@
+ #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 IS_TOP_TITLE_ROTATED(fw) \
++ ((fw)->flags.common.s.is_top_title_rotated)
++#define SET_IS_TOP_TITLE_ROTATED(fw,x) \
++ (fw)->flags.common.s.is_top_title_rotated = !!(x)
++#define SETM_IS_TOP_TITLE_ROTATED(fw,x) \
++ (fw)->flag_mask.common.s.is_top_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)
++#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)
++#define HAS_ROUNDED_CORNERS_TOP(fw) \
++ ((fw)->flags.common.s.has_rounded_corners_top)
++#define SET_HAS_ROUNDED_CORNERS_TOP(fw,x) \
++ (fw)->flags.common.s.has_rounded_corners_top = !!(x)
++#define SETM_HAS_ROUNDED_CORNERS_TOP(fw,x) \
++ (fw)->flag_mask.common.s.has_rounded_corners_top = !!(x)
++#define HAS_ROUNDED_CORNERS_BOTTOM(fw) \
++ ((fw)->flags.common.s.has_rounded_corners_bottom)
++#define SET_HAS_ROUNDED_CORNERS_BOTTOM(fw,x) \
++ (fw)->flags.common.s.has_rounded_corners_bottom = !!(x)
++#define SETM_HAS_ROUNDED_CORNERS_BOTTOM(fw,x) \
++ (fw)->flag_mask.common.s.has_rounded_corners_bottom = !!(x)
++#define HAS_SLIGHTLY_ROUNDED_CORNERS(fw) \
++ ((fw)->flags.common.s.has_slightly_rounded_corners)
++#define SET_HAS_SLIGHTLY_ROUNDED_CORNERS_BOTTOM(fw,x) \
++ (fw)->flags.common.s.has_slightly_rounded_corners = !!(x)
++#define SETM_HAS_SLIGHTLY_ROUNDED_CORNERS(fw,x) \
++ (fw)->flag_mask.common.s.has_slightly_rounded_corners = !!(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/10-ButtonWidth.patch
b/windowmanagers/fvwm/patches/10-ButtonWidth.patch
new file mode 100644
index 0000000..69faff6
--- /dev/null
+++ b/windowmanagers/fvwm/patches/10-ButtonWidth.patch
@@ -0,0 +1,370 @@
+diff -U10 -Naupr fvwm-2.5.21-09/fvwm/builtins.c
fvwm-2.5.21-10/fvwm/builtins.c
+--- fvwm-2.5.21-09/fvwm/builtins.c 2007-03-03 13:20:16.000000000 +0100
++++ fvwm-2.5.21-10/fvwm/builtins.c 2007-03-03 13:20:47.000000000 +0100
+@@ -478,20 +478,35 @@ static void do_title_style(F_CMD_ARGS, B
+ if (decor->title_height != height ||
+ decor->min_title_height != 0)
+ {
+ decor->title_height = height;
+ decor->min_title_height = 0;
+ decor->flags.has_title_height_changed = 1;
+ }
+ if (action)
+ action += next;
+ }
++ else if (!do_add && StrEquals(parm,"buttonwidth"))
++ {
++ int width = 0;
++ int next = 0;
++
++ sscanf(action, "%d%n", &width, &next);
++
++ if (decor->button_width != width)
++ {
++ decor->button_width = width;
++ decor->flags.has_changed = 1;
++ }
++ if (action)
++ action += next;
++ }
+ else if (!do_add && StrEquals(parm,"MinHeight"))
+ {
+ int height = 0;
+ int next = 0;
+
+ if (!action ||
+ sscanf(action, "%d%n", &height, &next) <= 0 ||
+ height < MIN_FONT_HEIGHT ||
+ height > MAX_FONT_HEIGHT)
+ {
+diff -U10 -Naupr fvwm-2.5.21-09/fvwm/frame.c fvwm-2.5.21-10/fvwm/frame.c
+--- fvwm-2.5.21-09/fvwm/frame.c 2007-03-03 13:20:16.000000000 +0100
++++ fvwm-2.5.21-10/fvwm/frame.c 2007-03-03 13:20:47.000000000 +0100
+@@ -1363,21 +1363,28 @@ void frame_get_titlebar_dimensions(
+ 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;
++ if (fw->decor->button_width == 0)
++ {
++ b_length = tb_thick;
++ }
++ else
++ {
++ b_length = fw->decor->button_width;
++ }
+ 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;
+diff -U10 -Naupr fvwm-2.5.21-09/fvwm/frame.c~ fvwm-2.5.21-10/fvwm/frame.c~
+--- fvwm-2.5.21-09/fvwm/frame.c~ 2007-03-03 13:20:16.000000000 +0100
++++ fvwm-2.5.21-10/fvwm/frame.c~ 2007-03-03 13:20:40.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-09/fvwm/screen.h fvwm-2.5.21-10/fvwm/screen.h
+--- fvwm-2.5.21-09/fvwm/screen.h 2007-03-03 13:20:16.000000000 +0100
++++ fvwm-2.5.21-10/fvwm/screen.h 2007-03-03 13:20:47.000000000 +0100
+@@ -279,20 +279,21 @@ typedef struct
+ #define TB_HAS_MWM_DECOR_STICK(tb) \
+ (!!((tb).flags.mwm_decor_flags & MWM_DECOR_STICK))
+
+ typedef struct FvwmDecor
+ {
+ #ifdef USEDECOR
+ char *tag; /* general style tag */
+ #endif
+ int title_height; /* explicitly specified title bar height
*/
+ int min_title_height;
++ int button_width;
+ /* titlebar buttons */
+ TitleButton buttons[NUMBER_OF_TITLE_BUTTONS];
+ TitleButton titlebar;
+ struct BorderStyle
+ {
+ DecorFace active, inactive;
+ } BorderStyle;
+ #ifdef USEDECOR
+ struct FvwmDecor *next; /* additional user-defined styles */
+ #endif
diff --git a/windowmanagers/fvwm/patches/11-MultiBorder.patch
b/windowmanagers/fvwm/patches/11-MultiBorder.patch
new file mode 100644
index 0000000..bfc0989
--- /dev/null
+++ b/windowmanagers/fvwm/patches/11-MultiBorder.patch
@@ -0,0 +1,5638 @@
+diff -U10 -Naupr fvwm-2.5.21-10/fvwm/borders.c fvwm-2.5.21-11/fvwm/borders.c
+--- fvwm-2.5.21-10/fvwm/borders.c 2007-03-03 13:20:40.000000000 +0100
++++ fvwm-2.5.21-11/fvwm/borders.c 2007-03-03 13:23:02.000000000 +0100
+@@ -1272,20 +1272,21 @@ static void border_fill_pixmap_backgroun
+ 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);
+@@ -1462,25 +1463,38 @@ static void border_get_frame_pixmap(
+ 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)
++ rectangle *part_g, rectangle *relative_g, int *free_bg_pixmap, Window
w, FvwmPicture *fp)
+ {
+ *free_bg_pixmap = False;
+
+- if (cd->texture_pixmap)
++ if (fp)
++ {
++ bg->flags.use_pixmap = 1;
++ bg->pixmap.p = fp->picture;
++ bg->pixmap.g.width = fp->width;
++ bg->pixmap.g.height = fp->height;
++ bg->pixmap.shape = None;
++ bg->pixmap.alpha = None;
++ bg->pixmap.depth = fp->depth;
++ bg->pixmap.flags.is_tiled = 1;
++ bg->pixmap.flags.is_stretched = 0;
++ bg->pixmap.fra.mask = 0;
++ }
++ else 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;
+@@ -1534,47 +1548,80 @@ static void border_get_border_background
+ }
+ else
+ {
+ bg->flags.use_pixmap = 0;
+ bg->pixel = cd->attributes.background_pixel;
+ }
+
+ return;
+ }
+
++#define DRAWBORDER(PIX,X,Y,WIDTH,HEIGHT) \
++ { \
++ fp = df->u.mb.pixmaps[PIX]; \
++ border_get_border_background( \
++ &bg, cd, &part_g, &relative_g, &free_bg_pixmap, w,
fp); \
++ r.x = X; \
++ r.y = Y; \
++ r.width = WIDTH; \
++ r.height = HEIGHT; \
++ border_fill_pixmap_background(p, &r, &bg, cd); \
++ }
++
+ 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;
++ int x, y, width, height;
+
+ /* 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);
++
++ DecorFace* df;
++ FvwmPicture* fp = 0;
++ df = border_get_border_style(fw, (Scr.Hilite == fw));
++ if (DFS_FACE_TYPE(df->style) == MultiBorder)
++ {
++ int id = -1;
++ if (part==PART_BORDER_NW) id = 0;
++ if (part==PART_BORDER_N) id = 1;
++ if (part==PART_BORDER_NE) id = 2;
++ if (part==PART_BORDER_E) id = 3;
++ if (part==PART_BORDER_SE) id = 4;
++ if (part==PART_BORDER_S) id = 5;
++ if (part==PART_BORDER_SW) id = 6;
++ if (part==PART_BORDER_W) id = 7;
++
++ if (id>=0 && df->u.mb.pixmaps[id])
++ {
++ fp = df->u.mb.pixmaps[id];
++ }
++ }
++
+ 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;
+@@ -1603,43 +1650,131 @@ static void border_draw_one_border_part(
+ 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);
++
++ border_get_border_background(
++ &bg, cd, &part_g, &relative_g, &free_bg_pixmap, w, fp);
++
++ int px = bg.pixmap.g.x;
++ int py = bg.pixmap.g.y;
++
++ if (fp)
++ {
++ /* Position pixmap so that it's aligned to the edge of the
window */
++ if (part & PART_BOTTOM)
++ {
++ bg.pixmap.g.y = fp->height - sidebar_g->y;
++ if (part == PART_BORDER_S)
++ {
++ bg.pixmap.g.y = fp->height -
fw->boundary_width;
++ }
++ }
++ if (part & PART_RIGHT)
++ {
++ bg.pixmap.g.x = fp->width - sidebar_g->x;
++ if (part == PART_BORDER_E)
++ {
++ bg.pixmap.g.x = fp->width -
fw->boundary_width;
++ }
++ }
++ }
++
++ /* 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);
++
++ bg.pixmap.g.x = px;
++ bg.pixmap.g.y = py;
++
++ if (fp)
++ {
++ height = pix_g.height;
++ width = pix_g.width;
++ x = pix_g.x;
++ y = pix_g.y;
++
++ /* draw parts from other borders that overflow because of
their width/height */
++ rectangle r;
++ if (part==PART_BORDER_S)
++ {
++ DRAWBORDER(6, pix_g.x - sidebar_g->x,
fw->boundary_width - fp->height, fp->width - sidebar_g->x, height);
++ DRAWBORDER(4, pix_g.width - fp->width + sidebar_g->x,
fw->boundary_width - fp->height, fp->width - sidebar_g->x, height);
++ }
++ if (!IS_SHADED(fw))
++ {
++ if (part==PART_BORDER_E)
++ {
++ DRAWBORDER(2, fw->boundary_width - fp->width,
pix_g.y - sidebar_g->y, width, fp->height - sidebar_g->y);
++ DRAWBORDER(4, fw->boundary_width - fp->width,
pix_g.height - fp->height + sidebar_g->y, width, fp->height - sidebar_g->y);
++ }
++ if (part==PART_BORDER_W)
++ {
++ DRAWBORDER(0, x, pix_g.y - sidebar_g->y, width,
fp->height - sidebar_g->y);
++ DRAWBORDER(6, x, pix_g.height - fp->height +
sidebar_g->y, width, fp->height - sidebar_g->y);
++ }
++ }
++ if (part==PART_BORDER_N)
++ {
++ DRAWBORDER(2, pix_g.width - fp->width + sidebar_g->x,
y, fp->width - sidebar_g->x, height);
++ DRAWBORDER(0, pix_g.x - fp->width + sidebar_g->x, y, fp->width
- sidebar_g->x, height);
++ }
++ /* Use the top border for the whole height of the titlebar,
overflowing to parts of the bottom corners if shaded */
++ if (IS_SHADED(fw))
++ {
++ if (part==PART_BORDER_W)
++ {
++ DRAWBORDER(0, 0, -height, width, height);
++ }
++ if (part==PART_BORDER_SW)
++ {
++ DRAWBORDER(0, 0, -height*2, width, height -
fw->boundary_width);
++ }
++ if (part==PART_BORDER_E)
++ {
++ DRAWBORDER(2, fw->boundary_width - fp->width,
-height, width, height);
++ }
++ if (part==PART_BORDER_SE)
++ {
++ DRAWBORDER(2, width - fp->width, -height*2,
width, height - fw->boundary_width);
++ }
++ }
++ }
++
+ 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 && !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)
+@@ -1679,21 +1814,21 @@ static void border_draw_all_border_parts
+ {
+ 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,
+@@ -3306,21 +3441,21 @@ static void border_set_button_pixmap(
+ 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, td->cd, button_g, &relative_g, &free_bg_pixmap,
w, 0);
+ 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)
+@@ -3756,21 +3891,21 @@ static void border_set_title_pixmap(
+ 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);
++ &free_bg_pixmap, w, 0);
+ 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);
+diff -U10 -Naupr fvwm-2.5.21-10/fvwm/borders.c~
fvwm-2.5.21-11/fvwm/borders.c~
+--- fvwm-2.5.21-10/fvwm/borders.c~ 2007-03-03 13:20:40.000000000 +0100
++++ fvwm-2.5.21-11/fvwm/borders.c~ 2007-03-03 13:20:56.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-10/fvwm/builtins.c
fvwm-2.5.21-11/fvwm/builtins.c
+--- fvwm-2.5.21-10/fvwm/builtins.c 2007-03-03 13:20:47.000000000 +0100
++++ fvwm-2.5.21-11/fvwm/builtins.c 2007-03-03 13:21:03.000000000 +0100
+@@ -763,20 +763,64 @@ static char *ReadMultiPixmapDecor(char *
+ }
+ free(pm);
+ free(acs);
+ free(pixels);
+ return NULL;
+ }
+
+ return s;
+ }
+
++static char *ReadMultiBorderDecor(char *s, DecorFace *df)
++{
++ FvwmPictureAttributes fpa;
++ FvwmPicture **pm;
++ char *token;
++ int x;
++ int y;
++
++ pm = df->u.mb.pixmaps;
++ df->style.face_type = MultiBorder;
++
++ for (x = 0; x < 8; x++)
++ {
++ s = DoPeekToken(s, &token, " ", NULL, NULL);
++ if (s == NULL)
++ {
++ break;
++ }
++ if (pm[x])
++ {
++ PDestroyFvwmPicture(dpy, pm[x]);
++ }
++ pm[x] = PCacheFvwmPicture(dpy, Scr.NoFocusWin, NULL,
++ token, fpa);
++
++ if (!pm[x])
++ {
++ fvwm_msg(ERR, "ReadMultiBorderDecor",
++ "Pixmap '%s' could not be loaded",
++ token);
++ for(y = 0; y < x; y++)
++ {
++ if (pm[y])
++ {
++ PDestroyFvwmPicture(dpy, pm[y]);
++ }
++ }
++ return NULL;
++ }
++ }
++
++ return s;
++}
++
+ /*
+ *
+ * DestroyFvwmDecor -- frees all memory assocated with an FvwmDecor
+ * structure, but does not free the FvwmDecor itself
+ *
+ */
+ static void DestroyFvwmDecor(FvwmDecor *decor)
+ {
+ int i;
+ /* reset to default button set (frees allocated mem) */
+@@ -1472,20 +1516,28 @@ void FreeDecorFace(Display *dpy, DecorFa
+ }
+ if (df->u.mp.acs)
+ {
+ free(df->u.mp.acs);
+ }
+ if (df->u.mp.pixels)
+ {
+ free(df->u.mp.pixels);
+ }
+ break;
++ case MultiBorder:
++ for (i = 0; i < 8; i++)
++ {
++ if (df->u.mb.pixmaps[i])
++ {
++ PDestroyFvwmPicture(dpy, df->u.mb.pixmaps[i]);
++ }
++ }
+ case VectorButton:
+ case DefaultVectorButton:
+ if (df->u.vector.x)
+ {
+ free (df->u.vector.x);
+ }
+ if (df->u.vector.y)
+ {
+ free (df->u.vector.y);
+ }
+@@ -1841,20 +1893,29 @@ Bool ReadDecorFace(char *s, DecorFace *d
+ " for TitleStyle");
+ }
+ return False;
+ }
+ s = ReadMultiPixmapDecor(s, df);
+ if (!s)
+ {
+ return False;
+ }
+ }
++ else if (strncasecmp(style,"MultiBorder",11)==0)
++ {
++ s = ReadMultiBorderDecor(s, df);
++ if (!s)
++ {
++ return False;
++ }
++ DFS_FACE_TYPE(df->style) = MultiBorder;
++ }
+ else if (FMiniIconsSupported &&
+ strncasecmp (style, "MiniIcon", 8) == 0)
+ {
+ memset(&df->style, 0, sizeof(df->style));
+ DFS_FACE_TYPE(df->style) = MiniIconButton;
+ /* pixmap read in when the window is created */
+ df->u.p = NULL;
+ }
+ else if (strncasecmp (style, "Colorset", 8) == 0)
+ {
+diff -U10 -Naupr fvwm-2.5.21-10/fvwm/builtins.c~
fvwm-2.5.21-11/fvwm/builtins.c~
+--- fvwm-2.5.21-10/fvwm/builtins.c~ 1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-11/fvwm/builtins.c~ 2007-03-03 13:20:56.000000000 +0100
+@@ -0,0 +1,4450 @@
++/* -*-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 <unistd.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <X11/keysym.h>
++
++#include "libs/fvwmlib.h"
++#include "libs/fvwmsignal.h"
++#include "libs/setpgrp.h"
++#include "libs/Picture.h"
++#include "libs/PictureUtils.h"
++#include "libs/FGettext.h"
++#include "libs/charmap.h"
++#include "libs/wcontext.h"
++#include "fvwm.h"
++#include "externs.h"
++#include "colorset.h"
++#include "bindings.h"
++#include "misc.h"
++#include "cursor.h"
++#include "functions.h"
++#include "commands.h"
++#include "screen.h"
++#include "builtins.h"
++#include "module_interface.h"
++#include "borders.h"
++#include "frame.h"
++#include "events.h"
++#include "ewmh.h"
++#include "virtual.h"
++#include "decorations.h"
++#include "add_window.h"
++#include "update.h"
++#include "style.h"
++#include "move_resize.h"
++#include "menus.h"
++#ifdef HAVE_STROKE
++#include "stroke.h"
++#endif /* HAVE_STROKE */
++
++/* ---------------------------- local definitions
-------------------------- */
++
++/* ---------------------------- local macros
------------------------------- */
++
++/* ---------------------------- imports
------------------------------------ */
++
++extern float rgpctMovementDefault[32];
++extern int cpctMovementDefault;
++extern int cmsDelayDefault;
++
++/* ---------------------------- included code files
------------------------ */
++
++/* ---------------------------- local types
-------------------------------- */
++typedef enum {FakeMouseEvent, FakeKeyEvent} FakeEventType;
++/* ---------------------------- forward declarations
----------------------- */
++
++/* ---------------------------- local variables
---------------------------- */
++
++static char *exec_shell_name="/bin/sh";
++
++/* button state strings must match the enumerated states */
++static char *button_states[BS_MaxButtonStateName + 1] =
++{
++ "ActiveUp",
++ "ActiveDown",
++ "InactiveUp",
++ "InactiveDown",
++ "ToggledActiveUp",
++ "ToggledActiveDown",
++ "ToggledInactiveUp",
++ "ToggledInactiveDown",
++ "Active",
++ "Inactive",
++ "ToggledActive",
++ "ToggledInactive",
++ "AllNormal",
++ "AllToggled",
++ "AllActive",
++ "AllInactive",
++ "AllUp",
++ "AllDown",
++ "AllActiveUp",
++ "AllActiveDown",
++ "AllInactiveUp",
++ "AllInactiveDown",
++ NULL
++};
++
++/* ---------------------------- exported variables (globals)
--------------- */
++
++char *ModulePath = FVWM_MODULEDIR;
++int moduleTimeout = DEFAULT_MODULE_TIMEOUT;
++
++/* ---------------------------- local functions
---------------------------- */
++
++/** Prepend rather than replace the image path.
++ Used for obsolete PixmapPath and IconPath **/
++static void obsolete_imagepaths( const char* pre_path )
++{
++ char* tmp = stripcpy( pre_path );
++ char* path = alloca(strlen( tmp ) + strlen(PictureGetImagePath()) + 2
);
++
++ strcpy( path, tmp );
++ free( tmp );
++
++ strcat( path, ":" );
++ strcat( path, PictureGetImagePath() );
++
++ PictureSetImagePath( path );
++
++ return;
++}
++
++/*
++ *
++ * Reads a title button description (veliaa AT rpi.edu)
++ *
++ */
++static char *ReadTitleButton(
++ char *s, TitleButton *tb, Boolean append, int button)
++{
++ char *end = NULL;
++ char *spec;
++ char *t;
++ int i;
++ int bs;
++ int bs_start, bs_end;
++ int pstyle = 0;
++ DecorFace tmpdf;
++
++ Bool multiple;
++ int use_mask = 0;
++ int set_mask = 0;
++
++ s = SkipSpaces(s, NULL, 0);
++ t = GetNextTokenIndex(s, button_states, 0, &bs);
++ if (bs != BS_All)
++ {
++ s = SkipSpaces(t, NULL, 0);
++ }
++
++ if (bs == BS_All)
++ {
++ use_mask = 0;
++ set_mask = 0;
++ }
++ else if (bs == BS_Active)
++ {
++ use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
++ set_mask = 0;
++ }
++ else if (bs == BS_Inactive)
++ {
++ use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
++ set_mask = BS_MASK_INACTIVE;
++ }
++ else if (bs == BS_ToggledActive)
++ {
++ use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
++ set_mask = BS_MASK_TOGGLED;
++ }
++ else if (bs == BS_ToggledInactive)
++ {
++ use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
++ set_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
++ }
++ else if (bs == BS_AllNormal)
++ {
++ use_mask = BS_MASK_TOGGLED;
++ set_mask = 0;
++ }
++ else if (bs == BS_AllToggled)
++ {
++ use_mask = BS_MASK_TOGGLED;
++ set_mask = BS_MASK_TOGGLED;
++ }
++ else if (bs == BS_AllActive)
++ {
++ use_mask = BS_MASK_INACTIVE;
++ set_mask = 0;
++ }
++ else if (bs == BS_AllInactive)
++ {
++ use_mask = BS_MASK_INACTIVE;
++ set_mask = BS_MASK_INACTIVE;
++ }
++ else if (bs == BS_AllUp)
++ {
++ use_mask = BS_MASK_DOWN;
++ set_mask = 0;
++ }
++ else if (bs == BS_AllDown)
++ {
++ use_mask = BS_MASK_DOWN;
++ set_mask = BS_MASK_DOWN;
++ }
++ else if (bs == BS_AllActiveUp)
++ {
++ use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
++ set_mask = 0;
++ }
++ else if (bs == BS_AllActiveDown)
++ {
++ use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
++ set_mask = BS_MASK_DOWN;
++ }
++ else if (bs == BS_AllInactiveUp)
++ {
++ use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
++ set_mask = BS_MASK_INACTIVE;
++ }
++ else if (bs == BS_AllInactiveDown)
++ {
++ use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
++ set_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
++ }
++
++ if ((bs & BS_MaxButtonStateMask) == bs)
++ {
++ multiple = False;
++ bs_start = bs;
++ bs_end = bs;
++ }
++ else
++ {
++ multiple = True;
++ bs_start = 0;
++ bs_end = BS_MaxButtonState - 1;
++ for (i = bs_start; (i & use_mask) != set_mask && i <= bs_end;
++ i++)
++ {
++ bs_start++;
++ }
++ }
++
++ if (*s == '(')
++ {
++ int len;
++ pstyle = 1;
++ if (!(end = strchr(++s, ')')))
++ {
++ fvwm_msg(
++ ERR, "ReadTitleButton",
++ "missing parenthesis: %s", s);
++ return NULL;
++ }
++ s = SkipSpaces(s, NULL, 0);
++ len = end - s + 1;
++ spec = safemalloc(len);
++ strncpy(spec, s, len - 1);
++ spec[len - 1] = 0;
++ }
++ else
++ {
++ spec = s;
++ }
++
++ spec = SkipSpaces(spec, NULL, 0);
++ /* setup temporary in case button read fails */
++ memset(&tmpdf, 0, sizeof(DecorFace));
++ DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
++
++ if (strncmp(spec, "--", 2) == 0)
++ {
++ /* only change flags */
++ Bool verbose = True;
++ for (i = bs_start; i <= bs_end; ++i)
++ {
++ if (multiple && (i & use_mask) != set_mask)
++ {
++ continue;
++ }
++ ReadDecorFace(spec, &TB_STATE(*tb)[i], button,
verbose);
++ verbose = False;
++ }
++ }
++ else if (ReadDecorFace(spec, &tmpdf, button, True))
++ {
++ if (append)
++ {
++ DecorFace *head = &TB_STATE(*tb)[bs_start];
++ DecorFace *tail = head;
++ DecorFace *next;
++
++ while (tail->next)
++ {
++ tail = tail->next;
++ }
++ tail->next = (DecorFace
*)safemalloc(sizeof(DecorFace));
++ memcpy(tail->next, &tmpdf, sizeof(DecorFace));
++ if (DFS_FACE_TYPE(tail->next->style) == VectorButton
&&
++ DFS_FACE_TYPE((&TB_STATE(*tb)[bs_start])->style)
==
++ DefaultVectorButton)
++ {
++ /* override the default vector style */
++ memcpy(
++ &tail->next->style, &head->style,
++ sizeof(DecorFaceStyle));
++ DFS_FACE_TYPE(tail->next->style) =
VectorButton;
++ next = head->next;
++ head->next = NULL;
++ FreeDecorFace(dpy, head);
++ memcpy(head, next, sizeof(DecorFace));
++ free(next);
++ }
++ for (i = bs_start + 1; i <= bs_end; ++i)
++ {
++ if (multiple && (i & use_mask) != set_mask)
++ {
++ continue;
++ }
++ head = &TB_STATE(*tb)[i];
++ tail = head;
++ while (tail->next)
++ {
++ tail = tail->next;
++ }
++ tail->next = (DecorFace *)safemalloc(
++ sizeof(DecorFace));
++ memset(
++ &DFS_FLAGS(tail->next->style), 0,
++ sizeof(DFS_FLAGS(tail->next->style)));
++ DFS_FACE_TYPE(tail->next->style) =
++ SimpleButton;
++ tail->next->next = NULL;
++ ReadDecorFace(spec, tail->next, button,
False);
++ if (DFS_FACE_TYPE(tail->next->style) ==
++ VectorButton &&
++ DFS_FACE_TYPE((&TB_STATE(*tb)[i])->style)
==
++ DefaultVectorButton)
++ {
++ /* override the default vector style
*/
++ memcpy(
++ &tail->next->style,
++ &head->style,
++ sizeof(DecorFaceStyle));
++ DFS_FACE_TYPE(tail->next->style) =
++ VectorButton;
++ next = head->next;
++ head->next = NULL;
++ FreeDecorFace(dpy, head);
++ memcpy(head, next, sizeof(DecorFace));
++ free(next);
++ }
++ }
++ }
++ else
++ {
++ FreeDecorFace(dpy, &TB_STATE(*tb)[bs_start]);
++ memcpy(
++ &(TB_STATE(*tb)[bs_start]), &tmpdf,
++ sizeof(DecorFace));
++ for (i = bs_start + 1; i <= bs_end; ++i)
++ {
++ if (multiple && (i & use_mask) != set_mask)
++ {
++ continue;
++ }
++ ReadDecorFace(
++ spec, &TB_STATE(*tb)[i], button,
False);
++ }
++ }
++ }
++ if (pstyle)
++ {
++ free(spec);
++ end++;
++ end = SkipSpaces(end, NULL, 0);
++ }
++
++ return end;
++}
++
++/* Remove the given decor from all windows */
++static void __remove_window_decors(F_CMD_ARGS, FvwmDecor *d)
++{
++ const exec_context_t *exc2;
++ exec_context_changes_t ecc;
++ FvwmWindow *t;
++
++ for (t = Scr.FvwmRoot.next; t; t = t->next)
++ {
++ if (t->decor == d)
++ {
++ /* remove the extra title height now because we delete
++ * the current decor before calling ChangeDecor(). */
++ t->g.frame.height -= t->decor->title_height;
++ t->decor = NULL;
++ ecc.w.fw = t;
++ ecc.w.wcontext = C_WINDOW;
++ exc2 = exc_clone_context(
++ exc, &ecc, ECC_FW | ECC_WCONTEXT);
++ execute_function(
++ cond_rc, exc2, "ChangeDecor Default", 0);
++ exc_destroy_context(exc2);
++ }
++ }
++
++ return;
++}
++
++static void do_title_style(F_CMD_ARGS, Bool do_add)
++{
++ 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;
++ decor->titlebar.flags.has_changed = 1;
++
++ for (prev = action ; (parm = PeekToken(action, &action)); prev =
action)
++ {
++ if (!do_add && StrEquals(parm,"centered"))
++ {
++ TB_JUSTIFICATION(decor->titlebar) = JUST_CENTER;
++ }
++ else if (!do_add && StrEquals(parm,"leftjustified"))
++ {
++ TB_JUSTIFICATION(decor->titlebar) = JUST_LEFT;
++ }
++ else if (!do_add && StrEquals(parm,"rightjustified"))
++ {
++ TB_JUSTIFICATION(decor->titlebar) = JUST_RIGHT;
++ }
++ else if (!do_add && StrEquals(parm,"height"))
++ {
++ int height = 0;
++ int next = 0;
++
++ if (!action ||
++ sscanf(action, "%d%n", &height, &next) <= 0 ||
++ height < MIN_FONT_HEIGHT ||
++ height > MAX_FONT_HEIGHT)
++ {
++ if (height != 0)
++ {
++ fvwm_msg(ERR, "do_title_style",
++ "bad height argument (height"
++ " must be from 5 to 256)");
++ height = 0;
++ }
++ }
++ if (decor->title_height != height ||
++ decor->min_title_height != 0)
++ {
++ decor->title_height = height;
++ decor->min_title_height = 0;
++ decor->flags.has_title_height_changed = 1;
++ }
++ if (action)
++ action += next;
++ }
++ else if (!do_add && StrEquals(parm,"buttonwidth"))
++ {
++ int width = 0;
++ int next = 0;
++
++ sscanf(action, "%d%n", &width, &next);
++
++ if (decor->button_width != width)
++ {
++ decor->button_width = width;
++ decor->flags.has_changed = 1;
++ }
++ if (action)
++ action += next;
++ }
++ else if (!do_add && StrEquals(parm,"MinHeight"))
++ {
++ int height = 0;
++ int next = 0;
++
++ if (!action ||
++ sscanf(action, "%d%n", &height, &next) <= 0 ||
++ height < MIN_FONT_HEIGHT ||
++ height > MAX_FONT_HEIGHT)
++ {
++ if (height < MIN_FONT_HEIGHT)
++ height = MIN_FONT_HEIGHT;
++ else if (height > MAX_FONT_HEIGHT)
++ height = 0;
++ }
++ if (decor->min_title_height != height)
++ {
++ decor->title_height = 0;
++ decor->min_title_height = height;
++ decor->flags.has_title_height_changed = 1;
++ }
++ if (action)
++ action += next;
++ }
++ else
++ {
++ action = ReadTitleButton(
++ prev, &decor->titlebar, do_add, -1);
++ }
++ }
++
++ return;
++}
++
++/*
++ *
++ * Reads a multi-pixmap titlebar config. (tril AT igs.net)
++ *
++ */
++static char *ReadMultiPixmapDecor(char *s, DecorFace *df)
++{
++ static char *pm_names[TBMP_NUM_PIXMAPS+1] =
++ {
++ "Main",
++ "LeftMain",
++ "RightMain",
++ "LeftButtons",
++ "RightButtons",
++ "UnderText",
++ "LeftOfText",
++ "RightOfText",
++ "LeftEnd",
++ "RightEnd",
++ "Buttons",
++ NULL
++ };
++ FvwmPicture **pm;
++ FvwmAcs *acs;
++ Pixel *pixels;
++ char *token;
++ Bool stretched;
++ Bool load_pixmap = False;
++ int pm_id, i = 0;
++ FvwmPictureAttributes fpa;
++
++ df->style.face_type = MultiPixmap;
++ df->u.mp.pixmaps = pm =
++ (FvwmPicture**)safecalloc(
++ TBMP_NUM_PIXMAPS, sizeof(FvwmPicture*));
++ df->u.mp.acs = acs =
++ (FvwmAcs *)safemalloc(TBMP_NUM_PIXMAPS * sizeof(FvwmAcs));
++ df->u.mp.pixels = pixels =
++ (Pixel *)safemalloc(TBMP_NUM_PIXMAPS * sizeof(Pixel));
++ for(i=0; i < TBMP_NUM_PIXMAPS; i++)
++ {
++ acs[i].cs = -1;
++ acs[i].alpha_percent = 100;
++ }
++ s = GetNextTokenIndex(s, pm_names, 0, &pm_id);
++ while (pm_id >= 0)
++ {
++ stretched = False;
++ load_pixmap = False;
++ s = DoPeekToken(s, &token, ",()", NULL, NULL);
++ if (StrEquals(token, "stretched"))
++ {
++ stretched = True;
++ s = DoPeekToken(s, &token, ",", NULL, NULL);
++ }
++ else if (StrEquals(token, "tiled"))
++ {
++ s = DoPeekToken(s, &token, ",", NULL, NULL);
++ }
++ if (!token)
++ {
++ break;
++ }
++ if (pm[pm_id] || acs[pm_id].cs >= 0 ||
++ (df->u.mp.solid_flags & (1 << pm_id)))
++ {
++ fvwm_msg(WARN, "ReadMultiPixmapDecor",
++ "Ignoring: already-specified %s",
++ pm_names[i]);
++ continue;
++ }
++ if (stretched)
++ {
++ df->u.mp.stretch_flags |= (1 << pm_id);
++ }
++ if (strncasecmp (token, "Colorset", 8) == 0)
++ {
++ int val;
++ char *tmp;
++
++ tmp = DoPeekToken(s, &token, ",", NULL, NULL);
++ if (!GetIntegerArguments(token, NULL, &val, 1) ||
++ val < 0)
++ {
++ fvwm_msg(
++ ERR, "ReadMultiPixmapDecor",
++ "Colorset shoule take one or two "
++ "positive integers as argument");
++ }
++ else
++ {
++ acs[pm_id].cs = val;
++ alloc_colorset(val);
++ s = tmp;
++ tmp = DoPeekToken(s, &token, ",", NULL, NULL);
++ if (GetIntegerArguments(token, NULL, &val, 1))
++ {
++ acs[pm_id].alpha_percent =
++ max(0, min(100,val));
++ s = tmp;
++ }
++ }
++ }
++ else if (strncasecmp(token, "TiledPixmap", 11) == 0)
++ {
++ s = DoPeekToken(s, &token, ",", NULL, NULL);
++ load_pixmap = True;
++ }
++ else if (strncasecmp(token, "AdjustedPixmap", 14) == 0)
++ {
++ s = DoPeekToken(s, &token, ",", NULL, NULL);
++ load_pixmap = True;
++ df->u.mp.stretch_flags |= (1 << pm_id);
++ }
++ else if (strncasecmp(token, "Solid", 5) == 0)
++ {
++ s = DoPeekToken(s, &token, ",", NULL, NULL);
++ if (token)
++ {
++ df->u.mp.pixels[pm_id] = GetColor(token);
++ df->u.mp.solid_flags |= (1 << pm_id);
++ }
++ }
++ else
++ {
++ load_pixmap = True;
++ }
++ if (load_pixmap && token)
++ {
++ fpa.mask = (Pdepth <= 8)? FPAM_DITHER:0; /* ? */
++ pm[pm_id] = PCacheFvwmPicture(
++ dpy, Scr.NoFocusWin, NULL, token, fpa);
++ if (!pm[pm_id])
++ {
++ fvwm_msg(ERR, "ReadMultiPixmapDecor",
++ "Pixmap '%s' could not be loaded",
++ token);
++ }
++ }
++ if (pm_id == TBMP_BUTTONS)
++ {
++ if (pm[TBMP_LEFT_BUTTONS])
++ {
++ PDestroyFvwmPicture(dpy,
pm[TBMP_LEFT_BUTTONS]);
++ }
++ if (pm[TBMP_RIGHT_BUTTONS])
++ {
++ PDestroyFvwmPicture(dpy,
pm[TBMP_RIGHT_BUTTONS]);
++ }
++ df->u.mp.stretch_flags &= ~(1 << TBMP_LEFT_BUTTONS);
++ df->u.mp.stretch_flags &= ~(1 << TBMP_RIGHT_BUTTONS);
++ df->u.mp.solid_flags &= ~(1 << TBMP_LEFT_BUTTONS);
++ df->u.mp.solid_flags &= ~(1 << TBMP_RIGHT_BUTTONS);
++ if (pm[TBMP_BUTTONS])
++ {
++ pm[TBMP_LEFT_BUTTONS] =
++ PCloneFvwmPicture(pm[TBMP_BUTTONS]);
++ acs[TBMP_LEFT_BUTTONS].cs = -1;
++ pm[TBMP_RIGHT_BUTTONS] =
++ PCloneFvwmPicture(pm[TBMP_BUTTONS]);
++ acs[TBMP_RIGHT_BUTTONS].cs = -1;
++ }
++ else
++ {
++ pm[TBMP_RIGHT_BUTTONS] =
++ pm[TBMP_LEFT_BUTTONS] = NULL;
++ acs[TBMP_RIGHT_BUTTONS].cs =
++ acs[TBMP_LEFT_BUTTONS].cs =
++ acs[TBMP_BUTTONS].cs;
++ acs[TBMP_RIGHT_BUTTONS].alpha_percent =
++ acs[TBMP_LEFT_BUTTONS].alpha_percent =
++ acs[TBMP_BUTTONS].alpha_percent;
++ pixels[TBMP_LEFT_BUTTONS] =
++ pixels[TBMP_RIGHT_BUTTONS] =
++ pixels[TBMP_BUTTONS];
++ }
++ if (stretched)
++ {
++ df->u.mp.stretch_flags |=
++ (1 << TBMP_LEFT_BUTTONS) |
++ (1 << TBMP_RIGHT_BUTTONS);
++ }
++ if (df->u.mp.solid_flags & (1 << TBMP_BUTTONS))
++ {
++ df->u.mp.solid_flags |=
++ (1 << TBMP_LEFT_BUTTONS);
++ df->u.mp.solid_flags |=
++ (1 << TBMP_RIGHT_BUTTONS);
++ }
++ if (pm[TBMP_BUTTONS])
++ {
++ PDestroyFvwmPicture(dpy, pm[TBMP_BUTTONS]);
++ pm[TBMP_BUTTONS] = NULL;
++ }
++ acs[TBMP_BUTTONS].cs = -1;
++ df->u.mp.solid_flags &= ~(1 << TBMP_BUTTONS);
++ }
++ s = SkipSpaces(s, NULL, 0);
++ s = GetNextTokenIndex(s, pm_names, 0, &pm_id);
++ }
++
++ if (!(pm[TBMP_MAIN] || acs[TBMP_MAIN].cs >= 0 ||
++ (df->u.mp.solid_flags & TBMP_MAIN))
++ &&
++ !(pm[TBMP_LEFT_MAIN] || acs[TBMP_LEFT_MAIN].cs >= 0 ||
++ (df->u.mp.solid_flags & TBMP_LEFT_MAIN))
++ &&
++ !(pm[TBMP_RIGHT_MAIN] || acs[TBMP_RIGHT_MAIN].cs >= 0 ||
++ (df->u.mp.solid_flags & TBMP_RIGHT_MAIN)))
++ {
++ fvwm_msg(ERR, "ReadMultiPixmapDecor",
++ "No Main pixmap/colorset/solid found for TitleStyle "
++ "MultiPixmap (you must specify either Main, "
++ "or both LeftMain and RightMain)");
++ for (i=0; i < TBMP_NUM_PIXMAPS; i++)
++ {
++ if (pm[i])
++ {
++ PDestroyFvwmPicture(dpy, pm[i]);
++ }
++ else if (!!(df->u.mp.solid_flags & i))
++ {
++ PictureFreeColors(
++ dpy, Pcmap, &df->u.mp.pixels[i], 1, 0,
++ False);
++ }
++ }
++ free(pm);
++ free(acs);
++ free(pixels);
++ return NULL;
++ }
++
++ return s;
++}
++
++/*
++ *
++ * DestroyFvwmDecor -- frees all memory assocated with an FvwmDecor
++ * structure, but does not free the FvwmDecor itself
++ *
++ */
++static void DestroyFvwmDecor(FvwmDecor *decor)
++{
++ int i;
++ /* reset to default button set (frees allocated mem) */
++ DestroyAllButtons(decor);
++ for (i = 0; i < BS_MaxButtonState; ++i)
++ {
++ FreeDecorFace(dpy, &TB_STATE(decor->titlebar)[i]);
++ }
++ FreeDecorFace(dpy, &decor->BorderStyle.active);
++ FreeDecorFace(dpy, &decor->BorderStyle.inactive);
++#ifdef USEDECOR
++ if (decor->tag)
++ {
++ free(decor->tag);
++ decor->tag = NULL;
++ }
++#endif
++
++ return;
++}
++
++static void SetLayerButtonFlag(
++ int layer, int multi, int set, FvwmDecor *decor, TitleButton *tb)
++{
++ int i;
++ int start = 0;
++ int add = 2;
++
++ if (multi)
++ {
++ if (multi == 2)
++ {
++ start = 1;
++ }
++ else if (multi == 3)
++ {
++ add = 1;
++ }
++ for (i = start; i < NUMBER_OF_TITLE_BUTTONS; i += add)
++ {
++ if (set)
++ {
++ TB_FLAGS(decor->buttons[i]).has_layer = 1;
++ TB_LAYER(decor->buttons[i]) = layer;
++ }
++ else
++ {
++ TB_FLAGS(decor->buttons[i]).has_layer = 0;
++ }
++ }
++ }
++ else
++ {
++ if (set)
++ {
++ TB_FLAGS(*tb).has_layer = 1;
++ TB_LAYER(*tb) = layer;
++ }
++ else
++ {
++ TB_FLAGS(*tb).has_layer = 0;
++ }
++ }
++
++ return;
++}
++
++/*
++ *
++ * Changes a button decoration style (changes by veliaa AT rpi.edu)
++ *
++ */
++static void SetMWMButtonFlag(
++ mwm_flags flag, int multi, int set, FvwmDecor *decor, TitleButton *tb)
++{
++ int i;
++ int start = 0;
++ int add = 2;
++
++ if (multi)
++ {
++ if (multi == 2)
++ {
++ start = 1;
++ }
++ else if (multi == 3)
++ {
++ add = 1;
++ }
++ for (i = start; i < NUMBER_OF_TITLE_BUTTONS; i += add)
++ {
++ if (set)
++ {
++ TB_MWM_DECOR_FLAGS(decor->buttons[i]) |= flag;
++ }
++ else
++ {
++ TB_MWM_DECOR_FLAGS(decor->buttons[i]) &=
~flag;
++ }
++ }
++ }
++ else
++ {
++ if (set)
++ {
++ TB_MWM_DECOR_FLAGS(*tb) |= flag;
++ }
++ else
++ {
++ TB_MWM_DECOR_FLAGS(*tb) &= ~flag;
++ }
++ }
++
++ return;
++}
++
++static void do_button_style(F_CMD_ARGS, Bool do_add)
++{
++ int i;
++ int multi = 0;
++ int button = 0;
++ int do_return;
++ char *text = NULL;
++ char *prev = NULL;
++ char *parm = NULL;
++ TitleButton *tb = NULL;
++#ifdef USEDECOR
++ FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
++#else
++ FvwmDecor *decor = &Scr.DefaultDecor;
++#endif
++
++ parm = PeekToken(action, &text);
++ if (parm && isdigit(*parm))
++ {
++ button = atoi(parm);
++ button = BUTTON_INDEX(button);
++ }
++
++ if (parm == NULL || button >= NUMBER_OF_TITLE_BUTTONS || button < 0)
++ {
++ fvwm_msg(
++ ERR, "ButtonStyle", "Bad button style (1) in line %s",
++ action);
++ return;
++ }
++
++ Scr.flags.do_need_window_update = 1;
++
++ do_return = 0;
++ if (!isdigit(*parm))
++ {
++ if (StrEquals(parm,"left"))
++ {
++ multi = 1; /* affect all left buttons */
++ }
++ else if (StrEquals(parm,"right"))
++ {
++ multi = 2; /* affect all right buttons */
++ }
++ else if (StrEquals(parm,"all"))
++ {
++ multi = 3; /* affect all buttons */
++ }
++ else
++ {
++ /* we're either resetting buttons or an invalid button
++ * set was specified */
++ if (StrEquals(parm,"reset"))
++ {
++ ResetAllButtons(decor);
++ }
++ else
++ {
++ fvwm_msg(
++ ERR, "ButtonStyle",
++ "Bad button style (2) in line %s",
++ action);
++ }
++ multi = 3;
++ do_return = 1;
++ }
++ }
++ /* mark button style and decor as changed */
++ decor->flags.has_changed = 1;
++ if (multi == 0)
++ {
++ /* a single button was specified */
++ tb = &decor->buttons[button];
++ TB_FLAGS(*tb).has_changed = 1;
++ }
++ else
++ {
++ for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
++ {
++ if (((multi & 1) && !(i & 1)) ||
++ ((multi & 2) && (i & 1)))
++ {
++ TB_FLAGS(decor->buttons[i]).has_changed = 1;
++ }
++ }
++ }
++ if (do_return == 1)
++ {
++ return;
++ }
++ for (prev = text; (parm = PeekToken(text, &text)); prev = text)
++ {
++ if (!do_add && strcmp(parm,"-") == 0)
++ {
++ char *tok;
++ text = GetNextToken(text, &tok);
++ while (tok)
++ {
++ int set = 1;
++ char *old_tok = NULL;
++
++ if (*tok == '!')
++ {
++ /* flag negate */
++ set = 0;
++ old_tok = tok;
++ tok++;
++ }
++ if (StrEquals(tok,"Clear"))
++ {
++ if (multi)
++ {
++ for (i = 0;
++ i <
NUMBER_OF_TITLE_BUTTONS; ++i)
++ {
++ if (((multi & 1) &&
++ !(i & 1)) ||
++ ((multi & 2) &&
++ (i & 1)))
++ {
++
TB_JUSTIFICATION(decor->buttons[i]) =
++ (set)
? JUST_CENTER : JUST_RIGHT;
++
memset(&TB_FLAGS(decor->buttons[i]), (set) ? 0 : 0xff,
++
sizeof(TB_FLAGS(decor->buttons[i])));
++ /* ? not very
useful if set == 0 ? */
++ }
++ }
++ }
++ else
++ {
++ TB_JUSTIFICATION(*tb) = (set)
?
++ JUST_CENTER :
++ JUST_RIGHT;
++ memset(&TB_FLAGS(*tb), (set) ?
++ 0 : 0xff,
++ sizeof(TB_FLAGS(*tb)));
++ /* ? not very useful if
++ * set == 0 ? */
++ }
++ }
++ else if (StrEquals(tok, "MWMDecorMenu"))
++ {
++ SetMWMButtonFlag(
++ MWM_DECOR_MENU, multi, set,
++ decor, tb);
++ }
++ else if (StrEquals(tok, "MWMDecorMin"))
++ {
++ SetMWMButtonFlag(
++ MWM_DECOR_MINIMIZE, multi,
set,
++ decor, tb);
++ }
++ else if (StrEquals(tok, "MWMDecorMax"))
++ {
++ SetMWMButtonFlag(
++ MWM_DECOR_MAXIMIZE, multi,
set,
++ decor, tb);
++ }
++ else if (StrEquals(tok, "MWMDecorShade"))
++ {
++ SetMWMButtonFlag(
++ MWM_DECOR_SHADE, multi, set,
++ decor, tb);
++ }
++ else if (StrEquals(tok, "MWMDecorStick"))
++ {
++ SetMWMButtonFlag(
++ MWM_DECOR_STICK, multi, set,
++ decor, tb);
++ }
++ else if (StrEquals(tok, "MwmDecorLayer"))
++ {
++ int layer, got_number;
++ char *ltok;
++ text = GetNextToken(text, &ltok);
++ if (ltok)
++ {
++ got_number =
++ (sscanf(ltok, "%d",
++ &layer) == 1);
++ free (ltok);
++ }
++ else
++ {
++ got_number = 0;
++ }
++ if (!ltok || !got_number)
++ {
++ fvwm_msg(ERR, "ButtonStyle",
++ "could not read"
++ " integer value for"
++ " layer -- line: %s",
++ text);
++ }
++ else
++ {
++ SetLayerButtonFlag(
++ layer, multi, set,
++ decor, tb);
++ }
++
++ }
++ else
++ {
++ fvwm_msg(ERR, "ButtonStyle",
++ "unknown title button flag"
++ " %s -- line: %s", tok,
text);
++ }
++ if (set)
++ {
++ free(tok);
++ }
++ else
++ {
++ free(old_tok);
++ }
++ text = GetNextToken(text, &tok);
++ }
++ break;
++ }
++ else
++ {
++ if (multi)
++ {
++ for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
++ {
++ if (((multi & 1) && !(i & 1)) ||
++ ((multi & 2) && (i & 1)))
++ {
++ text = ReadTitleButton(
++ prev,
++ &decor->buttons[i],
++ do_add, i);
++ }
++ }
++ }
++ else if (!(text = ReadTitleButton(
++ prev, tb, do_add, button)))
++ {
++ break;
++ }
++ }
++ }
++
++ return;
++}
++
++static
++int update_decorface_colorset(DecorFace *df, int cset)
++{
++ DecorFace *tdf;
++ int has_changed = 0;
++
++ for(tdf = df; tdf != NULL; tdf = tdf->next)
++ {
++ if (DFS_FACE_TYPE(tdf->style) == ColorsetButton &&
++ tdf->u.acs.cs == cset)
++ {
++ tdf->flags.has_changed = 1;
++ has_changed = 1;
++ }
++ else if (DFS_FACE_TYPE(tdf->style) == MultiPixmap)
++ {
++ int i;
++
++ for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
++ {
++ if (tdf->u.mp.acs[i].cs == cset)
++ {
++ tdf->flags.has_changed = 1;
++ has_changed = 1;
++ }
++ }
++ }
++}
++
++ return has_changed;
++}
++
++static
++int update_titlebutton_colorset(TitleButton *tb, int cset)
++{
++ int i;
++ int has_changed = 0;
++
++ for(i = 0; i < BS_MaxButtonState; i++)
++ {
++ tb->state[i].flags.has_changed =
++ update_decorface_colorset(&(tb->state[i]), cset);
++ has_changed |= tb->state[i].flags.has_changed;
++ }
++ return has_changed;
++}
++
++static
++void update_decors_colorset(int cset)
++{
++ int i;
++ int has_changed;
++ FvwmDecor *decor = &Scr.DefaultDecor;
++
++#ifdef USEDECOR
++ for(decor = &Scr.DefaultDecor; decor != NULL; decor = decor->next)
++#endif
++ {
++ has_changed = 0;
++ for(i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++ {
++ decor->flags.has_changed |=
update_titlebutton_colorset(
++ &(decor->buttons[i]), cset);
++ }
++ decor->flags.has_changed |= update_titlebutton_colorset(
++ &(decor->titlebar), cset);
++ decor->flags.has_changed |= update_decorface_colorset(
++ &(decor->BorderStyle.active), cset);
++ decor->flags.has_changed |= update_decorface_colorset(
++ &(decor->BorderStyle.inactive), cset);
++ if (decor->flags.has_changed)
++ {
++ Scr.flags.do_need_window_update = 1;
++ }
++ }
++}
++
++static Bool __parse_vector_line_one_coord(
++ char **ret_action, int *pcoord, int *poff, char *action)
++{
++ int offset;
++ int n;
++
++ *ret_action = action;
++ n = sscanf(action, "%d%n", pcoord, &offset);
++ if (n < 1)
++ {
++ return False;
++ }
++ action += offset;
++ /* check for offest */
++ if (*action == '+' || *action == '-')
++ {
++ n = sscanf(action, "%dp%n", poff, &offset);
++ if (n < 1)
++ {
++ return False;
++ }
++ if (*poff < -128)
++ {
++ *poff = -128;
++ }
++ else if (*poff > 127)
++ {
++ *poff = 127;
++ }
++ action += offset;
++ }
++ else
++ {
++ *poff = 0;
++ }
++ *ret_action = action;
++
++ return True;
++}
++
++static Bool __parse_vector_line(
++ char **ret_action, int *px, int *py, int *pxoff, int *pyoff, int *pc,
++ char *action)
++{
++ Bool is_valid = True;
++ int offset;
++ int n;
++
++ *ret_action = action;
++ if (__parse_vector_line_one_coord(&action, px, pxoff, action) ==
False)
++ {
++ return False;
++ }
++ if (*action != 'x')
++ {
++ return False;
++ }
++ action++;
++ if (__parse_vector_line_one_coord(&action, py, pyoff, action) ==
False)
++ {
++ return False;
++ }
++ if (*action != '@')
++ {
++ return False;
++ }
++ action++;
++ /* read the line style */
++ n = sscanf(action, "%d%n", pc, &offset);
++ if (n < 1)
++ {
++ return False;
++ }
++ action += offset;
++ *ret_action = action;
++
++ return is_valid;
++}
++
++/* ---------------------------- interface functions
------------------------ */
++
++void refresh_window(Window w, Bool window_update)
++{
++ XSetWindowAttributes attributes;
++ unsigned long valuemask;
++
++ valuemask = CWOverrideRedirect | CWBackingStore | CWSaveUnder |
++ CWBackPixmap;
++ attributes.override_redirect = True;
++ attributes.save_under = False;
++ attributes.background_pixmap = None;
++ attributes.backing_store = NotUseful;
++ w = XCreateWindow(
++ dpy, w, 0, 0, Scr.MyDisplayWidth, Scr.MyDisplayHeight, 0,
++ CopyFromParent, CopyFromParent, CopyFromParent, valuemask,
++ &attributes);
++ XMapWindow(dpy, w);
++ if (Scr.flags.do_need_window_update && window_update)
++ {
++ flush_window_updates();
++ }
++ XDestroyWindow(dpy, w);
++ XSync(dpy, 0);
++ handle_all_expose();
++
++ return;
++}
++
++void ApplyDefaultFontAndColors(void)
++{
++ XGCValues gcv;
++ unsigned long gcm;
++ int cset = Scr.DefaultColorset;
++
++ /* make GC's */
++ gcm = GCFunction|GCLineWidth|GCForeground|GCBackground;
++ gcv.function = GXcopy;
++ if (Scr.DefaultFont->font)
++ {
++ gcm |= GCFont;
++ gcv.font = Scr.DefaultFont->font->fid;
++ }
++ gcv.line_width = 0;
++ if (cset >= 0)
++ {
++ gcv.foreground = Colorset[cset].fg;
++ gcv.background = Colorset[cset].bg;
++ }
++ else
++ {
++ gcv.foreground = Scr.StdFore;
++ gcv.background = Scr.StdBack;
++ }
++ if (Scr.StdGC)
++ {
++ XChangeGC(dpy, Scr.StdGC, gcm, &gcv);
++ }
++ else
++ {
++ Scr.StdGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
++ }
++
++ gcm = GCFunction|GCLineWidth|GCForeground;
++ if (cset >= 0)
++ {
++ gcv.foreground = Colorset[cset].hilite;
++ }
++ else
++ {
++ gcv.foreground = Scr.StdHilite;
++ }
++ if (Scr.StdReliefGC)
++ {
++ XChangeGC(dpy, Scr.StdReliefGC, gcm, &gcv);
++ }
++ else
++ {
++ Scr.StdReliefGC = fvwmlib_XCreateGC(
++ dpy, Scr.NoFocusWin, gcm, &gcv);
++ }
++ if (cset >= 0)
++ {
++ gcv.foreground = Colorset[cset].shadow;
++ }
++ else
++ {
++ gcv.foreground = Scr.StdShadow;
++ }
++ if (Scr.StdShadowGC)
++ {
++ XChangeGC(dpy, Scr.StdShadowGC, gcm, &gcv);
++ }
++ else
++ {
++ Scr.StdShadowGC = fvwmlib_XCreateGC(
++ dpy, Scr.NoFocusWin, gcm, &gcv);
++ }
++ /* update the geometry window for move/resize */
++ if (Scr.SizeWindow != None)
++ {
++ resize_geometry_window();
++ }
++ UpdateAllMenuStyles();
++
++ return;
++}
++
++void FreeDecorFace(Display *dpy, DecorFace *df)
++{
++ int i;
++
++ switch (DFS_FACE_TYPE(df->style))
++ {
++ case GradientButton:
++ if (df->u.grad.d_pixels != NULL && df->u.grad.d_npixels)
++ {
++ PictureFreeColors(
++ dpy, Pcmap, df->u.grad.d_pixels,
++ df->u.grad.d_npixels, 0, False);
++ free(df->u.grad.d_pixels);
++ }
++ else if (Pdepth <= 8 && df->u.grad.xcs != NULL &&
++ df->u.grad.npixels > 0 && !df->u.grad.do_dither)
++ {
++ Pixel *p;
++ int i;
++
++ p = (Pixel *)safemalloc(
++ df->u.grad.npixels * sizeof(Pixel));
++ for(i=0; i < df->u.grad.npixels; i++)
++ {
++ p[i] = df->u.grad.xcs[i].pixel;
++ }
++ PictureFreeColors(
++ dpy, Pcmap, p, df->u.grad.npixels, 0, False);
++ free(p);
++ }
++ if (df->u.grad.xcs != NULL)
++ {
++ free(df->u.grad.xcs);
++ }
++ break;
++
++ case PixmapButton:
++ case TiledPixmapButton:
++ case StretchedPixmapButton:
++ case AdjustedPixmapButton:
++ case ShrunkPixmapButton:
++ if (df->u.p)
++ {
++ PDestroyFvwmPicture(dpy, df->u.p);
++ }
++ break;
++
++ case MultiPixmap:
++ if (df->u.mp.pixmaps)
++ {
++ for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
++ {
++ if (df->u.mp.pixmaps[i])
++ {
++ PDestroyFvwmPicture(
++ dpy, df->u.mp.pixmaps[i]);
++ }
++ else if (!!(df->u.mp.solid_flags & i))
++ {
++ PictureFreeColors(
++ dpy, Pcmap,
&df->u.mp.pixels[i],
++ 1, 0, False);
++ }
++ }
++ free(df->u.mp.pixmaps);
++ }
++ if (df->u.mp.acs)
++ {
++ free(df->u.mp.acs);
++ }
++ if (df->u.mp.pixels)
++ {
++ free(df->u.mp.pixels);
++ }
++ break;
++ case VectorButton:
++ case DefaultVectorButton:
++ if (df->u.vector.x)
++ {
++ free (df->u.vector.x);
++ }
++ if (df->u.vector.y)
++ {
++ free (df->u.vector.y);
++ }
++ /* free offsets for coord */
++ if (df->u.vector.xoff)
++ {
++ free(df->u.vector.xoff);
++ }
++ if (df->u.vector.yoff)
++ {
++ free(df->u.vector.yoff);
++ }
++ if (df->u.vector.c)
++ {
++ free (df->u.vector.c);
++ }
++ break;
++ default:
++ /* see below */
++ break;
++ }
++ /* delete any compound styles */
++ if (df->next)
++ {
++ FreeDecorFace(dpy, df->next);
++ free(df->next);
++ }
++ df->next = NULL;
++ memset(&df->style, 0, sizeof(df->style));
++ memset(&df->u, 0, sizeof(df->u));
++ DFS_FACE_TYPE(df->style) = SimpleButton;
++
++ return;
++}
++
++/*
++ *
++ * Reads a button face line into a structure (veliaa AT rpi.edu)
++ *
++ */
++Bool ReadDecorFace(char *s, DecorFace *df, int button, int verbose)
++{
++ int offset;
++ char style[256], *file;
++ char *action = s;
++
++ /* some variants of scanf do not increase the assign count when %n is
++ * used, so a return value of 1 is no error. */
++ if (sscanf(s, "%255s%n", style, &offset) < 1)
++ {
++ if (verbose)
++ {
++ fvwm_msg(ERR, "ReadDecorFace", "error in face `%s'",
s);
++ }
++ return False;
++ }
++ style[255] = 0;
++
++ if (strncasecmp(style, "--", 2) != 0)
++ {
++ s += offset;
++
++ FreeDecorFace(dpy, df);
++
++ /* determine button style */
++ if (strncasecmp(style,"Simple",6)==0)
++ {
++ memset(&df->style, 0, sizeof(df->style));
++ DFS_FACE_TYPE(df->style) = SimpleButton;
++ }
++ else if (strncasecmp(style,"Default",7)==0)
++ {
++ int b = -1, n = sscanf(s, "%d%n", &b, &offset);
++
++ if (n < 1)
++ {
++ if (button == -1)
++ {
++ if (verbose)
++ {
++ fvwm_msg(
++ ERR,"ReadDecorFace",
++ "need default button"
++ " number to load");
++ }
++ return False;
++ }
++ b = button;
++ }
++ else
++ {
++ b = BUTTON_INDEX(b);
++ s += offset;
++ }
++ if (b >= 0 && b < NUMBER_OF_TITLE_BUTTONS)
++ {
++ LoadDefaultButton(df, b);
++ }
++ else
++ {
++ if (verbose)
++ {
++ fvwm_msg(
++ ERR, "ReadDecorFace",
++ "button number out of range:"
++ " %d", b);
++ }
++ return False;
++ }
++ }
++ else if (strncasecmp(style,"Vector",6)==0 ||
++ (strlen(style)<=2 && isdigit(*style)))
++ {
++ /* normal coordinate list button style */
++ int i, num_coords, num;
++ struct vector_coords *vc = &df->u.vector;
++
++ /* get number of points */
++ if (strncasecmp(style,"Vector",6)==0)
++ {
++ num = sscanf(s,"%d%n",&num_coords,&offset);
++ s += offset;
++ }
++ else
++ {
++ num = sscanf(style,"%d",&num_coords);
++ }
++
++ if (num < 1 || num_coords<2 ||
++ num_coords > MAX_TITLE_BUTTON_VECTOR_LINES)
++ {
++ if (verbose)
++ {
++ fvwm_msg(
++ ERR, "ReadDecorFace",
++ "Bad button style (2) in
line:"
++ " %s",action);
++ }
++ return False;
++ }
++
++ vc->num = num_coords;
++ vc->use_fgbg = 0;
++ vc->x = (signed char*)safemalloc(sizeof(char) *
++ num_coords);
++ vc->y = (signed char*)safemalloc(sizeof(char) *
++ num_coords);
++ vc->xoff = (signed char*)safemalloc(sizeof(char) *
++ num_coords);
++ vc->yoff = (signed char*)safemalloc(sizeof(char) *
++ num_coords);
++ vc->c = (signed char*)safemalloc(sizeof(char) *
++ num_coords);
++
++ /* get the points */
++ for (i = 0; i < vc->num; ++i)
++ {
++ int x;
++ int y;
++ int xoff = 0;
++ int yoff = 0;
++ int c;
++
++ if (__parse_vector_line(
++ &s, &x, &y, &xoff, &yoff, &c, s)
==
++ False)
++ {
++ break;
++ }
++ if (x < 0)
++ {
++ x = 0;
++ }
++ if (x > 100)
++ {
++ x = 100;
++ }
++ if (y < 0)
++ {
++ y = 0;
++ }
++ if (y > 100)
++ {
++ y = 100;
++ }
++ if (c < 0 || c > 4)
++ {
++ c = 4;
++ }
++ vc->x[i] = x;
++ vc->y[i] = y;
++ vc->c[i] = c;
++ vc->xoff[i] = xoff;
++ vc->yoff[i] = yoff;
++ if (c == 2 || c == 3)
++ {
++ vc->use_fgbg = 1;
++ }
++ }
++ if (i < vc->num)
++ {
++ if (verbose)
++ {
++ fvwm_msg(
++ ERR, "ReadDecorFace",
++ "Bad button style (3) in line"
++ " %s", action);
++ }
++ free(vc->x);
++ free(vc->y);
++ free(vc->c);
++ free(vc->xoff);
++ free(vc->yoff);
++ vc->x = NULL;
++ vc->y = NULL;
++ vc->c = NULL;
++ vc->xoff = NULL;
++ vc->yoff = NULL;
++ return False;
++ }
++ memset(&df->style, 0, sizeof(df->style));
++ DFS_FACE_TYPE(df->style) = VectorButton;
++ }
++ else if (strncasecmp(style,"Solid",5)==0)
++ {
++ s = GetNextToken(s, &file);
++ if (file)
++ {
++ memset(&df->style, 0, sizeof(df->style));
++ DFS_FACE_TYPE(df->style) = SolidButton;
++ df->u.back = GetColor(file);
++ free(file);
++ }
++ else
++ {
++ if (verbose)
++ {
++ fvwm_msg(
++ ERR, "ReadDecorFace",
++ "no color given for Solid"
++ " face type: %s", action);
++ }
++ return False;
++ }
++ }
++ else if (strncasecmp(style+1, "Gradient", 8)==0)
++ {
++ char **s_colors;
++ int npixels, nsegs, *perc;
++ XColor *xcs;
++ Bool do_dither = False;
++
++ if (!IsGradientTypeSupported(style[0]))
++ {
++ return False;
++ }
++ /* translate the gradient string into an array of
++ * colors etc */
++ npixels = ParseGradient(
++ s, &s, &s_colors, &perc, &nsegs);
++ while (*s && isspace(*s))
++ {
++ s++;
++ }
++ if (npixels <= 0)
++ {
++ return False;
++ }
++ /* grab the colors */
++ if (Pdepth <= 16)
++ {
++ do_dither = True;
++ }
++ xcs = AllocAllGradientColors(
++ s_colors, perc, nsegs, npixels, do_dither);
++ if (xcs == None)
++ return False;
++ df->u.grad.xcs = xcs;
++ df->u.grad.npixels = npixels;
++ df->u.grad.do_dither = do_dither;
++ df->u.grad.d_pixels = NULL;
++ memset(&df->style, 0, sizeof(df->style));
++ DFS_FACE_TYPE(df->style) = GradientButton;
++ df->u.grad.gradient_type = toupper(style[0]);
++ }
++ else if (strncasecmp(style,"Pixmap",6)==0
++ || strncasecmp(style,"TiledPixmap",11)==0
++ || strncasecmp(style,"StretchedPixmap",15)==0
++ || strncasecmp(style,"AdjustedPixmap",14)==0
++ || strncasecmp(style,"ShrunkPixmap",12)==0)
++ {
++ FvwmPictureAttributes fpa;
++
++ s = GetNextToken(s, &file);
++ fpa.mask = (Pdepth <= 8)? FPAM_DITHER:0; /* ? */
++ df->u.p = PCacheFvwmPicture(
++ dpy, Scr.NoFocusWin, NULL, file, fpa);
++ if (df->u.p == NULL)
++ {
++ if (file)
++ {
++ if (verbose)
++ {
++ fvwm_msg(
++ ERR, "ReadDecorFace",
++ "couldn't load pixmap"
++ " %s", file);
++ }
++ free(file);
++ }
++ return False;
++ }
++ if (file)
++ {
++ free(file);
++ file = NULL;
++ }
++
++ memset(&df->style, 0, sizeof(df->style));
++ if (strncasecmp(style,"Tiled",5)==0)
++ {
++ DFS_FACE_TYPE(df->style) = TiledPixmapButton;
++ }
++ else if (strncasecmp(style,"Stretched",9)==0)
++ {
++ DFS_FACE_TYPE(df->style) =
++ StretchedPixmapButton;
++ }
++ else if (strncasecmp(style,"Adjusted",8)==0)
++ {
++ DFS_FACE_TYPE(df->style) =
++ AdjustedPixmapButton;
++ }
++ else if (strncasecmp(style,"Shrunk",6)==0)
++ {
++ DFS_FACE_TYPE(df->style) =
++ ShrunkPixmapButton;
++ }
++ else
++ {
++ DFS_FACE_TYPE(df->style) = PixmapButton;
++ }
++ }
++ else if (strncasecmp(style,"MultiPixmap",11)==0)
++ {
++ if (button != -1)
++ {
++ if (verbose)
++ {
++ fvwm_msg(
++ ERR, "ReadDecorFace",
++ "MultiPixmap is only valid"
++ " for TitleStyle");
++ }
++ return False;
++ }
++ s = ReadMultiPixmapDecor(s, df);
++ if (!s)
++ {
++ return False;
++ }
++ }
++ else if (FMiniIconsSupported &&
++ strncasecmp (style, "MiniIcon", 8) == 0)
++ {
++ memset(&df->style, 0, sizeof(df->style));
++ DFS_FACE_TYPE(df->style) = MiniIconButton;
++ /* pixmap read in when the window is created */
++ df->u.p = NULL;
++ }
++ else if (strncasecmp (style, "Colorset", 8) == 0)
++ {
++ int val[2];
++ int n;
++
++ n = GetIntegerArguments(s, NULL, val, 2);
++ if (n == 0)
++ {
++ }
++ memset(&df->style, 0, sizeof(df->style));
++ if (n > 0 && val[0] >= 0)
++ {
++
++ df->u.acs.cs = val[0];
++ alloc_colorset(val[0]);
++ DFS_FACE_TYPE(df->style) = ColorsetButton;
++ }
++ df->u.acs.alpha_percent = 100;
++ if (n > 1)
++ {
++ df->u.acs.alpha_percent =
++ max(0, min(100,val[1]));
++ }
++ s = SkipNTokens(s, n);
++ }
++ else
++ {
++ if (verbose)
++ {
++ fvwm_msg(
++ ERR, "ReadDecorFace",
++ "unknown style %s: %s", style,
action);
++ }
++ return False;
++ }
++ }
++
++ /* Process button flags ("--" signals start of flags,
++ it is also checked for above) */
++ s = GetNextToken(s, &file);
++ if (file && (strcmp(file,"--")==0))
++ {
++ char *tok;
++ s = GetNextToken(s, &tok);
++ while (tok && *tok)
++ {
++ int set = 1;
++ char *old_tok = NULL;
++
++ if (*tok == '!')
++ { /* flag negate */
++ set = 0;
++ old_tok = tok;
++ tok++;
++ }
++ if (StrEquals(tok,"Clear"))
++ {
++ memset(&DFS_FLAGS(df->style), (set) ? 0 :
0xff,
++ sizeof(DFS_FLAGS(df->style)));
++ /* ? what is set == 0 good for ? */
++ }
++ else if (StrEquals(tok,"Left"))
++ {
++ if (set)
++ {
++ DFS_H_JUSTIFICATION(df->style) =
++ JUST_LEFT;
++ }
++ else
++ {
++ DFS_H_JUSTIFICATION(df->style) =
++ JUST_RIGHT;
++ }
++ }
++ else if (StrEquals(tok,"Right"))
++ {
++ if (set)
++ {
++ DFS_H_JUSTIFICATION(df->style) =
++ JUST_RIGHT;
++ }
++ else
++ {
++ DFS_H_JUSTIFICATION(df->style) =
++ JUST_LEFT;
++ }
++ }
++ else if (StrEquals(tok,"Centered"))
++ {
++ DFS_H_JUSTIFICATION(df->style) = JUST_CENTER;
++ DFS_V_JUSTIFICATION(df->style) = JUST_CENTER;
++ }
++ else if (StrEquals(tok,"Top"))
++ {
++ if (set)
++ {
++ DFS_V_JUSTIFICATION(df->style) =
++ JUST_TOP;
++ }
++ else
++ {
++ DFS_V_JUSTIFICATION(df->style) =
++ JUST_BOTTOM;
++ }
++ }
++ else if (StrEquals(tok,"Bottom"))
++ {
++ if (set)
++ {
++ DFS_V_JUSTIFICATION(df->style) =
++ JUST_BOTTOM;
++ }
++ else
++ {
++ DFS_V_JUSTIFICATION(df->style) =
++ JUST_TOP;
++ }
++ }
++ else if (StrEquals(tok,"Flat"))
++ {
++ if (set)
++ {
++ DFS_BUTTON_RELIEF(df->style) =
++ DFS_BUTTON_IS_FLAT;
++ }
++ else if (DFS_BUTTON_RELIEF(df->style) ==
++ DFS_BUTTON_IS_FLAT)
++ {
++ DFS_BUTTON_RELIEF(df->style) =
++ DFS_BUTTON_IS_UP;
++ }
++ }
++ else if (StrEquals(tok,"Sunk"))
++ {
++ if (set)
++ {
++ DFS_BUTTON_RELIEF(df->style) =
++ DFS_BUTTON_IS_SUNK;
++ }
++ else if (DFS_BUTTON_RELIEF(df->style) ==
++ DFS_BUTTON_IS_SUNK)
++ {
++ DFS_BUTTON_RELIEF(df->style) =
++ DFS_BUTTON_IS_UP;
++ }
++ }
++ else if (StrEquals(tok,"Raised"))
++ {
++ if (set)
++ {
++ DFS_BUTTON_RELIEF(df->style) =
++ DFS_BUTTON_IS_UP;
++ }
++ else
++ {
++ DFS_BUTTON_RELIEF(df->style) =
++ DFS_BUTTON_IS_SUNK;
++ }
++ }
++ else if (StrEquals(tok,"UseTitleStyle"))
++ {
++ if (set)
++ {
++ DFS_USE_TITLE_STYLE(df->style) = 1;
++ DFS_USE_BORDER_STYLE(df->style) = 0;
++ }
++ else
++ DFS_USE_TITLE_STYLE(df->style) = 0;
++ }
++ else if (StrEquals(tok,"HiddenHandles"))
++ {
++ DFS_HAS_HIDDEN_HANDLES(df->style) = !!set;
++ }
++ else if (StrEquals(tok,"NoInset"))
++ {
++ DFS_HAS_NO_INSET(df->style) = !!set;
++ }
++ else if (StrEquals(tok,"UseBorderStyle"))
++ {
++ if (set)
++ {
++ DFS_USE_BORDER_STYLE(df->style) = 1;
++ DFS_USE_TITLE_STYLE(df->style) = 0;
++ }
++ else
++ {
++ DFS_USE_BORDER_STYLE(df->style) = 0;
++ }
++ }
++ else if (verbose)
++ {
++ fvwm_msg(
++ ERR, "ReadDecorFace",
++ "unknown button face flag '%s'"
++ " -- line: %s", tok, action);
++ }
++ if (set)
++ {
++ free(tok);
++ }
++ else
++ {
++ free(old_tok);
++ }
++ s = GetNextToken(s, &tok);
++ }
++ }
++ if (file)
++ {
++ free(file);
++ }
++
++ return True;
++}
++
++#ifdef USEDECOR
++/*
++ *
++ * Diverts a style definition to an FvwmDecor structure (veliaa AT rpi.edu)
++ *
++ */
++void AddToDecor(F_CMD_ARGS, FvwmDecor *decor)
++{
++ if (!action)
++ {
++ return;
++ }
++ while (*action && isspace((unsigned char)*action))
++ {
++ ++action;
++ }
++ if (!*action)
++ {
++ return;
++ }
++ Scr.cur_decor = decor;
++ execute_function(cond_rc, exc, action, 0);
++ Scr.cur_decor = NULL;
++
++ return;
++}
++
++/*
++ *
++ * InitFvwmDecor -- initializes an FvwmDecor structure to defaults
++ *
++ */
++void InitFvwmDecor(FvwmDecor *decor)
++{
++ int i;
++ DecorFace tmpdf;
++
++ /* zero out the structures */
++ memset(decor, 0, sizeof (FvwmDecor));
++ memset(&tmpdf, 0, sizeof(DecorFace));
++
++ /* initialize title-bar button styles */
++ DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
++ for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
++ {
++ int j = 0;
++ for (; j < BS_MaxButtonState; ++j)
++ {
++ TB_STATE(decor->buttons[i])[j] = tmpdf;
++ }
++ }
++ /* reset to default button set */
++ ResetAllButtons(decor);
++ /* initialize title-bar styles */
++ for (i = 0; i < BS_MaxButtonState; ++i)
++ {
++ DFS_FACE_TYPE(
++ TB_STATE(decor->titlebar)[i].style) = SimpleButton;
++ }
++
++ /* initialize border texture styles */
++ DFS_FACE_TYPE(decor->BorderStyle.active.style) = SimpleButton;
++ DFS_FACE_TYPE(decor->BorderStyle.inactive.style) = SimpleButton;
++
++ return;
++}
++
++void reset_decor_changes(void)
++{
++#ifndef USEDECOR
++ Scr.DefaultDecor.flags.has_changed = 0;
++ Scr.DefaultDecor.flags.has_title_height_changed = 0;
++#else
++ FvwmDecor *decor;
++ for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
++ {
++ decor->flags.has_changed = 0;
++ decor->flags.has_title_height_changed = 0;
++ }
++ /* todo: must reset individual change flags too */
++#endif
++
++ return;
++}
++
++void update_fvwm_colorset(int cset)
++{
++ if (cset == Scr.DefaultColorset)
++ {
++ Scr.flags.do_need_window_update = 1;
++ Scr.flags.has_default_color_changed = 1;
++ }
++ UpdateMenuColorset(cset);
++ update_style_colorset(cset);
++ update_decors_colorset(cset);
++
++ return;
++}
++
++/* ---------------------------- builtin commands
--------------------------- */
++
++void CMD_Beep(F_CMD_ARGS)
++{
++ XBell(dpy, 0);
++
++ return;
++}
++
++void CMD_Nop(F_CMD_ARGS)
++{
++ return;
++}
++
++void CMD_EscapeFunc(F_CMD_ARGS)
++{
++ return;
++}
++
++void CMD_CursorMove(F_CMD_ARGS)
++{
++ int x = 0, y = 0;
++ int val1, val2, val1_unit, val2_unit;
++ int virtual_x, virtual_y;
++ int pan_x, pan_y;
++ int x_pages, y_pages;
++
++ if (GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit) !=
2)
++ {
++ fvwm_msg(ERR, "movecursor", "CursorMove needs 2 arguments");
++ return;
++ }
++ if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
++ &x, &y, &JunkX, &JunkY, &JunkMask) == False)
++ {
++ /* pointer is on a different screen */
++ return;
++ }
++ x = x + val1 * val1_unit / 100;
++ y = y + val2 * val2_unit / 100;
++ virtual_x = Scr.Vx;
++ virtual_y = Scr.Vy;
++ if (x >= 0)
++ {
++ x_pages = x / Scr.MyDisplayWidth;
++ }
++ else
++ {
++ x_pages = ((x + 1) / Scr.MyDisplayWidth) - 1;
++ }
++ virtual_x += x_pages * Scr.MyDisplayWidth;
++ x -= x_pages * Scr.MyDisplayWidth;
++ if (virtual_x < 0)
++ {
++ x += virtual_x;
++ virtual_x = 0;
++ }
++ else if (virtual_x > Scr.VxMax)
++ {
++ x += virtual_x - Scr.VxMax;
++ virtual_x = Scr.VxMax;
++ }
++
++ if (y >= 0)
++ {
++ y_pages = y / Scr.MyDisplayHeight;
++ }
++ else
++ {
++ y_pages = ((y + 1) / Scr.MyDisplayHeight) - 1;
++ }
++ virtual_y += y_pages * Scr.MyDisplayHeight;
++ y -= y_pages * Scr.MyDisplayHeight;
++ if (virtual_y < 0)
++ {
++ y += virtual_y;
++ virtual_y = 0;
++ }
++ else if (virtual_y > Scr.VyMax)
++ {
++ y += virtual_y - Scr.VyMax;
++ virtual_y = Scr.VyMax;
++ }
++ if (virtual_x != Scr.Vx || virtual_y != Scr.Vy)
++ MoveViewport(virtual_x, virtual_y, True);
++ pan_x = (Scr.EdgeScrollX != 0) ? 2 : 0;
++ pan_y = (Scr.EdgeScrollY != 0) ? 2 : 0;
++ /* prevent paging if EdgeScroll is active */
++ if (x >= Scr.MyDisplayWidth - pan_x)
++ {
++ x = Scr.MyDisplayWidth - pan_x -1;
++ }
++ else if (x < pan_x)
++ {
++ x = pan_x;
++ }
++ if (y >= Scr.MyDisplayHeight - pan_y)
++ {
++ y = Scr.MyDisplayHeight - pan_y - 1;
++ }
++ else if (y < pan_y)
++ {
++ y = pan_y;
++ }
++ FWarpPointerUpdateEvpos(
++ exc->x.elast, dpy, None, Scr.Root, 0, 0, Scr.MyDisplayWidth,
++ Scr.MyDisplayHeight, x, y);
++
++ return;
++}
++
++void CMD_Delete(F_CMD_ARGS)
++{
++ FvwmWindow * const fw = exc->w.fw;
++
++ if (!is_function_allowed(F_DELETE, NULL, fw, True, True))
++ {
++ XBell(dpy, 0);
++ return;
++ }
++ if (IS_TEAR_OFF_MENU(fw))
++ {
++ /* 'soft' delete tear off menus. Note: we can't send the
++ * message to the menu window directly because it was created
++ * using a different display. The client message would never
++ * be read from there. */
++ send_clientmessage(
++ dpy, FW_W_PARENT(fw), _XA_WM_DELETE_WINDOW,
++ CurrentTime);
++ return;
++ }
++ if (WM_DELETES_WINDOW(fw))
++ {
++ send_clientmessage(
++ dpy, FW_W(fw), _XA_WM_DELETE_WINDOW, CurrentTime);
++ return;
++ }
++ else
++ {
++ XBell(dpy, 0);
++ }
++ XFlush(dpy);
++
++ return;
++}
++
++void CMD_Destroy(F_CMD_ARGS)
++{
++ FvwmWindow * const fw = exc->w.fw;
++
++ if (IS_TEAR_OFF_MENU(fw))
++ {
++ CMD_Delete(F_PASS_ARGS);
++ return;
++ }
++ if (!is_function_allowed(F_DESTROY, NULL, fw, True, True))
++ {
++ XBell(dpy, 0);
++ return;
++ }
++ if (
++ XGetGeometry(
++ dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
++ (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
++ (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)
++ != 0)
++ {
++ XKillClient(dpy, FW_W(fw));
++ }
++ destroy_window(fw);
++ XFlush(dpy);
++
++ return;
++}
++
++void CMD_Close(F_CMD_ARGS)
++{
++ FvwmWindow * const fw = exc->w.fw;
++
++ if (IS_TEAR_OFF_MENU(fw))
++ {
++ CMD_Delete(F_PASS_ARGS);
++ return;
++ }
++ if (!is_function_allowed(F_CLOSE, NULL, fw, True, True))
++ {
++ XBell(dpy, 0);
++ return;
++ }
++ if (WM_DELETES_WINDOW(fw))
++ {
++ send_clientmessage(
++ dpy, FW_W(fw), _XA_WM_DELETE_WINDOW, CurrentTime);
++ return;
++ }
++ if (
++ XGetGeometry(
++ dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
++ (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
++ (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)
++ != 0)
++ {
++ XKillClient(dpy, FW_W(fw));
++ }
++
++ destroy_window(fw);
++ XFlush(dpy);
++
++ return;
++}
++
++void CMD_Restart(F_CMD_ARGS)
++{
++ Done(1, action);
++
++ return;
++}
++
++void CMD_ExecUseShell(F_CMD_ARGS)
++{
++ char *arg=NULL;
++ static char shell_set = 0;
++
++ if (shell_set)
++ {
++ free(exec_shell_name);
++ }
++ shell_set = 1;
++ action = GetNextToken(action,&arg);
++ if (arg) /* specific shell was specified */
++ {
++ exec_shell_name = arg;
++ }
++ else /* no arg, so use $SHELL -- not working??? */
++ {
++ if (getenv("SHELL"))
++ {
++ exec_shell_name = safestrdup(getenv("SHELL"));
++ }
++ else
++ {
++ /* if $SHELL not set, use default */
++ exec_shell_name = safestrdup("/bin/sh");
++ }
++ }
++}
++
++void CMD_Exec(F_CMD_ARGS)
++{
++ char *cmd=NULL;
++
++ /* if it doesn't already have an 'exec' as the first word, add that
++ * to keep down number of procs started */
++ /* need to parse string better to do this right though, so not doing
++ * this for now... */
++#if 0
++ if (strncasecmp(action,"exec",4)!=0)
++ {
++ cmd = (char *)safemalloc(strlen(action)+6);
++ strcpy(cmd,"exec ");
++ strcat(cmd,action);
++ }
++ else
++#endif
++ {
++ cmd = safestrdup(action);
++ }
++ if (!cmd)
++ {
++ return;
++ }
++ /* Use to grab the pointer here, but the fork guarantees that
++ * we wont be held up waiting for the function to finish,
++ * so the pointer-gram just caused needless delay and flashing
++ * on the screen */
++ /* Thought I'd try vfork and _exit() instead of regular fork().
++ * The man page says that its better. */
++ /* Not everyone has vfork! */
++ /* According to the man page, vfork should never be used at all.
++ */
++
++ if (!(fork())) /* child process */
++ {
++ /* This is for fixing a problem with rox filer */
++ int fd;
++ fd = open("/dev/null", O_RDONLY, 0);
++ dup2(fd,STDIN_FILENO);
++ if (fvwm_setpgrp() == -1)
++ {
++ fvwm_msg(ERR, "exec_function", "setpgrp failed (%s)",
++ strerror(errno));
++ exit(100);
++ }
++ if (execl(exec_shell_name, exec_shell_name, "-c", cmd, NULL)
==
++ -1)
++ {
++ fvwm_msg(ERR, "exec_function", "execl failed (%s)",
++ strerror(errno));
++ exit(100);
++ }
++ }
++ free(cmd);
++
++ return;
++}
++
++void CMD_Refresh(F_CMD_ARGS)
++{
++ refresh_window(Scr.Root, True);
++
++ return;
++}
++
++void CMD_RefreshWindow(F_CMD_ARGS)
++{
++ FvwmWindow * const fw = exc->w.fw;
++
++ refresh_window(
++ (exc->w.wcontext == C_ICON) ?
++ FW_W_ICON_TITLE(fw) : FW_W_FRAME(fw), True);
++
++ return;
++}
++
++void CMD_Wait(F_CMD_ARGS)
++{
++ Bool done = False;
++ Bool redefine_cursor = False;
++ Bool is_ungrabbed;
++ char *escape;
++ Window nonewin = None;
++ char *wait_string, *rest;
++ FvwmWindow *t;
++
++ /* try to get a single token */
++ rest = GetNextToken(action, &wait_string);
++ if (wait_string)
++ {
++ while (*rest && isspace((unsigned char)*rest))
++ {
++ rest++;
++ }
++ if (*rest)
++ {
++ int i;
++ char *temp;
++
++ /* nope, multiple tokens - try old syntax */
++
++ /* strip leading and trailing whitespace */
++ temp = action;
++ while (*temp && isspace((unsigned char)*temp))
++ {
++ temp++;
++ }
++ wait_string = safestrdup(temp);
++ for (i = strlen(wait_string) - 1; i >= 0 &&
++ isspace(wait_string[i]); i--)
++ {
++ wait_string[i] = 0;
++ }
++ }
++ }
++ else
++ {
++ wait_string = safestrdup("");
++ }
++
++ is_ungrabbed = UngrabEm(GRAB_NORMAL);
++ while (!done && !isTerminated)
++ {
++ XEvent e;
++ if (BUSY_WAIT & Scr.BusyCursor)
++ {
++ XDefineCursor(dpy, Scr.Root,
Scr.FvwmCursors[CRS_WAIT]);
++ redefine_cursor = True;
++ }
++ if (My_XNextEvent(dpy, &e))
++ {
++ dispatch_event(&e);
++ if (XFindContext(
++ dpy, e.xmap.window, FvwmContext,
++ (caddr_t *)&t) == XCNOENT)
++ {
++ t = NULL;
++ }
++
++ if (e.type == MapNotify && e.xmap.event == Scr.Root)
++ {
++ if (!*wait_string)
++ {
++ done = True;
++ }
++ if (t && matchWildcards(
++ wait_string, t->name.name) ==
True)
++ {
++ done = True;
++ }
++ else if (t && t->class.res_class &&
++ matchWildcards(
++ wait_string,
++ t->class.res_class) == True)
++ {
++ done = True;
++ }
++ else if (t && t->class.res_name &&
++ matchWildcards(
++ wait_string,
++ t->class.res_name) == True)
++ {
++ done = True;
++ }
++ }
++ else if (e.type == KeyPress)
++ {
++ /* should I be using <t> or <exc->w.fw>?
++ * DV: t
++ */
++ int context;
++ XClassHint *class;
++ char *name;
++
++ context = GetContext(&t, t, &e, &nonewin);
++ if (t != NULL)
++ {
++ class = &(t->class);
++ name = t->name.name;
++ }
++ else
++ {
++ class = NULL;
++ name = NULL;
++ }
++ escape = CheckBinding(
++ Scr.AllBindings, STROKE_ARG(0)
++ e.xkey.keycode, e.xkey.state,
++ GetUnusedModifiers(), context,
++ BIND_KEYPRESS, class, name);
++ if (escape != NULL)
++ {
++ if (!strcasecmp(escape,"escapefunc"))
++ {
++ done = True;
++ }
++ }
++ }
++ }
++ }
++ if (redefine_cursor)
++ {
++ XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_ROOT]);
++ }
++ if (is_ungrabbed)
++ {
++ GrabEm(CRS_NONE, GRAB_NORMAL);
++ }
++ free(wait_string);
++
++ return;
++}
++
++void CMD_Quit(F_CMD_ARGS)
++{
++ if (master_pid != getpid())
++ {
++ kill(master_pid, SIGTERM);
++ }
++ Done(0,NULL);
++
++ return;
++}
++
++void CMD_QuitScreen(F_CMD_ARGS)
++{
++ Done(0,NULL);
++
++ return;
++}
++
++void CMD_Echo(F_CMD_ARGS)
++{
++ int len;
++
++ if (!action)
++ {
++ action = "";
++ }
++ len = strlen(action);
++ if (len != 0)
++ {
++ if (action[len-1]=='\n')
++ {
++ action[len-1]='\0';
++ }
++ }
++ fvwm_msg(ECHO,"Echo",action);
++
++ return;
++}
++
++void CMD_PrintInfo(F_CMD_ARGS)
++{
++ int verbose;
++ char *rest, *subject = NULL;
++
++ rest = GetNextToken(action, &subject);
++ if (!rest || GetIntegerArguments(rest, NULL, &verbose, 1) != 1)
++ {
++ verbose = 0;
++ }
++ if (StrEquals(subject, "Colors"))
++ {
++ PicturePrintColorInfo(verbose);
++ }
++ else if (StrEquals(subject, "Locale"))
++ {
++ FlocalePrintLocaleInfo(dpy, verbose);
++ }
++ else if (StrEquals(subject, "NLS"))
++ {
++ FGettextPrintLocalePath(verbose);
++ }
++ else if (StrEquals(subject, "style"))
++ {
++ print_styles(verbose);
++ }
++ else
++ {
++ fvwm_msg(ERR, "PrintInfo",
++ "Unknown subject '%s'", action);
++ }
++ if (subject)
++ {
++ free(subject);
++ }
++ return;
++}
++
++void CMD_ColormapFocus(F_CMD_ARGS)
++{
++ if (MatchToken(action,"FollowsFocus"))
++ {
++ Scr.ColormapFocus = COLORMAP_FOLLOWS_FOCUS;
++ }
++ else if (MatchToken(action,"FollowsMouse"))
++ {
++ Scr.ColormapFocus = COLORMAP_FOLLOWS_MOUSE;
++ }
++ else
++ {
++ fvwm_msg(ERR, "SetColormapFocus",
++ "ColormapFocus requires 1 arg: FollowsFocus or"
++ " FollowsMouse");
++ return;
++ }
++
++ return;
++}
++
++void CMD_ClickTime(F_CMD_ARGS)
++{
++ int val;
++
++ if (GetIntegerArguments(action, NULL, &val, 1) != 1)
++ {
++ Scr.ClickTime = DEFAULT_CLICKTIME;
++ }
++ else
++ {
++ Scr.ClickTime = (val < 0)? 0 : val;
++ }
++
++ /* Use a negative value during startup and change sign afterwards.
This
++ * speeds things up quite a bit. */
++ if (fFvwmInStartup)
++ {
++ Scr.ClickTime = -Scr.ClickTime;
++ }
++
++ return;
++}
++
++
++void CMD_ImagePath(F_CMD_ARGS)
++{
++ PictureSetImagePath( action );
++
++ return;
++}
++
++void CMD_IconPath(F_CMD_ARGS)
++{
++ fvwm_msg(ERR, "iconPath_function",
++ "IconPath is deprecated since 2.3.0; use ImagePath
instead.");
++ obsolete_imagepaths( action );
++
++ return;
++}
++
++void CMD_PixmapPath(F_CMD_ARGS)
++{
++ fvwm_msg(ERR, "pixmapPath_function",
++ "PixmapPath is deprecated since 2.3.0; use ImagePath"
++ " instead." );
++ obsolete_imagepaths( action );
++
++ return;
++}
++
++void CMD_LocalePath(F_CMD_ARGS)
++{
++ FGettextSetLocalePath( action );
++
++ return;
++}
++
++void CMD_ModulePath(F_CMD_ARGS)
++{
++ static int need_to_free = 0;
++
++ setPath( &ModulePath, action, need_to_free );
++ need_to_free = 1;
++
++ return;
++}
++
++void CMD_ModuleTimeout(F_CMD_ARGS)
++{
++ int timeout;
++
++ moduleTimeout = DEFAULT_MODULE_TIMEOUT;
++ if (GetIntegerArguments(action, NULL, &timeout, 1) == 1 && timeout >
0)
++ {
++ moduleTimeout = timeout;
++ }
++
++ return;
++}
++
++void CMD_HilightColor(F_CMD_ARGS)
++{
++ char *fore;
++ char *back;
++#ifdef USEDECOR
++ if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
++ {
++ fvwm_msg(
++ ERR, "SetHiColor",
++ "Decors do not support the HilightColor command"
++ " anymore. Please use"
++ " 'Style <stylename> HilightFore <forecolor>' and"
++ " 'Style <stylename> HilightBack <backcolor>'
instead."
++ " Sorry for the inconvenience.");
++ return;
++ }
++#endif
++ action = GetNextToken(action, &fore);
++ GetNextToken(action, &back);
++ if (fore && back)
++ {
++ action = safemalloc(strlen(fore) + strlen(back) + 29);
++ sprintf(action, "* HilightFore %s, HilightBack %s", fore,
back);
++ CMD_Style(F_PASS_ARGS);
++ }
++ if (fore)
++ {
++ free(fore);
++ }
++ if (back)
++ {
++ free(back);
++ }
++
++ return;
++}
++
++void CMD_HilightColorset(F_CMD_ARGS)
++{
++ char *newaction;
++
++#ifdef USEDECOR
++ if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
++ {
++ fvwm_msg(
++ ERR, "SetHiColorset",
++ "Decors do not support the HilightColorset command "
++ "anymore. Please use "
++ "'Style <stylename> HilightColorset <colorset>'"
++ " instead. Sorry for the inconvenience.");
++ return;
++ }
++#endif
++ if (action)
++ {
++ newaction = safemalloc(strlen(action) + 32);
++ sprintf(newaction, "* HilightColorset %s", action);
++ action = newaction;
++ CMD_Style(F_PASS_ARGS);
++ free(newaction);
++ }
++
++ return;
++}
++
++void CMD_TitleStyle(F_CMD_ARGS)
++{
++ do_title_style(F_PASS_ARGS, False);
++
++ return;
++} /* SetTitleStyle */
++
++/*
++ *
++ * Appends a titlestyle (veliaa AT rpi.edu)
++ *
++ */
++void CMD_AddTitleStyle(F_CMD_ARGS)
++{
++ do_title_style(F_PASS_ARGS, True);
++
++ return;
++}
++
++void CMD_PropertyChange(F_CMD_ARGS)
++{
++ char string[256] = "\0";
++ int ret;
++ unsigned long argument, data1 = 0, data2 = 0;
++
++ if (action == NULL || action == "\0")
++ {
++ return;
++ }
++ ret = sscanf(
++ action,"%lu %lu %lu %255c", &argument, &data1, &data2,
string);
++ if (ret < 1)
++ {
++ return;
++ }
++ BroadcastPropertyChange(
++ argument, data1, data2, (string == NULL)? "":string);
++
++ return;
++}
++
++void CMD_DefaultIcon(F_CMD_ARGS)
++{
++ if (Scr.DefaultIcon)
++ {
++ free(Scr.DefaultIcon);
++ }
++ GetNextToken(action, &Scr.DefaultIcon);
++
++ return;
++}
++
++void CMD_DefaultColorset(F_CMD_ARGS)
++{
++ int cset;
++
++ if (GetIntegerArguments(action, NULL, &cset, 1) != 1)
++ {
++ return;
++ }
++ Scr.DefaultColorset = cset;
++ if (Scr.DefaultColorset < 0)
++ {
++ Scr.DefaultColorset = -1;
++ }
++ alloc_colorset(Scr.DefaultColorset);
++ Scr.flags.do_need_window_update = 1;
++ Scr.flags.has_default_color_changed = 1;
++
++ return;
++}
++
++void CMD_DefaultColors(F_CMD_ARGS)
++{
++ char *fore = NULL;
++ char *back = NULL;
++
++ action = GetNextToken(action, &fore);
++ if (action)
++ {
++ action = GetNextToken(action, &back);
++ }
++ if (!back)
++ {
++ back = safestrdup(DEFAULT_BACK_COLOR);
++ }
++ if (!fore)
++ {
++ fore = safestrdup(DEFAULT_FORE_COLOR);
++ }
++ if (!StrEquals(fore, "-"))
++ {
++ PictureFreeColors(dpy, Pcmap, &Scr.StdFore, 1, 0, True);
++ Scr.StdFore = GetColor(fore);
++ }
++ if (!StrEquals(back, "-"))
++ {
++ PictureFreeColors(dpy, Pcmap, &Scr.StdBack, 3, 0, True);
++ Scr.StdBack = GetColor(back);
++ Scr.StdHilite = GetHilite(Scr.StdBack);
++ Scr.StdShadow = GetShadow(Scr.StdBack);
++ }
++ free(fore);
++ free(back);
++
++ Scr.DefaultColorset = -1;
++ Scr.flags.do_need_window_update = 1;
++ Scr.flags.has_default_color_changed = 1;
++
++ return;
++}
++
++void CMD_DefaultFont(F_CMD_ARGS)
++{
++ char *font;
++ FlocaleFont *new_font;
++ FvwmWindow *t;
++
++ font = PeekToken(action, &action);
++ if (!font)
++ {
++ /* Try 'fixed', pass NULL font name */
++ }
++ if (!(new_font = FlocaleLoadFont(dpy, font, "FVWM")))
++ {
++ if (Scr.DefaultFont == NULL)
++ {
++ exit(1);
++ }
++ else
++ {
++ return;
++ }
++ }
++ FlocaleUnloadFont(dpy, Scr.DefaultFont);
++ Scr.DefaultFont = new_font;
++ /* we should do that here because a redraw can happen before
++ flush_window_updates is called ... */
++ for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
++ {
++ if (USING_DEFAULT_ICON_FONT(t))
++ {
++ t->icon_font = Scr.DefaultFont;
++ }
++ if (USING_DEFAULT_WINDOW_FONT(t))
++ {
++ t->title_font = Scr.DefaultFont;
++ }
++ }
++ /* set flags to indicate that the font has changed */
++ Scr.flags.do_need_window_update = 1;
++ Scr.flags.has_default_font_changed = 1;
++
++ return;
++}
++
++void CMD_IconFont(F_CMD_ARGS)
++{
++ char *newaction;
++
++#ifdef USEDECOR
++ if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
++ {
++ fvwm_msg(
++ ERR, "LoadIconFont",
++ "Decors do not support the IconFont command anymore."
++ " Please use 'Style <stylename> IconFont <fontname>'"
++ " instead. Sorry for the inconvenience.");
++ return;
++ }
++#endif
++ if (action)
++ {
++ newaction = safemalloc(strlen(action) + 16);
++ sprintf(newaction, "* IconFont %s", action);
++ action = newaction;
++ CMD_Style(F_PASS_ARGS);
++ free(newaction);
++ }
++
++ return;
++}
++
++void CMD_WindowFont(F_CMD_ARGS)
++{
++ char *newaction;
++
++#ifdef USEDECOR
++ if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
++ {
++ fvwm_msg(
++ ERR, "LoadWindowFont",
++ "Decors do not support the WindowFont command
anymore."
++ " Please use 'Style <stylename> Font <fontname>'"
++ " instead. Sorry for the inconvenience.");
++ return;
++ }
++#endif
++ if (action)
++ {
++ newaction = safemalloc(strlen(action) + 16);
++ sprintf(newaction, "* Font %s", action);
++ action = newaction;
++ CMD_Style(F_PASS_ARGS);
++ free(newaction);
++ }
++
++ return;
++}
++
++/*
++ *
++ * Changes the window's FvwmDecor pointer (veliaa AT rpi.edu)
++ *
++ */
++void CMD_ChangeDecor(F_CMD_ARGS)
++{
++ char *item;
++ int old_height;
++ FvwmDecor *decor = &Scr.DefaultDecor;
++ FvwmDecor *found = NULL;
++ FvwmWindow * const fw = exc->w.fw;
++
++ item = PeekToken(action, &action);
++ if (!action || !item)
++ {
++ return;
++ }
++ /* search for tag */
++ for (; decor; decor = decor->next)
++ {
++ if (decor->tag && StrEquals(item, decor->tag))
++ {
++ found = decor;
++ break;
++ }
++ }
++ if (!found)
++ {
++ XBell(dpy, 0);
++ return;
++ }
++ SET_DECOR_CHANGED(fw, 1);
++ old_height = (fw->decor) ? fw->decor->title_height : 0;
++ fw->decor = found;
++ apply_decor_change(fw);
++
++ return;
++}
++
++/*
++ *
++ * Destroys an FvwmDecor (veliaa AT rpi.edu)
++ *
++ */
++void CMD_DestroyDecor(F_CMD_ARGS)
++{
++ char *item;
++ FvwmDecor *decor = Scr.DefaultDecor.next;
++ FvwmDecor *prev = &Scr.DefaultDecor, *found = NULL;
++ Bool do_recreate = False;
++
++ item = PeekToken(action, &action);
++ if (!item)
++ {
++ return;
++ }
++ if (StrEquals(item, "recreate"))
++ {
++ do_recreate = True;
++ item = PeekToken(action, NULL);
++ }
++ if (!item)
++ {
++ return;
++ }
++
++ /* search for tag */
++ for (; decor; decor = decor->next)
++ {
++ if (decor->tag && StrEquals(item, decor->tag))
++ {
++ found = decor;
++ break;
++ }
++ prev = decor;
++ }
++
++ if (found && (found != &Scr.DefaultDecor || do_recreate))
++ {
++ if (!do_recreate)
++ {
++ __remove_window_decors(F_PASS_ARGS, found);
++ }
++ DestroyFvwmDecor(found);
++ if (do_recreate)
++ {
++ int i;
++
++ InitFvwmDecor(found);
++ found->tag = safestrdup(item);
++ Scr.flags.do_need_window_update = 1;
++ found->flags.has_changed = 1;
++ found->flags.has_title_height_changed = 0;
++ found->titlebar.flags.has_changed = 1;
++ for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
++ {
++ TB_FLAGS(found->buttons[i]).has_changed = 1;
++ }
++ }
++ else
++ {
++ prev->next = found->next;
++ free(found);
++ }
++ }
++
++ return;
++}
++
++/*
++ *
++ * Initiates an AddToDecor (veliaa AT rpi.edu)
++ *
++ */
++void CMD_AddToDecor(F_CMD_ARGS)
++{
++ FvwmDecor *decor;
++ FvwmDecor *found = NULL;
++ char *item = NULL;
++
++ action = GetNextToken(action, &item);
++ if (!item)
++ {
++ return;
++ }
++ if (!action)
++ {
++ free(item);
++ return;
++ }
++ /* search for tag */
++ for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
++ {
++ if (decor->tag && StrEquals(item, decor->tag))
++ {
++ found = decor;
++ break;
++ }
++ }
++ if (!found)
++ {
++ /* then make a new one */
++ found = (FvwmDecor *)safemalloc(sizeof( FvwmDecor ));
++ InitFvwmDecor(found);
++ found->tag = item; /* tag it */
++ /* add it to list */
++ for (decor = &Scr.DefaultDecor; decor->next;
++ decor = decor->next)
++ {
++ /* nop */
++ }
++ decor->next = found;
++ }
++ else
++ {
++ free(item);
++ }
++
++ if (found)
++ {
++ AddToDecor(F_PASS_ARGS, found);
++ /* Set + state to last decor */
++ set_last_added_item(ADDED_DECOR, found);
++ }
++
++ return;
++}
++#endif /* USEDECOR */
++
++
++/*
++ *
++ * Updates window decoration styles (veliaa AT rpi.edu)
++ *
++ */
++void CMD_UpdateDecor(F_CMD_ARGS)
++{
++ FvwmWindow *fw2;
++#ifdef USEDECOR
++ FvwmDecor *decor, *found = NULL;
++ FvwmWindow *hilight = Scr.Hilite;
++ char *item = NULL;
++
++ action = GetNextToken(action, &item);
++ if (item)
++ {
++ /* search for tag */
++ for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
++ {
++ if (decor->tag && StrEquals(item, decor->tag))
++ {
++ found = decor;
++ break;
++ }
++ }
++ free(item);
++ }
++#endif
++
++ for (fw2 = Scr.FvwmRoot.next; fw2; fw2 = fw2->next)
++ {
++#ifdef USEDECOR
++ /* update specific decor, or all */
++ if (found)
++ {
++ if (fw2->decor == found)
++ {
++ border_draw_decorations(
++ fw2, PART_ALL, True, True, CLEAR_ALL,
++ NULL, NULL);
++ border_draw_decorations(
++ fw2, PART_ALL, False, True, CLEAR_ALL,
++ NULL, NULL);
++ }
++ }
++ else
++#endif
++ {
++ border_draw_decorations(
++ fw2, PART_ALL, True, True, CLEAR_ALL, NULL,
++ NULL);
++ border_draw_decorations(
++ fw2, PART_ALL, False, True, CLEAR_ALL, NULL,
++ NULL);
++ }
++ }
++ border_draw_decorations(
++ hilight, PART_ALL, True, True, CLEAR_ALL, NULL, NULL);
++}
++
++void CMD_ButtonStyle(F_CMD_ARGS)
++{
++ do_button_style(F_PASS_ARGS, False);
++
++ return;
++}
++
++/*
++ *
++ * Appends a button decoration style (veliaa AT rpi.edu)
++ *
++ */
++void CMD_AddButtonStyle(F_CMD_ARGS)
++{
++ do_button_style(F_PASS_ARGS, True);
++
++ return;
++}
++
++void CMD_SetEnv(F_CMD_ARGS)
++{
++ char *szVar = NULL;
++ char *szValue = NULL;
++ char *szPutenv = NULL;
++
++ action = GetNextToken(action, &szVar);
++ if (!szVar)
++ {
++ return;
++ }
++ action = GetNextToken(action, &szValue);
++ if (!szValue)
++ {
++ szValue = safestrdup("");
++ }
++ szPutenv = safemalloc(strlen(szVar) + strlen(szValue) + 2);
++ sprintf(szPutenv,"%s=%s", szVar, szValue);
++ flib_putenv(szVar, szPutenv);
++ free(szVar);
++ free(szPutenv);
++ free(szValue);
++
++ return;
++}
++
++void CMD_UnsetEnv(F_CMD_ARGS)
++{
++ char *szVar = NULL;
++
++ szVar = PeekToken(action, &action);
++ if (!szVar)
++ {
++ return;
++ }
++ flib_unsetenv(szVar);
++
++ return;
++}
++
++void CMD_GlobalOpts(F_CMD_ARGS)
++{
++ char *opt;
++ char *replace;
++ char buf[64];
++ int i;
++ Bool is_bugopt;
++ char *optlist[] = {
++ "WindowShadeShrinks",
++ "WindowShadeScrolls",
++ "SmartPlacementIsReallySmart",
++ "SmartPlacementIsNormal",
++ "ClickToFocusDoesntPassClick",
++ "ClickToFocusPassesClick",
++ "ClickToFocusDoesntRaise",
++ "ClickToFocusRaises",
++ "MouseFocusClickDoesntRaise",
++ "MouseFocusClickRaises",
++ "NoStipledTitles",
++ "StipledTitles",
++ "CaptureHonorsStartsOnPage",
++ "CaptureIgnoresStartsOnPage",
++ "RecaptureHonorsStartsOnPage",
++ "RecaptureIgnoresStartsOnPage",
++ "ActivePlacementHonorsStartsOnPage",
++ "ActivePlacementIgnoresStartsOnPage",
++ "RaiseOverNativeWindows",
++ "IgnoreNativeWindows",
++ NULL
++ };
++ char *replacelist[] = {
++ /* These options are mapped to the Style * command */
++ NULL, /* NULL means to use "Style * <optionname>" */
++ NULL,
++ "* MinOverlapPlacement",
++ "* TileCascadePlacement",
++ "* ClickToFocusPassesClickOff",
++ "* ClickToFocusPassesClick",
++ "* ClickToFocusRaisesOff",
++ "* ClickToFocusRaises",
++ "* MouseFocusClickRaisesOff",
++ "* MouseFocusClickRaises",
++ "* StippledTitleOff",
++ "* StippledTitle",
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ "* ManualPlacementHonorsStartsOnPage",
++ "* ManualPlacementIgnoresStartsOnPage",
++ /* These options are mapped to the BugOpts command */
++ "RaiseOverNativeWindows on",
++ "RaiseOverNativeWindows off"
++ };
++
++ fvwm_msg(ERR, "SetGlobalOptions",
++ "The GlobalOpts command is obsolete.");
++ for (action = GetNextSimpleOption(action, &opt); opt;
++ action = GetNextSimpleOption(action, &opt))
++ {
++ replace = NULL;
++ is_bugopt = False;
++
++ i = GetTokenIndex(opt, optlist, 0, NULL);
++ if (i > -1)
++ {
++ char *cmd;
++ char *tmp;
++
++ replace = replacelist[i];
++ if (replace == NULL)
++ {
++ replace = &(buf[0]);
++ sprintf(buf, "* %s", opt);
++ }
++ else if (*replace != '*')
++ {
++ is_bugopt = True;
++ }
++ tmp = action;
++ action = replace;
++ if (!is_bugopt)
++ {
++ CMD_Style(F_PASS_ARGS);
++ cmd = "Style";
++ }
++ else
++ {
++ CMD_BugOpts(F_PASS_ARGS);
++ cmd = "BugOpts";
++ }
++ action = tmp;
++ fvwm_msg(
++ ERR, "SetGlobalOptions",
++ "Please replace 'GlobalOpts %s' with '%s
%s'.",
++ opt, cmd, replace);
++ }
++ else
++ {
++ fvwm_msg(ERR, "SetGlobalOptions",
++ "Unknown Global Option '%s'", opt);
++ }
++ /* should never be null, but checking anyways... */
++ if (opt)
++ {
++ free(opt);
++ }
++ }
++ if (opt)
++ {
++ free(opt);
++ }
++
++ return;
++}
++
++void CMD_BugOpts(F_CMD_ARGS)
++{
++ char *opt;
++ char delim;
++ int toggle;
++
++ /* fvwm_msg(DBG,"SetGlobalOptions","init action == '%s'\n",action); */
++ while (action)
++ {
++ action = DoGetNextToken(action, &opt, NULL, ",", &delim);
++ if (!opt)
++ {
++ /* no more options */
++ return;
++ }
++ if (delim == '\n' || delim == ',')
++ {
++ /* missing toggle argument */
++ toggle = 2;
++ }
++ else
++ {
++ toggle = ParseToggleArgument(action, &action, 1,
False);
++ }
++
++ if (StrEquals(opt, "FlickeringMoveWorkaround"))
++ {
++ switch (toggle)
++ {
++ case -1:
++ Scr.bo.do_disable_configure_notify ^= 1;
++ break;
++ case 0:
++ case 1:
++ Scr.bo.do_disable_configure_notify = toggle;
++ break;
++ default:
++ Scr.bo.do_disable_configure_notify = 0;
++ break;
++ }
++ }
++ else if (StrEquals(opt, "MixedVisualWorkaround"))
++ {
++ switch (toggle)
++ {
++ case -1:
++ Scr.bo.do_install_root_cmap ^= 1;
++ break;
++ case 0:
++ case 1:
++ Scr.bo.do_install_root_cmap = toggle;
++ break;
++ default:
++ Scr.bo.do_install_root_cmap = 0;
++ break;
++ }
++ }
++ else if (StrEquals(opt, "ModalityIsEvil"))
++ {
++ switch (toggle)
++ {
++ case -1:
++ Scr.bo.is_modality_evil ^= 1;
++ break;
++ case 0:
++ case 1:
++ Scr.bo.is_modality_evil = toggle;
++ break;
++ default:
++ Scr.bo.is_modality_evil = 0;
++ break;
++ }
++ if (Scr.bo.is_modality_evil)
++ {
++ SetMWM_INFO(Scr.NoFocusWin);
++ }
++ }
++ else if (StrEquals(opt, "RaiseOverNativeWindows"))
++ {
++ switch (toggle)
++ {
++ case -1:
++ Scr.bo.is_raise_hack_needed ^= 1;
++ break;
++ case 0:
++ case 1:
++ Scr.bo.is_raise_hack_needed = toggle;
++ break;
++ default:
++ Scr.bo.is_raise_hack_needed = 0;
++ break;
++ }
++ }
++ else if (StrEquals(opt, "RaiseOverUnmanaged"))
++ {
++ switch (toggle)
++ {
++ case -1:
++ Scr.bo.do_raise_over_unmanaged ^= 1;
++ break;
++ case 0:
++ case 1:
++ Scr.bo.do_raise_over_unmanaged = toggle;
++ break;
++ default:
++ Scr.bo.do_raise_over_unmanaged = 0;
++ break;
++ }
++ }
++ else if (StrEquals(opt, "FlickeringQtDialogsWorkaround"))
++ {
++ switch (toggle)
++ {
++ case -1:
++
Scr.bo.do_enable_flickering_qt_dialogs_workaround ^= 1;
++ break;
++ case 0:
++ case 1:
++
Scr.bo.do_enable_flickering_qt_dialogs_workaround = toggle;
++ break;
++ default:
++
Scr.bo.do_enable_flickering_qt_dialogs_workaround = 0;
++ break;
++ }
++ }
++ else if (EWMH_BugOpts(opt, toggle))
++ {
++ /* work is done in EWMH_BugOpts */
++ }
++ else if (StrEquals(opt, "DisplayNewWindowNames"))
++ {
++ switch (toggle)
++ {
++ case -1:
++ Scr.bo.do_display_new_window_names ^= 1;
++ break;
++ case 0:
++ case 1:
++ Scr.bo.do_display_new_window_names = toggle;
++ break;
++ default:
++ Scr.bo.do_display_new_window_names = 0;
++ break;
++ }
++ }
++ else if (StrEquals(opt, "ExplainWindowPlacement"))
++ {
++ switch (toggle)
++ {
++ case -1:
++ Scr.bo.do_explain_window_placement ^= 1;
++ break;
++ case 0:
++ case 1:
++ Scr.bo.do_explain_window_placement = toggle;
++ break;
++ default:
++ Scr.bo.do_explain_window_placement = 0;
++ break;
++ }
++ }
++ else if (StrEquals(opt, "DebugCRMotionMethod"))
++ {
++ switch (toggle)
++ {
++ case -1:
++ Scr.bo.do_debug_cr_motion_method ^= 1;
++ break;
++ case 0:
++ case 1:
++ Scr.bo.do_debug_cr_motion_method = toggle;
++ break;
++ default:
++ Scr.bo.do_debug_cr_motion_method = 0;
++ break;
++ }
++ }
++ else
++ {
++ fvwm_msg(ERR, "SetBugOptions",
++ "Unknown Bug Option '%s'", opt);
++ }
++ free(opt);
++ }
++
++ return;
++}
++
++void CMD_Emulate(F_CMD_ARGS)
++{
++ char *style;
++
++ style = PeekToken(action, NULL);
++ if (!style || StrEquals(style, "fvwm"))
++ {
++ Scr.gs.do_emulate_mwm = False;
++ Scr.gs.do_emulate_win = False;
++ }
++ else if (StrEquals(style, "mwm"))
++ {
++ Scr.gs.do_emulate_mwm = True;
++ Scr.gs.do_emulate_win = False;
++ }
++ else if (StrEquals(style, "win"))
++ {
++ Scr.gs.do_emulate_mwm = False;
++ Scr.gs.do_emulate_win = True;
++ }
++ else
++ {
++ fvwm_msg(ERR, "Emulate", "Unknown style '%s'", style);
++ return;
++ }
++ Scr.flags.do_need_window_update = 1;
++ Scr.flags.has_default_font_changed = 1;
++ Scr.flags.has_default_color_changed = 1;
++
++ return;
++}
++
++void CMD_ColorLimit(F_CMD_ARGS)
++{
++ fvwm_msg(
++ WARN, "ColorLimit", "ColorLimit is obsolete,\n\tuse the "
++ "fvwm -color-limit option");
++
++ return;
++}
++
++
++/* set animation parameters */
++void CMD_SetAnimation(F_CMD_ARGS)
++{
++ char *opt;
++ int delay;
++ float pct;
++ int i = 0;
++
++ opt = PeekToken(action, &action);
++ if (!opt || sscanf(opt,"%d",&delay) != 1)
++ {
++ fvwm_msg(ERR,"SetAnimation",
++ "Improper milli-second delay as first argument");
++ return;
++ }
++ if (delay > 500)
++ {
++ fvwm_msg(WARN,"SetAnimation",
++ "Using longer than .5 seconds as between frame"
++ " animation delay");
++ }
++ cmsDelayDefault = delay;
++ for (opt = PeekToken(action, &action); opt;
++ opt = PeekToken(action, &action))
++ {
++ if (sscanf(opt,"%f",&pct) != 1)
++ {
++ fvwm_msg(ERR,"SetAnimation",
++ "Use fractional values ending in 1.0 as args"
++ " 2 and on");
++ return;
++ }
++ rgpctMovementDefault[i++] = pct;
++ }
++ /* No pct entries means don't change them at all */
++ if (i > 0 && rgpctMovementDefault[i-1] != 1.0)
++ {
++ rgpctMovementDefault[i++] = 1.0;
++ }
++
++ return;
++}
++
++/* Determine which modifiers are required with a keycode to make <keysym>.
*/
++static Bool FKeysymToKeycode (Display *dpy, KeySym keysym,
++ unsigned int *keycode, unsigned int *modifiers)
++{
++ int m;
++
++ *keycode = XKeysymToKeycode(dpy, keysym);
++ *modifiers = 0;
++
++ for (m = 0; m <= 8; ++m)
++ {
++ KeySym ks = XKeycodeToKeysym(dpy, *keycode, m);
++ if (ks == keysym)
++ {
++ switch (m)
++ {
++ case 0: /* No modifiers */
++ break;
++ case 1: /* Shift modifier */
++ *modifiers |= ShiftMask;
++ break;
++ default:
++ fvwm_msg(ERR, "FKeysymToKeycode",
++ "Unhandled modifier %d", m);
++ break;
++ }
++ return True;
++ }
++ }
++ return False;
++}
++
++static void __fake_event(F_CMD_ARGS, FakeEventType type)
++{
++ char *token;
++ char *optlist[] = {
++ "press", "p",
++ "release", "r",
++ "wait", "w",
++ "modifiers", "m",
++ "depth", "d",
++ NULL
++ };
++ unsigned int mask = 0;
++ Window root = Scr.Root;
++ int maxdepth = 0;
++ static char args[128];
++ strncpy(args, action, sizeof(args) - 1);
++
++ /* get the mask of pressed/released buttons/keys */
++ FQueryPointer(
++ dpy, Scr.Root, &root, &JunkRoot, &JunkX, &JunkY, &JunkX,
++ &JunkY, &mask);
++
++ token = PeekToken(action, &action);
++ while (token && action)
++ {
++ int index = GetTokenIndex(token, optlist, 0, NULL);
++ int val, depth;
++ XEvent e;
++ Window w;
++ Window child_w;
++ int x = 0;
++ int y = 0;
++ int rx = 0;
++ int ry = 0;
++ Bool do_unset;
++ long add_mask = 0;
++ KeySym keysym = NoSymbol;
++
++ XFlush(dpy);
++ do_unset = True;
++ switch (index)
++ {
++ case 0:
++ case 1:
++ do_unset = False;
++ /* fall through */
++ case 2:
++ case 3:
++ /* key/button press or release */
++ if (type == FakeMouseEvent)
++ {
++ if ((GetIntegerArguments(
++ action, &action, &val, 1) != 1)
||
++ val < 1 ||
++ val > NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
++ {
++ fvwm_msg(
++ ERR, "__fake_event",
++ "Invalid button specifier in"
++ " \"%s\" for FakeClick.",
args);
++ return; /* error */
++ }
++ }
++ else /* type == FakeKeyEvent */
++ {
++ char *key = PeekToken(action, &action);
++ if (key == NULL)
++ {
++ fvwm_msg(
++ ERR, "__fake_event",
++ "No keysym specifier in
\"%s\""
++ " for FakeKeypress.", args);
++ return;
++ }
++
++ /* Do *NOT* use FvwmStringToKeysym() as it is
++ * case insensitive. */
++ keysym = XStringToKeysym(key);
++ if (keysym == NoSymbol)
++ {
++ fvwm_msg(
++ ERR, "__fake_event",
++ "Invalid keysym specifier
(%s)"
++ " in \"%s\" for
FakeKeypress.",
++ key, args);
++ return;
++ }
++ }
++
++ w = None;
++ child_w = root;
++ for (depth = 1;
++ depth != maxdepth &&
++ w != child_w && child_w != None;
++ depth++)
++ {
++ w = child_w;
++ if (FQueryPointer(
++ dpy, w, &root, &child_w,
++ &rx, &ry, &x, &y,
++ &JunkMask) == False)
++ {
++ /* pointer is on a different
++ * screen - that's okay here */
++ }
++ }
++
++ if (type == FakeMouseEvent)
++ {
++ e.type = (do_unset) ?
++ ButtonRelease : ButtonPress;
++ e.xbutton.display = dpy;
++ e.xbutton.window = w;
++ e.xbutton.subwindow = None;
++ e.xbutton.root = root;
++ e.xbutton.time = fev_get_evtime();
++ e.xbutton.x = x;
++ e.xbutton.y = y;
++ e.xbutton.x_root = rx;
++ e.xbutton.y_root = ry;
++ e.xbutton.button = val;
++ e.xbutton.state = mask;
++ e.xbutton.same_screen = (Scr.Root == root);
++ /* SS: I think this mask handling code is
++ * buggy.
++ * The value of <mask> is overridden during a
++ * "wait" operation. Also why are we only
using
++ * Button1Mask? What if the user has requested
++ * a FakeClick using some other button? */
++ /* DV: Button1Mask is actually a bit.
Shifting
++ * it by (val -1) bits to the left gives
++ * Button2Mask, Button3Mask etc. */
++ if (do_unset)
++ {
++ mask &= ~(Button1Mask << (val - 1));
++ }
++ else
++ {
++ mask |= (Button1Mask << (val - 1));
++ }
++ add_mask = (do_unset) ?
++ ButtonPressMask : ButtonReleaseMask;
++ }
++ else
++ {
++ /* type == FakeKeyEvent */
++ e.type = (do_unset ? KeyRelease : KeyPress);
++ e.xkey.display = dpy;
++ e.xkey.subwindow = None;
++ e.xkey.root = root;
++ e.xkey.time = fev_get_evtime();
++ e.xkey.x = x;
++ e.xkey.y = y;
++ e.xkey.x_root = rx;
++ e.xkey.y_root = ry;
++ e.xkey.same_screen = (Scr.Root == root);
++
++ w = e.xkey.window = exc->w.w;
++
++ if (FKeysymToKeycode(
++ dpy, keysym, &(e.xkey.keycode),
++ &(e.xkey.state)) != True)
++ {
++ fvwm_msg(DBG, "__fake_event",
++ "FKeysymToKeycode failed");
++ return;
++ }
++ e.xkey.state |= mask;
++ add_mask = (do_unset) ?
++ KeyReleaseMask : KeyPressMask;
++ }
++ FSendEvent(dpy, w, True,
++ SubstructureNotifyMask | add_mask, &e);
++ XFlush(dpy);
++ break;
++ case 4:
++ case 5:
++ /* wait */
++ if ((GetIntegerArguments(
++ action, &action, &val, 1) != 1) ||
++ val <= 0 || val > 1000000)
++ {
++ fvwm_msg(ERR, "__fake_event",
++ "Invalid wait value in \"%s\"", args);
++ return;
++ }
++
++ usleep(1000 * val);
++ if (FQueryPointer(
++ dpy, Scr.Root, &root, &JunkRoot,
++ &JunkX, &JunkY, &JunkX, &JunkY,
++ &mask) == False)
++ {
++ /* pointer is on a different screen -
++ * that's okay here */
++ }
++ break;
++ case 6:
++ case 7:
++ /* set modifier */
++ if (GetIntegerArguments(action, &action, &val, 1) !=
1)
++ {
++ fvwm_msg(
++ ERR, "__fake_event",
++ "Invalid modifier value in \"%s\"",
++ args);
++ return;
++ }
++ do_unset = False;
++ if (val < 0)
++ {
++ do_unset = True;
++ val = -val;
++ }
++ if (val == 6)
++ {
++ val = ShiftMask;
++ }
++ else if (val == 7)
++ {
++ val = LockMask;
++ }
++ else if (val == 8)
++ {
++ val = ControlMask;
++ }
++ else if (val >=1 && val <= 5)
++ {
++ val = (Mod1Mask << (val - 1));
++ }
++ else
++ {
++ /* error */
++ return;
++ }
++ /* SS: Could be buggy if a "modifier" operation
++ * preceeds a "wait" operation. */
++ if (do_unset)
++ {
++ mask &= ~val;
++ }
++ else
++ {
++ mask |= val;
++ }
++ break;
++ case 8:
++ case 9:
++ /* new max depth */
++ if (GetIntegerArguments(action, &action, &val, 1) !=
1)
++ {
++ fvwm_msg(ERR, "__fake_event",
++ "Invalid depth value in \"%s\"",
args);
++ return;
++ }
++ maxdepth = val;
++ break;
++ default:
++ fvwm_msg(ERR, "__fake_event",
++ "Invalid command (%s) in \"%s\"", token,
args);
++ return;
++ }
++ if (action)
++ {
++ token = PeekToken(action, &action);
++ }
++ }
++
++ return;
++}
++
++void CMD_FakeClick(F_CMD_ARGS)
++{
++ __fake_event(F_PASS_ARGS, FakeMouseEvent);
++
++ return;
++}
++
++void CMD_FakeKeypress(F_CMD_ARGS)
++{
++ __fake_event(F_PASS_ARGS, FakeKeyEvent);
++
++ return;
++}
++
++/* A function to handle stroke (olicha Nov 11, 1999) */
++#ifdef HAVE_STROKE
++void CMD_StrokeFunc(F_CMD_ARGS)
++{
++ int finished = 0;
++ int abort = 0;
++ int modifiers = exc->x.etrigger->xbutton.state;
++ int start_event_type = exc->x.etrigger->type;
++ char sequence[STROKE_MAX_SEQUENCE + 1];
++ char *stroke_action, *name;
++ char *opt = NULL;
++ Bool finish_on_release = True;
++ KeySym keysym;
++ Bool restore_repeat = False;
++ Bool echo_sequence = False;
++ Bool draw_motion = False;
++ int i = 0;
++ int *x = NULL;
++ int *y = NULL;
++ const int STROKE_CHUNK_SIZE = 0xff;
++ int coords_size = STROKE_CHUNK_SIZE;
++ Window JunkRoot, JunkChild;
++ int JunkX, JunkY;
++ int tmpx, tmpy;
++ unsigned int JunkMask;
++ Bool feed_back = False;
++ int stroke_width = 1;
++ XEvent e;
++ XClassHint *class;
++
++
++
++ if (!GrabEm(CRS_STROKE, GRAB_NORMAL))
++ {
++ XBell(dpy, 0);
++ return;
++ }
++ x = (int*)safemalloc(coords_size * sizeof(int));
++ y = (int*)safemalloc(coords_size * sizeof(int));
++ e = *exc->x.etrigger;
++ /* set the default option */
++ if (e.type == KeyPress || e.type == ButtonPress)
++ {
++ finish_on_release = True;
++ }
++ else
++ {
++ finish_on_release = False;
++ }
++
++ /* parse the option */
++ for (action = GetNextSimpleOption(action, &opt); opt;
++ action = GetNextSimpleOption(action, &opt))
++ {
++ if (StrEquals("NotStayPressed",opt))
++ {
++ finish_on_release = False;
++ }
++ else if (StrEquals("EchoSequence",opt))
++ {
++ echo_sequence = True;
++ }
++ else if (StrEquals("DrawMotion",opt))
++ {
++ draw_motion = True;
++ }
++ else if (StrEquals("FeedBack",opt))
++ {
++ feed_back = True;
++ }
++ else if (StrEquals("StrokeWidth",opt))
++ {
++ /* stroke width takes a positive integer argument */
++ if (opt)
++ {
++ free(opt);
++ }
++ action = GetNextToken(action, &opt);
++ if (!opt)
++ {
++ fvwm_msg(
++ WARN, "StrokeWidth",
++ "needs an integer argument");
++ }
++ /* we allow stroke_width == 0 which means drawing a
++ * `fast' line of width 1; the upper level of 100 is
++ * arbitrary */
++ else if (!sscanf(opt, "%d", &stroke_width) ||
++ stroke_width < 0 || stroke_width > 100)
++ {
++ fvwm_msg(
++ WARN, "StrokeWidth",
++ "Bad integer argument %d",
++ stroke_width);
++ stroke_width = 1;
++ }
++ }
++ else
++ {
++ fvwm_msg(WARN,"StrokeFunc","Unknown option %s", opt);
++ }
++ if (opt)
++ {
++ free(opt);
++ }
++ }
++ if (opt)
++ {
++ free(opt);
++ }
++
++ /* Force auto repeat off and grab the Keyboard to get proper
++ * KeyRelease events if we need it.
++ * Some computers do not support KeyRelease events, can we
++ * check this here ? No ? */
++ if (start_event_type == KeyPress && finish_on_release)
++ {
++ XKeyboardState kstate;
++
++ XGetKeyboardControl(dpy, &kstate);
++ if (kstate.global_auto_repeat == AutoRepeatModeOn)
++ {
++ XAutoRepeatOff(dpy);
++ restore_repeat = True;
++ }
++ MyXGrabKeyboard(dpy);
++ }
++
++ /* be ready to get a stroke sequence */
++ stroke_init();
++
++ if (draw_motion)
++ {
++ MyXGrabServer(dpy);
++ if (FQueryPointer(
++ dpy, Scr.Root, &JunkRoot, &JunkChild, &x[0],
&y[0],
++ &JunkX, &JunkY, &JunkMask) == False)
++ {
++ /* pointer is on a different screen */
++ x[0] = 0;
++ y[0] = 0;
++ }
++ XSetLineAttributes(
++
dpy,Scr.XorGC,stroke_width,LineSolid,CapButt,JoinMiter);
++ }
++
++ while (!finished && !abort)
++ {
++ /* block until there is an event */
++ FMaskEvent(
++ dpy, ButtonPressMask | ButtonReleaseMask |
++ KeyPressMask | KeyReleaseMask | ButtonMotionMask |
++ PointerMotionMask, &e);
++ switch (e.type)
++ {
++ case MotionNotify:
++ if (e.xmotion.same_screen == False)
++ {
++ continue;
++ }
++ if (e.xany.window != Scr.Root)
++ {
++ if (FQueryPointer(
++ dpy, Scr.Root, &JunkRoot,
++ &JunkChild, &tmpx, &tmpy, &JunkX,
++ &JunkY, &JunkMask) == False)
++ {
++ /* pointer is on a different screen */
++ tmpx = 0;
++ tmpy = 0;
++ }
++ }
++ else
++ {
++ tmpx = e.xmotion.x;
++ tmpy = e.xmotion.y;
++ }
++ stroke_record(tmpx,tmpy);
++ if (draw_motion && (x[i] != tmpx || y[i] != tmpy))
++ {
++ i++;
++ if (i >= coords_size)
++ {
++ coords_size += STROKE_CHUNK_SIZE;
++ x = (int*)saferealloc(
++ (void *)x, coords_size *
++ sizeof(int));
++ y = (int*)saferealloc(
++ (void *)y, coords_size *
++ sizeof(int));
++ }
++ x[i] = tmpx;
++ y[i] = tmpy;
++ XDrawLine(
++ dpy, Scr.Root, Scr.XorGC, x[i-1],
++ y[i-1], x[i], y[i]);
++ }
++ break;
++ case ButtonRelease:
++ if (finish_on_release && start_event_type ==
++ ButtonPress)
++ {
++ finished = 1;
++ }
++ break;
++ case KeyRelease:
++ if (finish_on_release && start_event_type ==
KeyPress)
++ {
++ finished = 1;
++ }
++ break;
++ case KeyPress:
++ keysym = XLookupKeysym(&e.xkey, 0);
++ /* abort if Escape or Delete is pressed (as in
menus.c)
++ */
++ if (keysym == XK_Escape || keysym == XK_Delete ||
++ keysym == XK_KP_Separator)
++ {
++ abort = 1;
++ }
++ /* finish on enter or space (as in menus.c) */
++ if (keysym == XK_Return || keysym == XK_KP_Enter ||
++ keysym == XK_space)
++ {
++ finished = 1;
++ }
++ break;
++ case ButtonPress:
++ if (!finish_on_release)
++ {
++ finished = 1;
++ }
++ break;
++ default:
++ break;
++ }
++ }
++
++ if (draw_motion)
++ {
++ while (i > 0)
++ {
++ XDrawLine(
++ dpy, Scr.Root, Scr.XorGC, x[i-1], y[i-1],
x[i],
++ y[i]);
++ i--;
++ }
++
XSetLineAttributes(dpy,Scr.XorGC,0,LineSolid,CapButt,JoinMiter);
++ MyXUngrabServer(dpy);
++ }
++ if (x != NULL)
++ {
++ free(x);
++ free(y);
++ }
++ if (start_event_type == KeyPress && finish_on_release)
++ {
++ MyXUngrabKeyboard(dpy);
++ }
++ UngrabEm(GRAB_NORMAL);
++ if (restore_repeat)
++ {
++ XAutoRepeatOn(dpy);
++ }
++
++ /* get the stroke sequence */
++ stroke_trans(sequence);
++
++ if (echo_sequence)
++ {
++ char num_seq[STROKE_MAX_SEQUENCE + 1];
++
++ for (i = 0; sequence[i] != '\0';i++)
++ {
++ /* Telephone to numeric pad */
++ if ('7' <= sequence[i] && sequence[i] <= '9')
++ {
++ num_seq[i] = sequence[i]-6;
++ }
++ else if ('1' <= sequence[i] && sequence[i] <= '3')
++ {
++ num_seq[i] = sequence[i]+6;
++ }
++ else
++ {
++ num_seq[i] = sequence[i];
++ }
++ }
++ num_seq[i++] = '\0';
++ fvwm_msg(INFO, "StrokeFunc", "stroke sequence: %s (N%s)",
++ sequence, num_seq);
++ }
++ if (abort)
++ {
++ return;
++ }
++ if (exc->w.fw == NULL)
++ {
++ class = NULL;
++ name = NULL;
++ }
++ else
++ {
++ class = &exc->w.fw->class;
++ name = exc->w.fw->name.name;
++ }
++ /* check for a binding */
++ stroke_action = CheckBinding(
++ Scr.AllBindings, sequence, 0, modifiers, GetUnusedModifiers(),
++ exc->w.wcontext, BIND_STROKE, class, name);
++
++ /* execute the action */
++ if (stroke_action != NULL)
++ {
++ const exec_context_t *exc2;
++ exec_context_changes_t ecc;
++
++ if (feed_back && atoi(sequence) != 0)
++ {
++ GrabEm(CRS_WAIT, GRAB_BUSY);
++ usleep(200000);
++ UngrabEm(GRAB_BUSY);
++ }
++ ecc.x.etrigger = &e;
++ exc2 = exc_clone_context(exc, &ecc, ECC_ETRIGGER);
++ execute_function(cond_rc, exc2, stroke_action, 0);
++ exc_destroy_context(exc2);
++ }
++
++ return;
++}
++#endif /* HAVE_STROKE */
++
++void CMD_State(F_CMD_ARGS)
++{
++ unsigned int state;
++ int toggle;
++ int n;
++ FvwmWindow * const fw = exc->w.fw;
++
++ n = GetIntegerArguments(action, &action, (int *)&state, 1);
++ if (n <= 0)
++ {
++ return;
++ }
++ if (state < 0 || state > 31)
++ {
++ fvwm_msg(ERR, "CMD_State", "Illegal state %d\n", state);
++ return;
++ }
++ toggle = ParseToggleArgument(action, NULL, -1, 0);
++ state = (1 << state);
++ switch (toggle)
++ {
++ case -1:
++ TOGGLE_USER_STATES(fw, state);
++ break;
++ case 0:
++ CLEAR_USER_STATES(fw, state);
++ break;
++ case 1:
++ default:
++ SET_USER_STATES(fw, state);
++ break;
++ }
++
++ return;
++}
+diff -U10 -Naupr fvwm-2.5.21-10/fvwm/menus.c fvwm-2.5.21-11/fvwm/menus.c
+--- fvwm-2.5.21-10/fvwm/menus.c 2007-03-03 13:20:40.000000000 +0100
++++ fvwm-2.5.21-11/fvwm/menus.c 2007-03-03 13:21:03.000000000 +0100
+@@ -2429,20 +2429,55 @@ static Bool paint_menu_gradient_backgrou
+ XFreeGC(dpy, pmapgc);
+ XFreePixmap(dpy, pmap);
+ MR_IS_BACKGROUND_SET(mr) = True;
+ }
+ do_clear = True;
+ break;
+ }
+ return do_clear;
+ }
+
++#define DRAWMENUBORDER(NUM, XX, YY) XCopyArea(\
++ dpy, pm[(NUM)]->picture, MR_WINDOW(mr), Scr.TransMaskGC,\
++ 0, 0, pm[(NUM)]->width, pm[(NUM)]->height, (XX), (YY))
++static Bool paint_menu_multipixmap_background(
++ MenuRoot *mr, XEvent *pevent)
++{
++ MenuStyle *ms = MR_STYLE(mr);
++ int width, height, x, y;
++ int bw = MST_BORDER_WIDTH(mr);
++ FvwmPicture **pm;
++ pm = ST_FACE(ms).u.mb.pixmaps;
++
++ width = MR_WIDTH(mr);
++ height = MR_HEIGHT(mr);
++
++ FvwmPicture *p = pm[0];
++
++ width = MR_WIDTH(mr);
++ height = MR_HEIGHT(mr);
++
++ x = 0;
++
++ for (x = 0; x < width; x+=pm[1]->width) DRAWMENUBORDER(1, x, 0);
++ for (x = 0; x < width; x+=pm[5]->width) DRAWMENUBORDER(5, x,
height-pm[5]->height);
++ for (x = 0; x < height; x+=pm[3]->height) DRAWMENUBORDER(3,
width-pm[3]->height, x);
++ for (x = 0; x < height; x+=pm[7]->height) DRAWMENUBORDER(7, 0, x);
++
++ DRAWMENUBORDER(0, 0, 0);
++ DRAWMENUBORDER(2, width-pm[2]->width, 0);
++ DRAWMENUBORDER(4, width-pm[4]->width, height-pm[4]->height);
++ DRAWMENUBORDER(6, 0, height-pm[6]->height);
++
++ return False;
++}
++
+ 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;
+@@ -2533,29 +2568,34 @@ static void paint_menu(
+ 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);
++ if (ms && ST_FACE(ms).type == MultiPixmapMenu)
+ {
+- return;
++ paint_menu_multipixmap_background(mr, pevent);
+ }
++ else
++ {
++ 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)],
+@@ -2576,37 +2616,43 @@ static void paint_menu(
+ 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 MultiPixmapMenu:
++ do_clear = paint_menu_multipixmap_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);
++ if (!(ms && ST_FACE(ms).type == MultiPixmapMenu))
++ {
++ 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;
+diff -U10 -Naupr fvwm-2.5.21-10/fvwm/menus.c~ fvwm-2.5.21-11/fvwm/menus.c~
+--- fvwm-2.5.21-10/fvwm/menus.c~ 2007-03-03 13:20:40.000000000 +0100
++++ fvwm-2.5.21-11/fvwm/menus.c~ 2007-03-03 13:20:56.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-10/fvwm/menustyle.c
fvwm-2.5.21-11/fvwm/menustyle.c
+--- fvwm-2.5.21-10/fvwm/menustyle.c 2007-03-03 13:20:40.000000000 +0100
++++ fvwm-2.5.21-11/fvwm/menustyle.c 2007-03-03 13:21:03.000000000 +0100
+@@ -146,20 +146,22 @@ static void menustyle_copy_face(MenuFace
+ *
+ * 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;
++ FvwmPicture **pm;
++ int x, y;
+
+ s = GetNextToken(s, &style);
+ if (style && strncasecmp(style, "--", 2) == 0)
+ {
+ free(style);
+ return True;
+ }
+
+ menustyle_free_face(mf);
+ mf->type = SimpleMenu;
+@@ -257,20 +259,72 @@ static Boolean menustyle_parse_face(char
+ if (verbose)
+ {
+ fvwm_msg(ERR, "menustyle_parse_face",
+ "missing pixmap name for style %s",
+ style);
+ }
+ free(style);
+ return False;
+ }
+ }
++ else if (StrEquals(style,"MultiBorder"))
++ {
++ fpa.mask = (Pdepth <= 8)? FPAM_DITHER:0;
++ pm = mf->u.mb.pixmaps;
++
++ for (x = 0; x < 8; x++)
++ {
++ if (pm[x])
++ {
++ PDestroyFvwmPicture(dpy, pm[x]);
++ }
++ s = GetNextToken(s, &token);
++ if (token)
++ {
++ pm[x] = PCacheFvwmPicture(dpy,
Scr.NoFocusWin, NULL, token, fpa);
++ if (!pm[x])
++ {
++ fvwm_msg(ERR,
++ "menustyle_parse_face",
"Pixmap '%s' could not be loaded",
++ token);
++ }
++ }
++ else
++ {
++ fvwm_msg(ERR,
++ "menustyle_parse_face", "Too few
parameters for MultiBorder");
++ }
++ if (!token || !pm[x])
++ {
++ for (y = 0; y < x; y++)
++ {
++ if (pm[y])
++ {
++ PDestroyFvwmPicture(dpy,
pm[y]);
++ pm[y] = 0;
++ }
++ }
++ free(style);
++ if (token)
++ {
++ free(token);
++ }
++ if (mf->type == MultiPixmapMenu)
++ {
++ mf->type = SimpleMenu;
++ }
++ return False;
++ }
++ mf->type = MultiPixmapMenu;
++ free(token);
++ }
++ }
+ else
+ {
+ if (verbose)
+ {
+ fvwm_msg(
+ ERR,
+ "menustyle_parse_face", "unknown style %s:
%s",
+ style, action);
+ }
+ free(style);
+diff -U10 -Naupr fvwm-2.5.21-10/fvwm/menustyle.h
fvwm-2.5.21-11/fvwm/menustyle.h
+--- fvwm-2.5.21-10/fvwm/menustyle.h 2007-03-03 13:20:40.000000000 +0100
++++ fvwm-2.5.21-11/fvwm/menustyle.h 2007-03-03 13:21:03.000000000 +0100
+@@ -182,20 +182,21 @@
+
+ /* ---------------------------- type definitions
--------------------------- */
+
+ typedef enum
+ {
+ /* menu types */
+ SimpleMenu = 0,
+ GradientMenu,
+ PixmapMenu,
+ TiledPixmapMenu,
++ MultiPixmapMenu,
+ SolidMenu
+ /* max button is 8 (0x8) */
+ } MenuFaceType;
+
+ typedef enum
+ {
+ MDP_POST_MENU = 0,
+ MDP_ROOT_MENU = 1,
+ MDP_IGNORE = 2,
+ MDP_CLOSE = 3
+@@ -231,20 +232,23 @@ typedef struct MenuFeel
+ int PopupDelay10ms;
+ int DoubleClickTime;
+ char *item_format;
+ KeyCode select_on_release_key;
+ } MenuFeel;
+
+ typedef struct MenuFace
+ {
+ union
+ {
++ struct {
++ FvwmPicture *pixmaps[8];
++ } mb;
+ FvwmPicture *p;
+ Pixel back;
+ struct
+ {
+ int npixels;
+ XColor *xcs;
+ Bool do_dither;
+ } grad;
+ } u;
+ MenuFaceType type;
+diff -U10 -Naupr fvwm-2.5.21-10/fvwm/screen.h fvwm-2.5.21-11/fvwm/screen.h
+--- fvwm-2.5.21-10/fvwm/screen.h 2007-03-03 13:20:47.000000000 +0100
++++ fvwm-2.5.21-11/fvwm/screen.h 2007-03-03 13:21:03.000000000 +0100
+@@ -92,20 +92,21 @@ typedef enum
+ DefaultVectorButton,
+ VectorButton,
+ SimpleButton,
+ GradientButton,
+ PixmapButton,
+ TiledPixmapButton,
+ StretchedPixmapButton,
+ AdjustedPixmapButton,
+ ShrunkPixmapButton,
+ MultiPixmap,
++ MultiBorder,
+ MiniIconButton,
+ SolidButton,
+ ColorsetButton
+ } DecorFaceType;
+
+ typedef enum
+ {
+ JUST_CENTER = 0,
+ JUST_LEFT = 1,
+ JUST_TOP = 1,
+@@ -151,20 +152,23 @@ typedef struct DecorFace
+ struct
+ {
+ FvwmPicture *p;
+ struct {
+ FvwmPicture **pixmaps;
+ unsigned short stretch_flags;
+ FvwmAcs *acs;
+ Pixel *pixels;
+ unsigned short solid_flags;
+ } mp;
++ struct {
++ FvwmPicture *pixmaps[8];
++ } mb;
+ struct
+ {
+ int cs;
+ int alpha_percent;
+ } acs;
+ Pixel back;
+ struct
+ {
+ int npixels;
+ XColor *xcs;
diff --git a/windowmanagers/fvwm/patches/12-Hover.patch
b/windowmanagers/fvwm/patches/12-Hover.patch
new file mode 100644
index 0000000..ca2b3ef
--- /dev/null
+++ b/windowmanagers/fvwm/patches/12-Hover.patch
@@ -0,0 +1,5549 @@
+diff -U10 -Naupr fvwm-2.5.21-11/fvwm/borders.c fvwm-2.5.21-12/fvwm/borders.c
+--- fvwm-2.5.21-11/fvwm/borders.c 2007-03-03 13:23:02.000000000 +0100
++++ fvwm-2.5.21-12/fvwm/borders.c 2007-03-03 13:23:23.000000000 +0100
+@@ -58,20 +58,21 @@
+
+ /* ---------------------------- local definitions
-------------------------- */
+
+ /* ---------------------------- local macros
------------------------------- */
+
+ #define SWAP_ARGS(f,a1,a2) (f)?(a2):(a1),(f)?(a1):(a2)
+
+ /* ---------------------------- imports
------------------------------------ */
+
+ extern Window PressedW;
++extern Window HoverW;
+
+ /* ---------------------------- included code files
------------------------ */
+
+ /* ---------------------------- local types
-------------------------------- */
+
+ typedef struct
+ {
+ struct
+ {
+ unsigned use_pixmap : 1;
+@@ -178,20 +179,21 @@ typedef struct
+ } 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;
++ unsigned hover_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;
+@@ -283,22 +285,26 @@ static Bool is_button_toggled(
+ {
+ 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)
++ int is_pressed, int is_lit, int is_toggled, int is_hover)
+ {
++ if (is_lit && is_hover && Scr.gs.use_hover_buttons)
++ {
++ return BS_ActiveHover;
++ }
+ 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) ?
+@@ -582,21 +588,21 @@ static window_parts border_get_tb_parts_
+ 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);
++ (fw->decor_state.parts_lit & PART_TITLE), 0, 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;
+@@ -606,21 +612,22 @@ static window_parts border_get_tb_parts_
+ {
+ 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));
++ (fw->decor_state.buttons_toggled & mask),
++ (fw->decor_state.buttons_hover & 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 &&
+@@ -3999,20 +4006,21 @@ static void border_draw_buttons(
+ 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;
++ fw->decor_state.buttons_hover = td->tbstate.hover_bmask;
+
+ return;
+ }
+
+ static void border_setup_use_title_style(
+ FvwmWindow *fw, titlebar_descr *td)
+ {
+ int i;
+ DecorFace *df, *tsdf;
+ ButtonState bs, tsbs;
+@@ -4267,27 +4275,32 @@ static void border_get_titlebar_descr_st
+ 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;
+ }
++ if (FW_W_BUTTON(fw, i) == HoverW)
++ {
++ tbstate->hover_bmask |= mask;
++ }
+ tbstate->bstate[i] = border_flags_to_button_state(
+ tbstate->pressed_bmask & mask,
+ tbstate->lit_bmask & mask,
+- tbstate->toggled_bmask & mask);
++ tbstate->toggled_bmask & mask,
++ tbstate->hover_bmask & mask);
+ }
+ tbstate->tstate = border_flags_to_button_state(
+- tbstate->is_title_pressed, tbstate->is_title_lit, 0);
++ tbstate->is_title_pressed, tbstate->is_title_lit, 0, 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;
+@@ -4538,20 +4551,21 @@ static void border_draw_titlebar(
+ 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;
++ fw->decor_state.buttons_hover = 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 */
+@@ -4589,20 +4603,21 @@ static void border_draw_titlebar(
+ 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;
++ fw->decor_state.buttons_hover &= td.tbstate.hover_bmask;
+ }
+
+ return;
+ }
+
+ /*
+ *
+ * Redraws the windows borders
+ *
+ */
+@@ -4679,39 +4694,41 @@ DecorFace *border_get_border_style(
+
+ return df;
+ }
+
+ int border_is_using_border_style(
+ FvwmWindow *fw, Bool has_focus)
+ {
+ ButtonState bs;
+ int is_pressed;
+ int is_toggled;
++ int is_hover;
+ int i;
+
+ /* title */
+ is_pressed = (FW_W_TITLE(fw) == PressedW);
+- bs = border_flags_to_button_state(is_pressed, has_focus, 0);
++ bs = border_flags_to_button_state(is_pressed, has_focus, 0, 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);
++ is_hover = (FW_W_BUTTON(fw, i) == HoverW);
+ bs = border_flags_to_button_state(
+- is_pressed, (has_focus == True), is_toggled);
++ is_pressed, (has_focus == True), is_toggled,
is_hover);
+ if (DFS_USE_BORDER_STYLE(
+ TB_STATE(GetDecor(fw, buttons[i]))[bs].style))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+@@ -5158,20 +5175,21 @@ void CMD_ButtonState(F_CMD_ARGS)
+ {
+ 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;
++ Scr.gs.use_hover_buttons = 0;
+ 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))
+@@ -5179,28 +5197,35 @@ void CMD_ButtonState(F_CMD_ARGS)
+ 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 if (StrEquals("hover", token))
++ {
++ Scr.gs.use_hover_buttons = ParseToggleArgument(
++ action, &action,
++ 0, 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;
++ Scr.gs.use_hover_buttons = 0;
+ fvwm_msg(ERR, "cmd_button_state",
+ "Unknown button state %s", token);
+ return;
+ }
+ }
+
+ return;
+ }
+
+ /*
+diff -U10 -Naupr fvwm-2.5.21-11/fvwm/borders.c~
fvwm-2.5.21-12/fvwm/borders.c~
+--- fvwm-2.5.21-11/fvwm/borders.c~ 2007-03-03 13:20:56.000000000 +0100
++++ fvwm-2.5.21-12/fvwm/borders.c~ 2007-03-03 13:23:14.000000000 +0100
+@@ -1272,20 +1272,21 @@ static void border_fill_pixmap_backgroun
+ 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);
+@@ -1462,25 +1463,38 @@ static void border_get_frame_pixmap(
+ 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)
++ rectangle *part_g, rectangle *relative_g, int *free_bg_pixmap, Window
w, FvwmPicture *fp)
+ {
+ *free_bg_pixmap = False;
+
+- if (cd->texture_pixmap)
++ if (fp)
++ {
++ bg->flags.use_pixmap = 1;
++ bg->pixmap.p = fp->picture;
++ bg->pixmap.g.width = fp->width;
++ bg->pixmap.g.height = fp->height;
++ bg->pixmap.shape = None;
++ bg->pixmap.alpha = None;
++ bg->pixmap.depth = fp->depth;
++ bg->pixmap.flags.is_tiled = 1;
++ bg->pixmap.flags.is_stretched = 0;
++ bg->pixmap.fra.mask = 0;
++ }
++ else 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;
+@@ -1534,47 +1548,80 @@ static void border_get_border_background
+ }
+ else
+ {
+ bg->flags.use_pixmap = 0;
+ bg->pixel = cd->attributes.background_pixel;
+ }
+
+ return;
+ }
+
++#define DRAWBORDER(PIX,X,Y,WIDTH,HEIGHT) \
++ { \
++ fp = df->u.mb.pixmaps[PIX]; \
++ border_get_border_background( \
++ &bg, cd, &part_g, &relative_g, &free_bg_pixmap, w,
fp); \
++ r.x = X; \
++ r.y = Y; \
++ r.width = WIDTH; \
++ r.height = HEIGHT; \
++ border_fill_pixmap_background(p, &r, &bg, cd); \
++ }
++
+ 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;
++ int x, y, width, height;
+
+ /* 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);
++
++ DecorFace* df;
++ FvwmPicture* fp = 0;
++ df = border_get_border_style(fw, (Scr.Hilite == fw));
++ if (DFS_FACE_TYPE(df->style) == MultiBorder)
++ {
++ int id = -1;
++ if (part==PART_BORDER_NW) id = 0;
++ if (part==PART_BORDER_N) id = 1;
++ if (part==PART_BORDER_NE) id = 2;
++ if (part==PART_BORDER_E) id = 3;
++ if (part==PART_BORDER_SE) id = 4;
++ if (part==PART_BORDER_S) id = 5;
++ if (part==PART_BORDER_SW) id = 6;
++ if (part==PART_BORDER_W) id = 7;
++
++ if (id>=0 && df->u.mb.pixmaps[id])
++ {
++ fp = df->u.mb.pixmaps[id];
++ }
++ }
++
+ 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;
+@@ -1603,43 +1650,131 @@ static void border_draw_one_border_part(
+ 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);
++
++ border_get_border_background(
++ &bg, cd, &part_g, &relative_g, &free_bg_pixmap, w, fp);
++
++ int px = bg.pixmap.g.x;
++ int py = bg.pixmap.g.y;
++
++ if (fp)
++ {
++ /* Position pixmap so that it's aligned to the edge of the
window */
++ if (part & PART_BOTTOM)
++ {
++ bg.pixmap.g.y = fp->height - sidebar_g->y;
++ if (part == PART_BORDER_S)
++ {
++ bg.pixmap.g.y = fp->height -
fw->boundary_width;
++ }
++ }
++ if (part & PART_RIGHT)
++ {
++ bg.pixmap.g.x = fp->width - sidebar_g->x;
++ if (part == PART_BORDER_E)
++ {
++ bg.pixmap.g.x = fp->width -
fw->boundary_width;
++ }
++ }
++ }
++
++ /* 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);
++
++ bg.pixmap.g.x = px;
++ bg.pixmap.g.y = py;
++
++ if (fp)
++ {
++ height = pix_g.height;
++ width = pix_g.width;
++ x = pix_g.x;
++ y = pix_g.y;
++
++ /* draw parts from other borders that overflow because of
their width/height */
++ rectangle r;
++ if (part==PART_BORDER_S)
++ {
++ DRAWBORDER(6, pix_g.x - sidebar_g->x,
fw->boundary_width - fp->height, fp->width - sidebar_g->x, height);
++ DRAWBORDER(4, pix_g.width - fp->width + sidebar_g->x,
fw->boundary_width - fp->height, fp->width - sidebar_g->x, height);
++ }
++ if (!IS_SHADED(fw))
++ {
++ if (part==PART_BORDER_E)
++ {
++ DRAWBORDER(2, fw->boundary_width - fp->width,
pix_g.y - sidebar_g->y, width, fp->height - sidebar_g->y);
++ DRAWBORDER(4, fw->boundary_width - fp->width,
pix_g.height - fp->height + sidebar_g->y, width, fp->height - sidebar_g->y);
++ }
++ if (part==PART_BORDER_W)
++ {
++ DRAWBORDER(0, x, pix_g.y - sidebar_g->y, width,
fp->height - sidebar_g->y);
++ DRAWBORDER(6, x, pix_g.height - fp->height +
sidebar_g->y, width, fp->height - sidebar_g->y);
++ }
++ }
++ if (part==PART_BORDER_N)
++ {
++ DRAWBORDER(2, pix_g.width - fp->width + sidebar_g->x,
y, fp->width - sidebar_g->x, height);
++ DRAWBORDER(0, pix_g.x - fp->width + sidebar_g->x, y, fp->width
- sidebar_g->x, height);
++ }
++ /* Use the top border for the whole height of the titlebar,
overflowing to parts of the bottom corners if shaded */
++ if (IS_SHADED(fw))
++ {
++ if (part==PART_BORDER_W)
++ {
++ DRAWBORDER(0, 0, -height, width, height);
++ }
++ if (part==PART_BORDER_SW)
++ {
++ DRAWBORDER(0, 0, -height*2, width, height -
fw->boundary_width);
++ }
++ if (part==PART_BORDER_E)
++ {
++ DRAWBORDER(2, fw->boundary_width - fp->width,
-height, width, height);
++ }
++ if (part==PART_BORDER_SE)
++ {
++ DRAWBORDER(2, width - fp->width, -height*2,
width, height - fw->boundary_width);
++ }
++ }
++ }
++
+ 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 && !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)
+@@ -1679,21 +1814,21 @@ static void border_draw_all_border_parts
+ {
+ 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,
+@@ -3306,21 +3441,21 @@ static void border_set_button_pixmap(
+ 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, td->cd, button_g, &relative_g, &free_bg_pixmap,
w, 0);
+ 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)
+@@ -3756,21 +3891,21 @@ static void border_set_title_pixmap(
+ 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);
++ &free_bg_pixmap, w, 0);
+ 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);
+diff -U10 -Naupr fvwm-2.5.21-11/fvwm/builtins.c
fvwm-2.5.21-12/fvwm/builtins.c
+--- fvwm-2.5.21-11/fvwm/builtins.c 2007-03-03 13:21:03.000000000 +0100
++++ fvwm-2.5.21-12/fvwm/builtins.c 2007-03-03 13:23:23.000000000 +0100
+@@ -86,40 +86,47 @@ typedef enum {FakeMouseEvent, FakeKeyEve
+
+ /* ---------------------------- local variables
---------------------------- */
+
+ static char *exec_shell_name="/bin/sh";
+
+ /* button state strings must match the enumerated states */
+ static char *button_states[BS_MaxButtonStateName + 1] =
+ {
+ "ActiveUp",
+ "ActiveDown",
++ "ActiveHover",
+ "InactiveUp",
+ "InactiveDown",
++ "InactiveHover",
+ "ToggledActiveUp",
+ "ToggledActiveDown",
++ "ToggledActiveHover",
+ "ToggledInactiveUp",
+ "ToggledInactiveDown",
++ "ToggledInactiveHover",
+ "Active",
+ "Inactive",
+ "ToggledActive",
+ "ToggledInactive",
+ "AllNormal",
+ "AllToggled",
+ "AllActive",
+ "AllInactive",
+ "AllUp",
+ "AllDown",
++ "AllHover",
+ "AllActiveUp",
+ "AllActiveDown",
++ "AllActiveHover",
+ "AllInactiveUp",
+ "AllInactiveDown",
++ "AllInactiveHover",
+ NULL
+ };
+
+ /* ---------------------------- exported variables (globals)
--------------- */
+
+ char *ModulePath = FVWM_MODULEDIR;
+ int moduleTimeout = DEFAULT_MODULE_TIMEOUT;
+
+ /* ---------------------------- local functions
---------------------------- */
+
+diff -U10 -Naupr fvwm-2.5.21-11/fvwm/events.c fvwm-2.5.21-12/fvwm/events.c
+--- fvwm-2.5.21-11/fvwm/events.c 2007-03-03 13:20:56.000000000 +0100
++++ fvwm-2.5.21-12/fvwm/events.c 2007-03-03 13:24:03.000000000 +0100
+@@ -152,20 +152,21 @@ typedef struct
+ static int Button = 0;
+ static const FvwmWindow *xcrossing_last_grab_window = NULL;
+ STROKE_CODE(static int send_motion);
+ STROKE_CODE(static char sequence[STROKE_MAX_SEQUENCE + 1]);
+ static PFEH EventHandlerJumpTable[LASTEvent];
+
+ /* ---------------------------- exported variables (globals)
--------------- */
+
+ int last_event_type = 0;
+ Window PressedW = None;
++Window HoverW = None;
+
+ /* ---------------------------- local functions
---------------------------- */
+
+ static void fake_map_unmap_notify(const FvwmWindow *fw, int event_type)
+ {
+ XEvent client_event;
+ XWindowAttributes winattrs = {0};
+
+ if (!XGetWindowAttributes(dpy, FW_W(fw), &winattrs))
+ {
+@@ -1680,20 +1681,37 @@ static void __refocus_stolen_focus_win(c
+ FOCUS_SET(Scr.StolenFocusWin);
+ ea->exc->x.etrigger->xfocus.window = Scr.StolenFocusWin;
+ ea->exc->x.etrigger->type = FocusIn;
+ Scr.UnknownWinFocused = None;
+ Scr.StolenFocusWin = None;
+ dispatch_event(ea->exc->x.etrigger);
+
+ return;
+ }
+
++static void redraw_hover(FvwmWindow* fw, Window w)
++{
++ if (fw)
++ {
++ int i;
++ for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
++ {
++ if (w == FW_W_BUTTON(fw, i))
++ {
++ HoverW = FW_W_BUTTON(fw, i);
++ }
++ }
++ border_redraw_decorations(fw);
++ HoverW = None;
++ }
++}
++
+ /* ---------------------------- event handlers
----------------------------- */
+
+ void HandleButtonPress(const evh_args_t *ea)
+ {
+ DBUG("HandleButtonPress", "Routine Entered");
+
+ GrabEm(CRS_NONE, GRAB_PASSIVE);
+ if (__is_bpress_window_handled(ea->exc) == False)
+ {
+ __handle_bpress_on_unmanaged(ea->exc);
+@@ -1885,20 +1903,22 @@ void HandleEnterNotify(const evh_args_t
+ FvwmWindow *sf;
+ static Bool is_initial_ungrab_pending = True;
+ Bool is_tear_off_menu;
+ const XEvent *te = ea->exc->x.etrigger;
+ FvwmWindow * const fw = ea->exc->w.fw;
+
+ DBUG("HandleEnterNotify", "Routine Entered");
+ ewp = &te->xcrossing;
+ ENTER_DBG((stderr, "++++++++ en (%d): fw 0x%08x w 0x%08x sw 0x%08xmode 0x%x
detail 0x%x '%s'\n", ++ecount, (int)fw, (int)ewp->window,
(int)ewp->subwindow, ewp->mode, ewp->detail, fw?fw->visible_name:"(none)"));
+
++ redraw_hover(fw, ewp->window);
++
+ if (ewp->window == Scr.Root && ewp->subwindow == None &&
+ ewp->detail == NotifyInferior && ewp->mode == NotifyNormal)
+ {
+ BroadcastPacket(
+ MX_ENTER_WINDOW, 3, (long)Scr.Root, (long)NULL,
+ (long)NULL);
+ }
+ if (Scr.ColormapFocus == COLORMAP_FOLLOWS_MOUSE)
+ {
+ if (fw && !IS_ICONIFIED(fw) && ewp->window == FW_W(fw))
+@@ -2547,20 +2567,22 @@ void HandleKeyRelease(const evh_args_t *
+ __handle_key(ea, False);
+ }
+
+ void HandleLeaveNotify(const evh_args_t *ea)
+ {
+ const XEvent *te = ea->exc->x.etrigger;
+ FvwmWindow * const fw = ea->exc->w.fw;
+
+ DBUG("HandleLeaveNotify", "Routine Entered");
+
++ redraw_hover(fw, te->xcrossing.window);
++
+ ENTER_DBG((stderr, "-------- ln (%d): fw 0x%08x w 0x%08x sw 0x%08x mode
0x%x detail 0x%x '%s'\n", ++ecount, (int)fw, (int)te->xcrossing.window,
(int)te->xcrossing.subwindow, te->xcrossing.mode, te->xcrossing.detail,
fw?fw->visible_name:"(none)"));
+ /* Ignore LeaveNotify events while a window is resized or moved as a
+ * wire frame; otherwise the window list may be screwed up. */
+ if (Scr.flags.is_wire_frame_displayed)
+ {
+ return;
+ }
+ if (te->xcrossing.mode != NotifyNormal)
+ {
+ /* Ignore events generated by grabbing or ungrabbing the
+diff -U10 -Naupr fvwm-2.5.21-11/fvwm/events.c~ fvwm-2.5.21-12/fvwm/events.c~
+--- fvwm-2.5.21-11/fvwm/events.c~ 1970-01-01 01:00:00.000000000 +0100
++++ fvwm-2.5.21-12/fvwm/events.c~ 2007-03-03 13:23:14.000000000 +0100
+@@ -0,0 +1,4578 @@
++/* -*-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"
++
++#if HAVE_SYS_BSDTYPES_H
++#include <sys/bsdtypes.h>
++#endif
++
++#include <stdio.h>
++#include <unistd.h>
++
++#include "libs/ftime.h"
++#include "libs/fvwmlib.h"
++#include "libs/FShape.h"
++#include "libs/PictureBase.h"
++#include "libs/Colorset.h"
++#include "libs/charmap.h"
++#include "libs/wcontext.h"
++#include "fvwm.h"
++#include "externs.h"
++#include "cursor.h"
++#include "functions.h"
++#include "commands.h"
++#include "bindings.h"
++#include "misc.h"
++#include "screen.h"
++#include "events.h"
++#include "eventhandler.h"
++#include "eventmask.h"
++#include "fvwmsignal.h"
++#include "module_list.h"
++#include "module_interface.h"
++#include "session.h"
++#include "borders.h"
++#include "frame.h"
++#include "add_window.h"
++#include "icccm2.h"
++#include "icons.h"
++#include "gnome.h"
++#include "ewmh.h"
++#include "update.h"
++#include "style.h"
++#include "stack.h"
++#include "geometry.h"
++#include "focus.h"
++#include "virtual.h"
++#include "decorations.h"
++#include "schedule.h"
++#include "menus.h"
++#include "colormaps.h"
++#include "colorset.h"
++#ifdef HAVE_STROKE
++#include "stroke.h"
++#endif /* HAVE_STROKE */
++
++/* ---------------------------- local definitions
-------------------------- */
++
++#ifndef XUrgencyHint
++#define XUrgencyHint (1L << 8)
++#endif
++
++/*
++** LASTEvent is the number of X events defined - it should be defined
++** in X.h (to be like 35), but since extension (eg SHAPE) events are
++** numbered beyond LASTEvent, we need to use a bigger number than the
++** default, so let's undefine the default and use 256 instead.
++*/
++#undef LASTEvent
++#define LASTEvent 256
++
++#define CR_MOVERESIZE_MASK (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)
++
++/* ---------------------------- local macros
------------------------------- */
++
++/* ---------------------------- imports
------------------------------------ */
++
++extern void StartupStuff(void);
++
++/* ---------------------------- included code files
------------------------ */
++
++/* ---------------------------- local types
-------------------------------- */
++
++typedef void (*PFEH)(const evh_args_t *ea);
++
++typedef struct
++{
++ Window w;
++ Bool do_return_true;
++ Bool do_return_true_cr;
++ unsigned long cr_value_mask;
++ Bool ret_does_match;
++ unsigned long ret_type;
++} check_if_event_args;
++
++typedef struct
++{
++ unsigned do_forbid_function : 1;
++ unsigned do_focus : 1;
++ unsigned do_swallow_click : 1;
++ unsigned do_raise : 1;
++} hfrc_ret_t;
++
++/* ---------------------------- forward declarations
----------------------- */
++
++/* ---------------------------- local variables
---------------------------- */
++
++static int Button = 0;
++static const FvwmWindow *xcrossing_last_grab_window = NULL;
++STROKE_CODE(static int send_motion);
++STROKE_CODE(static char sequence[STROKE_MAX_SEQUENCE + 1]);
++static PFEH EventHandlerJumpTable[LASTEvent];
++
++/* ---------------------------- exported variables (globals)
--------------- */
++
++int last_event_type = 0;
++Window PressedW = None;
++
++/* ---------------------------- local functions
---------------------------- */
++
++static void fake_map_unmap_notify(const FvwmWindow *fw, int event_type)
++{
++ XEvent client_event;
++ XWindowAttributes winattrs = {0};
++
++ if (!XGetWindowAttributes(dpy, FW_W(fw), &winattrs))
++ {
++ return;
++ }
++ XSelectInput(
++ dpy, FW_W(fw),
++ winattrs.your_event_mask & ~StructureNotifyMask);
++ client_event.type = event_type;
++ client_event.xmap.display = dpy;
++ client_event.xmap.event = FW_W(fw);
++ client_event.xmap.window = FW_W(fw);
++ switch (event_type)
++ {
++ case MapNotify:
++ client_event.xmap.override_redirect = False;
++ break;
++ case UnmapNotify:
++ client_event.xunmap.from_configure = False;
++ break;
++ default:
++ /* not possible if called correctly */
++ break;
++ }
++ FSendEvent(
++ dpy, FW_W(fw), False, StructureNotifyMask, &client_event);
++ XSelectInput(dpy, FW_W(fw), winattrs.your_event_mask);
++ XFlush(dpy);
++
++ return;
++}
++
++static Bool test_map_request(
++ Display *display, XEvent *event, XPointer arg)
++{
++ check_if_event_args *cie_args;
++ Bool rc;
++
++ cie_args = (check_if_event_args *)arg;
++ cie_args->ret_does_match = False;
++ if (event->type == MapRequest &&
++ event->xmaprequest.window == cie_args->w)
++ {
++ cie_args->ret_type = MapRequest;
++ cie_args->ret_does_match = True;
++ rc = cie_args->do_return_true;
++ }
++ else
++ {
++ cie_args->ret_type = 0;
++ rc = False;
++ }
++
++ /* Yes, it is correct that this function always returns False. */
++ return rc;
++}
++
++Bool test_button_event(
++ Display *display, XEvent *event, XPointer arg)
++{
++ if (event->type == ButtonPress || event->type == ButtonRelease)
++ {
++ return True;
++ }
++
++ return False;
++}
++
++Bool test_typed_window_event(
++ Display *display, XEvent *event, XPointer arg)
++{
++ test_typed_window_event_args *ta = (test_typed_window_event_args
*)arg;
++
++ if (event->xany.window == ta->w &&
++ event->xany.type == ta->event_type)
++ {
++ return True;
++ }
++
++ return False;
++}
++
++static Bool test_resizing_event(
++ Display *display, XEvent *event, XPointer arg)
++{
++ check_if_event_args *cie_args;
++ Bool rc;
++
++ cie_args = (check_if_event_args *)arg;
++ cie_args->ret_does_match = False;
++ if (event->xany.window != cie_args->w)
++ {
++ return False;
++ }
++ rc = False;
++ switch (event->type)
++ {
++ case ConfigureRequest:
++ if ((event->xconfigurerequest.value_mask &
++ cie_args->cr_value_mask) != 0)
++ {
++ cie_args->ret_type = ConfigureRequest;
++ cie_args->ret_does_match = True;
++ rc = cie_args->do_return_true_cr;
++ }
++ break;
++ case PropertyNotify:
++ if (event->xproperty.atom == XA_WM_NORMAL_HINTS)
++ {
++ cie_args->ret_type = PropertyNotify;
++ cie_args->ret_does_match = True;
++ rc = cie_args->do_return_true;
++ }
++ default:
++ break;
++ }
++
++ /* Yes, it is correct that this function may always returns False. */
++ return rc;
++}
++
++static inline void __handle_cr_on_unmanaged(XConfigureRequestEvent *cre)
++{
++ XWindowChanges xwc;
++ unsigned long xwcm;
++
++ xwcm = (cre->value_mask & CR_MOVERESIZE_MASK);
++ xwc.x = cre->x;
++ xwc.y = cre->y;
++ xwc.width = cre->width;
++ xwc.height = cre->height;
++ xwc.border_width = cre->border_width;
++ XConfigureWindow(dpy, cre->window, xwcm, &xwc);
++
++ return;
++}
++
++static inline void __handle_cr_on_icon(
++ XConfigureRequestEvent *cre, FvwmWindow *fw)
++{
++ XWindowChanges xwc;
++ unsigned long xwcm;
++
++ xwcm = (cre->value_mask & CR_MOVERESIZE_MASK);
++ xwc.x = cre->x;
++ xwc.y = cre->y;
++ xwc.width = cre->width;
++ xwc.height = cre->height;
++ xwc.border_width = cre->border_width;
++ if (FW_W_ICON_PIXMAP(fw) == cre->window)
++ {
++ int bw;
++
++ if (cre->value_mask & CWBorderWidth)
++ {
++ fw->icon_border_width = cre->border_width;
++ }
++ bw = fw->icon_border_width;
++ if ((cre->value_mask & (CWWidth | CWHeight)) ==
++ (CWWidth | CWHeight))
++ {
++ set_icon_picture_size(
++ fw, cre->width + 2 * bw, cre->height + 2 *
bw);
++ }
++ }
++ set_icon_position(fw, cre->x, cre->y);
++ broadcast_icon_geometry(fw, False);
++ XConfigureWindow(dpy, cre->window, xwcm, &xwc);
++ if (cre->window != FW_W_ICON_PIXMAP(fw) &&
++ FW_W_ICON_PIXMAP(fw) != None)
++ {
++ rectangle g;
++
++ get_icon_picture_geometry(fw, &g);
++ xwc.x = g.x;
++ xwc.y = g.y;
++ xwcm = cre->value_mask & (CWX | CWY);
++ XConfigureWindow(
++ dpy, FW_W_ICON_PIXMAP(fw), xwcm, &xwc);
++ }
++ if (FW_W_ICON_TITLE(fw) != None)
++ {
++ rectangle g;
++
++ get_icon_title_geometry(fw, &g);
++ xwc.x = g.x;
++ xwc.y = g.y;
++ xwcm = cre->value_mask & (CWX | CWY);
++ XConfigureWindow(
++ dpy, FW_W_ICON_TITLE(fw), xwcm, &xwc);
++ }
++
++ return;
++}
++
++static inline void __handle_cr_on_shaped(FvwmWindow *fw)
++{
++ /* suppress compiler warnings w/o shape extension */
++ int i = 0;
++ unsigned int u = 0;
++ Bool b = False;
++ int boundingShaped;
++
++ if (FShapeQueryExtents(
++ dpy, FW_W(fw), &boundingShaped, &i, &i, &u, &u, &b,
++ &i, &i, &u, &u))
++ {
++ fw->wShaped = boundingShaped;
++ }
++ else
++ {
++ fw->wShaped = 0;
++ }
++
++ return;
++}
++
++static inline void __handle_cr_restack(
++ int *ret_do_send_event, XConfigureRequestEvent *cre, FvwmWindow *fw)
++{
++ XWindowChanges xwc;
++ unsigned long xwcm;
++ FvwmWindow *fw2 = NULL;
++
++ if (cre->value_mask & CWSibling)
++ {
++ if (XFindContext(
++ dpy, cre->above, FvwmContext,
++ (caddr_t *)&fw2) == XCNOENT)
++ {
++ fw2 = NULL;
++ }
++ if (fw2 == fw)
++ {
++ fw2 = NULL;
++ }
++ }
++ if (cre->detail != Above && cre->detail != Below)
++ {
++ HandleUnusualStackmodes(
++ cre->detail, fw, cre->window, fw2, cre->above);
++ }
++ /* only allow clients to restack windows within their layer */
++ else if (fw2 == NULL || compare_window_layers(fw2, fw) != 0)
++ {
++ switch (cre->detail)
++ {
++ case Above:
++ RaiseWindow(fw);
++ break;
++ case Below:
++ LowerWindow(fw);
++ break;
++ }
++ }
++ else
++ {
++ xwc.sibling = FW_W_FRAME(fw2);
++ xwc.stack_mode = cre->detail;
++ xwcm = CWSibling | CWStackMode;
++ XConfigureWindow(dpy, FW_W_FRAME(fw), xwcm, &xwc);
++
++ /* Maintain the condition that icon windows are stacked
++ * immediately below their frame
++ * 1. for fw */
++ xwc.sibling = FW_W_FRAME(fw);
++ xwc.stack_mode = Below;
++ xwcm = CWSibling | CWStackMode;
++ if (FW_W_ICON_TITLE(fw) != None)
++ {
++ XConfigureWindow(
++ dpy, FW_W_ICON_TITLE(fw), xwcm, &xwc);
++ }
++ if (FW_W_ICON_PIXMAP(fw) != None)
++ {
++ XConfigureWindow(
++ dpy, FW_W_ICON_PIXMAP(fw), xwcm, &xwc);
++ }
++ /* 2. for fw2 */
++ if (cre->detail == Below)
++ {
++ xwc.sibling = FW_W_FRAME(fw2);
++ xwc.stack_mode = Below;
++ xwcm = CWSibling | CWStackMode;
++ if (FW_W_ICON_TITLE(fw2) != None)
++ {
++ XConfigureWindow(
++ dpy, FW_W_ICON_TITLE(fw2), xwcm,
&xwc);
++ }
++ if (FW_W_ICON_PIXMAP(fw2) != None)
++ {
++ XConfigureWindow(
++ dpy, FW_W_ICON_PIXMAP(fw2), xwcm,
++ &xwc);
++ }
++ }
++ /* Maintain the stacking order ring */
++ if (cre->detail == Above)
++ {
++ remove_window_from_stack_ring(fw);
++ add_window_to_stack_ring_after(
++ fw, get_prev_window_in_stack_ring(fw2));
++ }
++ else /* cre->detail == Below */
++ {
++ remove_window_from_stack_ring(fw);
++ add_window_to_stack_ring_after(fw, fw2);
++ }
++ BroadcastRestackThisWindow(fw);
++ }
++ /* srt (28-Apr-2001): Tk needs a ConfigureNotify event after a
++ * raise, otherwise it would hang for two seconds */
++ *ret_do_send_event = 1;
++
++ return;
++}
++
++static inline void __cr_get_static_position(
++ rectangle *ret_g, FvwmWindow *fw, XConfigureRequestEvent *cre,
++ size_borders *b)
++{
++ if (cre->value_mask & CWX)
++ {
++ ret_g->x = cre->x - b->top_left.width;
++ }
++ else
++ {
++ ret_g->x = fw->g.frame.x;
++ }
++ if (cre->value_mask & CWY)
++ {
++ ret_g->y = cre->y - b->top_left.height;
++ }
++ else
++ {
++ ret_g->y = fw->g.frame.y;
++ }
++
++ return;
++}
++
++static inline void __cr_get_grav_position(
++ rectangle *ret_g, FvwmWindow *fw, XConfigureRequestEvent *cre,
++ size_borders *b)
++{
++ int grav_x;
++ int grav_y;
++
++ gravity_get_offsets(fw->hints.win_gravity, &grav_x, &grav_y);
++ if (cre->value_mask & CWX)
++ {
++ ret_g->x = cre->x - ((grav_x + 1) * b->total_size.width) / 2;
++ }
++ else
++ {
++ ret_g->x = fw->g.frame.x;
++ }
++ if (cre->value_mask & CWY)
++ {
++ ret_g->y = cre->y - ((grav_y + 1) * b->total_size.height) / 2;
++ }
++ else
++ {
++ ret_g->y = fw->g.frame.y;
++ }
++
++ return;
++}
++
++/* Try to detect whether the application uses the ICCCM way of moving its
++ * window or the traditional way, always assuming StaticGravity. */
++static inline void __cr_detect_icccm_move(
++ FvwmWindow *fw, XConfigureRequestEvent *cre, size_borders *b)
++{
++ rectangle grav_g;
++ rectangle static_g;
++ rectangle dg_g;
++ rectangle ds_g;
++ int mx;
++ int my;
++ int m;
++ int w;
++ int h;
++ int has_x;
++ int has_y;
++
++ if (CR_MOTION_METHOD(fw) != CR_MOTION_METHOD_AUTO)
++ {
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr,
++ "_cdim: --- already detected (pid %d) %p"
++ " '%s'\n", HAS_EWMH_WM_PID(fw), fw,
++ fw->visible_name);
++ }
++ return;
++ }
++ if (HAS_EWMH_WM_PID(fw))
++ {
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr,"_cdim: +++ has ewmh_wm_pid: icccm"
++ " %p '%s'\n", fw, fw->visible_name);
++ }
++ SET_CR_MOTION_METHOD(fw, CR_MOTION_METHOD_USE_GRAV);
++ SET_CR_MOTION_METHOD_DETECTED(fw, 1);
++ return;
++ }
++ if (fw->ewmh_window_type != EWMH_WINDOW_TYPE_NONE_ID)
++ {
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "_cdim: +++ has ewmh_window_type:"
++ " icccm %p '%s'\n", fw,
++ fw->visible_name);
++ }
++ SET_CR_MOTION_METHOD(fw, CR_MOTION_METHOD_USE_GRAV);
++ SET_CR_MOTION_METHOD_DETECTED(fw, 1);
++ return;
++ }
++ if (FShapesSupported && fw->wShaped)
++ {
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "_cdim: --- shaped window %p "
++ "'%s'\n", fw, fw->visible_name);
++ }
++ /* no detection for shaped windows */
++ return;
++ }
++ if (fw->hints.win_gravity == StaticGravity)
++ {
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "_cdim: --- using StaticGravity"
++ " %p '%s'\n", fw, fw->visible_name);
++ }
++ return;
++ }
++ if (fw->hints.win_gravity == StaticGravity)
++ {
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "_cdim: --- using StaticGravity"
++ " %p '%s'\n", fw, fw->visible_name);
++ }
++ return;
++ }
++ has_x = (cre->value_mask & CWX);
++ has_y = (cre->value_mask & CWY);
++ if (!has_x && !has_y)
++ {
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "_cdim: --- not moved %p '%s'\n",
++ fw, fw->visible_name);
++ }
++ return;
++ }
++ __cr_get_grav_position(&grav_g, fw, cre, b);
++ __cr_get_static_position(&static_g, fw, cre, b);
++ if (static_g.x == grav_g.x)
++ {
++ /* both methods have the same result; ignore */
++ has_x = 0;
++ }
++ if (static_g.y == grav_g.y)
++ {
++ /* both methods have the same result; ignore */
++ has_y = 0;
++ }
++ if (!has_x && !has_y)
++ {
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "_cdim: --- not moved %p '%s'\n",
++ fw, fw->visible_name);
++ }
++ return;
++ }
++ dg_g.x = grav_g.x - fw->g.frame.x;
++ dg_g.y = grav_g.y - fw->g.frame.y;
++ ds_g.x = static_g.x - fw->g.frame.x;
++ ds_g.y = static_g.y - fw->g.frame.y;
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "s %3d/%3d %2d/%2d, g %3d/%3d %2d/%2d: ",
++ static_g.x, static_g.y, ds_g.x, ds_g.y, grav_g.x,
++ grav_g.y, dg_g.x, dg_g.y);
++ }
++ /* check full screen */
++ if ((cre->value_mask & (CWX | CWY)) == (CWX | CWY) &&
++ (has_x || has_y) &&
++ cre->width == Scr.MyDisplayWidth &&
++ cre->height == Scr.MyDisplayHeight)
++ {
++ if (grav_g.x == -b->top_left.width &&
++ grav_g.y == -b->top_left.height)
++ {
++ /* Window is fullscreen using the ICCCM way. */
++ SET_CR_MOTION_METHOD(fw, CR_MOTION_METHOD_USE_GRAV);
++ SET_CR_MOTION_METHOD_DETECTED(fw, 1);
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "+++ fullscreen icccm %p"
++ " '%s'\n", fw, fw->visible_name);
++ }
++ return;
++ }
++ else if (static_g.x == -b->top_left.width &&
++ static_g.y == -b->top_left.height)
++ {
++ /* Window is fullscreen using the traditional way. */
++ SET_CR_MOTION_METHOD(fw,
CR_MOTION_METHOD_STATIC_GRAV);
++ SET_CR_MOTION_METHOD_DETECTED(fw, 1);
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "+++ fullscreen traditional"
++ " %p '%s'\n", fw,
++ fw->visible_name);
++ }
++ return;
++ }
++ }
++ /* check travelling across the screen */
++ if (has_x && dg_g.x == 0 && ds_g.x != 0 &&
++ has_y && dg_g.y == 0 && ds_g.y != 0)
++ {
++ /* The traditional way causes a shift by the border width or
++ * height. Use ICCCM way. */
++ SET_CR_MOTION_METHOD(fw, CR_MOTION_METHOD_USE_GRAV);
++ SET_CR_MOTION_METHOD_DETECTED(fw, 1);
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "+++ travelling icccm %p '%s'\n",
++ fw, fw->visible_name);
++ }
++ return;
++ }
++ if (has_x && dg_g.x != 0 && ds_g.x == 0 &&
++ has_y && dg_g.y != 0 && ds_g.y == 0)
++ {
++ /* The ICCCM way causes a shift by the border width or height.
++ * Use traditional way. */
++ SET_CR_MOTION_METHOD(fw, CR_MOTION_METHOD_STATIC_GRAV);
++ SET_CR_MOTION_METHOD_DETECTED(fw, 1);
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "+++ travelling traditional %p"
++ " '%s'\n", fw, fw->visible_name);
++ }
++ return;
++ }
++ /* check placement near border */
++ w = (cre->value_mask & CWWidth) ?
++ cre->width + b->total_size.width : fw->g.frame.width;
++ h = (cre->value_mask & CWHeight) ?
++ cre->height + b->total_size.height : fw->g.frame.height;
++ if (!has_x)
++ {
++ mx = CR_MOTION_METHOD_AUTO;
++ }
++ else if (static_g.x == 0 || static_g.x + w == Scr.MyDisplayWidth)
++ {
++ mx = CR_MOTION_METHOD_STATIC_GRAV;
++ }
++ else if (grav_g.x == 0 || grav_g.x + w == Scr.MyDisplayWidth)
++ {
++ mx = CR_MOTION_METHOD_USE_GRAV;
++ }
++ else
++ {
++ mx = CR_MOTION_METHOD_AUTO;
++ }
++ if (!has_y)
++ {
++ my = CR_MOTION_METHOD_AUTO;
++ }
++ else if (static_g.y == 0 || static_g.y + h == Scr.MyDisplayHeight)
++ {
++ my = CR_MOTION_METHOD_STATIC_GRAV;
++ }
++ else if (grav_g.y == 0 || grav_g.y + h == Scr.MyDisplayHeight)
++ {
++ my = CR_MOTION_METHOD_USE_GRAV;
++ }
++ else
++ {
++ my = CR_MOTION_METHOD_AUTO;
++ }
++ m = (mx != CR_MOTION_METHOD_AUTO) ? mx : my;
++ if (m != CR_MOTION_METHOD_AUTO)
++ {
++ /* Window was placed next to the display border. */
++ if (m == my || my == CR_MOTION_METHOD_AUTO)
++ {
++ SET_CR_MOTION_METHOD(fw, m);
++ SET_CR_MOTION_METHOD_DETECTED(fw, 1);
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "+++ near border %s %p "
++ "'%s'\n", (m ==
++ CR_MOTION_METHOD_USE_GRAV)
++ ? "icccm" : "traditional", fw,
++ fw->visible_name);
++ }
++ return;
++ }
++ }
++ if (Scr.bo.do_debug_cr_motion_method == 1)
++ {
++ fprintf(
++ stderr, "--- not detected %p '%s'\n", fw,
++ fw->visible_name);
++ }
++
++ return;
++}
++
++#define EXPERIMENTAL_ANTI_RACE_CONDITION_CODE
++/* This is not a good idea because this interferes with changes in the size
++ * hints of the window. However, it is impossible to be completely safe
here.
++ * For example, if the client changes the size inc, then resizes the size of
++ * its window and then changes the size inc again - all in one batch - then
++ * the WM will read the *second* size inc upon the *first* event and use the
++ * wrong one in the ConfigureRequest calculations. */
++/* dv (31 Mar 2002): The code now handles these situations, so enable it
++ * again. */
++#ifdef EXPERIMENTAL_ANTI_RACE_CONDITION_CODE
++static inline int __merge_cr_moveresize(
++ const evh_args_t *ea, XConfigureRequestEvent *cre, FvwmWindow *fw,
++ size_borders *b)
++{
++ int cn_count = 0;
++ XEvent e;
++ XConfigureRequestEvent *ecre;
++ check_if_event_args args;
++
++ args.w = cre->window;
++ args.do_return_true = False;
++ args.do_return_true_cr = True;
++ args.cr_value_mask = CR_MOVERESIZE_MASK;
++ args.ret_does_match = False;
++ args.ret_type = 0;
++#if 0
++ /* free some CPU */
++ /* dv (7 May 2002): No, it's better to not reschedule processes here
++ * because some funny applications (XMMS, GTK) seem to expect that
++ * ConfigureRequests are handled instantly or they freak out. */
++ usleep(1);
++#endif
++ for (cn_count = 0; 1; )
++ {
++ unsigned long vma;
++ unsigned long vmo;
++ unsigned long xm;
++ unsigned long ym;
++ evh_args_t ea2;
++ exec_context_changes_t ecc;
++
++ FCheckPeekIfEvent(
++ dpy, &e, test_resizing_event, (XPointer)&args);
++ ecre = &e.xconfigurerequest;
++ if (args.ret_does_match == False)
++ {
++ break;
++ }
++ else if (args.ret_type == PropertyNotify)
++ {
++ /* Can't merge events with a PropertyNotify in
++ * between. The event is still on the queue. */
++ break;
++ }
++ else if (args.ret_type != ConfigureRequest)
++ {
++ /* not good. unselected event type! */
++ continue;
++ }
++ /* Event was not yet removed from the queue but stored in e.
*/
++ xm = CWX | CWWidth;
++ ym = CWY | CWHeight;
++ vma = cre->value_mask & ecre->value_mask;
++ vmo = cre->value_mask | ecre->value_mask;
++ if (((vma & xm) == 0 && (vmo & xm) == xm) ||
++ ((vma & ym) == 0 && (vmo & ym) == ym))
++ {
++ /* can't merge events since location of window might
++ * get screwed up. */
++ break;
++ }
++ /* Finally remove the event from the queue */
++ FCheckIfEvent(dpy, &e, test_resizing_event, (XPointer)&args);
++ /* partially handle the event */
++ ecre->value_mask &= ~args.cr_value_mask;
++ ea2.exc = exc_clone_context(ea->exc, &ecc, ECC_ETRIGGER);
++ HandleConfigureRequest(&ea2);
++ exc_destroy_context(ea2.exc);
++ /* collect the size/position changes */
++ if (ecre->value_mask & CWX)
++ {
++ cre->x = ecre->x;
++ }
++ if (ecre->value_mask & CWY)
++ {
++ cre->y = ecre->y;
++ }
++ if (ecre->value_mask & CWWidth)
++ {
++ cre->width = ecre->width;
++ }
++ if (ecre->value_mask & CWHeight)
++ {
++ cre->height = ecre->height;
++ }
++ if (ecre->value_mask & CWBorderWidth)
++ {
++ cre->border_width = ecre->border_width;
++ }
++ cre->value_mask |= (ecre->value_mask & CR_MOVERESIZE_MASK);
++ cn_count++;
++ }
++
++ return cn_count;
++}
++#endif
++
++static inline int __handle_cr_on_client(
++ int *ret_do_send_event, XConfigureRequestEvent cre,
++ const evh_args_t *ea, FvwmWindow *fw, Bool force)
++{
++ rectangle new_g;
++ rectangle d_g;
++ size_rect constr_dim;
++ size_rect oldnew_dim;
++ size_borders b;
++ int cn_count = 0;
++
++ if (ea)
++ {
++ cre = ea->exc->x.etrigger->xconfigurerequest;
++ }
++ if ((cre.value_mask & (CWWidth | CWHeight | CWX | CWY)) == 0)
++ {
++ return 0;
++ }
++
++ get_window_borders(fw, &b);
++#ifdef EXPERIMENTAL_ANTI_RACE_CONDITION_CODE
++ /* Merge all pending ConfigureRequests for the window into a single
++ * event. However, we can not do this if the window uses the motion
++ * method autodetection because the merged event might confuse the
++ * detection code. */
++ if (ea && CR_MOTION_METHOD(fw) == CR_MOTION_METHOD_AUTO)
++ {
++ cn_count = __merge_cr_moveresize(ea, &cre, fw, &b);
++ }
++#endif
++#if 0
++ fprintf(stderr,
++ "cre: %d(%d) %d(%d) %d(%d)x%d(%d) fw 0x%08x w 0x%08x "
++ "ew 0x%08x '%s'\n",
++ cre.x, (int)(cre.value_mask & CWX),
++ cre.y, (int)(cre.value_mask & CWY),
++ cre.width, (int)(cre.value_mask & CWWidth),
++ cre.height, (int)(cre.value_mask & CWHeight),
++ (int)FW_W_FRAME(fw), (int)FW_W(fw), (int)cre.window,
++ (fw->name.name) ? fw->name.name : "");
++#endif
++ /* Don't modify frame_g fields before calling SetupWindow! */
++ memset(&d_g, 0, sizeof(d_g));
++
++ 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 (!HAS_OVERRIDE_SIZE_HINTS(fw) && (fw->hints.flags & PMaxSize))
++ {
++ /* Java workaround */
++ if (cre.height > fw->hints.max_height &&
++ fw->hints.max_height <= BROKEN_MAXSIZE_LIMIT)
++ {
++ fw->hints.max_height = DEFAULT_MAX_MAX_WINDOW_HEIGHT;
++ cre.value_mask |= CWHeight;
++ }
++ if (cre.width > fw->hints.max_width &&
++ fw->hints.max_width <= BROKEN_MAXSIZE_LIMIT)
++ {
++ fw->hints.max_width = DEFAULT_MAX_MAX_WINDOW_WIDTH;
++ cre.value_mask |= CWWidth;
++ }
++ }
++ if (!HAS_OVERRIDE_SIZE_HINTS(fw) && (fw->hints.flags & PMinSize))
++ {
++ if (cre.width < fw->hints.min_width &&
++ fw->hints.min_width >= BROKEN_MINSIZE_LIMIT)
++ {
++ fw->hints.min_width = 1;
++ cre.value_mask |= CWWidth;
++ }
++ if (cre.height < fw->hints.min_height &&
++ fw->hints.min_height >= BROKEN_MINSIZE_LIMIT)
++ {
++ fw->hints.min_height = 1;
++ cre.value_mask |= CWHeight;
++ }
++ }
++ if (IS_SHADED(fw) ||
++ !is_function_allowed(F_MOVE, NULL, fw, False, False))
++ {
++ /* forbid shaded applications to move their windows */
++ cre.value_mask &= ~(CWX | CWY);
++ /* resend the old geometry */
++ *ret_do_send_event = 1;
++ }
++ if (IS_MAXIMIZED(fw))
++ {
++ /* dont allow clients to resize maximized windows */
++ cre.value_mask &= ~(CWWidth | CWHeight);
++ /* resend the old geometry */
++ *ret_do_send_event = 1;
++ d_g.width = 0;
++ d_g.height = 0;
++ }
++ else if (!is_function_allowed(F_RESIZE, NULL, fw, False, False))
++ {
++ cre.value_mask &= ~(CWWidth | CWHeight);
++ *ret_do_send_event = 1;
++ }
++
++ if (cre.value_mask & CWBorderWidth)
++ {
++ /* for restoring */
++ fw->attr_backup.border_width = cre.border_width;
++ }
++ if (!force && CR_MOTION_METHOD(fw) == CR_MOTION_METHOD_AUTO)
++ {
++ __cr_detect_icccm_move(fw, &cre, &b);
++ }
++ if (!(cre.value_mask & (CWX | CWY)))
++ {
++ /* nothing */
++ }
++ else if ((force ||
++ CR_MOTION_METHOD(fw) == CR_MOTION_METHOD_USE_GRAV) &&
++ fw->hints.win_gravity != StaticGravity)
++ {
++ int ref_x;
++ int ref_y;
++ int grav_x;
++ int grav_y;
++
++ gravity_get_offsets(fw->hints.win_gravity, &grav_x, &grav_y);
++ if (cre.value_mask & CWX)
++ {
++ ref_x = cre.x -
++ ((grav_x + 1) * b.total_size.width) / 2;
++ d_g.x = ref_x - fw->g.frame.x;
++ }
++ if (cre.value_mask & CWY)
++ {
++ ref_y = cre.y -
++ ((grav_y + 1) * b.total_size.height) / 2;
++ d_g.y = ref_y - fw->g.frame.y;
++ }
++ }
++ else /* ..._USE_GRAV or ..._AUTO */
++ {
++ /* default: traditional cr handling */
++ if (cre.value_mask & CWX)
++ {
++ d_g.x = cre.x - fw->g.frame.x - b.top_left.width;
++ }
++ if (cre.value_mask & CWY)
++ {
++ d_g.y = cre.y - fw->g.frame.y - b.top_left.height;
++ }
++ }
++ if (cre.value_mask & CWHeight)
++ {
++ if (cre.height <
++ (WINDOW_FREAKED_OUT_SIZE - b.total_size.height))
++ {
++ d_g.height = cre.height -
++ (fw->g.frame.height - b.total_size.height);
++ }
++ else
++ {
++ /* Ignore height changes to astronomically large
++ * windows (needed for XEmacs 20.4); don't care if the
++ * window is shaded here - we won't use 'height' in
++ * this case anyway.
++ * Inform the buggy app about the size that *we* want
++ */
++ d_g.height = 0;
++ *ret_do_send_event = 1;
++ }
++ }
++ if (cre.value_mask & CWWidth)
++ {
++ if (cre.width < (WINDOW_FREAKED_OUT_SIZE -
b.total_size.width))
++ {
++ d_g.width = cre.width -
++ (fw->g.frame.width - b.total_size.width);
++ }
++ else
++ {
++ d_g.width = 0;
++ *ret_do_send_event = 1;
++ }
++ }
++
++ /* SetupWindow (x,y) are the location of the upper-left outer corner
++ * and are passed directly to XMoveResizeWindow (frame). The
++ * (width,height) are the inner size of the frame. The inner width is
++ * the same as the requested client window width; the inner height is
++ * the same as the requested client window height plus any title bar
++ * slop. */
++ new_g = fw->g.frame;
++ if (IS_SHADED(fw))
++ {
++ new_g.width = fw->g.normal.width;
++ new_g.height = fw->g.normal.height;
++ }
++ oldnew_dim.width = new_g.width + d_g.width;
++ oldnew_dim.height = new_g.height + d_g.height;
++ constr_dim.width = oldnew_dim.width;
++ constr_dim.height = oldnew_dim.height;
++ constrain_size(
++ fw, NULL, &constr_dim.width, &constr_dim.height, 0, 0,
++ CS_UPDATE_MAX_DEFECT);
++ d_g.width += (constr_dim.width - oldnew_dim.width);
++ d_g.height += (constr_dim.height - oldnew_dim.height);
++ if ((cre.value_mask & CWX) && d_g.width)
++ {
++ new_g.x = fw->g.frame.x + d_g.x;
++ new_g.width = fw->g.frame.width + d_g.width;
++ }
++ else if ((cre.value_mask & CWX) && !d_g.width)
++ {
++ new_g.x = fw->g.frame.x + d_g.x;
++ }
++ else if (!(cre.value_mask & CWX) && d_g.width)
++ {
++ gravity_resize(fw->hints.win_gravity, &new_g, d_g.width, 0);
++ }
++ if ((cre.value_mask & CWY) && d_g.height)
++ {
++ new_g.y = fw->g.frame.y + d_g.y;
++ new_g.height = fw->g.frame.height + d_g.height;
++ }
++ else if ((cre.value_mask & CWY) && !d_g.height)
++ {
++ new_g.y = fw->g.frame.y + d_g.y;
++ }
++ else if (!(cre.value_mask & CWY) && d_g.height)
++ {
++ gravity_resize(fw->hints.win_gravity, &new_g, 0, d_g.height);
++ }
++
++ if (new_g.x == fw->g.frame.x && new_g.y == fw->g.frame.y &&
++ new_g.width == fw->g.frame.width &&
++ new_g.height == fw->g.frame.height)
++ {
++ /* Window will not be moved or resized; send a synthetic
++ * ConfigureNotify. */
++ *ret_do_send_event = 1;
++ }
++ else if ((cre.value_mask & CWX) || (cre.value_mask & CWY) ||
++ d_g.width || d_g.height)
++ {
++ if (IS_SHADED(fw))
++ {
++ get_shaded_geometry(fw, &new_g, &new_g);
++ }
++ frame_setup_window_app_request(
++ fw, new_g.x, new_g.y, new_g.width, new_g.height,
++ False);
++ /* make sure the window structure has the new position */
++ update_absolute_geometry(fw);
++ maximize_adjust_offset(fw);
++ GNOME_SetWinArea(fw);
++ }
++ else if (DO_FORCE_NEXT_CR(fw))
++ {
++ *ret_do_send_event = 1;
++ }
++ SET_FORCE_NEXT_CR(fw, 0);
++ SET_FORCE_NEXT_PN(fw, 0);
++
++ return cn_count;
++}
++
++void __handle_configure_request(
++ XConfigureRequestEvent cre, const evh_args_t *ea, FvwmWindow *fw,
++ Bool force)
++{
++ int do_send_event = 0;
++ int cn_count = 0;
++
++ /* According to the July 27, 1988 ICCCM draft, we should ignore size
++ * and position fields in the WM_NORMAL_HINTS property when we map a
++ * window. Instead, we'll read the current geometry. Therefore, we
++ * should respond to configuration requests for windows which have
++ * never been mapped. */
++ if (fw == NULL)
++ {
++ __handle_cr_on_unmanaged(&cre);
++ return;
++ }
++ if (cre.window == FW_W_ICON_TITLE(fw) ||
++ cre.window == FW_W_ICON_PIXMAP(fw))
++ {
++ __handle_cr_on_icon(&cre, fw);
++ }
++ if (FShapesSupported)
++ {
++ __handle_cr_on_shaped(fw);
++ }
++ if (fw != NULL && cre.window == FW_W(fw))
++ {
++ cn_count = __handle_cr_on_client(
++ &do_send_event, cre, ea, fw, force);
++ }
++ /* Stacking order change requested. Handle this *after* geometry
++ * changes, since we need the new geometry in occlusion calculations
*/
++ if ((cre.value_mask & CWStackMode) &&
++ (!DO_IGNORE_RESTACK(fw) || force))
++ {
++ __handle_cr_restack(&do_send_event, &cre, fw);
++ }
++#if 1
++ /* This causes some ddd windows not to be drawn properly. Reverted
back
++ * to the old method in frame_setup_window. */
++ /* domivogt (15-Oct-1999): enabled this to work around buggy apps that
++ * ask for a nonsense height and expect that they really get it. */
++ if (cn_count == 0 && do_send_event)
++ {
++ cn_count = 1;
++ }
++ else if (cn_count > 0)
++ {
++ do_send_event = 1;
++ }
++ for ( ; cn_count > 0; cn_count--)
++ {
++ SendConfigureNotify(
++ fw, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width,
++ fw->g.frame.height, 0, True);
++ }
++ if (do_send_event)
++ {
++ XFlush(dpy);
++ }
++#endif
++
++ return;
++}
++
++static Bool __predicate_button_click(
++ Display *display, XEvent *event, XPointer arg)
++{
++ if (event->type == ButtonPress || event->type == ButtonRelease)
++ {
++ return True;
++ }
++
++ return False;
++}
++
++/* Helper function for __handle_focus_raise_click(). */
++static Bool __test_for_motion(int x0, int y0)
++{
++ int x;
++ int y;
++ unsigned int mask;
++ XEvent e;
++
++ /* Query the pointer to do this. We can't check for events here since
++ * the events are still needed if the pointer moves. */
++
++ /* However, some special mouse (e.g., a touchpad with the
++ * synaptic driver) may handle a double click in a special way
++ * (for dragging through short touching and holding down the
++ * finger on the touchpad). Bascially, when you execute a
++ * double click the first button release is queued after the
++ * second _physical_ mouse release happen. It seems that
++ * FQueryPointer may not work as expected: it does not see
++ * that the button is released on a double click. So, we need
++ * to check for a button press in the future to avoid a fvwm
++ * lockup! (olicha 2004-01-31) */
++
++ for (x = x0, y = y0; FQueryPointer(
++ dpy, Scr.Root, &JunkRoot, &JunkChild, &JunkX, &JunkY,
++ &x, &y, &mask) == True; usleep(20000))
++ {
++ if ((mask & DEFAULT_ALL_BUTTONS_MASK) == 0)
++ {
++ /* all buttons are released */
++ return False;
++ }
++ else if (abs(x - x0) >= Scr.MoveThreshold ||
++ abs(y - y0) >= Scr.MoveThreshold)
++ {
++ /* the pointer has moved */
++ return True;
++ }
++ if (FCheckPeekIfEvent(dpy, &e, __predicate_button_click,
NULL))
++ {
++ /* click in the future */
++ return False;
++ }
++ else
++ {
++ /* The predicate procedure finds no match, no event
++ * has been removed from the queue and XFlush was
++ * called. Nothing to do */
++ }
++ }
++
++ /* pointer has moved off screen */
++ return True;
++}
++
++/* Helper function for __handle_focus_raise_click(). */
++static void __check_click_to_focus_or_raise(
++ hfrc_ret_t *ret_args, const exec_context_t *exc)
++{
++ FvwmWindow * const fw = exc->w.fw;
++ const XEvent *te = exc->x.etrigger;
++ struct
++ {
++ unsigned is_client_click : 1;
++ unsigned is_focused : 1;
++ } f;
++
++ f.is_focused = !!focus_is_focused(fw);
++ f.is_client_click = (exc->w.wcontext == C_WINDOW ||
++ exc->w.wcontext == C_EWMH_DESKTOP);
++ /* check if we need to raise and/or focus the window */
++ ret_args->do_focus = focus_query_click_to_focus(fw, exc->w.wcontext);
++ if (f.is_client_click && !ret_args->do_focus &&
++ !f.is_focused && FP_DO_FOCUS_BY_PROGRAM(FW_FOCUS_POLICY(fw)) &&
++ !fpol_query_allow_user_focus(&FW_FOCUS_POLICY(fw)))
++ {
++ /* Give the window a chance to to take focus itself */
++ ret_args->do_focus = 1;
++ }
++ if (ret_args->do_focus && focus_is_focused(fw))
++ {
++ ret_args->do_focus = 0;
++ }
++ ret_args->do_raise =
++ focus_query_click_to_raise(fw, f.is_focused, exc->w.wcontext);
++#define EXPERIMENTAL_ROU_HANDLING_V2
++#ifdef EXPERIMENTAL_ROU_HANDLING_V2
++/* RBW -- Dang! This works without the one in HandleEnterNotify! */
++ if (ret_args->do_raise && is_on_top_of_layer_and_above_unmanaged(fw))
++#else
++ if (ret_args->do_raise && is_on_top_of_layer(fw))
++#endif
++ {
++ ret_args->do_raise = 0;
++ }
++ if ((ret_args->do_focus &&
++ FP_DO_IGNORE_FOCUS_CLICK_MOTION(FW_FOCUS_POLICY(fw))) ||
++ (ret_args->do_raise &&
++ FP_DO_IGNORE_RAISE_CLICK_MOTION(FW_FOCUS_POLICY(fw))))
++ {
++ /* Pass further events to the application and check if a
button
++ * release or motion event occurs next. If we don't do this
++ * here, the pointer will seem to be frozen in
++ * __test_for_motion(). */
++ XAllowEvents(dpy, ReplayPointer, CurrentTime);
++ if (__test_for_motion(te->xbutton.x_root, te->xbutton.y_root))
++ {
++ /* the pointer was moved, process event normally */
++ ret_args->do_focus = 0;
++ ret_args->do_raise = 0;
++ }
++ }
++ if (ret_args->do_focus || ret_args->do_raise)
++ {
++ if (!((ret_args->do_focus &&
++ FP_DO_ALLOW_FUNC_FOCUS_CLICK(FW_FOCUS_POLICY(fw))) ||
++ (ret_args->do_raise &&
++ FP_DO_ALLOW_FUNC_RAISE_CLICK(FW_FOCUS_POLICY(fw)))))
++ {
++ ret_args->do_forbid_function = 1;
++ }
++ if (!((ret_args->do_focus &&
++ FP_DO_PASS_FOCUS_CLICK(FW_FOCUS_POLICY(fw))) ||
++ (ret_args->do_raise &&
++ FP_DO_PASS_RAISE_CLICK(FW_FOCUS_POLICY(fw)))))
++ {
++ ret_args->do_swallow_click = 1;
++ }
++ }
++
++ return;
++}
++
++/* Finds out if the click on a window must be used to focus or raise it. */
++static void __handle_focus_raise_click(
++ hfrc_ret_t *ret_args, const exec_context_t *exc)
++{
++ memset(ret_args, 0, sizeof(*ret_args));
++ if (exc->w.fw == NULL)
++ {
++ return;
++ }
++ /* check for proper click button and modifiers*/
++ if (FP_USE_MOUSE_BUTTONS(FW_FOCUS_POLICY(exc->w.fw)) != 0 &&
++ !(FP_USE_MOUSE_BUTTONS(FW_FOCUS_POLICY(exc->w.fw)) &
++ (1 << (exc->x.etrigger->xbutton.button - 1))))
++ {
++ /* wrong button, handle click normally */
++ return;
++ }
++ else if (FP_USE_MODIFIERS(FW_FOCUS_POLICY(exc->w.fw)) !=
++ FPOL_ANY_MODIFIER &&
++ MaskUsedModifiers(
++ FP_USE_MODIFIERS(FW_FOCUS_POLICY(exc->w.fw))) !=
++ MaskUsedModifiers(exc->x.etrigger->xbutton.state))
++ {
++ /* right button but wrong modifiers, handle click normally */
++ return;
++ }
++ else
++ {
++ __check_click_to_focus_or_raise(ret_args, exc);
++ }
++
++ return;
++}
++
++/* Helper function for HandleButtonPress */
++static Bool __is_bpress_window_handled(const exec_context_t *exc)
++{
++ Window eventw;
++ const XEvent *te = exc->x.etrigger;
++
++ if (exc->w.fw == NULL)
++ {
++ if ((te->xbutton.window != Scr.Root ||
++ te->xbutton.subwindow != None) &&
++ !is_pan_frame(te->xbutton.window))
++ {
++ /* Ignore events in unmanaged windows or subwindows of
++ * a client */
++ return False;
++ }
++ else
++ {
++ return True;
++ }
++ }
++ eventw = (te->xbutton.subwindow != None &&
++ te->xany.window != FW_W(exc->w.fw)) ?
++ te->xbutton.subwindow : te->xany.window;
++ if (is_frame_hide_window(eventw) || eventw == FW_W_FRAME(exc->w.fw))
++ {
++ return False;
++ }
++ if (!XGetGeometry(
++ dpy, eventw, &JunkRoot, &JunkX, &JunkY,
++ (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
++ (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth))
++ {
++ /* The window has already died. */
++ return False;
++ }
++
++ return True;
++}
++
++/* Helper function for __handle_bpress_on_managed */
++static Bool __handle_click_to_focus(const exec_context_t *exc)
++{
++ fpol_set_focus_by_t set_by;
++
++ switch (exc->w.wcontext)
++ {
++ case C_WINDOW:
++ case C_EWMH_DESKTOP:
++ set_by = FOCUS_SET_BY_CLICK_CLIENT;
++ break;
++ case C_ICON:
++ set_by = FOCUS_SET_BY_CLICK_ICON;
++ break;
++ default:
++ set_by = FOCUS_SET_BY_CLICK_DECOR;
++ break;
++ }
++ SetFocusWindow(exc->w.fw, True, set_by);
++ focus_grab_buttons(exc->w.fw);
++ if (focus_is_focused(exc->w.fw) && !IS_ICONIFIED(exc->w.fw))
++ {
++ border_draw_decorations(
++ exc->w.fw, PART_ALL, True, True, CLEAR_ALL, NULL,
++ NULL);
++ }
++
++ return focus_is_focused(exc->w.fw);
++}
++
++/* Helper function for __handle_bpress_on_managed */
++static Bool __handle_click_to_raise(const exec_context_t *exc)
++{
++ Bool rc = False;
++ int is_focused;
++
++ is_focused = focus_is_focused(exc->w.fw);
++ if (focus_query_click_to_raise(exc->w.fw, is_focused, True))
++ {
++ rc = True;
++ }
++
++ return rc;
++}
++
++/* Helper function for HandleButtonPress */
++static void __handle_bpress_stroke(void)
++{
++ STROKE_CODE(stroke_init());
++ STROKE_CODE(send_motion = True);
++
++ return;
++}
++
++/* Helper function for __handle_bpress_on_managed */
++static Bool __handle_bpress_action(
++ const exec_context_t *exc, char *action)
++{
++ window_parts part;
++ Bool do_force;
++ Bool rc = False;
++
++ if (!action || *action == 0)
++ {
++ PressedW = None;
++ return False;
++ }
++ /* draw pressed in decorations */
++ part = border_context_to_parts(exc->w.wcontext);
++ do_force = (part & PART_TITLEBAR) ? True : False;
++ border_draw_decorations(
++ exc->w.fw, part, (Scr.Hilite == exc->w.fw), do_force,
++ CLEAR_ALL, NULL, NULL);
++ /* execute the action */
++ if (IS_ICONIFIED(exc->w.fw))
++ {
++ /* release the pointer since it can't do harm over an icon */
++ XAllowEvents(dpy, AsyncPointer, CurrentTime);
++ }
++ execute_function(NULL, exc, action, 0);
++ if (exc->w.wcontext != C_WINDOW && exc->w.wcontext != C_NO_CONTEXT)
++ {
++ WaitForButtonsUp(True);
++ rc = True;
++ }
++ /* redraw decorations */
++ PressedW = None;
++ if (check_if_fvwm_window_exists(exc->w.fw))
++ {
++ part = border_context_to_parts(exc->w.wcontext);
++ do_force = (part & PART_TITLEBAR) ? True : False;
++ border_draw_decorations(
++ exc->w.fw, part, (Scr.Hilite == exc->w.fw), do_force,
++ CLEAR_ALL, NULL, NULL);
++ }
++
++ return rc;
++}
++
++/* Handles button presses on the root window. */
++static void __handle_bpress_on_root(const exec_context_t *exc)
++{
++ char *action;
++
++ PressedW = None;
++ __handle_bpress_stroke();
++ /* search for an appropriate mouse binding */
++ action = CheckBinding(
++ Scr.AllBindings, STROKE_ARG(0)
exc->x.etrigger->xbutton.button,
++ exc->x.etrigger->xbutton.state, GetUnusedModifiers(), C_ROOT,
++ BIND_BUTTONPRESS, NULL, NULL);
++ if (action && *action)
++ {
++ const exec_context_t *exc2;
++ exec_context_changes_t ecc;
++
++ ecc.w.wcontext = C_ROOT;
++ exc2 = exc_clone_context(exc, &ecc, ECC_WCONTEXT);
++ execute_function(NULL, exc2, action, 0);
++ exc_destroy_context(exc2);
++ WaitForButtonsUp(True);
++ }
++ else
++ {
++ /* do gnome buttonpress forwarding if win == root */
++ GNOME_ProxyButtonEvent(exc->x.etrigger);
++ }
++
++ return;
++}
++
++/* Handles button presses on unmanaged windows */
++static void __handle_bpress_on_unmanaged(const exec_context_t *exc)
++{
++ /* Pass the event to the application. */
++ XAllowEvents(dpy, ReplayPointer, CurrentTime);
++ XFlush(dpy);
++
++ return;
++}
++
++/* Handles button presses on managed windows */
++static void __handle_bpress_on_managed(const exec_context_t *exc)
++{
++ char *action;
++ hfrc_ret_t f;
++ FvwmWindow * const fw = exc->w.fw;
++ XEvent *e;
++
++ e = exc->x.etrigger;
++ /* Now handle click to focus and click to raise. */
++ __handle_focus_raise_click(&f, exc);
++ PressedW = (f.do_forbid_function) ? None : exc->w.w;
++ if (f.do_focus)
++ {
++ if (!__handle_click_to_focus(exc))
++ {
++ /* Window didn't accept the focus; pass the click to
++ * the application. */
++ f.do_swallow_click = 0;
++ }
++ }
++ if (f.do_raise)
++ {
++ if (__handle_click_to_raise(exc) == True)
++ {
++ /* We can't raise the window immediately because the
++ * action bound to the click might be "Lower" or
++ * "RaiseLower". So mark the window as scheduled to be
++ * raised after the binding is executed. Functions
that
++ * modify the stacking order will reset this flag. */
++ SET_SCHEDULED_FOR_RAISE(fw, 1);
++ }
++ }
++ /* handle bindings */
++ if (!f.do_forbid_function)
++ {
++ /* stroke bindings */
++ __handle_bpress_stroke();
++ /* mouse bindings */
++ action = CheckBinding(
++ Scr.AllBindings, STROKE_ARG(0) e->xbutton.button,
++ e->xbutton.state, GetUnusedModifiers(),
++ exc->w.wcontext, BIND_BUTTONPRESS, &fw->class,
++ fw->name.name);
++ if (__handle_bpress_action(exc, action))
++ {
++ f.do_swallow_click = 1;
++ }
++ }
++ /* raise the window */
++ if (IS_SCHEDULED_FOR_RAISE(fw))
++ {
++ /* Now that we know the action did not restack the window we
++ * can raise it.
++ * dv (10-Aug-2002): We can safely raise the window after
++ * redrawing it since all the decorations are drawn in the
++ * window background and no Expose event is generated. */
++ RaiseWindow(fw);
++ SET_SCHEDULED_FOR_RAISE(fw, 0);
++ }
++ /* clean up */
++ if (!f.do_swallow_click)
++ {
++ /* pass the click to the application */
++ XAllowEvents(dpy, ReplayPointer, CurrentTime);
++ XFlush(dpy);
++ }
++ else if (f.do_focus || f.do_raise)
++ {
++ WaitForButtonsUp(True);
++ }
++
++ return;
++}
++
++/* restore focus stolen by unmanaged */
++static void __refocus_stolen_focus_win(const evh_args_t *ea)
++{
++ FOCUS_SET(Scr.StolenFocusWin);
++ ea->exc->x.etrigger->xfocus.window = Scr.StolenFocusWin;
++ ea->exc->x.etrigger->type = FocusIn;
++ Scr.UnknownWinFocused = None;
++ Scr.StolenFocusWin = None;
++ dispatch_event(ea->exc->x.etrigger);
++
++ return;
++}
++
++/* ---------------------------- event handlers
----------------------------- */
++
++void HandleButtonPress(const evh_args_t *ea)
++{
++ DBUG("HandleButtonPress", "Routine Entered");
++
++ GrabEm(CRS_NONE, GRAB_PASSIVE);
++ if (__is_bpress_window_handled(ea->exc) == False)
++ {
++ __handle_bpress_on_unmanaged(ea->exc);
++ }
++ else if (ea->exc->w.fw != NULL)
++ {
++ __handle_bpress_on_managed(ea->exc);
++ }
++ else
++ {
++ __handle_bpress_on_root(ea->exc);
++ }
++ UngrabEm(GRAB_PASSIVE);
++
++ return;
++}
++
++#ifdef HAVE_STROKE
++void HandleButtonRelease(const evh_args_t *ea)
++{
++ char *action;
++ char *name;
++ int real_modifier;
++ const XEvent *te = ea->exc->x.etrigger;
++ XClassHint *class;
++
++ DBUG("HandleButtonRelease", "Routine Entered");
++ send_motion = False;
++ stroke_trans (sequence);
++ DBUG("HandleButtonRelease",sequence);
++ /* Allows modifier to work (Only R context works here). */
++ real_modifier = te->xbutton.state - (1 << (7 + te->xbutton.button));
++ if (ea->exc->w.fw == NULL)
++ {
++ class = NULL;
++ name = NULL;
++ }
++ else
++ {
++ class = &ea->exc->w.fw->class;
++ name = ea->exc->w.fw->name.name;
++ }
++ /* need to search for an appropriate stroke binding */
++ action = CheckBinding(
++ Scr.AllBindings, sequence, te->xbutton.button, real_modifier,
++ GetUnusedModifiers(), ea->exc->w.wcontext, BIND_STROKE,
++ class, name);
++ /* got a match, now process it */
++ if (action != NULL && (action[0] != 0))
++ {
++ execute_function(NULL, ea->exc, action, 0);
++ WaitForButtonsUp(True);
++ }
++ else
++ {
++ /*
++ * do gnome buttonpress forwarding if win == root
++ */
++ if (Scr.Root == te->xany.window)
++ {
++ GNOME_ProxyButtonEvent(te);
++ }
++ }
++
++ return;
++}
++#endif /* HAVE_STROKE */
++
++void HandleClientMessage(const evh_args_t *ea)
++{
++ const XEvent *te = ea->exc->x.etrigger;
++ FvwmWindow * const fw = ea->exc->w.fw;
++
++ DBUG("HandleClientMessage", "Routine Entered");
++
++ /* Process GNOME and EWMH Messages */
++ if (GNOME_ProcessClientMessage(ea->exc))
++ {
++ return;
++ }
++ else if (EWMH_ProcessClientMessage(ea->exc))
++ {
++ return;
++ }
++
++ /* handle deletion of tear out menus */
++ if (fw && IS_TEAR_OFF_MENU(fw) && te->xclient.format == 32 &&
++ te->xclient.data.l[0] == _XA_WM_DELETE_WINDOW)
++ {
++ menu_close_tear_off_menu(fw);
++ return;
++ }
++
++ if (te->xclient.message_type == _XA_WM_CHANGE_STATE &&
++ fw && te->xclient.data.l[0] == IconicState && !IS_ICONIFIED(fw))
++ {
++ const exec_context_t *exc;
++ exec_context_changes_t ecc;
++
++ ecc.w.wcontext = C_WINDOW;
++ exc = exc_clone_context(ea->exc, &ecc, ECC_WCONTEXT);
++ execute_function(NULL, exc, "Iconify", 0);
++ exc_destroy_context(exc);
++ return;
++ }
++
++ /* FIXME: Is this safe enough ? I guess if clients behave
++ * according to ICCCM and send these messages only if they
++ * grabbed the pointer, it is OK */
++ {
++ extern Atom _XA_WM_COLORMAP_NOTIFY;
++ if (te->xclient.message_type == _XA_WM_COLORMAP_NOTIFY)
++ {
++ set_client_controls_colormaps(te->xclient.data.l[1]);
++ return;
++ }
++ }
++
++ /* CKH - if we get here, it was an unknown client message, so send
++ * it to the client if it was in a window we know about. I'm not so
++ * sure this should be done or not, since every other window manager
++ * I've looked at doesn't. But it might be handy for a free drag and
++ * drop setup being developed for Linux. */
++ if (fw)
++ {
++ if (te->xclient.window != FW_W(fw))
++ {
++ XEvent e;
++
++ e = *te;
++ e.xclient.window = FW_W(fw);
++ FSendEvent(dpy, FW_W(fw), False, NoEventMask, &e);
++ }
++ }
++}
++
++void HandleColormapNotify(const evh_args_t *ea)
++{
++ colormap_handle_colormap_notify(ea);
++
++ return;
++}
++
++void HandleConfigureRequest(const evh_args_t *ea)
++{
++ const XEvent *te = ea->exc->x.etrigger;
++ XConfigureRequestEvent cre;
++ FvwmWindow *fw = ea->exc->w.fw;
++
++ DBUG("HandleConfigureRequest", "Routine Entered");
++
++ cre = te->xconfigurerequest;
++ /* te->xany.window is te->.xconfigurerequest.parent, so the context
++ * window may be wrong. */
++ if (XFindContext(dpy, cre.window, FvwmContext, (caddr_t *)&fw) ==
++ XCNOENT)
++ {
++ fw = NULL;
++ }
++
++ __handle_configure_request(cre, ea, fw, False);
++}
++
++void HandleDestroyNotify(const evh_args_t *ea)
++{
++ DBUG("HandleDestroyNotify", "Routine Entered");
++
++ destroy_window(ea->exc->w.fw);
++ EWMH_ManageKdeSysTray(
++ ea->exc->x.etrigger->xdestroywindow.window,
++ ea->exc->x.etrigger->type);
++ EWMH_WindowDestroyed();
++ GNOME_SetClientList();
++
++ return;
++}
++
++#define DEBUG_ENTERNOTIFY 0
++#if DEBUG_ENTERNOTIFY
++static int ecount=0;
++#define ENTER_DBG(x) fprintf x;
++#else
++#define ENTER_DBG(x)
++#endif
++void HandleEnterNotify(const evh_args_t *ea)
++{
++ const XEnterWindowEvent *ewp;
++ XEvent d;
++ FvwmWindow *sf;
++ static Bool is_initial_ungrab_pending = True;
++ Bool is_tear_off_menu;
++ const XEvent *te = ea->exc->x.etrigger;
++ FvwmWindow * const fw = ea->exc->w.fw;
++
++ DBUG("HandleEnterNotify", "Routine Entered");
++ ewp = &te->xcrossing;
++ENTER_DBG((stderr, "++++++++ en (%d): fw 0x%08x w 0x%08x sw 0x%08xmode 0x%x
detail 0x%x '%s'\n", ++ecount, (int)fw, (int)ewp->window,
(int)ewp->subwindow, ewp->mode, ewp->detail, fw?fw->visible_name:"(none)"));
++
++ if (ewp->window == Scr.Root && ewp->subwindow == None &&
++ ewp->detail == NotifyInferior && ewp->mode == NotifyNormal)
++ {
++ BroadcastPacket(
++ MX_ENTER_WINDOW, 3, (long)Scr.Root, (long)NULL,
++ (long)NULL);
++ }
++ if (Scr.ColormapFocus == COLORMAP_FOLLOWS_MOUSE)
++ {
++ if (fw && !IS_ICONIFIED(fw) && ewp->window == FW_W(fw))
++ {
++ InstallWindowColormaps(fw);
++ }
++ else
++ {
++ /* make sure its for one of our windows */
++ /* handle a subwindow cmap */
++ InstallWindowColormaps(NULL);
++ }
++ }
++ else if (!fw)
++ {
++ EnterSubWindowColormap(ewp->window);
++ }
++ if (Scr.flags.is_wire_frame_displayed)
++ {
++ENTER_DBG((stderr, "en: exit: iwfd\n"));
++ /* Ignore EnterNotify events while a window is resized or
moved
++ * as a wire frame; otherwise the window list may be screwed
++ * up. */
++ return;
++ }
++ if (fw)
++ {
++ if (ewp->window != FW_W_FRAME(fw) &&
++ ewp->window != FW_W_PARENT(fw) &&
++ ewp->window != FW_W(fw) &&
++ ewp->window != FW_W_ICON_TITLE(fw) &&
++ ewp->window != FW_W_ICON_PIXMAP(fw))
++ {
++ /* Ignore EnterNotify that received by any of the sub
++ * windows that don't handle this event. unclutter
++ * triggers these events sometimes, re focusing an
++ * unfocused window under the pointer */
++ENTER_DBG((stderr, "en: exit: funny window\n"));
++ return;
++ }
++ }
++ if (Scr.focus_in_pending_window != NULL)
++ {
++ENTER_DBG((stderr, "en: exit: fipw\n"));
++ /* Ignore EnterNotify event while we are waiting for a window
to
++ * receive focus via Focus or FlipFocus commands. */
++ focus_grab_buttons(fw);
++ return;
++ }
++ if (ewp->mode == NotifyGrab)
++ {
++ENTER_DBG((stderr, "en: exit: NotifyGrab\n"));
++ return;
++ }
++ else if (ewp->mode == NotifyNormal)
++ {
++ENTER_DBG((stderr, "en: NotifyNormal\n"));
++ if (ewp->detail == NotifyNonlinearVirtual &&
++ ewp->focus == False && ewp->subwindow != None)
++ {
++ /* This takes care of some buggy apps that forget that
++ * one of their dialog subwindows has the focus after
++ * popping up a selection list several times (ddd,
++ * netscape). I'm not convinced that this does not
++ * break something else. */
++ENTER_DBG((stderr, "en: NN: refreshing focus\n"));
++ refresh_focus(fw);
++ }
++ }
++ else if (ewp->mode == NotifyUngrab)
++ {
++ENTER_DBG((stderr, "en: NotifyUngrab\n"));
++ /* Ignore events generated by grabbing or ungrabbing the
++ * pointer. However, there is no way to prevent the client
++ * application from handling this event and, for example,
++ * grabbing the focus. This will interfere with functions
that
++ * transferred the focus to a different window. */
++ if (is_initial_ungrab_pending)
++ {
++ENTER_DBG((stderr, "en: NU: initial ungrab pending (lgw = NULL)\n"));
++ is_initial_ungrab_pending = False;
++ xcrossing_last_grab_window = NULL;
++ }
++ else
++ {
++ if (ewp->detail == NotifyNonlinearVirtual &&
++ ewp->focus == False && ewp->subwindow != None)
++ {
++ /* see comment above */
++ENTER_DBG((stderr, "en: NU: refreshing focus\n"));
++ refresh_focus(fw);
++ }
++ if (fw && fw == xcrossing_last_grab_window)
++ {
++ENTER_DBG((stderr, "en: exit: NU: is last grab window\n"));
++ if (ewp->window == FW_W_FRAME(fw) ||
++ ewp->window == FW_W_ICON_TITLE(fw) ||
++ ewp->window == FW_W_ICON_PIXMAP(fw))
++ {
++ENTER_DBG((stderr, "en: exit: NU: last grab window = NULL\n"));
++ xcrossing_last_grab_window = NULL;
++ }
++ focus_grab_buttons(fw);
++
++ return;
++ }
++ else if (fw)
++ {
++ if (ewp->window != FW_W_FRAME(fw) &&
++ ewp->window != FW_W_ICON_TITLE(fw) &&
++ ewp->window != FW_W_ICON_PIXMAP(fw))
++ {
++ENTER_DBG((stderr, "en: exit: NU: not frame window\n"));
++ focus_grab_buttons(fw);
++ return;
++ }
++ }
++ }
++ }
++ if (fw)
++ {
++ is_initial_ungrab_pending = False;
++ }
++
++ /* look for a matching leaveNotify which would nullify this
EnterNotify
++ */
++ /*
++ * RBW - if we're in startup, this is a coerced focus, so we don't
++ * want to save the event time, or exit prematurely.
++ *
++ * Ignore LeaveNotify events for tear out menus - handled by menu code
++ */
++ is_tear_off_menu =
++ (fw && IS_TEAR_OFF_MENU(fw) && ewp->window == FW_W(fw));
++ if (!fFvwmInStartup && !is_tear_off_menu &&
++ FCheckTypedWindowEvent(dpy, ewp->window, LeaveNotify, &d))
++ {
++ if (d.xcrossing.mode == NotifyNormal &&
++ d.xcrossing.detail != NotifyInferior)
++ {
++ENTER_DBG((stderr, "en: exit: found LeaveNotify\n"));
++ return;
++ }
++ }
++
++ if (ewp->window == Scr.Root)
++ {
++ FvwmWindow *lf = get_last_screen_focus_window();
++
++ if (!Scr.flags.is_pointer_on_this_screen)
++ {
++ Scr.flags.is_pointer_on_this_screen = 1;
++ if (lf && lf != &Scr.FvwmRoot &&
++ !FP_DO_UNFOCUS_LEAVE(FW_FOCUS_POLICY(lf)))
++ {
++ SetFocusWindow(lf, True, FOCUS_SET_FORCE);
++ }
++ else if (lf != &Scr.FvwmRoot)
++ {
++ ForceDeleteFocus();
++ }
++ else
++ {
++ /* This was the first EnterNotify event for
the
++ * root window - ignore */
++ }
++ set_last_screen_focus_window(NULL);
++ }
++ else if (!(sf = get_focus_window()) ||
++ FP_DO_UNFOCUS_LEAVE(FW_FOCUS_POLICY(sf)))
++ {
++ DeleteFocus(True);
++ }
++ else if (
++ Scr.UnknownWinFocused != None && sf != NULL &&
++ FW_W(sf) == Scr.StolenFocusWin)
++ {
++ __refocus_stolen_focus_win(ea);
++ }
++ if (Scr.ColormapFocus == COLORMAP_FOLLOWS_MOUSE)
++ {
++ InstallWindowColormaps(NULL);
++ }
++ focus_grab_buttons(lf);
++ return;
++ }
++ else
++ {
++ Scr.flags.is_pointer_on_this_screen = 1;
++ }
++
++ /* An EnterEvent in one of the PanFrameWindows activates the Paging or
++ an EdgeCommand. */
++ if (is_pan_frame(ewp->window))
++ {
++ char *edge_command = NULL;
++
++ if (
++ Scr.UnknownWinFocused != None &&
++ (sf = get_focus_window()) != NULL &&
++ FW_W(sf) == Scr.StolenFocusWin)
++ {
++ __refocus_stolen_focus_win(ea);
++ }
++ /* check for edge commands */
++ if (ewp->window == Scr.PanFrameTop.win)
++ {
++ edge_command = Scr.PanFrameTop.command;
++ }
++ else if (ewp->window == Scr.PanFrameBottom.win)
++ {
++ edge_command = Scr.PanFrameBottom.command;
++ }
++ else if (ewp->window == Scr.PanFrameLeft.win)
++ {
++ edge_command = Scr.PanFrameLeft.command;
++ }
++ else if (ewp->window == Scr.PanFrameRight.win)
++ {
++ edge_command = Scr.PanFrameRight.command;
++ }
++ if (edge_command && ewp->mode == NotifyUngrab &&
++ ewp->detail == NotifyAncestor)
++ {
++ /* nothing */
++ }
++ else if (edge_command)
++ {
++ execute_function(NULL, ea->exc, edge_command, 0);
++ }
++ else
++ {
++ /* no edge command for this pan frame - so we do
++ * HandlePaging */
++ int delta_x = 0;
++ int delta_y = 0;
++ XEvent e;
++
++ /* this was in the HandleMotionNotify before, HEDU */
++ Scr.flags.is_pointer_on_this_screen = 1;
++ e = *te;
++ HandlePaging(
++ &e, Scr.EdgeScrollX, Scr.EdgeScrollY, &JunkX,
++ &JunkY, &delta_x, &delta_y, True, True,
False);
++ return;
++ }
++ }
++ if (!fw)
++ {
++ return;
++ }
++ if (IS_EWMH_DESKTOP(FW_W(fw)))
++ {
++ BroadcastPacket(
++ MX_ENTER_WINDOW, 3, (long)Scr.Root, (long)NULL,
++ (long)NULL);
++ return;
++ }
++ if (ewp->window == FW_W_FRAME(fw) ||
++ ewp->window == FW_W_ICON_TITLE(fw) ||
++ ewp->window == FW_W_ICON_PIXMAP(fw))
++ {
++ BroadcastPacket(
++ MX_ENTER_WINDOW, 3, (long)FW_W(fw),
++ (long)FW_W_FRAME(fw), (unsigned long)fw);
++ }
++ sf = get_focus_window();
++ if (sf && fw != sf && FP_DO_UNFOCUS_LEAVE(FW_FOCUS_POLICY(sf)))
++ {
++ENTER_DBG((stderr, "en: delete focus\n"));
++ DeleteFocus(True);
++ }
++ focus_grab_buttons(fw);
++ if (FP_DO_FOCUS_ENTER(FW_FOCUS_POLICY(fw)))
++ {
++ENTER_DBG((stderr, "en: set mousey focus\n"));
++ if (ewp->window == FW_W(fw))
++ {
++ /* Event is for the client window...*/
++#ifndef EXPERIMENTAL_ROU_HANDLING_V2
++ /* RBW -- This may still be needed at times, I'm not
++ *sure yet. */
++ SetFocusWindowClientEntered(
++ fw, True, FOCUS_SET_BY_ENTER);
++#else
++ SetFocusWindow(fw, True, FOCUS_SET_BY_ENTER);
++#endif
++ }
++ else
++ {
++ /* Event is for the frame...*/
++ SetFocusWindow(fw, True, FOCUS_SET_BY_ENTER);
++ }
++ }
++ else if (focus_is_focused(fw) && focus_does_accept_input_focus(fw))
++ {
++ /* We have to refresh the focus window here in case we left
the
++ * focused fvwm window. Motif apps may lose the input focus
++ * otherwise. But do not try to refresh the focus of
++ * applications that want to handle it themselves. */
++ focus_force_refresh_focus(fw);
++ }
++ else if (sf != fw)
++ {
++ /* Give the window a chance to grab the buttons needed for
++ * raise-on-click */
++ focus_grab_buttons(sf);
++ }
++ if (
++ Scr.UnknownWinFocused != None && sf != NULL &&
++ FW_W(sf) == Scr.StolenFocusWin)
++ {
++ __refocus_stolen_focus_win(ea);
++ }
++ /* We get an EnterNotify with mode == UnGrab when fvwm releases the
++ * grab held during iconification. We have to ignore this, or icon
++ * title will be initially raised. */
++ if (IS_ICONIFIED(fw) && (ewp->mode == NotifyNormal) &&
++ (ewp->window == FW_W_ICON_PIXMAP(fw) ||
++ ewp->window == FW_W_ICON_TITLE(fw)) &&
++ FW_W_ICON_PIXMAP(fw) != None)
++ {
++ SET_ICON_ENTERED(fw, 1);
++ DrawIconWindow(fw, True, False, False, False, NULL);
++ }
++ /* Check for tear off menus */
++ if (is_tear_off_menu)
++ {
++ menu_enter_tear_off_menu(ea->exc);
++ }
++
++ return;
++}
++
++void HandleExpose(const evh_args_t *ea)
++{
++ XEvent e;
++ FvwmWindow * const fw = ea->exc->w.fw;
++
++ e = *ea->exc->x.etrigger;
++#if 0
++ /* This doesn't work well. Sometimes, the expose count is zero
although
++ * dozens of expose events are pending. This happens all the time
++ * during a shading animation. Simply flush expose events
++ * unconditionally. */
++ if (e.xexpose.count != 0)
++ {
++ flush_accumulate_expose(e.xexpose.window, &e);
++ }
++#else
++ flush_accumulate_expose(e.xexpose.window, &e);
++#endif
++ if (fw == NULL)
++ {
++ return;
++ }
++ if (e.xany.window == FW_W_ICON_TITLE(fw) ||
++ e.xany.window == FW_W_ICON_PIXMAP(fw))
++ {
++ DrawIconWindow(fw, True, True, False, False, &e);
++ return;
++ }
++ else if (IS_TEAR_OFF_MENU(fw) && e.xany.window == FW_W(fw))
++ {
++ /* refresh the contents of the torn out menu */
++ menu_expose(&e, NULL);
++ }
++
++ return;
++}
++
++void HandleFocusIn(const evh_args_t *ea)
++{
++ XEvent d;
++ Window w = None;
++ Window focus_w = None;
++ Window focus_fw = None;
++ Pixel fc = 0;
++ Pixel bc = 0;
++ FvwmWindow *ffw_old = get_focus_window();
++ FvwmWindow *sf;
++ Bool do_force_broadcast = False;
++ Bool is_unmanaged_focused = False;
++ static Window last_focus_w = None;
++ static Window last_focus_fw = None;
++ static Bool was_nothing_ever_focused = True;
++ FvwmWindow *fw = ea->exc->w.fw;
++
++ DBUG("HandleFocusIn", "Routine Entered");
++
++ Scr.focus_in_pending_window = NULL;
++ /* This is a hack to make the PointerKey command work */
++ if (ea->exc->x.etrigger->xfocus.detail != NotifyPointer)
++ {
++ /**/
++ w = ea->exc->x.etrigger->xany.window;
++ }
++ while (FCheckTypedEvent(dpy, FocusIn, &d))
++ {
++ /* dito */
++ if (d.xfocus.detail != NotifyPointer)
++ {
++ /**/
++ w = d.xany.window;
++ }
++ }
++ /* dito */
++ if (w == None)
++ {
++ return;
++ }
++ /**/
++ if (XFindContext(dpy, w, FvwmContext, (caddr_t *) &fw) == XCNOENT)
++ {
++ fw = NULL;
++ }
++
++ Scr.UnknownWinFocused = None;
++ if (!fw)
++ {
++ if (w != Scr.NoFocusWin)
++ {
++ Scr.UnknownWinFocused = w;
++ Scr.StolenFocusWin =
++ (ffw_old != NULL) ? FW_W(ffw_old) : None;
++ focus_w = w;
++ is_unmanaged_focused = True;
++ }
++ /* Only show a non-focused window as focused,
++ * if the focus is on unmanaged and flickering qt dialogs
++ * workaround is on. */
++ if (!Scr.bo.do_enable_flickering_qt_dialogs_workaround ||
++ !is_unmanaged_focused)
++ {
++ border_draw_decorations(
++ Scr.Hilite, PART_ALL, False, True, CLEAR_ALL,
++ NULL, NULL);
++ if (Scr.ColormapFocus == COLORMAP_FOLLOWS_FOCUS)
++ {
++ if ((Scr.Hilite)&&(!IS_ICONIFIED(Scr.Hilite)))
++ {
++ InstallWindowColormaps(Scr.Hilite);
++ }
++ else
++ {
++ InstallWindowColormaps(NULL);
++ }
++ }
++ }
++ /* Not very useful if no window that fvwm and its modules know
++ * about has the focus. */
++ fc = GetColor(DEFAULT_FORE_COLOR);
++ bc = GetColor(DEFAULT_BACK_COLOR);
++ }
++ else if (fw != Scr.Hilite ||
++ /* domivogt (16-May-2000): This check is necessary to force
++ * sending a M_FOCUS_CHANGE packet after an unmanaged window
++ * was focused. Otherwise fvwm would believe that Scr.Hilite
++ * was still focused and not send any info to the modules. */
++ last_focus_fw == None ||
++ IS_FOCUS_CHANGE_BROADCAST_PENDING(fw))
++ {
++ do_force_broadcast = IS_FOCUS_CHANGE_BROADCAST_PENDING(fw);
++ SET_FOCUS_CHANGE_BROADCAST_PENDING(fw, 0);
++ if (fw != Scr.Hilite)
++ {
++ border_draw_decorations(
++ fw, PART_ALL, True, True, CLEAR_ALL, NULL,
++ NULL);
++ }
++ focus_w = FW_W(fw);
++ focus_fw = FW_W_FRAME(fw);
++ fc = fw->hicolors.fore;
++ bc = fw->hicolors.back;
++ set_focus_window(fw);
++ if (Scr.ColormapFocus == COLORMAP_FOLLOWS_FOCUS)
++ {
++ if ((Scr.Hilite)&&(!IS_ICONIFIED(Scr.Hilite)))
++ {
++ InstallWindowColormaps(Scr.Hilite);
++ }
++ else
++ {
++ InstallWindowColormaps(NULL);
++ }
++ }
++ }
++ else
++ {
++ return;
++ }
++ if (was_nothing_ever_focused || last_focus_fw == None ||
++ focus_w != last_focus_w || focus_fw != last_focus_fw ||
++ do_force_broadcast)
++ {
++ if (!Scr.bo.do_enable_flickering_qt_dialogs_workaround ||
++ !is_unmanaged_focused)
++ {
++ BroadcastPacket(
++ M_FOCUS_CHANGE, 5, (long)focus_w,
++ (long)focus_fw,
++ (unsigned long)IsLastFocusSetByMouse(),
++ (long)fc, (long)bc);
++ EWMH_SetActiveWindow(focus_w);
++ }
++ last_focus_w = focus_w;
++ last_focus_fw = focus_fw;
++ was_nothing_ever_focused = False;
++ }
++ if ((sf = get_focus_window()) != ffw_old)
++ {
++ focus_grab_buttons(sf);
++ focus_grab_buttons(ffw_old);
++ }
++
++ return;
++}
++
++void HandleFocusOut(const evh_args_t *ea)
++{
++ if (Scr.UnknownWinFocused != None && Scr.StolenFocusWin != None &&
++ ea->exc->x.etrigger->xfocus.window == Scr.UnknownWinFocused)
++ {
++ __refocus_stolen_focus_win(ea);
++ }
++
++ return;
++}
++
++void __handle_key(const evh_args_t *ea, Bool is_press)
++{
++ char *action;
++ FvwmWindow *sf;
++ KeyCode kc;
++ int kcontext;
++ const XEvent *te = ea->exc->x.etrigger;
++ const FvwmWindow * const fw = ea->exc->w.fw;
++ Bool is_second_binding;
++ const XClassHint *winClass1, *winClass2;
++ XClassHint tmp;
++ char *name1, *name2;
++ const exec_context_t *exc;
++ exec_context_changes_t ecc;
++
++ PressedW = None;
++
++ /* Here's a real hack - some systems have two keys with the
++ * same keysym and different keycodes. This converts all
++ * the cases to one keycode. */
++ kc = XKeysymToKeycode(dpy, XKeycodeToKeysym(dpy, te->xkey.keycode,
0));
++
++ /* Check if there is something bound to the key */
++
++ sf = get_focus_window();
++ if (sf == NULL)
++ {
++ tmp.res_name = tmp.res_class = name1 = "root";
++ winClass1 = &tmp;
++ kcontext = C_ROOT;
++ }
++ else
++ {
++ winClass1 = &sf->class;
++ name1 = sf->name.name;
++ kcontext = (sf == fw ? ea->exc->w.wcontext : C_WINDOW);
++ }
++
++ if (fw == NULL)
++ {
++ tmp.res_name = tmp.res_class = name2 = "root";
++ winClass2 = &tmp;
++ }
++ else
++ {
++ winClass2 = &fw->class;
++ name2 = fw->name.name;
++ }
++ /* Searching the binding list with a different 'type' value
++ * (ie. BIND_KEYPRESS vs BIND_PKEYPRESS) doesn't make a difference.
++ * The different context value does though. */
++ action = CheckTwoBindings(
++ &is_second_binding, Scr.AllBindings, STROKE_ARG(0) kc,
++ te->xkey.state, GetUnusedModifiers(), kcontext, BIND_KEYPRESS,
++ winClass1, name1, ea->exc->w.wcontext, BIND_PKEYPRESS,
++ winClass2, name2);
++
++ if (action != NULL)
++ {
++ if (!is_press)
++ {
++ XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
++ return;
++ }
++ exc = ea->exc;
++ if (is_second_binding == False)
++ {
++ ecc.w.fw = sf;
++ ecc.w.wcontext = kcontext;
++ exc = exc_clone_context(
++ ea->exc, &ecc, ECC_FW | ECC_WCONTEXT);
++ }
++ execute_function(NULL, exc, action, 0);
++ if (is_second_binding == False)
++ {
++ exc_destroy_context(exc);
++ }
++ XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
++ return;
++ }
++
++ /* if we get here, no function key was bound to the key. Send it
++ * to the client if it was in a window we know about. */
++ sf = get_focus_window();
++ if (sf && te->xkey.window != FW_W(sf))
++ {
++ XEvent e;
++
++ e = *te;
++ e.xkey.window = FW_W(sf);
++ FSendEvent(
++ dpy, e.xkey.window, False,
++ (is_press)? KeyPressMask:KeyReleaseMask, &e);
++ }
++ else if (fw && te->xkey.window != FW_W(fw))
++ {
++ XEvent e;
++
++ e = *te;
++ e.xkey.window = FW_W(fw);
++ FSendEvent(
++ dpy, e.xkey.window, False,
++ (is_press)? KeyPressMask:KeyReleaseMask, &e);
++ }
++ XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
++
++ return;
++}
++
++void HandleKeyPress(const evh_args_t *ea)
++{
++ __handle_key(ea, True);
++}
++
++void HandleKeyRelease(const evh_args_t *ea)
++{
++ __handle_key(ea, False);
++}
++
++void HandleLeaveNotify(const evh_args_t *ea)
++{
++ const XEvent *te = ea->exc->x.etrigger;
++ FvwmWindow * const fw = ea->exc->w.fw;
++
++ DBUG("HandleLeaveNotify", "Routine Entered");
++
++ENTER_DBG((stderr, "-------- ln (%d): fw 0x%08x w 0x%08x sw 0x%08x mode
0x%x detail 0x%x '%s'\n", ++ecount, (int)fw, (int)te->xcrossing.window,
(int)te->xcrossing.subwindow, te->xcrossing.mode, te->xcrossing.detail,
fw?fw->visible_name:"(none)"));
++ /* Ignore LeaveNotify events while a window is resized or moved as a
++ * wire frame; otherwise the window list may be screwed up. */
++ if (Scr.flags.is_wire_frame_displayed)
++ {
++ return;
++ }
++ if (te->xcrossing.mode != NotifyNormal)
++ {
++ /* Ignore events generated by grabbing or ungrabbing the
++ * pointer. However, there is no way to prevent the client
++ * application from handling this event and, for example,
++ * grabbing the focus. This will interfere with functions
that
++ * transferred the focus to a different window. It is
++ * necessary to check for LeaveNotify events on the client
++ * window too in case buttons are not grabbed on it. */
++ if (te->xcrossing.mode == NotifyGrab && fw &&
++ (te->xcrossing.window == FW_W_FRAME(fw) ||
++ te->xcrossing.window == FW_W(fw) ||
++ te->xcrossing.window == FW_W_ICON_TITLE(fw) ||
++ te->xcrossing.window == FW_W_ICON_PIXMAP(fw)))
++ {
++ENTER_DBG((stderr, "ln: *** lgw = 0x%08x\n", (int)fw));
++ xcrossing_last_grab_window = fw;
++ }
++#ifdef FOCUS_EXPANDS_TITLE
++ if (fw && IS_ICONIFIED(fw))
++ {
++ SET_ICON_ENTERED(fw, 0);
++ DrawIconWindow(
++ fw, True, False, False, False, NULL);
++ }
++#endif
++ return;
++ }
++ /* CDE-like behaviour of raising the icon title if the icon
++ gets the focus (in particular if the cursor is over the icon) */
++ if (fw && IS_ICONIFIED(fw))
++ {
++ SET_ICON_ENTERED(fw,0);
++ DrawIconWindow(fw, True, False, False, False, NULL);
++ }
++
++ /* An LeaveEvent in one of the PanFrameWindows activates
++ an EdgeLeaveCommand. */
++ if (is_pan_frame(te->xcrossing.window))
++ {
++ char *edge_command_leave = NULL;
++
++ /* check for edge commands */
++ if (te->xcrossing.window == Scr.PanFrameTop.win)
++ {
++ edge_command_leave = Scr.PanFrameTop.command_leave;
++ }
++ else if (te->xcrossing.window == Scr.PanFrameBottom.win)
++ {
++ edge_command_leave = Scr.PanFrameBottom.command_leave;
++ }
++ else if (te->xcrossing.window == Scr.PanFrameLeft.win)
++ {
++ edge_command_leave = Scr.PanFrameLeft.command_leave;
++ }
++ else if (te->xcrossing.window == Scr.PanFrameRight.win)
++ {
++ edge_command_leave = Scr.PanFrameRight.command_leave;
++ }
++ if (edge_command_leave && te->xcrossing.mode == NotifyUngrab
&&
++ te->xcrossing.detail == NotifyAncestor)
++ {
++ /* nothing */
++ }
++ else if (edge_command_leave)
++ {
++ execute_function(NULL, ea->exc, edge_command_leave,
0);
++ }
++ }
++
++
++ /* If we leave the root window, then we're really moving
++ * another screen on a multiple screen display, and we
++ * need to de-focus and unhighlight to make sure that we
++ * don't end up with more than one highlighted window at a time */
++ if (te->xcrossing.window == Scr.Root &&
++ /* domivogt (16-May-2000): added this test because somehow fvwm
++ * sometimes gets a LeaveNotify on the root window although it is
++ * single screen. */
++ Scr.NumberOfScreens > 1)
++ {
++ if (te->xcrossing.mode == NotifyNormal)
++ {
++ if (te->xcrossing.detail != NotifyInferior)
++ {
++ FvwmWindow *sf = get_focus_window();
++
++ Scr.flags.is_pointer_on_this_screen = 0;
++ set_last_screen_focus_window(sf);
++ if (sf != NULL)
++ {
++ DeleteFocus(True);
++ }
++ if (Scr.Hilite != NULL)
++ {
++ border_draw_decorations(
++ Scr.Hilite, PART_ALL, False,
++ True, CLEAR_ALL, NULL, NULL);
++ }
++ }
++ }
++ }
++ else
++ {
++ /* handle a subwindow cmap */
++ LeaveSubWindowColormap(te->xany.window);
++ }
++ if (fw != NULL &&
++ (te->xcrossing.window == FW_W_FRAME(fw) ||
++ te->xcrossing.window == FW_W_ICON_TITLE(fw) ||
++ te->xcrossing.window == FW_W_ICON_PIXMAP(fw)))
++ {
++ BroadcastPacket(
++ MX_LEAVE_WINDOW, 3, (long)FW_W(fw),
++ (long)FW_W_FRAME(fw), (unsigned long)fw);
++ }
++
++ return;
++}
++
++void HandleMapNotify(const evh_args_t *ea)
++{
++ Bool is_on_this_page = False;
++ const XEvent *te = ea->exc->x.etrigger;
++ FvwmWindow * const fw = ea->exc->w.fw;
++
++ DBUG("HandleMapNotify", "Routine Entered");
++
++ if (!fw)
++ {
++ if (te->xmap.override_redirect == True &&
++ te->xmap.window != Scr.NoFocusWin)
++ {
++ XSelectInput(dpy, te->xmap.window, XEVMASK_ORW);
++ XFlush(dpy);
++ Scr.UnknownWinFocused = te->xmap.window;
++ }
++ return;
++ }
++ if (te->xmap.window == FW_W_FRAME(fw))
++ {
++ /* Now that we know the frame is mapped after capturing the
++ * window we do not need StructureNotifyMask events anymore.
*/
++ XSelectInput(dpy, FW_W_FRAME(fw), XEVMASK_FRAMEW);
++ XFlush(dpy);
++ }
++ /* Except for identifying over-ride redirect window mappings, we
++ * don't need or want windows associated with the
++ * SubstructureNotifyMask */
++ if (te->xmap.event != te->xmap.window)
++ {
++ return;
++ }
++ SET_MAP_PENDING(fw, 0);
++ /* don't map if the event was caused by a de-iconify */
++ if (IS_ICONIFY_PENDING(fw))
++ {
++ return;
++ }
++
++ /* Make sure at least part of window is on this page before giving it
++ * focus... */
++ is_on_this_page = IsRectangleOnThisPage(&(fw->g.frame), fw->Desk);
++
++ /*
++ * Need to do the grab to avoid race condition of having server send
++ * MapNotify to client before the frame gets mapped; this is bad
because
++ * the client would think that the window has a chance of being
viewable
++ * when it really isn't.
++ */
++ MyXGrabServer (dpy);
++ 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));
++ }
++ XMapSubwindows(dpy, FW_W_FRAME(fw));
++ if (fw->Desk == Scr.CurrentDesk)
++ {
++ XMapWindow(dpy, FW_W_FRAME(fw));
++ }
++ if (IS_ICONIFIED(fw))
++ {
++ BroadcastPacket(
++ M_DEICONIFY, 3, (long)FW_W(fw), (long)FW_W_FRAME(fw),
++ (unsigned long)fw);
++ }
++ else
++ {
++ BroadcastPacket(
++ M_MAP, 3, (long)FW_W(fw), (long)FW_W_FRAME(fw),
++ (unsigned long)fw);
++ }
++
++ if (is_on_this_page &&
++ focus_query_open_grab_focus(fw, get_focus_window()) == True)
++ {
++ SetFocusWindow(fw, True, FOCUS_SET_FORCE);
++ }
++ border_draw_decorations(
++ fw, PART_ALL, (fw == get_focus_window()) ? True : False, True,
++ CLEAR_ALL, NULL, NULL);
++ MyXUngrabServer (dpy);
++ SET_MAPPED(fw, 1);
++ SET_ICONIFIED(fw, 0);
++ SET_ICON_UNMAPPED(fw, 0);
++ if (DO_ICONIFY_AFTER_MAP(fw))
++ {
++ initial_window_options_t win_opts;
++
++ /* finally, if iconification was requested before the window
++ * was mapped, request it now. */
++ memset(&win_opts, 0, sizeof(win_opts));
++ Iconify(fw, &win_opts);
++ SET_ICONIFY_AFTER_MAP(fw, 0);
++ }
++ focus_grab_buttons_on_layer(fw->layer);
++
++ return;
++}
++
++void HandleMappingNotify(const evh_args_t *ea)
++{
++ XRefreshKeyboardMapping(&ea->exc->x.etrigger->xmapping);
++
++ return;
++}
++
++void HandleMapRequest(const evh_args_t *ea)
++{
++ DBUG("HandleMapRequest", "Routine Entered");
++
++ if (fFvwmInStartup)
++ {
++ /* Just map the damn thing, decorations are added later
++ * in CaptureAllWindows. */
++ XMapWindow(dpy, ea->exc->x.etrigger->xmaprequest.window);
++ return;
++ }
++ HandleMapRequestKeepRaised(ea, None, NULL, NULL);
++
++ return;
++}
++
++void HandleMapRequestKeepRaised(
++ const evh_args_t *ea, Window KeepRaised, FvwmWindow *ReuseWin,
++ initial_window_options_t *win_opts)
++{
++ Bool is_on_this_page = False;
++ Bool is_new_window = False;
++ FvwmWindow *tmp;
++ FvwmWindow *sf;
++ initial_window_options_t win_opts_bak;
++ Window ew;
++ FvwmWindow *fw;
++
++ if (win_opts == NULL)
++ {
++ memset(&win_opts_bak, 0, sizeof(win_opts_bak));
++ win_opts = &win_opts_bak;
++ }
++ ew = ea->exc->w.w;
++ if (ReuseWin == NULL)
++ {
++ Window pw;
++
++ pw = ea->exc->x.etrigger->xmaprequest.parent;
++ if (XFindContext(dpy, ew, FvwmContext, (caddr_t *)&fw) ==
++ XCNOENT)
++ {
++ fw = NULL;
++ }
++ if (fw != NULL && IS_MAP_PENDING(fw))
++ {
++ /* The window is already going to be mapped, no need
to
++ * do that twice */
++ return;
++ }
++ }
++ else
++ {
++ fw = ReuseWin;
++ }
++
++ if (fw == NULL && EWMH_IsKdeSysTrayWindow(ew))
++ {
++ /* This means that the window is swallowed by kicker and that
++ * kicker restart or exit. As we should assume that kicker
++ * restart we should return here, if not we go into trouble
++ * ... */
++ return;
++ }
++ if (!win_opts->flags.do_override_ppos)
++ {
++ XFlush(dpy);
++ }
++
++ /* If the window has never been mapped before ... */
++ if (!fw || (fw && DO_REUSE_DESTROYED(fw)))
++ {
++ /* Add decorations. */
++ fw = AddWindow(ea->exc, ReuseWin, win_opts);
++ if (fw == AW_NO_WINDOW)
++ {
++ return;
++ }
++ else if (fw == AW_UNMANAGED)
++ {
++ XMapWindow(dpy, ew);
++ return;
++ }
++ is_new_window = True;
++ }
++ /*
++ * Make sure at least part of window is on this page
++ * before giving it focus...
++ */
++ is_on_this_page = IsRectangleOnThisPage(&(fw->g.frame), fw->Desk);
++ if (KeepRaised != None)
++ {
++ XRaiseWindow(dpy, KeepRaised);
++ }
++ /* If it's not merely iconified, and we have hints, use them. */
++
++ if (IS_ICONIFIED(fw))
++ {
++ /* If no hints, or currently an icon, just "deiconify" */
++ DeIconify(fw);
++ }
++ else if (IS_MAPPED(fw))
++ {
++ /* the window is already mapped - fake a MapNotify event */
++ fake_map_unmap_notify(fw, MapNotify);
++ }
++ else
++ {
++ int state;
++
++ if (fw->wmhints && (fw->wmhints->flags & StateHint))
++ {
++ state = fw->wmhints->initial_state;
++ }
++ else
++ {
++ state = NormalState;
++ }
++ if (win_opts->initial_state != DontCareState)
++ {
++ state = win_opts->initial_state;
++ }
++
++ switch (state)
++ {
++ case DontCareState:
++ case NormalState:
++ case InactiveState:
++ default:
++ MyXGrabServer(dpy);
++ if (fw->Desk == Scr.CurrentDesk)
++ {
++ Bool do_grab_focus;
++
++ SET_MAP_PENDING(fw, 1);
++ XMapWindow(dpy, FW_W_FRAME(fw));
++ XMapWindow(dpy, FW_W(fw));
++ SetMapStateProp(fw, NormalState);
++ if (Scr.flags.is_map_desk_in_progress)
++ {
++ do_grab_focus = False;
++ }
++ else if (!is_on_this_page)
++ {
++ do_grab_focus = False;
++ }
++ else if (focus_query_open_grab_focus(
++ fw, get_focus_window()) ==
++ True)
++ {
++ do_grab_focus = True;
++ }
++ else
++ {
++ do_grab_focus = False;
++ }
++ if (do_grab_focus)
++ {
++ SetFocusWindow(
++ fw, True, FOCUS_SET_FORCE);
++ }
++ else
++ {
++ /* make sure the old focused window
++ * still has grabbed all necessary
++ * buttons. */
++ focus_grab_buttons(
++ get_focus_window());
++ }
++ }
++ else
++ {
++#ifndef ICCCM2_UNMAP_WINDOW_PATCH
++ /* nope, this is forbidden by the ICCCM2 */
++ XMapWindow(dpy, FW_W(fw));
++ SetMapStateProp(fw, NormalState);
++#else
++ /* Since we will not get a MapNotify, set the
++ * IS_MAPPED flag manually. */
++ SET_MAPPED(fw, 1);
++ SetMapStateProp(fw, IconicState);
++ /* fake that the window was mapped to allow
++ * modules to swallow it */
++ BroadcastPacket(
++ M_MAP, 3, (long)FW_W(fw),
++ (long)FW_W_FRAME(fw),
++ (unsigned long)fw);
++#endif
++ }
++ MyXUngrabServer(dpy);
++ break;
++
++ case IconicState:
++ if (is_new_window)
++ {
++ /* the window will not be mapped - fake a
++ * MapNotify and an UnmapNotify event. Can't
++ * remember exactly why this is necessary, but
++ * probably something w/ (de)iconify state
++ * confusion. */
++ fake_map_unmap_notify(fw, MapNotify);
++ fake_map_unmap_notify(fw, UnmapNotify);
++ }
++ if (win_opts->flags.is_iconified_by_parent ||
++ ((tmp = get_transientfor_fvwmwindow(fw)) &&
++ IS_ICONIFIED(tmp)))
++ {
++ win_opts->flags.is_iconified_by_parent = 0;
++ SET_ICONIFIED_BY_PARENT(fw, 1);
++ }
++ if (USE_ICON_POSITION_HINT(fw) && fw->wmhints &&
++ (fw->wmhints->flags & IconPositionHint))
++ {
++ win_opts->default_icon_x =
fw->wmhints->icon_x;
++ win_opts->default_icon_y =
fw->wmhints->icon_y;
++ }
++ Iconify(fw, win_opts);
++ break;
++ }
++ }
++ if (IS_SHADED(fw))
++ {
++ BroadcastPacket(
++ M_WINDOWSHADE, 3, (long)FW_W(fw),
(long)FW_W_FRAME(fw),
++ (unsigned long)fw);
++ }
++ /* If the newly mapped window overlaps the focused window, make sure
++ * ClickToFocusRaises and MouseFocusClickRaises work again. */
++ sf = get_focus_window();
++ if (sf != NULL)
++ {
++ focus_grab_buttons(sf);
++ }
++ if (win_opts->flags.is_menu)
++ {
++ SET_MAPPED(fw, 1);
++ SET_MAP_PENDING(fw, 0);
++ }
++ EWMH_SetClientList();
++ EWMH_SetClientListStacking();
++ GNOME_SetClientList();
++
++ return;
++}
++
++#ifdef HAVE_STROKE
++void HandleMotionNotify(const evh_args_t *ea)
++{
++ DBUG("HandleMotionNotify", "Routine Entered");
++
++ if (send_motion == True)
++ {
++ stroke_record(
++ ea->exc->x.etrigger->xmotion.x,
++ ea->exc->x.etrigger->xmotion.y);
++ }
++
++ return;
++}
++#endif /* HAVE_STROKE */
++
++void HandlePropertyNotify(const evh_args_t *ea)
++{
++ Bool OnThisPage = False;
++ Bool has_icon_changed = False;
++ Bool has_icon_pixmap_hint_changed = False;
++ Bool has_icon_window_hint_changed = False;
++ FlocaleNameString new_name = { NoName, NULL };
++ int old_wmhints_flags;
++ const XEvent *te = ea->exc->x.etrigger;
++ char *urgency_action = NULL;
++ FvwmWindow * const fw = ea->exc->w.fw;
++
++ DBUG("HandlePropertyNotify", "Routine Entered");
++
++ if (te->xproperty.window == Scr.Root &&
++ te->xproperty.state == PropertyNewValue &&
++ (te->xproperty.atom == _XA_XSETROOT_ID ||
++ te->xproperty.atom == _XA_XROOTPMAP_ID))
++ {
++ /* background change */
++ /* _XA_XSETROOT_ID is used by fvwm-root, xli and more (xv
sends
++ * no property notify?). _XA_XROOTPMAP_ID is used by
Esetroot
++ * compatible program: the problem here is that with some
++ * Esetroot compatible program we get the message _before_ the
++ * background change. This is fixed with Esetroot 9.2 (not yet
++ * released, 2002-01-14) */
++
++ /* update icon window with some alpha and tear-off menu */
++ FvwmWindow *t;
++
++ for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
++ {
++ int cs;
++ int t_cs = -1;
++ int b_cs = t->icon_background_cs;
++ Bool draw_picture = False;
++ Bool draw_title = False;
++
++ /* redraw ParentRelative tear-off menu */
++ menu_redraw_transparent_tear_off_menu(t, True);
++
++ if (!IS_ICONIFIED(t) || IS_ICON_SUPPRESSED(t))
++ {
++ continue;
++ }
++ if (Scr.Hilite == t)
++ {
++ if (t->icon_title_cs_hi >= 0)
++ {
++ t_cs = cs = t->icon_title_cs_hi;
++ }
++ else
++ {
++ cs = t->cs_hi;
++ }
++ }
++ else
++ {
++ if (t->icon_title_cs >= 0)
++ {
++ t_cs = cs = t->icon_title_cs;
++ }
++ else
++ {
++ cs = t->cs;
++ }
++ }
++ if (t->icon_alphaPixmap != None ||
++ (cs >= 0 &&
++ Colorset[cs].icon_alpha_percent < 100) ||
++ CSET_IS_TRANSPARENT_PR(b_cs) ||
++ (!IS_ICON_SHAPED(t) &&
++ t->icon_background_padding > 0))
++ {
++ draw_picture = True;
++ }
++ if (CSET_IS_TRANSPARENT_PR(t_cs))
++ {
++ draw_title = True;
++ }
++ if (draw_title || draw_picture)
++ {
++ DrawIconWindow(
++ t, draw_title, draw_picture, False,
++ draw_picture, NULL);
++ }
++ }
++ if (te->xproperty.atom == _XA_XROOTPMAP_ID)
++ {
++ update_root_transparent_colorset(te->xproperty.atom);
++ }
++ BroadcastPropertyChange(
++ MX_PROPERTY_CHANGE_BACKGROUND, 0, 0, "");
++ return;
++ }
++
++ if (!fw)
++ {
++ return;
++ }
++ if (XGetGeometry(
++ dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
++ (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
++ (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth) == 0)
++ {
++ return;
++ }
++
++ /*
++ * Make sure at least part of window is on this page
++ * before giving it focus...
++ */
++ OnThisPage = IsRectangleOnThisPage(&(fw->g.frame), fw->Desk);
++
++ switch (te->xproperty.atom)
++ {
++ case XA_WM_TRANSIENT_FOR:
++ flush_property_notify(XA_WM_TRANSIENT_FOR, FW_W(fw));
++ if (setup_transientfor(fw) == True)
++ {
++ RaiseWindow(fw);
++ }
++ break;
++
++ case XA_WM_NAME:
++ flush_property_notify(XA_WM_NAME, FW_W(fw));
++ if (HAS_EWMH_WM_NAME(fw))
++ {
++ return;
++ }
++ FlocaleGetNameProperty(XGetWMName, dpy, FW_W(fw), &new_name);
++ if (new_name.name == NULL)
++ {
++ FlocaleFreeNameProperty(&new_name);
++ return;
++ }
++ if (strlen(new_name.name) > MAX_WINDOW_NAME_LEN)
++ {
++ /* limit to prevent hanging X server */
++ (new_name.name)[MAX_WINDOW_NAME_LEN] = 0;
++ }
++ if (fw->name.name && strcmp(new_name.name, fw->name.name) ==
0)
++ {
++ /* migo: some apps update their names every second */
++ /* griph: make sure we don't free the property if it
++ is THE same name */
++ if (new_name.name != fw->name.name)
++ {
++ FlocaleFreeNameProperty(&new_name);
++ }
++ return;
++ }
++
++ free_window_names(fw, True, False);
++ fw->name = new_name;
++ SET_NAME_CHANGED(fw, 1);
++ if (fw->name.name == NULL)
++ {
++ fw->name.name = NoName; /* must not happen */
++ }
++ setup_visible_name(fw, False);
++ BroadcastWindowIconNames(fw, True, False);
++
++ /* fix the name in the title bar */
++ if (!IS_ICONIFIED(fw))
++ {
++ border_draw_decorations(
++ fw, PART_TITLE, (Scr.Hilite == fw), True,
++ CLEAR_ALL, NULL, NULL);
++ }
++ EWMH_SetVisibleName(fw, False);
++ /*
++ * if the icon name is NoName, set the name of the icon to be
++ * the same as the window
++ */
++ if (!WAS_ICON_NAME_PROVIDED(fw))
++ {
++ fw->icon_name = fw->name;
++ setup_visible_name(fw, True);
++ BroadcastWindowIconNames(fw, False, True);
++ RedoIconName(fw);
++ }
++ break;
++
++ case XA_WM_ICON_NAME:
++ flush_property_notify(XA_WM_ICON_NAME, FW_W(fw));
++ if (HAS_EWMH_WM_ICON_NAME(fw))
++ {
++ return;
++ }
++ FlocaleGetNameProperty(
++ XGetWMIconName, dpy, FW_W(fw), &new_name);
++ if (new_name.name == NULL)
++ {
++ FlocaleFreeNameProperty(&new_name);
++ return;
++ }
++ if (new_name.name && strlen(new_name.name) >
MAX_ICON_NAME_LEN)
++ {
++ /* limit to prevent hanging X server */
++ (new_name.name)[MAX_ICON_NAME_LEN] = 0;
++ }
++ if (fw->icon_name.name &&
++ strcmp(new_name.name, fw->icon_name.name) == 0)
++ {
++ /* migo: some apps update their names every second */
++ /* griph: make sure we don't free the property if it
++ is THE same name */
++ if (new_name.name != fw->icon_name.name)
++ {
++ FlocaleFreeNameProperty(&new_name);
++ }
++ return;
++ }
++
++ free_window_names(fw, False, True);
++ fw->icon_name = new_name;
++ SET_WAS_ICON_NAME_PROVIDED(fw, 1);
++ if (fw->icon_name.name == NULL)
++ {
++ /* currently never happens */
++ fw->icon_name.name = fw->name.name;
++ SET_WAS_ICON_NAME_PROVIDED(fw, 0);
++ }
++ setup_visible_name(fw, True);
++ BroadcastWindowIconNames(fw, False, True);
++ RedoIconName(fw);
++ EWMH_SetVisibleName(fw, True);
++ break;
++
++ case XA_WM_HINTS:
++ flush_property_notify(XA_WM_HINTS, FW_W(fw));
++ /* clasen AT mathematik.uni-freiburg.de - 02/01/1998 - new -
++ * the urgency flag is an ICCCM 2.0 addition to the WM_HINTS.
++ */
++ old_wmhints_flags = 0;
++ if (fw->wmhints)
++ {
++ old_wmhints_flags = fw->wmhints->flags;
++ XFree ((char *) fw->wmhints);
++ }
++ setup_wm_hints(fw);
++ if (fw->wmhints == NULL)
++ {
++ return;
++ }
++
++ /*
++ * rebuild icon if the client either provides an icon
++ * pixmap or window or has reset the hints to `no icon'.
++ */
++ if ((fw->wmhints->flags & IconPixmapHint) ||
++ (old_wmhints_flags & IconPixmapHint))
++ {
++ICON_DBG((stderr, "hpn: iph changed (%d) '%s'\n",
!!(int)(fw->wmhints->flags & IconPixmapHint), fw->name));
++ has_icon_pixmap_hint_changed = True;
++ }
++ if ((fw->wmhints->flags & IconWindowHint) ||
++ (old_wmhints_flags & IconWindowHint))
++ {
++ICON_DBG((stderr, "hpn: iwh changed (%d) '%s'\n",
!!(int)(fw->wmhints->flags & IconWindowHint), fw->name));
++ has_icon_window_hint_changed = True;
++ SET_USE_EWMH_ICON(fw, False);
++ }
++ increase_icon_hint_count(fw);
++ if (has_icon_window_hint_changed ||
++ has_icon_pixmap_hint_changed)
++ {
++ if (ICON_OVERRIDE_MODE(fw) == ICON_OVERRIDE)
++ {
++ICON_DBG((stderr, "hpn: icon override '%s'\n", fw->name));
++ has_icon_changed = False;
++ }
++ else if (ICON_OVERRIDE_MODE(fw) ==
++ NO_ACTIVE_ICON_OVERRIDE)
++ {
++ if (has_icon_pixmap_hint_changed)
++ {
++ if (WAS_ICON_HINT_PROVIDED(fw) ==
++ ICON_HINT_MULTIPLE)
++ {
++ICON_DBG((stderr, "hpn: using further iph '%s'\n", fw->name));
++ has_icon_changed = True;
++ }
++ else if (fw->icon_bitmap_file ==
++ NULL ||
++ fw->icon_bitmap_file ==
++ Scr.DefaultIcon)
++ {
++ICON_DBG((stderr, "hpn: using first iph '%s'\n", fw->name));
++ has_icon_changed = True;
++ }
++ else
++ {
++ /* ignore the first icon
pixmap
++ * hint if the application did
++ * not provide it from the
++ * start */
++ICON_DBG((stderr, "hpn: first iph ignored '%s'\n", fw->name));
++ has_icon_changed = False;
++ }
++ }
++ else if (has_icon_window_hint_changed)
++ {
++ICON_DBG((stderr, "hpn: using iwh '%s'\n", fw->name));
++ has_icon_changed = True;
++ }
++ else
++ {
++ICON_DBG((stderr, "hpn: iwh not changed, hint ignored '%s'\n", fw->name));
++ has_icon_changed = False;
++ }
++ }
++ else /* NO_ICON_OVERRIDE */
++ {
++ICON_DBG((stderr, "hpn: using hint '%s'\n", fw->name));
++ has_icon_changed = True;
++ }
++
++ if (USE_EWMH_ICON(fw))
++ {
++ has_icon_changed = False;
++ }
++
++ if (has_icon_changed)
++ {
++ICON_DBG((stderr, "hpn: icon changed '%s'\n", fw->name));
++ /* Okay, the icon hint has changed and style
++ * options tell us to honour this change. Now
++ * let's see if we have to use the application
++ * provided pixmap or window (if any), the
icon
++ * file provided by the window's style or the
++ * default style's icon. */
++ if (fw->icon_bitmap_file == Scr.DefaultIcon)
++ {
++ fw->icon_bitmap_file = NULL;
++ }
++ if (!fw->icon_bitmap_file &&
++ !(fw->wmhints->flags &
++ (IconPixmapHint|IconWindowHint)))
++ {
++ fw->icon_bitmap_file =
++ (Scr.DefaultIcon) ?
++ Scr.DefaultIcon : NULL;
++ }
++ fw->iconPixmap = (Window)NULL;
++ ChangeIconPixmap(fw);
++ }
++ }
++
++ /* clasen AT mathematik.uni-freiburg.de - 02/01/1998 - new -
++ * the urgency flag is an ICCCM 2.0 addition to the WM_HINTS.
++ * Treat urgency changes by calling user-settable functions.
++ * These could e.g. deiconify and raise the window or
++ * temporarily change the decor. */
++ if (!(old_wmhints_flags & XUrgencyHint) &&
++ (fw->wmhints->flags & XUrgencyHint))
++ {
++ urgency_action = "Function UrgencyFunc";
++ }
++ if ((old_wmhints_flags & XUrgencyHint) &&
++ !(fw->wmhints->flags & XUrgencyHint))
++ {
++ urgency_action = "Function UrgencyDoneFunc";
++ }
++ if (urgency_action)
++ {
++ const exec_context_t *exc;
++ exec_context_changes_t ecc;
++
++ ecc.w.fw = fw;
++ ecc.w.wcontext = C_WINDOW;
++ exc = exc_clone_context(
++ ea->exc, &ecc, ECC_FW | ECC_WCONTEXT);
++ execute_function(NULL, exc, urgency_action, 0);
++ exc_destroy_context(exc);
++ }
++ break;
++ case XA_WM_NORMAL_HINTS:
++ /* just mark wm normal hints as changed and look them up when
++ * the next ConfigureRequest w/ x, y, width or height set
++ * arrives. */
++ SET_HAS_NEW_WM_NORMAL_HINTS(fw, 1);
++ break;
++ default:
++ if (te->xproperty.atom == _XA_WM_PROTOCOLS)
++ {
++ FetchWmProtocols (fw);
++ }
++ else if (te->xproperty.atom == _XA_WM_COLORMAP_WINDOWS)
++ {
++ FetchWmColormapWindows (fw); /* frees old data */
++ ReInstallActiveColormap();
++ }
++ else if (te->xproperty.atom == _XA_WM_STATE)
++ {
++ if (fw && OnThisPage && focus_is_focused(fw) &&
++ FP_DO_FOCUS_ENTER(FW_FOCUS_POLICY(fw)))
++ {
++ /* refresh the focus - why? */
++ focus_force_refresh_focus(fw);
++ }
++ }
++ else
++ {
++ EWMH_ProcessPropertyNotify(ea->exc);
++ }
++ break;
++ }
++}
++
++void HandleReparentNotify(const evh_args_t *ea)
++{
++ const XEvent *te = ea->exc->x.etrigger;
++ FvwmWindow * const fw = ea->exc->w.fw;
++
++ if (!fw)
++ {
++ return;
++ }
++ if (te->xreparent.parent == Scr.Root)
++ {
++ /* Ignore reparenting to the root window. In some cases these
++ * events are selected although the window is no longer
++ * managed. */
++ return;
++ }
++ if (te->xreparent.parent != FW_W_FRAME(fw))
++ {
++ /* window was reparented by someone else, destroy the frame */
++ SetMapStateProp(fw, WithdrawnState);
++ EWMH_RestoreInitialStates(fw, te->type);
++ if (!IS_TEAR_OFF_MENU(fw))
++ {
++ XRemoveFromSaveSet(dpy, te->xreparent.window);
++ XSelectInput(dpy, te->xreparent.window, NoEventMask);
++ }
++ else
++ {
++ XSelectInput(dpy, te->xreparent.window,
XEVMASK_MENUW);
++ }
++ discard_events(XEVMASK_FRAMEW);
++ destroy_window(fw);
++ EWMH_ManageKdeSysTray(te->xreparent.window, te->type);
++ EWMH_WindowDestroyed();
++ }
++
++ return;
++}
++
++void HandleSelectionRequest(const evh_args_t *ea)
++{
++ icccm2_handle_selection_request(ea->exc->x.etrigger);
++
++ return;
++}
++
++void HandleSelectionClear(const evh_args_t *ea)
++{
++ icccm2_handle_selection_clear();
++
++ return;
++}
++
++void HandleShapeNotify(const evh_args_t *ea)
++{
++ FvwmWindow * const fw = ea->exc->w.fw;
++
++ DBUG("HandleShapeNotify", "Routine Entered");
++
++ if (FShapesSupported)
++ {
++ const FShapeEvent *sev =
++ (const FShapeEvent *)(ea->exc->x.etrigger);
++
++ if (!fw)
++ {
++ return;
++ }
++ if (sev->kind != FShapeBounding)
++ {
++ return;
++ }
++ frame_setup_shape(
++ fw, fw->g.frame.width, fw->g.frame.height,
sev->shaped);
++ GNOME_SetWinArea(fw);
++ EWMH_SetFrameStrut(fw);
++ if (!IS_ICONIFIED(fw))
++ {
++ border_redraw_decorations(fw);
++ }
++ }
++
++ return;
++}
++
++void HandleUnmapNotify(const evh_args_t *ea)
++{
++ int dstx, dsty;
++ Window dumwin;
++ XEvent dummy;
++ XEvent map_event;
++ const XEvent *te = ea->exc->x.etrigger;
++ int weMustUnmap;
++ Bool focus_grabbed;
++ Bool must_return = False;
++ Bool do_map = False;
++ FvwmWindow * const fw = ea->exc->w.fw;
++ Window pw;
++ Window cw;
++
++ DBUG("HandleUnmapNotify", "Routine Entered");
++
++ /* Don't ignore events as described below. */
++ if (te->xunmap.event != te->xunmap.window &&
++ (te->xunmap.event != Scr.Root || !te->xunmap.send_event))
++ {
++ must_return = True;
++ }
++
++ /*
++ * The July 27, 1988 ICCCM spec states that a client wishing to switch
++ * to WithdrawnState should send a synthetic UnmapNotify with the
++ * event field set to (pseudo-)root, in case the window is already
++ * unmapped (which is the case for fvwm for IconicState).
++ * Unfortunately, we looked for the FvwmContext using that field, so
++ * try the window field also. */
++ weMustUnmap = 0;
++ if (!fw)
++ {
++ weMustUnmap = 1;
++ if (XFindContext(
++ dpy, te->xunmap.window, FvwmContext,
++ (caddr_t *)&fw) == XCNOENT)
++ {
++ return;
++ }
++ }
++ cw = FW_W(fw);
++ pw = FW_W_PARENT(fw);
++ if (te->xunmap.window == FW_W_FRAME(fw))
++ {
++ SET_ICONIFY_PENDING(fw , 0);
++ return;
++ }
++ if (must_return)
++ {
++ return;
++ }
++
++ if (weMustUnmap)
++ {
++ Bool is_map_request_pending;
++ check_if_event_args args;
++
++ args.w = te->xunmap.window;
++ args.do_return_true = False;
++ args.do_return_true_cr = False;
++ /* Using FCheckTypedWindowEvent() does not work here. I don't
++ * have the slightest idea why, but using FCheckIfEvent() with
++ * the appropriate predicate procedure works fine. */
++ FCheckIfEvent(dpy, &dummy, test_map_request, (XPointer)&args);
++ /* Unfortunately, there is no procedure in X that simply tests
++ * if an event of a certain type in on the queue without
++ * waiting and without removing it from the queue.
++ * XCheck...Event() does not wait but removes the event while
++ * XPeek...() does not remove the event but waits. To solve
++ * this, the predicate procedure sets a flag in the passed in
++ * structure and returns False unconditionally. */
++ is_map_request_pending = (args.ret_does_match == True);
++ if (!is_map_request_pending)
++ {
++ XUnmapWindow(dpy, te->xunmap.window);
++ }
++ }
++ if (fw == Scr.Hilite)
++ {
++ Scr.Hilite = NULL;
++ }
++ focus_grabbed = focus_query_close_release_focus(fw);
++ restore_focus_after_unmap(fw, False);
++ if (!IS_MAPPED(fw) && !IS_ICONIFIED(fw))
++ {
++ return;
++ }
++
++ /*
++ * The program may have unmapped the client window, from either
++ * NormalState or IconicState. Handle the transition to
WithdrawnState.
++ *
++ * We need to reparent the window back to the root (so that fvwm
exiting
++ * won't cause it to get mapped) and then throw away all state
(pretend
++ * that we've received a DestroyNotify).
++ */
++ if (!FCheckTypedWindowEvent(
++ dpy, te->xunmap.window, DestroyNotify, &dummy) &&
++ XTranslateCoordinates(
++ dpy, te->xunmap.window, Scr.Root, 0, 0, &dstx, &dsty,
++ &dumwin))
++ {
++ MyXGrabServer(dpy);
++ SetMapStateProp(fw, WithdrawnState);
++ EWMH_RestoreInitialStates(fw, te->type);
++ if (FCheckTypedWindowEvent(
++ dpy, te->xunmap.window, ReparentNotify, &dummy))
++ {
++ if (fw->attr_backup.border_width)
++ {
++ XSetWindowBorderWidth(
++ dpy, te->xunmap.window,
++ fw->attr_backup.border_width);
++ }
++ if ((!IS_ICON_SUPPRESSED(fw))&&
++ (fw->wmhints &&
++ (fw->wmhints->flags & IconWindowHint)))
++ {
++ XUnmapWindow(dpy, fw->wmhints->icon_window);
++ }
++ }
++ else
++ {
++ RestoreWithdrawnLocation(fw, False, Scr.Root);
++ }
++ if (!IS_TEAR_OFF_MENU(fw))
++ {
++ XRemoveFromSaveSet(dpy, te->xunmap.window);
++ XSelectInput(dpy, te->xunmap.window, NoEventMask);
++ }
++ XSync(dpy, 0);
++ MyXUngrabServer(dpy);
++ if (FCheckTypedWindowEvent(dpy, pw, MapRequest, &map_event))
++ {
++ /* the client tried to map the window again while it
++ * was still inside the decoration windows */
++ do_map = True;
++ }
++ }
++ destroy_window(fw);
++ if (focus_grabbed == True)
++ {
++ CoerceEnterNotifyOnCurrentWindow();
++ }
++ EWMH_ManageKdeSysTray(te->xunmap.window, te->type);
++ EWMH_WindowDestroyed();
++ GNOME_SetClientList();
++ if (do_map == True)
++ {
++ map_event.xmaprequest.window = cw;
++ map_event.xmaprequest.parent = Scr.Root;
++ dispatch_event(&map_event);
++ /* note: we really should handle all map and unmap notify
++ * events for that window in a loop here */
++ }
++
++ return;
++}
++
++void HandleVisibilityNotify(const evh_args_t *ea)
++{
++ FvwmWindow * const fw = ea->exc->w.fw;
++
++ DBUG("HandleVisibilityNotify", "Routine Entered");
++
++ if (fw && ea->exc->x.etrigger->xvisibility.window == FW_W_FRAME(fw))
++ {
++ switch (ea->exc->x.etrigger->xvisibility.state)
++ {
++ case VisibilityUnobscured:
++ SET_FULLY_VISIBLE(fw, 1);
++ SET_PARTIALLY_VISIBLE(fw, 1);
++ break;
++ case VisibilityPartiallyObscured:
++ SET_FULLY_VISIBLE(fw, 0);
++ SET_PARTIALLY_VISIBLE(fw, 1);
++ break;
++ default:
++ SET_FULLY_VISIBLE(fw, 0);
++ SET_PARTIALLY_VISIBLE(fw, 0);
++ break;
++ }
++ /* Make sure the button grabs are up to date */
++ focus_grab_buttons(fw);
++ }
++
++ return;
++}
++
++/* ---------------------------- interface functions
------------------------ */
++
++/* Inform a client window of its geometry.
++ *
++ * The input (frame) geometry will be translated to client geometry
++ * before sending. */
++void SendConfigureNotify(
++ FvwmWindow *fw, int x, int y, int w, int h, int bw,
++ Bool send_for_frame_too)
++{
++ XEvent client_event;
++ size_borders b;
++
++ if (!fw || IS_SHADED(fw))
++ {
++ return;
++ }
++ client_event.type = ConfigureNotify;
++ client_event.xconfigure.display = dpy;
++ client_event.xconfigure.event = FW_W(fw);
++ client_event.xconfigure.window = FW_W(fw);
++ get_window_borders(fw, &b);
++ client_event.xconfigure.x = x + b.top_left.width;
++ client_event.xconfigure.y = y + b.top_left.height;
++ client_event.xconfigure.width = w - b.total_size.width;
++ client_event.xconfigure.height = h - b.total_size.height;
++ client_event.xconfigure.border_width = bw;
++ client_event.xconfigure.above = FW_W_FRAME(fw);
++ client_event.xconfigure.override_redirect = False;
++ FSendEvent(
++ dpy, FW_W(fw), False, StructureNotifyMask, &client_event);
++ if (send_for_frame_too)
++ {
++ /* This is for buggy tk, which waits for the real
++ * ConfigureNotify on frame instead of the synthetic one on w.
++ * The geometry data in the event will not be correct for the
++ * frame, but tk doesn't look at that data anyway. */
++ client_event.xconfigure.event = FW_W_FRAME(fw);
++ client_event.xconfigure.window = FW_W_FRAME(fw);
++ FSendEvent(
++ dpy, FW_W_FRAME(fw), False, StructureNotifyMask,
++ &client_event);
++ }
++
++ return;
++}
++
++/*
++** Procedure:
++** InitEventHandlerJumpTable
++*/
++void InitEventHandlerJumpTable(void)
++{
++ int i;
++
++ for (i=0; i<LASTEvent; i++)
++ {
++ EventHandlerJumpTable[i] = NULL;
++ }
++ EventHandlerJumpTable[Expose] = HandleExpose;
++ EventHandlerJumpTable[DestroyNotify] = HandleDestroyNotify;
++ EventHandlerJumpTable[MapRequest] = HandleMapRequest;
++ EventHandlerJumpTable[MapNotify] = HandleMapNotify;
++ EventHandlerJumpTable[UnmapNotify] = HandleUnmapNotify;
++ EventHandlerJumpTable[ButtonPress] = HandleButtonPress;
++ EventHandlerJumpTable[EnterNotify] = HandleEnterNotify;
++ EventHandlerJumpTable[LeaveNotify] = HandleLeaveNotify;
++ EventHandlerJumpTable[FocusIn] = HandleFocusIn;
++ EventHandlerJumpTable[FocusOut] = HandleFocusOut;
++ EventHandlerJumpTable[ConfigureRequest] = HandleConfigureRequest;
++ EventHandlerJumpTable[ClientMessage] = HandleClientMessage;
++ EventHandlerJumpTable[PropertyNotify] = HandlePropertyNotify;
++ EventHandlerJumpTable[KeyPress] = HandleKeyPress;
++ EventHandlerJumpTable[KeyRelease] = HandleKeyRelease;
++ EventHandlerJumpTable[VisibilityNotify] = HandleVisibilityNotify;
++ EventHandlerJumpTable[ColormapNotify] = HandleColormapNotify;
++ if (FShapesSupported)
++ {
++ EventHandlerJumpTable[FShapeEventBase+FShapeNotify] =
++ HandleShapeNotify;
++ }
++ EventHandlerJumpTable[SelectionClear] = HandleSelectionClear;
++ EventHandlerJumpTable[SelectionRequest] = HandleSelectionRequest;
++ EventHandlerJumpTable[ReparentNotify] = HandleReparentNotify;
++ EventHandlerJumpTable[MappingNotify] = HandleMappingNotify;
++ STROKE_CODE(EventHandlerJumpTable[ButtonRelease] =
HandleButtonRelease);
++ STROKE_CODE(EventHandlerJumpTable[MotionNotify] = HandleMotionNotify);
++#ifdef MOUSE_DROPPINGS
++ STROKE_CODE(stroke_init(dpy,DefaultRootWindow(dpy)));
++#else /* no MOUSE_DROPPINGS */
++ STROKE_CODE(stroke_init());
++#endif /* MOUSE_DROPPINGS */
++
++ return;
++}
++
++/* handle a single X event */
++void dispatch_event(XEvent *e)
++{
++ Window w = e->xany.window;
++ FvwmWindow *fw;
++
++ DBUG("dispatch_event", "Routine Entered");
++
++ XFlush(dpy);
++ if (w == Scr.Root)
++ {
++ switch (e->type)
++ {
++ case ButtonPress:
++ case ButtonRelease:
++ if (e->xbutton.subwindow != None)
++ {
++ w = e->xbutton.subwindow;
++ }
++ case MapRequest:
++ w = e->xmaprequest.window;
++ break;
++ default:
++ break;
++ }
++ }
++ if (w == Scr.Root ||
++ XFindContext(dpy, w, FvwmContext, (caddr_t *)&fw) == XCNOENT)
++ {
++ fw = NULL;
++ }
++ last_event_type = e->type;
++ if (EventHandlerJumpTable[e->type])
++ {
++ evh_args_t ea;
++ exec_context_changes_t ecc;
++ Window dummyw;
++
++ ecc.type = EXCT_EVENT;
++ ecc.x.etrigger = e;
++ ecc.w.wcontext = GetContext(&fw, fw, e, &dummyw);
++ ecc.w.w = w;
++ ecc.w.fw = fw;
++ ea.exc = exc_create_context(
++ &ecc, ECC_TYPE | ECC_ETRIGGER | ECC_FW | ECC_W |
++ ECC_WCONTEXT);
++ (*EventHandlerJumpTable[e->type])(&ea);
++ exc_destroy_context(ea.exc);
++ }
++
++#ifdef C_ALLOCA
++ /* If we're using the C version of alloca, see if anything needs to be
++ * freed up.
++ */
++ alloca(0);
++#endif
++ DBUG("dispatch_event", "Leaving Routine");
++
++ return;
++}
++
++/* ewmh configure request */
++void events_handle_configure_request(
++ XConfigureRequestEvent cre, FvwmWindow *fw, Bool force)
++{
++ __handle_configure_request(cre, NULL, fw, force);
++}
++
++void HandleEvents(void)
++{
++ XEvent ev;
++
++ DBUG("HandleEvents", "Routine Entered");
++ STROKE_CODE(send_motion = False);
++ while (!isTerminated)
++ {
++ last_event_type = 0;
++ if (Scr.flags.is_window_scheduled_for_destroy)
++ {
++ destroy_scheduled_windows();
++ }
++ if (Scr.flags.do_need_window_update)
++ {
++ flush_window_updates();
++ }
++ if (My_XNextEvent(dpy, &ev))
++ {
++ dispatch_event(&ev);
++ }
++ if (Scr.flags.do_need_style_list_update)
++ {
++ simplify_style_list();
++ }
++ }
++
++ return;
++}
++
++/*
++ *
++ * Waits for next X or module event, fires off startup routines when startup
++ * modules have finished or after a timeout if the user has specified a
++ * command line module that doesn't quit or gets stuck.
++ *
++ */
++int My_XNextEvent(Display *dpy, XEvent *event)
++{
++ fd_set in_fdset, out_fdset;
++ int num_fd;
++ fmodule *module;
++ fmodule_input *input;
++ static struct timeval timeout;
++ static struct timeval *timeoutP = &timeout;
++
++ DBUG("My_XNextEvent", "Routine Entered");
++
++ /* include this next bit if HandleModuleInput() gets called anywhere
++ * else with queueing turned on. Because this routine is the only
++ * place that queuing is on _and_ ExecuteCommandQueue is always called
++ * immediately after it is impossible for there to be anything in the
++ * queue at this point */
++#if 0
++ /* execute any commands queued up */
++ DBUG("My_XNextEvent", "executing module comand queue");
++ ExecuteCommandQueue();
++#endif
++
++ /* check for any X events already queued up.
++ * Side effect: this does an XFlush if no events are queued
++ * Make sure nothing between here and the select causes further
++ * X requests to be sent or the select may block even though
++ * there are events in the queue */
++ if (FPending(dpy))
++ {
++ DBUG(
++ "My_XNextEvent", "taking care of queued up events"
++ " & returning (1)");
++ FNextEvent(dpy, event);
++ return 1;
++ }
++
++ /* The SIGCHLD signal is sent every time one of our child processes
++ * dies, and the SIGCHLD handler now reaps them automatically. We
++ * should therefore never see a zombie */
++#if 0
++ DBUG("My_XNextEvent", "no X events waiting - about to reap children");
++ /* Zap all those zombies! */
++ /* If we get to here, then there are no X events waiting to be
++ * processed. Just take a moment to check for dead children. */
++ ReapChildren();
++#endif
++
++ /* check for termination of all startup modules */
++ if (fFvwmInStartup)
++ {
++ module = module_get_next(NULL);
++ for (; module != NULL; module = module_get_next(module))
++ {
++ if (MOD_IS_CMDLINE(module) == 1)
++ {
++ break;
++ }
++ }
++ if (module == NULL)
++ {
++ /* last module */
++ DBUG(
++ "My_XNextEvent",
++ "Starting up after command lines modules");
++ /* set an infinite timeout to stop ticking */
++ timeoutP = NULL;
++ /* This may cause X requests to be sent */
++ StartupStuff();
++
++ return 0; /* so return without select()ing */
++ }
++ }
++
++ /* Some signals can interrupt us while we wait for any action
++ * on our descriptors. While some of these signals may be asking
++ * fvwm to die, some might be harmless. Harmless interruptions
++ * mean we have to start waiting all over again ... */
++ do
++ {
++ int ms;
++ Bool is_waiting_for_scheduled_command = False;
++ static struct timeval *old_timeoutP = NULL;
++
++ /* The timeouts become undefined whenever the select returns,
++ * and so we have to reinitialise them */
++ ms = squeue_get_next_ms();
++ if (ms == 0)
++ {
++ /* run scheduled commands */
++ squeue_execute();
++ ms = squeue_get_next_ms();
++ /* should not happen anyway.
++ * get_next_schedule_queue_ms() can't return 0 after a
++ * call to execute_schedule_queue(). */
++ if (ms == 0)
++ {
++ ms = 1;
++ }
++ }
++ if (ms < 0)
++ {
++ timeout.tv_sec = 42;
++ timeout.tv_usec = 0;
++ }
++ else
++ {
++ /* scheduled commands are pending - don't wait too
++ * long */
++ timeout.tv_sec = ms / 1000;
++ timeout.tv_usec = 1000 * (ms % 1000);
++ old_timeoutP = timeoutP;
++ timeoutP = &timeout;
++ is_waiting_for_scheduled_command = True;
++ }
++
++ FD_ZERO(&in_fdset);
++ FD_ZERO(&out_fdset);
++ FD_SET(x_fd, &in_fdset);
++
++ /* nothing is done here if fvwm was compiled without session
++ * support */
++ if (sm_fd >= 0)
++ {
++ FD_SET(sm_fd, &in_fdset);
++ }
++
++ module = module_get_next(NULL);
++ for (; module != NULL; module = module_get_next(module))
++ {
++ FD_SET(MOD_READFD(module), &in_fdset);
++
++ if (!FQUEUE_IS_EMPTY(&MOD_PIPEQUEUE(module)))
++ {
++ FD_SET(MOD_WRITEFD(module), &out_fdset);
++ }
++ }
++
++ DBUG("My_XNextEvent", "waiting for module input/output");
++ num_fd = fvwmSelect(
++ fvwmlib_max_fd, &in_fdset, &out_fdset, 0, timeoutP);
++ if (is_waiting_for_scheduled_command)
++ {
++ timeoutP = old_timeoutP;
++ }
++
++ /* Express route out of FVWM ... */
++ if (isTerminated)
++ {
++ return 0;
++ }
++ } while (num_fd < 0);
++
++ if (num_fd > 0)
++ {
++ /* Check for module input. */
++ module = module_get_next(NULL);
++ for (; module != NULL; module = module_get_next(module))
++ {
++ if (FD_ISSET(MOD_READFD(module), &in_fdset))
++ {
++ input = module_receive(module);
++ /* enqueue the received command */
++ module_input_enqueue(input);
++ }
++ if (
++ MOD_WRITEFD(module) >= 0 &&
++ FD_ISSET(MOD_WRITEFD(module), &out_fdset))
++ {
++ DBUG("My_XNextEvent",
++ "calling FlushMessageQueue");
++ FlushMessageQueue(module);
++ }
++ }
++
++ /* execute any commands queued up */
++ DBUG("My_XNextEvent", "executing module comand queue");
++ ExecuteCommandQueue();
++
++ /* nothing is done here if fvwm was compiled without session
++ * support */
++ if ((sm_fd >= 0) && (FD_ISSET(sm_fd, &in_fdset)))
++ {
++ ProcessICEMsgs();
++ }
++
++ }
++ else
++ {
++ /* select has timed out, things must have calmed down so let's
++ * decorate */
++ if (fFvwmInStartup)
++ {
++ fvwm_msg(ERR, "My_XNextEvent",
++ "Some command line modules have not quit, "
++ "Starting up after timeout.\n");
++ StartupStuff();
++ timeoutP = NULL; /* set an infinite timeout to stop
++ * ticking */
++ reset_style_changes();
++ Scr.flags.do_need_window_update = 0;
++ }
++ /* run scheduled commands if necessary */
++ squeue_execute();
++ }
++
++ /* check for X events again, rather than return 0 and get called again
++ */
++ if (FPending(dpy))
++ {
++ DBUG("My_XNextEvent",
++ "taking care of queued up events & returning (2)");
++ FNextEvent(dpy,event);
++ return 1;
++ }
++
++ DBUG("My_XNextEvent", "leaving My_XNextEvent");
++ return 0;
++}
++
++/*
++ *
++ * Procedure:
++ * Find the Fvwm context for the event.
++ *
++ */
++int GetContext(FvwmWindow **ret_fw, FvwmWindow *t, const XEvent *e, Window
*w)
++{
++ int context;
++ Window win;
++ Window subw = None;
++ int x = 0;
++ int y = 0;
++ Bool is_key_event = False;
++
++ win = e->xany.window;
++ context = C_NO_CONTEXT;
++ switch (e->type)
++ {
++ case KeyPress:
++ case KeyRelease:
++ x = e->xkey.x;
++ y = e->xkey.y;
++ subw = e->xkey.subwindow;
++ if (win == Scr.Root && subw != None)
++ {
++ /* Translate root coordinates into subwindow
++ * coordinates. Necessary for key bindings that work
++ * over unfocused windows. */
++ win = subw;
++ XTranslateCoordinates(
++ dpy, Scr.Root, subw, x, y, &x, &y, &subw);
++ XFindContext(dpy, win, FvwmContext, (caddr_t *) &t);
++ }
++ is_key_event = True;
++ /* fall through */
++ case ButtonPress:
++ case ButtonRelease:
++ if (!is_key_event)
++ {
++ x = e->xbutton.x;
++ y = e->xbutton.y;
++ subw = e->xbutton.subwindow;
++ }
++ if (t && win == FW_W_FRAME(t) && subw != None)
++ {
++ /* Translate frame coordinates into subwindow
++ * coordinates. */
++ win = subw;
++ XTranslateCoordinates(
++ dpy, FW_W_FRAME(t), subw, x, y, &x, &y,
&subw);
++ if (win == FW_W_PARENT(t))
++ {
++ win = subw;
++ XTranslateCoordinates(
++ dpy, FW_W_PARENT(t), subw, x, y, &x,
++ &y, &subw);
++ }
++ }
++ break;
++ default:
++ XFindContext(dpy, win, FvwmContext, (caddr_t *)&t);
++ break;
++ }
++ if (ret_fw != NULL)
++ {
++ *ret_fw = t;
++ }
++ if (!t)
++ {
++ return C_ROOT;
++ }
++ *w = win;
++ if (*w == Scr.NoFocusWin)
++ {
++ return C_ROOT;
++ }
++ if (subw != None)
++ {
++ if (win == FW_W_PARENT(t))
++ {
++ *w = subw;
++ }
++ }
++ if (*w == Scr.Root)
++ {
++ return C_ROOT;
++ }
++ context = frame_window_id_to_context(t, *w, &Button);
++
++ return context;
++}
++
++/*
++ *
++ * Removes expose events for a specific window from the queue
++ *
++ */
++int flush_expose(Window w)
++{
++ XEvent dummy;
++ int i=0;
++
++ while (FCheckTypedWindowEvent(dpy, w, Expose, &dummy))
++ {
++ i++;
++ }
++
++ return i;
++}
++
++/* same as above, but merges the expose rectangles into a single big one */
++int flush_accumulate_expose(Window w, XEvent *e)
++{
++ XEvent dummy;
++ int i = 0;
++ int x1 = e->xexpose.x;
++ int y1 = e->xexpose.y;
++ int x2 = x1 + e->xexpose.width;
++ int y2 = y1 + e->xexpose.height;
++
++ while (FCheckTypedWindowEvent(dpy, w, Expose, &dummy))
++ {
++ x1 = min(x1, dummy.xexpose.x);
++ y1 = min(y1, dummy.xexpose.y);
++ x2 = max(x2, dummy.xexpose.x + dummy.xexpose.width);
++ y2 = max(y2, dummy.xexpose.y + dummy.xexpose.height);
++ i++;
++ }
++ e->xexpose.x = x1;
++ e->xexpose.y = y1;
++ e->xexpose.width = x2 - x1;
++ e->xexpose.height = y2 - y1;
++
++ return i;
++}
++
++/*
++ *
++ * Removes all expose events from the queue and does the necessary redraws
++ *
++ */
++void handle_all_expose(void)
++{
++ void *saved_event;
++ XEvent evdummy;
++
++ saved_event = fev_save_event();
++ FPending(dpy);
++ while (FCheckMaskEvent(dpy, ExposureMask, &evdummy))
++ {
++ dispatch_event(&evdummy);
++ }
++ fev_restore_event(saved_event);
++
++ return;
++}
++
++/* CoerceEnterNotifyOnCurrentWindow()
++ * Pretends to get a HandleEnterNotify on the window that the pointer
++ * currently is in so that the focus gets set correctly from the beginning.
++ * Note that this presently only works if the current window is not
++ * click_to_focus; I think that that behaviour is correct and desirable.
++ * --11/08/97 gjb */
++void CoerceEnterNotifyOnCurrentWindow(void)
++{
++ Window child;
++ Window root;
++ Bool f;
++ evh_args_t ea;
++ exec_context_changes_t ecc;
++ XEvent e;
++ FvwmWindow *fw;
++
++ f = FQueryPointer(
++ dpy, Scr.Root, &root, &child, &e.xcrossing.x_root,
++ &e.xcrossing.y_root, &e.xcrossing.x, &e.xcrossing.y,
++ &JunkMask);
++ if (f == False || child == None)
++ {
++ return;
++ }
++ e.xcrossing.type = EnterNotify;
++ e.xcrossing.window = child;
++ e.xcrossing.subwindow = None;
++ e.xcrossing.mode = NotifyNormal;
++ e.xcrossing.detail = NotifyAncestor;
++ e.xcrossing.same_screen = True;
++ if (XFindContext(dpy, child, FvwmContext, (caddr_t *)&fw) == XCNOENT)
++ {
++ fw = NULL;
++ }
++ else
++ {
++ XTranslateCoordinates(
++ dpy, Scr.Root, child, e.xcrossing.x_root,
++ e.xcrossing.y_root, &JunkX, &JunkY, &child);
++ if (child == FW_W_PARENT(fw))
++ {
++ child = FW_W(fw);
++ }
++ if (child != None)
++ {
++ e.xany.window = child;
++ }
++ }
++ e.xcrossing.focus = (fw == get_focus_window()) ? True : False;
++ ecc.type = EXCT_NULL;
++ ecc.x.etrigger = &e;
++ ea.exc = exc_create_context(&ecc, ECC_TYPE | ECC_ETRIGGER);
++ HandleEnterNotify(&ea);
++ exc_destroy_context(ea.exc);
++
++ return;
++}
++
++/* This function discards all queued up ButtonPress, ButtonRelease and
++ * ButtonMotion events. */
++int discard_events(long event_mask)
++{
++ XEvent e;
++ int count;
++
++ XSync(dpy, 0);
++ for (count = 0; FCheckMaskEvent(dpy, event_mask, &e); count++)
++ {
++ /* nothing */
++ }
++
++ return count;
++}
++
++/* This function discards all queued up ButtonPress, ButtonRelease and
++ * ButtonMotion events. */
++int discard_window_events(Window w, long event_mask)
++{
++ XEvent e;
++ int count;
++
++ XSync(dpy, 0);
++ for (count = 0; FCheckWindowEvent(dpy, w, event_mask, &e); count++)
++ {
++ /* nothing */
++ }
++
++ return count;
++}
++
++/* Similar function for certain types of PropertyNotify. */
++int flush_property_notify(Atom atom, Window w)
++{
++ XEvent e;
++ int count;
++ test_typed_window_event_args args;
++
++ XSync(dpy, 0);
++ args.w = w;
++ args.event_type = PropertyNotify;
++ for (count = 0;
++ FCheckPeekIfEvent(
++ dpy, &e, test_typed_window_event, (XPointer)&args);
++ count++)
++ {
++ Bool rc;
++
++ if (e.xproperty.atom != atom)
++ {
++ break;
++ }
++ /* remove the event from the queue */
++ rc = FCheckIfEvent(
++ dpy, &e, test_typed_window_event, (XPointer)&args);
++ }
++
++ return count;
++}
++
++/* Wait for all mouse buttons to be released
++ * This can ease some confusion on the part of the user sometimes
++ *
++ * Discard superflous button events during this wait period. */
++void WaitForButtonsUp(Bool do_handle_expose)
++{
++ unsigned int mask;
++ unsigned int bmask;
++ long evmask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|
++ KeyPressMask|KeyReleaseMask;
++ int count;
++ int use_wait_cursor;
++ XEvent e;
++
++ if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild, &JunkX,
&JunkY,
++ &JunkX, &JunkY, &mask) == False)
++ {
++ /* pointer is on a different screen - that's okay here */
++ }
++ mask &= DEFAULT_ALL_BUTTONS_MASK;
++ if (mask == 0)
++ {
++ return;
++ }
++ if (do_handle_expose)
++ {
++ evmask |= ExposureMask;
++ }
++ GrabEm(None, GRAB_NORMAL);
++ for (count = 0, use_wait_cursor = 0; mask != 0; count++)
++ {
++ /* handle expose events */
++ XAllowEvents(dpy, SyncPointer, CurrentTime);
++ if (FCheckMaskEvent(dpy, evmask, &e))
++ {
++ switch (e.type)
++ {
++ case ButtonRelease:
++ if (e.xbutton.button <=
++ NUMBER_OF_MOUSE_BUTTONS)
++ {
++ bmask = (Button1Mask <<
++ (e.xbutton.button - 1));
++ mask = e.xbutton.state & ~bmask;
++ }
++ break;
++ case Expose:
++ dispatch_event(&e);
++ break;
++ default:
++ break;
++ }
++ }
++ else
++ {
++ if (FQueryPointer(
++ dpy, Scr.Root, &JunkRoot, &JunkChild,
++ &JunkX, &JunkY, &JunkX, &JunkY, &mask) ==
++ False)
++ {
++ /* pointer is on a different screen - that's
++ * okay here */
++ }
++ mask &= DEFAULT_ALL_BUTTONS_MASK;
++ usleep(1);
++ }
++ if (use_wait_cursor == 0 && count == 20)
++ {
++ GrabEm(CRS_WAIT, GRAB_NORMAL);
++ use_wait_cursor = 1;
++ }
++ }
++ UngrabEm(GRAB_NORMAL);
++ if (use_wait_cursor)
++ {
++ UngrabEm(GRAB_NORMAL);
++ XFlush(dpy);
++ }
++
++ return;
++}
++
++void sync_server(int toggle)
++{
++ static Bool synced = False;
++
++ if (toggle == -1)
++ {
++ toggle = (synced == False);
++ }
++ if (toggle == 1)
++ {
++ synced = True;
++ }
++ else
++ {
++ synced = False;
++ }
++ XSynchronize(dpy, synced);
++ XFlush(dpy);
++
++ return;
++}
++
++Bool is_resizing_event_pending(
++ FvwmWindow *fw)
++{
++ XEvent e;
++ check_if_event_args args;
++
++ args.w = FW_W(fw);
++ args.do_return_true = False;
++ args.do_return_true_cr = False;
++ args.cr_value_mask = 0;
++ args.ret_does_match = False;
++ args.ret_type = 0;
++ FCheckIfEvent(dpy, &e, test_resizing_event, (XPointer)&args);
++
++ return args.ret_does_match;
++}
++
++/* ---------------------------- builtin commands
--------------------------- */
++
++void CMD_XSynchronize(F_CMD_ARGS)
++{
++ int toggle;
++
++ toggle = ParseToggleArgument(action, NULL, -1, 0);
++ sync_server(toggle);
++
++ return;
++}
++
++void CMD_XSync(F_CMD_ARGS)
++{
++ XSync(dpy, 0);
++
++ return;
++}
+diff -U10 -Naupr fvwm-2.5.21-11/fvwm/fvwm.h fvwm-2.5.21-12/fvwm/fvwm.h
+--- fvwm-2.5.21-11/fvwm/fvwm.h 2007-03-03 13:20:56.000000000 +0100
++++ fvwm-2.5.21-12/fvwm/fvwm.h 2007-03-03 13:23:23.000000000 +0100
+@@ -718,20 +718,21 @@ typedef struct FvwmWindow
+ 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 buttons_hover : 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;
+diff -U10 -Naupr fvwm-2.5.21-11/fvwm/fvwm.h~ fvwm-2.5.21-12/fvwm/fvwm.h~
+--- fvwm-2.5.21-11/fvwm/fvwm.h~ 2007-03-03 13:20:56.000000000 +0100
++++ fvwm-2.5.21-12/fvwm/fvwm.h~ 2007-03-03 13:23:14.000000000 +0100
+@@ -268,20 +268,21 @@ typedef struct
+ #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;
++ unsigned has_no_top_border : 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-11/fvwm/screen.h fvwm-2.5.21-12/fvwm/screen.h
+--- fvwm-2.5.21-11/fvwm/screen.h 2007-03-03 13:21:03.000000000 +0100
++++ fvwm-2.5.21-12/fvwm/screen.h 2007-03-03 13:23:23.000000000 +0100
+@@ -195,42 +195,49 @@ typedef struct DecorFace
+ {
+ unsigned has_changed : 1;
+ } flags;
+ } DecorFace;
+
+ typedef enum
+ {
+ BS_All = -1,
+ BS_ActiveUp,
+ BS_ActiveDown,
++ BS_ActiveHover,
+ BS_InactiveUp,
+ BS_InactiveDown,
++ BS_InactiveHover,
+ BS_ToggledActiveUp,
+ BS_ToggledActiveDown,
++ BS_ToggledActiveHover,
+ BS_ToggledInactiveUp,
+ BS_ToggledInactiveDown,
++ BS_ToggledInactiveHover,
+ BS_MaxButtonState,
+ BS_MaxButtonStateMask = BS_MaxButtonState - 1,
+ BS_Active,
+ BS_Inactive,
+ BS_ToggledActive,
+ BS_ToggledInactive,
+ BS_AllNormal,
+ BS_AllToggled,
+ BS_AllActive,
+ BS_AllInactive,
+ BS_AllUp,
+ BS_AllDown,
++ BS_AllHover,
+ BS_AllActiveUp,
+ BS_AllActiveDown,
++ BS_AllActiveHover,
+ BS_AllInactiveUp,
+ BS_AllInactiveDown,
++ BS_AllInactiveHover,
+ BS_MaxButtonStateName
+ } ButtonState;
+
+ #define BS_MASK_DOWN (1 << 0)
+ #define BS_MASK_INACTIVE (1 << 1)
+ #define BS_MASK_TOGGLED (1 << 2)
+
+ typedef enum
+ {
+ /* The first five are used in title buttons. These can't be
+@@ -503,20 +510,21 @@ typedef struct ScreenInfo
+ } bo; /* bug workaround control options */
+ struct
+ {
+ unsigned do_emulate_mwm : 1;
+ unsigned do_emulate_win : 1;
+ unsigned do_hide_position_window : 1;
+ unsigned do_hide_resize_window : 1;
+ unsigned use_active_down_buttons : 1;
+ unsigned use_inactive_buttons : 1;
+ unsigned use_inactive_down_buttons : 1;
++ unsigned use_hover_buttons : 1;
+ } gs; /* global style structure */
+ struct
+ {
+ unsigned are_functions_silent : 1;
+ unsigned are_windows_captured : 1;
+ unsigned do_edge_wrap_x : 1;
+ unsigned do_edge_wrap_y : 1;
+ unsigned do_need_style_list_update : 1;
+ unsigned do_need_window_update : 1;
+ unsigned do_save_under : 1;
diff --git a/windowmanagers/fvwm/patches/15-FvwmIconMan.patch
b/windowmanagers/fvwm/patches/15-FvwmIconMan.patch
new file mode 100644
index 0000000..ff66c15
--- /dev/null
+++ b/windowmanagers/fvwm/patches/15-FvwmIconMan.patch
@@ -0,0 +1,181 @@
+diff -U10 -Naupr fvwm-2.5.21-12/modules/FvwmIconMan/FvwmIconMan.h
fvwm-2.5.21-15/modules/FvwmIconMan/FvwmIconMan.h
+--- fvwm-2.5.21-12/modules/FvwmIconMan/FvwmIconMan.h 2007-03-03
13:23:14.000000000 +0100
++++ fvwm-2.5.21-15/modules/FvwmIconMan/FvwmIconMan.h 2007-03-03
13:24:58.000000000 +0100
+@@ -308,20 +308,22 @@ typedef struct win_manager {
+ Uchar showtransient;
+ rectangle managed_g; /* dimensions of managed screen portion */
+ int relief_thickness; /* relief thickness for each non-flat button
*/
+ #define TIPS_NEVER 0
+ #define TIPS_ALWAYS 1
+ #define TIPS_NEEDED 2
+ int tips;
+ char *tips_fontname;
+ char *tips_formatstring;
+ ftips_config *tips_conf;
++ Uchar roundedcorners;
++ int padding;
+
+ /* X11 state */
+ Window theWindow, theFrame;
+ long sizehints_flags;
+ int gravity;
+ int fontheight, fontwidth;
+ int win_title, win_border;
+ int off_x, off_y;
+ Uchar cursor_in_window;
+ Uchar window_up;
+diff -U10 -Naupr fvwm-2.5.21-12/modules/FvwmIconMan/readconfig.c
fvwm-2.5.21-15/modules/FvwmIconMan/readconfig.c
+--- fvwm-2.5.21-12/modules/FvwmIconMan/readconfig.c 2007-03-03
13:23:14.000000000 +0100
++++ fvwm-2.5.21-15/modules/FvwmIconMan/readconfig.c 2007-03-03
13:24:58.000000000 +0100
+@@ -2021,20 +2021,54 @@ void read_in_resources()
+ ConsoleMessage("Bad line: %s\n", current_line);
+ continue;
+ }
+ if (extract_int(p, &n) == 0) {
+ ConsoleMessage("This is not a number: %s\n", p);
+ ConsoleMessage("Bad line: %s\n", current_line);
+ continue;
+ }
+ SET_MANAGER(manager, relief_thickness, n);
+ }
++ else if (!strcasecmp(option1, "padding")) {
++ p = read_next_cmd(READ_ARG);
++ if (!p) {
++ ConsoleMessage("Bad line: %s\n", current_line);
++ continue;
++ }
++ if (extract_int(p, &n) == 0) {
++ ConsoleMessage("This is not a number: %s\n", p);
++ ConsoleMessage("Bad line: %s\n", current_line);
++ continue;
++ }
++ SET_MANAGER(manager, padding, n);
++ }
++ else if (!strcasecmp(option1, "roundedcorners")) {
++ p = read_next_cmd(READ_ARG);
++ if (!p) {
++ ConsoleMessage("Bad line: %s\n", current_line);
++ ConsoleMessage("Need argument to roundedcorners\n");
++ continue;
++ }
++ if (!strcasecmp(p, "true")) {
++ i = 1;
++ }
++ else if (!strcasecmp(p, "false")) {
++ i = 0;
++ }
++ else {
++ ConsoleMessage("Bad line: %s\n", current_line);
++ ConsoleMessage("What is this: %s?\n", p);
++ continue;
++ }
++ ConsoleDebug(CONFIG, "Setting roundedcorners to: %d\n", i);
++ SET_MANAGER(manager, roundedcorners, i);
++ }
+ else if (!strcasecmp(option1, "tips")) {
+ p = read_next_cmd(READ_ARG);
+ if (!p) {
+ ConsoleMessage("Bad line: %s\n", current_line);
+ continue;
+ }
+ if (!strcasecmp(p, "always")) {
+ i = TIPS_ALWAYS;
+ }
+
+diff -U10 -Naupr fvwm-2.5.21-12/modules/FvwmIconMan/xmanager.c
fvwm-2.5.21-15/modules/FvwmIconMan/xmanager.c
+--- fvwm-2.5.21-12/modules/FvwmIconMan/xmanager.c 2007-03-03
13:23:14.000000000 +0100
++++ fvwm-2.5.21-15/modules/FvwmIconMan/xmanager.c 2007-03-03
13:24:58.000000000 +0100
+@@ -1389,20 +1389,22 @@ static void get_button_geometry(WinManag
+ g->text_x = g->icon_x + g->icon_w + 2;
+ g->text_w = g->button_w - 4 - (g->text_x - g->button_x);
+ if (g->text_w <= 0)
+ g->text_w = 1;
+ g->text_h = man->fontheight;
+
+ text_pad = center_padding(man->fontheight, g->button_h);
+
+ g->text_y = g->button_y + text_pad;
+ g->text_base = g->text_y + man->FButtonFont->ascent;
++
++ g->button_w -= man->padding;
+ }
+
+ static void draw_button_background(
+ WinManager *man, XRectangle bounding, Contexts button_state)
+ {
+ int cset = man->colorsets[button_state];
+
+ if (CSET_IS_TRANSPARENT_PR_PURE(cset) ||
+ man->backContext[button_state] == None)
+ {
+@@ -1661,20 +1663,47 @@ static void draw_relief(WinManager *man,
+ g->button_w - 5, g->button_h - 5, context2, context1,
+ relief);
+ }
+ else {
+ RelieveRectangle(theDisplay, man->theWindow, g->button_x, g->button_y,
+ g->button_w - 1, g->button_h - 1, context1, context2,
+ relief);
+ }
+ }
+
++static void __draw_rounded_corner(WinManager *man, ButtonGeometry *g,
++ int x, int y, int width, int height, GC gc)
++{
++ int x1 = g->button_x + x;
++ int x2 = g->button_x + g->button_w - x - width;
++ int y1 = g->button_y + y;
++ int y2 = g->button_y + g->button_h - y - height;
++
++ XFillRectangle(theDisplay, man->theWindow, gc, x1, y1, width, height);
++ XFillRectangle(theDisplay, man->theWindow, gc, x2, y1, width, height);
++ XFillRectangle(theDisplay, man->theWindow, gc, x1, y2, width, height);
++ XFillRectangle(theDisplay, man->theWindow, gc, x2, y2, width, height);
++}
++
++static void draw_rounded_corners(WinManager *man, ButtonGeometry *g, GC gc)
++{
++ if (man->roundedcorners)
++ {
++ __draw_rounded_corner(man, g, 0, 0, 2, 1,
man->backContext[TITLE_CONTEXT]);
++ __draw_rounded_corner(man, g, 0, 1, 1, 1,
man->backContext[TITLE_CONTEXT]);
++ __draw_rounded_corner(man, g, 1, 1, 1, 1, gc);
++ }
++
++ XFillRectangle(theDisplay, man->theWindow,
man->backContext[TITLE_CONTEXT],
++ g->button_x + g->button_w, g->button_y, man->padding,
g->button_h);
++}
++
+ static void draw_button(WinManager *man, int button, int force)
+ {
+ Button *b;
+ WinData *win;
+ ButtonGeometry g, old_g;
+ GC context1, context2;
+ Contexts button_state;
+ int cleared_button = 0, dirty;
+ int draw_background = 0, draw_icon = 0, draw_string = 0;
+ int clear_old_pic = 0;
+@@ -1849,20 +1878,22 @@ static void draw_button(WinManager *man,
+ {
+ ConsoleDebug(X11, "\tDrawing reliefs\n");
+ if (!PictureUseBWOnly())
+ {
+ get_gcs(
+ man, button_state, win->iconified,
+ &context1, &context2);
+ draw_relief(
+ man, button_state, &g, context1,
+ context2);
++
++ draw_rounded_corners(man, &g, context1);
+ }
+ else if (button_state & SELECT_CONTEXT)
+ {
+ XDrawRectangle(
+ theDisplay, man->theWindow,
+ man->hiContext[button_state],
+ g.button_x + 2, g.button_y + 1,
+ g.button_w - 4, g.button_h - 2);
+ }
+ }
diff --git a/windowmanagers/fvwm/patches/16-FvwmButtonsTips.patch
b/windowmanagers/fvwm/patches/16-FvwmButtonsTips.patch
new file mode 100644
index 0000000..42466ff
--- /dev/null
+++ b/windowmanagers/fvwm/patches/16-FvwmButtonsTips.patch
@@ -0,0 +1,547 @@
+diff -U10 -Naupr fvwm-2.5.21-15/libs/FTips.c fvwm-2.5.21-16/libs/FTips.c
+--- fvwm-2.5.21-15/libs/FTips.c 2007-03-03 13:24:15.000000000 +0100
++++ fvwm-2.5.21-16/libs/FTips.c 2007-03-03 13:25:14.000000000 +0100
+@@ -496,21 +496,21 @@ void FTipsOn(
+ unsigned long delay;
+
+ box.x = x;
+ box.y = y;
+ box.width = w;
+ box.height = h;
+
+ if (fc == NULL)
+ {
+ fc = default_config;
+- }
++ }
+ current_config = fc;
+
+ if (label != NULL)
+ {
+ free(label);
+ }
+ CopyString(&label, str);
+ win_for = win_f;
+
+ if (id == boxID)
+diff -U10 -Naupr fvwm-2.5.21-15/modules/FvwmButtons/FvwmButtons.c
fvwm-2.5.21-16/modules/FvwmButtons/FvwmButtons.c
+--- fvwm-2.5.21-15/modules/FvwmButtons/FvwmButtons.c 2007-03-03
13:24:15.000000000 +0100
++++ fvwm-2.5.21-16/modules/FvwmButtons/FvwmButtons.c 2007-03-03
13:25:14.000000000 +0100
+@@ -56,20 +56,21 @@
+ #include "libs/FRenderInit.h"
+ #include "libs/Grab.h"
+ #include <libs/gravity.h>
+ #include "fvwm/fvwm.h"
+ #include "libs/Module.h"
+ #include "libs/fvwmsignal.h"
+ #include "libs/Colorset.h"
+ #include "libs/vpacket.h"
+ #include "libs/FRender.h"
+ #include "libs/fsm.h"
++#include "libs/FTips.h"
+
+ #include "FvwmButtons.h"
+ #include "misc.h" /* ConstrainSize() */
+ #include "parse.h" /* ParseConfiguration(), parse_window_geometry() */
+ #include "draw.h"
+ #include "dynamic.h"
+
+
+ #define MW_EVENTS ( \
+ ExposureMask | \
+@@ -922,20 +923,21 @@ static button_info *handle_new_position(
+ redraw = True;
+ }
+
+ if (b != ActiveButton && CurrentButton == NULL)
+ {
+ if (ActiveButton)
+ {
+ button_info *tmp = ActiveButton;
+ ActiveButton = b;
+ RedrawButton(tmp, DRAW_FORCE, NULL);
++
+ }
+ if (b->flags.b_ActiveIcon || b->flags.b_ActiveTitle ||
+ UberButton->c->flags.b_ActiveColorset)
+ {
+ ActiveButton = b;
+ redraw = True;
+ }
+ }
+ if (redraw)
+ {
+@@ -1075,20 +1077,23 @@ void Loop(void)
+ char buffer[10], *act;
+ int i, button;
+ int x;
+ int y;
+ button_info *ub, *b;
+ button_info *tmpb;
+ FlocaleNameString tmp;
+
+ tmp.name = NULL;
+ tmp.name_list = NULL;
++
++ FTipsInit(Dpy);
++
+ while ( !isTerminated )
+ {
+ if (My_FNextEvent(Dpy, &Event))
+ {
+ if (FShapesSupported && Event.type == FShapeEventBase
+ FShapeNotify)
+ {
+ FShapeEvent *sev = (FShapeEvent *) &Event;
+
+ if (sev->kind != FShapeBounding)
+ {
+@@ -1200,20 +1205,24 @@ void Loop(void)
+ {
+ XEvent event;
+ unsigned int depth, tw, th, border_width;
+ Window root;
+
+ while (FCheckTypedWindowEvent(Dpy, MyWindow, ConfigureNotify, &event))
+ {
+ if (!event.xconfigure.send_event &&
+ Event.xconfigure.window != MyWindow)
+ continue;
++
++ if(FTipsHandleEvents(Dpy, &event))
++ continue;
++
+ Event.xconfigure.x = event.xconfigure.x;
+ Event.xconfigure.y = event.xconfigure.y;
+ Event.xconfigure.send_event = True;
+ }
+ if (!XGetGeometry(Dpy, MyWindow, &root, &x, &y, &tw, &th,
+ &border_width, &depth))
+ {
+ break;
+ }
+ if (tw != Width || th != Height)
+@@ -1242,41 +1251,66 @@ void Loop(void)
+ Event.xconfigure.send_event)
+ {
+ update_root_transparency(&Event);
+ }
+ }
+ break;
+
+ case EnterNotify:
+ b = handle_new_position(
+ b, Event.xcrossing.x, Event.xcrossing.y);
++
++ if(Event.xcrossing.mode == NotifyNormal)
++ {
++ b = handle_new_position(
++ b, Event.xcrossing.x, Event.xcrossing.y);
++ FTipsOn(Dpy,MyWindow,UberButton->c->tips_config,
++ (void *)UberButton, b->tipslabel,
++ b->x, b->y, Width,Height);
++ FTipsUpdateLabel(Dpy, b->tipslabel);
++ }
+ break;
+
+ case MotionNotify:
++
+ b = handle_new_position(b, Event.xmotion.x, Event.xmotion.y);
++
++ x = Event.xbutton.x;
++ y = Event.xbutton.y;
++
++ if(b->tipslabel != NULL)
++ {
++ FTipsOn(Dpy,MyWindow,UberButton->c->tips_config,
(void *)UberButton, b->tipslabel, x, y, w, h);
++ FTipsUpdateLabel(Dpy, b->tipslabel);
++ } else {
++ FTipsCancel(Dpy);
++ }
++
+ break;
+
+ case LeaveNotify:
+ {
+ if (reallyLeaveWindow(Event.xcrossing.x, Event.xcrossing.y,
+ Event.xcrossing.window, NULL))
+ {
+ if (ActiveButton)
+ {
+ b = ActiveButton;
+ ActiveButton = NULL;
+ RedrawButton(b, DRAW_FORCE, NULL);
++
+ }
+ if (CurrentButton)
+ {
+ RedrawButton(b, DRAW_FORCE, NULL);
+ }
++ FTipsCancel(Dpy);
+ }
+ break;
+ }
+ case KeyPress:
+ XLookupString(&Event.xkey, buffer, 10, &keysym, 0);
+ if (
+ keysym != XK_Return && keysym != XK_KP_Enter &&
+ keysym != XK_Linefeed)
+ break; /* fall through to ButtonPress */
+
+@@ -1284,22 +1318,22 @@ void Loop(void)
+ if (Event.xbutton.window == MyWindow)
+ {
+ x = Event.xbutton.x;
+ y = Event.xbutton.y;
+ }
+ else
+ {
+ Window dummy;
+
+ XTranslateCoordinates(
+- Dpy, Event.xbutton.window, MyWindow, Event.xbutton.x,
+- Event.xbutton.y, &x, &y, &dummy);
++ Dpy, Event.xbutton.window, MyWindow,
Event.xbutton.x,
++ Event.xbutton.y, &x, &y, &dummy);
+ }
+ if (CurrentButton)
+ {
+ b = CurrentButton;
+ CurrentButton = NULL;
+ ActiveButton = select_button(UberButton, x, y);
+ RedrawButton(b, DRAW_FORCE, NULL);
+ if (ActiveButton != b)
+ {
+ RedrawButton(ActiveButton, DRAW_FORCE, NULL);
+@@ -1327,21 +1361,24 @@ void Loop(void)
+
+ /* Undraw ActiveButton (if there is one). */
+ if (ActiveButton)
+ {
+ /* $b & $ActiveButton are always the same button. */
+ button_info *tmp = ActiveButton;
+ ActiveButton = NULL;
+ RedrawButton(tmp, DRAW_FORCE, NULL);
+ }
+ else
++ {
+ RedrawButton(b, DRAW_FORCE, NULL);
++ }
++
+ if (!act)
+ {
+ break;
+ }
+ if (act && !b->flags.b_ActionOnPress &&
+ strncasecmp(act, "popup", 5) != 0)
+ {
+ free(act);
+ act = NULL;
+ break;
+diff -U10 -Naupr fvwm-2.5.21-15/modules/FvwmButtons/FvwmButtons.h
fvwm-2.5.21-16/modules/FvwmButtons/FvwmButtons.h
+--- fvwm-2.5.21-15/modules/FvwmButtons/FvwmButtons.h 2007-03-03
13:24:15.000000000 +0100
++++ fvwm-2.5.21-16/modules/FvwmButtons/FvwmButtons.h 2007-03-03
13:25:14.000000000 +0100
+@@ -31,20 +31,22 @@
+
+ /* ---------------------------- compatibility
------------------------------ */
+
+ /*#define OLD_EXPOSE*/ /* Try this if resizing/exposes screw up */
+
+ /* -------------------------------- more
---------------------------------- */
+
+ #include "libs/fvwmlib.h"
+ #include "libs/Picture.h"
+ #include "libs/Flocale.h"
++#include "libs/FTips.h"
++#define FONT_STRING "-*-fixed-medium-r-normal--13-*"
+
+ /* ------------------------------- structs
--------------------------------- */
+
+ /* flags for b->flags */
+ typedef struct
+ {
+ unsigned b_Container : 1; /* Contains several buttons */
+ unsigned b_Font : 1; /* Has personal font data */
+ unsigned b_Fore : 1; /* Has personal text color */
+ unsigned b_Back : 1; /* Has personal background color (or
"none") */
+@@ -74,20 +76,21 @@ typedef struct
+ /* Actions work only on the background
+ of a button with a swallowed app. */
+ unsigned b_ActionOnPress : 1; /* By default this only done on Popup
*/
+ unsigned b_Id : 1; /* Has user-defined id for referencing
*/
+ unsigned b_ActiveIcon : 1; /* Use alternate Icon on hover */
+ unsigned b_ActiveColorset : 1; /* Use alternate colorset on hover */
+ unsigned b_ActiveTitle : 1; /* Use alternate Title text on hover */
+ unsigned b_PressIcon : 1; /* Use alternate Icon on press */
+ unsigned b_PressColorset : 1; /* Use alternate Colorset on press */
+ unsigned b_PressTitle : 1; /* Use alternate Title text on press */
++ unsigned b_UseTips : 1; /* Whether to use tips or not. */

+ } flags_type;
+
+ /* Flags for b->swallow */
+ #define b_Count 0x0003 /* Init counter for swallowing */
+ #define b_NoHints 0x0004 /* Ignore window hints from swallowed window */
+ #define b_NoClose 0x0008 /* Don't close window when exiting, unswallow
it */
+ #define b_Kill 0x0010 /* Don't close window when exiting, kill it */
+ #define b_Respawn 0x0020 /* Respawn if swallowed window dies */
+ #define b_UseOld 0x0040 /* Try to capture old window, don't spawn it */
+ #define b_UseTitle 0x0080 /* Allow window to write to b->title */
+@@ -123,20 +126,23 @@ struct container_info_struct
+ byte xpad, ypad; /* b_Padding */
+ signed char framew; /* b_Frame */
+ FlocaleFont *Ffont; /* b_Font */
+ char *font_string; /* b_Font */
+ char *back; /* b_Back && !b_IconBack */
+ char *back_file; /* b_Back && b_IconBack */
+ char *fore; /* b_Fore */
+ int colorset; /* b_Colorset */
+ int activeColorset; /* b_ActiveColorset */
+ int pressColorset; /* b_PressColorset */
++ char *tipsfont; /* b_TipsFont*/
++ ftips_config *tips_config; /* Struct that holds tips info.*/
++
+ Pixel fc; /* b_Fore */
+ Pixel bc, hc, sc; /* b_Back && !b_IconBack */
+ FvwmPicture *backicon; /* b_Back && b_IconBack */
+ ushort minx, miny; /* b_Size */
+ };
+
+ typedef struct
+ {
+ unsigned smooth : 1;
+ unsigned ignore_lrborder : 1;
+@@ -179,20 +185,21 @@ struct button_info_struct
+ char *hangon; /* b_Hangon || b_Swallow */
+ Pixel fc; /* b_Fore */
+ Pixel bc, hc, sc; /* b_Back && !b_IconBack */
+ ushort minx, miny; /* b_Size */
+ FvwmPicture *icon; /* b_Icon */
+ FvwmPicture *backicon; /* b_Back && b_IconBack */
+ FvwmPicture *activeicon; /* b_ActiveIcon */
+ FvwmPicture *pressicon; /* b_PressIcon */
+ int activeColorset; /* b_ActiveColorset */
+ int pressColorset; /* b_PressColorset */
++ char *tipslabel; /* b_TipsLabel */
+ Window IconWin; /* b_Swallow */
+ Window PanelWin; /* b_Panel */
+ Window BackIconWin; /* b_Back && b_IconBack */
+
+ unsigned int swallow; /* b_Swallow */
+ unsigned int swallow_mask; /* b_Swallow */
+ int icon_w, icon_h; /* b_Swallow */
+ Window IconWinParent; /* b_Swallow */
+ XSizeHints *hints; /* b_Swallow && !b_NoHints */
+ char *spawn; /* b_Swallow */
+diff -U10 -Naupr fvwm-2.5.21-15/modules/FvwmButtons/parse.c
fvwm-2.5.21-16/modules/FvwmButtons/parse.c
+--- fvwm-2.5.21-15/modules/FvwmButtons/parse.c 2007-03-03 13:24:15.000000000
+0100
++++ fvwm-2.5.21-16/modules/FvwmButtons/parse.c 2007-03-03 13:25:14.000000000
+0100
+@@ -880,20 +880,21 @@ static void ParseButton(button_info **ub
+ "center",
+ "colorset",
+ "action",
+ "id",
+ "activeicon",
+ "activetitle",
+ "pressicon",
+ "presstitle",
+ "activecolorset",
+ "presscolorset",
++ "tipslabel",
+ NULL
+ };
+ s = trimleft(s);
+ while (*s && *s != ')')
+ {
+ Bool is_swallow = False;
+
+ if (*s == ',')
+ {
+ s++;
+@@ -1618,21 +1619,47 @@ static void ParseButton(button_info **ub
+ b->pressColorset = i;
+ b->flags.b_PressColorset = 1;
+ s = t;
+ AllocColorset(i);
+ }
+ else
+ {
+ b->flags.b_PressColorset = 0;
+ }
+ break;
++ /* --------- TipsLabel ---------*/
++ case 27:
++ s = trimleft(s);
++ t = seekright(&s);
++ if(ub->c->flags.b_UseTips)
++ {
++ if (*s == '(')
++ {
++ fprintf(stderr,
++ "%s: justification not
allowed "
++ "for TipsLabel.\n", MyName);
++ }
++
++
++
++ if (t && *t && (t[0] != '-' || t[1]
!= 0))
++ {
++ if (b->tipslabel != NULL)
++ {
++ free(b->tipslabel);
++ } else {
++ b->tipslabel = t;
++ }
++ }
++ }
+
++ break;
+ /* --------------- --------------- */
+ default:
+ t = seekright(&s);
+ fprintf(stderr,
+ "%s: Illegal button option \"%s\"\n",
+ MyName, (t) ? t : "");
+ if (t)
+ {
+ free(t);
+ }
+@@ -1771,20 +1798,28 @@ static void ParseConfigLine(button_info
+ "rows",
+ "back",
+ "fore",
+ "frame",
+ "file",
+ "pixmap",
+ "boxsize",
+ "colorset",
+ "activecolorset",
+ "presscolorset",
++ "usetips",
++ "tipsfont",
++ "tipsdelay",
++ "tipscolorset",
++ "tipsborderwidth",
++ "tipsplacement",
++ "tipsjustification",
++ "tipsoffset",
+ NULL
+ };
+ int i, j, k;
+
+ switch (GetTokenIndex(s, opts, -1, &s))
+ {
+ case 0:/* Geometry */
+ {
+ char geom[64];
+
+@@ -1918,21 +1953,111 @@ static void ParseConfigLine(button_info
+ {
+ ub->c->pressColorset = j;
+ ub->c->flags.b_PressColorset = 1;
+ AllocColorset(j);
+ }
+ else
+ {
+ ub->c->flags.b_PressColorset = 0;
+ }
+ break;
++ case 15: /* UseTips */
++ /* We're using tips.*/
++ ub->c->flags.b_UseTips = 1;
++
++ /* Set the defaults up. */
++ ub->c->tips_config = FTipsNewConfig();
++
++ /* Include fonts. */
++ CopyStringWithQuotes(&ub->c->tipsfont,FONT_STRING);
++ ub->c->tips_config->Ffont = FlocaleLoadFont(Dpy,
++ ub->c->tipsfont, MyName);
++ break;
++ case 16: /* TipsFont */
++ if(ub->c->flags.b_UseTips)
++ {
++ CopyStringWithQuotes(&ub->c->tipsfont,s);
+
++ ub->c->tips_config->Ffont = FlocaleLoadFont(Dpy,
ub->c->tipsfont,
++ MyName);
++ }
++
++ break;
++ case 17: /*TipsDelay */
++ if(ub->c->flags.b_UseTips)
++ {
++ i = sscanf(s, "%d %d", &j, &k);
++ if( i > 0)
++ {
++ /* Then only one value was given. Set the
++ * mapped_delay option to this given value
++ * also since it's optional.
++ */
++ ub->c->tips_config->delay =
ub->c->tips_config->mapped_delay = j;
++ }
++ if( i > 1)
++ {
++ /* Two values passed in. We only need to
++ * change the value for mapped_delay here.
++ */
++
++ ub->c->tips_config->mapped_delay = k;
++
++ }
++ }
++ break;
++ case 18: /* TipsColorset */
++ if (ub->c->flags.b_UseTips)
++ {
++ i = sscanf(s, "%d", &j);
++ if (i > 0)
++ {
++ ub->c->tips_config->colorset = j;
++ AllocColorset(j);
++ }
++ }
++ break;
++ case 19: /* TipsBorderWidth */
++ if (ub->c->flags.b_UseTips)
++ {
++ i = sscanf(s, "%d", &j);
++
++ if(i > 0)
++ {
++ ub->c->tips_config->border_width = j;
++ }
++ }
++ break;
++ case 20: /* TipsPlacement */
++ if(ub->c->flags.b_UseTips)
++ {
++ s = trimleft(s);
++
++ /* Options ... */
++ if(!strcasecmp(s, "up"))
++ {
++ i = FTIPS_PLACEMENT_UP;
++ } else if(!strcasecmp(s, "down")) {
++ i = FTIPS_PLACEMENT_DOWN;
++ } else if(!strcasecmp(s, "left")) {
++ i = FTIPS_PLACEMENT_LEFT;
++ } else if(!strcasecmp(s, "right")) {
++ i = FTIPS_PLACEMENT_RIGHT;
++ } else if(!strcasecmp(s, "updown")) {
++ i = FTIPS_PLACEMENT_AUTO_UPDOWN;
++ } else if(!strcasecmp(s, "leftright")) {
++ i = FTIPS_PLACEMENT_AUTO_LEFTRIGHT;
++ }
++
++ ub->c->tips_config->placement = i;
++ }
++ break;
+ default:
+ s = trimleft(s);
+ ParseButton(ubb, s);
+ break;
+ }
+ }
+
+ /**
+ *** ParseConfigFile()
+ *** Parses optional separate configuration file for FvwmButtons
diff --git a/windowmanagers/fvwm/patches/17-DefaultCharset.patch
b/windowmanagers/fvwm/patches/17-DefaultCharset.patch
new file mode 100644
index 0000000..20cc4e2
--- /dev/null
+++ b/windowmanagers/fvwm/patches/17-DefaultCharset.patch
@@ -0,0 +1,26 @@
+diff -U10 -Naupr fvwm-2.5.21-16/libs/FlocaleCharset.c
fvwm-2.5.21-17/libs/FlocaleCharset.c
+--- fvwm-2.5.21-16/libs/FlocaleCharset.c 2007-03-03 13:25:06.000000000
+0100
++++ fvwm-2.5.21-17/libs/FlocaleCharset.c 2007-03-03 13:26:26.000000000
+0100
+@@ -515,21 +515,21 @@ void FlocaleInit_X_Charset(Display *dpy,
+ #endif
+ }
+ }
+ }
+ if (om)
+ {
+ XCloseOM(om);
+ }
+
+ if (FLCXOMCharsetList_num > 0 && FLCXOMCharsetList[0])
+- FLCXOMCharset = FLCXOMCharsetList[0];
++ FLCXOMCharset = FLCXOMCharsetList[FLCXOMCharsetList_num - 1];
+ #endif
+ }
+
+ /* ---------------------------- interface functions
------------------------ */
+
+ void FlocaleCharsetInit(Display *dpy, const char *module)
+ {
+ static Bool initialized = False;
+ char *charset;
+
diff --git a/windowmanagers/fvwm/patches/18-FirstItemUnderPointer.patch
b/windowmanagers/fvwm/patches/18-FirstItemUnderPointer.patch
new file mode 100644
index 0000000..1b29b99
--- /dev/null
+++ b/windowmanagers/fvwm/patches/18-FirstItemUnderPointer.patch
@@ -0,0 +1,181 @@
+diff -U10 -Naupr fvwm-2.5.21-17/fvwm/menus.c fvwm-2.5.21-18/fvwm/menus.c
+--- fvwm-2.5.21-17/fvwm/menus.c 2007-03-03 13:26:07.000000000 +0100
++++ fvwm-2.5.21-18/fvwm/menus.c 2007-03-03 13:26:56.000000000 +0100
+@@ -3114,20 +3114,27 @@ static int pop_menu_up(
+ * empty from the start. */
+ return False;
+ }
+ fw = (*pexc)->w.fw;
+ if (fw && !check_if_fvwm_window_exists(fw))
+ {
+ fw = NULL;
+ }
+ context = (*pexc)->w.wcontext;
+
++ /* Popup menu with first item (not title) under pointer */
++ if(MI_IS_TITLE(MR_FIRST_ITEM(mr)))
++ {
++ y-=MI_HEIGHT(MR_FIRST_ITEM(mr));
++ do_warp_to_item = True;
++ }
++
+ /*
+ * 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)
+ {
+diff -U10 -Naupr fvwm-2.5.21-17/fvwm/menus.c~ fvwm-2.5.21-18/fvwm/menus.c~
+--- fvwm-2.5.21-17/fvwm/menus.c~ 2007-03-03 13:26:07.000000000 +0100
++++ fvwm-2.5.21-18/fvwm/menus.c~ 2007-03-03 13:26:38.000000000 +0100
+@@ -2429,20 +2429,55 @@ static Bool paint_menu_gradient_backgrou
+ XFreeGC(dpy, pmapgc);
+ XFreePixmap(dpy, pmap);
+ MR_IS_BACKGROUND_SET(mr) = True;
+ }
+ do_clear = True;
+ break;
+ }
+ return do_clear;
+ }
+
++#define DRAWMENUBORDER(NUM, XX, YY) XCopyArea(\
++ dpy, pm[(NUM)]->picture, MR_WINDOW(mr), Scr.TransMaskGC,\
++ 0, 0, pm[(NUM)]->width, pm[(NUM)]->height, (XX), (YY))
++static Bool paint_menu_multipixmap_background(
++ MenuRoot *mr, XEvent *pevent)
++{
++ MenuStyle *ms = MR_STYLE(mr);
++ int width, height, x, y;
++ int bw = MST_BORDER_WIDTH(mr);
++ FvwmPicture **pm;
++ pm = ST_FACE(ms).u.mb.pixmaps;
++
++ width = MR_WIDTH(mr);
++ height = MR_HEIGHT(mr);
++
++ FvwmPicture *p = pm[0];
++
++ width = MR_WIDTH(mr);
++ height = MR_HEIGHT(mr);
++
++ x = 0;
++
++ for (x = 0; x < width; x+=pm[1]->width) DRAWMENUBORDER(1, x, 0);
++ for (x = 0; x < width; x+=pm[5]->width) DRAWMENUBORDER(5, x,
height-pm[5]->height);
++ for (x = 0; x < height; x+=pm[3]->height) DRAWMENUBORDER(3,
width-pm[3]->height, x);
++ for (x = 0; x < height; x+=pm[7]->height) DRAWMENUBORDER(7, 0, x);
++
++ DRAWMENUBORDER(0, 0, 0);
++ DRAWMENUBORDER(2, width-pm[2]->width, 0);
++ DRAWMENUBORDER(4, width-pm[4]->width, height-pm[4]->height);
++ DRAWMENUBORDER(6, 0, height-pm[6]->height);
++
++ return False;
++}
++
+ 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;
+@@ -2533,29 +2568,34 @@ static void paint_menu(
+ 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);
++ if (ms && ST_FACE(ms).type == MultiPixmapMenu)
+ {
+- return;
++ paint_menu_multipixmap_background(mr, pevent);
+ }
++ else
++ {
++ 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)],
+@@ -2576,37 +2616,43 @@ static void paint_menu(
+ 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 MultiPixmapMenu:
++ do_clear = paint_menu_multipixmap_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);
++ if (!(ms && ST_FACE(ms).type == MultiPixmapMenu))
++ {
++ 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;
diff --git a/windowmanagers/fvwm/patches/19-FluxCorner.patch
b/windowmanagers/fvwm/patches/19-FluxCorner.patch
new file mode 100644
index 0000000..53b54af
--- /dev/null
+++ b/windowmanagers/fvwm/patches/19-FluxCorner.patch
@@ -0,0 +1,26 @@
+diff -U10 -Naupr fvwm-2.5.21-18/fvwm/borders.c fvwm-2.5.21-19/fvwm/borders.c
+--- fvwm-2.5.21-18/fvwm/borders.c 2007-03-03 13:26:38.000000000 +0100
++++ fvwm-2.5.21-19/fvwm/borders.c 2007-03-03 13:27:13.000000000 +0100
+@@ -1388,21 +1388,21 @@ static void border_fill_pixmap_backgroun
+ 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;
++ //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(
diff --git a/windowmanagers/fvwm/patches/20-ThinGeometryProxy.patch
b/windowmanagers/fvwm/patches/20-ThinGeometryProxy.patch
new file mode 100644
index 0000000..5f5b7c5
--- /dev/null
+++ b/windowmanagers/fvwm/patches/20-ThinGeometryProxy.patch
@@ -0,0 +1,3580 @@
+diff -U10 -Naupr fvwm-2.5.21-19/libs/defaults.h
fvwm-2.5.21-20/libs/defaults.h
+--- fvwm-2.5.21-19/libs/defaults.h 2007-03-03 13:27:04.000000000 +0100
++++ fvwm-2.5.21-20/libs/defaults.h 2007-03-03 13:27:34.000000000 +0100
+@@ -144,21 +144,21 @@
+ #define MIN_ALLOWABLE_ICON_DIMENSION 0 /* pixels */
+ #define MAX_ALLOWABLE_ICON_DIMENSION 255 /* pixels */
+
+ /* this value is used in a bugfix */
+ #define WINDOW_FREAKED_OUT_SIZE 65500 /* pixels */
+ /* Used in Workaround for broken min and max size hints vs a size request */
+ #define BROKEN_MAXSIZE_LIMIT 1
+ #define BROKEN_MINSIZE_LIMIT 30000
+
+ /* geometry window */
+-#define GEOMETRY_WINDOW_BW 2 /* pixels */
++#define GEOMETRY_WINDOW_BW 1 /* pixels */
+ #define GEOMETRY_WINDOW_STRING " +8888 x +8888 "
+ #define GEOMETRY_WINDOW_POS_STRING " %+-4d %+-4d "
+ #define GEOMETRY_WINDOW_SIZE_STRING " %4d x %-4d "
+
+ /*
+ * window title layout
+ */
+ /* the title buttons are shrunk if the title would become smaller than this
+ * number of pixels */
+ #define MIN_WINDOW_TITLE_LENGTH 10 /* pixels */
+diff -U10 -Naupr fvwm-2.5.21-19/modules/FvwmProxy/FvwmProxy.c
fvwm-2.5.21-20/modules/FvwmProxy/FvwmProxy.c
+--- fvwm-2.5.21-19/modules/FvwmProxy/FvwmProxy.c 2007-03-03
13:27:05.000000000 +0100
++++ fvwm-2.5.21-20/modules/FvwmProxy/FvwmProxy.c 2007-03-03
13:29:34.000000000 +0100
+@@ -955,21 +955,21 @@ static void DrawWindow(
+ XSetForeground(dpy,fg_gc,Colorset[cset].fg);
+ XSetBackground(dpy,fg_gc,Colorset[cset].bg);
+ XSetForeground(dpy,sh_gc,Colorset[cset].shadow);
+ XSetForeground(dpy,hi_gc,Colorset[cset].hilite);
+
+ /* FIXME: use clip redrawing (not really essential here) */
+ if (FLF_FONT_HAS_ALPHA(Ffont,cset) || PICTURE_HAS_ALPHA(picture,cset))
+ {
+ XClearWindow(dpy,proxy->proxy);
+ }
+- RelieveRectangle(dpy,proxy->proxy, 0,0, w - 1,h - 1, hi_gc,sh_gc, 2);
++ RelieveRectangle(dpy,proxy->proxy, 0,0, w - 1,h - 1, hi_gc,sh_gc, 1);
+
+ big_name = proxy->iconname;
+ if(big_name==NULL || !big_name[0])
+ {
+ big_name = proxy->name;
+ }
+ small_name = proxy->name;
+ if(small_name == NULL)
+ {
+ small_name=big_name;
+diff -U10 -Naupr fvwm-2.5.21-19/modules/FvwmProxy/FvwmProxy.c~
fvwm-2.5.21-20/modules/FvwmProxy/FvwmProxy.c~
+--- fvwm-2.5.21-19/modules/FvwmProxy/FvwmProxy.c~ 1970-01-01
01:00:00.000000000 +0100
++++ fvwm-2.5.21-20/modules/FvwmProxy/FvwmProxy.c~ 2007-03-03
13:27:24.000000000 +0100
+@@ -0,0 +1,3524 @@
++/* -*-c-*- */
++/* vim: set ts=8 shiftwidth=8: */
++/* This module, FvwmProxy, is an original work by Jason Weber.
++ *
++ * 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/Module.h"
++#include "libs/fvwmlib.h"
++#include "libs/FRenderInit.h"
++#include "libs/FRender.h"
++#include "libs/Colorset.h"
++#include "libs/Flocale.h"
++#include "libs/gravity.h"
++#include "libs/FScreen.h"
++#include "libs/Picture.h"
++#include "libs/PictureGraphics.h"
++#include "libs/safemalloc.h"
++#include "libs/charmap.h"
++#include "libs/modifiers.h"
++
++#include "FvwmProxy.h"
++
++/* ---------------------------- local definitions
--------------------------- */
++
++/* defaults for things we put in a configuration file */
++
++#define PROXY_GROUP_DEBUG False
++#define PROXY_KEY_POLLING True
++#define PROXY_MOVE False /* move window when proxy is dragged
*/
++#define PROXY_ICONIFIED False /* show proxy when iconified
*/
++#define PROXY_WIDTH 180
++#define PROXY_HEIGHT 60
++#define PROXY_SEPARATION 10
++#define PROXY_MINWIDTH 15
++#define PROXY_MINHEIGHT 10
++#define PROXY_SLOT_SIZE 16
++#define PROXY_SLOT_SPACE 4
++#define PROXY_GROUP_SLOT 2
++#define PROXY_GROUP_COUNT 6
++#define PROXY_STAMP_LIMIT 8
++
++#define STARTUP_DEBUG False /* store output before log is opened
*/
++
++#define CMD_SELECT "WindowListFunc $[w.id]"
++#define CMD_CLICK1 "Raise"
++#define CMD_CLICK3 "Lower"
++#define CMD_DEFAULT "Nop"
++
++/* ---------------------------- local macros
-------------------------------- */
++
++/* ---------------------------- imports
------------------------------------- */
++
++/* ---------------------------- included code files
------------------------- */
++
++/* ---------------------------- local types
--------------------------------- */
++
++/* ---------------------------- forward declarations
------------------------ */
++
++/* ---------------------------- local variables
----------------------------- */
++
++static char *ImagePath = NULL;
++static char *MyName;
++static int x_fd;
++static fd_set_size_t fd_width;
++static int fd[2];
++static Display *dpy;
++static unsigned long screen;
++static GC fg_gc;
++static GC hi_gc;
++static GC sh_gc;
++static GC miniIconGC;
++static Window rootWindow;
++static Window focusWindow;
++static XTextProperty windowName;
++static int deskNumber=0;
++static int mousex,mousey;
++static ProxyWindow *firstProxy=NULL;
++static ProxyWindow *lastProxy=NULL;
++static ProxyWindow *selectProxy=NULL;
++static ProxyWindow *startProxy=NULL;
++static ProxyWindow *enterProxy=NULL;
++static ProxyWindow *last_rotation_instigator=NULL;
++static ProxyGroup *firstProxyGroup=NULL;
++static FvwmPicture **pictureArray=NULL;
++static int numSlots=0;
++static int miniIconSlot=0;
++static XGCValues xgcv;
++static int are_windows_shown = 0;
++static int watching_modifiers = 0;
++static int waiting_to_config = 0;
++static int waiting_to_stamp = 0;
++static int pending_do = 0;
++static unsigned int held_modifiers=0;
++static int watched_modifiers=0;
++static FlocaleWinString *FwinString;
++
++static int cset_normal = 0;
++static int cset_select = 0;
++static int cset_iconified = 0;
++static char *font_name = NULL;
++static char *small_font_name = NULL;
++static FlocaleFont *Ffont;
++static FlocaleFont *Ffont_small;
++static int enterSelect=False;
++static int showMiniIcons=True;
++static int proxyIconified=PROXY_ICONIFIED;
++static int proxyMove=PROXY_MOVE;
++static int proxyWidth=PROXY_WIDTH;
++static int proxyHeight=PROXY_HEIGHT;
++static int proxySeparation=PROXY_SEPARATION;
++static int slotWidth=PROXY_SLOT_SIZE;
++static int slotHeight=PROXY_SLOT_SIZE;
++static int slotSpace=PROXY_SLOT_SPACE;
++static int groupSlot=PROXY_GROUP_SLOT;
++static int groupCount=PROXY_GROUP_COUNT;
++static int stampLimit=PROXY_STAMP_LIMIT;
++
++static GeometryStamp* stampQueue=NULL;
++static int stamp= 0;
++static int stampMin=0;
++static int stampMax=0;
++
++static char commandBuffer[256];
++static char resultBuffer[256];
++
++typedef enum
++{
++ PROXY_ACTION_SELECT = 0,
++ PROXY_ACTION_SHOW,
++ PROXY_ACTION_HIDE,
++ PROXY_ACTION_ABORT,
++ PROXY_ACTION_MARK,
++ PROXY_ACTION_UNMARK,
++ PROXY_ACTION_MODIFIER_RELEASE,
++ /* this one *must* be last */
++ PROXY_ACTION_CLICK,
++ PROXY_ACTION_LAST = PROXY_ACTION_CLICK +
++ NUMBER_OF_EXTENDED_MOUSE_BUTTONS
++} proxy_action_t;
++
++#define GROUP_COLORS 7
++static char* group_color[GROUP_COLORS][2] =
++{
++ {"#dddddd", "#777777"},
++ {"#ffcccc", "#ff0000"},
++ {"#ccffcc", "#00ff00"},
++ {"#ccccff", "#0000ff"},
++ {"#ffccff", "#ff00ff"},
++ {"#ffffcc", "#ffff00"},
++ {"#ccffff", "#00ffff"}
++};
++
++char *action_list[PROXY_ACTION_LAST];
++char **slot_action_list[NUMBER_OF_EXTENDED_MOUSE_BUTTONS];
++
++static WindowName* new_WindowName(void);
++static ProxyGroup* FindProxyGroup(char* groupname);
++
++static int (*originalXErrorHandler)(Display *,XErrorEvent *);
++static int (*originalXIOErrorHandler)(Display *);
++
++/* ---------------------------- exported variables (globals)
---------------- */
++
++/* ---------------------------- local functions (options)
------------------- */
++
++static void ExpandSlots(int slots)
++{
++ int m;
++ int n;
++ if(slots>numSlots)
++ {
++ pictureArray=(FvwmPicture**)realloc(pictureArray,
++ sizeof(FvwmPicture*)*(slots));
++ for(m=0;m<NUMBER_OF_EXTENDED_MOUSE_BUTTONS;m++)
++ {
++ slot_action_list[m]=(char**)realloc(
++ slot_action_list[m],
++ sizeof(char*)*(slots));
++ for(n=numSlots;n<slots;n++)
++ {
++ slot_action_list[m][n]=NULL;
++ }
++ }
++ for(n=numSlots;n<slots;n++)
++ {
++ pictureArray[n]=NULL;
++ }
++ numSlots=slots;
++ }
++}
++
++static void LinkSlotAction(char *string)
++{
++ char *token;
++ int slot;
++
++ token = PeekToken(string, &string);
++ slot=atoi(token);
++
++ token = PeekToken(string, &string);
++ if (strncasecmp(token, "Click", 5) == 0)
++ {
++ int b;
++ int i;
++ i = sscanf(token + 5, "%d", &b);
++ if (i > 0 && b >=1 && b <= NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
++ {
++ ExpandSlots(slot+1);
++ if (slot_action_list[b-1][slot] != NULL)
++ {
++ free(slot_action_list[b-1][slot]);
++ }
++ slot_action_list[b-1][slot] = safestrdup(string);
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"slot_action_list[%d][%d]=\"%s\"\n",
++ b-1,slot,slot_action_list[b-1][slot]);
++#endif
++ }
++ }
++}
++
++static void LinkAction(char *string)
++{
++ char *token;
++
++ token = PeekToken(string, &string);
++ if (strncasecmp(token, "Click", 5) == 0)
++ {
++ int b;
++ int i;
++ i = sscanf(token + 5, "%d", &b);
++ if (i > 0 && b >=1 && b <= NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
++ {
++ if (action_list[PROXY_ACTION_CLICK + b - 1] != NULL)
++ {
++ free(action_list[PROXY_ACTION_CLICK + b - 1]);
++ }
++ action_list[PROXY_ACTION_CLICK + b - 1] =
++ safestrdup(string);
++ }
++ }
++ else if (StrEquals(token, "Select"))
++ {
++ if (action_list[PROXY_ACTION_SELECT] != NULL)
++ {
++ free(action_list[PROXY_ACTION_SELECT]);
++ }
++ action_list[PROXY_ACTION_SELECT] = safestrdup(string);
++ }
++ else if (StrEquals(token, "Show"))
++ {
++ if (action_list[PROXY_ACTION_SHOW] != NULL)
++ {
++ free(action_list[PROXY_ACTION_SHOW]);
++ }
++ action_list[PROXY_ACTION_SHOW] = safestrdup(string);
++ }
++ else if (StrEquals(token, "Hide"))
++ {
++ if (action_list[PROXY_ACTION_HIDE] != NULL)
++ {
++ free(action_list[PROXY_ACTION_HIDE]);
++ }
++ action_list[PROXY_ACTION_HIDE] = safestrdup(string);
++ }
++ else if (StrEquals(token, "Abort"))
++ {
++ if (action_list[PROXY_ACTION_ABORT] != NULL)
++ {
++ free(action_list[PROXY_ACTION_ABORT]);
++ }
++ action_list[PROXY_ACTION_ABORT] = safestrdup(string);
++ }
++ else if (StrEquals(token, "Mark"))
++ {
++ if (action_list[PROXY_ACTION_MARK] != NULL)
++ {
++ free(action_list[PROXY_ACTION_MARK]);
++ }
++ action_list[PROXY_ACTION_MARK] = safestrdup(string);
++ }
++ else if (StrEquals(token, "Unmark"))
++ {
++ if (action_list[PROXY_ACTION_UNMARK] != NULL)
++ {
++ free(action_list[PROXY_ACTION_UNMARK]);
++ }
++ action_list[PROXY_ACTION_UNMARK] = safestrdup(string);
++ }
++ else if (StrEquals(token, "ModifierRelease"))
++ {
++ token = PeekToken(string, &string);
++
++ if (action_list[PROXY_ACTION_MODIFIER_RELEASE] != NULL)
++ {
++ free(action_list[PROXY_ACTION_MODIFIER_RELEASE]);
++ }
++
++ modifiers_string_to_modmask(token, (int *)&watched_modifiers);
++ action_list[PROXY_ACTION_MODIFIER_RELEASE] =
safestrdup(string);
++ }
++
++ return;
++}
++
++#if 0
++static void parse_cmd(char **ret_cmd, char *cmd)
++{
++ if (*ret_cmd != NULL)
++ {
++ free(*ret_cmd);
++ *ret_cmd = NULL;
++ }
++ if (cmd != NULL)
++ {
++ *ret_cmd = safestrdup(cmd);
++ }
++
++ return;
++}
++#endif
++
++FvwmPicture* loadPicture(char* name)
++{
++ FvwmPicture *picture=NULL;
++ FvwmPictureAttributes fpa;
++
++ if(!name)
++ {
++ return NULL;
++ }
++
++ fpa.mask = FPAM_NO_COLOR_LIMIT;
++ picture = PGetFvwmPicture(dpy, RootWindow(dpy,screen),
++ ImagePath, name, fpa);
++ if (!picture)
++ {
++ fprintf(stderr, "loadPixmap failed to load \"%s\"\n", name);
++ }
++ return picture;
++}
++
++static Bool parse_options(void)
++{
++ int m;
++ char *tline;
++
++ memset(action_list, 0, sizeof(action_list));
++ action_list[PROXY_ACTION_SELECT] = strdup(CMD_SELECT);
++ action_list[PROXY_ACTION_CLICK + 0] = strdup(CMD_CLICK1);
++ if (NUMBER_OF_EXTENDED_MOUSE_BUTTONS > 2)
++ {
++ action_list[PROXY_ACTION_CLICK + 2] = strdup(CMD_CLICK3);
++ }
++ for (m=0;m<PROXY_ACTION_LAST;m++)
++ {
++ if (action_list[m]==NULL)
++ {
++ action_list[m] = strdup(CMD_DEFAULT);
++ }
++ }
++
++ InitGetConfigLine(fd, CatString3("*", MyName, 0));
++ for (GetConfigLine(fd, &tline); tline != NULL;
++ GetConfigLine(fd, &tline))
++ {
++ char *resource;
++ char *token;
++ char *next;
++
++ token = PeekToken(tline, &next);
++ if (StrEquals(token, "Colorset"))
++ {
++ LoadColorset(next);
++ continue;
++ }
++ if (StrEquals(token, "ImagePath"))
++ {
++ if (ImagePath)
++ {
++ free(ImagePath);
++ }
++ CopyString(&ImagePath, next);
++ continue;
++ }
++
++ tline = GetModuleResource(tline, &resource, MyName);
++ if (resource == NULL)
++ {
++ continue;
++ }
++
++ /* dump leading whitespace */
++ while (*tline==' ' || *tline=='\t')
++ tline++;
++ if (!strncasecmp(resource,"Action",6))
++ {
++ LinkAction(tline);
++ }
++ else if (!strncasecmp(resource,"SlotAction",10))
++ {
++ LinkSlotAction(tline);
++ }
++ else if (StrEquals(resource, "Colorset"))
++ {
++ if (sscanf(tline, "%d", &cset_normal) < 1)
++ {
++ cset_normal = 0;
++ }
++ }
++ else if (StrEquals(resource, "SelectColorset"))
++ {
++ if (sscanf(tline, "%d", &cset_select) < 1)
++ {
++ cset_select = 0;
++ }
++ }
++ else if (StrEquals(resource, "IconifiedColorset"))
++ {
++ if (sscanf(tline, "%d", &cset_iconified) < 1)
++ {
++ cset_iconified = 0;
++ }
++ }
++ else if (StrEquals(resource, "Font"))
++ {
++ if (font_name != NULL)
++ {
++ free(font_name);
++ }
++ font_name = safestrdup(tline);
++ }
++ else if (StrEquals(resource, "SmallFont"))
++ {
++ if (small_font_name != NULL)
++ {
++ free(small_font_name);
++ }
++ small_font_name = safestrdup(tline);
++ }
++ else if (StrEquals(resource, "ShowMiniIcons"))
++ {
++ showMiniIcons = ParseToggleArgument(tline, NULL, 0,
1);
++ }
++ else if (StrEquals(resource, "EnterSelect"))
++ {
++ enterSelect = ParseToggleArgument(tline, NULL, 0, 1);
++ }
++ else if (StrEquals(resource, "ProxyMove"))
++ {
++ proxyMove = ParseToggleArgument(tline, NULL, 0, 1);
++ }
++ else if (StrEquals(resource, "ProxyIconified"))
++ {
++ proxyIconified = ParseToggleArgument(tline, NULL, 0,
1);
++ }
++ else if (StrEquals(resource, "Width"))
++ {
++ if (sscanf(tline, "%d", &proxyWidth) < 1)
++ proxyWidth=PROXY_MINWIDTH;
++ }
++ else if (StrEquals(resource, "Height"))
++ {
++ if (sscanf(tline, "%d", &proxyHeight) < 1)
++ proxyHeight=PROXY_MINHEIGHT;
++ }
++ else if (StrEquals(resource, "Separation"))
++ {
++ if (sscanf(tline, "%d", &proxySeparation) < 1)
++ proxySeparation=False;
++ }
++ else if (StrEquals(resource, "UndoLimit"))
++ {
++ if (sscanf(tline, "%d", &stampLimit) < 1)
++ stampLimit=PROXY_STAMP_LIMIT;
++ }
++ else if (StrEquals(resource, "SlotWidth"))
++ {
++ if (sscanf(tline, "%d", &slotWidth) < 1)
++ slotWidth=PROXY_SLOT_SIZE;
++ }
++ else if (StrEquals(resource, "SlotHeight"))
++ {
++ if (sscanf(tline, "%d", &slotHeight) < 1)
++ slotHeight=PROXY_SLOT_SIZE;
++ }
++ else if (StrEquals(resource, "SlotSpace"))
++ {
++ if (sscanf(tline, "%d", &slotSpace) < 1)
++ slotSpace=PROXY_SLOT_SPACE;
++ }
++ else if (StrEquals(resource, "GroupSlot"))
++ {
++ if (sscanf(tline, "%d", &groupSlot) < 0)
++ groupSlot=PROXY_GROUP_SLOT;
++ }
++ else if (StrEquals(resource, "GroupCount"))
++ {
++ if (sscanf(tline, "%d", &groupCount) < 0)
++ groupCount=PROXY_GROUP_COUNT;
++ }
++ else if (StrEquals(resource, "SlotStyle"))
++ {
++ int slot= -1;
++ char style[128];
++ char name[128];
++ int bytes=0;
++ int args = sscanf(tline, "%d%s%*[^\"]\"%[^\"]\"%n",
++ &slot,style,name,&bytes);
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,
++ "SlotStyle: %d \"%s\" -> %d \"%s\" \"%s\"\n",
++ args,tline,slot,style,name);
++#endif
++ if (args>=3 && StrEquals(style, "Pixmap"))
++ {
++ ExpandSlots(slot+1);
++ pictureArray[slot]=loadPicture(name);
++ }
++ else if (args>=2 && StrEquals(style, "MiniIcon"))
++ {
++ miniIconSlot=slot;
++ }
++ }
++ else if (StrEquals(resource, "Group"))
++ {
++ char groupname[128];
++ char directive[128];
++ char tail[128];
++ char pattern[128];
++ int bytes=0;
++ int args = sscanf(tline, "\"%[^\"]\"%s%n",
++ groupname,directive,&bytes);
++ ProxyGroup* proxygroup;
++
++ strncpy(tail,&tline[bytes],128);
++ tail[127]=0;
++ args = sscanf(tail, "%*[^\"]\"%[^\"]\"",pattern);
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,
++ "Group: %d \"%s\" -> \"%s\" \"%s\" \"%s\"\n",
++ args,tline,groupname,directive,pattern);
++#endif
++
++ proxygroup=FindProxyGroup(groupname);
++ if (StrEquals(directive, "IgnoreIDs"))
++ {
++ proxygroup->flags.ignore_ids=1;
++ }
++ else if (StrEquals(directive, "AutoInclude"))
++ {
++ proxygroup->flags.auto_include=1;
++ }
++ else if (StrEquals(directive, "AutoSoft"))
++ {
++ proxygroup->flags.auto_include=1;
++ proxygroup->flags.auto_soft=1;
++ }
++ else if (StrEquals(directive, "Isolated"))
++ {
++ proxygroup->flags.isolated=1;
++ }
++ else if (StrEquals(directive, "Include") ||
++ StrEquals(directive, "SoftInclude"))
++ {
++ WindowName* include=new_WindowName();
++ include->name=strdup(pattern);
++ include->flags.is_soft=
++ StrEquals(directive, "SoftInclude");
++ include->next=proxygroup->includes;
++ proxygroup->includes=include;
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"Include \"%s\"\n",
++ pattern);
++#endif
++ }
++ else if (StrEquals(directive, "Exclude"))
++ {
++ WindowName* exclude=new_WindowName();
++ exclude->name=strdup(pattern);
++ exclude->next=proxygroup->excludes;
++ proxygroup->excludes=exclude;
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"Exclude \"%s\"\n",
++ pattern);
++#endif
++ }
++ }
++ else
++ {
++ fprintf(stderr,"Unknown: \"%s\"\n",tline);
++ }
++
++ free(resource);
++ }
++
++ return True;
++}
++
++/* ---------------------------- local functions (classes)
------------------- */
++
++/* classes */
++
++static void ProxyWindow_ProxyWindow(ProxyWindow *p)
++{
++ memset(p, 0, sizeof *p);
++}
++
++static ProxyWindow *new_ProxyWindow(void)
++{
++ ProxyWindow *p=(ProxyWindow *)safemalloc(sizeof(ProxyWindow));
++ ProxyWindow_ProxyWindow(p);
++ return p;
++}
++
++static void delete_ProxyWindow(ProxyWindow *p)
++{
++ if (p)
++ {
++ if (p->name)
++ {
++ free(p->name);
++ }
++ if (p->iconname)
++ {
++ free(p->iconname);
++ }
++ if (p->proxy != None)
++ {
++ XDestroyWindow(dpy, p->proxy);
++ }
++ free(p);
++ }
++}
++
++static void WindowName_WindowName(WindowName *p)
++{
++ memset(p, 0, sizeof *p);
++}
++
++static WindowName *new_WindowName(void)
++{
++ WindowName *p=(WindowName *)safemalloc(sizeof(WindowName));
++ WindowName_WindowName(p);
++ return p;
++}
++
++static void delete_WindowName(WindowName *p)
++{
++ if (p)
++ {
++ delete_WindowName(p->next);
++ free(p->name);
++ free(p);
++ }
++}
++
++static void ProxyGroup_ProxyGroup(ProxyGroup *p)
++{
++ memset(p, 0, sizeof *p);
++}
++
++static ProxyGroup *new_ProxyGroup(void)
++{
++ ProxyGroup *p=(ProxyGroup *)safemalloc(sizeof(ProxyGroup));
++ ProxyGroup_ProxyGroup(p);
++ return p;
++}
++
++static void delete_ProxyGroup(ProxyGroup *p)
++{
++ if (p)
++ {
++ delete_ProxyGroup(p->next);
++ delete_WindowName(p->includes);
++ delete_WindowName(p->excludes);
++ free(p->name);
++ free(p);
++ }
++}
++
++/* ---------------------------- error handlers
------------------------------ */
++
++static int myXErrorHandler(Display *display,XErrorEvent *error_event)
++{
++ const long messagelen=256;
++ char buffer[messagelen],function[messagelen];
++ char request_number[16];
++
++ sprintf(request_number,"%d",error_event->request_code);
++ sprintf(buffer,"UNKNOWN");
++ XGetErrorDatabaseText(display,"XRequest",
++ request_number,buffer,function,messagelen);
++
++ fprintf(stderr, "non-fatal X error as follows, display %p"
++ " op %d:%d \"%s\" serial %u error %d\n",
++ display,
++ error_event->request_code,error_event->minor_code,
++ function,(unsigned int)error_event->serial,
++ error_event->error_code);
++
++ return 0;
++}
++
++static int myXIOErrorHandler(Display *display)
++{
++ fprintf(stderr, "fatal IO Error on display %p\n", display);
++ originalXIOErrorHandler(display);
++
++ /* should never get this far */
++ return 0;
++}
++
++/* ---------------------------- local functions
----------------------------- */
++
++static void send_command_to_fvwm(char *command, Window w)
++{
++ if (command == NULL || *command == 0)
++ {
++ return;
++ }
++ SendText(fd, command, w);
++
++ return;
++}
++
++static int GetProperty(Window w,char* propertyname)
++{
++ Atom atom,actual_type;
++ char *atom_name;
++ int actual_format;
++ unsigned long nitems;
++ unsigned long bytes_after;
++ unsigned char *prop;
++ int status;
++ int result=0;
++ int byte;
++ int bytes;
++
++ atom = XInternAtom(dpy, propertyname, True);
++ atom_name = XGetAtomName (dpy,atom);
++
++ status = XGetWindowProperty(dpy, w, atom, 0L, 1024,
++ False, AnyPropertyType,
++ &actual_type,
++ &actual_format, &nitems,
++ &bytes_after,
++ &prop);
++ if (status!=0)
++ {
++/* fprintf(stderr,"GetProperty: cannot get %s\n",propertyname);
++*/
++ return 0;
++ }
++ if (!prop) {
++/* fprintf(stderr,"GetProperty: no properties\n");
++*/
++ return 0;
++ }
++
++ bytes=actual_format/8;
++ for(byte=bytes-1;byte>=0;byte--)
++ {
++ result=result*256+prop[byte];
++ }
++ XFree(prop);
++ return result;
++}
++
++static int GetProcessId(Window w)
++{
++ return GetProperty(w, "_NET_WM_PID");
++}
++
++static int GetLeader(Window w)
++{
++ int result=GetProperty(w, "WM_CLIENT_LEADER");
++ if(!result)
++ {
++ XWMHints* hints=XGetWMHints(dpy,w);
++ if(hints && hints->flags&WindowGroupHint)
++ {
++ result=hints->window_group;
++ XFree(hints);
++ }
++ }
++ return result;
++}
++
++static int GetParentProcessId(int pid)
++{
++ int ppid=0;
++ int bytes;
++ FILE* statusfile;
++
++ sprintf(commandBuffer,"/proc/%d/stat",pid);
++ statusfile=fopen(commandBuffer,"r");
++ if(!statusfile)
++ {
++ return 0;
++ }
++ bytes=fread(resultBuffer,32,1,statusfile);
++ sscanf(resultBuffer,"%*d %*[^)]) %*s %d",&ppid);
++ fclose(statusfile);
++ return ppid;
++}
++
++static ProxyGroup* FindProxyGroup(char* groupname)
++{
++ ProxyGroup* proxygroup=firstProxyGroup;
++ while(proxygroup)
++ {
++ if(StrEquals(proxygroup->name, groupname))
++ {
++ return proxygroup;
++ }
++ proxygroup=proxygroup->next;
++ }
++ proxygroup=new_ProxyGroup();
++ proxygroup->next=firstProxyGroup;
++ proxygroup->name=strdup(groupname);
++ firstProxyGroup=proxygroup;
++ return proxygroup;
++}
++
++static int MatchWindowName(WindowName* namelist,char* name)
++{
++ WindowName* include=namelist;
++ while(include)
++ {
++ if(matchWildcards(include->name, name))
++ {
++ return 1;
++ }
++ include=include->next;
++ }
++
++ return 0;
++}
++
++static ProxyGroup* FindProxyGroupWithWindowName(char* name)
++{
++ ProxyGroup* proxygroup=firstProxyGroup;
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"FindProxyGroupWithWindowName(%s)\n",name);
++#endif
++
++ while(proxygroup)
++ {
++ if(MatchWindowName(proxygroup->includes, name))
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr," found in %s\n",proxygroup->name);
++#endif
++ return proxygroup;
++ }
++ proxygroup=proxygroup->next;
++ }
++
++ return NULL;
++}
++
++static ProxyWindow *FindProxy(Window window)
++{
++ ProxyWindow *proxy=firstProxy;
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if (proxy->proxy==window || proxy->window==window)
++ {
++ return proxy;
++ }
++ }
++
++ return NULL;
++}
++
++static void DrawPicture(
++ Window window, int x, int y, FvwmPicture *picture, int cset)
++{
++ FvwmRenderAttributes fra;
++
++ if (!picture || picture->picture == None)
++ return;
++
++ fra.mask = FRAM_DEST_IS_A_WINDOW;
++ if (cset >= 0)
++ {
++ fra.mask |= FRAM_HAVE_ICON_CSET;
++ fra.colorset = &Colorset[cset];
++ }
++ PGraphicsRenderPicture(
++ dpy, window, picture, &fra, window, miniIconGC, None, None,
++ 0, 0, picture->width, picture->height,
++ x, y, picture->width, picture->height, False);
++}
++
++static void DrawWindow(
++ ProxyWindow *proxy, int x,int y,int w,int h)
++{
++ int texty,maxy;
++ int cset;
++ FvwmPicture *picture = &proxy->picture;
++ int drawMiniIcon=(showMiniIcons && proxy->picture.picture != None);
++ int group;
++ int m;
++ char *big_name;
++ char *small_name;
++ int overrun=0;
++
++ if (!proxy || proxy->proxy == None)
++ {
++ return;
++ }
++
++ x=0;
++ y=0;
++ w=proxy->proxyw;
++ h=proxy->proxyh;
++
++ texty=(h+ Ffont->ascent - Ffont->descent)/2; /* center */
++ if (drawMiniIcon)
++ {
++ texty+=4;
++ }
++
++ maxy=h-Ffont->descent-4;
++ if (texty>maxy)
++ {
++ texty=maxy;
++ }
++
++ cset = (proxy==selectProxy) ? cset_select :
++ ((proxy->flags.is_iconified) ? cset_iconified : cset_normal);
++ XSetForeground(dpy,fg_gc,Colorset[cset].fg);
++ XSetBackground(dpy,fg_gc,Colorset[cset].bg);
++ XSetForeground(dpy,sh_gc,Colorset[cset].shadow);
++ XSetForeground(dpy,hi_gc,Colorset[cset].hilite);
++
++ /* FIXME: use clip redrawing (not really essential here) */
++ if (FLF_FONT_HAS_ALPHA(Ffont,cset) || PICTURE_HAS_ALPHA(picture,cset))
++ {
++ XClearWindow(dpy,proxy->proxy);
++ }
++ RelieveRectangle(dpy,proxy->proxy, 0,0, w - 1,h - 1, hi_gc,sh_gc, 2);
++
++ big_name = proxy->iconname;
++ if(big_name==NULL || !big_name[0])
++ {
++ big_name = proxy->name;
++ }
++ small_name = proxy->name;
++ if(small_name == NULL)
++ {
++ small_name=big_name;
++ }
++ if (big_name != NULL && big_name[0])
++ {
++ int text_width = FlocaleTextWidth(
++ Ffont,big_name,strlen(big_name));
++ int edge=(w-text_width)/2;
++
++ if (edge<5)
++ {
++ edge=5;
++ }
++ if(w-text_width<5)
++ {
++ overrun=1;
++ }
++
++ FwinString->str = big_name;
++ FwinString->win = proxy->proxy;
++ FwinString->x = edge;
++ FwinString->y = texty;
++ FwinString->gc = fg_gc;
++ FwinString->flags.has_colorset = False;
++ if (cset >= 0)
++ {
++ FwinString->colorset = &Colorset[cset];
++ FwinString->flags.has_colorset = True;
++ }
++ FlocaleDrawString(dpy, Ffont, FwinString, 0);
++ }
++ if (small_name != NULL && small_name[0] &&
++ (overrun || strcmp(small_name,big_name)) && Ffont_small!=NULL)
++ {
++ int text_width = FlocaleTextWidth(
++ Ffont_small,small_name,strlen(small_name));
++ int edge=(w-text_width)/2;
++
++ if (edge<5)
++ {
++ edge=w-text_width-5;
++ }
++
++ FwinString->str = small_name;
++ FwinString->win = proxy->proxy;
++ FwinString->x = edge;
++ FwinString->y = h-Ffont_small->descent-3;
++ FwinString->gc = hi_gc;
++ FwinString->flags.has_colorset = False;
++ if (cset >= 0)
++ {
++ FwinString->colorset = &Colorset[cset];
++ FwinString->flags.has_colorset = True;
++ }
++ FlocaleDrawString(dpy, Ffont_small, FwinString, 0);
++ }
++ if (drawMiniIcon && miniIconSlot>0)
++ {
++ int widgetx=slotSpace+(slotWidth+slotSpace)*(miniIconSlot-1);
++ DrawPicture(proxy->proxy, widgetx, slotSpace, picture, cset);
++ }
++ for(group=1;group<groupCount+1;group++)
++ {
++ int lit=(proxy->group==group);
++ int widgetx=slotSpace+
++ (slotWidth+slotSpace)*(groupSlot+group-2);
++ int color_index=group%GROUP_COLORS;
++ int drawsoft=lit && proxy->flags.is_soft;
++ int drawisolated=lit && proxy->flags.is_isolated;
++
++ if(drawsoft)
++ {
++ XSetForeground(dpy,fg_gc,GetColor(
++ group_color[color_index][0]));
++ XFillRectangle(dpy,proxy->proxy,fg_gc,
++ widgetx,slotSpace,
++ slotWidth,slotHeight);
++
++ XSetForeground(dpy,sh_gc,GetColor("black"));
++ RelieveRectangle(dpy,proxy->proxy,
++ widgetx,slotSpace,
++ slotWidth,slotHeight/2,
++ hi_gc,sh_gc, 1);
++ }
++ XSetForeground(dpy,fg_gc,GetColor(
++ group_color[color_index][proxy->group==group]));
++ XFillRectangle(dpy,proxy->proxy,fg_gc,
++ widgetx,slotSpace,
++ slotWidth,
++ drawsoft? slotHeight/2: slotHeight);
++
++ XSetForeground(dpy,sh_gc,GetColor(lit? "black": "white"));
++ XSetForeground(dpy,hi_gc,GetColor(lit? "black": "white"));
++ RelieveRectangle(dpy,proxy->proxy,
++ widgetx,slotSpace,
++ slotWidth,slotHeight,
++ hi_gc,sh_gc, 2);
++ if(drawisolated)
++ {
++ RelieveRectangle(dpy,proxy->proxy,
++ widgetx+4,slotSpace+4,
++ slotWidth-8,slotHeight-8,
++ hi_gc,sh_gc, 2);
++ }
++ }
++ for(m=0;m<numSlots;m++)
++ {
++ int widgetx=slotSpace+(slotWidth+slotSpace)*(m-1);
++ DrawPicture(proxy->proxy, widgetx, slotSpace, pictureArray[m],
++ cset);
++ }
++}
++
++static void DrawProxy(ProxyWindow *proxy)
++{
++ if (proxy)
++ {
++ DrawWindow(
++ proxy, proxy->proxyx, proxy->proxyy, proxy->proxyw,
++ proxy->proxyh);
++ }
++}
++
++static void DrawProxyBackground(ProxyWindow *proxy)
++{
++ int cset;
++
++ if (proxy == NULL || proxy->proxy == None)
++ {
++ return;
++ }
++ cset = (proxy==selectProxy) ? cset_select :
++ ((proxy->flags.is_iconified) ? cset_iconified : cset_normal);
++ XSetForeground(dpy,fg_gc,Colorset[cset].fg);
++ XSetBackground(dpy,fg_gc,Colorset[cset].bg);
++ SetWindowBackground(
++ dpy, proxy->proxy, proxy->proxyw, proxy->proxyh,
++ &Colorset[cset], Pdepth, fg_gc, True);
++}
++
++static void OpenOneWindow(ProxyWindow *proxy)
++{
++ int border=0;
++ unsigned long valuemask=CWOverrideRedirect;
++ XSetWindowAttributes attributes;
++
++ if (proxy == NULL)
++ {
++ return;
++ }
++ if (proxy->desk != deskNumber ||
++ (!proxyIconified && proxy->flags.is_iconified) )
++ {
++ return;
++ }
++ if (proxy->flags.is_shown)
++ {
++ return;
++ }
++ if (proxy->proxy == None)
++ {
++ long eventMask=ButtonPressMask|ExposureMask|ButtonMotionMask;
++
++ if (enterSelect)
++ {
++ eventMask|=EnterWindowMask;
++ }
++ attributes.override_redirect = True;
++ proxy->proxy = XCreateWindow(
++ dpy, rootWindow, proxy->proxyx, proxy->proxyy,
++ proxy->proxyw, proxy->proxyh,border,
++ DefaultDepth(dpy,screen), InputOutput, Pvisual,
++ valuemask, &attributes);
++ XSelectInput(dpy,proxy->proxy,eventMask);
++ }
++ else
++ {
++ XMoveWindow(dpy, proxy->proxy, proxy->proxyx, proxy->proxyy);
++ }
++ XMapRaised(dpy, proxy->proxy);
++ DrawProxyBackground(proxy);
++ proxy->flags.is_shown = 1;
++
++ return;
++}
++
++static void OpenWindows(void)
++{
++ ProxyWindow *proxy;
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ OpenOneWindow(proxy);
++ }
++
++ selectProxy = NULL;
++ return;
++}
++
++static void CloseOneWindow(ProxyWindow *proxy)
++{
++ if (proxy == NULL)
++ {
++ return;
++ }
++ if (proxy->flags.is_shown)
++ {
++ XUnmapWindow(dpy, proxy->proxy);
++ proxy->flags.is_shown = 0;
++ }
++
++ return;
++}
++
++static void CloseWindows(void)
++{
++ ProxyWindow *proxy;
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ CloseOneWindow(proxy);
++ }
++
++ return;
++}
++
++static Bool SortProxiesOnce(void)
++{
++ Bool change=False;
++
++ ProxyWindow *proxy;
++ ProxyWindow *next;
++
++ int x1,x2;
++ int y1,y2;
++
++ lastProxy=NULL;
++ for (proxy=firstProxy; proxy != NULL && proxy->next != NULL;
++ proxy=proxy->next)
++ {
++ x1=proxy->proxyx;
++ x2=proxy->next->proxyx;
++ y1=proxy->proxyy;
++ y2=proxy->next->proxyy;
++
++ /* sort x, then y, then arbitrarily on pointer */
++ if ( x1>x2 || (x1==x2 && y1>y2) ||
++ (x1==x2 && y1==y2 &&
++ proxy->window>proxy->next->window))
++ {
++ change=True;
++ next=proxy->next;
++
++ if (lastProxy)
++ lastProxy->next=next;
++ else
++ firstProxy=next;
++ proxy->next=next->next;
++ next->next=proxy;
++ }
++
++ lastProxy=proxy;
++ }
++
++ lastProxy=NULL;
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ proxy->prev=lastProxy;
++ lastProxy=proxy;
++ }
++
++ return change;
++}
++
++static void SortProxies(void)
++{
++ while (SortProxiesOnce() == True)
++ {
++ /* nothing */
++ }
++
++ return;
++}
++
++static Bool AdjustOneWindow(ProxyWindow *proxy)
++{
++ Bool rc = False;
++ ProxyWindow *other=proxy->next;
++
++ for (other=proxy->next; other; other=other->next)
++ {
++ int dx;
++ int dy;
++
++ if(other->desk != deskNumber)
++ {
++ continue;
++ }
++ dx = abs(proxy->proxyx-other->proxyx);
++ dy = abs(proxy->proxyy-other->proxyy);
++ if (dx<(proxyWidth+proxySeparation) &&
++ dy<proxyHeight+proxySeparation )
++ {
++ rc = True;
++ if (proxyWidth-dx<proxyHeight-dy)
++ {
++ if (proxy->proxyx<=other->proxyx)
++ {
++ other->proxyx=
++ proxy->proxyx+ proxy->proxyw+
++ proxySeparation;
++ }
++ else
++ {
++ proxy->proxyx=
++ other->proxyx+ other->proxyw+
++ proxySeparation;
++ }
++ }
++ else
++ {
++ if (proxy->proxyy<=other->proxyy)
++ {
++ other->proxyy=
++ proxy->proxyy+ proxy->proxyh+
++ proxySeparation;
++ }
++ else
++ {
++ proxy->proxyy=
++ other->proxyy+ other->proxyh+
++ proxySeparation;
++ }
++ }
++ }
++ }
++
++ return rc;
++}
++
++static void AdjustWindows(void)
++{
++ Bool collision=True;
++
++ while (collision == True)
++ {
++ ProxyWindow *proxy;
++
++ collision=False;
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if(proxy->desk != deskNumber)
++ continue;
++
++ if (AdjustOneWindow(proxy) == True)
++ {
++ collision = True;
++ }
++ }
++ }
++}
++
++static void RecenterProxy(ProxyWindow *proxy)
++{
++ proxy->proxyx=proxy->x + (proxy->w-proxy->proxyw)/2;
++ proxy->proxyy=proxy->y + (proxy->h-proxy->proxyh)/2;
++}
++
++static void RecalcProxyTweaks(void)
++{
++ ProxyWindow *proxy;
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ proxy->tweakx=proxy->proxyx -
++ (proxy->x + (proxy->w-proxy->proxyw)/2);
++ proxy->tweaky=proxy->proxyy -
++ (proxy->y + (proxy->h-proxy->proxyh)/2);
++ }
++}
++static void TweakProxy(ProxyWindow *proxy)
++{
++ proxy->proxyx += proxy->tweakx;
++ proxy->proxyy += proxy->tweaky;
++}
++
++static void ReshuffleWindows(void)
++{
++ ProxyWindow *proxy;
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "ReshuffleWindows\n");
++#endif
++
++ if (are_windows_shown)
++ {
++ CloseWindows();
++ }
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ RecenterProxy(proxy);
++ }
++ AdjustWindows();
++ SortProxies();
++ if (are_windows_shown)
++ {
++ OpenWindows();
++ }
++ RecalcProxyTweaks();
++
++ return;
++}
++
++static void UpdateOneWindow(ProxyWindow *proxy)
++{
++ if (proxy == NULL)
++ {
++ return;
++ }
++ if (proxy->flags.is_shown)
++ {
++ ReshuffleWindows();
++ }
++
++ return;
++}
++
++static void SendResolve(ProxyWindow *proxy)
++{
++ SendFvwmPipe(fd, "SendToModule FvwmProxy Resolve",
++ proxy->window);
++}
++
++static void WaitToConfig(ProxyWindow *proxy)
++{
++ proxy->pending_config++;
++ if(!waiting_to_config)
++ {
++ waiting_to_config=1;
++ SendResolve(proxy);
++ }
++}
++
++static void IsolateGroup(ProxyWindow *instigator,int isolate)
++{
++ ProxyWindow *proxy;
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "IsolateGroup %p %d\n",
++ instigator,isolate);
++#endif
++
++ if(!instigator->group)
++ {
++ return;
++ }
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if(proxy==instigator)
++ {
++ continue;
++ }
++ if (proxy->desk == deskNumber &&
++ proxy->group==instigator->group)
++ {
++ proxy->flags.is_isolated=isolate;
++
++ DrawProxyBackground(proxy);
++ DrawProxy(proxy);
++ }
++ }
++}
++
++static void IconifyGroup(ProxyWindow *instigator,int iconify)
++{
++ ProxyWindow *proxy;
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "IconifyGroup %p %d\n",
++ instigator,iconify);
++#endif
++
++ if(!instigator->group)
++ {
++ return;
++ }
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if(proxy==instigator)
++ {
++ continue;
++ }
++ if (proxy->desk == deskNumber &&
++ proxy->group==instigator->group)
++ {
++ sprintf(commandBuffer,"Iconify %s",
++ iconify? "On": "Off");
++ SendText(fd,commandBuffer,proxy->window);
++ }
++ }
++}
++
++static void RaiseLowerGroup(Window w,int raise)
++{
++ ProxyWindow *instigator;
++ ProxyWindow *proxy;
++
++ instigator = FindProxy(w);
++ if(instigator==NULL || instigator->flags.is_isolated)
++ {
++ return;
++ }
++
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "RaiseLowerGroup %p %d %d\n",
++ instigator,raise,instigator->raised);
++#endif
++
++ if(abs(instigator->raised)>10)
++ {
++ exit(1);
++ }
++
++ if(instigator->raised == (raise? 1: -1))
++ {
++ return;
++ }
++
++ instigator->raised=0;
++
++ if(instigator->flags.is_iconified || !instigator->group)
++ {
++ return;
++ }
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if(proxy==instigator || proxy->raised == (raise? 1: -1))
++ {
++ continue;
++ }
++ if (proxy->desk == deskNumber &&
++ proxy->group==instigator->group)
++ {
++ if(raise)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "Raise %p\n",proxy);
++#endif
++
++ proxy->raised=1;
++ XRaiseWindow(dpy, proxy->window);
++ }
++ else
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "Lower %p\n",proxy);
++#endif
++
++ proxy->raised= -1;
++ XLowerWindow(dpy, proxy->window);
++ }
++ }
++ }
++ /* make sure instigator ends on on top/bottom */
++ if(raise)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "ReRaise %p\n",instigator);
++#endif
++
++ instigator->raised=1;
++ XRaiseWindow(dpy, instigator->window);
++ }
++ else
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "ReLower %p\n",instigator);
++#endif
++
++ instigator->raised= -1;
++ XLowerWindow(dpy, instigator->window);
++ }
++}
++
++static void ClearRaised(void)
++{
++ ProxyWindow *proxy;
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "ClearRaised\n");
++#endif
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ proxy->raised=0;
++ }
++}
++
++static void ShiftWindows(ProxyWindow *instigator,int dx,int dy)
++{
++ ProxyWindow *proxy;
++
++ if((are_windows_shown && !instigator->flags.is_isolated) ||
++ !instigator->group || instigator->flags.is_soft)
++ {
++ return;
++ }
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "ShiftWindows %d %d %d\n",
++ instigator->group,dx,dy);
++#endif
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if(proxy==instigator)
++ {
++ continue;
++ }
++ if (proxy->desk == deskNumber &&
++ proxy->group==instigator->group)
++ {
++ proxy->x+=dx;
++ proxy->y+=dy;
++/*
++ XMoveWindow(dpy, proxy->window,
++ proxy->x+proxy->border_width,
++ proxy->y+proxy->title_height+
++ proxy->border_width);
++*/
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "shift %d %d (%d %d)\n",
++ proxy->x,proxy->y, dx,dy);
++#endif
++ WaitToConfig(proxy);
++ }
++ }
++}
++
++static void CatchWindows(ProxyWindow *instigator,int vertical,int from,int
to,
++ int direction)
++{
++ ProxyWindow *proxy;
++
++ if((are_windows_shown && !instigator->flags.is_isolated) ||
++ !instigator->group || instigator->flags.is_soft)
++ {
++ return;
++ }
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "CatchWindows %d %d %d %d\n",
++ instigator->group,vertical,from,to);
++#endif
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if(proxy==instigator)
++ {
++ continue;
++ }
++ if (proxy->desk == deskNumber &&
++ proxy->group==instigator->group &&
++ !proxy->flags.is_soft)
++ {
++ int changed=0;
++ int newx=proxy->x;
++ int newy=proxy->y;
++ int neww=proxy->goal_width;
++ int newh=proxy->goal_height;
++ const int incx=proxy->incx;
++ const int incy=proxy->incy;
++/* int threshold=(vertical? incy: incx)-1;
++*/
++ int threshold=0;
++ int least=from;
++ int most=from;
++
++ if(direction<0)
++ {
++ least-=threshold;
++ }
++ else
++ {
++ most+=threshold;
++ }
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,
++ "check %p %d %d size %d %d"
++ " goal %d %d inc %d %d\n",
++ proxy,proxy->x,proxy->y,proxy->w,proxy->h,
++ proxy->goal_width,proxy->goal_height,
++ incx,incy);
++#endif
++
++ if(vertical)
++ {
++ if(newy>=least && newy<=most)
++ {
++ newy=to;
++ newh-=to-from;
++ changed=1;
++ }
++ else if(newy+newh>=least &&
++ newy+newh<=most)
++ {
++ newh=to-newy;
++ changed=1;
++ }
++ }
++ else
++ {
++ if(newx>=least && newx<=most)
++ {
++ newx=to;
++ neww-=to-from;
++ changed=1;
++ }
++ else if(newx+neww>=least &&
++ newx+neww<=most)
++ {
++ neww=to-newx;
++ changed=1;
++ }
++ }
++ if(changed)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "change %d %d %d %d\n",
++ newx,newy,neww,newh);
++#endif
++ if(newx!=proxy->x || newy!=proxy->y)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "move\n");
++#endif
++/*
++ XMoveWindow(dpy, proxy->window,
++ newx+bw,
++ newy+th+bw);
++*/
++ WaitToConfig(proxy);
++
++ /* in case more motion of
instigator
++ precedes this window's config
*/
++ proxy->x=newx;
++ proxy->y=newy;
++ }
++ if(neww<proxy->w ||
++ neww>=proxy->w+incx ||
++ newh<proxy->h ||
++ newh>=proxy->h+incy)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "resize\n");
++#endif
++/*
++ XResizeWindow(dpy, proxy->window,
++ neww-2*bw,
++ newh-2*bw-th);
++*/
++ WaitToConfig(proxy);
++
++ /* in case more motion of
instigator
++ precedes this window's config
*/
++ if(neww<proxy->w)
++ {
++ proxy->w-=((proxy->w-neww-1)/
++ incx+1)*incx;
++ }
++ else if(neww>=proxy->w+incx)
++ {
++ proxy->w+=(neww-proxy->w)/incx
++ *incx;
++ }
++ if(newh<proxy->h)
++ {
++ proxy->h-=((proxy->h-newh-1)/
++ incy+1)*incy;
++ }
++ else if(newh>=proxy->h+incy)
++ {
++ proxy->h+=(newh-proxy->h)/incy
++ *incy;
++ }
++ }
++ proxy->goal_width=neww;
++ proxy->goal_height=newh;
++
++ }
++ }
++ }
++}
++
++static void MoveProxiedWindow(ProxyWindow* proxy,int x,int y,int w,int h)
++{
++#if 1
++ sprintf(commandBuffer,"ResizeMove frame %dp %dp %dp %dp",
++ w,
++ h,
++ x,
++ y);
++ SendText(fd,commandBuffer,proxy->window);
++#else
++ const int bw=proxy->border_width;
++ const int th=proxy->title_height;
++
++ XMoveResizeWindow(dpy, proxy->window,
++ x+bw,
++ y+th+bw,
++ w-2*bw,
++ h-2*bw-th);
++#endif
++}
++
++static void ResolvePendingWindows(void)
++{
++ ProxyWindow *proxy;
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if(proxy->pending_config)
++ {
++ MoveProxiedWindow(proxy,proxy->x,proxy->y,
++ proxy->goal_width,proxy->goal_height);
++ }
++ }
++}
++
++int FindUniqueGroup(int desk)
++{
++ ProxyWindow *proxy;
++
++ /* find unique group */
++ int group=1;
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if (proxy->desk == desk && proxy->group==group)
++ {
++ group++;
++ proxy=firstProxy;
++ continue;
++ }
++ }
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"FindUniqueGroup desk %d group %d\n",desk,group);
++#endif
++ return group;
++}
++
++static void MoveGroupToDesk(ProxyWindow *instigator,int desk)
++{
++ ProxyWindow *proxy;
++ int old_desk;
++ int old_group;
++ int group;
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "MoveGroupToDesk %p %d\n",
++ instigator,desk);
++#endif
++
++ if(!instigator->group)
++ {
++ return;
++ }
++
++ old_desk=instigator->desk;
++ old_group=instigator->group;
++ group=FindUniqueGroup(desk);
++
++ sprintf(commandBuffer, "MoveToDesk 0 %d", desk);
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if (proxy->desk == old_desk &&
++ proxy->group==old_group)
++ {
++ proxy->desk=desk;
++ proxy->group=group;
++
++ SendText(fd, commandBuffer, proxy->window);
++
++ DrawProxyBackground(proxy);
++ DrawProxy(proxy);
++ }
++ }
++}
++
++
++static ProxyWindow* FindNeighborInGroup(ProxyWindow* instigator,
++ int not_iconified)
++{
++ ProxyWindow *proxy;
++
++ if(!instigator)
++ {
++ return NULL;
++ }
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"FindNeighborInGroup %p %p desk %d group %d\n",
++ instigator,instigator->proxy_group,instigator->desk,
++ instigator->group);
++#endif
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr," vs %p %p desk %d group %d\n",
++ proxy,proxy->proxy_group,proxy->desk,proxy->group);
++#endif
++ if (proxy!= instigator && proxy->desk == instigator->desk &&
++ proxy->group &&
++ proxy->group==instigator->group &&
++ (!not_iconified || !proxy->flags.is_iconified))
++ {
++ return proxy;
++ }
++ }
++
++ return NULL;
++}
++
++static ProxyWindow* FindNeighborForProxy(ProxyWindow* instigator)
++{
++ ProxyWindow *proxy;
++ ProxyWindow *neighbor=NULL;
++ int group;
++
++ if(!instigator)
++ {
++ return NULL;
++ }
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"FindNeighborForProxy %p %p desk %d\n",
++ instigator,instigator->proxy_group,instigator->desk);
++#endif
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr," vs %p %p desk %d group %d\n",
++ proxy,proxy->proxy_group,proxy->desk,proxy->group);
++#endif
++ if (proxy!= instigator && proxy->desk == instigator->desk &&
++ proxy->proxy_group==instigator->proxy_group)
++ {
++ if(proxy->proxy_group->flags.isolated &&
++ !instigator->flags.is_isolated)
++ {
++ SendFvwmPipe(fd,
++ "SendToModule FvwmProxy
IsolateToggle",
++ proxy->window);
++ }
++ if(proxy->group)
++ {
++ return proxy;
++ }
++ neighbor=proxy;
++ }
++ }
++
++ if(!neighbor)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"not found\n");
++#endif
++ return NULL;
++ }
++
++ group=FindUniqueGroup(instigator->desk);
++
++ /* assign group to all proxies with given pid */
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if (proxy->desk == instigator->desk &&
++ proxy->proxy_group==instigator->proxy_group)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"unique group %d reassign %s\n",
++ group,proxy->name);
++#endif
++ proxy->group=group;
++ }
++ }
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"group %d\n",group);
++#endif
++ return neighbor;
++}
++
++static ProxyWindow* FindNeighborForProcess(ProxyWindow* proxy,
++ int desk,int pid,int ppid)
++{
++ ProxyWindow *other;
++ ProxyWindow *neighbor=NULL;
++ int group;
++ int auto_include=0;
++
++ if(!pid)
++ {
++ return 0;
++ }
++
++ /* find existing group for pid */
++ for (other=firstProxy; other != NULL; other=other->next)
++ {
++ if (other->desk == desk && other->proxy_group &&
++ (other->pid==pid || (ppid && other->pid==ppid) ||
++ other->ppid==pid) &&
++ (MatchWindowName(other->proxy_group->includes,
++ proxy->name) ||
++
(auto_include=other->proxy_group->flags.auto_include)))
++ {
++ proxy->flags.is_soft=auto_include &&
++ other->proxy_group->flags.auto_soft;
++ if(other->proxy_group->flags.isolated &&
++ !proxy->flags.is_isolated)
++ {
++ SendFvwmPipe(fd,
++ "SendToModule FvwmProxy
IsolateToggle",
++ proxy->window);
++ }
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,
++ "pid %d %d found %d %d group %d soft %d\n",
++ pid,ppid,other->pid,other->ppid,
++ other->group,proxy->flags.is_soft);
++#endif
++ if(other->group)
++ {
++ return other;
++ }
++ neighbor=other;
++ }
++ }
++ if(!neighbor)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"FindNeighborForProcess pid %d %d not found\n",
++ pid,ppid);
++#endif
++ return NULL;
++ }
++
++ group=FindUniqueGroup(desk);
++
++ /* assign pid to all proxies with given pid */
++ for (other=firstProxy; other != NULL; other=other->next)
++ {
++ if (other->desk == desk && other->proxy_group &&
++ (other->pid==pid || (ppid && other->pid==ppid) ||
++ other->ppid==pid))
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"unique group %d reassign %s\n",
++ group,other->name);
++#endif
++ other->group=group;
++ }
++ }
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"FindNeighborForProcess pid %d new %d\n",pid,group);
++#endif
++ return neighbor;
++}
++
++static ProxyWindow* FindNeighborForLeader(ProxyWindow* proxy,
++ int desk,int leader)
++{
++ ProxyWindow *other;
++ ProxyWindow *neighbor=NULL;
++ int group;
++ int auto_include=0;
++
++ if(!leader)
++ {
++ return 0;
++ }
++
++ /* find existing group for leader */
++ for (other=firstProxy; other != NULL; other=other->next)
++ {
++ if (other->desk == desk && other->proxy_group &&
++ other->leader==leader &&
++ (MatchWindowName(other->proxy_group->includes,
++ proxy->name) ||
++
(auto_include=other->proxy_group->flags.auto_include)))
++ {
++ proxy->flags.is_soft=auto_include &&
++ other->proxy_group->flags.auto_soft;
++ if(other->proxy_group->flags.isolated &&
++ !proxy->flags.is_isolated)
++ {
++ SendFvwmPipe(fd,
++ "SendToModule FvwmProxy
IsolateToggle",
++ proxy->window);
++ }
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"leader %d found %d group %d soft
%d\n",
++ leader,other->leader,
++ other->group,proxy->flags.is_soft);
++#endif
++ if(other->group)
++ {
++ return other;
++ }
++ neighbor=other;
++ }
++ }
++ if(!neighbor)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"FindNeighborForLeader leader %d not found\n",
++ leader);
++#endif
++ return NULL;
++ }
++
++ group=FindUniqueGroup(desk);
++
++ /* assign leader to all proxies with given leader */
++ for (other=firstProxy; other != NULL; other=other->next)
++ {
++ if (other->desk == desk && other->leader==leader &&
++ other->proxy_group)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"unique group %d reassign %s\n",
++ group,other->name);
++ other->group=group;
++#endif
++ }
++ }
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"FindNeighborForLeader leader %x new %d\n",
++ leader,group);
++#endif
++ return neighbor;
++}
++
++static ProxyWindow* FindNeighborForApplication(ProxyWindow* proxy)
++{
++ ProxyWindow* neighbor=FindNeighborForLeader(proxy,proxy->desk,
++ proxy->leader);
++ if(!neighbor)
++ {
++ neighbor=FindNeighborForProcess(proxy,proxy->desk,
++ proxy->pid,proxy->ppid);
++ }
++ return neighbor;
++}
++
++static int ProxyGroupCheckSoft(ProxyGroup* proxy_group,
++ ProxyWindow* proxy)
++{
++ WindowName* include=proxy_group->includes;
++ while(include)
++ {
++ if(matchWildcards(include->name, proxy->name))
++ {
++ return include->flags.is_soft;
++ }
++ include=include->next;
++ }
++ return 0;
++}
++
++static void UpdateProxyGroup(ProxyWindow* proxy)
++{
++ ProxyWindow* neighbor;
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"UpdateProxyGroup %s\n",proxy->name);
++#endif
++
++ if(proxy->proxy_group)
++ {
++ return;
++ }
++ if(!proxy->proxy_group)
++ {
++ neighbor=FindNeighborForApplication(proxy);
++/*
++ proxy->group=0;
++*/
++ proxy->proxy_group=NULL;
++ if(neighbor && neighbor->proxy_group)
++ {
++ proxy->group=neighbor->group;
++ proxy->proxy_group=neighbor->proxy_group;
++ }
++ }
++ if(!proxy->proxy_group)
++ {
++ proxy->proxy_group=
++ FindProxyGroupWithWindowName(proxy->name);
++ }
++ if(proxy->proxy_group &&
++ MatchWindowName(proxy->proxy_group->excludes,proxy->name))
++ {
++ proxy->proxy_group=NULL;
++ proxy->group=0;
++ }
++ if(proxy->proxy_group && !proxy->group &&
++ proxy->proxy_group->flags.ignore_ids)
++ {
++ neighbor=FindNeighborForProxy(proxy);
++ if(neighbor)
++ {
++ proxy->group=neighbor->group;
++ }
++ }
++
++ if(proxy->proxy_group)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr," ProxyGroup %s\n",proxy->proxy_group->name);
++#endif
++
++ proxy->flags.is_soft=proxy->flags.is_soft ||
++ ProxyGroupCheckSoft(proxy->proxy_group,proxy);
++ }
++}
++
++static void UpdateProxyGroupForAll(void)
++{
++ ProxyWindow *proxy;
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ UpdateProxyGroup(proxy);
++ }
++}
++
++static void AdhereGroup(ProxyWindow *instigator)
++{
++ ProxyWindow *proxy;
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "AdhereGroup %p\n", instigator);
++#endif
++
++ if(!instigator)
++ {
++ return;
++ }
++
++ if(!instigator->group || instigator->flags.is_soft)
++ {
++ return;
++ }
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if(proxy==instigator)
++ {
++ continue;
++ }
++ if (proxy->desk == instigator->desk &&
++ proxy->group==instigator->group)
++ {
++ if(!proxy->flags.is_soft &&
++ (proxy->x != instigator->x ||
++ proxy->y != instigator->y ||
++ proxy->goal_width != instigator->goal_width ||
++ proxy->goal_height !=
instigator->goal_height))
++ {
++ proxy->x=instigator->x;
++ proxy->y=instigator->y;
++ proxy->goal_width=instigator->goal_width;
++ proxy->goal_height=instigator->goal_height;
++
++ MoveProxiedWindow(proxy,proxy->x,proxy->y,
++ proxy->goal_width,proxy->goal_height);
++ }
++ }
++ }
++}
++
++static void SetGroup(ProxyWindow* proxy, int group)
++{
++ ProxyWindow *neighbor;
++
++ proxy->group=group;
++ if(group)
++ {
++ neighbor=FindNeighborInGroup(proxy,0);
++ if(neighbor)
++ {
++ proxy->flags.is_isolated =
neighbor->flags.is_isolated;
++ if(proxy->flags.is_isolated)
++ {
++ AdhereGroup(neighbor);
++ }
++ }
++ if(proxy->flags.is_isolated && !proxy->flags.is_iconified)
++ {
++ IconifyGroup(proxy,1);
++ }
++ }
++ else
++ {
++ proxy->flags.is_soft=0;
++ proxy->flags.is_isolated=0;
++ }
++}
++
++void DumpStampQueue(void)
++{
++#if PROXY_GROUP_DEBUG
++ int m;
++
++ fprintf(stderr,"DumpStampQueue stamp %d min %d max %d\n",
++ stamp,stampMin,stampMax);
++ for(m=0;m<stampLimit;m++)
++ {
++ fprintf(stderr,"stampQueue[%d] %x %d %d %d %d\n",m,
++ (int)(stampQueue[m].window),
++ stampQueue[m].x,
++ stampQueue[m].y,
++ stampQueue[m].w,
++ stampQueue[m].h);
++ }
++#endif
++}
++
++void StoreStamp(Window window,int x,int y,int w,int h)
++{
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"StoreStamp %x %d %d %d %d\n",(int)window,x,y,w,h);
++#endif
++
++ stamp=(stamp+1)%stampLimit;
++ stampMax=stamp;
++ if(stampMin==stampMax)
++ {
++ stampMin=(stampMax+1)%stampLimit;
++ }
++
++ stampQueue[stamp].window=window;
++ stampQueue[stamp].x=x;
++ stampQueue[stamp].y=y;
++ stampQueue[stamp].w=w;
++ stampQueue[stamp].h=h;
++
++ DumpStampQueue();
++}
++
++void UndoStamp(void)
++{
++ ProxyWindow *proxy;
++
++ if(stamp==stampMin)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"UndoStamp empty, stamp %d min %d max %d\n",
++ stamp,stampMin,stampMax);
++#endif
++ return;
++ }
++ proxy = FindProxy(stampQueue[stamp].window);
++ if(!proxy)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"UndoStamp no proxy for window\n");
++#endif
++ return;
++ }
++
++ pending_do++;
++ MoveProxiedWindow(proxy,
++ stampQueue[stamp].x,
++ stampQueue[stamp].y,
++ stampQueue[stamp].w,
++ stampQueue[stamp].h);
++
++ stampQueue[stamp].window=proxy->window;
++ stampQueue[stamp].x=proxy->x;
++ stampQueue[stamp].y=proxy->y;
++ stampQueue[stamp].w=proxy->w;
++ stampQueue[stamp].h=proxy->h;
++
++ stamp=(stamp-1+stampLimit)%stampLimit;
++
++ DumpStampQueue();
++
++ SendResolve(proxy);
++}
++
++void RedoStamp(void)
++{
++ ProxyWindow *proxy;
++
++ if(stamp==stampMax)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"RedoStamp empty, stamp %d min %d max %d\n",
++ stamp,stampMin,stampMax);
++#endif
++ return;
++ }
++
++ stamp=(stamp+1)%stampLimit;
++
++ proxy = FindProxy(stampQueue[stamp].window);
++ if(!proxy)
++ {
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"RedoStamp no proxy for window\n");
++#endif
++ return;
++ }
++
++ pending_do++;
++ MoveProxiedWindow(proxy,
++ stampQueue[stamp].x,
++ stampQueue[stamp].y,
++ stampQueue[stamp].w,
++ stampQueue[stamp].h);
++
++ stampQueue[stamp].window=proxy->window;
++ stampQueue[stamp].x=proxy->x;
++ stampQueue[stamp].y=proxy->y;
++ stampQueue[stamp].w=proxy->w;
++ stampQueue[stamp].h=proxy->h;
++
++ DumpStampQueue();
++
++ SendResolve(proxy);
++}
++
++static void ConfigureWindow(FvwmPacket *packet)
++{
++ unsigned long* body = packet->body;
++
++ struct ConfigWinPacket *cfgpacket=(void *)body;
++ int wx=cfgpacket->frame_x;
++ int wy=cfgpacket->frame_y;
++ int desk=cfgpacket->desk;
++ int wsx=cfgpacket->frame_width;
++ int wsy=cfgpacket->frame_height;
++ int border_width=cfgpacket->border_width;
++ int title_height=cfgpacket->title_height;
++ int incx=cfgpacket->hints_width_inc;
++ int incy=cfgpacket->hints_height_inc;
++ Window target=cfgpacket->w;
++ int leader;
++ int pid;
++ int ppid;
++ ProxyWindow *proxy;
++ int is_new_window = 0;
++
++ if (DO_SKIP_WINDOW_LIST(cfgpacket))
++ {
++ return;
++ }
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"\n");
++#endif
++ leader=GetLeader(target);
++ pid=GetProcessId(target);
++ ppid=GetParentProcessId(pid);
++ proxy = FindProxy(target);
++ if (proxy == NULL)
++ {
++ is_new_window = 1;
++ proxy=new_ProxyWindow();
++ proxy->next = firstProxy;
++ firstProxy = proxy;
++ proxy->window=target;
++
++ /* unreliable on existing windows
++ on 2.5.10, reporting false just after M_ICONIFY */
++ proxy->flags.is_iconified = !!IS_ICONIFIED(cfgpacket);
++ }
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,
++ "Config %p %x ld %x pid=%d %d\n"
++ " pos %d %d sz %d %d"
++ " was %d %d sz %d %d goal %d %d"
++ " bdr %d %d pend %d %d\n",
++ proxy,(int)target,leader,pid,ppid,
++ wx,wy,wsx,wsy,
++ proxy->x,proxy->y,
++ proxy->w,proxy->h,
++ proxy->goal_width,proxy->goal_height,
++ border_width,title_height,
++ proxy->pending_config,
++ pending_do);
++#endif
++
++ if(proxy->pending_config)
++ {
++ proxy->pending_config=0;
++ }
++ else
++ {
++ if(!pending_do && !waiting_to_stamp &&
++ (is_new_window || proxy->x!=wx || proxy->y!=wy ||
++ proxy->w!=wsx || proxy->h!=wsy))
++ {
++ waiting_to_stamp=1;
++ sprintf(commandBuffer,
++ "SendToModule FvwmProxy Stamp %d %d %d %d",
++ proxy->x,proxy->y,proxy->w,proxy->h);
++ SendFvwmPipe(fd, commandBuffer, proxy->window);
++ }
++
++ if (is_new_window)
++ {
++ proxy->goal_width=wsx;
++ proxy->goal_height=wsy;
++ }
++ else
++ {
++ int shifted=0;
++ int wasx=proxy->x;
++ int wasy=proxy->y;
++ int wasw=proxy->w;
++ int wash=proxy->h;
++ int wasgw=proxy->goal_width;
++ int wasgh=proxy->goal_height;
++ if(proxy->x!=wx && proxy->w==wsx)
++ {
++ ShiftWindows(proxy,wx-proxy->x,wy-proxy->y);
++ shifted=1;
++ }
++ else
++ {
++ if(wasx!=wx)
++ {
++ CatchWindows(proxy,0,proxy->x,wx,-1);
++ proxy->goal_width=wsx;
++ }
++ if(wasx+wasw!=wx+wsx)
++ {
++ CatchWindows(proxy,0,
++ wasx+wasgw,
++ wx+wsx,1);
++ proxy->goal_width=wsx;
++ }
++ }
++
++ if(proxy->y!=wy && proxy->h==wsy)
++ {
++ if(!shifted)
++ {
++ ShiftWindows(proxy,0,wy-proxy->y);
++ }
++ }
++ else
++ {
++ if(wasy!=wy)
++ {
++ CatchWindows(proxy,1,proxy->y,wy,-1);
++ proxy->goal_height=wsy;
++ }
++ if(wasy+wash!=wy+wsy)
++ {
++ CatchWindows(proxy,1,
++ wasy+wasgh,
++ wy+wsy,1);
++ proxy->goal_height=wsy;
++ }
++ }
++/*
++ if(wx!=proxy->x || wy!=proxy->y ||
++ wsx!=proxy->w || wsy!=proxy->h)
++ {
++ StoreStamp(target,proxy->x,proxy->y,
++ proxy->w,proxy->h);
++ }
++*/
++ }
++ }
++
++ if(!is_new_window && proxy->desk!=desk)
++ {
++ MoveGroupToDesk(proxy,desk);
++ }
++
++ proxy->leader=leader;
++ proxy->pid=pid;
++ proxy->ppid=ppid;
++ proxy->x=wx;
++ proxy->y=wy;
++ proxy->desk=desk;
++ proxy->w=wsx;
++ proxy->h=wsy;
++ proxy->proxyw=proxyWidth;
++ proxy->proxyh=proxyHeight;
++ proxy->border_width=border_width;
++ proxy->title_height=title_height;
++ proxy->incx=incx;
++ proxy->incy=incy;
++
++ RecenterProxy(proxy);
++ if (!is_new_window)
++ {
++ TweakProxy(proxy);
++ }
++
++ if (are_windows_shown)
++ {
++ if (is_new_window)
++ {
++ ReshuffleWindows();
++ }
++ else
++ {
++ CloseOneWindow(proxy);
++ OpenOneWindow(proxy);
++ }
++ }
++
++ if(proxy->flags.is_isolated)
++ {
++ AdhereGroup(proxy);
++ }
++
++ return;
++}
++
++static void IconifyWindow(ProxyWindow *proxy, int is_iconified)
++{
++ if (proxy == NULL)
++ {
++ return;
++ }
++ is_iconified = !!is_iconified;
++ if(proxy->flags.is_iconified != is_iconified)
++ {
++ proxy->flags.is_iconified = is_iconified;
++ if (!proxyIconified && is_iconified)
++ {
++ if (proxy->flags.is_shown)
++ {
++ CloseOneWindow(proxy);
++ }
++ }
++ else
++ {
++ if (are_windows_shown)
++ {
++/* ReshuffleWindows();
++*/
++ OpenOneWindow(proxy);
++ }
++ }
++
++ DrawProxyBackground(proxy);
++
++ if(proxy->flags.is_isolated)
++ {
++ if(!is_iconified)
++ {
++ IconifyGroup(proxy, 1);
++ }
++ }
++ else
++ {
++ IconifyGroup(proxy,is_iconified);
++ }
++ }
++
++ return;
++}
++
++static void IsolateCheck(ProxyWindow *instigator,int force_other)
++{
++ if(instigator->flags.is_isolated)
++ {
++ if(!force_other && !instigator->flags.is_iconified)
++ {
++ IconifyGroup(instigator,1);
++ AdhereGroup(instigator);
++ }
++ else
++ {
++ ProxyWindow *neighbor=
++ FindNeighborInGroup(instigator,1);
++ if(neighbor)
++ {
++ IconifyGroup(neighbor,1);
++ }
++ else
++ {
++ neighbor=FindNeighborInGroup(instigator,0);
++ if(neighbor && force_other)
++ {
++ sprintf(commandBuffer,"Iconify Off");
++ SendText(fd,commandBuffer,
++ neighbor->window);
++ }
++ }
++ AdhereGroup(neighbor);
++ }
++ }
++}
++
++static void DestroyWindow(Window w)
++{
++ ProxyWindow *proxy;
++ ProxyWindow *prev;
++
++ for (proxy=firstProxy, prev = NULL; proxy != NULL;
++ prev = proxy, proxy=proxy->next)
++ {
++ if (proxy->proxy==w || proxy->window==w)
++ break;
++ }
++ if (proxy == NULL)
++ {
++ return;
++ }
++ if (prev == NULL)
++ {
++ firstProxy = proxy->next;
++ }
++ else
++ {
++ prev->next = proxy->next;
++ }
++ if (selectProxy == proxy)
++ {
++ selectProxy = NULL;
++ }
++ if (enterProxy == proxy)
++ {
++ enterProxy = NULL;
++ }
++ if(!proxy->flags.is_iconified)
++ {
++ IsolateCheck(proxy,1);
++ }
++ CloseOneWindow(proxy);
++ delete_ProxyWindow(proxy);
++
++ return;
++}
++
++static unsigned int GetModifiers(void)
++{
++ Window root_return, child_return;
++ int root_x_return, root_y_return;
++ int win_x_return, win_y_return;
++ unsigned int mask_return;
++
++ if (FQueryPointer(
++ dpy,rootWindow,&root_return,
++ &child_return,
++ &root_x_return,&root_y_return,
++ &win_x_return,&win_y_return,
++ &mask_return) == False)
++ {
++ /* pointer is on another screen - ignore */
++ }
++
++ /* mask_return
++ 0x01 shift
++ 0x02 caplock
++ 0x04 ctrl
++ 0x08 alt
++ 0x40 logo
++ */
++ return mask_return;
++}
++
++static void StartProxies(void)
++{
++ if (are_windows_shown)
++ {
++ return;
++ }
++
++ held_modifiers=GetModifiers();
++ enterProxy=NULL;
++ selectProxy=NULL;
++
++ if(action_list[PROXY_ACTION_MODIFIER_RELEASE])
++ watching_modifiers=1;
++
++ send_command_to_fvwm(action_list[PROXY_ACTION_SHOW], None);
++ are_windows_shown = 1;
++ CloseWindows();
++ ReshuffleWindows();
++ OpenWindows();
++
++ return;
++}
++
++static void MarkProxy(ProxyWindow *new_proxy)
++{
++ ProxyWindow *old_proxy;
++
++ old_proxy = selectProxy;
++ selectProxy = new_proxy;
++ if (selectProxy != old_proxy)
++ {
++ if (old_proxy != NULL)
++ {
++ DrawProxyBackground(old_proxy);
++ DrawProxy(old_proxy);
++ }
++ if (selectProxy != NULL)
++ {
++ DrawProxyBackground(selectProxy);
++ DrawProxy(selectProxy);
++ }
++ }
++ if (old_proxy != NULL)
++ send_command_to_fvwm(action_list[PROXY_ACTION_UNMARK],
++ old_proxy->window);
++ if (selectProxy != NULL)
++ send_command_to_fvwm(action_list[PROXY_ACTION_MARK],
++ selectProxy->window);
++
++ return;
++}
++
++static void HideProxies(void)
++{
++ if (!are_windows_shown)
++ {
++ return;
++ }
++ are_windows_shown = 0;
++ CloseWindows();
++
++ return;
++}
++
++static void SelectProxy(void)
++{
++ ProxyWindow *proxy;
++
++ HideProxies();
++ if (selectProxy)
++ send_command_to_fvwm(action_list[PROXY_ACTION_SELECT],
++ selectProxy->window);
++
++ send_command_to_fvwm(action_list[PROXY_ACTION_HIDE], None);
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ if (proxy==selectProxy)
++ {
++ startProxy=proxy;
++ break;
++ }
++
++ selectProxy=NULL;
++
++ return;
++}
++
++static void AbortProxies(void)
++{
++ HideProxies();
++ send_command_to_fvwm(action_list[PROXY_ACTION_ABORT], None);
++ selectProxy = NULL;
++
++ return;
++}
++
++static void RotateIsolated(ProxyWindow *instigator,int direction)
++{
++ int found=0;
++ ProxyWindow *proxy;
++ ProxyWindow *first=NULL;
++ ProxyWindow *adjacent=NULL;
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"RotateIsolated %p %p %d\n",
++ instigator,last_rotation_instigator,direction);
++#endif
++
++ /* rotation can lose focus, so we store it */
++ if(!instigator || !instigator->group ||
++ !instigator->flags.is_isolated)
++ {
++ instigator=last_rotation_instigator;
++ }
++ if(!instigator || !instigator->group ||
++ !instigator->flags.is_isolated)
++ {
++ return;
++ }
++ last_rotation_instigator=instigator;
++
++ for (proxy=firstProxy; proxy != NULL; proxy=proxy->next)
++ {
++ if(proxy->desk == instigator->desk &&
++ proxy->group==instigator->group)
++ {
++ if(!proxy->flags.is_iconified)
++ {
++ if(direction<0 && adjacent)
++ {
++ break;
++ }
++ found=1;
++ }
++ else
++ {
++ if(direction<0)
++ {
++ adjacent=proxy;
++ }
++ else if(found)
++ {
++ adjacent=proxy;
++ break;
++ }
++ else if(!first)
++ {
++ first=proxy;
++ }
++ }
++ }
++ }
++
++ if(!adjacent)
++ {
++ adjacent=first;
++ }
++ if(adjacent)
++ {
++ sprintf(commandBuffer,"Iconify Off");
++ SendText(fd,commandBuffer,adjacent->window);
++ }
++
++ return;
++}
++
++static void change_cset(int cset)
++{
++ if (cset == cset_normal || cset == cset_iconified)
++ {
++ ProxyWindow *proxy;
++
++ for (proxy = firstProxy; proxy != NULL; proxy = proxy->next)
++ {
++ DrawProxyBackground(proxy);
++ }
++ }
++ else if (cset == cset_select && selectProxy != NULL)
++ {
++ DrawProxyBackground(selectProxy);
++ }
++
++ return;
++}
++
++static void ProcessMessage(FvwmPacket* packet)
++{
++ unsigned long type = packet->type;
++ unsigned long* body = packet->body;
++ FvwmWinPacketBodyHeader *bh = (void *)body;
++ ProxyWindow *proxy;
++ int x=0;
++ int y=0;
++ int w=0;
++ int h=0;
++
++ if(type!=M_RAISE_WINDOW && type!=M_LOWER_WINDOW &&
++ type!=M_FOCUS_CHANGE && type!=M_ICON_NAME &&
++ type!=M_MINI_ICON && type!=M_STRING)
++ {
++ ClearRaised();
++ }
++
++ switch (type)
++ {
++ case M_CONFIGURE_WINDOW:
++ case M_ADD_WINDOW:
++ ConfigureWindow(packet);
++ break;
++ case M_DESTROY_WINDOW:
++ DestroyWindow(bh->w);
++ break;
++ case M_ICONIFY:
++ IconifyWindow(FindProxy(bh->w), 1);
++ break;
++ case M_DEICONIFY:
++ IconifyWindow(FindProxy(bh->w), 0);
++ break;
++ case M_RAISE_WINDOW:
++ RaiseLowerGroup(bh->w,1);
++ break;
++ case M_LOWER_WINDOW:
++ RaiseLowerGroup(bh->w,0);
++ break;
++ case M_WINDOW_NAME:
++ proxy = FindProxy(bh->w);
++ if (proxy != NULL)
++ {
++ if (proxy->name != NULL)
++ {
++ free(proxy->name);
++ }
++ proxy->name = safestrdup((char*)&body[3]);
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"M_WINDOW_NAME %s\n",proxy->name);
++#endif
++ UpdateProxyGroup(proxy);
++ UpdateProxyGroupForAll();
++ }
++ break;
++ case M_ICON_NAME:
++ proxy = FindProxy(bh->w);
++ if (proxy != NULL)
++ {
++ if (proxy->iconname != NULL)
++ {
++ free(proxy->iconname);
++ }
++ proxy->iconname = safestrdup((char*)&body[3]);
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr,"M_ICON_NAME %s\n",proxy->iconname);
++#endif
++/* UpdateOneWindow(proxy);
++*/
++ DrawProxyBackground(proxy);
++ DrawProxy(proxy);
++ }
++ break;
++ case M_NEW_DESK:
++ if (deskNumber!=body[0])
++ {
++ deskNumber=body[0];
++ if (are_windows_shown)
++ {
++ ReshuffleWindows();
++ }
++ }
++ break;
++ case M_NEW_PAGE:
++ deskNumber=body[2];
++ ReshuffleWindows();
++ break;
++ case M_MINI_ICON:
++ proxy = FindProxy(bh->w);
++ if (proxy != NULL)
++ {
++ proxy->picture.width=body[3];
++ proxy->picture.height=body[4];
++ proxy->picture.depth=body[5];
++ proxy->picture.picture=body[6];
++ proxy->picture.mask=body[7];
++ proxy->picture.alpha=body[8];
++ UpdateOneWindow(proxy);
++ }
++ break;
++ case M_FOCUS_CHANGE:
++ {
++ focusWindow=bh->w;
++ if(bh->w != 0)
++ {
++ last_rotation_instigator=NULL;
++ }
++ }
++ break;
++ case M_STRING:
++ {
++ char *message=(char*)&body[3];
++ char *token;
++ char *next;
++ int prev;
++ int isolate_check=0;
++ int reshuffle=0;
++
++#if PROXY_GROUP_DEBUG
++ fprintf(stderr, "M_STRING \"%s\"\n", message);
++#endif
++
++ token = PeekToken(message, &next);
++ prev=(StrEquals(token, "Prev"));
++ if (StrEquals(token, "Next") || prev)
++ {
++ ProxyWindow *lastSelect=selectProxy;
++ ProxyWindow *newSelect=selectProxy;
++ ProxyWindow *first=prev? lastProxy: firstProxy;
++
++ /* auto-show if not already shown */
++ if (!are_windows_shown)
++ StartProxies();
++
++ if (startProxy && startProxy->desk==deskNumber)
++ {
++ newSelect=startProxy;
++ startProxy=NULL;
++ }
++ else
++ {
++ if (newSelect)
++ {
++ if (prev)
++ newSelect=newSelect->prev;
++ else
++ newSelect=newSelect->next;
++ }
++ if (!newSelect)
++ newSelect=first;
++ while (newSelect!=lastSelect &&
++ newSelect->desk!=deskNumber)
++ {
++ if (prev)
++ newSelect=newSelect->prev;
++ else
++ newSelect=newSelect->next;
++ if (!newSelect && lastSelect)
++ newSelect=first;
++ }
++ }
++
++ MarkProxy(newSelect);
++ }
++ else if (StrEquals(token, "Circulate"))
++ {
++ Window w;
++
++ /* auto-show if not already shown */
++ if (!are_windows_shown)
++ StartProxies();
++
++ w = (selectProxy) ? selectProxy->window : focusWindow;
++
++ strcpy(commandBuffer,next);
++ strcat(commandBuffer," SendToModule FvwmProxy Mark");
++ if (next)
++ SendFvwmPipe(fd,commandBuffer,w);
++ }
++ else if (StrEquals(token, "Show"))
++ {
++ StartProxies();
++ }
++ else if (StrEquals(token, "Hide"))
++ {
++ SelectProxy();
++ }
++ else if (StrEquals(token, "ShowToggle"))
++ {
++ if (are_windows_shown)
++ {
++ SelectProxy();
++ }
++ else
++ {
++ StartProxies();
++ }
++ }
++ else if (StrEquals(token, "Abort"))
++ {
++ AbortProxies();
++ }
++ else if (StrEquals(token, "Mark"))
++ {
++#if 0
++ Window w;
++
++ if (next == NULL)
++ {
++ proxy = NULL;
++ }
++ else if (sscanf(next, "0x%x", (int *)&w) < 1)
++ {
++ proxy = NULL;
++ }
++ else
++#endif
++ {
++ focusWindow=bh->w;
++ proxy = FindProxy(bh->w);
++ }
++ MarkProxy(proxy);
++ }
++ else if (StrEquals(token, "Resolve"))
++ {
++ waiting_to_config=0;
++ pending_do=0;
++ ResolvePendingWindows();
++ reshuffle=1;
++ }
++ else if (StrEquals(token, "Stamp"))
++ {
++ token = PeekToken(message, &next);
++ sscanf(next,"%d%d%d%d",&x,&y,&w,&h);
++
++ waiting_to_stamp=0;
++ proxy = FindProxy(bh->w);
++ if(proxy && w && h)
++ {
++ StoreStamp(bh->w,x,y,w,h);
++ }
++ reshuffle=1;
++ }
++ else if (StrEquals(token, "Undo"))
++ {
++ UndoStamp();
++ reshuffle=1;
++ }
++ else if (StrEquals(token, "Redo"))
++ {
++ RedoStamp();
++ reshuffle=1;
++ }
++ else if (StrEquals(token, "PrevIsolated"))
++ {
++ RotateIsolated(FindProxy(bh->w),-1);
++ }
++ else if (StrEquals(token, "NextIsolated"))
++ {
++ RotateIsolated(FindProxy(bh->w),1);
++ }
++ else if (StrEquals(token, "SoftToggle"))
++ {
++ proxy = FindProxy(bh->w);
++ if(proxy)
++ {
++ proxy->flags.is_soft= proxy->group?
++ !proxy->flags.is_soft: 0;
++ isolate_check=1;
++
++ DrawProxyBackground(proxy);
++ DrawProxy(proxy);
++ }
++ }
++ else if (StrEquals(token, "IsolateToggle"))
++ {
++ proxy = FindProxy(bh->w);
++ if(proxy)
++ {
++ proxy->flags.is_isolated= proxy->group?
++ !proxy->flags.is_isolated: 0;
++ IsolateGroup(proxy,proxy->flags.is_isolated);
++ isolate_check=1;
++
++ DrawProxyBackground(proxy);
++ DrawProxy(proxy);
++ reshuffle=1;
++ }
++ }
++ if(isolate_check)
++ {
++ IsolateCheck(proxy,0);
++ }
++ if(reshuffle)
++ {
++ /* windows may have moved, so update proxy windows */
++ if (are_windows_shown)
++ {
++ ReshuffleWindows();
++ }
++ }
++ break;
++ }
++ case M_CONFIG_INFO:
++ {
++ char *tline, *token;
++
++ tline = (char*)&(body[3]);
++ token = PeekToken(tline, &tline);
++ if (StrEquals(token, "Colorset"))
++ {
++ int cset;
++ cset = LoadColorset(tline);
++ change_cset(cset);
++ }
++ break;
++ }
++ }
++
++ return;
++}
++
++static int My_XNextEvent(Display *dpy,XEvent *event)
++{
++ fd_set in_fdset;
++
++ struct timeval timevalue,*timeout=&timevalue;
++ timevalue.tv_sec = 0;
++ timevalue.tv_usec = 100000;
++
++ if (FPending(dpy))
++ {
++ FNextEvent(dpy,event);
++ return 1;
++ }
++
++ FD_ZERO(&in_fdset);
++ FD_SET(x_fd,&in_fdset);
++ FD_SET(fd[1],&in_fdset);
++
++ if ( fvwmSelect(fd_width, &in_fdset, 0, 0, timeout) > 0)
++ {
++ if (FD_ISSET(x_fd, &in_fdset))
++ {
++ if (FPending(dpy))
++ {
++ FNextEvent(dpy,event);
++ return 1;
++ }
++ }
++
++ if (FD_ISSET(fd[1], &in_fdset))
++ {
++ FvwmPacket* packet = ReadFvwmPacket(fd[1]);
++ if (!packet)
++ {
++ exit(0);
++ }
++
++ ProcessMessage(packet);
++ }
++ }
++
++ return 0;
++}
++
++static void DispatchEvent(XEvent *pEvent)
++{
++ Window window=pEvent->xany.window;
++ ProxyWindow *proxy;
++ int dx,dy;
++
++ switch(pEvent->xany.type)
++ {
++ case Expose:
++ proxy = FindProxy(window);
++ if (proxy != NULL)
++ {
++ DrawWindow(
++ proxy, pEvent->xexpose.x, pEvent->xexpose.y,
++ pEvent->xexpose.width,
pEvent->xexpose.height);
++ }
++ break;
++ case ButtonPress:
++ proxy = FindProxy(window);
++ if (proxy)
++ {
++ int button=pEvent->xbutton.button;
++ int wx=pEvent->xbutton.x;
++ int wy=pEvent->xbutton.y;
++ if (button >= 1 &&
++ button <= NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
++ {
++ if(wy < slotSpace+slotHeight)
++ {
++ int index=(wx-slotSpace)/
++ (slotWidth+slotSpace)+1;
++ int group=index-groupSlot+1;
++
++ if(index<numSlots)
++ {
++ char* action=slot_action_list[
++ button-1][index];
++ if(action)
++ {
++
SendFvwmPipe(fd,action,
++
proxy->window);
++ }
++ }
++ if(group && group<=groupCount)
++ {
++ SetGroup(proxy,
++ proxy->group==group?
++ 0: group);
++ DrawProxyBackground(proxy);
++ DrawProxy(proxy);
++ }
++ }
++ else
++ {
++ SendFvwmPipe(fd,
++ action_list[PROXY_ACTION_CLICK
++ + button-1],
++ proxy->window);
++ }
++ }
++ }
++ mousex=pEvent->xbutton.x_root;
++ mousey=pEvent->xbutton.y_root;
++ break;
++ case MotionNotify:
++ proxy = FindProxy(window);
++ dx=pEvent->xbutton.x_root-mousex;
++ dy=pEvent->xbutton.y_root-mousey;
++ if (proxy && proxyMove)
++ {
++ sprintf(commandBuffer,"Silent Move w%dp w%dp",dx,dy);
++ SendText(fd,commandBuffer,proxy->window);
++ }
++
++ mousex=pEvent->xbutton.x_root;
++ mousey=pEvent->xbutton.y_root;
++ break;
++ case EnterNotify:
++ proxy = FindProxy(pEvent->xcrossing.window);
++ if (pEvent->xcrossing.mode == NotifyNormal)
++ {
++ MarkProxy(proxy);
++ enterProxy = proxy;
++ }
++ else if (pEvent->xcrossing.mode == NotifyUngrab &&
++ proxy != NULL && proxy != selectProxy &&
++ proxy != enterProxy)
++ {
++ MarkProxy(proxy);
++ enterProxy = proxy;
++ }
++ break;
++ default:
++ fprintf(stderr, "Unrecognized XEvent %d\n",
pEvent->xany.type);
++ break;
++ }
++
++ return;
++}
++
++static void Loop(int *fd)
++{
++ XEvent event;
++ long result;
++
++ while (1)
++ {
++ if ((result=My_XNextEvent(dpy,&event))==1)
++ {
++ DispatchEvent(&event);
++ }
++
++#if PROXY_KEY_POLLING
++ if(are_windows_shown && watching_modifiers)
++ {
++ unsigned int mask_return=GetModifiers();
++ if(!(mask_return&watched_modifiers))
++ {
++ watching_modifiers=0;
++ send_command_to_fvwm(
++ action_list
++ [PROXY_ACTION_MODIFIER_RELEASE],
++ None);
++ }
++ }
++#endif
++ }
++}
++
++/* ---------------------------- interface functions
------------------------- */
++
++int main(int argc, char **argv)
++{
++ char *titles[1];
++
++ if (argc < 6)
++ {
++ fprintf(
++ stderr,
++ "FvwmProxy should only be executed by fvwm!\n");
++ exit(1);
++ }
++
++ FlocaleInit(LC_CTYPE, "", "", "FvwmProxy");
++ MyName = GetFileNameFromPath(argv[0]);
++
++ fd[0] = atoi(argv[1]);
++ fd[1] = atoi(argv[2]);
++
++ originalXIOErrorHandler=XSetIOErrorHandler(myXIOErrorHandler);
++ originalXErrorHandler=XSetErrorHandler(myXErrorHandler);
++
++ if (!(dpy=XOpenDisplay(NULL)))
++ {
++ fprintf(stderr,"can't open display\n");
++ exit (1);
++ }
++ titles[0]="FvwmProxy";
++ if (XStringListToTextProperty(titles,1,&windowName) == 0)
++ {
++ fprintf(stderr,"Proxy_CreateBar() could not allocate space"
++ " for window title");
++ }
++
++ PictureInitCMap(dpy);
++ FScreenInit(dpy);
++ FRenderInit(dpy);
++ AllocColorset(0);
++ FlocaleAllocateWinString(&FwinString);
++ screen = DefaultScreen(dpy);
++ rootWindow = RootWindow(dpy,screen);
++ xgcv.plane_mask=AllPlanes;
++ miniIconGC=fvwmlib_XCreateGC(dpy,rootWindow,GCPlaneMask,&xgcv);
++ fg_gc = fvwmlib_XCreateGC(dpy,rootWindow,GCPlaneMask,&xgcv);
++ hi_gc = fvwmlib_XCreateGC(dpy,rootWindow,GCPlaneMask,&xgcv);
++ sh_gc = fvwmlib_XCreateGC(dpy,rootWindow,GCPlaneMask,&xgcv);
++
++ x_fd = XConnectionNumber(dpy);
++ fd_width = GetFdWidth();
++
++ SetMessageMask(
++ fd, M_STRING| M_RAISE_WINDOW| M_LOWER_WINDOW|
++ M_CONFIGURE_WINDOW| M_ADD_WINDOW| M_FOCUS_CHANGE|
++ M_DESTROY_WINDOW| M_NEW_DESK| M_NEW_PAGE| M_ICON_NAME|
++ M_WINDOW_NAME| M_MINI_ICON| M_ICONIFY| M_DEICONIFY|
++ M_CONFIG_INFO| M_END_CONFIG_INFO);
++
++ if (parse_options() == False)
++ exit(1);
++ stampQueue=(GeometryStamp*)safemalloc(
++ sizeof(GeometryStamp)*stampLimit);
++ if ((Ffont = FlocaleLoadFont(dpy, font_name, MyName)) == NULL)
++ {
++ fprintf(stderr,"%s: Couldn't load font \"%s\". Exiting!\n",
++ MyName, font_name);
++ exit(1);
++ }
++ if (Ffont->font != NULL)
++ {
++ XSetFont(dpy,fg_gc,Ffont->font->fid);
++ }
++ Ffont_small=NULL;
++ if(small_font_name)
++ {
++ if((Ffont_small =
++ FlocaleLoadFont(dpy, small_font_name, MyName)) ==
NULL)
++ {
++ fprintf(stderr,
++ "%s: Couldn't load small font \"%s\"\n",
++ MyName, small_font_name);
++ }
++ }
++ if (Ffont_small != NULL && Ffont_small->font != NULL)
++ {
++ XSetFont(dpy,hi_gc,Ffont_small->font->fid);
++ }
++ SendInfo(fd,"Send_WindowList",0);
++ SendFinishedStartupNotification(fd);
++ Loop(fd);
++
++ free(stampQueue);
++ return 0;
++}




Archive powered by MHonArc 2.6.24.

Top of Page