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 7044bc319..8fa776903 100644 --- a/fvwm/move_resize.c +++ b/fvwm/move_resize.c @@ -285,6 +285,7 @@ static void move_to_next_monitor( position page; struct monitor *m; int x1, x2, y1, y2; /* Working area bounds */ + int left = 0, right = 0, top = 0, bottom = 0; int check_vert = 0, check_hor = 0; get_page_offset_check_visible(&page.x, &page.y, fw); @@ -296,53 +297,49 @@ static void move_to_next_monitor( if (fw->m == m) continue; + if (ewmh) { + EWMH_UpdateWorkArea(m); + left = m->Desktops->ewmh_working_area.x; + right = m->si->w - left - + m->Desktops->ewmh_working_area.width; + top = m->Desktops->ewmh_working_area.y; + bottom = m->si->h - top - + m->Desktops->ewmh_working_area.height; + } + if (dir == DIR_N && m->si->y + m->si->h == fw->m->si->y && win_r->x < m->si->x + m->si->w && win_r->x + win_r->width > m->si->x) { check_hor = 1; - win_r->y = m->si->y + m->si->h - win_r->height; - if (ewmh) - win_r->y -= m->ewmhc.BaseStrut.bottom; + win_r->y = m->si->y + m->si->h - win_r->height - bottom; } else if (dir == DIR_E && m->si->x == fw->m->si->x + fw->m->si->w && win_r->y < m->si->y + m->si->h && win_r->y + win_r->height > m->si->y) { check_vert = 1; - win_r->x = m->si->x; - if (ewmh) - win_r->x += m->ewmhc.BaseStrut.left; + win_r->x = m->si->x + left; } else if (dir == DIR_S && m->si->y == fw->m->si->y + fw->m->si->h && win_r->x < m->si->x + m->si->w && win_r->x + win_r->width > m->si->x) { check_hor = 1; - win_r->y = m->si->y; - if (ewmh) - win_r->y += m->ewmhc.BaseStrut.top; + win_r->y = m->si->y + top; } else if (dir == DIR_W && m->si->x + m->si->w == fw->m->si->x && win_r->y < m->si->y + m->si->h && win_r->y + win_r->height > m->si->y) { check_vert = 1; - win_r->x = m->si->x + m->si->w - win_r->width; - if (ewmh) - win_r->x -= m->ewmhc.BaseStrut.right; + win_r->x = m->si->x + m->si->w - win_r->width - right; } if (check_hor || check_vert) { - x1 = m->si->x; - y1 = m->si->y; - x2 = x1 + m->si->w; - y2 = y1 + m->si->h; - if (ewmh) { - x1 += m->ewmhc.BaseStrut.left; - y1 += m->ewmhc.BaseStrut.top; - x2 -= m->ewmhc.BaseStrut.right; - y2 -= m->ewmhc.BaseStrut.bottom; - } + x1 = m->si->x + left; + y1 = m->si->y + top; + x2 = x1 + m->si->w - right; + y2 = y1 + m->si->h - bottom; break; } } @@ -425,12 +422,11 @@ static void shuffle_win_to_closest( wa.height = fw->m->si->h; if (ewmh) { - wa.x += fw->m->ewmhc.BaseStrut.left; - wa.y += fw->m->ewmhc.BaseStrut.top; - wa.width -= fw->m->ewmhc.BaseStrut.left; - wa.width -= fw->m->ewmhc.BaseStrut.right; - wa.height -= fw->m->ewmhc.BaseStrut.top; - wa.height -= fw->m->ewmhc.BaseStrut.bottom; + EWMH_UpdateWorkArea(fw->m); + wa.x += fw->m->Desktops->ewmh_working_area.x; + wa.y += fw->m->Desktops->ewmh_working_area.y; + wa.width = fw->m->Desktops->ewmh_working_area.width; + wa.height = fw->m->Desktops->ewmh_working_area.height; } /* Get direction(s) */ @@ -727,7 +723,6 @@ int GetMoveArguments(FvwmWindow *fw, shuffle_win_to_closest(fw, &action, pFinal, fWarp); *paction = action; return 2; - } if (s1 && StrEquals(s1, "screen")) { @@ -738,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); @@ -789,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++; @@ -841,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; @@ -853,16 +836,88 @@ 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) { free(s1); @@ -4426,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(); @@ -5239,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;