diff --git a/doc/fvwm3_manpage_source.adoc b/doc/fvwm3_manpage_source.adoc index 65ace03de..43ee3631b 100644 --- a/doc/fvwm3_manpage_source.adoc +++ b/doc/fvwm3_manpage_source.adoc @@ -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 @@ -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_. diff --git a/fvwm/ewmh.c b/fvwm/ewmh.c index 10ddd5d84..4b7e20d57 100644 --- a/fvwm/ewmh.c +++ b/fvwm/ewmh.c @@ -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); diff --git a/fvwm/ewmh.h b/fvwm/ewmh.h index b8b20494e..68fe5903b 100644 --- a/fvwm/ewmh.h +++ b/fvwm/ewmh.h @@ -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, diff --git a/fvwm/move_resize.c b/fvwm/move_resize.c index 3bc083191..8fa776903 100644 --- a/fvwm/move_resize.c +++ b/fvwm/move_resize.c @@ -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")) { @@ -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); @@ -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++; @@ -837,9 +821,12 @@ 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 -= (use_virt_x) ? m->virtual_scr.Vx : 0; @@ -849,14 +836,86 @@ int GetMoveArguments(FvwmWindow *fw, 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) @@ -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(); @@ -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 diff --git a/fvwm/placement.c b/fvwm/placement.c index a664ab38e..4e845aa94 100644 --- a/fvwm/placement.c +++ b/fvwm/placement.c @@ -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 @@ -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;