From f3b479b83aa5cbc59be9605e93b335de5657ad5e Mon Sep 17 00:00:00 2001 From: Jaimos Skriletz Date: Sat, 23 Nov 2024 11:17:12 -0700 Subject: [PATCH] Add screen option to CursorMove. First, move CMD_CursorMove form builtins to cursor (as this seems to be more appropriate location for it). Then add a screen RANDRNAME option to CursorMove, which will move the cursor to a specified position on a given monitor. This is done by splitting the actual movement computation to helper functions for each case of having a screen or not. --- doc/fvwm3_manpage_source.adoc | 53 +++++++----- fvwm/builtins.c | 104 ----------------------- fvwm/cursor.c | 154 ++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 123 deletions(-) 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..00d6513d7 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,119 @@ static void SafeDefineCursor(Window w, Cursor cursor) return; } +static void cursor_move_relative(int x_unit, int y_unit, + const exec_context_t *exc) +{ + int x = 0, y = 0; + 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; + + if (m->virtual_scr.EdgeScrollY == 0 && + (y >= height || y + y_unit >= height)) + return; + + FWarpPointerUpdateEvpos( + exc->x.elast, dpy, None, Scr.Root, 0, 0, + width, height, x, y); + + return; +} + +static void cursor_move_screen(struct monitor *m, int x_unit, int y_unit, + const exec_context_t *exc) +{ + int x = x_unit % m->si->w; + int y = y_unit % m->si->h; + + if (x < 0) + x += m->si->w; + if (y < 0) + y += m->si->h; + + FWarpPointerUpdateEvpos( + exc->x.elast, dpy, None, Scr.Root, 0, 0, + monitor_get_all_widths(), monitor_get_all_heights(), + x + m->si->x, y + m->si->y); + + return; +} + /* ---------------------------- interface functions ------------------------ */ /* CreateCursors - Loads fvwm cursors */ @@ -189,6 +303,46 @@ Cursor *CreateCursors(Display *disp) /* ---------------------------- builtin commands --------------------------- */ +void CMD_CursorMove(F_CMD_ARGS) +{ + 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) + cursor_move_relative(val1, val2, exc); + else + cursor_move_screen(m, val1, val2, exc); + + return; +} + void CMD_CursorStyle(F_CMD_ARGS) { char *cname=NULL;