Subject: Patch for placing windows under the mouse

From: Christoph Bussenius <[email-masked]>
Date: Fri, 27 Aug 2004 01:39:04 +0200

Hi everyone,

I did not feal comfortable with any of the provided window placement
methods.  I would like the windows to appear where the mouse pointer is
because this is the place my eyes are concentrating on.

Even ManualPlacement is one click too much.

The patch allows you to put "Style * MousePlacement" into your .fvwm2rc
and you will never have to turn your head again when a new window shows
up.

diff -ru fvwm-2.5.10/fvwm/fvwm.h fvwm-2.5.10-pepe/fvwm/fvwm.h
--- fvwm-2.5.10/fvwm/fvwm.h	2004-02-16 14:45:59.000000000 +0100
+++ fvwm-2.5.10-pepe/fvwm/fvwm.h	2004-08-27 00:12:11.633285840 +0200
@@ -467,8 +467,9 @@
 #define PLACE_TILECASCADE       0x5
 #define PLACE_CASCADE_B         0x6
 #define PLACE_MINOVERLAP        0x7
-#define PLACE_MASK              0x7
-	unsigned placement_mode : 3;
+#define PLACE_MOUSE		0x8
+#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
diff -ru fvwm-2.5.10/fvwm/placement.c fvwm-2.5.10-pepe/fvwm/placement.c
--- fvwm-2.5.10/fvwm/placement.c	2004-03-17 17:57:50.000000000 +0100
+++ fvwm-2.5.10-pepe/fvwm/placement.c	2004-08-26 23:31:00.000000000 +0200
@@ -984,6 +984,13 @@
 			fw, sflags, &screen_g, &xl, &yt, pdeltax, pdeltay, 1);
 		flags.is_smartly_placed = True;
 		break;
+	case PLACE_MOUSE:
+		if (False != FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
+		      &attr_g->x, &attr_g->y, &JunkX, &JunkY, &JunkMask))
+		{
+			break;
+		}
+		/* fall through to tilecascade placement */
 	case PLACE_TILECASCADE:
 		flags.is_smartly_placed = SmartPlacement(
 			fw, &screen_g, fw->frame_g.width, fw->frame_g.height,
diff -ru fvwm-2.5.10/fvwm/style.c fvwm-2.5.10-pepe/fvwm/style.c
--- fvwm-2.5.10/fvwm/style.c	2004-02-16 14:45:59.000000000 +0100
+++ fvwm-2.5.10-pepe/fvwm/style.c	2004-08-26 23:34:29.000000000 +0200
@@ -3087,6 +3087,12 @@
 			FPS_RAISE_UNFOCUSED_CLIENT_CLICK(
 				S_FOCUS_POLICY(SCC(*ps)), 1);
 		}
