diff --git a/doc/fvwm3/fvwm3.adoc b/doc/fvwm3/fvwm3.adoc index 13826fd08..3712af901 100644 --- a/doc/fvwm3/fvwm3.adoc +++ b/doc/fvwm3/fvwm3.adoc @@ -4052,27 +4052,22 @@ AddToFunc lower-to-bottom + I Lower .... -*Move* [[screen _screen_] [w | m]_x_[p | w] ... [w | m]_y_[p | w] ... [Warp]] | [pointer] | [ewmhiwa]:: - Allows the user to move a window. If called from somewhere in a window - or its border, then that window is moved. If called from the root - window then the user is allowed to select the target window. By - default, the EWMH working area is honoured. -+ -If the literal option _screen_ followed by a _screen_ argument is -specified, the coordinates are interpreted as relative to the given -screen. The width and height of the screen are used for the -calculations instead of the display dimensions. The _screen_ as -interpreted as in the *MoveToScreen* command. If the optional argument -_Warp_ is specified the pointer is warped with the window. If the -single argument _pointer_ is given, the top left corner of the window -is moved to the pointer position before starting the operation; this -is mainly intended for internal use by modules like *FvwmPager*. If -the optional argument _ewmhiwa_ is given, then the window position -will ignore the working area (such as ignoring any values set via -*EwmhBaseStruts*). -+ -The operation can be aborted with -+ +*Move* [_options_]:: + Allows the user to move a window. If called from somewhere in a + window or its border, then that window is moved. If called from + the root window, then the user is allowed to select the target + window. Move can be called with various options to either start + an interactive move, specify the position to move, or a direction. ++ +Calling *Move* by itself with no options starts an interactive move. +When moving a window interactively, the window may snap to other windows +and screen boundaries, configurable via the *SnapAttraction* style. Holding +down _Alt_ whilst moving the window will disable snap attraction during +the move. Moving a window to the edge of the screen can be used to drag the +window to other pages, see *EdgeScroll*, and the *EdgeMoveDelay* style +for more information. ++ +The interactive move operation can be aborted with Escape or any mouse button not set to place the window. By default mouse button 2 is set to cancel the move operation. To change this you may use the *Mouse* command with special context 'P' for Placement. @@ -4081,18 +4076,75 @@ The window condition _PlacedByButton_ can be used to check if a specific button was pressed to place the window (see *Current* command). + -If the optional arguments _x_ and _y_ are provided, then the window is -moved immediately without user interaction. Each argument 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 precent 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 leave either coordinate unchanged, "_keep_" can be -specified in place of _x_ or _y_. +If the single argument _pointer_ is given, the top left corner of the +window is moved to the pointer position before starting an interactive +move; this is mainly intended for internal use by modules like *FvwmPager*. ++ + +> *Move* pointer + ++ +To move a window in a given direction until it hits another window, icon, +or screen boundary use: ++ + +> *Move* shuffle [Warp] [snap _type_] [layers _min_ _max_] _direction_(s) + ++ +The _direction_ can be _North_/_N_/_Up_/_U_, _East_/_E_/_Right_/_R_, +_South_/_S_/_Down_/_D_, or _West_/_W_/_Left_/_L_. The window will move +in the given direction until it hits another window, the *EwmhBaseStruts*, +or the screen boundary. If multiple _direction_(s) are given, the window +will move the directions in the order of the sequence stated. ++ +The literal option _Warp_ will warp the mouse pointer to the window. +If the literal option _snap_ followed by a snap _type_ of _windows_, +_icons_, or _same_ is given, then the window will only stop if it hits +another window, icon, or the same type. If the literal option _layers_ +followed by a _min_ layer and _max_ layer is given, then only windows on +the layers between _min_ and _max_ layers will stop the window. For example: ++ + +.... +# Shuffle the window Right. +Move shuffle Right +# Shuffle Up, only consider windows on Layer 3. +Move shuffle layers 3 3 Up +# Shuffle Left then Up +Move shuffle Left Up +# Shuffle Up then Left (may not be same position as above) +Move shuffle Up Left +.... + ++ +*Move* can be used to moved a window to a specified position: ++ + +> *Move* [screen _S_] \[w | m]_x_[p | w] \[w | m]_y_[p | w] [Warp] [ewmhiwa] + ++ +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. ++ +If the literal option _screen_ followed by a RandR screen name _S_ is +specified, the coordinates are interpreted as relative to the given +screen. The width and height of the screen are used for the +calculations instead of the display dimensions. The _screen_ is +interpreted as in the *MoveToScreen* command. ++ +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 +leave either coordinate unchanged, "_keep_" can be specified in place of +_x_ or _y_. + For advanced uses, the arguments _x_ and _y_ can be used multiple times, but without the prefix '_m_' or '_w_'. (See complex examples @@ -4136,16 +4188,13 @@ Move 40p w-10p Move m+0 m+0 # Move window to center of screen (50% of screen -# poition minus 50% of widow size). +# position minus 50% of widow size). Move 50-50w 50-50w .... -+ -Note: In order to obtain moving windows which do not snap to screen, -with interactive move, hold down _Alt_ whilst moving the window to -disable snap attraction if it's defined. + See also the *AnimatedMove* command. ++ *MoveToDesk* [prev | _arg1_ [_arg2_] [_min_ _max_]]:: Moves the selected window to another desktop. The arguments are the diff --git a/fvwm/geometry.c b/fvwm/geometry.c index df88e1d9b..acbc61010 100644 --- a/fvwm/geometry.c +++ b/fvwm/geometry.c @@ -1408,10 +1408,10 @@ void get_page_offset_check_visible( { get_page_offset(ret_page_x, ret_page_y, fw); } - +#if 0 fprintf(stderr, "%s: MON: %s {page_x: %d, page_y: %d}\n", __func__, fw->m->si->name, *ret_page_x, *ret_page_y); - +#endif return; } diff --git a/fvwm/move_resize.c b/fvwm/move_resize.c index 53fe40684..fdf741d3f 100644 --- a/fvwm/move_resize.c +++ b/fvwm/move_resize.c @@ -291,6 +291,204 @@ static int ParsePositionArgumentSuffix( return n; } +/* Functions to shuffle windows to the closest boundary. */ +static void grow_bound_to_next_monitor( + FvwmWindow *fw, rectangle *bound, rectangle win_r, direction_t dir) +{ + int page_x, page_y; + struct monitor *m; + + get_page_offset_check_visible(&page_x, &page_y, fw); + bound->x -= page_x; + bound->y -= page_y; + win_r.x -= page_x; + win_r.y -= page_y; + + TAILQ_FOREACH(m, &monitor_q, entry) + { + if (fw->m == m) + continue; + + 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) + { + bound->y = m->si->y + m->ewmhc.BaseStrut.top; + bound->height = win_r.y + win_r.height - bound->y; + } + 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) + { + bound->width = m->si->x + m->si->w - bound->x - + m->ewmhc.BaseStrut.right; + } + 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) + { + bound->height = m->si->y + m->si->h - bound->y - + m->ewmhc.BaseStrut.bottom; + } + 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) + { + bound->x = m->si->x + m->ewmhc.BaseStrut.left; + bound->width = win_r.x + win_r.width - bound->x; + } + } + bound->x += page_x; + bound->y += page_y; +} +static void shuffle_win_to_closest( + FvwmWindow *fw, char **action, int *pFinalX, int *pFinalY, Bool *fWarp) +{ + direction_t dir; + rectangle cwin, bound; + char *naction, *token = NULL; + int page_x, page_y, n; + int snap = SNAP_NONE; + int layers[2] = { -1, -1 }; + + cwin = fw->g.frame; + get_page_offset_check_visible(&page_x, &page_y, fw); + + token = PeekToken(*action, &naction); + /* Get flags */ + while (token) + { + if (StrEquals(token, "snap")) + { + *action = naction; + token = PeekToken(*action, &naction); + if (StrEquals(token, "windows")) + snap = SNAP_WINDOWS; + else if (StrEquals(token, "icons")) + snap = SNAP_ICONS; + else if (StrEquals(token, "same")) + snap = SNAP_SAME; + } + else if (StrEquals(token, "layers")) + { + *action = naction; + n = GetIntegerArguments(*action, &naction, layers, 2); + if (n != 2) + { + layers[0] = -1; + layers[1] = -1; + } + } + else if (StrEquals(token, "Warp") && fWarp != NULL) + { + *fWarp = true; + } + else + { + break; + } + *action = naction; + token = PeekToken(*action, &naction); + + } + + /* Get direction(s) */ + while (token) + { + dir = gravity_parse_dir_argument( + *action, &naction, DIR_NONE); + + switch (dir) + { + case DIR_N: + bound.x = cwin.x; + bound.y = fw->m->si->y + page_y; + if (cwin.y - bound.y > fw->m->ewmhc.BaseStrut.top) + bound.y += fw->m->ewmhc.BaseStrut.top; + bound.width = cwin.width; + bound.height = cwin.y + cwin.height - bound.y; + if (cwin.y <= bound.y) + { + grow_bound_to_next_monitor( + fw, &bound, cwin, DIR_N); + } + grow_to_closest_type(fw, &cwin, bound, layers, + snap, false); + cwin.height = fw->g.frame.height; + break; + case DIR_E: + bound.x = cwin.x; + bound.y = cwin.y; + bound.width = fw->m->si->x + fw->m->si->w - + bound.x + page_x; + if (bound.x + bound.width - cwin.x - cwin.width > + fw->m->ewmhc.BaseStrut.right) + { + bound.width -= fw->m->ewmhc.BaseStrut.right; + } + bound.height = cwin.height; + if (cwin.x + cwin.width >= bound.x + bound.width) + { + grow_bound_to_next_monitor( + fw, &bound, cwin, DIR_E); + } + grow_to_closest_type(fw, &cwin, bound, layers, + snap, false); + cwin.x = cwin.x + cwin.width - fw->g.frame.width; + cwin.width = fw->g.frame.width; + break; + case DIR_S: + bound.x = cwin.x; + bound.y = cwin.y; + bound.width = cwin.width; + bound.height = fw->m->si->y + fw->m->si->h - + bound.y + page_y; + if (bound.y + bound.height - cwin.y - cwin.height > + fw->m->ewmhc.BaseStrut.bottom) + { + bound.height -= fw->m->ewmhc.BaseStrut.bottom; + } + if (cwin.y + cwin.height >= bound.y + bound.height) + { + grow_bound_to_next_monitor( + fw, &bound, cwin, DIR_S); + } + grow_to_closest_type(fw, &cwin, bound, layers, + snap, false); + cwin.y = cwin.y + cwin.height - fw->g.frame.height; + cwin.height = fw->g.frame.height; + break; + case DIR_W: + bound.x = fw->m->si->x + page_x; + if (cwin.x - bound.x > fw->m->ewmhc.BaseStrut.left) + bound.x += fw->m->ewmhc.BaseStrut.left; + bound.y = cwin.y; + bound.width = cwin.y + cwin.width - bound.x; + bound.height = cwin.height; + bound.height = cwin.y + cwin.height - bound.y; + if (cwin.x <= bound.x) + { + grow_bound_to_next_monitor( + fw, &bound, cwin, DIR_W); + } + grow_to_closest_type(fw, &cwin, bound, layers, + snap, false); + cwin.width = fw->g.frame.width; + break; + case DIR_NONE: + /* No direction found, need to move to next token */ + token = PeekToken(*action, &naction); + break; + default: + break; + } + *action = naction; + token = PeekToken(*action, &naction); + } + *pFinalX = cwin.x; + *pFinalY = cwin.y; +} + static int __get_shift(int val, float factor) { int shift; @@ -460,6 +658,14 @@ int GetMoveArguments(FvwmWindow *fw, free(s1); return 0; } + if (s1 && StrEquals(s1, "shuffle")) + { + free(s1); + shuffle_win_to_closest(fw, &action, pFinalX, pFinalY, fWarp); + *paction = action; + return 2; + + } if (s1 && StrEquals(s1, "screen")) { fscreen_scr_arg parg;