Revising the spectacle hack-fix

Not too long ago I talked about my quick and dirty workaround for KDE’s screenshot capture utility being … less useful than I’d like thanks to a(n upstream) Qt bug.

To recap:

  • When you try to capture rectangular region of the screen, Spectacle (said screenshot utility) will freeze the entire desktop and allow you to draw a square
  • If you’re running a multi-monitor setup with high PPI monitor(s) under Xorg, the image of your frozen desktop will be moved partly off-screen.
  • This means that you will not be able to see or select a certain portion of the screen

My solution amounted to a few console commands bashed together that move the frozen desktop frame back where it’s supposed to be.

This has downsides. For example, the issue only gets fixed when you trigger screen capture with a keyboard shortcut. If you tell Spectacle to capture a screenshot after a timeout, the issue won’t get fixed. It’s also not guaranteed to work if you have multiple Spectacle windows already open from previous screen captures.

That’s not good enough.

What about fixing the problem at the source?

From this point forward, there are roughly two options. I can try to use Xlib (with which I had a very brief encounter some time ago) and watch for new Windows getting launched, or I can do the right way and fix Spectacle. After all, we are talking about open source software.

Thus I go ahead and clone Spectacle’s github repo. I start looking at the code and notice the first problem: it’s written in C++.

I’m doing javascript/typescript by the day, bash on a very odd weekend, python if I really have to. C# has been sitting on a shelf since my diploma, Java for longer (though it’s getting dusted off lately). C is a faded memory from like three classes in entire university. Obviously advanced C is the last program language I’d prefer to use.

Still, I dig through the code, trying to find if there’s any place I can see that sets the spawn position of the frozen frame. One and a half hour later, I just give up. It’s time for Xlib.

X gon give it to ya

After giving up on Spectacle, I go back to whipping up my dirty hacks. I start shopping for functions that I want and incorporate them into my program. Eventually, I’m far enough to do a test compile. This is where I get to witness this bullshit.

We are witnessing a missing import. The question on the table is which. As we start looking for an answer, we run into another problem: C and Xorg were both designed before stackoverflow existed.

They were designed in a time where people assumed people will actually read the _entire_ documentation before trying to write their first “hello world” thing. The “you need to import this file” will be hidden as an offhand mention in one of the two tutorials you were linked to kick things off (and it’s always gonna only be in the tutorial you didn’t check), and then never again.

If you’re doing your function-shopping on stackoverflow code or by browsing the list of functions on websites that are basically manpages but with links, you will miss that. Documentation and manpages for functions will treat the necessary import as if it were a recipe for coca-cola.

It’s X11/Xutil.h. Is it really that hard to put on a manpage, or am I just missing something because I have literally no experience?

Anyway, back to track.

The program is set to log window titles, which it does … Except the values aren’t quite what we’d want. We expect to see “Spectacle” appear (and nothing else) — but nothing of the sort pops up:


What gives? There’s two thing, actually. One: we’re requesting “WM_NAME” property, when we really want “_NET_WM_NAME.” Second: we’re requesting CreateNotify events, but Qt may be changing titles (and geometry) after creating windows. This means we need to catch ConfigureNotify events as well.

When we listen for ConfigureNotify events as well, we finally get what we want:

When we log _NET_WM_TITLE and WM_TITLE during the process of taking a screenshot, we can clearly see that title ‘Spectacle’ doesn’t get set immediately after window creation.

The hard part seems to be over now. All we need is another strcmp to compare _NET_WM_TITLE with and XMoveWindow, both pretty straightforward. (And we can’t forget to set up an error handler, because BadWindow will happen every now and then. We can ignore this error).

Now let’s try to figure if this hack can work with vlc and smplayer as well …

(Code is available on github)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.