X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fscreenhack.c;h=c3c8ad4aa713280b5809c91e3253c2a29d0ff540;hb=de041722414a2e31c1c04caa10aaec9d6952e9b4;hp=86789e4800a594caa72e63c0cd4dd1060f5ed7fc;hpb=c6b273ef7292ba10943694df1656b05203d7b62f;p=xscreensaver diff --git a/hacks/screenhack.c b/hacks/screenhack.c index 86789e48..c3c8ad4a 100644 --- a/hacks/screenhack.c +++ b/hacks/screenhack.c @@ -1,5 +1,5 @@ /* xscreensaver, Copyright (c) 1992, 1995, 1997, 1998 - * Jamie Zawinski + * 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 @@ -37,6 +37,8 @@ #include #include #include +#include +#include #ifdef __sgi # include /* for SgiUseSchemes() */ @@ -55,8 +57,17 @@ #include "version.h" #include "vroot.h" +#ifndef isupper +# define isupper(c) ((c) >= 'A' && (c) <= 'Z') +#endif +#ifndef _tolower +# define _tolower(c) ((c) - 'A' + 'a') +#endif + + char *progname; XrmDatabase db; +XtAppContext app; Bool mono_p; static XrmOptionDescRec default_options [] = { @@ -71,7 +82,7 @@ static XrmOptionDescRec default_options [] = { }; static char *default_defaults[] = { - "*root: false", + ".root: false", "*geometry: 600x480", /* this should be .geometry, but nooooo... */ "*mono: false", "*installColormap: false", @@ -115,6 +126,23 @@ merge_options (void) def_defaults_size * sizeof(*defaults)); memcpy (merged_defaults + def_defaults_size, defaults, (defaults_size + 1) * sizeof(*defaults)); + + /* This totally sucks. Xt should behave like this by default. + If the string in `defaults' looks like ".foo", change that + to "Progclass.foo". + */ + { + char **s; + for (s = merged_defaults; *s; s++) + if (**s == '.') + { + const char *oldr = *s; + char *newr = (char *) malloc(strlen(oldr) + strlen(progclass) + 3); + strcpy (newr, progclass); + strcat (newr, oldr); + *s = newr; + } + } } @@ -141,23 +169,181 @@ MapNotify_event_p (Display *dpy, XEvent *event, XPointer window) } -#ifdef USE_GL -extern Visual *get_gl_visual (Screen *, const char *, const char *); -#endif - #ifdef XLOCKMORE extern void pre_merge_options (void); #endif +static Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW; + +/* Dead-trivial event handling: exits if "q" or "ESC" are typed. + Exit if the WM_PROTOCOLS WM_DELETE_WINDOW ClientMessage is received. + */ +void +screenhack_handle_event (Display *dpy, XEvent *event) +{ + switch (event->xany.type) + { + case KeyPress: + { + KeySym keysym; + char c = 0; + XLookupString (&event->xkey, &c, 1, &keysym, 0); + if (c == 'q' || + c == 'Q' || + c == 3 || /* ^C */ + c == 27) /* ESC */ + exit (0); + else if (! (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)) + XBell (dpy, 0); /* beep for non-chord keys */ + } + break; + case ButtonPress: + XBell (dpy, 0); + break; + case ClientMessage: + { + if (event->xclient.message_type != XA_WM_PROTOCOLS) + { + char *s = XGetAtomName(dpy, event->xclient.message_type); + if (!s) s = "(null)"; + fprintf (stderr, "%s: unknown ClientMessage %s received!\n", + progname, s); + } + else if (event->xclient.data.l[0] != XA_WM_DELETE_WINDOW) + { + char *s1 = XGetAtomName(dpy, event->xclient.message_type); + char *s2 = XGetAtomName(dpy, event->xclient.data.l[0]); + if (!s1) s1 = "(null)"; + if (!s2) s2 = "(null)"; + fprintf (stderr, "%s: unknown ClientMessage %s[%s] received!\n", + progname, s1, s2); + } + else + { + exit (0); + } + } + break; + } +} + + +void +screenhack_handle_events (Display *dpy) +{ + while (XPending (dpy)) + { + XEvent event; + XNextEvent (dpy, &event); + screenhack_handle_event (dpy, &event); + } +} + + +static Visual * +pick_visual (Screen *screen) +{ +#ifdef USE_GL + /* If we're linking against GL (that is, this is the version of screenhack.o + that the GL hacks will use, which is different from the one that the + non-GL hacks will use) then try to pick the "best" visual by interrogating + the GL library instead of by asking Xlib. GL knows better. + */ + Visual *v = 0; + char *string = get_string_resource ("visualID", "VisualID"); + char *s; + + if (string) + for (s = string; *s; s++) + if (isupper (*s)) *s = _tolower (*s); + + if (!string || !*string || + !strcmp (string, "gl") || + !strcmp (string, "best") || + !strcmp (string, "color") || + !strcmp (string, "default")) + v = get_gl_visual (screen); /* from ../utils/visual-gl.c */ + + if (string) + free (string); + if (v) + return v; +#endif /* USE_GL */ + + return get_visual_resource (screen, "visualID", "VisualID", False); +} + + +/* Notice when the user has requested a different visual or colormap + on a pre-existing window (e.g., "-root -visual truecolor" or + "-window-id 0x2c00001 -install") and complain, since when drawing + on an existing window, we have no choice about these things. + */ +static void +visual_warning (Screen *screen, Window window, Visual *visual, Colormap cmap, + Bool window_p) +{ + char *visual_string = get_string_resource ("visualID", "VisualID"); + Visual *desired_visual = pick_visual (screen); + char win[100]; + char why[100]; + + if (window == RootWindowOfScreen (screen)) + strcpy (win, "root window"); + else + sprintf (win, "window 0x%x", (unsigned long) window); + + if (window_p) + sprintf (why, "-window-id 0x%x", (unsigned long) window); + else + strcpy (why, "-root"); + + if (visual_string && *visual_string) + { + char *s; + for (s = visual_string; *s; s++) + if (isupper (*s)) *s = _tolower (*s); + + if (!strcmp (visual_string, "default") || + !strcmp (visual_string, "default") || + !strcmp (visual_string, "best")) + /* don't warn about these, just silently DWIM. */ + ; + else if (visual != desired_visual) + { + fprintf (stderr, "%s: ignoring `-visual %s' because of `%s'.\n", + progname, visual_string, why); + fprintf (stderr, "%s: using %s's visual 0x%x.\n", + progname, win, XVisualIDFromVisual (visual)); + } + free (visual_string); + } + + if (visual == DefaultVisualOfScreen (screen) && + has_writable_cells (screen, visual) && + get_boolean_resource ("installColormap", "InstallColormap")) + { + fprintf (stderr, "%s: ignoring `-install' because of `%s'.\n", + progname, why); + fprintf (stderr, "%s: using %s's colormap 0x%x.\n", + progname, win, (unsigned long) cmap); + } + +# ifdef USE_GL + if (!validate_gl_visual (stderr, screen, win, visual)) + exit (1); +# endif /* USE_GL */ +} + int main (int argc, char **argv) { - XtAppContext app; Widget toplevel; Display *dpy; Window window; + Screen *screen; Visual *visual; Colormap cmap; Bool root_p; @@ -187,16 +373,30 @@ main (int argc, char **argv) merged_options_size, &argc, argv, merged_defaults, 0, 0); dpy = XtDisplay (toplevel); + screen = XtScreen (toplevel); db = XtDatabase (dpy); + XtGetApplicationNameAndClass (dpy, &progname, &progclass); + + /* half-assed way of avoiding buffer-overrun attacks. */ + if (strlen (progname) >= 100) progname[100] = 0; + XSetErrorHandler (screenhack_ehandler); + XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False); + XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False); + { char *v = (char *) strdup(strchr(screensaver_id, ' ')); - char *s = (char *) strchr(v, ','); - *s = 0; - sprintf (version, "%s: from the XScreenSaver%s distribution.", - progclass, v); + char *s1, *s2, *s3, *s4; + s1 = (char *) strchr(v, ' '); s1++; + s2 = (char *) strchr(s1, ' '); + s3 = (char *) strchr(v, '('); s3++; + s4 = (char *) strchr(s3, ')'); + *s2 = 0; + *s4 = 0; + sprintf (version, "%s: from the XScreenSaver %s distribution (%s.)", + progclass, s1, s3); free(v); } @@ -209,7 +409,7 @@ main (int argc, char **argv) Bool help_p = !strcmp(argv[1], "-help"); fprintf (stderr, "%s\n", version); for (s = progclass; *s; s++) fprintf(stderr, " "); - fprintf (stderr, " http://people.netscape.com/jwz/xscreensaver/\n\n"); + fprintf (stderr, " http://www.jwz.org/xscreensaver/\n\n"); if (!help_p) fprintf(stderr, "Unrecognised option: %s\n", argv[1]); @@ -256,6 +456,7 @@ main (int argc, char **argv) XGetWindowAttributes (dpy, window, &xgwa); cmap = xgwa.colormap; visual = xgwa.visual; + visual_warning (screen, window, visual, cmap, True); } else if (root_p) { @@ -265,17 +466,17 @@ main (int argc, char **argv) XGetWindowAttributes (dpy, window, &xgwa); cmap = xgwa.colormap; visual = xgwa.visual; + visual_warning (screen, window, visual, cmap, False); } else { Boolean def_visual_p; - Screen *screen = XtScreen (toplevel); + visual = pick_visual (screen); -#ifdef USE_GL - visual = get_gl_visual (screen, "visualID", "VisualID"); -#else - visual = get_visual_resource (screen, "visualID", "VisualID", False); -#endif +# ifdef USE_GL + if (!validate_gl_visual (stderr, screen, "window", visual)) + exit (1); +# endif /* USE_GL */ if (toplevel->core.width <= 0) toplevel->core.width = 600; @@ -304,6 +505,7 @@ main (int argc, char **argv) XtNcolormap, cmap, XtNbackground, (Pixel) bg, XtNborderColor, (Pixel) bd, + XtNinput, True, /* for WM_HINTS */ 0); XtDestroyWidget (toplevel); toplevel = new; @@ -312,7 +514,10 @@ main (int argc, char **argv) } else { - XtVaSetValues (toplevel, XtNmappedWhenManaged, False, 0); + XtVaSetValues (toplevel, + XtNmappedWhenManaged, False, + XtNinput, True, /* for WM_HINTS */ + 0); XtRealizeWidget (toplevel); window = XtWindow (toplevel); @@ -342,6 +547,18 @@ main (int argc, char **argv) } XtVaSetValues(toplevel, XtNtitle, version, 0); + + /* For screenhack_handle_events(): select KeyPress, and + announce that we accept WM_DELETE_WINDOW. */ + { + XWindowAttributes xgwa; + XGetWindowAttributes (dpy, window, &xgwa); + XSelectInput (dpy, window, + xgwa.your_event_mask | KeyPressMask | ButtonPressMask); + XChangeProperty (dpy, window, XA_WM_PROTOCOLS, XA_ATOM, 32, + PropModeReplace, + (unsigned char *) &XA_WM_DELETE_WINDOW, 1); + } } if (!dont_clear) @@ -357,7 +574,13 @@ main (int argc, char **argv) XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window); XSync (dpy, False); - srandom ((int) time ((time_t *) 0)); + + /* This is the one and only place that the random-number generator is + seeded in any screenhack. You do not need to seed the RNG again, + it is done for you before your code is invoked. */ +# undef ya_rand_init + ya_rand_init (0); + screenhack (dpy, window); /* doesn't return */ return 0; }