--- /dev/null
+#!/usr/bin/perl -w
+use strict (qw(vars));
+
+use IO::File;
+
+our @pipes;
+
+sub reap_pipe () {
+ my ($child, $pipe) = @{ shift @pipes };
+ { local ($/) = undef; $_= <$pipe>; }
+ if (m/^WM_NAME: +not found/) {
+ } elsif (m/^WM_NAME\(STRING\) = $/) {
+ } elsif (m/^WM_NAME\(STRING\) = \"(.*)\"$/) {
+ print "$child $1\n" or die $!;
+ } else {
+ die "$child $_ ?";
+ }
+ $!=0; $pipe->close(); $? and die "$? $! ?";
+}
+
+open WI, "LC_ALL=C xwininfo -root -children |" or die $!;
+while (<WI>) {
+ next unless m/^\s+\d+ children:/..0;
+ next unless m/^\s+(0x[0-9a-f]+) /;
+ my $child= $1;
+
+ my $pipe= new IO::File "LC_ALL=C xprop -id $child WM_NAME |" or die $!;
+ push @pipes, [ $child, $pipe ];
+
+ while (@pipes > 40) { reap_pipe(); }
+}
+$!=0; close WI; $? and die "$? $! ?";
+
+while (@pipes) { reap_pipe(); }
+
+close STDOUT or die $!;
--- /dev/null
+/**/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+
+#define eassert assert
+
+static Display *disp;
+static long id;
+
+static void kmevent(XEvent *ev) {
+ int r;
+ r= XSendEvent(disp,id,False,0,ev); assert(r);
+}
+
+static KeyCode keycode(const char *s) {
+ KeySym sym= XStringToKeysym(s);
+ return XKeysymToKeycode(disp,sym);
+}
+
+int main(int argc, const char *const *argv) {
+ char *ep;
+ XWindowAttributes attr;
+ XEvent ev;
+ int r;
+
+ id= strtoul(*++argv,&ep,0);
+ disp= XOpenDisplay(0); eassert(disp);
+
+ r= XGetWindowAttributes(disp, id, &attr); eassert(r);
+
+ while (*++argv) {
+
+ memset(&ev,0,sizeof(ev));
+#define KE ev.xkey
+#define ME ev.xbutton
+
+ switch (**argv) {
+ case 'r':
+ r= XRaiseWindow(disp, id); eassert(r);
+ break;
+
+#define KMEVENT(e,t) \
+ e.type= t; \
+ e.window= id; \
+ e.root= attr.root; \
+ e.x= atoi(*++argv); \
+ e.y= atoi(*++argv); \
+ e.x_root= e.x; \
+ e.y_root= e.y; \
+ e.same_screen= True; \
+ kmevent(&ev); \
+ break;
+
+ case 'K': KE.keycode= keycode(*++argv); KMEVENT(KE,KeyPress);
+ case 'k': KE.keycode= keycode(*++argv); KMEVENT(KE,KeyRelease);
+ case 'M': ME.button=1; KMEVENT(ME,ButtonPress);
+ case 'm': ME.button=1; ME.state=Button1Mask; KMEVENT(ME,ButtonRelease);
+ default:
+ abort();
+ }
+ }
+
+ r= XSync(disp, False); eassert(r);
+ exit(0);
+}