+		else if (StrEquals(token, "MousePlacement"))
+		{
+			ps->flags.placement_mode = PLACE_MOUSE;
+			ps->flag_mask.placement_mode = PLACE_MASK;
+			ps->change_mask.placement_mode = PLACE_MASK;
+		}
 		else if (StrEquals(token, "MaxWindowSize"))
 		{
 			int val1;

Regards,
Christoph
--
Visit the official FVWM web page at <URL:http://www.fvwm.org/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked]

---

From: Mikhael Goikhman <[email-masked]>
Date: Fri, 27 Aug 2004 00:15:07 +0000

> and you will never have to turn your head again when a new window shows

I think UnderCursorPlacement is a more intuitive name.
MousePlacement sounds like ManualPlacement using the mouse.

todo-3.0 also mentions UnderCursorPlacementOffset. Or maybe the algorithm
should be to center a window under the cursor, but have it fully visible
if possible.

You should also patch at least the man page (and ChangeLog, NEWS).

Regards,
Mikhael.

---

From: Arwed von Merkatz <[email-masked]>
Date: Fri, 27 Aug 2004 14:02:25 +0200

> should be to center a window under the cursor, but have it fully visible

Here's my implementation of UnderMousePlacement I did several months
ago, it centers the window under the mouse pointer, keeping it within
the screen if possible (also takes struts into account).

-- 
Arwed v. Merkatz                              Source Mage GNU/Linux developer
                                                    http://www.sourcemage.org
Index: fvwm/fvwm.h
===================================================================
RCS file: /home/cvs/fvwm/fvwm/fvwm/fvwm.h,v
retrieving revision 1.235
diff -u -r1.235 fvwm.h
--- fvwm/fvwm.h	7 Aug 2004 20:46:10 -0000	1.235
+++ fvwm/fvwm.h	27 Aug 2004 11:58:03 -0000
@@ -487,6 +487,7 @@
 #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 */
Index: fvwm/placement.c
===================================================================
RCS file: /home/cvs/fvwm/fvwm/fvwm/placement.c,v
retrieving revision 1.137
diff -u -r1.137 placement.c
--- fvwm/placement.c	19 Aug 2004 19:56:30 -0000	1.137
+++ fvwm/placement.c	27 Aug 2004 11:58:08 -0000
@@ -1061,6 +1061,34 @@
 			fw, sflags, &screen_g, &xl, &yt, pdeltax, pdeltay, 0);
 		flags.is_smartly_placed = True;
 		break;
+  case PLACE_UNDERMOUSE:
+      {
+        int mx;
+        int my;
+        FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
+          &mx, &my, &JunkX, &JunkY, &JunkMask);
+        xl = mx - (fw->frame_g.width / 2);
+        yt = my - (fw->frame_g.height / 2);
+        if (xl + fw->frame_g.width > screen_g.x + screen_g.width)
+        {
+          xl = screen_g.x + screen_g.width - fw->frame_g.width;
+        }
+        if (yt + fw->frame_g.height > screen_g.y + screen_g.height)
+        {
+          yt = screen_g.y + screen_g.height - fw->frame_g.height;
+        }
+        if (xl < screen_g.x)
+        {
+          xl = screen_g.x;
+        }
+        if (yt < screen_g.y)
+        {
+          yt = screen_g.y;
+        }
+        attr_g->x = xl;
+        attr_g->y = yt;
+      }
+      break;
 	default:
 		/* can't happen */
 		break;
@@ -1820,6 +1848,9 @@
 		case PLACE_MINOVERLAP:
 			a = "MinOverlap";
 			break;
+    case PLACE_UNDERMOUSE:
+      a = "UnderMouse";
+      break;
 		default:
 			a = "bug";
 			break;
Index: fvwm/style.c
===================================================================
RCS file: /home/cvs/fvwm/fvwm/fvwm/style.c,v
retrieving revision 1.226
diff -u -r1.226 style.c
--- fvwm/style.c	30 May 2004 14:05:48 -0000	1.226
+++ fvwm/style.c	27 Aug 2004 11:58:26 -0000
@@ -3769,7 +3769,13 @@
 		break;
 
 	case 'u':
-		if (StrEquals(token, "UsePPosition"))
+		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;

---

From: Christoph Bussenius <[email-masked]>
Date: Tue, 31 Aug 2004 23:46:42 +0200

> You should also patch at least the man page (and ChangeLog, NEWS).

OK, here is my next try:

UnderCursorPlacement places new windows at a position  relative  to
where  the  mouse  pointer is.  It takes two arguments: XOffset and
YOffset.  YOffset specifies the vertical position of the upper win-
dow  edge  relative  to  the mouse pointer.  If YOffset is preceded
with the letter 'c', the center of the window is  used  instead  of
the  upper edge.  A similar definition holds for XOffset.  An argu-
ment 'c0' may also be written as 'c'.

This example should place new windows so that the mouse is  in  the
right half of the title bar:

     Style * UnderCursorPlacement c-20 -10

Regards,
Christoph

