void SecureDisplay (struct display *d, Display *dpy) { Debug ("SecureDisplay %s\n", d->name); (void) Signal (SIGALRM, syncTimeout); if (Setjmp (syncJump)) { LogError ("WARNING: display %s could not be secured\n", d->name); SessionExit (d, RESERVER_DISPLAY, FALSE); } (void) alarm ((unsigned) d->grabTimeout); Debug ("Before XGrabServer %s\n", d->name); XGrabServer (dpy); if (XGrabKeyboard (dpy, DefaultRootWindow (dpy), True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { (void) alarm (0); (void) Signal (SIGALRM, SIG_DFL); LogError ("WARNING: keyboard on display %s could not be secured\n", d->name); SessionExit (d, RESERVER_DISPLAY, FALSE); } Debug ("XGrabKeyboard succeeded %s\n", d->name); (void) alarm (0); (void) Signal (SIGALRM, SIG_DFL); pseudoReset (dpy); if (!d->grabServer) { XUngrabServer (dpy); XSync (dpy, 0); } Debug ("done secure %s\n", d->name); }
void SessionPingFailed(struct display *d) { if (clientPid > 1) { AbortClient(clientPid); source(verify.systemEnviron, d->reset); } SessionExit(d, RESERVER_DISPLAY, TRUE); }
static void callback_die(SmcConn smc_conn __UNUSED__, SmPointer client_data __UNUSED__) { if (EDebug(EDBUG_TYPE_SESSION)) Eprintf("callback_die\n"); SessionExit(EEXIT_EXIT, NULL); }
__dead void ManageSession (struct display *d) { pid_t pid = 0; greet_user_rtn greet_stat; Debug ("ManageSession %s\n", d->name); (void)XSetIOErrorHandler(IOErrorHandler); (void)XSetErrorHandler(ErrorHandler); setproctitle("%s", d->name); if (d->autoLogin == NULL || d->autoLogin[0] == '\0') { /* Load system default Resources */ LoadXloginResources (d); greet_stat = GreetUser(d, &verify, &greet); } else greet_stat = AutoLogin(d, &verify, &greet); if (greet_stat == Greet_Success) { clientPid = 0; (void) signal (SIGTERM, catchTerm); /* * Start the clients, changing uid/groups * setting up environment and running the session */ if (StartClient (&verify, d, &clientPid, greet.name)) { Debug ("Client Started\n"); /* Wait for session to end, */ pid = waitpid(clientPid, NULL, 0); if (pid <= 0 && abortSession) { /* * when terminating the session, nuke * the child and then run the reset script */ AbortClient (clientPid); } } else { LogError ("session start failed\n"); } } /* * run system-wide reset file */ if (d->windowPath != NULL) login_fbtab(d->windowPath, 0, 0); Debug ("Source reset program %s\n", d->reset); source (verify.systemEnviron, d->reset); SessionExit (d, OBEYSESS_DISPLAY, TRUE); }
void SecureDisplay (struct display *d, Display *dpy) { Debug ("SecureDisplay %s\n", d->name); Debug ("Before XGrabServer %s\n", d->name); XGrabServer (dpy); if (XGrabKeyboard (dpy, DefaultRootWindow (dpy), True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { LogError ("WARNING: keyboard on display %s could not be secured\n", d->name); SessionExit (d, RESERVER_DISPLAY, FALSE); } Debug ("XGrabKeyboard succeeded %s\n", d->name); pseudoReset (dpy); if (!d->grabServer) { XUngrabServer (dpy); XSync (dpy, 0); } Debug ("done secure %s\n", d->name); }
static void guaranteed_read(int fd, char *buf, size_t count) { int bytes_read; if (count == 0) { return; } while ((bytes_read = read(fd, buf, count)) > 0) { count -= bytes_read; buf += bytes_read; if (count == 0) { return; } } WDMError("Greet: guarenteed_read error, UNMANAGE DISPLAY\n"); WDMError("Greet: pipe read error with %s\n", wdmLogin); SessionExit(Save_d, RESERVER_DISPLAY, FALSE); /* this exits */ exit(UNMANAGE_DISPLAY); /* should not happen */ }
int main(int argc, char **argv) { int ch, i, loop; struct utsname ubuf; const char *str, *dstr; /* This function runs all the setup for startup, and then * proceeds into the primary event loop at the end. */ /* Init state variable struct */ memset(&Mode, 0, sizeof(EMode)); Mode.wm.master = 1; Mode.wm.pid = getpid(); Mode.wm.exec_name = argv[0]; Mode.wm.startup = 1; Mode.mode = MODE_NONE; EXInit(); Dpy.screen = -1; str = getenv("EDEBUG"); if (str) EDebugInit(str); str = getenv("EDEBUG_COREDUMP"); if (str) Mode.wm.coredump = 1; str = getenv("EDEBUG_EXIT"); if (str) Mode.debug_exit = atoi(str); str = getenv("ECONFNAME"); if (str) EConfNameSet(str); str = getenv("ECONFDIR"); if (str) EDirUserSet(str); str = getenv("ECACHEDIR"); if (str) EDirUserCacheSet(str); srand((unsigned int)time(NULL)); if (!uname(&ubuf)) Mode.wm.machine_name = Estrdup(ubuf.nodename); if (!Mode.wm.machine_name) Mode.wm.machine_name = Estrdup("localhost"); /* Now we're going to interpret any of the commandline parameters * that are passed to it -- Well, at least the ones that we * understand. */ Mode.theme.path = NULL; dstr = NULL; for (loop = 1; loop;) { ch = EoptGet(argc, argv); if (ch <= 0) break; #if 0 Eprintf("Opt: %c: %d - %s\n", ch, eoptind, eoptarg); #endif switch (ch) { default: case '?': printf("e16: Ignoring: "); for (i = eoptind; i < argc; i++) printf("%s ", argv[i]); printf("\n"); loop = 0; break; case 'h': EoptHelp(); exit(0); break; case 'd': dstr = eoptarg; break; case 'f': Mode.wm.restart = 1; break; case 'p': EConfNameSet(eoptarg); break; case 'P': EDirUserSet(eoptarg); break; case 'Q': EDirUserCacheSet(eoptarg); break; case 's': Mode.wm.single = 1; Dpy.screen = strtoul(eoptarg, NULL, 10); break; case 'S': SetSMID(eoptarg); break; case 't': Mode.theme.path = Estrdup(eoptarg); break; case 'V': printf("%s %s\n", e_wm_name, e_wm_version); exit(0); break; case 'v': EDebugSet(EDBUG_TYPE_VERBOSE, 1); break; case 'w': sscanf(eoptarg, "%dx%d", &Mode.wm.win_w, &Mode.wm.win_h); Mode.wm.window = 1; Mode.wm.single = 1; Mode.wm.master = 0; break; #ifdef USE_EXT_INIT_WIN case 'X': ExtInitWinSet(strtoul(eoptarg, NULL, 0)); Mode.wm.restart = 1; break; #endif case 'm': Mode.wm.master = 0; Mode.wm.master_screen = strtoul(eoptarg, NULL, 10); break; } } SignalsSetup(); /* Install signal handlers */ EDirsSetup(); ECheckEprog("epp"); ECheckEprog("eesh"); SetupX(dstr); /* This is where the we fork per screen */ /* X is now running, and we have forked per screen */ ESavePrefixSetup(); /* So far nothing should rely on a selected settings or theme. */ ConfigurationLoad(); /* Load settings */ /* Initialise internationalisation */ LangInit(); /* The theme path must now be available for config file loading. */ ThemePathFind(); /* Set the Environment variables */ Esetenv("EVERSION", e_wm_version); Esetenv("EROOT", EDirRoot()); Esetenv("EBIN", EDirBin()); Esetenv("ECONFDIR", EDirUser()); Esetenv("ECACHEDIR", EDirUserCache()); Esetenv("ETHEME", Mode.theme.path); /* Move elsewhere? */ EImageInit(); HintsInit(); CommsInit(); SessionInit(); SnapshotsLoad(); #if USE_DBUS DbusInit(); #endif if (Mode.wm.window) EMapWindow(VROOT); ModulesSignal(ESIGNAL_INIT, NULL); /* Load the theme */ ThemeConfigLoad(); if (Mode.debug_exit) return 0; /* Do initial configuration */ ModulesSignal(ESIGNAL_CONFIGURE, NULL); /* Set root window cursor */ ECsrApply(ECSR_ROOT, WinGetXwin(VROOT)); #ifdef USE_EXT_INIT_WIN /* Kill the E process owning the "init window" */ ExtInitWinKill(); #endif /* let's make sure we set this up and go to our desk anyways */ DeskGoto(DesksGetCurrent()); ESync(ESYNC_MAIN); #ifdef SIGCONT for (i = 0; i < Mode.wm.child_count; i++) kill(Mode.wm.children[i], SIGCONT); #endif ModulesSignal(ESIGNAL_START, NULL); #if ENABLE_DIALOGS DialogsInit(); #endif EwinsManage(); RunInitPrograms(); SnapshotsSpawn(); if (!Mode.wm.restart) StartupWindowsOpen(); Conf.startup.firsttime = 0; Mode.wm.save_ok = Conf.autosave; Mode.wm.startup = 0; autosave(); /* The primary event loop */ EventsMain(); SessionExit(EEXIT_QUIT, NULL); return 0; }
void ManageSession (struct display *d) { static int pid = 0; Display *dpy; greet_user_rtn greet_stat; static GreetUserProc greet_user_proc = NULL; #ifndef GREET_USER_STATIC void *greet_lib_handle; #endif Debug ("ManageSession %s\n", d->name); (void)XSetIOErrorHandler(IOErrorHandler); (void)XSetErrorHandler(ErrorHandler); #ifndef HAS_SETPROCTITLE SetTitle(d->name, (char *) 0); #else setproctitle("%s", d->name); #endif /* * Load system default Resources */ LoadXloginResources (d); #ifdef GREET_USER_STATIC greet_user_proc = GreetUser; #else Debug("ManageSession: loading greeter library %s\n", greeterLib); greet_lib_handle = dlopen(greeterLib, RTLD_NOW); if (greet_lib_handle != NULL) greet_user_proc = (GreetUserProc)dlsym(greet_lib_handle, "GreetUser"); if (greet_user_proc == NULL) { LogError("%s while loading %s\n", dlerror(), greeterLib); exit(UNMANAGE_DISPLAY); } #endif /* tell the possibly dynamically loaded greeter function * what data structure formats to expect. * These version numbers are registered with The Open Group. */ verify.version = 1; greet.version = 1; greet_stat = (*greet_user_proc)(d, &dpy, &verify, &greet, &dlfuncs); if (greet_stat == Greet_Success) { clientPid = 0; if (!Setjmp (abortSession)) { (void) Signal (SIGTERM, catchTerm); /* * Start the clients, changing uid/groups * setting up environment and running the session */ if (StartClient (&verify, d, &clientPid, greet.name, greet.password)) { Debug ("Client Started\n"); #ifndef GREET_USER_STATIC /* Save memory; close library */ dlclose(greet_lib_handle); #endif /* * Wait for session to end, */ for (;;) { if (d->pingInterval) { if (!Setjmp (pingTime)) { (void) Signal (SIGALRM, catchAlrm); (void) alarm (d->pingInterval * 60); pid = wait ((waitType *) 0); (void) alarm (0); } else { (void) alarm (0); if (!PingServer (d, (Display *) NULL)) SessionPingFailed (d); } } else { pid = wait ((waitType *) 0); } if (pid == clientPid) break; } } else { LogError ("session start failed\n"); } } else { /* * when terminating the session, nuke * the child and then run the reset script */ AbortClient (clientPid); } } /* * run system-wide reset file */ Debug ("Source reset program %s\n", d->reset); source (verify.systemEnviron, d->reset); SessionExit (d, OBEYSESS_DISPLAY, TRUE); }
static void HandleXIOError(void) { SessionExit(EEXIT_ERROR, NULL); }
void ManageSession(struct display *d) { static int pid = 0; Display *dpy; greet_user_rtn greet_stat; #ifdef WITH_CONSOLE_KIT char *ck_session_cookie = NULL; #endif WDMDebug("ManageSession %s\n", d->name); (void)XSetIOErrorHandler(IOErrorHandler); (void)XSetErrorHandler(ErrorHandler); #ifndef HAS_SETPROCTITLE SetTitle(d->name, (char *)0); #else setproctitle("%s", d->name); #endif /* * Load system default Resources */ LoadXloginResources(d); verify.version = 1; greet.version = 1; greet_stat = GreetUser(d, &dpy, &verify, &greet); if (greet_stat == Greet_Success) { clientPid = 0; if (!Setjmp(abortSession)) { (void)Signal(SIGTERM, catchTerm); /* * Start the clients, changing uid/groups * setting up environment and running the session */ #ifdef WITH_CONSOLE_KIT ck_session_cookie = open_ck_session(getpwnam(greet.name), d); #endif if (StartClient(&verify, d, &clientPid, greet.name, greet.password #ifdef WITH_CONSOLE_KIT , ck_session_cookie #endif )) { WDMDebug("Client Started\n"); /* * Wait for session to end, */ for (;;) { if (d->pingInterval) { if (!Setjmp(pingTime)) { (void)Signal(SIGALRM, catchAlrm); (void)alarm(d->pingInterval * 60); pid = wait((waitType *) 0); (void)alarm(0); } else { (void)alarm(0); if (!PingServer(d, (Display *) NULL)) SessionPingFailed(d); } } else { pid = wait((waitType *) 0); } if (pid == clientPid) break; } } else { WDMError("session start failed\n"); } } else { /* * when terminating the session, nuke * the child and then run the reset script */ AbortClient(clientPid); } } #ifdef WITH_CONSOLE_KIT if (ck_session_cookie != NULL) { close_ck_session(ck_session_cookie); free(ck_session_cookie); } #endif /* * run system-wide reset file */ WDMDebug("Source reset program %s\n", d->reset); source(verify.systemEnviron, d->reset); SessionExit(d, OBEYSESS_DISPLAY, TRUE); }
greet_user_rtn GreetUser(struct display * d, Display ** dpy, struct verify_info * verify, struct greet_info * greet) { int flag; int pid; int code; Save_d = d; /* hopefully, this is OK */ *dpy = XOpenDisplay(d->name); /* make sure we have the display */ /* * Run the setup script - note this usually will not work when * the server is grabbed, so we don't even bother trying. */ if (!d->grabServer) SetupDisplay(d); if (!*dpy) { WDMError("Cannot reopen display %s for greet window\n", d->name); exit(RESERVER_DISPLAY); } pid = InitGreet(d); /* fork and exec the external program */ for (;;) { /* * Greet user, requesting name/password */ code = Greet(d, greet); WDMDebug("Greet greet done: %s, pwlen=%i\n", name, strlen(password)); if (code != 0) { WDMDebug("Greet: exit code=%i, %s\n", code, exitArg); if (wdmVerify || wdmRoot) { flag = False; if (Verify(d, greet, verify)) flag = True; if (wdmRoot && (strcmp(greet->name, "root") != 0)) flag = False; } else flag = True; if (flag == True) { switch (code) { case 2: /* reboot */ CloseGreet(pid); WDMInfo("reboot(%s) by %s\n", exitArg, name); system(wdmReboot); SessionExit(d, UNMANAGE_DISPLAY, FALSE); break; case 3: /* halt */ CloseGreet(pid); WDMInfo("halt(%s) by %s\n", exitArg, name); system(wdmHalt); SessionExit(d, UNMANAGE_DISPLAY, FALSE); break; case 4: /* exit */ CloseGreet(pid); WDMDebug("UNMANAGE_DISPLAY\n"); WDMInfo("%s exit(%s) by %s\n", PACKAGE_NAME, exitArg, name); #if 0 SessionExit(d, UNMANAGE_DISPLAY, FALSE); #else WDMDebug("Killing parent process %d\n", getppid()); kill(getppid(), SIGINT); #endif break; } } else { kill(pid, SIGUSR1); /* Verify failed */ } } else { /* * Verify user */ if ((!*greet->name) && *wdmDefaultUser) { greet->name = wdmDefaultUser; greet->password = wdmDefaultPasswd; } if (Verify(d, greet, verify)) break; else kill(pid, SIGUSR1); /* Verify failed */ } } DeleteXloginResources(d, *dpy); CloseGreet(pid); WDMDebug("Greet loop finished\n"); /* * Run system-wide initialization file */ if (source(verify->systemEnviron, d->startup) != 0) { WDMDebug("Startup program %s exited with non-zero status\n", d->startup); SessionExit(d, OBEYSESS_DISPLAY, FALSE); } return Greet_Success; }
static void ShowAlert(const char *title, const char *ignore, const char *restart, const char *quit, const char *fmt, va_list args) { char text[4096], buf1[64], buf2[64], buf3[64]; Window win, b1 = 0, b2 = 0, b3 = 0, root; Display *dd; int wid, hih, w, h, i, k, mask; XGCValues gcv; GC gc; unsigned int len; XEvent ev; XSetWindowAttributes att; XRectangle rect1, rect2; char colorful; unsigned long cols[5]; XColor xcl; Colormap cmap; int cnum, fh, x, y, ww, hh, bw, bh; char *str1, *str2, *str3, *p; KeyCode keycode; int button; char **missing_charset_list_return, *def_string_return; int missing_charset_count_return; XFontStruct **font_struct_list_return; char **font_name_list_return; #if 0 /* Don't play sound here (maybe if not forked/in signal handler - later) */ SoundPlay(SOUND_ALERT); #endif if (!fmt) return; Evsnprintf(text, sizeof(text), fmt, args); /* * We may get here from obscure places like an X-error or signal handler * and things seem to work properly only if we do a new XOpenDisplay(). */ dd = XOpenDisplay(NULL); if (!dd) { fprintf(stderr, "%s\n", text); fflush(stderr); return; } button = 0; if (!title) title = _("Enlightenment Error"); str1 = AlertButtonText(1, buf1, sizeof(buf1), ignore); str2 = AlertButtonText(2, buf2, sizeof(buf2), restart); str3 = AlertButtonText(3, buf3, sizeof(buf3), quit); cnum = 0; colorful = 0; cols[0] = cols[1] = cols[2] = cols[3] = cols[4] = 0; cmap = DefaultColormap(dd, DefaultScreen(dd)); if (DefaultDepth(dd, DefaultScreen(dd)) > 4) { ExSetColor(&xcl, 220, 220, 220); if (!XAllocColor(dd, cmap, &xcl)) goto CN; cols[cnum++] = xcl.pixel; ExSetColor(&xcl, 160, 160, 160); if (!XAllocColor(dd, cmap, &xcl)) goto CN; cols[cnum++] = xcl.pixel; ExSetColor(&xcl, 100, 100, 100); if (!XAllocColor(dd, cmap, &xcl)) goto CN; cols[cnum++] = xcl.pixel; ExSetColor(&xcl, 0, 0, 0); if (!XAllocColor(dd, cmap, &xcl)) goto CN; cols[cnum++] = xcl.pixel; ExSetColor(&xcl, 255, 255, 255); if (!XAllocColor(dd, cmap, &xcl)) goto CN; cols[cnum++] = xcl.pixel; colorful = 1; } CN: if (colorful) att.background_pixel = cols[1]; else att.background_pixel = BlackPixel(dd, DefaultScreen(dd)); if (colorful) att.border_pixel = cols[3]; else att.border_pixel = WhitePixel(dd, DefaultScreen(dd)); att.backing_store = Always; att.save_under = True; att.override_redirect = True; mask = CWBackPixel | CWBorderPixel | CWOverrideRedirect | CWSaveUnder | CWBackingStore; #if USE_COMPOSITE_OVERLAY_WINDOW /* * Intended workings: * Composite extension not enabled (or COW not available?) * - fall back to root * Composite extension enabled * - use COW whether or not compositing is enabled, window mode too */ root = XCompositeGetOverlayWindow(dd, DefaultRootWindow(dd)); if (root == None) #endif { root = DefaultRootWindow(dd); } win = XCreateWindow(dd, root, -100, -100, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, mask, &att); gc = XCreateGC(dd, win, 0, &gcv); if (colorful) XSetForeground(dd, gc, cols[3]); else XSetForeground(dd, gc, att.border_pixel); xfs = XCreateFontSet(dd, "fixed", &missing_charset_list_return, &missing_charset_count_return, &def_string_return); if (!xfs) goto done; if (missing_charset_list_return) XFreeStringList(missing_charset_list_return); k = XFontsOfFontSet(xfs, &font_struct_list_return, &font_name_list_return); fh = 0; for (i = 0; i < k; i++) { h = font_struct_list_return[i]->ascent + font_struct_list_return[i]->descent; if (fh < h) fh = h; } XSelectInput(dd, win, ExposureMask); XMapWindow(dd, win); XGrabServer(dd); XGrabPointer(dd, win, False, ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); XGrabKeyboard(dd, win, False, GrabModeAsync, GrabModeAsync, CurrentTime); XSetInputFocus(dd, win, RevertToPointerRoot, CurrentTime); XSync(dd, False); wid = DisplayWidth(dd, DefaultScreen(dd)); hih = DisplayHeight(dd, DefaultScreen(dd)); ww = (wid >= 600) ? 600 : (wid / 40) * 40; hh = (hih >= 440) ? 440 : (hih / 40) * 40; for (i = 40; i < ww; i += 40) { w = i; h = (i * hh) / ww; x = (wid - w) >> 1; y = (hih - h) >> 1; XMoveResizeWindow(dd, win, x, y, w, h); DRAW_BOX_OUT(dd, gc, win, 0, 0, w, h); XSync(dd, False); SleepUs(20000); } x = (wid - ww) >> 1; y = (hih - hh) >> 1; XMoveResizeWindow(dd, win, x, y, ww, hh); XSync(dd, False); bw = 0; if (str1) { ExTextExtents(xfs, str1, strlen(str1), &rect1, &rect2); bw = (rect2.width > bw) ? rect2.width : bw; } if (str2) { ExTextExtents(xfs, str2, strlen(str2), &rect1, &rect2); bw = (rect2.width > bw) ? rect2.width : bw; } if (str3) { ExTextExtents(xfs, str3, strlen(str3), &rect1, &rect2); bw = (rect2.width > bw) ? rect2.width : bw; } bw += 20; bh = fh + 10; #define BX(i) (5 + (((ww - bw - 10) * (i)) / 2)) #define BY (hh - bh - 5) if (str1) { b1 = XCreateWindow(dd, win, BX(0), BY, bw, bh, 0, CopyFromParent, InputOutput, CopyFromParent, mask, &att); XMapWindow(dd, b1); } if (str2) { b2 = XCreateWindow(dd, win, BX(1), BY, bw, bh, 0, CopyFromParent, InputOutput, CopyFromParent, mask, &att); XMapWindow(dd, b2); } if (str3) { b3 = XCreateWindow(dd, win, BX(2), BY, bw, bh, 0, CopyFromParent, InputOutput, CopyFromParent, mask, &att); XMapWindow(dd, b3); } XSync(dd, False); button = 0; for (; button == 0;) { XNextEvent(dd, &ev); switch (ev.type) { case KeyPress: keycode = XKeysymToKeycode(dd, XK_F1); if (keycode == ev.xkey.keycode) { DRAW_BOX_IN(dd, gc, b1, 0, 0, bw, bh); XSync(dd, False); SleepUs(500000); DRAW_BOX_OUT(dd, gc, b1, 0, 0, bw, bh); button = 1; goto do_sync; } keycode = XKeysymToKeycode(dd, XK_F2); if (keycode == ev.xkey.keycode) { DRAW_BOX_IN(dd, gc, b2, 0, 0, bw, bh); XSync(dd, False); SleepUs(500000); DRAW_BOX_OUT(dd, gc, b2, 0, 0, bw, bh); button = 2; goto do_sync; } keycode = XKeysymToKeycode(dd, XK_F3); if (keycode == ev.xkey.keycode) { DRAW_BOX_IN(dd, gc, b3, 0, 0, bw, bh); XSync(dd, False); SleepUs(500000); DRAW_BOX_OUT(dd, gc, b3, 0, 0, bw, bh); button = 3; goto do_sync; } break; case ButtonPress: if (!(ev.xbutton.y >= BY && ev.xbutton.y < BY + bh)) break; x = BX(0); if (b1 && ev.xbutton.x >= x && ev.xbutton.x < x + bw) { DRAW_BOX_IN(dd, gc, b1, 0, 0, bw, bh); goto do_sync; } x = BX(1); if (b2 && ev.xbutton.x >= x && ev.xbutton.x < x + bw) { DRAW_BOX_IN(dd, gc, b2, 0, 0, bw, bh); goto do_sync; } x = BX(2); if (b3 && ev.xbutton.x >= x && ev.xbutton.x < x + bw) { DRAW_BOX_IN(dd, gc, b3, 0, 0, bw, bh); goto do_sync; } break; case ButtonRelease: if (!(ev.xbutton.y >= BY && ev.xbutton.y < BY + bh)) break; x = BX(0); if (b1 && ev.xbutton.x >= x && ev.xbutton.x < x + bw) { DRAW_BOX_OUT(dd, gc, b1, 0, 0, bw, bh); button = 1; goto do_sync; } x = BX(1); if (b2 && ev.xbutton.x >= x && ev.xbutton.x < x + bw) { DRAW_BOX_OUT(dd, gc, b2, 0, 0, bw, bh); button = 2; goto do_sync; } x = BX(2); if (b3 && ev.xbutton.x >= x && ev.xbutton.x < x + bw) { DRAW_BOX_OUT(dd, gc, b3, 0, 0, bw, bh); button = 3; goto do_sync; } break; case Expose: /* Flush all other Expose events */ while (XCheckTypedWindowEvent(dd, ev.xexpose.window, Expose, &ev)) ; ExTextExtents(xfs, title, strlen(title), &rect1, &rect2); w = rect2.width; DRAW_HEADER(dd, gc, win, (ww - w) / 2, 5 - rect2.y, title); DRAW_BOX_OUT(dd, gc, win, 0, 0, ww, bh); DRAW_BOX_OUT(dd, gc, win, 0, bh - 1, ww, hh - fh - fh - 30 + 2); DRAW_BOX_OUT(dd, gc, win, 0, hh - fh - 20, ww, fh + 20); k = bh; for (p = text;; p += len + 1) { len = strcspn(p, "\n"); DRAW_STRING(dd, gc, win, 6, 6 + k + fh, p, len); k += fh + 2; if (p[len] == '\0') break; } if (str1) { ExTextExtents(xfs, str1, strlen(str1), &rect1, &rect2); w = rect2.width; DRAW_HEADER(dd, gc, b1, (bw - w) / 2, 5 - rect2.y, str1); DRAW_BOX_OUT(dd, gc, b1, 0, 0, bw, bh); DRAW_THIN_BOX_IN(dd, gc, win, BX(0) - 2, BY - 2, bw + 4, bh + 4); } if (str2) { ExTextExtents(xfs, str2, strlen(str2), &rect1, &rect2); w = rect2.width; DRAW_HEADER(dd, gc, b2, (bw - w) / 2, 5 - rect2.y, str2); DRAW_BOX_OUT(dd, gc, b2, 0, 0, bw, bh); DRAW_THIN_BOX_IN(dd, gc, win, BX(1) - 2, BY - 2, bw + 4, bh + 4); } if (str3) { ExTextExtents(xfs, str3, strlen(str3), &rect1, &rect2); w = rect2.width; DRAW_HEADER(dd, gc, b3, (bw - w) / 2, 5 - rect2.y, str3); DRAW_BOX_OUT(dd, gc, b3, 0, 0, bw, bh); DRAW_THIN_BOX_IN(dd, gc, win, BX(2) - 2, BY - 2, bw + 4, bh + 4); } do_sync: XSync(dd, False); break; default: break; } } XFreeFontSet(dd, xfs); done: XUngrabServer(dd); XDestroyWindow(dd, win); XFreeGC(dd, gc); if (cnum > 0) XFreeColors(dd, cmap, cols, cnum, 0); XCloseDisplay(dd); switch (button) { default: case 1: break; case 2: SessionExit(EEXIT_RESTART, NULL); break; case 3: SessionExit(EEXIT_EXIT, NULL); break; } }