1 /* xscreensaver, Copyright (c) 1992-2010 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * And remember: X Windows is to graphics hacking as roman numerals are to
12 * the square root of pi.
15 /* This file contains simple code to open a window or draw on the root.
16 The idea being that, when writing a graphics hack, you can just link
17 with this .o to get all of the uninteresting junk out of the way.
19 Create a few static global procedures and variables:
21 static void *YOURNAME_init (Display *, Window);
23 Return an opaque structure representing your drawing state.
25 static unsigned long YOURNAME_draw (Display *, Window, void *closure);
28 The `closure' arg is your drawing state, that you created in `init'.
29 Return the number of microseconds to wait until the next frame.
31 This should return in some small fraction of a second.
32 Do not call `usleep' or loop excessively. For long loops, use a
35 static void YOURNAME_reshape (Display *, Window, void *closure,
36 unsigned int width, unsigned int height);
38 Called when the size of the window changes with the new size.
40 static Bool YOURNAME_event (Display *, Window, void *closure,
43 Called when a keyboard or mouse event arrives.
44 Return True if you handle it in some way, False otherwise.
46 static void YOURNAME_free (Display *, Window, void *closure);
48 Called when you are done: free everything you've allocated,
49 including your private `state' structure.
51 NOTE: this is called in windowed-mode when the user typed
52 'q' or clicks on the window's close box; but when
53 xscreensaver terminates this screenhack, it does so by
54 killing the process with SIGSTOP. So this callback is
57 static char YOURNAME_defaults [] = { "...", "...", ... , 0 };
59 This variable is an array of strings, your default resources.
60 Null-terminate the list.
62 static XrmOptionDescRec YOURNAME_options[] = { { ... }, ... { 0,0,0,0 } }
64 This variable describes your command-line options.
65 Null-terminate the list.
67 Finally , invoke the XSCREENSAVER_MODULE() macro to tie it all together.
71 - Make sure that all functions in your module are static (check this
72 by running "nm -g" on the .o file).
74 - Do not use global variables: all such info must be stored in the
75 private `state' structure.
77 - Do not use static function-local variables, either. Put it in `state'.
79 Assume that there are N independent runs of this code going in the
80 same address space at the same time: they must not affect each other.
82 - Don't forget to write an XML file to describe the user interface
83 of your screen saver module. See .../hacks/config/README for details.
89 #include <X11/Intrinsic.h>
90 #include <X11/IntrinsicP.h>
91 #include <X11/CoreP.h>
92 #include <X11/Shell.h>
93 #include <X11/StringDefs.h>
94 #include <X11/keysym.h>
95 /* #include <libosso.h> */
96 #include <dbus/dbus.h>
97 /* #include <dbus/dbus-glib.h> */
100 # include <X11/SGIScheme.h> /* for SgiUseSchemes() */
105 # include <X11/Xmu/Error.h>
107 # include <Xmu/Error.h>
113 #include "screenhackI.h"
118 #ifndef _XSCREENSAVER_VROOT_H_
119 # error Error! You have an old version of vroot.h! Check -I args.
120 #endif /* _XSCREENSAVER_VROOT_H_ */
123 # define isupper(c) ((c) >= 'A' && (c) <= 'Z')
126 # define _tolower(c) ((c) - 'A' + 'a')
130 /* This is defined by the SCREENHACK_MAIN() macro via screenhack.h.
132 extern struct xscreensaver_function_table *xscreensaver_function_table;
135 const char *progname; /* used by hacks in error messages */
136 const char *progclass; /* used by ../utils/resources.c */
137 Bool mono_p; /* used by hacks */
140 static XrmOptionDescRec default_options [] = {
141 { "-root", ".root", XrmoptionNoArg, "True" },
142 { "-window", ".root", XrmoptionNoArg, "False" },
143 { "-mono", ".mono", XrmoptionNoArg, "True" },
144 { "-install", ".installColormap", XrmoptionNoArg, "True" },
145 { "-noinstall",".installColormap", XrmoptionNoArg, "False" },
146 { "-visual", ".visualID", XrmoptionSepArg, 0 },
147 { "-window-id", ".windowID", XrmoptionSepArg, 0 },
148 { "-fps", ".doFPS", XrmoptionNoArg, "True" },
149 { "-no-fps", ".doFPS", XrmoptionNoArg, "False" },
150 { "-view", ".view", XrmoptionSepArg, 1 },
153 { "-pair", ".pair", XrmoptionNoArg, "True" },
154 # endif /* DEBUG_PAIR */
158 static char *default_defaults[] = {
160 "*geometry: 600x480", /* this should be .geometry, but nooooo... */
162 "*installColormap: false",
164 "*visualID: default",
166 "*desktopGrabber: xscreensaver-getimage %s",
170 static XrmOptionDescRec *merged_options;
171 static int merged_options_size;
172 static char **merged_defaults;
178 struct xscreensaver_function_table *ft = xscreensaver_function_table;
180 const XrmOptionDescRec *options = ft->options;
181 const char * const *defaults = ft->defaults;
182 const char *progclass = ft->progclass;
184 int def_opts_size, opts_size;
185 int def_defaults_size, defaults_size;
187 for (def_opts_size = 0; default_options[def_opts_size].option;
190 for (opts_size = 0; options[opts_size].option; opts_size++)
193 merged_options_size = def_opts_size + opts_size;
194 merged_options = (XrmOptionDescRec *)
195 malloc ((merged_options_size + 1) * sizeof(*default_options));
196 memcpy (merged_options, default_options,
197 (def_opts_size * sizeof(*default_options)));
198 memcpy (merged_options + def_opts_size, options,
199 ((opts_size + 1) * sizeof(*default_options)));
201 for (def_defaults_size = 0; default_defaults[def_defaults_size];
204 for (defaults_size = 0; defaults[defaults_size]; defaults_size++)
206 merged_defaults = (char **)
207 malloc ((def_defaults_size + defaults_size + 1) * sizeof (*defaults));;
208 memcpy (merged_defaults, default_defaults,
209 def_defaults_size * sizeof(*defaults));
210 memcpy (merged_defaults + def_defaults_size, defaults,
211 (defaults_size + 1) * sizeof(*defaults));
213 /* This totally sucks. Xt should behave like this by default.
214 If the string in `defaults' looks like ".foo", change that
219 for (s = merged_defaults; *s; s++)
222 const char *oldr = *s;
223 char *newr = (char *) malloc(strlen(oldr) + strlen(progclass) + 3);
224 strcpy (newr, progclass);
234 /* Make the X errors print out the name of this program, so we have some
235 clue which one has a bug when they die under the screensaver.
239 screenhack_ehandler (Display *dpy, XErrorEvent *error)
241 fprintf (stderr, "\nX error in %s:\n", progname);
242 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
245 fprintf (stderr, " (nonfatal.)\n");
250 MapNotify_event_p (Display *dpy, XEvent *event, XPointer window)
252 return (event->xany.type == MapNotify &&
253 event->xvisibility.window == (Window) window);
257 static Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW;
259 /* Dead-trivial event handling: exits if "q" or "ESC" are typed.
260 Exit if the WM_PROTOCOLS WM_DELETE_WINDOW ClientMessage is received.
261 Returns False if the screen saver should now terminate.
264 screenhack_handle_event_1 (Display *dpy, XEvent *event)
266 switch (event->xany.type)
272 XLookupString (&event->xkey, &c, 1, &keysym, 0);
277 return False; /* exit */
278 else if (! (keysym >= XK_Shift_L && keysym <= XK_Hyper_R))
279 XBell (dpy, 0); /* beep for non-chord keys */
287 if (event->xclient.message_type != XA_WM_PROTOCOLS)
289 char *s = XGetAtomName(dpy, event->xclient.message_type);
290 if (!s) s = "(null)";
291 fprintf (stderr, "%s: unknown ClientMessage %s received!\n",
294 else if (event->xclient.data.l[0] != XA_WM_DELETE_WINDOW)
296 char *s1 = XGetAtomName(dpy, event->xclient.message_type);
297 char *s2 = XGetAtomName(dpy, event->xclient.data.l[0]);
298 if (!s1) s1 = "(null)";
299 if (!s2) s2 = "(null)";
300 fprintf (stderr, "%s: unknown ClientMessage %s[%s] received!\n",
305 return False; /* exit */
315 pick_visual (Screen *screen)
317 struct xscreensaver_function_table *ft = xscreensaver_function_table;
319 if (ft->pick_visual_hook)
321 Visual *v = ft->pick_visual_hook (screen);
325 return get_visual_resource (screen, "visualID", "VisualID", False);
329 /* Notice when the user has requested a different visual or colormap
330 on a pre-existing window (e.g., "-root -visual truecolor" or
331 "-window-id 0x2c00001 -install") and complain, since when drawing
332 on an existing window, we have no choice about these things.
335 visual_warning (Screen *screen, Window window, Visual *visual, Colormap cmap,
338 struct xscreensaver_function_table *ft = xscreensaver_function_table;
340 char *visual_string = get_string_resource (DisplayOfScreen (screen),
341 "visualID", "VisualID");
342 Visual *desired_visual = pick_visual (screen);
346 if (window == RootWindowOfScreen (screen))
347 strcpy (win, "root window");
349 sprintf (win, "window 0x%lx", (unsigned long) window);
352 sprintf (why, "-window-id 0x%lx", (unsigned long) window);
354 strcpy (why, "-root");
356 if (visual_string && *visual_string)
359 for (s = visual_string; *s; s++)
360 if (isupper (*s)) *s = _tolower (*s);
362 if (!strcmp (visual_string, "default") ||
363 !strcmp (visual_string, "default") ||
364 !strcmp (visual_string, "best"))
365 /* don't warn about these, just silently DWIM. */
367 else if (visual != desired_visual)
369 fprintf (stderr, "%s: ignoring `-visual %s' because of `%s'.\n",
370 progname, visual_string, why);
371 fprintf (stderr, "%s: using %s's visual 0x%lx.\n",
372 progname, win, XVisualIDFromVisual (visual));
374 free (visual_string);
377 if (visual == DefaultVisualOfScreen (screen) &&
378 has_writable_cells (screen, visual) &&
379 get_boolean_resource (DisplayOfScreen (screen),
380 "installColormap", "InstallColormap"))
382 fprintf (stderr, "%s: ignoring `-install' because of `%s'.\n",
384 fprintf (stderr, "%s: using %s's colormap 0x%lx.\n",
385 progname, win, (unsigned long) cmap);
388 if (ft->validate_visual_hook)
390 if (! ft->validate_visual_hook (screen, win, visual))
399 /* Bad Things Happen if stdin, stdout, and stderr have been closed
400 (as by the `sh incantation "attraction >&- 2>&-"). When you do
401 that, the X connection gets allocated to one of these fds, and
402 then some random library writes to stderr, and random bits get
403 stuffed down the X pipe, causing "Xlib: sequence lost" errors.
404 So, we cause the first three file descriptors to be open to
405 /dev/null if they aren't open to something else already. This
406 must be done before any other files are opened (or the closing
407 of that other file will again free up one of the "magic" first
410 We do this by opening /dev/null three times, and then closing
411 those fds, *unless* any of them got allocated as #0, #1, or #2,
412 in which case we leave them open. Gag.
414 Really, this crap is technically required of *every* X program,
415 if you want it to be robust in the face of "2>&-".
417 int fd0 = open ("/dev/null", O_RDWR);
418 int fd1 = open ("/dev/null", O_RDWR);
419 int fd2 = open ("/dev/null", O_RDWR);
420 if (fd0 > 2) close (fd0);
421 if (fd1 > 2) close (fd1);
422 if (fd2 > 2) close (fd2);
427 screenhack_table_handle_events (Display *dpy,
428 const struct xscreensaver_function_table *ft,
429 Window window, void *closure
431 , Window window2, void *closure2
435 XtAppContext app = XtDisplayToApplicationContext (dpy);
437 if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
438 XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
440 while (XPending (dpy))
443 XNextEvent (dpy, &event);
445 if (event.xany.type == ConfigureNotify)
447 if (event.xany.window == window)
448 ft->reshape_cb (dpy, window, closure,
449 event.xconfigure.width, event.xconfigure.height);
451 if (event.xany.window == window2)
452 ft->reshape_cb (dpy, window2, closure2,
453 event.xconfigure.width, event.xconfigure.height);
456 else if (event.xany.type == ClientMessage ||
457 (! (event.xany.window == window
458 ? ft->event_cb (dpy, window, closure, &event)
460 : event.xany.window == window2
461 ? ft->event_cb (dpy, window2, closure2, &event)
464 if (! screenhack_handle_event_1 (dpy, &event))
467 if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
468 XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
475 usleep_and_process_events (Display *dpy,
476 const struct xscreensaver_function_table *ft,
477 Window window, fps_state *fpst, void *closure,
480 , Window window2, fps_state *fpst2, void *closure2,
486 unsigned long quantum = 100000; /* 1/10th second */
495 if (fpst) fps_slept (fpst, quantum);
497 if (fpst2) fps_slept (fpst2, quantum);
501 if (! screenhack_table_handle_events (dpy, ft, window, closure
514 screenhack_do_fps (Display *dpy, Window w, fps_state *fpst, void *closure)
516 fps_compute (fpst, 0);
522 run_screenhack_table (Display *dpy,
527 const struct xscreensaver_function_table *ft,
530 #define LIVEWP_SIGNAL_INTERFACE "org.maemo.livewp"
531 #define LIVEWP_PAUSE_LIVEBG_ON_VIEW1 "pause_livebg_on_view1"
532 #define LIVEWP_PAUSE_LIVEBG_ON_VIEW2 "pause_livebg_on_view2"
533 #define LIVEWP_PAUSE_LIVEBG_ON_VIEW3 "pause_livebg_on_view3"
534 #define LIVEWP_PAUSE_LIVEBG_ON_VIEW4 "pause_livebg_on_view4"
535 #define LIVEWP_PAUSE_LIVEBG_ON_VIEW "pause_livebg_on_view"
536 #define LIVEWP_PLAY_LIVEBG_ON_VIEW1 "play_livebg_on_view1"
537 #define LIVEWP_PLAY_LIVEBG_ON_VIEW2 "play_livebg_on_view2"
538 #define LIVEWP_PLAY_LIVEBG_ON_VIEW3 "play_livebg_on_view3"
539 #define LIVEWP_PLAY_LIVEBG_ON_VIEW4 "play_livebg_on_view4"
540 #define LIVEWP_PLAY_LIVEBG_ON_VIEW "play_livebg_on_view"
542 DBusConnection* conn;
544 DBusMessageIter args;
548 int start_frame = 200;
550 /* Kludge: even though the init_cb functions are declared to take 2 args,
551 actually call them with 3, for the benefit of xlockmore_init() and
554 void *(*init_cb) (Display *, Window, void *) =
555 (void *(*) (Display *, Window, void *)) ft->init_cb;
557 void (*fps_cb) (Display *, Window, fps_state *, void *) = ft->fps_cb;
559 void *closure = init_cb (dpy, window, ft->setup_arg);
560 fps_state *fpst = fps_init (dpy, window);
564 fps_state *fpst2 = 0;
565 if (window2) closure2 = init_cb (dpy, window2, ft->setup_arg);
566 if (window2) fpst2 = fps_init (dpy, window2);
569 if (! closure) /* if it returns nothing, it can't possibly be re-entrant. */
572 if (! fps_cb) fps_cb = screenhack_do_fps;
574 /* initialise the error */
575 dbus_error_init(&err);
576 conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
577 if (dbus_error_is_set(&err)) {
578 fprintf(stderr, "Connection Error (%s)\n", err.message);
579 dbus_error_free(&err);
582 fprintf(stderr, "Connection Null\n");
586 dbus_bus_add_match (conn, "type='signal', interface='org.maemo.livewp', member='pause_livebg_on_view1'", NULL);
587 dbus_bus_add_match (conn, "type='signal', interface='org.maemo.livewp', member='play_livebg_on_view1'", NULL);
590 dbus_bus_add_match (conn, "type='signal', interface='org.maemo.livewp', member='pause_livebg_on_view2'", NULL);
591 dbus_bus_add_match (conn, "type='signal', interface='org.maemo.livewp', member='play_livebg_on_view2'", NULL);
594 dbus_bus_add_match (conn, "type='signal', interface='org.maemo.livewp', member='pause_livebg_on_view3'", NULL);
595 dbus_bus_add_match (conn, "type='signal', interface='org.maemo.livewp', member='play_livebg_on_view3'", NULL);
598 dbus_bus_add_match (conn, "type='signal', interface='org.maemo.livewp', member='pause_livebg_on_view4'", NULL);
599 dbus_bus_add_match (conn, "type='signal', interface='org.maemo.livewp', member='play_livebg_on_view4'", NULL);
602 dbus_connection_flush(conn);
607 unsigned long delay = ft->draw_cb (dpy, window, closure);
609 unsigned long delay2 = 0;
610 if (window2) delay2 = ft->draw_cb (dpy, window2, closure2);
614 if (fpst) fps_cb (dpy, window, fpst, closure);
616 if (fpst2) fps_cb (dpy, window, fpst2, closure);
618 if (! usleep_and_process_events (dpy, ft,
619 window, fpst, closure, delay
621 , window2, fpst2, closure2, delay2
627 if (start_frame > 0) {
632 /* non blocking read of the next available message */
633 dbus_connection_read_write(conn, 0);
635 /* blocking read of the next available message */
636 dbus_connection_read_write(conn, 20000);
637 /*fprintf(stderr, "111111\n");*/
638 /* msg = dbus_connection_borrow_message(conn); */
640 msg = dbus_connection_pop_message(conn);
642 /*fprintf(stderr, "2222222\n");*/
645 /*fprintf(stderr, "333333\n");*/
648 fprintf(stderr, "signal on view %i\n", view);
649 /* check this is a method call for the right interface & method */
650 if ((view == 1 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PAUSE_LIVEBG_ON_VIEW1))||
651 (view == 2 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PAUSE_LIVEBG_ON_VIEW2))||
652 (view == 3 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PAUSE_LIVEBG_ON_VIEW3))||
653 (view == 4 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PAUSE_LIVEBG_ON_VIEW4))){
654 fprintf(stderr, "Pause scene visible %i\n", view);
656 dbus_message_unref (msg);
659 if ((view == 1 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PLAY_LIVEBG_ON_VIEW1))||
660 (view == 2 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PLAY_LIVEBG_ON_VIEW2))||
661 (view == 3 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PLAY_LIVEBG_ON_VIEW3))||
662 (view == 4 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PLAY_LIVEBG_ON_VIEW4))){
663 fprintf(stderr, "Play scene visible %i\n", view);
665 dbus_message_unref (msg);
669 /* dbus_connection_steal_borrowed_message(conn, msg); */
670 /* fprintf (stderr, "APPLICATION PATH11111111111111111111 %s %s %s\n", dbus_message_get_path(msg), dbus_message_get_interface (msg), dbus_message_get_member (msg));*/
671 /*dbus_connection_return_message(conn, msg);*/
672 if (dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PAUSE_LIVEBG_ON_VIEW) ||
673 dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PLAY_LIVEBG_ON_VIEW)){
674 if (!dbus_message_iter_init(msg, &args))
675 fprintf(stderr, "dbus message has no param\n");
676 else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args))
677 fprintf(stderr, "dbus message param is not int \n");
679 dbus_message_iter_get_basic(&args, ¶m);
680 fprintf(stderr, "dbus param = %i\n", param);
683 if (dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PAUSE_LIVEBG_ON_VIEW)){
684 fprintf(stderr, "dbus Pause scene visible %i\n", param);
687 if (dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PLAY_LIVEBG_ON_VIEW)){
688 fprintf(stderr, "dbus Play scene visible %i\n", param);
691 /*msg = dbus_connection_pop_message(conn);*/
692 fprintf(stderr, "dbus steal message\n");
693 /*dbus_connection_steal_borrowed_message(conn, msg);*/
695 fprintf(stderr, "dbus return message\n");
696 /*dbus_connection_return_message(conn, msg);*/
700 dbus_message_unref (msg);
701 /* check this is a method call for the right interface & method */
703 if ((view == 1 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PAUSE_LIVEBG_ON_VIEW1))||
704 (view == 2 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PAUSE_LIVEBG_ON_VIEW2))||
705 (view == 3 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PAUSE_LIVEBG_ON_VIEW3))||
706 (view == 4 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PAUSE_LIVEBG_ON_VIEW4))){
707 fprintf(stderr, "Pause scene visible %i\n", view);
709 dbus_message_unref (msg);
712 if ((view == 1 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PLAY_LIVEBG_ON_VIEW1))||
713 (view == 2 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PLAY_LIVEBG_ON_VIEW2))||
714 (view == 3 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PLAY_LIVEBG_ON_VIEW3))||
715 (view == 4 && dbus_message_is_signal(msg, LIVEWP_SIGNAL_INTERFACE, LIVEWP_PLAY_LIVEBG_ON_VIEW4))){
716 fprintf(stderr, "Play scene visible %i\n", view);
718 dbus_message_unref (msg);
724 ft->free_cb (dpy, window, closure);
725 if (fpst) fps_free (fpst);
728 if (window2) ft->free_cb (dpy, window2, closure2);
729 if (window2) fps_free (fpst2);
731 /* close the connection */
732 dbus_connection_close(conn);
737 make_shell (Screen *screen, Widget toplevel, int width, int height)
739 Display *dpy = DisplayOfScreen (screen);
740 Visual *visual = pick_visual (screen);
741 Boolean def_visual_p = (toplevel &&
742 visual == DefaultVisualOfScreen (screen));
744 if (width <= 0) width = 600;
745 if (height <= 0) height = 480;
750 XtVaSetValues (toplevel,
751 XtNmappedWhenManaged, False,
754 XtNinput, True, /* for WM_HINTS */
756 XtRealizeWidget (toplevel);
757 window = XtWindow (toplevel);
759 if (get_boolean_resource (dpy, "installColormap", "InstallColormap"))
762 XCreateColormap (dpy, window, DefaultVisualOfScreen (screen),
764 XSetWindowColormap (dpy, window, cmap);
771 Colormap cmap = XCreateColormap (dpy, VirtualRootWindowOfScreen(screen),
773 bg = get_pixel_resource (dpy, cmap, "background", "Background");
774 bd = get_pixel_resource (dpy, cmap, "borderColor", "Foreground");
776 new = XtVaAppCreateShell (progname, progclass,
777 topLevelShellWidgetClass, dpy,
778 XtNmappedWhenManaged, False,
780 XtNdepth, visual_depth (screen, visual),
784 XtNbackground, (Pixel) bg,
785 XtNborderColor, (Pixel) bd,
786 XtNinput, True, /* for WM_HINTS */
789 if (!toplevel) /* kludge for the second window in -pair mode... */
790 XtVaSetValues (new, XtNx, 0, XtNy, 550, NULL);
792 XtRealizeWidget (new);
800 init_window (Display *dpy, Widget toplevel, const char *title)
803 XWindowAttributes xgwa;
804 XtPopup (toplevel, XtGrabNone);
805 XtVaSetValues (toplevel, XtNtitle, title, NULL);
807 /* Select KeyPress, and announce that we accept WM_DELETE_WINDOW.
809 window = XtWindow (toplevel);
810 XGetWindowAttributes (dpy, window, &xgwa);
811 XSelectInput (dpy, window,
812 (xgwa.your_event_mask | KeyPressMask | KeyReleaseMask |
813 ButtonPressMask | ButtonReleaseMask));
814 XChangeProperty (dpy, window, XA_WM_PROTOCOLS, XA_ATOM, 32,
816 (unsigned char *) &XA_WM_DELETE_WINDOW, 1);
821 main (int argc, char **argv)
823 struct xscreensaver_function_table *ft = xscreensaver_function_table;
825 /* osso_context_t *osso; */
827 XWindowAttributes xgwa;
833 Widget toplevel2 = 0;
837 Window on_window = 0;
845 progname = argv[0]; /* reset later */
846 progclass = ft->progclass;
849 ft->setup_cb (ft, ft->setup_arg);
854 /* We have to do this on SGI to prevent the background color from being
855 overridden by the current desktop color scheme (we'd like our backgrounds
856 to be black, thanks.) This should be the same as setting the
857 "*useSchemes: none" resource, but it's not -- if that resource is
858 present in the `default_defaults' above, it doesn't work, though it
859 does work when passed as an -xrm arg on the command line. So screw it,
860 turn them off from C instead.
862 SgiUseSchemes ("none");
865 toplevel = XtAppInitialize (&app, progclass, merged_options,
866 merged_options_size, &argc, argv,
867 merged_defaults, 0, 0);
869 dpy = XtDisplay (toplevel);
871 XtGetApplicationNameAndClass (dpy,
873 (char **) &progclass);
875 /* half-assed way of avoiding buffer-overrun attacks. */
876 if (strlen (progname) >= 100) ((char *) progname)[100] = 0;
878 XSetErrorHandler (screenhack_ehandler);
880 XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False);
881 XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
884 char *v = (char *) strdup(strchr(screensaver_id, ' '));
885 char *s1, *s2, *s3, *s4;
886 s1 = (char *) strchr(v, ' '); s1++;
887 s2 = (char *) strchr(s1, ' ');
888 s3 = (char *) strchr(v, '('); s3++;
889 s4 = (char *) strchr(s3, ')');
892 sprintf (version, "%s: from the XScreenSaver %s distribution (%s.)",
903 Bool help_p = (!strcmp(argv[1], "-help") ||
904 !strcmp(argv[1], "--help"));
905 fprintf (stderr, "%s\n", version);
906 for (s = progclass; *s; s++) fprintf(stderr, " ");
907 fprintf (stderr, " http://www.jwz.org/xscreensaver/\n\n");
910 fprintf(stderr, "Unrecognised option: %s\n", argv[1]);
911 fprintf (stderr, "Options include: ");
912 for (i = 0; i < merged_options_size; i++)
914 char *sw = merged_options [i].option;
915 Bool argp = (merged_options [i].argKind == XrmoptionSepArg);
916 int size = strlen (sw) + (argp ? 6 : 0) + 2;
919 fprintf (stderr, "\n\t\t ");
923 fprintf (stderr, "%s", sw);
924 if (argp) fprintf (stderr, " <arg>");
925 if (i != merged_options_size - 1) fprintf (stderr, ", ");
928 fprintf (stderr, ".\n");
933 fprintf (stderr, "\nResources:\n\n");
934 for (i = 0; i < merged_options_size; i++)
936 const char *opt = merged_options [i].option;
937 const char *res = merged_options [i].specifier + 1;
938 const char *val = merged_options [i].value;
939 char *s = get_string_resource (dpy, (char *) res, (char *) res);
944 while (L > 0 && (s[L-1] == ' ' || s[L-1] == '\t'))
948 fprintf (stderr, " %-16s %-18s ", opt, res);
949 if (merged_options [i].argKind == XrmoptionSepArg)
951 fprintf (stderr, "[%s]", (s ? s : "?"));
955 fprintf (stderr, "%s", (val ? val : "(null)"));
956 if (val && s && !strcasecmp (val, s))
957 fprintf (stderr, " [default]");
959 fprintf (stderr, "\n");
961 fprintf (stderr, "\n");
965 exit (help_p ? 0 : 1);
970 for (s = merged_defaults; *s; s++)
974 free (merged_options);
975 free (merged_defaults);
979 dont_clear = get_boolean_resource (dpy, "dontClearRoot", "Boolean");
980 mono_p = get_boolean_resource (dpy, "mono", "Boolean");
981 if (CellsOfScreen (DefaultScreenOfDisplay (dpy)) <= 2)
984 root_p = get_boolean_resource (dpy, "root", "Boolean");
987 char *s = get_string_resource (dpy, "windowID", "WindowID");
989 on_window = get_integer_resource (dpy, "windowID", "WindowID");
993 view = get_integer_resource (dpy, "view", "view");
994 fprintf(stderr, "View %i\n", view);
997 window = (Window) on_window;
998 XtDestroyWidget (toplevel);
999 XGetWindowAttributes (dpy, window, &xgwa);
1000 visual_warning (xgwa.screen, window, xgwa.visual, xgwa.colormap, True);
1002 /* Select KeyPress and resize events on the external window.
1004 xgwa.your_event_mask |= KeyPressMask | StructureNotifyMask;
1005 XSelectInput (dpy, window, xgwa.your_event_mask);
1007 /* Select ButtonPress and ButtonRelease events on the external window,
1008 if no other app has already selected them (only one app can select
1009 ButtonPress at a time: BadAccess results.)
1011 if (! (xgwa.all_event_masks & (ButtonPressMask | ButtonReleaseMask)))
1012 XSelectInput (dpy, window,
1013 (xgwa.your_event_mask |
1014 ButtonPressMask | ButtonReleaseMask));
1018 window = VirtualRootWindowOfScreen (XtScreen (toplevel));
1019 XtDestroyWidget (toplevel);
1020 XGetWindowAttributes (dpy, window, &xgwa);
1021 /* With RANDR, the root window can resize! */
1022 XSelectInput (dpy, window, xgwa.your_event_mask | StructureNotifyMask);
1023 visual_warning (xgwa.screen, window, xgwa.visual, xgwa.colormap, False);
1027 Widget new = make_shell (XtScreen (toplevel), toplevel,
1028 toplevel->core.width,
1029 toplevel->core.height);
1030 if (new != toplevel)
1032 XtDestroyWidget (toplevel);
1036 init_window (dpy, toplevel, version);
1037 window = XtWindow (toplevel);
1038 XGetWindowAttributes (dpy, window, &xgwa);
1041 if (get_boolean_resource (dpy, "pair", "Boolean"))
1043 toplevel2 = make_shell (xgwa.screen, 0,
1044 toplevel->core.width,
1045 toplevel->core.height);
1046 init_window (dpy, toplevel2, version);
1047 window2 = XtWindow (toplevel2);
1049 # endif /* DEBUG_PAIR */
1054 unsigned int bg = get_pixel_resource (dpy, xgwa.colormap,
1055 "background", "Background");
1056 XSetWindowBackground (dpy, window, bg);
1057 XClearWindow (dpy, window);
1061 XSetWindowBackground (dpy, window2, bg);
1062 XClearWindow (dpy, window2);
1067 if (!root_p && !on_window)
1068 /* wait for it to be mapped */
1069 XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
1073 /* This is the one and only place that the random-number generator is
1074 seeded in any screenhack. You do not need to seed the RNG again,
1075 it is done for you before your code is invoked. */
1076 # undef ya_rand_init
1079 run_screenhack_table (dpy, window,
1085 XtDestroyWidget (toplevel);
1086 XtDestroyApplicationContext (app);