Skip to content

Commit

Permalink
Adjust windows to fit working area after move.
Browse files Browse the repository at this point in the history
When moving windows, it made sense to consider the working area
base struts before the move when the base struts were on the
global view port. Now that the base struts are per monitor this
no longer makes sense, and caused strange behavior since the
coordinates were relative to the current monitor when computing
where to move a window.

Instead the window's position is adjusted to fit inside the working
area of the monitor the window is mostly on (determined by the center
of the window) after the move is done. This way the position of the
window is always computed relative to the global screen (or the monitor
specified via the 'screen RANDR_NAME' option). This also ensures that
the window is placed on a valid page.

If the ewmhiwa option is provided, any adjustment to the window
is skipped, and this allows users to place the window anywhere
they want. This option should now be used more often in cases like
auto hiding a panel just off screen.
  • Loading branch information
somiaj committed Oct 15, 2024
1 parent aa4e6a3 commit a5424e6
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 42 deletions.
34 changes: 21 additions & 13 deletions doc/fvwm3_manpage_source.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3906,10 +3906,16 @@ Move [screen _S_] [desk _N_] [w | m | v]_x_[p | w] [w | m | v]_y_[p | w] [Warp]
....
+
This will move the window to the _x_ and _y_ position (see below).
By default, the EWMH working area is honoured. If he trailing option
_ewmhiwa_ is given, then the window position will ignore the working
area (such as ignoring any values set via *EwmhBaseStruts*). If the
option _Warp_ is given then the pointer is warped to the window.
By default, the EWMH working area of each monitor is honoured (the
working area for each monitor is set via *EwmhBaseStruts* and honors
any strut hints provided by windows on the monitor). This means that
if a window is placed outside the working area, the position of the
window will be adjusted to fit inside the working area of the screen
the center of the window is on. If the trailing option _ewmhiwa_ is
given, then the window position will ignore the working area and its
position will not be adjusted (this option is needed to move windows
off the screen and to have full control of where it is placed). If
the option _Warp_ is given then the pointer is warped to the window.
+
If the literal option _screen_ followed by a RandR screen name _S_ is
specified, the coordinates are interpreted as relative to the given
Expand All @@ -3925,15 +3931,17 @@ is updated to be the same as the new monitor. This option can override
that behavior by specifying which desk the window should end up on.
+
The positional arguments _x_ and _y_ can specify an absolute or relative
position from either the left/top or right/bottom of the screen. By default,
the numeric value given is interpreted as a percentage of the screen
width/height, but a trailing '_p_' changes the interpretation to mean pixels,
while a trailing '_w_' means percent of the window width/height. To move the
window relative to its current position, add the '_w_' (for "window") prefix
before the _x_ and/or _y_ value. To move the window to a position relative to
the current location of the pointer, add the '_m_' (for "mouse") prefix. To
move the window relative to the virtual screen coordinates, add the '_v_'
(for "virtual screen") prefix. This is mostly for internal use with FvwmPager,
position from either the left/top (positive values) or right/bottom
(negative values) of the global screen (the bounding box that contains all
monitors) or specified _screen_. By default, the numeric value given is
interpreted as a percentage of the screen's width/height, but a trailing
'_p_' changes the interpretation to mean pixels, while a trailing '_w_'
means percent of the window width/height. To move the window relative to
its current position, add the '_w_' (for "window") prefix before the _x_
and/or _y_ value. To move the window to a position relative to the current
location of the pointer, add the '_m_' (for "mouse") prefix. To move the
window relative to the virtual screen coordinates, add the '_v_' (for
"virtual screen") prefix. This is mostly for internal use with FvwmPager,
but can be used to give exact coordinates on the virtual screen and is best
used with the '_p_' suffix. To leave either coordinate unchanged, "_keep_"
can be specified in place of _x_ or _y_.
Expand Down
4 changes: 2 additions & 2 deletions fvwm/ewmh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1116,9 +1116,9 @@ void EWMH_UpdateWorkArea(struct monitor *m)
}

