/* * xlaunch: program to launch window processes and display their * window ids on stdout. * derived from sample code on the net from here: http://groups.google.co.in/group/comp.os.linux.x/browse_thread/thread/2166307a9473ffbe/6bd3c21d87c2d5f6?lnk=st&q=pid+and+window+id&rnum=12&hl=en#6bd3c21d87c2d5f6 * shown to me by Sanjeev Gupta * modified based on requirements from Alan Buchanan * Designed by Rich Coe * * also found at: http://cvsweb.netbsd.org/bsdweb.cgi/xsrc/xc/test/appgroup/Attic/embedtest.c?rev=1.1.1 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include XtAppContext xLac; XtIntervalId exitTimeout = 0; Widget shell; int debug = 0; struct appInfo *appList = NULL; static XErrorHandler oldXErrorHandler; struct appInfo { struct appInfo *next; Window w; }; char authFile[80]; /* purpose: launch application (script?) specified on the command line * * how it works: * - create xauth app group * - fork * - set xauth * - launch app * * - wait for events * - display window event * - child exits * - wait for any windows to close * - exit * */ static void exitHandler(void *date, XtIntervalId *val) { exitTimeout = 0; /* XtAppSetExitFlag(xLac); control does not return to main loop */ unlink(authFile); exit(0); } struct appInfo * addWindow(struct appInfo *app, Window w) { struct appInfo *p; p = app; while (p) { if (w == p->w) return app; p = p->next; } p = (struct appInfo*) calloc(1, sizeof(struct appInfo)); p->w = w; if (app) p->next = app; return p; } struct appInfo * delWindow(struct appInfo *app, Window w) { struct appInfo *p, *last = NULL; p = app; while (p) { if (w == p->w) break; last = p; p = p->next; } if (NULL == p) return app; /* not found */ if (last) last->next = p->next; else app = p->next; free(p); return app; } void sigChild(int sig) { int status, ex; if (0 < wait(&status) && WIFEXITED(status)) { if (debug) fprintf(stderr, "child exited\n"); if (0 != (ex = WEXITSTATUS(status))) { XtAppSetExitFlag(xLac); fprintf(stderr, "child exited non-zero %d\n", ex); } else if (WIFSIGNALED(status)) { ex = WTERMSIG(status); XtAppSetExitFlag(xLac); fprintf(stderr, "child exited on signal %d\n", ex); } else if (NULL == appList) { if (exitTimeout) { XtRemoveTimeOut(exitTimeout); } exitTimeout = XtAppAddTimeOut(xLac, 6000, exitHandler, None); } } } static void iconify(Widget w, void *cd, XEvent *event) { if (MapNotify == event->type) { XEvent icon; XtRemoveEventHandler(w, StructureNotifyMask, False, (XtEventHandler)iconify, (XtPointer)0); icon.xclient.type = ClientMessage; icon.xclient.display = XtDisplay(shell); icon.xclient.window = XtWindow(shell); icon.xclient.message_type = XInternAtom(XtDisplay(shell), "WM_CHANGE_STATE", False); icon.xclient.format = 32; icon.xclient.data.l[0] = IconicState; XSendEvent(icon.xclient.display, RootWindowOfScreen(XtScreen(shell)), False, SubstructureRedirectMask|SubstructureNotifyMask, &icon); XUnmapWindow(XtDisplay(shell), XtWindow(shell)); } } int winIsTransient(Widget w, Window window) { Atom actualType; int actualFormat; unsigned long nItems, bytesAfter; unsigned char *propRtrn; if (Success == XGetWindowProperty(XtDisplay(w), window, (Atom)68, 0, 1, False, AnyPropertyType, &actualType, &actualFormat, &nItems, &bytesAfter, &propRtrn)) { if ((None != actualType) && (0 < nItems)) { if (NULL != propRtrn) XFree(propRtrn); return True; } } return False; } static int newXErrorHandler(Display *display, XErrorEvent *error) { if (BadWindow != error->error_code) oldXErrorHandler( display, error ); return 0; } static void EH(Widget w, XtPointer clientdata, XEvent * event, Boolean * cont) { XWindowChanges values; switch (event->type) { case MapRequest: XMapWindow(XtDisplay(w), event->xmaprequest.window); #ifdef VXTL_IS_BROKEN /* vxtl is incorrectly coded to create one of it's main * window as a transient. Additionally, it may be desired to * manage a transient window of an application. */ if (True == winIsTransient(w, event->xmaprequest.window)) return; #endif printf("0x%x\n", event->xmaprequest.window); fflush(stdout); XSelectInput(XtDisplay(w), event->xmaprequest.window, PropertyChangeMask|StructureNotifyMask); appList = addWindow(appList, event->xmaprequest.window); if (exitTimeout) { XtRemoveTimeOut(exitTimeout); exitTimeout = 0; } break; case ConfigureRequest: if (debug) fprintf(stderr, "resize window 0x%x mask %x x,y (%d, %d) w,h (%d,%d)\n", event->xconfigurerequest.window, event->xconfigurerequest.value_mask, event->xconfigurerequest.x, event->xconfigurerequest.y, event->xconfigurerequest.width, event->xconfigurerequest.height ); values.x = event->xconfigurerequest.x; values.y = event->xconfigurerequest.y; values.width = event->xconfigurerequest.width; values.height = event->xconfigurerequest.height; values.border_width = event->xconfigurerequest.border_width; if (event->xconfigurerequest.value_mask & (CWX|CWY|CWBorderWidth|CWWidth|CWHeight)) { XConfigureWindow(XtDisplay(w), event->xconfigurerequest.window, event->xconfigurerequest.value_mask, &values); } if (event->xconfigurerequest.value_mask & (CWWidth|CWHeight)) { XResizeWindow(XtDisplay(w), event->xconfigurerequest.window, event->xconfigurerequest.width, event->xconfigurerequest.height); XtResizeWidget(w, event->xconfigurerequest.width, event->xconfigurerequest.height, 0); } break; case DestroyNotify: if (debug) fprintf(stderr, "destroy window 0x%x\n", event->xdestroywindow.window); appList = delWindow(appList, event->xdestroywindow.window); if (NULL == appList) { if (exitTimeout) { XtRemoveTimeOut(exitTimeout); } exitTimeout = XtAppAddTimeOut(xLac, 60000, exitHandler, None); } break; default: if (debug) fprintf(stderr, "event %d\n", event->type); break; } } void closeAllFds() { char path[80]; struct dirent *de; DIR *dir; int dfd, *fdList, fdSize, fdCnt; sprintf(path, "/proc/%d/fd", getpid()); if (NULL == (dir = opendir(path))) return; dfd = dirfd(dir); fdSize = 10; fdList = (int *) malloc(fdSize * sizeof(int)); fdCnt = 0; while (NULL != (de = readdir(dir))) { if ('.' == de->d_name[0]) continue; /* skip hidden */ if (0 == de->d_name[1] /* skip 0, 1, 2 */ && (0x30 == de->d_name[0] || 0x31 == de->d_name[0] || 0x32 == de->d_name[0])) continue; fdList[fdCnt] = atoi( de->d_name ); if (dfd == fdList[fdCnt]) continue; /* skip opendir fd */ if (++fdCnt == fdSize) { fdSize += fdSize; fdList = realloc(fdList, fdSize * sizeof(int)); } } closedir(dir); for (dfd = 0; dfd < fdCnt; dfd++) close( fdList[ dfd ] ); free(fdList); } int initXapps(int argc, char **argv, char **c_argv) { Display * dpy; int major, minor; XAppGroup appgrp; Xauth * auth1; Xauth * auth2; struct utsname uts; FILE * file; XSecurityAuthorizationAttributes secattr; XSecurityAuthorization secid; pid_t ppid; closeAllFds(); /* close any fds passed on to us */ shell = XtVaOpenApplication(&xLac, "Test", 0, 0, &argc, argv, 0, applicationShellWidgetClass, XtNgeometry, "100x100+100+100", XtNinput, True, NULL); XtAddEventHandler(shell, StructureNotifyMask, False, (XtEventHandler) iconify, (XtPointer) 0); XtRealizeWidget(shell); XtAddRawEventHandler(shell, SubstructureRedirectMask, False, EH, ( XtPointer) 0); oldXErrorHandler = XSetErrorHandler( newXErrorHandler ); dpy = XtDisplay(shell); XagQueryVersion(dpy, &major, &minor); XSecurityQueryExtension(dpy, &major, &minor); XagCreateEmbeddedApplicationGroup(dpy, None, None, 0, 0, &appgrp); XtRegisterDrawable(dpy, appgrp, shell); auth1 = XSecurityAllocXauth(); auth1->family = FamilyWild; auth1->name = strdup("MIT-MAGIC-COOKIE-1"); auth1->name_length = strlen(auth1->name); auth1->data = 0; auth1->data_length = 0; secattr.timeout = 0; secattr.trust_level = XSecurityClientTrusted; secattr.group = appgrp; uname(&uts); auth2 = XSecurityGenerateAuthorization(dpy, auth1, XSecurityTimeout|XSecurityTrustLevel|XSecurityGroup, &secattr, &secid); auth2->family = FamilyLocal; auth2->address = strdup(uts.nodename); auth2->address_length = strlen(auth2->address); auth2->number = "0"; auth2->number_length = strlen(auth2->number); sprintf(authFile, "/tmp/secfile.%d", ppid = getpid()); if (NULL == (file = fopen(authFile, "w"))) { fprintf(stderr, "cannot open auth file '%s'\n", authFile); exit(1); } XauWriteAuth(file, auth2); fclose(file); XSecurityFreeXauth(auth1); XSecurityFreeXauth(auth2); signal(SIGCHLD, sigChild); if (fork() == 0) { sprintf(authFile, "XAUTHORITY=/tmp/secfile.%d", ppid); putenv(authFile); closeAllFds(); /* don't leak my X-fd on to dasher processes */ execvp(c_argv[0], c_argv); exit(ENOENT); } for ( ; FALSE == XtAppGetExitFlag(xLac); ) { XEvent event; XtAppNextEvent(xLac, &event); if (MapNotify == event.type || DestroyNotify == event.type) EH(shell, None, &event, None); XtDispatchEvent(&event); } unlink(authFile); return 0; } void usage() { fputs("usage: [-h] [--X apps] [x-args] -- appName startup-args ...\n" "\t-h\t\t help\n" "\tx-args\t\t any x arguments for parent\n" "\tappName\t\t x application to launch\n" "\tstartup-args\t arguments to x application\n", stderr); /* exit(99); */ } char *optarg = NULL; int optind = 0; int my_getopt(int argc, char **argv, char *opts) { static char **s_argv = NULL; char *p, *av; optarg = NULL; if (argv != s_argv || 0 == optind) { optind = 1; s_argv = argv; } if (optind >= argc) return -1; p = opts; av = argv[optind++]; if ('-' == *av && '-' == *(av + 1) && 0 == *(av + 2)) return -1; if ('-' != *av && '+' != *av) return '?'; av++; if ('-' == *av) av++; while (NULL != p && 0 != *p) { if (*p == *av) { if (':' == *(p + 1) && optind < argc + 1) optarg = argv[optind++]; return *p; } p++; } return '?'; } int main(int argc, char **argv) { int i, opt, userr = 0; int c_argc = 0, p_argc = 0; char *p = NULL, **c_argv, **p_argv; c_argv = (char **) malloc(argc * sizeof(char *)); p_argv = (char **) malloc(argc * sizeof(char *)); while (EOF != (opt = my_getopt(argc, argv, "hD"))) switch (opt) { case 'h': usage(); exit(1); break; case 'D': debug++; break; case '?': fprintf(stderr, "unknown (or malformed) option %s\n", p); userr++; break; default: p = argv[optind-1]; if ('-' == *p) { p_argv[p_argc++] = p; if ('-' != *argv[optind]) { p_argv[p_argc++] = argv[optind]; optind++; } break; } fprintf(stderr, "unknown (or malformed) option %s\n", p); userr++; break; } if (userr) { usage(); exit(1); } for (i = optind; i < argc; i++) c_argv[c_argc++] = argv[i]; if (debug) { fprintf(stderr, "Parent\n"); for (i = 0; i < p_argc; i++) fprintf(stderr, "\tp_argv[%d] %s\n", i, p_argv[i]); fprintf(stderr, "Child\n"); for (i = 0; i < c_argc; i++) fprintf(stderr, "\tc_argv[%d] %s\n", i, c_argv[i]); } if (c_argc) initXapps(p_argc, p_argv, c_argv); return 0; }