+DEBUG_DEFINE_SOME_DEBUGF(findypp,debugfind)
+
+static int nfound;
+static Atom wm_name;
+static int screen;
+
+static void findypp_recurse(int depth, int targetdepth, Window w) {
+ unsigned int nchildren;
+ int i;
+ Window *children=0;
+ Window gotroot, gotparent;
+
+ static const char prefix[]= "Puzzle Pirates - ";
+ static const char onthe[]= " on the ";
+ static const char suffix[]= " ocean";
+#define S(x) ((int)sizeof((x))-1)
+
+ debugfind("FINDYPP %d/%d screen %d %*s %lx",
+ depth,targetdepth,screen,
+ depth,"",(unsigned long)w);
+
+ if (depth!=targetdepth) {
+ xassert( XQueryTree(disp,w,
+ &gotroot,&gotparent,
+ &children,&nchildren) );
+ debugfind(" nchildren=%d\n",nchildren);
+
+ for (i=0; i<nchildren; i++) {
+ Window child= children[i];
+ findypp_recurse(depth+1, targetdepth, child);
+ }
+ XFree(children);
+ return;
+ }
+
+
+ int gotfmt;
+ Atom gottype;
+ unsigned long len, gotbytesafter;
+ char *title;
+ unsigned char *gottitle=0;
+ xassert( !XGetWindowProperty(disp,w, wm_name,0,512, False,
+ AnyPropertyType,&gottype, &gotfmt, &len,
+ &gotbytesafter, &gottitle) );
+ title= (char*)gottitle;
+
+ if (DEBUGP(findypp)) {
+ debugfind(" gf=%d len=%lu gba=%lu \"", gotfmt,len,gotbytesafter);
+ char *p;
+ for (p=title; p < title+len; p++) {
+ char c= *p;
+ if (c>=' ' && c<=126) fputc(c,debug);
+ else fprintf(debug,"\\x%02x",c & 0xff);
+ }
+ fputs("\": ",debug);
+ }
+
+#define REQUIRE(pred) \
+ if (!(pred)) { debugfind(" failed test %s\n", #pred); return; } \
+ else
+
+ REQUIRE( gottype!=None );
+ REQUIRE( len );
+ REQUIRE( gotfmt==8 );
+
+ REQUIRE( len >= S(prefix) + 1 + S(onthe) + 1 + S(suffix) );
+
+ char *spc1= strchr( title + S(prefix), ' '); REQUIRE(spc1);
+ char *spc2= strrchr((title + len) - S(suffix), ' '); REQUIRE(spc2);
+
+ REQUIRE( (title + len) - spc1 >= S(onthe) + S(suffix) );
+ REQUIRE( spc2 - title >= S(prefix) + S(onthe) );
+
+ REQUIRE( !memcmp(title, prefix, S(prefix)) );
+ REQUIRE( !memcmp(title + len - S(suffix), suffix, S(suffix)) );
+ REQUIRE( !memcmp(spc1, onthe, S(onthe)) );
+
+#define ASSIGN(what, start, end) \
+ what= masprintf("%.*s", (int)((end)-(start)), start); \
+ if (o_##what) REQUIRE( !strcasecmp(o_##what, what) ); \
+ else
+
+ ASSIGN(ocean, spc1 + S(onthe), (title + len) - S(suffix));
+ ASSIGN(pirate, title + S(prefix), spc1);
+
+ debugfind(" YES!\n");
+ id= w;
+ nfound++;
+ progress_log("found YPP client (0x%lx):"
+ " %s ocean - %s.",
+ (unsigned long)id, ocean, pirate);
+}
+
+void find_yppclient_window(void) {
+ int targetdepth;
+
+ nfound=0;
+
+ if (id) return;
+
+ progress("looking for YPP client window...");
+
+ xassert( (wm_name= XInternAtom(disp,"WM_NAME",True)) != None);
+
+ for (targetdepth=1; targetdepth<4; targetdepth++) {
+ for (screen=0; screen<ScreenCount(disp); screen++) {
+ debugfind("FINDYPP screen %d\n", screen);
+ findypp_recurse(0,targetdepth, RootWindow(disp,screen));
+ }
+ if (nfound) break;
+ }
+
+ if (nfound>1)
+ fatal("Found several possible YPP clients. Close one,\n"
+ " disambiguate with --pirate or --ocean,"
+ " or specify --window-id.\n");
+ if (nfound<1)
+ fatal("Did not find %sYPP client."
+ " Use --window-id and/or report this as a fault.\n",
+ o_ocean || o_pirate ? "matching ": "");
+}