#include #include #include #include #include #include #include #include #include #include /* configuration */ #define ARGV "xterm", "xterm", "-e", "u", "/usr/local/bin/ksh", "-w", fifo #define MAX_CMD 1000 #define MAX_LOOK 1000 /* state */ Atom pidatom; Display *display; /* print on stderr and exit */ #define die(...) do { fprintf(stderr, __VA_ARGS__); exit(1); } while (0) /* find window associated with pid */ Window findwindow(unsigned int pid, Window w) { Atom type; int format; unsigned char *pidprop; unsigned int i, nchildren; unsigned long nitems, bytes_after; Window *children, _root, parent; pidprop = 0; if (XGetWindowProperty(display, w, pidatom, 0, 1, False, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &pidprop) == Success && pidprop && pid == *((unsigned long *)pidprop)) return w; if (XQueryTree(display, w, &_root, &parent, &children, &nchildren)) for (i = 0; i < nchildren; i++) { w = findwindow(pid, children[i]); if (w) return w; } return 0; } /* copy cwd and rewrite /home/ */ char * cwdcpy(char *path) { char *user, *r; int len; r = strdup(path); if (strncmp(path, "/home/", sizeof("/home/")-1) == 0) { user = getenv("USER"); len = strlen(user); r += sizeof("/home")-1; if (strncmp(r + 1, user, len) == 0) r += len; r[0] = '~'; } return r; } int main() { char *cwd, *cmd, *line, *fifo; FILE *fifofp; int i; pid_t child; size_t size; ssize_t len; Window w; if ((display = XOpenDisplay(0)) == NULL) die("could not open display\n"); if (mkdir("/var/tmp/tterm", 0700) == -1 && errno != EEXIST) err(1, "mkdir"); /* build fifo path */ if ((fifo = malloc(40*sizeof(char))) == NULL) err(1, "malloc"); sprintf(fifo, "/var/tmp/tterm/%d", getpid()); /* create fifo */ unlink(fifo); if (mkfifo(fifo, 0600) == -1) err(1, "mkfifo"); /* retrieve atom for _NET_WM_PID */ pidatom = XInternAtom(display, "_NET_WM_PID", 0); if (pidatom == None) die("no _NET_WM_PID atom found\n"); /* use ISO8859-1 encoding to speed up xterm start */ setenv("LC_ALL", "en_US.ISO8859-1", 1); /* start terminal */ if ((child = vfork()) == 0) { execlp(ARGV, NULL); err(1, "execvp"); } /* find window belonging to child */ for (i = 0; !w && i < MAX_LOOK; i++) w = findwindow(child, XDefaultRootWindow(display)); if (!w) die("could not find window\n"); /* read from fifo */ if ((fifofp = fopen(fifo, "r")) == NULL) err(1, "fopen"); if ((cmd = malloc(MAX_CMD*sizeof(char))) == NULL) err(1, "malloc"); line = NULL; size = 0; /* get first line and unlink fifo */ if ((len = getline(&line, &size, fifofp)) == -1) goto end; unlink(fifo); goto loop; /* process line and update title */ while ((len = getline(&line, &size, fifofp)) != -1) { loop: if (strncmp(line, "cwd", 3) == 0) { line[len-1] = 0; line += 3; cwd = cwdcpy(line); XStoreName(display, w, cwd); XFlush(display); } else if (strncmp(line, "cmd", 3) == 0) { line[len-1] = 0; len -= 1; line += 3; len -= 3; for (i = len-1; i > 0 && line[i] == ' '; i--) line[i] = 0; /* strip space */ snprintf(cmd, MAX_CMD, "%s (%s)", line, cwd); XStoreName(display, w, cmd); XFlush(display); } else { XStoreName(display, w, cwd); XFlush(display); } } end: XCloseDisplay(display); }