diff -ru fvwm-2.5.10/AUTHORS fvwm-2.5.10-pepe/AUTHORS
--- fvwm-2.5.10/AUTHORS	2004-03-19 17:16:23.000000000 +0100
+++ fvwm-2.5.10-pepe/AUTHORS	2004-08-31 23:00:26.341213504 +0200
@@ -172,6 +172,9 @@
 Original idea for 'previous page' parameter (MoveToPage and
 GotoPage).
 
+Christoph Bussenius:
+UnderCursorPlacement style
+
 Dan Espen:
 Color Limiting, Multiple IconBoxes, Iconification Animation, new
 3d hilight/shadow calc from scwm as a library routine, updated web
diff -ru fvwm-2.5.10/ChangeLog fvwm-2.5.10-pepe/ChangeLog
--- fvwm-2.5.10/ChangeLog	2004-03-19 17:30:46.000000000 +0100
+++ fvwm-2.5.10-pepe/ChangeLog	2004-08-31 23:20:14.971514232 +0200
@@ -1,3 +1,14 @@
+2004-08-31  Christoph Bussenius  <[email-masked]>
+
+	* fvwm/fvwh.h:
+	* fvwm/style.h:
+	* fvwm/style.c:
+	* fvwm/placement.c:
+	Added "UnderCursorPlacement"
+
+	* fvwm/placement.c (__place_get_wm_pos and __place_window):
+	Extended prototypes
+
 2004-03-19  Dominik Vogt  <[email-masked]>
 
 	* NEWS:
diff -ru fvwm-2.5.10/fvwm/fvwm.1.in fvwm-2.5.10-pepe/fvwm/fvwm.1.in
--- fvwm-2.5.10/fvwm/fvwm.1.in	2004-03-17 15:42:54.000000000 +0100
+++ fvwm-2.5.10-pepe/fvwm/fvwm.1.in	2004-08-31 22:52:34.590930448 +0200
@@ -6193,7 +6193,7 @@
 .IR StickyAcrossDesksIcon " / " !StickyAcrossDesksIcon ,
 .IR ManualPlacement " / " CascadePlacement " / " MinOverlapPlacement " / "
 .IR MinOverlapPercentPlacement " / " TileManualPlacement " / "
-.IR TileCascadePlacement ,
+.IR TileCascadePlacement " / " UnderCursorPlacement,
 .IR MinOverlapPlacementPenalties ,
 .IR MinOverlapPercentPlacementPenalties ,
 .IR DecorateTransient " / " NakedTransient ,
@@ -7378,6 +7378,32 @@
 finish initial placement, the window is automatically enlarged
 until it hits the bottom screen border.
 
+.I UnderCursorPlacement
+places new windows at a position relative to where the mouse pointer is.
+It takes two arguments:
+.IR XOffset
+and
+.IR YOffset .
+.IR YOffset
+specifies the vertical position of the upper window edge relative to the
+mouse pointer.  If
+.IR YOffset
+is preceded with the letter
+.RI ' c ',
+the center of the window is used instead of the upper edge.
+A similar definition holds for
+.IR XOffset .
+An argument
+.RI ' c0 '
+may also be written as
+.RI ' c '.
+
+This example should place new windows so that the mouse is in the right half
+of the title bar:
+.EX
+Style * UnderCursorPlacement c-20 -10
+.EE
+
 .I Old placement styles
 DumbPlacement / SmartPlacement / SmartPlacementOff,
 ActivePlacement / RandomPlacement,
diff -ru fvwm-2.5.10/fvwm/fvwm.h fvwm-2.5.10-pepe/fvwm/fvwm.h
--- fvwm-2.5.10/fvwm/fvwm.h	2004-02-16 14:45:59.000000000 +0100
+++ fvwm-2.5.10-pepe/fvwm/fvwm.h	2004-08-31 20:55:05.768514336 +0200
@@ -467,8 +467,9 @@
 #define PLACE_TILECASCADE       0x5
 #define PLACE_CASCADE_B         0x6
 #define PLACE_MINOVERLAP        0x7
