Yup, I found that method myself, after some digging.
How I'm detecting the end of playback is a little sneaky. I'm spawning the CLI MP3 player application like this:
$cmd = sprintf($opts{playercmd},
($listbox->getRow($i))[0]);
$player_pid = open($PLAYER, "|$cmd");
This gets me a blocking open on the player, so that I don't ever get two tracks playing at once, and a child PID back. But, the child player doesn't terminate on exit. So then I poll /proc/pid/status every 50ms in my non-Tk event loop, and wait for the status to change to 'zombie', at which point I know playback has finished. Then I can close the player handle, do any necessary processing, and advance to the next track. The 50ms response time is too short for the listener to notice, but slow enough in system terms that the task load from the polling is down in the noise.