diff --git a/doc/fvwm3_manpage_source.adoc b/doc/fvwm3_manpage_source.adoc index 7bd8bc2a7..2aa42a421 100644 --- a/doc/fvwm3_manpage_source.adoc +++ b/doc/fvwm3_manpage_source.adoc @@ -4376,40 +4376,55 @@ CursorBarrier destroy + _CursorBarrier_ only works if fvwm is complied with the XFixes extension. -*CursorMove* _horizontal_[p] _vertical_[p]:: - Moves the mouse pointer by _horizontal_ pages in the X direction and - _vertical_ pages in the Y direction. Either or both entries may be - negative. CursorMove can only move the mouse cursor to a relative - position. To move the mouse cursor to an absolute position, see - *WarpToWindow*. Both horizontal and vertical values are expressed in - percent of pages, so +*CursorMove* [screen _RANDRNAME_] _horizontal_[p] _vertical_[p]:: + Without the _screen_ option, _CusorMove_ moves the mouse cursor a + _horizontal_ distance and _vertical_ distance from its current position. + The values are expressed as either a percent of the virtual desktop size, + or a pixel distance by appending a '_p_' to the value. Either or both + entries may be negative. For example, + .... +# Move down and right by one full page. CursorMove 100 100 -.... -+ -means to move down and right by one full page. -+ +# Move down two full pages. +CursorMove 0 200 -.... -CursorMove 50 25 +# Move half page right and quarter page up. +CursorMove 50 -25 + +# Move left 100 pixels and down 50 pixels. +CursorMove -100p 50p .... + -means to move right half a page and down a quarter of a page. -Alternatively, the distance can be specified in pixels by appending a -'_p_' to the horizontal and/or vertical specification. For example +If the option _screen_ followed by a valid RandR monitor name is included, +_CursorMove_ will move the cursor to the absolute position (starting at +the top left corner) given by the arguments, as either percent values +of the monitor's size, or an absolute location with the '_p_' suffix. +For example, + .... -CursorMove -10p -10p +# Move cursor to center of monitor DP-1 +CursorMove screen DP-1 50 50 + +# Move cursor to the exact location (400, 200) of monitor DP-2 +CursorMove screen DP-2 400p 200p .... + -means move ten pixels up and ten pixels left. The CursorMove function -should not be called from pop-up menus. +When moving to a specified _screen_, the _horizontal_ and _vertical_ +values are always shifted to be inside the current page of the specified +monitor. For instance '50', '150', and '-150' will all be the center of the +monitor, and will not change monitor's page. Use *GotoPage* to change the +page of a specified monitor. Negative values can be used to specify distance +from the right/bottom corner of the monitor. ++ +_CusorMove_ can only move the cursor relative to its current position, +or to an absolute position on a given monitor. To move the cursor relative +to a window, use *WarpToWindow*. *FlipFocus* [NoWarp]:: Executes a *Focus* command as if the user had used the pointer to diff --git a/fvwm/builtins.c b/fvwm/builtins.c index 1e87d64da..2c1d782d5 100644 --- a/fvwm/builtins.c +++ b/fvwm/builtins.c @@ -2237,110 +2237,6 @@ void CMD_EscapeFunc(F_CMD_ARGS) return; } -void CMD_CursorMove(F_CMD_ARGS) -{ - int x = 0, y = 0; - int val1, val2, val1_unit, val2_unit; - int x_unit, y_unit; - int virtual_x, virtual_y; - int x_pages, y_pages; - struct monitor *m = NULL; - - if (GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit) != 2) - { - fvwm_debug(__func__, "CursorMove needs 2 arguments"); - return; - } - FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild, - &x, &y, &JunkX, &JunkY, &JunkMask); - - m = monitor_get_current(); - - x_unit = val1 * val1_unit / 100; - y_unit = val2 * val2_unit / 100; - - x += x_unit; - y += y_unit; - - virtual_x = m->virtual_scr.Vx; - virtual_y = m->virtual_scr.Vy; - if (x >= 0) - { - x_pages = x / monitor_get_all_widths(); - } - else - { - x_pages = ((x + 1) / monitor_get_all_widths()) - 1; - } - virtual_x += x_pages * monitor_get_all_widths(); - x -= x_pages * monitor_get_all_widths(); - if (virtual_x < 0) - { - x += virtual_x; - virtual_x = 0; - } - else if (virtual_x > m->virtual_scr.VxMax) - { - x += virtual_x - m->virtual_scr.VxMax; - virtual_x = m->virtual_scr.VxMax; - } - - if (y >= 0) - { - y_pages = y / monitor_get_all_heights(); - } - else - { - y_pages = ((y + 1) / monitor_get_all_heights()) - 1; - } - virtual_y += y_pages * monitor_get_all_heights(); - y -= y_pages * monitor_get_all_heights(); - - if (virtual_y < 0) - { - y += virtual_y; - virtual_y = 0; - } - else if (virtual_y > m->virtual_scr.VyMax) - { - y += virtual_y - m->virtual_scr.VyMax; - virtual_y = m->virtual_scr.VyMax; - } - - /* TA: (2010/12/19): Only move to the new page if scrolling is - * enabled and the viewport is able to change based on where the - * pointer is. - */ - if ((virtual_x != m->virtual_scr.Vx && m->virtual_scr.EdgeScrollX != 0) || - (virtual_y != m->virtual_scr.Vy && m->virtual_scr.EdgeScrollY != 0)) - { - MoveViewport(m, virtual_x, virtual_y, True); - } - - /* TA: (2010/12/19): If the cursor is about to enter a pan-window, or - * is one, or the cursor's next step is to go beyond the page - * boundary, stop the cursor from moving in that direction, *if* we've - * disallowed edge scrolling. - * - * Whilst this stops the cursor short of the edge of the screen in a - * given direction, this is the desired behaviour. - */ - if (m->virtual_scr.EdgeScrollX == 0 && (x >= monitor_get_all_widths() || - x + x_unit >= monitor_get_all_widths())) - return; - - if (m->virtual_scr.EdgeScrollY == 0 && (y >= monitor_get_all_heights() || - y + y_unit >= monitor_get_all_heights())) - return; - - FWarpPointerUpdateEvpos( - exc->x.elast, dpy, None, Scr.Root, 0, 0, - monitor_get_all_widths(), - monitor_get_all_heights(), x, y); - - return; -} - void CMD_Delete(F_CMD_ARGS) { FvwmWindow * const fw = exc->w.fw; diff --git a/fvwm/cursor.c b/fvwm/cursor.c index 4f70c2b86..74062761c 100644 --- a/fvwm/cursor.c +++ b/fvwm/cursor.c @@ -35,6 +35,7 @@ #include "bindings.h" #include "misc.h" #include "screen.h" +#include "virtual.h" #include "cursor.h" #include "menus.h" @@ -171,6 +172,111 @@ static void SafeDefineCursor(Window w, Cursor cursor) return; } +static int cursor_move_relative(int x_unit, int y_unit, int *x, int *y) +{ + int virtual_x, virtual_y; + int x_pages, y_pages; + int width = monitor_get_all_widths(); + int height = monitor_get_all_heights(); + struct monitor *m = monitor_get_current(); + + FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild, + x, y, &JunkX, &JunkY, &JunkMask); + + *x += x_unit; + *y += y_unit; + + virtual_x = m->virtual_scr.Vx; + virtual_y = m->virtual_scr.Vy; + if (*x >= 0) + { + x_pages = *x / width; + } + else + { + x_pages = ((*x + 1) / width) - 1; + } + virtual_x += x_pages * width; + *x -= x_pages * width; + if (virtual_x < 0) + { + *x += virtual_x; + virtual_x = 0; + } + else if (virtual_x > m->virtual_scr.VxMax) + { + *x += virtual_x - m->virtual_scr.VxMax; + virtual_x = m->virtual_scr.VxMax; + } + + if (*y >= 0) + { + y_pages = *y / height; + } + else + { + y_pages = ((*y + 1) / height) - 1; + } + virtual_y += y_pages * height; + *y -= y_pages * height; + + if (virtual_y < 0) + { + *y += virtual_y; + virtual_y = 0; + } + else if (virtual_y > m->virtual_scr.VyMax) + { + *y += virtual_y - m->virtual_scr.VyMax; + virtual_y = m->virtual_scr.VyMax; + } + + /* TA: (2010/12/19): Only move to the new page if scrolling is + * enabled and the viewport is able to change based on where the + * pointer is. + */ + if ((virtual_x != m->virtual_scr.Vx && m->virtual_scr.EdgeScrollX != 0) || + (virtual_y != m->virtual_scr.Vy && m->virtual_scr.EdgeScrollY != 0)) + { + MoveViewport(m, virtual_x, virtual_y, True); + } + + /* TA: (2010/12/19): If the cursor is about to enter a pan-window, or + * is one, or the cursor's next step is to go beyond the page + * boundary, stop the cursor from moving in that direction, *if* we've + * disallowed edge scrolling. + * + * Whilst this stops the cursor short of the edge of the screen in a + * given direction, this is the desired behaviour. + */ + if (m->virtual_scr.EdgeScrollX == 0 && + (*x >= width || *x + x_unit >= width)) + return 0; + + if (m->virtual_scr.EdgeScrollY == 0 && + (*y >= height || *y + y_unit >= height)) + return 0; + + return 1; +} + +static void cursor_move_screen(struct monitor *m, int x_unit, int y_unit, + int *x, int *y) +{ + *x = x_unit % m->si->w; + *y = y_unit % m->si->h; + + if (*x < 0) + *x += m->si->w; + if (*y < 0) + *y += m->si->h; + + *x += m->si->x; + *y += m->si->y; + + return; +} + /* ---------------------------- interface functions ------------------------ */ /* CreateCursors - Loads fvwm cursors */ @@ -189,6 +295,53 @@ Cursor *CreateCursors(Display *disp) /* ---------------------------- builtin commands --------------------------- */ +void CMD_CursorMove(F_CMD_ARGS) +{ + int x, y; + int val1, val2; + int val1_unit = monitor_get_all_widths(); + int val2_unit = monitor_get_all_heights(); + struct monitor *m = NULL; + char *option; + + /* Check if screen option is provided. */ + if ((option = PeekToken(action, NULL)) != NULL && + StrEquals(option, "screen")) + { + option = PeekToken(action, &action); /* Skip literal screen. */ + option = PeekToken(action, &action); + if ((m = monitor_resolve_name(option)) == NULL) { + fvwm_debug(__func__, "Invalid screen: %s", option); + return; + } + val1_unit = m->si->w; + val2_unit = m->si->h; + } + + if (GetTwoPercentArguments( + action, &val1, &val2, &val1_unit, &val2_unit) != 2) + { + fvwm_debug(__func__, "CursorMove needs 2 arguments"); + return; + } + + val1 *= val1_unit / 100; + val2 *= val2_unit / 100; + + if (m == NULL) { + if (cursor_move_relative(val1, val2, &x, &y) == 0) + return; + } else { + cursor_move_screen(m, val1, val2, &x, &y); + } + + FWarpPointerUpdateEvpos( + exc->x.elast, dpy, None, Scr.Root, 0, 0, + monitor_get_all_widths(), monitor_get_all_heights(), x, y); + + return; +} + void CMD_CursorStyle(F_CMD_ARGS) { char *cname=NULL;