X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fxscreensaver.c;h=dd27cae56f679727d5b42ab9679266c120692942;hb=4361b69d3178d7fc98d0388f9a223af6c2651aba;hp=09665b665de43e7c4cff488992de83749510e1a2;hpb=96a411663168b0ba5432b407a83be55f3df0c802;p=xscreensaver diff --git a/driver/xscreensaver.c b/driver/xscreensaver.c index 09665b66..dd27cae5 100644 --- a/driver/xscreensaver.c +++ b/driver/xscreensaver.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1991-2003 Jamie Zawinski +/* xscreensaver, Copyright (c) 1991-2017 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -46,6 +46,8 @@ * via the $XSCREENSAVER_WINDOW environment variable -- this trick requires * a recent (Aug 2003) revision of vroot.h. * + * (See comments in screens.c for more details about Xinerama/RANDR stuff.) + * * While we are waiting for user activity, we also set up timers so that, * after a certain amount of time has passed, we can start a different * screenhack. We do this by killing the running child process with @@ -91,6 +93,14 @@ * subwindows. It is an incredible misdesign that one client can make * another client malfunction in this way. * + * But here's a new kink that started showing up in late 2014: GNOME programs + * don't actually select for or receive KeyPress events! They do it behind + * the scenes through some kind of Input Method magic, even when running in + * an en_US locale. However, in that case, those applications *do* seem to + * update the _NET_WM_USER_TIME on their own windows every time they have + * received a secret KeyPress, so we *also* monitor that property on every + * window, and treat changes to it as identical to KeyPress. + * * To detect mouse motion, we periodically wake up and poll the mouse * position and button/modifier state, and notice when something has * changed. We make this check every five seconds by default, and since the @@ -142,6 +152,11 @@ #include #include +#ifdef ENABLE_NLS +# include +# include +#endif /* ENABLE_NLS */ + #include #include @@ -152,6 +167,8 @@ #include #include #include /* for gethostbyname() */ +#include +#include #ifdef HAVE_XMU # ifndef VMS # include @@ -162,20 +179,59 @@ # include "xmu.h" #endif /* !HAVE_XMU */ +#ifdef HAVE_MIT_SAVER_EXTENSION +#include +#endif /* HAVE_MIT_SAVER_EXTENSION */ + #ifdef HAVE_XIDLE_EXTENSION # include #endif /* HAVE_XIDLE_EXTENSION */ +#ifdef HAVE_SGI_VC_EXTENSION +# include +#endif /* HAVE_SGI_VC_EXTENSION */ + +#ifdef HAVE_READ_DISPLAY_EXTENSION +# include +#endif /* HAVE_READ_DISPLAY_EXTENSION */ + +#ifdef HAVE_XSHM_EXTENSION +# include +#endif /* HAVE_XSHM_EXTENSION */ + +#ifdef HAVE_DPMS_EXTENSION +# include +#endif /* HAVE_DPMS_EXTENSION */ + + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION +# include +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + +#ifdef HAVE_XF86VMODE +# include +#endif /* HAVE_XF86VMODE */ + +#ifdef HAVE_XF86MISCSETGRABKEYSSTATE +# include +#endif /* HAVE_XF86MISCSETGRABKEYSSTATE */ + #ifdef HAVE_XINERAMA # include #endif /* HAVE_XINERAMA */ +#ifdef HAVE_RANDR +# include +#endif /* HAVE_RANDR */ + + #include "xscreensaver.h" #include "version.h" #include "yarandom.h" #include "resources.h" #include "visual.h" #include "usleep.h" +#include "auth.h" saver_info *global_si_kludge = 0; /* I hate C so much... */ @@ -202,36 +258,7 @@ static XrmOptionDescRec options [] = { /* useful for debugging */ { "-no-capture-stderr", ".captureStderr", XrmoptionNoArg, "off" }, - - /* There's really no reason to have these command-line args; they just - lead to confusion when the .xscreensaver file has conflicting values. - */ -#if 0 - { "-splash", ".splash", XrmoptionNoArg, "on" }, - { "-capture-stderr", ".captureStderr", XrmoptionNoArg, "on" }, - { "-timeout", ".timeout", XrmoptionSepArg, 0 }, - { "-cycle", ".cycle", XrmoptionSepArg, 0 }, - { "-lock-mode", ".lock", XrmoptionNoArg, "on" }, - { "-no-lock-mode", ".lock", XrmoptionNoArg, "off" }, - { "-no-lock", ".lock", XrmoptionNoArg, "off" }, - { "-lock-timeout", ".lockTimeout", XrmoptionSepArg, 0 }, - { "-lock-vts", ".lockVTs", XrmoptionNoArg, "on" }, - { "-no-lock-vts", ".lockVTs", XrmoptionNoArg, "off" }, - { "-visual", ".visualID", XrmoptionSepArg, 0 }, - { "-install", ".installColormap", XrmoptionNoArg, "on" }, - { "-no-install", ".installColormap", XrmoptionNoArg, "off" }, - { "-timestamp", ".timestamp", XrmoptionNoArg, "on" }, - { "-xidle-extension", ".xidleExtension", XrmoptionNoArg, "on" }, - { "-no-xidle-extension", ".xidleExtension", XrmoptionNoArg, "off" }, - { "-mit-extension", ".mitSaverExtension",XrmoptionNoArg, "on" }, - { "-no-mit-extension", ".mitSaverExtension",XrmoptionNoArg, "off" }, - { "-sgi-extension", ".sgiSaverExtension",XrmoptionNoArg, "on" }, - { "-no-sgi-extension", ".sgiSaverExtension",XrmoptionNoArg, "off" }, - { "-proc-interrupts", ".procInterrupts", XrmoptionNoArg, "on" }, - { "-no-proc-interrupts", ".procInterrupts", XrmoptionNoArg, "off" }, - { "-idelay", ".initialDelay", XrmoptionSepArg, 0 }, - { "-nice", ".nice", XrmoptionSepArg, 0 }, -#endif /* 0 */ + { "-log", ".logFile", XrmoptionSepArg, 0 }, }; #ifdef __GNUC__ @@ -252,17 +279,24 @@ ERROR! You must not include vroot.h in this file. static void do_help (saver_info *si) { + char *s, year[5]; + s = strchr (screensaver_id, '-'); + s = strrchr (s, '-'); + s++; + strncpy (year, s, 4); + year[4] = 0; + fflush (stdout); fflush (stderr); fprintf (stdout, "\ -xscreensaver %s, copyright (c) 1991-2003 by Jamie Zawinski \n\ +xscreensaver %s, copyright (c) 1991-%s by Jamie Zawinski \n\ \n\ All xscreensaver configuration is via the `~/.xscreensaver' file.\n\ Rather than editing that file by hand, just run `xscreensaver-demo':\n\ that program lets you configure the screen saver graphically,\n\ including timeouts, locking, and display modes.\n\ \n", - si->version); + si->version, year); fprintf (stdout, "\ Just getting started? Try this:\n\ \n\ @@ -271,7 +305,7 @@ xscreensaver %s, copyright (c) 1991-2003 by Jamie Zawinski \n\ \n\ For updates, online manual, and FAQ, please see the web page:\n\ \n\ - http://www.jwz.org/xscreensaver/\n\ + https://www.jwz.org/xscreensaver/\n\ \n"); fflush (stdout); @@ -280,17 +314,32 @@ xscreensaver %s, copyright (c) 1991-2003 by Jamie Zawinski \n\ } +Bool in_signal_handler_p = 0; /* I hate C so much... */ + char * -timestring (void) +timestring (time_t when) { - time_t now = time ((time_t *) 0); - char *str = (char *) ctime (&now); - char *nl = (char *) strchr (str, '\n'); - if (nl) *nl = 0; /* take off that dang newline */ - return str; + if (in_signal_handler_p) + { + /* Turns out that ctime() and even localtime_r() call malloc() on Linux! + So we can't call them from inside SIGCHLD. WTF. + */ + static char buf[30]; + strcpy (buf, "... ... .. signal ...."); + return buf; + } + else + { + char *str, *nl; + if (! when) when = time ((time_t *) 0); + str = (char *) ctime (&when); + nl = (char *) strchr (str, '\n'); + if (nl) *nl = 0; /* take off that dang newline */ + return str; + } } -static Bool blurb_timestamp_p = False; /* kludge */ +static Bool blurb_timestamp_p = True; /* kludge */ const char * blurb (void) @@ -300,7 +349,7 @@ blurb (void) else { static char buf[255]; - char *ct = timestring(); + char *ct = timestring(0); int n = strlen(progname); if (n > 100) n = 99; strncpy(buf, progname, n); @@ -361,27 +410,30 @@ saver_ehandler (Display *dpy, XErrorEvent *error) } else { +#ifdef __GNUC__ + __extension__ /* don't warn about "string length is greater than the + length ISO C89 compilers are required to support". */ +#endif fprintf (real_stderr, - "#######################################" - "#######################################\n\n"); - fprintf (real_stderr, + "#######################################################################\n" + "\n" " If at all possible, please re-run xscreensaver with the command\n" - " line arguments `-sync -verbose -no-capture', and reproduce this\n" + " line arguments `-sync -verbose -log log.txt', and reproduce this\n" " bug. That will cause xscreensaver to dump a `core' file to the\n" " current directory. Please include the stack trace from that core\n" - " file in your bug report. *DO NOT* mail the core file itself!\n" - " That won't work.\n"); - fprintf (real_stderr, + " file in your bug report. *DO NOT* mail the core file itself! That\n" + " won't work. A \"log.txt\" file will also be written. Please *do*\n" + " include the complete \"log.txt\" file with your bug report.\n" "\n" - " http://www.jwz.org/xscreensaver/bugs.html explains how to create\n" + " https://www.jwz.org/xscreensaver/bugs.html explains how to create\n" " the most useful bug reports, and how to examine core files.\n" "\n" " The more information you can provide, the better. But please\n" " report this bug, regardless!\n" + "\n" + "#######################################################################\n" + "\n" "\n"); - fprintf (real_stderr, - "#######################################" - "#######################################\n\n"); saver_exit (si, -1, 0); } @@ -443,8 +495,8 @@ startup_ehandler (String name, String type, String class, } fprintf (stderr, "\n" - " http://www.jwz.org/xscreensaver/faq.html\n" - " http://www.jwz.org/xscreensaver/man.html\n" + " https://www.jwz.org/xscreensaver/faq.html\n" + " https://www.jwz.org/xscreensaver/man.html\n" "\n"); fflush (stderr); @@ -478,7 +530,7 @@ set_version_string (saver_info *si, int *argc, char **argv) *s = '_'; } - si->version = (char *) malloc (5); + si->version = (char *) malloc (32); memcpy (si->version, screensaver_id + 17, 4); si->version [4] = 0; } @@ -557,6 +609,19 @@ lock_initialization (saver_info *si, int *argc, char **argv) } } + /* Like MacOS, locking under Wayland's embedded X11 server does not work. + (X11 grabs don't work because the Wayland window manager lives at a + higher level than the X11 emulation layer.) + */ + if (!si->locking_disabled_p && getenv ("WAYLAND_DISPLAY")) + { + si->locking_disabled_p = True; + si->nolock_reason = "Cannot lock securely under Wayland"; + } + + if (si->prefs.debug_p) /* But allow locking anyway in debug mode. */ + si->locking_disabled_p = False; + #endif /* NO_LOCKING */ } @@ -613,6 +678,7 @@ connect_to_server (saver_info *si, int *argc, char **argv) XA_XSETROOT_ID = XInternAtom (si->dpy, "_XSETROOT_ID", False); XA_ESETROOT_PMAP_ID = XInternAtom (si->dpy, "ESETROOT_PMAP_ID", False); XA_XROOTPMAP_ID = XInternAtom (si->dpy, "_XROOTPMAP_ID", False); + XA_NET_WM_USER_TIME = XInternAtom (si->dpy, "_NET_WM_USER_TIME", False); XA_ACTIVATE = XInternAtom (si->dpy, "ACTIVATE", False); XA_DEACTIVATE = XInternAtom (si->dpy, "DEACTIVATE", False); XA_RESTART = XInternAtom (si->dpy, "RESTART", False); @@ -684,14 +750,7 @@ process_command_line (saver_info *si, int *argc, char **argv) You control a running xscreensaver process by sending it messages\n\ with `xscreensaver-demo' or `xscreensaver-command'.\n\ . See the man pages for details, or check the web page:\n\ - http://www.jwz.org/xscreensaver/\n\n"); - - /* Since version 1.21 renamed the "-lock" option to "-lock-mode", - suggest that explicitly. */ - if (!strcmp (s, "-lock")) - fprintf (stderr, "\ - Or perhaps you meant either the \"-lock-mode\" or the\n\ - \"-lock-timeout \" options to xscreensaver?\n\n"); + https://www.jwz.org/xscreensaver/\n\n"); } exit (1); @@ -708,20 +767,28 @@ print_banner (saver_info *si) { saver_preferences *p = &si->prefs; + char *s, year[5]; + s = strchr (screensaver_id, '-'); + s = strrchr (s, '-'); + s++; + strncpy (year, s, 4); + year[4] = 0; + /* This resource gets set some time before the others, so that we know whether to print the banner (and so that the banner gets printed before any resource-database-related error messages.) */ - p->verbose_p = (p->debug_p || get_boolean_resource ("verbose", "Boolean")); + p->verbose_p = (p->debug_p || + get_boolean_resource (si->dpy, "verbose", "Boolean")); /* Ditto, for the locking_disabled_p message. */ - p->lock_p = get_boolean_resource ("lock", "Boolean"); + p->lock_p = get_boolean_resource (si->dpy, "lock", "Boolean"); if (p->verbose_p) fprintf (stderr, - "%s %s, copyright (c) 1991-2003 " + "%s %s, copyright (c) 1991-%s " "by Jamie Zawinski .\n", - progname, si->version); + progname, si->version, year); if (p->debug_p) fprintf (stderr, "\n" @@ -737,6 +804,17 @@ print_banner (saver_info *si) "\n", blurb()); + if (p->verbose_p && decrepit_p ()) + fprintf (stderr, "\n" + "*************************************" + "**************************************\n" + "%s: Warning: this version of xscreensaver is VERY OLD!\n" + "%s: Please upgrade! https://www.jwz.org/xscreensaver/\n" + "*************************************" + "**************************************\n" + "\n", + blurb(), blurb()); + if (p->verbose_p) { if (!si->uid_message || !*si->uid_message) @@ -781,177 +859,53 @@ print_lock_failure_banner (saver_info *si) } +/* called from screens.c so that all the Xt crud is here. */ +void +initialize_screen_root_widget (saver_screen_info *ssi) +{ + saver_info *si = ssi->global; + if (ssi->toplevel_shell) + XtDestroyWidget (ssi->toplevel_shell); + ssi->toplevel_shell = + XtVaAppCreateShell (progname, progclass, + applicationShellWidgetClass, + si->dpy, + XtNscreen, ssi->screen, + XtNvisual, ssi->current_visual, + XtNdepth, visual_depth (ssi->screen, + ssi->current_visual), + NULL); +} + + /* Examine all of the display's screens, and populate the `saver_screen_info' structures. Make sure this is called after hack_environment() sets $PATH. */ static void initialize_per_screen_info (saver_info *si, Widget toplevel_shell) { - Bool found_any_writable_cells = False; int i; -# ifdef HAVE_XINERAMA - { - int event, error; - si->xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) && - XineramaIsActive (si->dpy)); - } + update_screen_layout (si); - if (si->xinerama_p && ScreenCount (si->dpy) != 1) - { - si->xinerama_p = False; - if (si->prefs.verbose_p) - fprintf (stderr, - "%s: Xinerama AND %d screens? Disabling Xinerama support!\n", - blurb(), ScreenCount(si->dpy)); - } - - if (si->xinerama_p) - { - XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &si->nscreens); - if (!xsi) - si->xinerama_p = False; - else - { - si->screens = (saver_screen_info *) - calloc(sizeof(saver_screen_info), si->nscreens); - for (i = 0; i < si->nscreens; i++) - { - si->screens[i].x = xsi[i].x_org; - si->screens[i].y = xsi[i].y_org; - si->screens[i].width = xsi[i].width; - si->screens[i].height = xsi[i].height; - } - XFree (xsi); - } - si->default_screen = &si->screens[0]; - si->default_screen->real_screen_p = True; - } -# endif /* !HAVE_XINERAMA */ - - if (!si->xinerama_p) - { - si->nscreens = ScreenCount(si->dpy); - si->screens = (saver_screen_info *) - calloc(sizeof(saver_screen_info), si->nscreens); - si->default_screen = &si->screens[DefaultScreen(si->dpy)]; - - for (i = 0; i < si->nscreens; i++) - { - saver_screen_info *ssi = &si->screens[i]; - ssi->width = DisplayWidth (si->dpy, i); - ssi->height = DisplayHeight (si->dpy, i); - ssi->real_screen_p = True; - ssi->real_screen_number = i; - } - } - - - /* In "quad mode", we use the Xinerama code to pretend that there are 4 - screens for every physical screen, and run four times as many hacks... - */ - if (si->prefs.quad_p) - { - int ns2 = si->nscreens * 4; - saver_screen_info *ssi2 = (saver_screen_info *) - calloc(sizeof(saver_screen_info), ns2); - - for (i = 0; i < si->nscreens; i++) - { - saver_screen_info *old = &si->screens[i]; - - if (si->prefs.debug_p) old->width = old->width / 2; - - ssi2[i*4 ] = *old; - ssi2[i*4+1] = *old; - ssi2[i*4+2] = *old; - ssi2[i*4+3] = *old; - - ssi2[i*4 ].width /= 2; - ssi2[i*4 ].height /= 2; - - ssi2[i*4+1].x += ssi2[i*4 ].width; - ssi2[i*4+1].width -= ssi2[i*4 ].width; - ssi2[i*4+1].height /= 2; - - ssi2[i*4+2].y += ssi2[i*4 ].height; - ssi2[i*4+2].width /= 2; - ssi2[i*4+2].height -= ssi2[i*4 ].height; - - ssi2[i*4+3].x += ssi2[i*4+2].width; - ssi2[i*4+3].y += ssi2[i*4+2].height; - ssi2[i*4+3].width -= ssi2[i*4+2].width; - ssi2[i*4+3].height -= ssi2[i*4+2].height; - - ssi2[i*4+1].real_screen_p = False; - ssi2[i*4+2].real_screen_p = False; - ssi2[i*4+3].real_screen_p = False; - } - - si->nscreens = ns2; - free (si->screens); - si->screens = ssi2; - si->default_screen = &si->screens[DefaultScreen(si->dpy) * 4]; - si->xinerama_p = True; - } - - /* finish initializing the screens. + /* Check to see whether fading is ever possible -- if any of the + screens on the display has a PseudoColor visual, then fading can + work (on at least some screens.) If no screen has a PseudoColor + visual, then don't bother ever trying to fade, because it will + just cause a delay without causing any visible effect. */ for (i = 0; i < si->nscreens; i++) { saver_screen_info *ssi = &si->screens[i]; - ssi->global = si; - - ssi->number = i; - ssi->screen = ScreenOfDisplay (si->dpy, ssi->real_screen_number); - - if (!si->xinerama_p) + if (has_writable_cells (ssi->screen, ssi->current_visual) || + get_visual (ssi->screen, "PseudoColor", True, False) || + get_visual (ssi->screen, "GrayScale", True, False)) { - ssi->width = WidthOfScreen (ssi->screen); - ssi->height = HeightOfScreen (ssi->screen); + si->fading_possible_p = True; + break; } - - /* Note: we can't use the resource ".visual" because Xt is SO FUCKED. */ - ssi->default_visual = - get_visual_resource (ssi->screen, "visualID", "VisualID", False); - - ssi->current_visual = ssi->default_visual; - ssi->current_depth = visual_depth (ssi->screen, ssi->current_visual); - - /* Execute a subprocess to find the GL visual. */ - ssi->best_gl_visual = get_best_gl_visual (ssi); - - if (ssi == si->default_screen) - /* Since this is the default screen, use the one already created. */ - ssi->toplevel_shell = toplevel_shell; - else - /* Otherwise, each screen must have its own unmapped root widget. */ - ssi->toplevel_shell = - XtVaAppCreateShell (progname, progclass, applicationShellWidgetClass, - si->dpy, - XtNscreen, ssi->screen, - XtNvisual, ssi->current_visual, - XtNdepth, visual_depth (ssi->screen, - ssi->current_visual), - NULL); - - if (! found_any_writable_cells) - { - /* Check to see whether fading is ever possible -- if any of the - screens on the display has a PseudoColor visual, then fading can - work (on at least some screens.) If no screen has a PseudoColor - visual, then don't bother ever trying to fade, because it will - just cause a delay without causing any visible effect. - */ - if (has_writable_cells (ssi->screen, ssi->current_visual) || - get_visual (ssi->screen, "PseudoColor", True, False) || - get_visual (ssi->screen, "GrayScale", True, False)) - found_any_writable_cells = True; - } } - si->fading_possible_p = found_any_writable_cells; - #ifdef HAVE_XF86VMODE_GAMMA si->fading_possible_p = True; /* if we can gamma fade, go for it */ #endif @@ -970,26 +924,41 @@ initialize_server_extensions (saver_info *si) Bool server_has_sgi_saver_extension_p = False; Bool server_has_mit_saver_extension_p = False; Bool system_has_proc_interrupts_p = False; + Bool server_has_xinput_extension_p = False; const char *piwhy = 0; si->using_xidle_extension = p->use_xidle_extension; si->using_sgi_saver_extension = p->use_sgi_saver_extension; si->using_mit_saver_extension = p->use_mit_saver_extension; si->using_proc_interrupts = p->use_proc_interrupts; + si->using_xinput_extension = p->use_xinput_extension; #ifdef HAVE_XIDLE_EXTENSION - server_has_xidle_extension_p = query_xidle_extension (si); + { + int ev, er; + server_has_xidle_extension_p = XidleQueryExtension (si->dpy, &ev, &er); + } #endif #ifdef HAVE_SGI_SAVER_EXTENSION - server_has_sgi_saver_extension_p = query_sgi_saver_extension (si); + server_has_sgi_saver_extension_p = + XScreenSaverQueryExtension (si->dpy, + &si->sgi_saver_ext_event_number, + &si->sgi_saver_ext_error_number); #endif #ifdef HAVE_MIT_SAVER_EXTENSION - server_has_mit_saver_extension_p = query_mit_saver_extension (si); + server_has_mit_saver_extension_p = + XScreenSaverQueryExtension (si->dpy, + &si->mit_saver_ext_event_number, + &si->mit_saver_ext_error_number); #endif #ifdef HAVE_PROC_INTERRUPTS system_has_proc_interrupts_p = query_proc_interrupts_available (si, &piwhy); #endif +#ifdef HAVE_XINPUT + server_has_xinput_extension_p = query_xinput_extension (si); +#endif + if (!server_has_xidle_extension_p) si->using_xidle_extension = False; else if (p->verbose_p) @@ -1025,14 +994,48 @@ initialize_server_extensions (saver_info *si) blurb()); } - /* These are incompatible (or at least, our support for them is...) */ - if (si->xinerama_p && si->using_mit_saver_extension) +#ifdef HAVE_RANDR + if (XRRQueryExtension (si->dpy, + &si->randr_event_number, &si->randr_error_number)) + { + int nscreens = ScreenCount (si->dpy); /* number of *real* screens */ + int i; + + si->using_randr_extension = TRUE; + + if (p->verbose_p) + fprintf (stderr, "%s: selecting RANDR events\n", blurb()); + for (i = 0; i < nscreens; i++) +# ifdef RRScreenChangeNotifyMask /* randr.h 1.5, 2002/09/29 */ + XRRSelectInput (si->dpy, RootWindow (si->dpy, i), + RRScreenChangeNotifyMask); +# else /* !RRScreenChangeNotifyMask */ /* Xrandr.h 1.4, 2001/06/07 */ + XRRScreenChangeSelectInput (si->dpy, RootWindow (si->dpy, i), True); +# endif /* !RRScreenChangeNotifyMask */ + } +# endif /* HAVE_RANDR */ + +#ifdef HAVE_XINPUT + if (!server_has_xinput_extension_p) + si->using_xinput_extension = False; + else { - si->using_mit_saver_extension = False; + if (si->using_xinput_extension) + init_xinput_extension(si); + if (p->verbose_p) - fprintf (stderr, "%s: Xinerama in use: disabling MIT-SCREEN-SAVER.\n", - blurb()); + { + if (si->using_xinput_extension) + fprintf (stderr, + "%s: selecting events from %d XInputExtension devices.\n", + blurb(), si->num_xinput_devices); + else + fprintf (stderr, + "%s: not using XInputExtension.\n", + blurb()); + } } +#endif if (!system_has_proc_interrupts_p) { @@ -1055,6 +1058,26 @@ initialize_server_extensions (saver_info *si) } +#ifdef DEBUG_MULTISCREEN +static void +debug_multiscreen_timer (XtPointer closure, XtIntervalId *id) +{ + saver_info *si = (saver_info *) closure; + saver_preferences *p = &si->prefs; + if (update_screen_layout (si)) + { + if (p->verbose_p) + { + fprintf (stderr, "%s: new layout:\n", blurb()); + describe_monitor_layout (si); + } + resize_screensaver_window (si); + } + XtAppAddTimeOut (si->app, 1000*4, debug_multiscreen_timer, (XtPointer) si); +} +#endif /* DEBUG_MULTISCREEN */ + + /* For the case where we aren't using an server extensions, select user events on all the existing windows, and launch timers to select events on newly-created windows as well. @@ -1107,6 +1130,10 @@ select_events (saver_info *si) if (p->verbose_p) fprintf (stderr, " done.\n"); + +# ifdef DEBUG_MULTISCREEN + if (p->debug_p) debug_multiscreen_timer ((XtPointer) si, 0); +# endif } @@ -1120,7 +1147,7 @@ maybe_reload_init_file (saver_info *si) fprintf (stderr, "%s: file \"%s\" has changed, reloading.\n", blurb(), init_file_name()); - load_init_file (p); + load_init_file (si->dpy, p); /* If a server extension is in use, and p->timeout has changed, we need to inform the server of the new timeout. */ @@ -1131,6 +1158,7 @@ maybe_reload_init_file (saver_info *si) sync_server_dpms_settings (si->dpy, (p->dpms_enabled_p && p->mode != DONT_BLANK), + p->dpms_quickoff_p, p->dpms_standby / 1000, p->dpms_suspend / 1000, p->dpms_off / 1000, @@ -1153,6 +1181,7 @@ main_loop (saver_info *si) { saver_preferences *p = &si->prefs; Bool ok_to_unblank; + int i; while (1) { @@ -1169,10 +1198,10 @@ main_loop (saver_info *si) { if (si->demoing_p) fprintf (stderr, "%s: demoing %d at %s.\n", blurb(), - si->selection_mode, timestring()); + si->selection_mode, timestring(0)); else fprintf (stderr, "%s: blanking screen at %s.\n", blurb(), - timestring()); + timestring(0)); } maybe_reload_init_file (si); @@ -1181,15 +1210,38 @@ main_loop (saver_info *si) { if (p->verbose_p) fprintf (stderr, "%s: idle with blanking disabled at %s.\n", - blurb(), timestring()); + blurb(), timestring(0)); /* Go around the loop and wait for the next bout of idleness, or for the init file to change, or for a remote command to come in, or something. + + But, if locked_p is true, go ahead. This can only happen + if we're in "disabled" mode but a "lock" clientmessage came + in: in that case, we should go ahead and blank/lock the screen. */ - continue; + if (!si->locked_p) + continue; + } + + /* Since we're about to blank the screen, kill the de-race timer, + if any. It might still be running if we have unblanked and then + re-blanked in a short period (e.g., when using the "next" button + in xscreensaver-demo.) + */ + if (si->de_race_id) + { + if (p->verbose_p) + fprintf (stderr, "%s: stopping de-race timer (%d remaining.)\n", + blurb(), si->de_race_ticks); + XtRemoveTimeOut (si->de_race_id); + si->de_race_id = 0; } + + /* Now, try to blank. + */ + if (! blank_screen (si)) { /* We were unable to grab either the keyboard or mouse. @@ -1199,22 +1251,65 @@ main_loop (saver_info *si) we would never be able to un-blank it! We would never see any events, and the display would be wedged. + In particular, without that keyboard grab, we will be + unable to ever read keypresses on the unlock dialog. + You can't unlock if you can't type your password. + So, just go around the loop again and wait for the - next bout of idleness. + next bout of idleness. (If the user remains idle, we + will next try to blank the screen again in no more than + 60 seconds.) */ + Time retry = 60 * 1000; + if (p->timeout < retry) + retry = p->timeout; - fprintf (stderr, + if (p->debug_p) + { + fprintf (stderr, + "%s: DEBUG MODE: unable to grab -- BLANKING ANYWAY.\n", + blurb()); + } + else + { + fprintf (stderr, "%s: unable to grab keyboard or mouse! Blanking aborted.\n", - blurb()); - continue; + blurb()); + + /* Since we were unable to blank, clearly we're not locked, + but we might have been prematurely marked as locked by + the LOCK ClientMessage. */ + if (si->locked_p) + set_locked_p (si, False); + + schedule_wakeup_event (si, retry, p->debug_p); + continue; + } } - kill_screenhack (si); + for (i = 0; i < si->nscreens; i++) + kill_screenhack (&si->screens[i]); - if (!si->throttled_p) - spawn_screenhack (si, True); - else if (p->verbose_p) + raise_window (si, True, True, False); + if (si->throttled_p) fprintf (stderr, "%s: not launching hack (throttled.)\n", blurb()); + else + for (i = 0; i < si->nscreens; i++) + spawn_screenhack (&si->screens[i]); + + /* If we are blanking only, optionally power down monitor right now. */ + if (p->mode == BLANK_ONLY && + p->dpms_enabled_p && + p->dpms_quickoff_p) + { + sync_server_dpms_settings (si->dpy, True, + p->dpms_quickoff_p, + p->dpms_standby / 1000, + p->dpms_suspend / 1000, + p->dpms_off / 1000, + False); + monitor_power_on (si, False); + } /* Don't start the cycle timer in demo mode. */ if (!si->demoing_p && p->cycle) @@ -1285,14 +1380,16 @@ main_loop (saver_info *si) was_locked = True; si->dbox_up_p = True; - suspend_screenhack (si, True); + for (i = 0; i < si->nscreens; i++) + suspend_screenhack (&si->screens[i], True); /* suspend */ XUndefineCursor (si->dpy, ssi->screensaver_window); ok_to_unblank = unlock_p (si); si->dbox_up_p = False; XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor); - suspend_screenhack (si, False); /* resume */ + for (i = 0; i < si->nscreens; i++) + suspend_screenhack (&si->screens[i], False); /* resume */ if (!ok_to_unblank && !screenhack_running_p (si)) @@ -1315,10 +1412,11 @@ main_loop (saver_info *si) if (p->verbose_p) fprintf (stderr, "%s: unblanking screen at %s.\n", - blurb(), timestring ()); + blurb(), timestring (0)); /* Kill before unblanking, to stop drawing as soon as possible. */ - kill_screenhack (si); + for (i = 0; i < si->nscreens; i++) + kill_screenhack (&si->screens[i]); unblank_screen (si); set_locked_p (si, False); @@ -1348,52 +1446,10 @@ main_loop (saver_info *si) si->lock_id = 0; } - /* It's possible that a race condition could have led to the saver - window being unexpectedly still mapped. This can happen like so: - - - screen is blanked - - hack is launched - - that hack tries to grab a screen image (it does this by - first unmapping the saver window, then remapping it.) - - hack unmaps window - - hack waits - - user becomes active - - hack re-maps window (*) - - driver kills subprocess - - driver unmaps window (**) - - The race is that (*) might have been sent to the server before - the client process was killed, but, due to scheduling randomness, - might not have been received by the server until after (**). - In other words, (*) and (**) might happen out of order, meaning - the driver will unmap the window, and then after that, the - recently-dead client will re-map it. This leaves the user - locked out (it looks like a desktop, but it's not!) - - To avoid this: after un-blanking the screen, sleep for a second, - and then really make sure the window is unmapped. - */ - { - int i; - XSync (si->dpy, False); - sleep (1); - for (i = 0; i < si->nscreens; i++) - { - saver_screen_info *ssi = &si->screens[i]; - Window w = ssi->screensaver_window; - XWindowAttributes xgwa; - XGetWindowAttributes (si->dpy, w, &xgwa); - if (xgwa.map_state != IsUnmapped) - { - if (p->verbose_p) - fprintf (stderr, - "%s: %d: client race! emergency unmap 0x%lx.\n", - blurb(), i, (unsigned long) w); - XUnmapWindow (si->dpy, w); - } - } - XSync (si->dpy, False); - } + /* Since we're unblanked now, break race conditions and make + sure we stay that way (see comment in timers.c.) */ + if (! si->de_race_id) + de_race_timer ((XtPointer) si, 0); } } @@ -1407,8 +1463,36 @@ main (int argc, char **argv) saver_info the_si; saver_info *si = &the_si; saver_preferences *p = &si->prefs; + struct passwd *spasswd; int i; + /* It turns out that if we do setlocale (LC_ALL, "") here, people + running in Japanese locales get font craziness on the password + dialog, presumably because it is displaying Japanese characters + in a non-Japanese font. However, if we don't call setlocale() + at all, then XLookupString() never returns multi-byte UTF-8 + characters when people type non-Latin1 characters on the + keyboard. + + The current theory (and at this point, I'm really guessing!) is + that using LC_CTYPE instead of LC_ALL will make XLookupString() + behave usefully, without having the side-effect of screwing up + the fonts on the unlock dialog. + + See https://bugs.launchpad.net/ubuntu/+source/xscreensaver/+bug/671923 + from comment #20 onward. + + -- jwz, 24-Sep-2011 + */ +#ifdef ENABLE_NLS + if (!setlocale (LC_CTYPE, "")) + fprintf (stderr, "%s: warning: could not set default locale\n", + progname); + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + textdomain (GETTEXT_PACKAGE); +#endif /* ENABLE_NLS */ + memset(si, 0, sizeof(*si)); global_si_kludge = si; /* I hate C so much... */ @@ -1422,11 +1506,26 @@ main (int argc, char **argv) privileged_initialization (si, &argc, argv); hack_environment (si); + spasswd = getpwuid(getuid()); + if (!spasswd) + { + fprintf(stderr, "Could not figure out who the current user is!\n"); + return 1; + } + + si->user = strdup(spasswd->pw_name ? spasswd->pw_name : "(unknown)"); + +# ifndef NO_LOCKING + si->unlock_cb = gui_auth_conv; + si->auth_finished_cb = auth_finished_cb; +# endif /* !NO_LOCKING */ + shell = connect_to_server (si, &argc, argv); process_command_line (si, &argc, argv); + stderr_log_file (si); print_banner (si); - load_init_file (p); /* must be before initialize_per_screen_info() */ + load_init_file(si->dpy, p); /* must be before initialize_per_screen_info() */ blurb_timestamp_p = p->timestamp_p; /* kludge */ initialize_per_screen_info (si, shell); /* also sets si->fading_possible_p */ @@ -1453,7 +1552,7 @@ main (int argc, char **argv) if (p->verbose_p) analyze_display (si); initialize_server_extensions (si); - si->blank_time = time ((time_t) 0); /* must be before ..._window */ + si->blank_time = time ((time_t *) 0); /* must be before ..._window */ initialize_screensaver_window (si); select_events (si); @@ -1463,6 +1562,7 @@ main (int argc, char **argv) sync_server_dpms_settings (si->dpy, (p->dpms_enabled_p && p->mode != DONT_BLANK), + p->dpms_quickoff_p, p->dpms_standby / 1000, p->dpms_suspend / 1000, p->dpms_off / 1000, @@ -1595,10 +1695,23 @@ clientmessage_response (saver_info *si, Window w, Bool error, static void bogus_clientmessage_warning (saver_info *si, XEvent *event) { +#if 0 /* Oh, fuck it. GNOME likes to spew random ClientMessages at us + all the time. This is presumably indicative of an error in + the sender of that ClientMessage: if we're getting it and + ignoring it, then it's not reaching the intended recipient. + But people complain to me about this all the time ("waaah! + xscreensaver is printing to it's stderr and that gets my + panties all in a bunch!") And I'm sick of hearing about it. + So we'll just ignore these messages and let GNOME go right + ahead and continue to stumble along in its malfunction. + */ + + saver_preferences *p = &si->prefs; char *str = XGetAtomName_safe (si->dpy, event->xclient.message_type); Window w = event->xclient.window; char wdesc[255]; int screen = 0; + Bool root_p = False; *wdesc = 0; for (screen = 0; screen < si->nscreens; screen++) @@ -1610,9 +1723,19 @@ bogus_clientmessage_warning (saver_info *si, XEvent *event) else if (w == RootWindow (si->dpy, screen)) { strcpy (wdesc, "root"); + root_p = True; break; } + /* If this ClientMessage was sent to the real root window instead of to the + xscreensaver window, then it might be intended for someone else who is + listening on the root window (e.g., the window manager). So only print + the warning if: we are in debug mode; or if the bogus message was + actually sent to one of the xscreensaver-created windows. + */ + if (root_p && !p->debug_p) + return; + if (!*wdesc) { XErrorHandler old_handler; @@ -1643,8 +1766,11 @@ bogus_clientmessage_warning (saver_info *si, XEvent *event) fprintf (stderr, "%s: %d: for window 0x%lx (%s)\n", blurb(), screen, (unsigned long) w, wdesc); if (str) XFree (str); + +#endif /* 0 */ } + Bool handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) { @@ -1701,29 +1827,47 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) } else if (type == XA_DEACTIVATE) { - if (! until_idle_p) - { - if (si->throttled_p && p->verbose_p) - fprintf (stderr, "%s: unthrottled.\n", blurb()); - si->throttled_p = False; +# if 0 + /* When -deactivate is received while locked, pop up the dialog box + instead of just ignoring it. Some people depend on this behavior + to be able to unlock by using e.g. a fingerprint reader without + also having to click the mouse first. + */ + if (si->locked_p) + { + clientmessage_response(si, window, False, + "DEACTIVATE ClientMessage received while locked: ignored.", + "screen is locked."); + } + else +# endif /* 0 */ + { + if (! until_idle_p) + { + if (si->throttled_p && p->verbose_p) + fprintf (stderr, "%s: unthrottled.\n", blurb()); + si->throttled_p = False; - clientmessage_response(si, window, False, - "DEACTIVATE ClientMessage received.", - "deactivating."); - if (si->using_mit_saver_extension || si->using_sgi_saver_extension) - { - XForceScreenSaver (si->dpy, ScreenSaverReset); - return False; - } - else - { - return True; - } - } - clientmessage_response(si, window, False, - "ClientMessage DEACTIVATE received while inactive: resetting idle timer.", - "not active: idle timer reset."); - reset_timers (si); + clientmessage_response(si, window, False, + "DEACTIVATE ClientMessage received.", + "deactivating."); + if (si->using_mit_saver_extension || + si->using_sgi_saver_extension) + { + XForceScreenSaver (si->dpy, ScreenSaverReset); + return False; + } + else + { + return True; + } + } + clientmessage_response(si, window, False, + "ClientMessage DEACTIVATE received while inactive: " + "resetting idle timer.", + "not active: idle timer reset."); + reset_timers (si); + } } else if (type == XA_CYCLE) { @@ -1819,8 +1963,10 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) "exiting."); if (! until_idle_p) { + int i; + for (i = 0; i < si->nscreens; i++) + kill_screenhack (&si->screens[i]); unblank_screen (si); - kill_screenhack (si); XSync (si->dpy, False); } saver_exit (si, 0, 0); @@ -1842,8 +1988,10 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) "restarting."); if (! until_idle_p) { + int i; + for (i = 0; i < si->nscreens; i++) + kill_screenhack (&si->screens[i]); unblank_screen (si); - kill_screenhack (si); XSync (si->dpy, False); } @@ -1858,7 +2006,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) else if (type == XA_DEMO) { long arg = event->xclient.data.l[1]; - Bool demo_one_hack_p = (arg == 300); + Bool demo_one_hack_p = (arg == 5000); if (demo_one_hack_p) { @@ -1906,11 +2054,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) "not compiled with support for locking.", "locking not enabled."); #else /* !NO_LOCKING */ - if (p->mode == DONT_BLANK) - clientmessage_response(si, window, True, - "LOCK ClientMessage received in DONT_BLANK mode.", - "screen blanking is currently disabled."); - else if (si->locking_disabled_p) + if (si->locking_disabled_p) clientmessage_response (si, window, True, "LOCK ClientMessage received, but locking is disabled.", "locking not enabled."); @@ -1926,7 +2070,16 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) : "locking."); sprintf (buf, "LOCK ClientMessage received; %s", response); clientmessage_response (si, window, False, buf, response); + + /* Note that this leaves things in a slightly inconsistent state: + we are blanked but not locked. And blanking might actually + fail if we can't get the grab. */ set_locked_p (si, True); + + /* Have to set the time or xscreensaver-command doesn't + report the LOCK state change. */ + si->blank_time = time ((time_t *) 0); + si->selection_mode = 0; si->demoing_p = False; @@ -1954,6 +2107,12 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) } else if (type == XA_THROTTLE) { + /* The THROTTLE command is deprecated -- it predates the XDPMS + extension. Instead of using -throttle, users should instead + just power off the monitor (e.g., "xset dpms force off".) + In a few minutes, xscreensaver will notice that the monitor + is off, and cease running hacks. + */ if (si->throttled_p) clientmessage_response (si, window, True, "THROTTLE ClientMessage received, but " @@ -2039,88 +2198,122 @@ analyze_display (saver_info *si) { int i, j; static struct { - const char *name; const char *desc; Bool useful_p; + const char *name; const char *desc; + Bool useful_p; + Status (*version_fn) (Display *, int *majP, int *minP); } exts[] = { { "SCREEN_SAVER", /* underscore */ "SGI Screen-Saver", # ifdef HAVE_SGI_SAVER_EXTENSION - True + True, 0 # else - False + False, 0 # endif }, { "SCREEN-SAVER", /* dash */ "SGI Screen-Saver", # ifdef HAVE_SGI_SAVER_EXTENSION - True + True, 0 # else - False + False, 0 # endif }, { "MIT-SCREEN-SAVER", "MIT Screen-Saver", # ifdef HAVE_MIT_SAVER_EXTENSION - True + True, XScreenSaverQueryVersion # else - False + False, 0 # endif }, { "XIDLE", "XIdle", # ifdef HAVE_XIDLE_EXTENSION - True + True, 0 # else - False + False, 0 # endif }, { "SGI-VIDEO-CONTROL", "SGI Video-Control", # ifdef HAVE_SGI_VC_EXTENSION - True + True, XSGIvcQueryVersion # else - False + False, 0 # endif }, { "READDISPLAY", "SGI Read-Display", # ifdef HAVE_READ_DISPLAY_EXTENSION - True + True, XReadDisplayQueryVersion # else - False + False, 0 # endif }, { "MIT-SHM", "Shared Memory", # ifdef HAVE_XSHM_EXTENSION - True + True, (Status (*) (Display*,int*,int*)) XShmQueryVersion /* 4 args */ # else - False + False, 0 # endif }, { "DOUBLE-BUFFER", "Double-Buffering", # ifdef HAVE_DOUBLE_BUFFER_EXTENSION - True + True, XdbeQueryExtension # else - False + False, 0 # endif }, { "DPMS", "Power Management", # ifdef HAVE_DPMS_EXTENSION - True + True, DPMSGetVersion # else - False + False, 0 # endif }, { "GLX", "GLX", # ifdef HAVE_GL - True + True, 0 # else - False + False, 0 # endif }, { "XFree86-VidModeExtension", "XF86 Video-Mode", # ifdef HAVE_XF86VMODE - True + True, XF86VidModeQueryVersion +# else + False, 0 +# endif + }, { "XC-VidModeExtension", "XC Video-Mode", +# ifdef HAVE_XF86VMODE + True, XF86VidModeQueryVersion +# else + False, 0 +# endif + }, { "XFree86-MISC", "XF86 Misc", +# ifdef HAVE_XF86MISCSETGRABKEYSSTATE + True, XF86MiscQueryVersion # else - False + False, 0 +# endif + }, { "XC-MISC", "XC Misc", +# ifdef HAVE_XF86MISCSETGRABKEYSSTATE + True, XF86MiscQueryVersion +# else + False, 0 # endif }, { "XINERAMA", "Xinerama", - True +# ifdef HAVE_XINERAMA + True, XineramaQueryVersion +# else + False, 0 +# endif + }, { "RANDR", "Resize-and-Rotate", +# ifdef HAVE_RANDR + True, XRRQueryVersion +# else + False, 0 +# endif + }, { "DRI", "DRI", + True, 0 + }, { "NV-CONTROL", "NVidia", + True, 0 + }, { "NV-GLX", "NVidia GLX", + True, 0 }, { "Apple-DRI", "Apple-DRI (XDarwin)", - True + True, 0 + }, { "XInputExtension", "XInput", + True, 0 }, }; - fprintf (stderr, "%s: running on display \"%s\" (%d %sscreen%s).\n", - blurb(), - DisplayString(si->dpy), - si->nscreens, - (si->xinerama_p ? "Xinerama " : ""), - (si->nscreens == 1 ? "" : "s")); + fprintf (stderr, "%s: running on display \"%s\"\n", blurb(), + DisplayString(si->dpy)); fprintf (stderr, "%s: vendor is %s, %d.\n", blurb(), ServerVendor(si->dpy), VendorRelease(si->dpy)); @@ -2129,18 +2322,31 @@ analyze_display (saver_info *si) { int op = 0, event = 0, error = 0; char buf [255]; - int j; + int maj = 0, min = 0; + int dummy1, dummy2, dummy3; + + /* Most of the extension version functions take 3 args, + writing results into args 2 and 3, but some take more. + We only ever care about the first two results, but we + pass in three extra pointers just in case. + */ + Status (*version_fn_2) (Display*,int*,int*,int*,int*,int*) = + (Status (*) (Display*,int*,int*,int*,int*,int*)) exts[i].version_fn; + if (!XQueryExtension (si->dpy, exts[i].name, &op, &event, &error)) continue; sprintf (buf, "%s: ", blurb()); - j = strlen (buf); strcat (buf, exts[i].desc); + + if (!version_fn_2) + ; + else if (version_fn_2 (si->dpy, &maj, &min, &dummy1, &dummy2, &dummy3)) + sprintf (buf+strlen(buf), " (%d.%d)", maj, min); + else + strcat (buf, " (unavailable)"); + if (!exts[i].useful_p) - { - int k = j + 18; - while (strlen (buf) < k) strcat (buf, " "); - strcat (buf, "<-- not supported at compile time!"); - } + strcat (buf, " (disabled at compile time)"); fprintf (stderr, "%s\n", buf); } @@ -2157,11 +2363,13 @@ analyze_display (saver_info *si) vi_in.screen = ssi->real_screen_number; vi_out = XGetVisualInfo (si->dpy, VisualScreenMask, &vi_in, &out_count); if (!vi_out) continue; - for (j = 0; j < out_count; j++) + for (j = 0; j < out_count; j++) { + if (vi_out[j].depth >= 32) continue; if (vi_out[j].class == PseudoColor) colormapped_depths |= (1 << vi_out[j].depth); else non_mapped_depths |= (1 << vi_out[j].depth); + } XFree ((char *) vi_out); if (colormapped_depths) @@ -2184,21 +2392,10 @@ analyze_display (saver_info *si) } } - if (si->xinerama_p) - { - fprintf (stderr, "%s: Xinerama layout:\n", blurb()); - for (i = 0; i < si->nscreens; i++) - { - saver_screen_info *ssi = &si->screens[i]; - fprintf (stderr, "%s: %c %d/%d: %dx%d+%d+%d\n", - blurb(), - (ssi->real_screen_p ? '+' : ' '), - ssi->number, ssi->real_screen_number, - ssi->width, ssi->height, ssi->x, ssi->y); - } - } + describe_monitor_layout (si); } + Bool display_is_on_console_p (saver_info *si) { @@ -2218,6 +2415,8 @@ display_is_on_console_p (saver_info *si) not_on_console = False; else if (gethostname (localname, sizeof (localname))) not_on_console = True; /* can't find hostname? */ + else if (!strncmp (dpyname, "/tmp/launch-", 12)) /* MacOS X launchd */ + not_on_console = False; else { /* We have to call gethostbyname() on the result of gethostname() @@ -2252,7 +2451,7 @@ display_is_on_console_p (saver_info *si) void check_for_leaks (const char *where) { -#ifdef HAVE_SBRK +#if defined(HAVE_SBRK) && defined(LEAK_PARANOIA) static unsigned long last_brk = 0; int b = (unsigned long) sbrk(0); if (last_brk && last_brk < b)