Pointer warping on wayland

Hi There,

my application Horizon EDA uses pointer warping similar to blender to get infinite panning: https://paste.selfnet.de/index.php/xPCIh/ Here’s the code: horizon/warp_cursor.cpp at next · horizon-eda/horizon · GitHub

What’s the least hacky way to get something similar happening on wayland since there’s no easy way to just move the cursor to another position?

Yes, pointer warping is somewhat of an anti-feature, but in this particular case, it enables infinite panning which is really convenient to use with unconstrained input devices such as trackballs.


This is handled by the pointer-constraints extension.

For infinite scroll, as mentioned already, you can use the pointer constraints extension. If you to use a pointer cursor moving around and jumping from side to side as a frame of reference, you create a pointer sprite subsurface and move it around freely. It has the added bonus of eliminating the lag that otherwise can be visible when dragging the view around. When the pointer lock is done, you can provide a hint of where the actual pointer should move to upon release.

I also came across this, but couldn’t quite figure out how to integrate it into my application. Let’s say I locked the pointer using Pointer constraints protocol | Wayland Explorer, do I still receive events via Gdk, or do I now need to get the events from wayland myself?

you create a pointer sprite subsurface

That’s exactly the kind of complexity I tried to avoid.

No, you have to use relative-pointer to get the relative events yourself.

It’s not really possible to avoid it, without introducing some issues with rendering lag or safety issues (gdk_device_warp on X11 has both).

I just remembered something, the use of a subsurface is only necessary if you want to have the pointer still draw outside of the bounds of the window. For a “panning canvas” type GUI, I think it may be better to hide the cursor and then draw your own inside the canvas while the pointer lock is held. To make it have the appearance of wrapping around the edges you may want to draw the pointer up to four times using an algorithm like this pseudocode:

real_x = mod_euclidean(cursor_x - hotspot_x, widget_width)
real_y = mod_euclidean(cursor_y - hotspot_y, widget_height)
is_wrapping_x = real_x + cursor_width >= widget_width
is_wrapping_y = real_y + cursor_height >= widget_height

draw_cursor(real_x, real_y)
if is_wrapping_x:
	draw_cursor(real_x - widget_width, real_y)
if is_wrapping_y:
	draw_cursor(real_x, real_y - widget_height)
if is_wrapping_x && is_wrapping_y:
	draw_cursor(real_x - widget_width, real_y - widget_height)

Then you can have it clipped to the edges of the canvas to really make it clear the cursor has been “captured” by the widget.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.