1fac0e66fd
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@883 a1c6a512-1295-4272-9138-f99709370657
584 lines
18 KiB
C
584 lines
18 KiB
C
/* xscreensaver, Copyright (c) 1992, 1995, 1997, 1998
|
|
* Jamie Zawinski <jwz@jwz.org>
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation. No representations are made about the suitability of this
|
|
* software for any purpose. It is provided "as is" without express or
|
|
* implied warranty.
|
|
*
|
|
* And remember: X Windows is to graphics hacking as roman numerals are to
|
|
* the square root of pi.
|
|
*/
|
|
|
|
/* This file contains simple code to open a window or draw on the root.
|
|
The idea being that, when writing a graphics hack, you can just link
|
|
with this .o to get all of the uninteresting junk out of the way.
|
|
|
|
- create a procedure `screenhack(dpy, window)'
|
|
|
|
- create a variable `char *progclass' which names this program's
|
|
resource class.
|
|
|
|
- create a variable `char defaults []' for the default resources, and
|
|
null-terminate it.
|
|
|
|
- create a variable `XrmOptionDescRec options[]' for the command-line,
|
|
and null-terminate it.
|
|
|
|
And that's it...
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <X11/Intrinsic.h>
|
|
#include <X11/IntrinsicP.h>
|
|
#include <X11/CoreP.h>
|
|
#include <X11/Shell.h>
|
|
#include <X11/StringDefs.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/keysym.h>
|
|
|
|
#ifdef __sgi
|
|
# include <X11/SGIScheme.h> /* for SgiUseSchemes() */
|
|
#endif /* __sgi */
|
|
|
|
#ifdef HAVE_XMU
|
|
# ifndef VMS
|
|
# include <X11/Xmu/Error.h>
|
|
# else /* VMS */
|
|
# include <Xmu/Error.h>
|
|
# endif
|
|
#else
|
|
# include "xmu.h"
|
|
#endif
|
|
#include "screenhack.h"
|
|
#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 [] = {
|
|
{ "-root", ".root", XrmoptionNoArg, "True" },
|
|
{ "-window", ".root", XrmoptionNoArg, "False" },
|
|
{ "-mono", ".mono", XrmoptionNoArg, "True" },
|
|
{ "-install", ".installColormap", XrmoptionNoArg, "True" },
|
|
{ "-noinstall",".installColormap", XrmoptionNoArg, "False" },
|
|
{ "-visual", ".visualID", XrmoptionSepArg, 0 },
|
|
{ "-window-id", ".windowID", XrmoptionSepArg, 0 },
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
|
|
static char *default_defaults[] = {
|
|
".root: false",
|
|
"*geometry: 120x70", /* this should be .geometry, but nooooo... */
|
|
"*mono: false",
|
|
"*installColormap: false",
|
|
"*visualID: default",
|
|
"*windowID: ",
|
|
0
|
|
};
|
|
|
|
extern Display* dpy;
|
|
|
|
static XrmOptionDescRec *merged_options;
|
|
static int merged_options_size;
|
|
static char **merged_defaults;
|
|
|
|
static void merge_options (void)
|
|
{
|
|
int def_opts_size, opts_size;
|
|
int def_defaults_size, defaults_size;
|
|
|
|
for (def_opts_size = 0; default_options[def_opts_size].option;
|
|
def_opts_size++)
|
|
;
|
|
for (opts_size = 0; options[opts_size].option; opts_size++)
|
|
;
|
|
|
|
merged_options_size = def_opts_size + opts_size;
|
|
merged_options = (XrmOptionDescRec *)
|
|
malloc ((merged_options_size + 1) * sizeof(*default_options));
|
|
memcpy (merged_options, default_options,
|
|
(def_opts_size * sizeof(*default_options)));
|
|
memcpy (merged_options + def_opts_size, options,
|
|
((opts_size + 1) * sizeof(*default_options)));
|
|
|
|
for (def_defaults_size = 0; default_defaults[def_defaults_size];
|
|
def_defaults_size++)
|
|
;
|
|
for (defaults_size = 0; defaults[defaults_size]; defaults_size++)
|
|
;
|
|
|
|
merged_defaults = (char **)
|
|
malloc ((def_defaults_size + defaults_size + 1) * sizeof (*defaults));
|
|
|
|
memcpy (merged_defaults, default_defaults,
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Make the X errors print out the name of this program, so we have some
|
|
clue which one has a bug when they die under the screensaver.
|
|
*/
|
|
|
|
static int screenhack_ehandler (Display *dpy, XErrorEvent *error)
|
|
{
|
|
fprintf (stderr, "\nX error in %s:\n", progname);
|
|
if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
|
|
exit (-1);
|
|
else
|
|
fprintf (stderr, " (nonfatal.)\n");
|
|
return 0;
|
|
}
|
|
|
|
static Bool MapNotify_event_p (Display *dpy, XEvent *event, XPointer window)
|
|
{
|
|
return (event->xany.type == MapNotify &&
|
|
event->xvisibility.window == (Window) window);
|
|
}
|
|
|
|
|
|
#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.
|
|
*/
|
|
int screenhack_handle_event (Display *dpy, XEvent *event)
|
|
{
|
|
int key=0;
|
|
switch (event->xany.type)
|
|
{
|
|
case KeyPress:
|
|
{
|
|
KeySym keysym;
|
|
unsigned char c = 0;
|
|
XLookupString (&event->xkey, &c, 1, &keysym, 0);
|
|
if (! (keysym >= XK_Shift_L && keysym <= XK_Hyper_R))
|
|
XBell (dpy, 0); /* beep for non-chord keys */
|
|
key = keysym;
|
|
/* fprintf(stderr, "KEY PRESSED: %c (%02x)\n", c, c); */
|
|
}
|
|
break;
|
|
case ResizeRequest:
|
|
screen_resized(event->xresizerequest.width,
|
|
event->xresizerequest.height);
|
|
screen_redraw();
|
|
fprintf(stderr, "WINDOW RESIZED to width %d height %d\n",
|
|
event->xresizerequest.width, event->xresizerequest.height);
|
|
break;
|
|
default:
|
|
/* fprintf(stderr, "EVENT: %d (see /usr/include/X11/X.h)\n",
|
|
event->xany.type);
|
|
*/
|
|
break;
|
|
case Expose:
|
|
screen_redraw();
|
|
fprintf(stderr, "EXPOSE: x: %d y: %d width: %d height: %d\n",
|
|
event->xexpose.x, event->xexpose.y,
|
|
event->xexpose.width, event->xexpose.height);
|
|
break;
|
|
case ButtonPress:
|
|
fprintf(stderr, "BUTTON PRESSED: x: %d y:%d\n",event->xbutton.x,event->xbutton.y);
|
|
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;
|
|
}
|
|
return key;
|
|
}
|
|
|
|
|
|
int screenhack_handle_events (void)
|
|
{
|
|
int key=0;
|
|
while (XPending (dpy))
|
|
{
|
|
XEvent event;
|
|
XNextEvent (dpy, &event);
|
|
key=screenhack_handle_event (dpy, &event);
|
|
}
|
|
return key;
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
int main (int argc, char **argv)
|
|
{
|
|
Widget toplevel;
|
|
Display *dpy;
|
|
Window window;
|
|
Screen *screen;
|
|
Visual *visual;
|
|
Colormap cmap;
|
|
Bool root_p;
|
|
Window on_window = 0;
|
|
XEvent event;
|
|
Boolean dont_clear /*, dont_map */;
|
|
char version[255];
|
|
|
|
sprintf(version,"rockboxui %s",ROCKBOXUI_VERSION);
|
|
#ifdef XLOCKMORE
|
|
pre_merge_options ();
|
|
#endif
|
|
merge_options ();
|
|
|
|
#ifdef __sgi
|
|
/* We have to do this on SGI to prevent the background color from being
|
|
overridden by the current desktop color scheme (we'd like our
|
|
backgrounds to be black, thanks.) This should be the same as setting
|
|
the "*useSchemes: none" resource, but it's not -- if that resource is
|
|
present in the `default_defaults' above, it doesn't work, though it
|
|
does work when passed as an -xrm arg on the command line. So screw it,
|
|
turn them off from C instead.
|
|
*/
|
|
SgiUseSchemes ("none");
|
|
#endif /* __sgi */
|
|
|
|
toplevel = XtAppInitialize (&app, progclass, merged_options,
|
|
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);
|
|
|
|
|
|
if (argc > 1)
|
|
{
|
|
fprintf (stderr,
|
|
"This is the RockBox simulator. The firmware will not take\n"
|
|
"arguements, so the simulator will not either.\n");
|
|
exit(0);
|
|
#ifdef LETS_NOT_USE_ARGS
|
|
const char *s;
|
|
int i;
|
|
int x = 18;
|
|
int end = 78;
|
|
Bool help_p = !strcmp(argv[1], "-help");
|
|
fprintf (stderr, "%s\n", version);
|
|
for (s = progclass; *s; s++) fprintf(stderr, " ");
|
|
fprintf (stderr, " eXcellent GUI\n\n");
|
|
|
|
if (!help_p)
|
|
fprintf(stderr, "Unrecognised option: %s\n", argv[1]);
|
|
fprintf (stderr, "Options include: ");
|
|
for (i = 0; i < merged_options_size; i++)
|
|
{
|
|
char *sw = merged_options [i].option;
|
|
Bool argp = (merged_options [i].argKind == XrmoptionSepArg);
|
|
int size = strlen (sw) + (argp ? 6 : 0) + 2;
|
|
if (x + size >= end)
|
|
{
|
|
fprintf (stderr, "\n\t\t ");
|
|
x = 18;
|
|
}
|
|
x += size;
|
|
fprintf (stderr, "%s", sw);
|
|
if (argp) fprintf (stderr, " <arg>");
|
|
if (i != merged_options_size - 1) fprintf (stderr, ", ");
|
|
}
|
|
fprintf (stderr, ".\n");
|
|
exit (help_p ? 0 : 1);
|
|
#endif
|
|
}
|
|
|
|
dont_clear = get_boolean_resource ("dontClearRoot", "Boolean");
|
|
/*dont_map = get_boolean_resource ("dontMapWindow", "Boolean"); */
|
|
mono_p = get_boolean_resource ("mono", "Boolean");
|
|
if (CellsOfScreen (DefaultScreenOfDisplay (dpy)) <= 2)
|
|
mono_p = True;
|
|
|
|
root_p = get_boolean_resource ("root", "Boolean");
|
|
|
|
{
|
|
char *s = get_string_resource ("windowID", "WindowID");
|
|
if (s && *s)
|
|
on_window = get_integer_resource ("windowID", "WindowID");
|
|
if (s) free (s);
|
|
}
|
|
|
|
if (on_window)
|
|
{
|
|
XWindowAttributes xgwa;
|
|
window = (Window) on_window;
|
|
XtDestroyWidget (toplevel);
|
|
XGetWindowAttributes (dpy, window, &xgwa);
|
|
cmap = xgwa.colormap;
|
|
visual = xgwa.visual;
|
|
visual_warning (screen, window, visual, cmap, True);
|
|
}
|
|
else if (root_p)
|
|
{
|
|
XWindowAttributes xgwa;
|
|
window = RootWindowOfScreen (XtScreen (toplevel));
|
|
XtDestroyWidget (toplevel);
|
|
XGetWindowAttributes (dpy, window, &xgwa);
|
|
cmap = xgwa.colormap;
|
|
visual = xgwa.visual;
|
|
visual_warning (screen, window, visual, cmap, False);
|
|
}
|
|
else
|
|
{
|
|
Boolean def_visual_p;
|
|
visual = pick_visual (screen);
|
|
|
|
if (toplevel->core.width <= 0)
|
|
toplevel->core.width = 600;
|
|
if (toplevel->core.height <= 0)
|
|
toplevel->core.height = 480;
|
|
|
|
def_visual_p = (visual == DefaultVisualOfScreen (screen));
|
|
|
|
if (!def_visual_p)
|
|
{
|
|
unsigned int bg, bd;
|
|
Widget new;
|
|
|
|
cmap = XCreateColormap (dpy, RootWindowOfScreen(screen),
|
|
visual, AllocNone);
|
|
bg = get_pixel_resource ("background", "Background", dpy, cmap);
|
|
bd = get_pixel_resource ("borderColor", "Foreground", dpy, cmap);
|
|
|
|
new = XtVaAppCreateShell (progname, progclass,
|
|
topLevelShellWidgetClass, dpy,
|
|
XtNmappedWhenManaged, False,
|
|
XtNvisual, visual,
|
|
XtNdepth, visual_depth (screen, visual),
|
|
XtNwidth, toplevel->core.width,
|
|
XtNheight, toplevel->core.height,
|
|
XtNcolormap, cmap,
|
|
XtNbackground, (Pixel) bg,
|
|
XtNborderColor, (Pixel) bd,
|
|
XtNinput, True, /* for WM_HINTS */
|
|
0);
|
|
XtDestroyWidget (toplevel);
|
|
toplevel = new;
|
|
XtRealizeWidget (toplevel);
|
|
window = XtWindow (toplevel);
|
|
}
|
|
else
|
|
{
|
|
XtVaSetValues (toplevel,
|
|
XtNmappedWhenManaged, False,
|
|
XtNinput, True, /* for WM_HINTS */
|
|
0);
|
|
XtRealizeWidget (toplevel);
|
|
window = XtWindow (toplevel);
|
|
|
|
if (get_boolean_resource ("installColormap", "InstallColormap"))
|
|
{
|
|
cmap = XCreateColormap (dpy, window,
|
|
DefaultVisualOfScreen (XtScreen
|
|
(toplevel)),
|
|
AllocNone);
|
|
XSetWindowColormap (dpy, window, cmap);
|
|
}
|
|
else
|
|
{
|
|
cmap = DefaultColormap (dpy, DefaultScreen (dpy));
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (dont_map)
|
|
{
|
|
XtVaSetValues (toplevel, XtNmappedWhenManaged, False, 0);
|
|
XtRealizeWidget (toplevel);
|
|
}
|
|
else
|
|
*/
|
|
{
|
|
XtPopup (toplevel, XtGrabNone);
|
|
}
|
|
|
|
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 | ResizeRedirectMask | ExposureMask);
|
|
XChangeProperty (dpy, window, XA_WM_PROTOCOLS, XA_ATOM, 32,
|
|
PropModeReplace,
|
|
(unsigned char *) &XA_WM_DELETE_WINDOW, 1);
|
|
}
|
|
}
|
|
|
|
if (!dont_clear)
|
|
{
|
|
XSetWindowBackground (dpy, window,
|
|
get_pixel_resource ("background", "Background",
|
|
dpy, cmap));
|
|
XClearWindow (dpy, window);
|
|
}
|
|
|
|
if (!root_p && !on_window)
|
|
/* wait for it to be mapped */
|
|
XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
|
|
|
|
XSync (dpy, False);
|
|
|
|
screenhack (dpy, window); /* doesn't return */
|
|
return 0;
|
|
}
|