void EWMH_GetWorkAreaIntersection(
FvwmWindow *fw, int *x, int *y, int *w, int *h, int type)
struct monitor *mon, int *x, int *y, int *w, int *h, int type)
{
struct monitor *m = (fw && fw->m) ? fw->m : monitor_get_current();
struct monitor *m = (mon) ? mon : monitor_get_current();

EWMH_UpdateWorkArea(m);

Expand Down
2 changes: 1 addition & 1 deletion fvwm/ewmh.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void EWMH_SetClientList(struct monitor *);
void EWMH_SetClientListStacking(struct monitor *);
void EWMH_UpdateWorkArea(struct monitor *);
void EWMH_GetWorkAreaIntersection(
FvwmWindow *fw, int *x, int *y, int *w, int *h, int type);
struct monitor *mon, int *x, int *y, int *w, int *h, int type);
float EWMH_GetBaseStrutIntersection(struct monitor *m,
int x11, int y11, int x12, int y12, Bool use_percent);
float EWMH_GetStrutIntersection(struct monitor *m,
Expand Down
105 changes: 82 additions & 23 deletions fvwm/move_resize.c
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,6 @@ int GetMoveArguments(FvwmWindow *fw,
shuffle_win_to_closest(fw, &action, pFinal, fWarp);
*paction = action;
return 2;

}
if (s1 && StrEquals(s1, "screen"))
{
Expand All @@ -734,13 +733,6 @@ int GetMoveArguments(FvwmWindow *fw,
token = PeekToken(action, &action);
parg.name = token;

/* When being asked to move a window to coordinates which are
* relative to a given screen, don't assume to use the
* screen's working area, as the coordinates given are not
* relative to that.
*/
use_working_area = False;

FScreenGetScrRect(
&parg, FSCREEN_BY_NAME, &scr_pos.x, &scr_pos.y,
&scr_w, &scr_h);
Expand Down Expand Up @@ -785,17 +777,9 @@ int GetMoveArguments(FvwmWindow *fw,
}
}

if (use_working_area)
{
EWMH_GetWorkAreaIntersection(
NULL, &scr_pos.x, &scr_pos.y, &scr_w, &scr_h,
EWMH_USE_WORKING_AREA);
}

if (s1 != NULL && s2 != NULL)
{
int n;
retval = 0;
if (fKeep == True && StrEquals(s1, "keep"))
{
retval++;
Expand Down Expand Up @@ -837,26 +821,101 @@ int GetMoveArguments(FvwmWindow *fw,
/* make sure warping is off for interactive moves */
*fWarp = False;
}
else if (use_virt_x || use_virt_y)
else if (!use_working_area && (use_virt_x || use_virt_y))
{
/* Adjust position when using virtual screen. */
/* Adjust position when using virtual screen.
* If using working area, do nothing here, this
* will be done later.
*/
struct monitor *m = FindScreenOfXY(
pFinal->x, pFinal->y);
pFinal->x, pFinal->y);
pFinal->x -= (use_virt_x) ? m->virtual_scr.Vx : 0;
pFinal->y -= (use_virt_y) ? m->virtual_scr.Vy : 0;
}
}
else
{
/* not enough arguments, switch to current page. */
scr_w = monitor_get_all_widths();
scr_h = monitor_get_all_heights();
while (pFinal->x < 0)
{
pFinal->x = monitor_get_all_widths() + pFinal->x;
pFinal->x += scr_w;
}
while (pFinal->y < 0)
{
pFinal->y = monitor_get_all_heights() + pFinal->y;
pFinal->y += scr_h;
}
}

if (retval == 2 && use_working_area) {
/* Adjusts final position to fit inside the working area. */
struct monitor *m = FindScreenOfXY(pFinal->x, pFinal->y);
int x, y, dx = 0, dy = 0;

/* Reset screen size to global screen. */
scr_pos.x = scr_pos.y = 0;
scr_w = monitor_get_all_widths();
scr_h = monitor_get_all_heights();

/* Ensure the window is placed on a valid page. This requires
* first computing the coordinates relative to the virtual
* desktop, then moving the window onto the virtual desktop,
* then determine what monitor the window is mostly on, and
* adjusting its coordinates relative to that monitor.
*/
x = pFinal->x;
if (!use_virt_x)
x += m->virtual_scr.Vx;
y = pFinal->y;
if (!use_virt_y)
y += m->virtual_scr.Vy;
if (x < 0)
x = 0;
if (y < 0)
y = 0;
if (x + s.width > m->virtual_scr.VxMax + scr_w)
x = m->virtual_scr.VxMax + scr_w - s.width;
if (y + s.height > m->virtual_scr.VyMax + scr_h)
y = m->virtual_scr.VyMax + scr_h - s.height;
m = FindScreenOfXY(x + s.width / 2, y + s.height / 2);
pFinal->x = x - m->virtual_scr.Vx;
pFinal->y = y - m->virtual_scr.Vy;

/* Since the final position might not be on the current
* page, compute the adjustment needed as if it were on
* the current page. The midpoint is used to determine
* which page the window is mostly on.
*/
x = (pFinal->x + s.width / 2) % scr_w;
y = (pFinal->y + s.height / 2) % scr_h;
if (x < 0)
x += scr_w;
if (y < 0)
y += scr_h;
x -= s.width / 2;
y -= s.height / 2;

/* Move the window into the working area. */
EWMH_GetWorkAreaIntersection(
m, &scr_pos.x, &scr_pos.y, &scr_w, &scr_h,
EWMH_USE_WORKING_AREA);
if (x < scr_pos.x) {
dx = scr_pos.x - x;
} else if (x + s.width > scr_pos.x + scr_w) {
dx = scr_pos.x + scr_w - x - s.width;
if (x + dx < scr_pos.x)
dx = scr_pos.x - x;
}
if (y < scr_pos.y) {
dy = scr_pos.y - y;
} else if (y + s.height > scr_pos.y + scr_h) {
dy = scr_pos.y + scr_h - y - s.height;
if (y + dy < scr_pos.y)
dy = scr_pos.y - y;
}
pFinal->x += dx;
pFinal->y += dy;
}

if (s1)
Expand Down Expand Up @@ -4422,7 +4481,7 @@ static Bool _resize_window(F_CMD_ARGS)
FQueryPointer(
dpy, Scr.Root, &JunkRoot, &JunkChild, &x,
&y, &JunkX, &JunkY, &JunkMask);

fev_make_null_event(&e2, dpy);
e2.type = MotionNotify;
e2.xmotion.time = fev_get_evtime();
Expand Down Expand Up @@ -5235,7 +5294,7 @@ void CMD_Maximize(F_CMD_ARGS)
if (!ignore_working_area)
{
EWMH_GetWorkAreaIntersection(
fw, &scr.x, &scr.y, &scr.width, &scr.height,
fw->m, &scr.x, &scr.y, &scr.width, &scr.height,
EWMH_MAXIMIZE_MODE(fw));
}
#if 0
Expand Down
6 changes: 3 additions & 3 deletions fvwm/placement.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,8 +460,8 @@ static pl_penalty_t _pl_position_get_pos_simple(
* options.
*/
EWMH_GetWorkAreaIntersection(
arg->place_fw, (int *)&arg->screen_g.x, (int *)&arg->screen_g.y,
(int *)&arg->screen_g.width,
arg->place_fw->m, (int *)&arg->screen_g.x,
(int *)&arg->screen_g.y, (int *)&arg->screen_g.width,
(int *)&arg->screen_g.height, EWMH_USE_WORKING_AREA);

if (ret_p->x + arg->place_fw->g.frame.width > arg->screen_g.x
Expand Down Expand Up @@ -1812,7 +1812,7 @@ static int _place_window(
* for this placement policy.
*/
EWMH_GetWorkAreaIntersection(
fw, &screen_g.x, &screen_g.y, &screen_g.width,
fw->m, &screen_g.x, &screen_g.y, &screen_g.width,
&screen_g.height,
SEWMH_PLACEMENT_MODE(&pstyle->flags));
reason->screen.was_modified_by_ewmh_workingarea = 1;
Expand Down

0 comments on commit a5424e6

Please sign in to comment.