X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fxscreensaver.c;h=dd27cae56f679727d5b42ab9679266c120692942;hb=4361b69d3178d7fc98d0388f9a223af6c2651aba;hp=ed5bf3032fbc7e86b1c477c304ae22dc23491b7f;hpb=6f5482d73adb0165c0130bb47d852644ab0c4869;p=xscreensaver diff --git a/driver/xscreensaver.c b/driver/xscreensaver.c index ed5bf303..dd27cae5 100644 --- a/driver/xscreensaver.c +++ b/driver/xscreensaver.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1991-2012 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 @@ -93,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 @@ -271,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-2008 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\ @@ -290,7 +305,7 @@ xscreensaver %s, copyright (c) 1991-2008 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); @@ -302,7 +317,7 @@ xscreensaver %s, copyright (c) 1991-2008 by Jamie Zawinski \n\ Bool in_signal_handler_p = 0; /* I hate C so much... */ char * -timestring (void) +timestring (time_t when) { if (in_signal_handler_p) { @@ -315,9 +330,10 @@ timestring (void) } else { - time_t now = time ((time_t *) 0); - char *str = (char *) ctime (&now); - char *nl = (char *) strchr (str, '\n'); + 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; } @@ -333,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); @@ -409,7 +425,7 @@ saver_ehandler (Display *dpy, XErrorEvent *error) " 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" @@ -479,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); @@ -514,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; } @@ -593,6 +609,16 @@ 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; @@ -652,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); @@ -723,7 +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"); + https://www.jwz.org/xscreensaver/\n\n"); } exit (1); @@ -740,6 +767,13 @@ 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.) @@ -752,9 +786,9 @@ print_banner (saver_info *si) if (p->verbose_p) fprintf (stderr, - "%s %s, copyright (c) 1991-2008 " + "%s %s, copyright (c) 1991-%s " "by Jamie Zawinski .\n", - progname, si->version); + progname, si->version, year); if (p->debug_p) fprintf (stderr, "\n" @@ -770,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) @@ -1113,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, @@ -1152,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); @@ -1164,7 +1210,7 @@ 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 @@ -1230,6 +1276,12 @@ main_loop (saver_info *si) "%s: unable to grab keyboard or mouse! Blanking aborted.\n", 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; } @@ -1245,19 +1297,16 @@ main_loop (saver_info *si) for (i = 0; i < si->nscreens; i++) spawn_screenhack (&si->screens[i]); - /* If we are blanking only, optionally power down monitor right now. - To do this, we might need to temporarily re-enable DPMS first. - */ + /* 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 - ? (p->dpms_off / 1000) - : 0xFFFF), + p->dpms_off / 1000, False); monitor_power_on (si, False); } @@ -1363,7 +1412,7 @@ 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. */ for (i = 0; i < si->nscreens; i++) @@ -1503,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); @@ -1513,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, @@ -1777,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) { @@ -2002,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; @@ -2247,7 +2324,6 @@ analyze_display (saver_info *si) char buf [255]; int maj = 0, min = 0; int dummy1, dummy2, dummy3; - int j; /* Most of the extension version functions take 3 args, writing results into args 2 and 3, but some take more. @@ -2260,7 +2336,6 @@ analyze_display (saver_info *si) 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) @@ -2288,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)