-#define PLACE_MASK              0x7
-	unsigned placement_mode : 3;
+#define PLACE_CURSOR		0x8
+#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
@@ -599,6 +600,7 @@
 	float norm_placement_penalty;
 	float placement_penalty[6];
 	int placement_percentage_penalty[4];
+	int placement_undercursor_offset[2];
 	style_flags flags;
 	style_flags flag_default;
 	style_flags flag_mask;
diff -ru fvwm-2.5.10/fvwm/placement.c fvwm-2.5.10-pepe/fvwm/placement.c
--- fvwm-2.5.10/fvwm/placement.c	2004-03-17 17:57:50.000000000 +0100
+++ fvwm-2.5.10-pepe/fvwm/placement.c	2004-08-31 21:26:48.328281288 +0200
@@ -851,11 +851,11 @@
 }
 
 static Bool __place_get_wm_pos(
-	const exec_context_t *exc, style_flags *sflags, rectangle *attr_g,
-	placement_flags_t flags, rectangle screen_g,
-	placement_start_style_t start_style, int mode,
-	initial_window_options_t *win_opts, placement_reason_t *reason,
-	int pdeltax, int pdeltay)
+	const exec_context_t *exc, struct window_style *pstyle, style_flags
+	*sflags, rectangle *attr_g, placement_flags_t flags, rectangle
+	screen_g, placement_start_style_t start_style, int mode,
+	initial_window_options_t *win_opts, placement_reason_t *reason, int
+	pdeltax, int pdeltay)
 {
 	unsigned int placement_mode = SPLACEMENT_MODE(sflags);
 	FvwmWindow *fw = exc->w.fw;
@@ -984,6 +984,31 @@
 			fw, sflags, &screen_g, &xl, &yt, pdeltax, pdeltay, 1);
 		flags.is_smartly_placed = True;
 		break;
+	case PLACE_CURSOR:
+		if (False != FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
+		      &attr_g->x, &attr_g->y, &JunkX, &JunkY, &JunkMask))
+		{
+			int i;
+			int *pos[2] = {&attr_g->x, &attr_g->y};
+			int dim[2] = {fw->frame_g.width, fw->frame_g.height};
+			int scrdim[2] = {screen_g.width, screen_g.height};
+			int scrpos[2] = {screen_g.x, screen_g.y};
+			for (i=0; i<2; i++)
+			{
+				if (SGET_PLACEMENT_CURSOR_CENTER(
+					*pstyle, i))
+				{
+					*pos[i] -= dim[i]/2;
+				}
+				*pos[i] += SGET_PLACEMENT_CURSOR_OFFSET(
+					*pstyle, i);
+				/* Do not place the window off the viewport */
+				*pos[i] = max(scrpos[i], min(
+					scrpos[i]+scrdim[i]-dim[i], *pos[i]));
+			}
+			break;
+		}
+		/* fall through to tilecascade placement */
 	case PLACE_TILECASCADE:
 		flags.is_smartly_placed = SmartPlacement(
 			fw, &screen_g, fw->frame_g.width, fw->frame_g.height,
@@ -1220,9 +1245,9 @@
  *   1 = OK
  *   2 = OK, window must be resized too */
 static Bool __place_window(
-	const exec_context_t *exc, style_flags *sflags, rectangle *attr_g,
-	placement_start_style_t start_style, int mode,
-	initial_window_options_t *win_opts, placement_reason_t *reason)
+	const exec_context_t *exc, struct window_style *pstyle, style_flags
+	*sflags, rectangle *attr_g, placement_start_style_t start_style, int
+	mode, initial_window_options_t *win_opts, placement_reason_t *reason)
 {
 	FvwmWindow *t;
 	int px = 0;
@@ -1489,7 +1514,7 @@
 	else
 	{
 		rc = __place_get_wm_pos(
-			exc, sflags, attr_g, flags, screen_g, start_style,
+			exc, pstyle, sflags, attr_g, flags, screen_g, start_style,
 			mode, win_opts, reason, pdeltax, pdeltay);
 	}
 	reason->pos.x = attr_g->x;
@@ -1888,7 +1913,7 @@
 	start_style.page_y = SGET_START_PAGE_Y(*pstyle);
 	start_style.screen = SGET_START_SCREEN(*pstyle);
 	rc = __place_window(
-		exc, &pstyle->flags, attr_g, start_style, mode, win_opts,
+		exc, pstyle, &pstyle->flags, attr_g, start_style, mode, win_opts,
 		&reason);
 	exc_destroy_context(exc);
 	if (Scr.bo.do_explain_window_placement == 1)
diff -ru fvwm-2.5.10/fvwm/style.c fvwm-2.5.10-pepe/fvwm/style.c
--- fvwm-2.5.10/fvwm/style.c	2004-02-16 14:45:59.000000000 +0100
+++ fvwm-2.5.10-pepe/fvwm/style.c	2004-08-31 21:41:59.991687384 +0200
@@ -613,6 +613,12 @@
 			*merged_style,
 			SGET_75_PLACEMENT_PERCENTAGE_PENALTY(*add_style));
 	}
