I have a problem. My work was throwing out a pile of monitors so I took a few home. Unfortunately, they're much nicer than my existing monitors! Woe is me, I know.
The reason this is a problem is because the new monitors are 4K, and most of my current ones are 1080p. Most(all?) major operating systems (Linux and the other ones) consider the virtual size of the monitor to be directly proportional to its pixel count. For example, this is what my laptop workstation setup currently looks like:
On the left I have a 1080p monitor, rotated vertically. On top I have a 4K display from work, and on the bottom is my 1080p laptop display. Here's how these displays look virtually:
It doesn't line up with physical reality at all! The top display is, virtually, much too big, and as a result the left screen doesn't reach up high enough. If I move my cursor into the top half of the left edge of the top display, it just gets stuck. What I would like is for it to move to the same spot (in physical reality) on the left display.
This is also a problem between my top and bottom displays, since their resolutions don't match. I could center the bottom display, which might make the map between the top/bottom screen a bit more sane, but then I wouldn't be able to move the cursor between the bottom display and the left display at all!
Really, what I want is this:
The pink sections are what I'm calling cursor wormholes, and the green lines are the mouths of these wormholes. When the cursor collides with a mouth, it should be seamlessly teleported to the opposite mouth. The position on the new mouth should correspond to where the mouse collided with the old mouth.
And so, I built a very simple proof of concept! I threw it together in about half a day, so it's pretty janky. The way it works is by polling the mouse cursor 1000 times per second, and when crossing a mouth, moving the cursor to where you expect. The wormholes are defined as follows (this is the actual config for the setup pictured above):
[[vertical_wormhole]] mouth1.x1 = 1080 mouth1.x2 = 2999 # 1080 + 1919 mouth1.y = 2160 mouth2.x1 = 1080 mouth2.x2 = 4919 # 1080 + 3839 mouth2.y = 2159 [[horizontal_wormhole]] mouth1.y1 = 1320 mouth1.y2 = 2646 mouth1.x = 1079 mouth2.y1 = 0 mouth2.y2 = 2160 mouth2.x = 1080 [[horizontal_wormhole]] mouth1.y1 = 2647 mouth1.y2 = 3239 mouth1.x = 1079 mouth2.y1 = 2161 mouth2.y2 = 3239 mouth2.x = 1080
As a PoC, it works decently well. I can move my cursor between monitors in an intuitive way, which is pretty satisfying.
Shortcomings
My PoC definitely needs some work before I'd recommend using it as a daily driver. For one, the polling mechanism is pretty inefficient. Between the mouse-wormhole
process and the increased load on X, it sucks down about 10% of my CPU when I move the mouse rapidly. This is really something I'd want to hack into X/Wayland directly, as part of its mouse handling routine (wherever that lives). The amount of actual work we're doing is so low that it shouldn't affect CPU usage in any meaningful way.
Aside from performance, polling also makes the mouse a bit "jumpy". For instance, after the wormhole code runs and updates the mouse position, the display still needs to refresh. This means sometimes you see one frame of where the mouse would be if the program wasn't running, which can be a bit distracting.
Also, because we're only updating the mouse position, if you put the cursor right at the border of two monitors (such that it's rendered on both), the two halves won't line up as you expect - they don't respect the wormholes.
One other badly-needed feature is the ability to associate wormhole configs with monitor setups, such that e.g. plugging in a monitor automatically loads the relevant wormhole config. Without this, it requires the user to manually retweak/change their config and restart the program.
Finally, there needs to be some kind of GUI way to create wormholes. Since I'm on X, I'd want it to be a part of arandr, and I imagine Wayland has something similar. Creating wormholes by manually tweaking a config file is tedious and error-prone, and if I rearrange things I'll need to redo it.
Final Thoughts
I think I am most surprised that what I've built isn't something that most systems already have. It's not that hard to implement, and presumably it must be a common problem. I've run into it myself before, such as when I first started migrating to 1080p displays (and mixed them with various 720p or 4:3 displays). I think I would eventually like to see something like this supported first-class in... something... rather than being an add-on daemon.