Skip to content

Commit

Permalink
Add screen option to CursorMove.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
somiaj committed Nov 23, 2024
1 parent d935452 commit cf1a154
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 123 deletions.
53 changes: 34 additions & 19 deletions doc/fvwm3_manpage_source.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
104 changes: 0 additions & 104 deletions fvwm/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
153 changes: 153 additions & 0 deletions fvwm/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "bindings.h"
#include "misc.h"
#include "screen.h"
#include "virtual.h"
#include "cursor.h"
#include "menus.h"

Expand Down Expand Up @@ -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 */
Expand All @@ -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;
Expand Down

0 comments on commit cf1a154

Please sign in to comment.