Wayland Pointers
Pointers (aka mice) are one of those things that seem like they should be super straightforward. Turns out, there's quite a lot of complexity behind them, especially related to scrolling. In this devlog, we explore and discuss the different challenges, and implement the basics for pointers to work in Breezy.
Displaying Cursors
There are two parts to displaying a cursor on the screen:
- Loading a cursor image into a buffer
- Rendering that buffer onto the display
The first piece can be accomplished using libXcursor and the icons located on your filesystem at /usr/share/icons/<theme>/cursors/<name>. In this devlog, I decide to keep it simple by just filling the cursor's buffer with solid red, but I'll be integrating libXcursor in the near future.
For the second piece, you can either draw the cursor's buffer on top of the same OpenGL buffer you've been using for everything else, or you can attempt to put the cursor into its own DRM plane (called "the cursor plane"). The cursor plane performs better, but it doesn't always exist and its size can vary system-to-system, so even if you do choose this approach, you'll also need to implement some fallback. My test system doesn't expose a cursor plane, so I was stuck taking the simpler (but less performant) approach and just using my primary plane for everything.
Point and Click
Motion and click events are pretty straightforward. libinput emits events for both of these which contain all the info you need. It's just a matter of pulling that info out, then potentially sending it to the appropriate Wayland client when applicable (ie, when the cursor is on top of a client's surface).
Scrolling
Scrolling is a beast of its own. Wayland exposes 6 different "axis" events which are related to scrolling, and cover every scenario from mouse wheels with notches to trackpads and kinetic scrolling.
My "Breezy" system only has access to a mouse with a wheel, so I've only implemented the events I was able to test with a wheel: axis and axis_value120. To go along with these, I also emit axis_source which identifies the type of device that's causing the axis event (ie, a wheel), and frame which marks the end of a group of axis* events that belong together.
Related Links
Here's the PR for these changes: Github PR #8
There are also API reference pages for things discussed in this video: