/* xscreensaver, Copyright (c) 1992, 1995, 1997, 1998 * 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 * 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 #include #include #include #include #include #include #include #ifdef __sgi # include /* for SgiUseSchemes() */ #endif /* __sgi */ #ifdef HAVE_XMU # ifndef VMS # include # else /* VMS */ # include # endif #else # include "xmu.h" #endif #include "screenhack.h" #include "version.h" #include "vroot.h" #include "debug.h" #include "config.h" #ifndef isupper # define isupper(c) ((c) >= 'A' && (c) <= 'Z') #endif #ifndef _tolower # define _tolower(c) ((c) - 'A' + 'a') #endif #define KEYBOARD_GENERIC \ "Keyboard Rockbox\n" \ "-------- --------------\n" \ "+ ON\n" \ "8 UP\n" \ "2 DOWN\n" \ "4 LEFT\n" \ #ifdef HAVE_LCD_BITMAP #define KEYBOARD_SPECIFIC \ "6 RIGHT\n" \ "Enter OFF\n" \ "5 PLAY\n" \ "/ F1\n" \ "* F2\n" \ "- F3\n" #else #define KEYBOARD_SPECIFIC \ "6 RIGHT/PLAY (there's no separation between PLAY and RIGHT)\n" \ "Enter MENU\n" #endif char having_new_lcd=True; 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", #define GEOMETRY_POSITION 1 "*geometry: " #ifdef HAVE_LCD_BITMAP "120x68" #else "280x132" /* A bit larger that necessary */ #endif , /* this should be .geometry, but nooooo... */ "*mono: false", "*installColormap: false", "*visualID: default", "*windowID: ", 0 }; extern Display* dpy; extern int display_zoom; 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) { (void)dpy; return (event->xany.type == MapNotify && event->xvisibility.window == (Window) window); } static Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW; static Bool checkrepeat(time_t prev, time_t now) { if(now-prev < 50) { return true; } return false; } /* Dead-trivial event handling. Exit if the WM_PROTOCOLS WM_DELETE_WINDOW ClientMessage is received. */ int screenhack_handle_event(Display *dpy, XEvent *event, bool *release, bool *repeat) { int key=0; static time_t lasttime; static unsigned int lastkeycode; *release = FALSE; *repeat = false; switch (event->xany.type) { case KeyPress: { KeySym keysym; unsigned char c = 0; XLookupString (&event->xkey, &c, 1, &keysym, 0); key = keysym; #if 0 DEBUGF("Got keypress: %02x %x, time %lx\n", c, event->xkey.keycode, event->xkey.time); #endif if(lastkeycode == event->xkey.keycode) *repeat = checkrepeat(lasttime, event->xkey.time); lasttime = event->xkey.time; lastkeycode = event->xkey.keycode; } break; case KeyRelease: { KeySym keysym; unsigned char c = 0; XLookupString (&event->xkey, &c, 1, &keysym, 0); key = keysym; #if 0 DEBUGF("Got keyrelease: %c (%02x) %x\n", c, c, event->xkey.keycode); #endif if(lastkeycode == event->xkey.keycode) *repeat = checkrepeat(lasttime, event->xkey.time); lasttime = event->xkey.time; lastkeycode = event->xkey.keycode; if(*repeat) return 0; /* on repeats, return nothing on release */ *release = TRUE; } break; case Expose: { screen_redraw(); } break; default: 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] != (int)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(bool *release, bool *repeat) { int key=0; if(XPending(dpy)) { XEvent event; XNextEvent(dpy, &event); key=screenhack_handle_event(dpy, &event, release, repeat); } 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); } int main (int argc, char **argv) { Widget toplevel; Display *dpy; Window window; Screen *screen; Visual *visual; Colormap cmap; XEvent event; char version[255]; sprintf(version,"rockboxui %s",ROCKBOXUI_VERSION); #ifdef HAVE_LCD_BITMAP display_zoom=2; { char *env=getenv("RECORDER_ZOOM"); if (env) { display_zoom=atoi(env); } } #else display_zoom=1; { char *env=getenv("PLAYER_ZOOM"); if (env) { display_zoom=atoi(env); } } #endif if (argc > 1) { int x; for (x=1; x= 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 (CellsOfScreen (DefaultScreenOfDisplay (dpy)) <= 2) mono_p = True; { 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)); } } 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 | KeyRelease | ButtonPressMask | ExposureMask); XChangeProperty (dpy, window, XA_WM_PROTOCOLS, XA_ATOM, 32, PropModeReplace, (unsigned char *) &XA_WM_DELETE_WINDOW, 1); } } XSetWindowBackground (dpy, window, get_pixel_resource ("background", "Background", dpy, cmap)); XClearWindow (dpy, 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; }