+	if (PLACE_CURSOR == add_style->flags.placement_mode)
+	{
+		memcpy(merged_style->placement_undercursor_offset,
+			add_style->placement_undercursor_offset,
+			sizeof(add_style->placement_undercursor_offset));
+	}
 	/* merge the style flags */
 
 	/*** ATTENTION:
@@ -3734,7 +3740,45 @@
 		break;
 
 	case 'u':
-		if (StrEquals(token, "UsePPosition"))
+		if (StrEquals(token, "UnderCursorPlacement"))
+		{
+			int i, offset;
+			for (i=0; i<2; i++)
+			{
+				rest = GetNextToken(rest, &token);
+				if (NULL != token && 'c' == token[0])
+				{
+					SSET_PLACEMENT_CURSOR_CENTER(*ps, i);
+					if ('\0' == *++token)
+					{
+						SSET_PLACEMENT_CURSOR_OFFSET(
+							*ps, 0, i);
+						continue;
+					}
+				}
+				if (NULL != token &&
+					1 == sscanf(token, "%d", &offset))
+				{
+					SSET_PLACEMENT_CURSOR_OFFSET(
+						*ps, offset, i);
+				}
+				else
+				{
+					fvwm_msg(ERR,
+						"style_parse_one_style_option",
+						"UnderCursorPlacement: "
+						"Bad or missing parameters");
+					break;
+				}
+			}
+			if (2 == i) /* No error */
+			{
+				ps->flags.placement_mode = PLACE_CURSOR;
+				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;
diff -ru fvwm-2.5.10/fvwm/style.h fvwm-2.5.10-pepe/fvwm/style.h
--- fvwm-2.5.10/fvwm/style.h	2004-02-16 14:45:59.000000000 +0100
+++ fvwm-2.5.10-pepe/fvwm/style.h	2004-08-31 21:49:35.799394080 +0200
@@ -571,6 +571,14 @@
 	((s).placement_percentage_penalty[2] = (x))
 #define SSET_75_PLACEMENT_PERCENTAGE_PENALTY(s,x) \
 	((s).placement_percentage_penalty[3] = (x))
+#define SGET_PLACEMENT_CURSOR_CENTER(sf,coord) \
+	((sf).placement_undercursor_offset[coord] & 1)
+#define SSET_PLACEMENT_CURSOR_CENTER(sf,coord) \
+	((sf).placement_undercursor_offset[coord] |= 1)
+#define SGET_PLACEMENT_CURSOR_OFFSET(sf,coord) \
+	((sf).placement_undercursor_offset[coord] >> 1)
+#define SSET_PLACEMENT_CURSOR_OFFSET(sf, off,coord) \
+	((sf).placement_undercursor_offset[coord] |= off << 1)
 
 /* function prototypes */
 void lookup_style(FvwmWindow *fw, window_style *styles);

-- 
``There's no dark side of the moon, really
Matter of fact, it's all dark''

--Pink Floyd