Watching For Changes in Window Focus Under X11

TL;DR: Here’s some example code. (backup copy)

UPDATE: It now also has the code to watch for the active window’s title changing without the window having to lose and regain focus.

I needed to explain to someone the proper way to watch a Linux desktop for changes to the active window (ie. When the user focuses a new window) and, since I had a surprising amount of trouble finding a reliable way to do this, I thought I’d blog about it.

The first thing you’re likely to see when you go looking for this is people polling commands like xprop to get that information. I think everyone knows this is a method of last resort. All the people doing it seem to.

Option two, once you compose the right search queries, is to watch FocusOut and possibly FocusIn events across your whole desktop. Some people seem to get that working but, unfortunately, it was very erratic on my KDE 4.x desktop.

Finally, the solution that’s both simple (by X11 standards) and seems to work reliably for me. I’d like to thank @alanc on StackOverflow for drawing my attention to this: You can opt into property-change notifications on the root window and watch _NET_ACTIVE_WINDOW. (Which is a standard property maintained by any modern window manager)

You will still want to do your own change checking, though. Watching the property is good for minimizing resource consumption, but I did receive duplicate events.

In addition to GitHub Gist, I’ve also posted the example in several StackOverflow answers (such as this one) in the hope that others will have a much easier time of it than I did.

Posted in Geek Stuff | Leave a comment

Making MPV EDL files double-clickable on Linux

After using OpenCV to skip post-roll ads, I wanted to share the relief with family who don’t launch their video players from the command line, so I researched how to associate the resulting .mpv.edl files with MPV so they could be double-clicked.

I won’t babble on. Here’s the script (including links to the reference material I used), which also associates any file which has “# mpv EDL” as the first bytes in the file.

Posted in Geek Stuff | Leave a comment

A Better Linkifying Regex

From time to time, I run across situations where the linkifying Greasemonkey script I use mistakenly includes a closing parenthesis in what it considers to be a URL.

Given that I can’t remember a single situation where I needed to linkify a URL with nested unescaped parentheses but URLs inside parentheses have bitten me repeatedly, I decided to solve the problem in a way that’ll work with any regex grammar.

const urlRegex = /\b((ht|f)tps?:\/\/[^\s+\"\<\>()]+(\([^\s+\"\<\>()]*\)[^\s+\"\<\>()]*)*)/ig;

Basically, it matches:

  1. http, https, ftp, or ftps followed by ://
  2. an alternating sequence of “stuff” and balanced pairs of parentheses containing “stuff”

…where “stuff” to refers to a sequence of zero or more non-whitespace, non-parenthesis characters (and, in this linkify.user.js version, non-caret, non-double-quote too).

Embarassingly, aside from two corrections and a few extra characters in the blacklists that I kept from the original linkify.user.js regex, this is a direct translation of something I wrote for years ago… I’d just never remembered the problem in a situation where I could spare the time and willpower to do something about it.

Here’s the corrected Python original.

hyperlinkable_url_re = re.compile(r"""((?:ht|f)tps?://[^\s()]+(?:\([^\s()]*\)[^\s()]*)*)""", re.IGNORECASE | re.UNICODE)

The corrections made were:

  1. Allow the pairs of literal parentheses to be empty
  2. Move a grouping parenthesis so that a(b)c(d)e will be matched as readily as a(b)(c)d.

Markdown source code works especially well to demonstrate the difference.

Naive Linkifying Regex My Linkifying Regex
[FreeDOS]( [FreeDOS](

Theoretically, look-ahead/behind assertions are enough of an extension to regexp syntax to allow real HTML parsing, so I could probably also support nested parens, but I’m just not in the mood to self-nerd-snipe right now.

Posted in Geek Stuff | Leave a comment

Mixed Feelings on Cloanto and Amiga/C64 Forever

UPDATE: I’ve received a response from Cloanto and, after talking to a real human about this, I’m convinced that this is mostly, if not entirely, a pile of unfortunate mistakes that they sincerely want to get fixed. I’ve added notes to clarify things.

As someone who prefers to take the high ground, when I was offered the opportunity to get Amiga Forever and C64 Forever at a big discount, I jumped at it. My first PC was an original IBM PC and I’d missed out on those famous platforms entirely… here was a chance to get into them without compromising my principles.

I also loved how, as a Linux user, Cloanto seems to be walking a balance with their cross-platform support page… admitting that their digital download releases are MSI installers, but providing what I’ll call “relaxed support” for other platforms from CD/DVD versions and clarifying that users have confirmed the ability to generate them from the MSIs using Wine or equivalent.

However, after deciding to purchase, I noticed that their website design wasn’t the only thing that, to be kind, felt a bit dated.

First, their purchase process. Is it really necessary to ask users for their shipping address if they’ve selected a digital download item and PayPal payment? I could easily see that driving away some on-the-fence buyers who value their privacy.

UPDATE: We’re still talking, but this looks to me like one of those “their merchant services provider doesn’t understand this marget segment” issues… they’re already working on a new site design to help remedy that problem as much as possible.

Second, the post-purchase e-mails. Where do I start?

  1. Is it really necessary for me to receive seven e-mails in response to a successfully completed transaction?
  2. What’s the point in sending me an e-mail, just to tell me to log into my e-mail account to follow the instructions in the e-mail I’m about to receive? (No joke.) I’m not going to see it until I’ve done what it’s telling me to do!
  3. An anti-fraud measure involving them asking me to confirm my PayPal e-mail? What’s wrong with just asking PayPal if I’m a verified user. (Oh well, if Cloanto or Avangate start spamming me, I can just move PayPal to a new alias and delete the old one.)
  4. Is it really necessary to send three different confirmation e-mails for different stages of the process, rather than just waiting a couple of seconds and sending one combined e-mail?

Oh well… on to the next problem.

UPDATE: The seven e-mails are all from their merchant services provider (Avangate) and I received no argument on this side that it’s excessive. They’ve passed on my concerns via the B2B communication channels available to them.

Third, the registration keys.

As soon as I saw those, I immediately worried that maybe Amiga Forever and C64 Forever were online-activated products and the installers would stop working if Cloanto went out of business.

(Thankfully, the “Forever” in the title does appear to be accurate, as they installed without complaint on the quarantined Windows XP retro-PC that does double-duty as an online activation tester. No need to demand a refund.)

UPDATE: We’re still talking, but I’ve suggested, at minimum, that an explanation of the key’s purpose (unlocking the paid content in a multi-role offline install package) be provided either with or before showing the keys. I also made suggestions for a longer-term strategy.

Fourth, when your selling a game-related product in the era of services like Steam and GOG, this can easily trigger buyer’s remorse:

You have 50 downloads remaining.
Link expires on: November 16, 2017.

There are many reasons this is a problem:

  1. This is retro-emulation stuff with the bulk of it being more than 20 years old. It’s already easy enough and tempting enough for people to pirate it without adding an expiry message so they can’t rationalize it as paying for a booklet of 50 off-site backup coupons.
  2. In the era of cheap hosting like Amazon S3 and “re-download is better than backup” services like Steam/Origin/uPlay/GOG/etc., is it really necessary to make people with flaky connections worry about whether their download manager’s resume feature will chew up most of their redownloads?
  3. The installer acts as if the same download is offered for both trial and paid copies, depending on whether you enter a registration code. Again, why am I made to agonize over a redownload limit and expiry counter on this thing?

All in all, this screams “Danger, Will Robinson! Danger!” because this kind of out-of-touchness makes me worry about whether they’ll remain competitive enough in the market to avoid going under.

*sigh* Ok, I’ve paid for the damn thing and, as much as it hurts, I’ve already spent far too much money on taking the moral high ground for other platforms (eg. I use a Retrode and buy actual cartridges, rather than being locked into Nintendo’s Virtual Console.). What’s next?

UPDATE: They’ve actually been trying to get Avangate to understand this for a while and providing their own accounts system to resolve this is part of the reason they’re working on a new site design.

Fifth, the download speed.

An average download speed of 80KiB/s because it gives me spikes of full speed alternated with several seconds of nothing… ’nuff said.

UPDATE: Avangate serves the files.

Sixth, the license agreement.

  1. Make up your mind. The website I can see before I pay seems friendly and willing to allow me to install on any platform I have the know-how for, but the license says that installing it on any platform other than Windows, MacOS, or GNU/Linux (eg. FreeBSD) will terminate my license.
  2. I can only install it on two machines? Dammit, I forgot to pay attention to whether that “wait at least 6 months” rule was only for the evaluation version.
    Does my “moral high ground” rule mean that I can’t install it on both my Linux desktop and my Linux handheld until 6 months after I remove it from the XP machine I used for testing?

UPDATE: I had to clarify my concerns in my response. I’ve waiting for a reply.

Seventh, the RP9 files.

Not strictly Cloanto’s fault, but there are no Google results which mention that you can get more broadly compatible disk images from an RP9 using 7-Zip. I just figured it out by accident when I right-clicked one on the test machine.

UPDATE: I’ve suggested some minor adjustments to the knowledge base page which shows up in Google and/or the “RP9 Toolbox” software to draw more attention to the link to the RP9 spec which I missed.

Eighth, the games themselves.

Ok, so, dude, I bought this pack because I want to stay legal. Ya dig? …so why am I seeing a cracking group intro when I fire up B.C.’s Quest for Tires on the C64?

I seriously doubt the rightsholder for the game got permission to use the cracking group’s intellectual property and just because it’s an unauthorized derivative work doesn’t magically cause the rights to be forfeit.

I’m now stuck in one of those BS situations where I’m only “legal” because the guys I sided with have the bigger stick, not because they’re actually in the moral right.

…so, what did I pay for then? Kickstart ROMs and disk images that would have fallen into the public domain by now if Copyright hadn’t become corrupted and the warm, fuzzy feeling of having a slightly lighter wallet?

I’m really starting to understand why the user base considers Cloanto to be at fault for failing to negotiate a deal for the Kickstart ROMs so they could include Amiga games in their catalogue.

I’d say “I give up”, but that might be taken as “I’m going to start pirating” when, really, it just means that I’m probably going to buy fewer retro-games. I already have

They wonder why people pirate things when, even if you spend hours and tie yourself in knots trying to stay compliant with the letter of copyright law, your upstream suppliers are unilaterally deciding that a cracking group’s IP deserves no protection because it’s an unauthorized derivative work. It’s simply flat-out impossible to enjoy early cultural artifacts in the world of gaming and retain the moral high ground in a world of bit-rotting floppy discs. 🙁

UPDATE: They’ve actually brought this “We got the rights to the games, but what about the copyright on the code the crackers wrote?” issue up with the US Copyright Office multiple times.

Also, on the “GOG failed to negotiate a deal” front, Cloanto is apparently aiming to eventually get the Amiga/C64 IP to the point where it can be spun off as a non-profit… it’s just not as simple as I make it sound.

Finally, the convenience (or lack thereof).

I can only assume that Cloanto is mostly trying to compete with pirates based on convenience (like Steam does quite well)… but does this seem convenient to you?

  1. Install both things on my quarantined XP machine so I can be sure they’re not phoning home.
  2. Ask both tools to generate the promised ISO versions (and printable covers, since I’m going to this effort anyway) because using p7zip to unpack the installers on my Linux desktop without running them produces unhelpful filenames.
  3. Put everything including the ISOs, my purchase invoice, and a text file containing the registration keys into another DVD ISO so I know everything can be kept together nicely.
  4. Run all three of the aforementioned ISOs (official C64, official Amiga, combined backup) through dvdisaster to augment the raw ISO filesystem with forward error correction in case the discs start to bit-rot after my download links have expired.
  5. Burn all three to discs from the stockpile of Taiyo Yuden T02 DVD+R media that I use for archival (which, by the way, they no longer make).
  6. Write the order number and my name on all three discs so that they won’t look pirated if Cloanto goes out of business and their records become unavailable.
  7. Write the registration keys on the official media, since they won’t have them in the burned data.

UPDATE: Already addressed as a side-effect of addressing the earlier concerns.

…and no, I couldn’t just rely on pirated copies as my off-site backup. Those bits have the wrong colour.

Posted in Geek Stuff | Leave a comment

Simple Alarm Clock Script For Linux

TL;DR: Install python-dateutil, pytimeparse, and this script, then see the --help output for more details.

For a while, I’d been using the at command to schedule alarms when I needed to wake up in the morning, but I found that it was a fragile solution because of how MPlayer and its descendants interacted with PulseAudio’s session-centric setup and the presence or absence of a video output.

…and you really don’t want a fragile solution for your alarm clock, so I decided to write a little helper script that could run inside my quake-style terminal in my user session so it would Just Work™.

You’ll want to edit the hard-coded media player command it uses to actually play the alarm, but, otherwise, it should be pretty polished for something I just hacked together for my own use.

It’ll accept arguments in two forms:

  • wakeme at 6am
  • wakeme in 3 hours

(It accepts a great many formats for times and durations, so I’ll just point you at the docs for dateutil.parser.parse() (times) and pytimeparse (durations) for the complete list.)

Either one will cause it to echo back its interpretation of what you asked for (so you can double-check that it understood properly) and then sleep until it’s time to wake you.

Installation is as simple as:

  1. Make sure Python 2.x is installed (I haven’t tested 3.x)
  2. Install python-dateutil
  3. Install pytimeparse
  4. Put wakeme in your PATH
Posted in Geek Stuff | Leave a comment

What Disney Has Forgotten About Classic Donald Duck

Who hasn’t seen at least one of the classic Donald Duck cartoons from the 1930s, 40s, and 50s? You know, the ones where, in the later cartoons, the theme says “Who never never starts an argument?”

Sadly, it seems that Disney has forgotten what made those so special. About 5 years ago, when I had the opportunity to borrow the Chronological Donald box set [1] [2], I saw that it ended with an example of a modern Donald Duck cartoon from Mickey Mouse Works which Leonard Maltin referred to as proof that Donald was still alive and well.

The problem was that, in that cartoon, we see Donald at the zoo, trying to take a picture of the Aracuan Bird for Daisy, while the Aracuan Bird keeps tormenting him… I felt sorry for Donald and that’s not supposed to happen!

What Disney seems to have forgotten is that classic Donald Duck cartoons are supposed to be a caricature of our own failings. That short felt more like a Warner Brothers cartoon in disguise.

I gave it some thought and I managed to come up with three rules:

1. Donald is the maker of his own misfortune

This rule is satirized right in the opening song. They sing about how Donald never loses his temper and so on, and Donald is listening and agreeing, but we all know how false that is.

Look at Donald trying to make waffles. What goes wrong? He leaves his scrapbooking rubber cement out and mistakenly uses it in the recipe… and why was he using rubber cement for scrapbooking in the first place?

What about getting into a fight with Huey, Dewy, and Louie? Same verditct. He starts it by smashing up their snowman with his toboggan and then refuses to concede defeat as things escalate.

Getting into a fight with a robot butler in a museum of modern marvels over whether he can keep his hat on? Not only is it stupid to argue with a machine, the jerk cheated the turnstile with a coin on a string!

2. Animals are innocent

Look at the cartoons. whenever Donald gets into a fight with an animal, he always throws the first punch. For example, look at when he goes on a picnic. Sure, the ants show up to cart off his food, but that’s just ants being ants! How does Donald respond? He provokes them by playing mean-spirited pranks on them.

Donald the Beekeeper? He keeps escalating the fight when the bees don’t take kindly to having their honey stolen. Donald the highway-builder, assigned to remove Chip and Dale’s tree? He pranks them when they mistake his steam shovel for a dragon.

This is the biggest mistake that the modern cartoon made. Warner Brothers has antagonistic slapstick between two characters who, if you really think about it, tend to be jerks. Disney is supposed to do better. (eg. Classic Pluto cartoons are caricatures of things you can easily imagine your dog actually doing. Classic Goofy cartoons began as parodies of wholesome father-and-son shows, then became parodies of “how to” videos.)

3. Inanimate objects are antagonistic

While you probably haven’t gotten mocked by a clock spring or taunted by a steam piston (“So!” “Ssssoooo what?”), we’ve all had those moments when we felt so frustrated because “Why won’t you just work!?“.

These moments are Donald Duck’s bread and butter, with inanimate objects like rocks, bike pumps, and machinery doing the wildly improbably or, sometimes, even the impossible in order to produce the most frustrating outcome for Donald Duck.

From a pebble under his camping cot getting thrown and landing in the one place where it can trigger a rock slide, to his rubber-cemented waffle batter behaving in a very familiar way to anyone who’s ever used a not-brand-new tube of rubber cement, Donald Duck spent a ton of time being a send-up to all of the little frustrations of day-to-day life.

So… how would I have done it?

The key is to make it completely clear that Donald’s troubles are his own damn fault.

After Daisy asked Donald for the picture, I’d have started with Donald getting frustrated with the view and deciding he knows better than the posted zoo rules… maybe climbing a tree or fence to get a better angle for the photo.

Then, when he encounters the inevitable pratfall, the Aracuan Bird can laugh along with the audience, egging Donald on further. From this point on, it’s clear that Donald’s at fault.

The episode could then take on that Roadrunner and Coyote-esque quality that happens when Donald provokes an innocent creature, except more focused on antagonistic inanimate objects since the Aracuan hasn’t truly been given cause to fight Donald.

Posted in Writing | 1 Comment

A more formal way to think about validity of input data

I’ve begun to port one of my hobby projects from Python to Rust and, while setting up the clap argument parser, I found myself having to bind to the access(2) libc function myself.

Yes, it exposes you to a race condition exploit if you’re not careful, because the permissions could change between checking and depending on them. Yes, it’s a documented fact that it may be more permissive than actually attempting to access the filesystem. (I believe the situation I’m remembering was “access() doesn’t consider ACLs when evaluating permissions”) …but how else am I to implement a “fail early” check for “Can I create files in this directory?” when there exist real in-the-wild examples of filesystems (eg. AFS) having been configured to allow the creation of a hypothetical test file, but not the subsequent deletion?

That said, despite my intent to use Rust to ensure I handle every recoverable error case, there’s still a certain appeal to being able to point to a spot and say “beyond this point, this piece of data is trustworthy”.

Thinking about this made me realize a nice, simple way to think about handling input data. By analogy to passing by value (with deep copying) or by reference.

NOTE: While my examples will all use command-line arguments, this applies to any kind of input data.

Value Arguments

If a command-line argument cannot become invalid after being validated, then it’s a value argument. Examples of this include:

  • Boolean flags like “mirror this print job”
  • Integers representing things like the number of copies of a document to print
  • Strings which can’t experience any kind of namespace collision

You can validate value arguments once and then trust that they’ll stay valid.

Reference Arguments

If an argument depends on something outside your control to determine its validity, then a validity check only applies to the instant you perform it. Common examples of “reference arguments” include:

  • Filesystem paths (Between the check and use, permissions could change, a creation/deletion/rename could invalidate the path, etc.)
  • File descriptors (Even a supposedly local file descriptor could be on a network-mounted drive which goes away)
  • Strings used to create filenames (someone could create a file with that name which you lack the permissions to manipulate)
  • Network addresses
  • Cached results of arbitrary checks

This means that you need to be prepared for the unexpected every time you use a reference argument and you can only check separately from using them if the following conditions are met:

  1. The check has no security implications and can be safely removed
  2. You accept that the check could fail but the attempt could still succeed
  3. You accept that the check could succeed but the attempt could still fail


Argument Type Why?
Boolean Value Nothing external to the program will invalidate this.

(The only way this could be a reference is if there were some kind of wrapper which detected the orientation of pre-punched cardstock in the printer and then did or didn’t pass this flag. The user could invalidate it by flipping/rotating the card stock before the print job actually begins.)

Boolean Reference The flag implies that either the user or the code detected a rewritable CD/DVD, but the user could swap in a non-rewritable disc before it actually gets used if the script does something long-running first, like generating an ISO in /tmp

Because you can only erase a rewritable disc, this must be validated as late as possible. (ie. After the drive tray has been locked and right before the operation would take place)

 Number of copies to print Integer Value The only relevant detail which can change is how much paper is in the printer, and, if there isn’t enough, the proper solution isn’t to reduce the size of the print job.
 File descriptor Integer Reference The descriptor could be pointing at a resource on a network-attached device that goes away.
Document Title String Either Whether to treat this as a reference depends on where it will end up and how you handle failure.

If you’re converting an eBook with ebook-convert from Calibre, then it’s a value because the output filename is specified separately and whether your title will override the source file’s metadata is not up for debate.

Output Filename String Reference No matter how many times you validate, it’s possible that a read-only file will have taken that name by the time you call open()

The Takeaway

  • Think in terms of how one piece of data depends on another and don’t forget that dependencies can extend outside of your program.
  • Whether a piece of data can be validated once and then trusted is unrelated to its data type or how it’s passed within your code. (You can pass a filename or URL by value but it’s still a reference to an external resource. A network filesystem will subvert your expectations for how reliable it is to hold an open file descriptor. etc. etc. etc.)
  • The definition of “valid” for a piece of data may depend on how your program is intended to be used. (A human might specify a filename and re-run your tool if it’s already taken. From your perspective, that means it’s valid even if it causes the process to abort. A GUI frontend, on the other hand, probably won’t know how to detect that kind of failure and retry. Expose a more foolproof API by using something like mkstemp or mkdtemp and then returning the newly-created path.)
  • Functions like access which check the validity of a reference are unreliable and should only be used to catch obvious mistakes early so the user doesn’t have to waste their time waiting for a failure that could have been anticipated. If it’s unsafe to comment them out, you’re doing it wrong.
    (eg. You can use access to detect read-only target directories before you know the exact output filename… with the caveat that they could be made read-only between the check and the attempt to actually write the file.)
Posted in Geek Stuff | Leave a comment