zzzclip
- 10 Devlogs
- 51 Total hours
the cooler wayland clipboard manager, now with history, persistence, MIME type awareness, and file representation of clipboard contents
the cooler wayland clipboard manager, now with history, persistence, MIME type awareness, and file representation of clipboard contents
I have no idea how this devlog ended up so long
Anyway, I cleaned up some potential crashes/undefined behavior, fixed up the README, and finally tagged a release + published to AUR!
Spent a lot of time wrestling with static linking. I remember using old versions of linux before and getting glibc problems so I wanted to link it statically. I first tried using musl-gcc, but I ended up needing too many static versions of libraries so I just made a Dockerfile with alpine (which has static versions of basically everything) and made the binary there.
Did you know PKGBUILDs are just bash scripts? I didn’t.
the clipboard-as-files thing is added!
I originally wanted to use FUSE/libfuse, but i realized i could just change the storage format to have the data be in a single file. now i’m just using symlinks instead, no dependencies
this was relatively easy, ran into a couple of bugs but nothing too crazy. Biggest thing I got hung up on was which directory to put it in ($XDG_STATE_HOME? $XDG_DATA_HOME? ~/clipboard?). I eventually decided on $XDG_RUNTIME_DIR which seems mostly appropriate - the only thing is that it’s kinda annoying to access, but you could just make your own symlink, change the path with $ZZZCLIP_SYMLINK_PATH, or add a bookmark like in the screenshot.
Another thing was to add extensions (e.g. .png) to the file, because apps like discord won’t recognize them if they don’t have extensions. I was initially gonna take and process one of the giant lists online, but then i found out most systems have a /etc/mime.types so i parsed that instead.
I added some more options to the CLI, which ended up being a lot more annoying than i expected. Here are the ones I added:
added to zzzclip list:
added to zzzclip get:
wl-copy starts a background process when you run it. The clipboard contents aren’t owned by the compositor, so a process has to be running to supply the data. I made zzzclip get do the same thing, but like wl-copy I added an option to make it run in the foreground.zzzclip list -v but only for one item.big ticket is overhauling the config format. Previously, the index looked like this:
4a93d8d7 6b5d69df
2143c202
Each random string of 8 characters was a label for data under a particular mime type, and each line was a selection (a selection can have multiple mimetypes). Each label had its own file to store the actual clipboard data, with the mimetype included in that file.
this worked fine, but I’ve been wanting to implement the feature where the current clipboard contents are accessible via file. If I moved the mimetype out of the data files, I could just use symlinks because each file has exactly the data I need; using the old format, i’d need to use libfuse to make “fake” files without the mimetypes instead.
this was a lot more annoying than i expected (thank god for address sanitizer, caught many mistakes), but I eventually got it working. I think i’m nearing the finish line
lots of minor-ish stuff for this batch of changes.
Biggest change is actually adding proper cli parsing and help messages! previously, the cli was extremely bare-bones and just good enough to actually work but didn’t have any decent error handling or help messages.
I’ve also ditched the option that runs the selector program (e.g. rofi, fuzzel). I didn’t know about he -nth those programs have, which let you hide data from the selector, so that functionality was kinda redundant.
(also the sizes are human-readable now, i.e. in kb/mb/gb instead of just raw bytes)
the tests were bad. I fixed them and now everything passes. hooray!
Anyway, welcome to macro hell!
i’ve been working through the todo list and one of the items I wanted to hit was to support the ext-data-control protocol on top of the wlr-data-control protocol. Wayland compositors work on “protocols,” and not every compositor supports every protocol; the *-data-control protocols are what allow clipboard managers to mess with the clipboard. wlr-data-control was first (i think) and is only supported by wlroots-based compositors, but ext-data-control is the standard now. (except the compositor I use, river, doesn’t support it yet…)
The problem with supporting both is that C is not a very expressive language. I had to generate wrapper functions for every function supplied by the protocol, which was bad enough, but I also had to write wrapper functions for my own functions that were used in listeners. This part could have been so much worse, but I was able to hide some function pointers in the user data and cut down even more boilerplate.
Not fun. 3/10.
there’s always the boring janitorial stuff (e.g. i renamed a few files, moved some stuff around, fixed a mem leak and a potential crash, etc.)
the cooler change is that I finally added testing! testing an app like this is infinitely more annoying than something like a chess engine (shameless plug) because it’s built around IO. I followed in fuzzel’s footsteps and did integration testing in a shell script, which isn’t something i realized is practical until seeing it used there. the very sparse tests actually already did find a bug, but i’ll fix it later……
the testing is to set up more disruptive features i’ll add later, like implementing the ext-data-control protocol on top of wlr-data-control, and I want to make sure they won’t break anything without having to manually test
two things:
minor changes for this devlog. spent way more time than is reasonable thinking of the best way to deal with allocation failures… it seems like everyone online has a different opinion on it. I tried doing it “properly” before seeing how many lines of checks that would require for a codepath that would realistically never get hit, so I gave up and just did xmalloc (basically, a wrapper around malloc that exits with an error message when it fails).
Also in the theme of error handling, I did a sweep of the code and wrapped (most) of the io functions I missed to check for failure. it seems like overkill… there has to be a better way but maybe this is how it is.
Finally, I switched from libpcre2 to posix regex.h. I didn’t realize POSIX had a regex.h and it’s way more than is required for this use-case (matching mimetypes).
I started this project much earlier than stardance (it’s years old by now), but it’s only recently become usable. think of this devlog as motivation/background
the main goal was to make a clipboard manager that could
Here’s something interesting you might not have known about linux clipboards (both wayland and x11): the data doesn’t actually exist until a client requests it. This is how applications like firefox offer 20 morbillion image types; it’s converting the image on-the-fly. Given this, it’s impractical to request every offered type, so most clipboard managers I’ve found solve this by giving up and only doing text or text+hardcoded image mimetypes. zzzclip has a probably-overcomplicated system that lets you configure which mimetypes it’ll remember and priority between mimetypes (plus regexes).
Another feature I want to add eventually is a FUSE clipboard system where it can make a “fake” (meaning it’s backed by the program, not something on disk) file holding the current clipboard contents.
(as for what these 17 hours are actually for: it’s just adding config parsing and a load of cleanups.)