reverted to signal without parameters
[xscreensaver] / xscreensaver / hacks / screenhack.c
1 /* xscreensaver, Copyright (c) 1992-2010 Jamie Zawinski <jwz@jwz.org>
2  *
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 
9  * implied warranty.
10  *
11  * And remember: X Windows is to graphics hacking as roman numerals are to
12  * the square root of pi.
13  */
14
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.
18
19    Create a few static global procedures and variables:
20
21       static void *YOURNAME_init (Display *, Window);
22
23           Return an opaque structure representing your drawing state.
24
25       static unsigned long YOURNAME_draw (Display *, Window, void *closure);
26
27           Draw one frame.
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.
30
31           This should return in some small fraction of a second. 
32           Do not call `usleep' or loop excessively.  For long loops, use a
33           finite state machine.
34
35       static void YOURNAME_reshape (Display *, Window, void *closure,
36                                     unsigned int width, unsigned int height);
37
38           Called when the size of the window changes with the new size.
39
40       static Bool YOURNAME_event (Display *, Window, void *closure,
41                                   XEvent *event);
42
43           Called when a keyboard or mouse event arrives.
44           Return True if you handle it in some way, False otherwise.
45
46       static void YOURNAME_free (Display *, Window, void *closure);
47
48            Called when you are done: free everything you've allocated,
49            including your private `state' structure.  
50
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
55            mostly useless.
56
57       static char YOURNAME_defaults [] = { "...", "...", ... , 0 };
58
59            This variable is an array of strings, your default resources.
60            Null-terminate the list.
61
62       static XrmOptionDescRec YOURNAME_options[] = { { ... }, ... { 0,0,0,0 } }
63
64            This variable describes your command-line options.
65            Null-terminate the list.
66
67       Finally , invoke the XSCREENSAVER_MODULE() macro to tie it all together.
68
69    Additional caveats:
70
71       - Make sure that all functions in your module are static (check this
72         by running "nm -g" on the .o file).
73
74       - Do not use global variables: all such info must be stored in the
75         private `state' structure.
76
77       - Do not use static function-local variables, either.  Put it in `state'.
78
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.
81
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.
84  */
85
86 #define DEBUG_PAIR
87
88 #include <stdio.h>
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>  */
98
99 #ifdef __sgi
100 # include <X11/SGIScheme.h>     /* for SgiUseSchemes() */
101 #endif /* __sgi */
102
103 #ifdef HAVE_XMU
104 # ifndef VMS
105 #  include <X11/Xmu/Error.h>
106 # else /* VMS */
107 #  include <Xmu/Error.h>
108 # endif
109 #else
110 # include "xmu.h"
111 #endif
112
113 #include "screenhackI.h"
114 #include "version.h"
115 #include "vroot.h"
116 #include "fps.h"
117
118 #ifndef _XSCREENSAVER_VROOT_H_
119 # error Error!  You have an old version of vroot.h!  Check -I args.
120 #endif /* _XSCREENSAVER_VROOT_H_ */
121
122 #ifndef isupper
123 # define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
124 #endif
125 #ifndef _tolower
126 # define _tolower(c)  ((c) - 'A' + 'a')
127 #endif
128
129
130 /* This is defined by the SCREENHACK_MAIN() macro via screenhack.h.
131  */
132 extern struct xscreensaver_function_table *xscreensaver_function_table;
133
134
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 */
138
139
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 },
151
152 # ifdef DEBUG_PAIR
153   { "-pair",    ".pair",                XrmoptionNoArg, "True" },
154 # endif /* DEBUG_PAIR */
155   { 0, 0, 0, 0 }
156 };
157
158 static char *default_defaults[] = {
159   ".root:               false",
160   "*geometry:           600x480", /* this should be .geometry, but nooooo... */
161   "*mono:               false",
162   "*installColormap:    false",
163   "*doFPS:              false",
164   "*visualID:           default",
165   "*windowID:           ",
166   "*desktopGrabber:     xscreensaver-getimage %s",
167   0
168 };
169
170 static XrmOptionDescRec *merged_options;
171 static int merged_options_size;
172 static char **merged_defaults;
173
174
175 static void
176 merge_options (void)
177 {
178   struct xscreensaver_function_table *ft = xscreensaver_function_table;
179
180   const XrmOptionDescRec *options = ft->options;
181   const char * const *defaults    = ft->defaults;
182   const char *progclass           = ft->progclass;
183
184   int def_opts_size, opts_size;
185   int def_defaults_size, defaults_size;
186
187   for (def_opts_size = 0; default_options[def_opts_size].option;
188        def_opts_size++)
189     ;
190   for (opts_size = 0; options[opts_size].option; opts_size++)
191     ;
192
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)));
200
201   for (def_defaults_size = 0; default_defaults[def_defaults_size];
202        def_defaults_size++)
203     ;
204   for (defaults_size = 0; defaults[defaults_size]; defaults_size++)
205     ;
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));
212
213   /* This totally sucks.  Xt should behave like this by default.
214      If the string in `defaults' looks like ".foo", change that
215      to "Progclass.foo".
216    */
217   {
218     char **s;
219     for (s = merged_defaults; *s; s++)
220       if (**s == '.')
221         {
222           const char *oldr = *s;
223           char *newr = (char *) malloc(strlen(oldr) + strlen(progclass) + 3);
224           strcpy (newr, progclass);
225           strcat (newr, oldr);
226           *s = newr;
227         }
228       else
229         *s = strdup (*s);
230   }
231 }
232
233 \f
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.
236  */
237
238 static int
239 screenhack_ehandler (Display *dpy, XErrorEvent *error)
240 {
241   fprintf (stderr, "\nX error in %s:\n", progname);
242   if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
243     exit (-1);
244   else
245     fprintf (stderr, " (nonfatal.)\n");
246   return 0;
247 }
248
249 static Bool
250 MapNotify_event_p (Display *dpy, XEvent *event, XPointer window)
251 {
252   return (event->xany.type == MapNotify &&
253           event->xvisibility.window == (Window) window);
254 }
255
256
257 static Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW;
258
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.
262  */
263 static Bool
264 screenhack_handle_event_1 (Display *dpy, XEvent *event)
265 {
266   switch (event->xany.type)
267     {
268     case KeyPress:
269       {
270         KeySym keysym;
271         char c = 0;
272         XLookupString (&event->xkey, &c, 1, &keysym, 0);
273         if (c == 'q' ||
274             c == 'Q' ||
275             c == 3 ||   /* ^C */
276             c == 27)    /* ESC */
277           return False;  /* exit */
278         else if (! (keysym >= XK_Shift_L && keysym <= XK_Hyper_R))
279           XBell (dpy, 0);  /* beep for non-chord keys */
280       }
281       break;
282     case ButtonPress:
283       XBell (dpy, 0);
284       break;
285     case ClientMessage:
286       {
287         if (event->xclient.message_type != XA_WM_PROTOCOLS)
288           {
289             char *s = XGetAtomName(dpy, event->xclient.message_type);
290             if (!s) s = "(null)";
291             fprintf (stderr, "%s: unknown ClientMessage %s received!\n",
292                      progname, s);
293           }
294         else if (event->xclient.data.l[0] != XA_WM_DELETE_WINDOW)
295           {
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",
301                      progname, s1, s2);
302           }
303         else
304           {
305             return False;  /* exit */
306           }
307       }
308       break;
309     }
310   return True;
311 }
312
313
314 static Visual *
315 pick_visual (Screen *screen)
316 {
317   struct xscreensaver_function_table *ft = xscreensaver_function_table;
318
319   if (ft->pick_visual_hook)
320     {
321       Visual *v = ft->pick_visual_hook (screen);
322       if (v) return v;
323     }
324
325   return get_visual_resource (screen, "visualID", "VisualID", False);
326 }
327
328
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.
333  */
334 static void
335 visual_warning (Screen *screen, Window window, Visual *visual, Colormap cmap,
336                 Bool window_p)
337 {
338   struct xscreensaver_function_table *ft = xscreensaver_function_table;
339
340   char *visual_string = get_string_resource (DisplayOfScreen (screen),
341                                              "visualID", "VisualID");
342   Visual *desired_visual = pick_visual (screen);
343   char win[100];
344   char why[100];
345
346   if (window == RootWindowOfScreen (screen))
347     strcpy (win, "root window");
348   else
349     sprintf (win, "window 0x%lx", (unsigned long) window);
350
351   if (window_p)
352     sprintf (why, "-window-id 0x%lx", (unsigned long) window);
353   else
354     strcpy (why, "-root");
355
356   if (visual_string && *visual_string)
357     {
358       char *s;
359       for (s = visual_string; *s; s++)
360         if (isupper (*s)) *s = _tolower (*s);
361
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. */
366         ;
367       else if (visual != desired_visual)
368         {
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));
373         }
374       free (visual_string);
375     }
376
377   if (visual == DefaultVisualOfScreen (screen) &&
378       has_writable_cells (screen, visual) &&
379       get_boolean_resource (DisplayOfScreen (screen),
380                             "installColormap", "InstallColormap"))
381     {
382       fprintf (stderr, "%s: ignoring `-install' because of `%s'.\n",
383                progname, why);
384       fprintf (stderr, "%s: using %s's colormap 0x%lx.\n",
385                progname, win, (unsigned long) cmap);
386     }
387
388   if (ft->validate_visual_hook)
389     {
390       if (! ft->validate_visual_hook (screen, win, visual))
391         exit (1);
392     }
393 }
394
395
396 static void
397 fix_fds (void)
398 {
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
408      three FDs.)
409
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.
413
414      Really, this crap is technically required of *every* X program,
415      if you want it to be robust in the face of "2>&-".
416    */
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);
423 }
424
425
426 static Boolean
427 screenhack_table_handle_events (Display *dpy,
428                                 const struct xscreensaver_function_table *ft,
429                                 Window window, void *closure
430 #ifdef DEBUG_PAIR
431                                 , Window window2, void *closure2
432 #endif
433                                 )
434 {
435   XtAppContext app = XtDisplayToApplicationContext (dpy);
436
437   if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
438     XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
439
440   while (XPending (dpy))
441     {
442       XEvent event;
443       XNextEvent (dpy, &event);
444
445       if (event.xany.type == ConfigureNotify)
446         {
447           if (event.xany.window == window)
448             ft->reshape_cb (dpy, window, closure,
449                             event.xconfigure.width, event.xconfigure.height);
450 #ifdef DEBUG_PAIR
451           if (event.xany.window == window2)
452             ft->reshape_cb (dpy, window2, closure2,
453                             event.xconfigure.width, event.xconfigure.height);
454 #endif
455         }
456       else if (event.xany.type == ClientMessage ||
457                (! (event.xany.window == window
458                    ? ft->event_cb (dpy, window, closure, &event)
459 #ifdef DEBUG_PAIR
460                    : event.xany.window == window2
461                    ? ft->event_cb (dpy, window2, closure2, &event)
462 #endif
463                    : 0)))
464         if (! screenhack_handle_event_1 (dpy, &event))
465           return False;
466
467       if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
468         XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
469     }
470   return True;
471 }
472
473
474 static Boolean
475 usleep_and_process_events (Display *dpy,
476                            const struct xscreensaver_function_table *ft,
477                            Window window, fps_state *fpst, void *closure,
478                            unsigned long delay
479 #ifdef DEBUG_PAIR
480                          , Window window2, fps_state *fpst2, void *closure2,
481                            unsigned long delay2
482 #endif
483                            )
484 {
485   do {
486     unsigned long quantum = 100000;  /* 1/10th second */
487     if (quantum > delay) 
488       quantum = delay;
489     delay -= quantum;
490
491     XSync (dpy, False);
492     if (quantum > 0)
493       {
494         usleep (quantum);
495         if (fpst) fps_slept (fpst, quantum);
496 #ifdef DEBUG_PAIR
497         if (fpst2) fps_slept (fpst2, quantum);
498 #endif
499       }
500
501     if (! screenhack_table_handle_events (dpy, ft, window, closure
502 #ifdef DEBUG_PAIR
503                                           , window2, closure2
504 #endif
505                                           ))
506       return False;
507   } while (delay > 0);
508
509   return True;
510 }
511
512
513 static void
514 screenhack_do_fps (Display *dpy, Window w, fps_state *fpst, void *closure)
515 {
516   fps_compute (fpst, 0);
517   fps_draw (fpst);
518 }
519
520
521 static void
522 run_screenhack_table (Display *dpy, 
523                       Window window,
524 # ifdef DEBUG_PAIR
525                       Window window2,
526 # endif
527                       const struct xscreensaver_function_table *ft,
528                       int view)
529 {
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" 
541    DBusMessage* msg;
542    DBusConnection* conn;
543    DBusError err;
544    DBusMessageIter args;
545    int ret;
546    char pause = 0;
547    int param = 0;
548    int start_frame = 200;
549
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
552      xlockmore_setup().
553    */
554   void *(*init_cb) (Display *, Window, void *) = 
555     (void *(*) (Display *, Window, void *)) ft->init_cb;
556
557   void (*fps_cb) (Display *, Window, fps_state *, void *) = ft->fps_cb;
558
559   void *closure = init_cb (dpy, window, ft->setup_arg);
560   fps_state *fpst = fps_init (dpy, window);
561
562 #ifdef DEBUG_PAIR
563   void *closure2 = 0;
564   fps_state *fpst2 = 0;
565   if (window2) closure2 = init_cb (dpy, window2, ft->setup_arg);
566   if (window2) fpst2 = fps_init (dpy, window2);
567 #endif
568
569   if (! closure)  /* if it returns nothing, it can't possibly be re-entrant. */
570     abort();
571
572   if (! fps_cb) fps_cb = screenhack_do_fps;
573   /* DBUS */
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); 
580   }
581   if (NULL == conn) {
582          fprintf(stderr, "Connection Null\n"); 
583          exit(1); 
584   }
585   if (view == 1){
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);
588   }
589   if (view == 2){
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);
592   }
593   if (view == 3){
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);
596   }
597   if (view == 4){
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);
600   }
601
602   dbus_connection_flush(conn);
603
604   while (1)
605     {
606       if (pause == 0){
607         unsigned long delay = ft->draw_cb (dpy, window, closure);
608 #ifdef DEBUG_PAIR
609         unsigned long delay2 = 0;
610         if (window2) delay2 = ft->draw_cb (dpy, window2, closure2);
611 #endif
612
613      
614         if (fpst) fps_cb (dpy, window, fpst, closure);
615 #ifdef DEBUG_PAIR
616         if (fpst2) fps_cb (dpy, window, fpst2, closure);
617 #endif
618       if (! usleep_and_process_events (dpy, ft,
619                                        window, fpst, closure, delay
620 #ifdef DEBUG_PAIR
621                                        , window2, fpst2, closure2, delay2
622 #endif
623                                        ))
624         break;
625
626       }
627       if (start_frame > 0) {
628           start_frame--;
629           continue;
630         }
631       if (pause == 0)
632       /* non blocking read of the next available message */
633         dbus_connection_read_write(conn, 0);
634       else
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); */
639
640       msg = dbus_connection_pop_message(conn);
641
642         /*fprintf(stderr, "2222222\n");*/
643       if (NULL == msg){  
644
645         /*fprintf(stderr, "333333\n");*/
646           continue; 
647       }
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); 
655            pause = 1;
656            dbus_message_unref (msg);
657            continue;
658       }
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); 
664            pause = 0;
665            dbus_message_unref (msg);
666            continue;
667       }
668 #if 0  
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");
678           else{ 
679               dbus_message_iter_get_basic(&args, &param);
680               fprintf(stderr, "dbus param = %i\n", param);
681           }
682           if (param == view){
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); 
685                      pause = 1;
686               }
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); 
689                      pause = 0;
690               }
691               /*msg = dbus_connection_pop_message(conn);*/
692               fprintf(stderr, "dbus  steal message\n"); 
693               /*dbus_connection_steal_borrowed_message(conn, msg);*/
694           }else{ 
695               fprintf(stderr, "dbus  return message\n"); 
696               /*dbus_connection_return_message(conn, msg);*/
697           }
698       }    
699 #endif      
700       dbus_message_unref (msg);
701       /* check this is a method call for the right interface & method */
702       /*
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); 
708            pause = 1;
709            dbus_message_unref (msg); 
710            continue;
711       }
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); 
717            pause = 0;
718            dbus_message_unref (msg); 
719            continue;
720       }
721 */
722     }
723
724   ft->free_cb (dpy, window, closure);
725   if (fpst) fps_free (fpst);
726
727 #ifdef DEBUG_PAIR
728   if (window2) ft->free_cb (dpy, window2, closure2);
729   if (window2) fps_free (fpst2);
730 #endif
731   /* close the connection */
732   dbus_connection_close(conn);
733 }
734
735
736 static Widget
737 make_shell (Screen *screen, Widget toplevel, int width, int height)
738 {
739   Display *dpy = DisplayOfScreen (screen);
740   Visual *visual = pick_visual (screen);
741   Boolean def_visual_p = (toplevel && 
742                           visual == DefaultVisualOfScreen (screen));
743
744   if (width  <= 0) width  = 600;
745   if (height <= 0) height = 480;
746
747   if (def_visual_p)
748     {
749       Window window;
750       XtVaSetValues (toplevel,
751                      XtNmappedWhenManaged, False,
752                      XtNwidth, width,
753                      XtNheight, height,
754                      XtNinput, True,  /* for WM_HINTS */
755                      NULL);
756       XtRealizeWidget (toplevel);
757       window = XtWindow (toplevel);
758
759       if (get_boolean_resource (dpy, "installColormap", "InstallColormap"))
760         {
761           Colormap cmap = 
762             XCreateColormap (dpy, window, DefaultVisualOfScreen (screen),
763                              AllocNone);
764           XSetWindowColormap (dpy, window, cmap);
765         }
766     }
767   else
768     {
769       unsigned int bg, bd;
770       Widget new;
771       Colormap cmap = XCreateColormap (dpy, VirtualRootWindowOfScreen(screen),
772                                        visual, AllocNone);
773       bg = get_pixel_resource (dpy, cmap, "background", "Background");
774       bd = get_pixel_resource (dpy, cmap, "borderColor", "Foreground");
775
776       new = XtVaAppCreateShell (progname, progclass,
777                                 topLevelShellWidgetClass, dpy,
778                                 XtNmappedWhenManaged, False,
779                                 XtNvisual, visual,
780                                 XtNdepth, visual_depth (screen, visual),
781                                 XtNwidth, width,
782                                 XtNheight, height,
783                                 XtNcolormap, cmap,
784                                 XtNbackground, (Pixel) bg,
785                                 XtNborderColor, (Pixel) bd,
786                                 XtNinput, True,  /* for WM_HINTS */
787                                 NULL);
788
789       if (!toplevel)  /* kludge for the second window in -pair mode... */
790         XtVaSetValues (new, XtNx, 0, XtNy, 550, NULL);
791
792       XtRealizeWidget (new);
793       toplevel = new;
794     }
795
796   return toplevel;
797 }
798
799 static void
800 init_window (Display *dpy, Widget toplevel, const char *title)
801 {
802   Window window;
803   XWindowAttributes xgwa;
804   XtPopup (toplevel, XtGrabNone);
805   XtVaSetValues (toplevel, XtNtitle, title, NULL);
806
807   /* Select KeyPress, and announce that we accept WM_DELETE_WINDOW.
808    */
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,
815                    PropModeReplace,
816                    (unsigned char *) &XA_WM_DELETE_WINDOW, 1);
817 }
818
819
820 int
821 main (int argc, char **argv)
822 {
823   struct xscreensaver_function_table *ft = xscreensaver_function_table;
824
825 /*  osso_context_t  *osso; */
826
827   XWindowAttributes xgwa;
828   Widget toplevel;
829   Display *dpy;
830   Window window;
831 # ifdef DEBUG_PAIR
832   Window window2 = 0;
833   Widget toplevel2 = 0;
834 # endif
835   XtAppContext app;
836   Bool root_p;
837   Window on_window = 0;
838   XEvent event;
839   Boolean dont_clear;
840   char version[255];
841   int view;
842
843   fix_fds();
844
845   progname = argv[0];   /* reset later */
846   progclass = ft->progclass;
847
848   if (ft->setup_cb)
849     ft->setup_cb (ft, ft->setup_arg);
850
851   merge_options ();
852
853 #ifdef __sgi
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.
861    */
862   SgiUseSchemes ("none"); 
863 #endif /* __sgi */
864
865   toplevel = XtAppInitialize (&app, progclass, merged_options,
866                               merged_options_size, &argc, argv,
867                               merged_defaults, 0, 0);
868
869   dpy = XtDisplay (toplevel);
870
871   XtGetApplicationNameAndClass (dpy,
872                                 (char **) &progname,
873                                 (char **) &progclass);
874
875   /* half-assed way of avoiding buffer-overrun attacks. */
876   if (strlen (progname) >= 100) ((char *) progname)[100] = 0;
877
878   XSetErrorHandler (screenhack_ehandler);
879
880   XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False);
881   XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
882
883   {
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, ')');
890     *s2 = 0;
891     *s4 = 0;
892     sprintf (version, "%s: from the XScreenSaver %s distribution (%s.)",
893              progclass, s1, s3);
894     free(v);
895   }
896
897   if (argc > 1)
898     {
899       const char *s;
900       int i;
901       int x = 18;
902       int end = 78;
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");
908
909       if (!help_p)
910         fprintf(stderr, "Unrecognised option: %s\n", argv[1]);
911       fprintf (stderr, "Options include: ");
912       for (i = 0; i < merged_options_size; i++)
913         {
914           char *sw = merged_options [i].option;
915           Bool argp = (merged_options [i].argKind == XrmoptionSepArg);
916           int size = strlen (sw) + (argp ? 6 : 0) + 2;
917           if (x + size >= end)
918             {
919               fprintf (stderr, "\n\t\t ");
920               x = 18;
921             }
922           x += size;
923           fprintf (stderr, "%s", sw);
924           if (argp) fprintf (stderr, " <arg>");
925           if (i != merged_options_size - 1) fprintf (stderr, ", ");
926         }
927
928       fprintf (stderr, ".\n");
929
930 #if 0
931       if (help_p)
932         {
933           fprintf (stderr, "\nResources:\n\n");
934           for (i = 0; i < merged_options_size; i++)
935             {
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);
940
941               if (s)
942                 {
943                   int L = strlen(s);
944                 while (L > 0 && (s[L-1] == ' ' || s[L-1] == '\t'))
945                   s[--L] = 0;
946                 }
947
948               fprintf (stderr, "    %-16s %-18s ", opt, res);
949               if (merged_options [i].argKind == XrmoptionSepArg)
950                 {
951                   fprintf (stderr, "[%s]", (s ? s : "?"));
952                 }
953               else
954                 {
955                   fprintf (stderr, "%s", (val ? val : "(null)"));
956                   if (val && s && !strcasecmp (val, s))
957                     fprintf (stderr, " [default]");
958                 }
959               fprintf (stderr, "\n");
960             }
961           fprintf (stderr, "\n");
962         }
963 #endif
964
965       exit (help_p ? 0 : 1);
966     }
967
968   {
969     char **s;
970     for (s = merged_defaults; *s; s++)
971       free(*s);
972   }
973
974   free (merged_options);
975   free (merged_defaults);
976   merged_options = 0;
977   merged_defaults = 0;
978
979   dont_clear = get_boolean_resource (dpy, "dontClearRoot", "Boolean");
980   mono_p = get_boolean_resource (dpy, "mono", "Boolean");
981   if (CellsOfScreen (DefaultScreenOfDisplay (dpy)) <= 2)
982     mono_p = True;
983
984   root_p = get_boolean_resource (dpy, "root", "Boolean");
985
986   {
987     char *s = get_string_resource (dpy, "windowID", "WindowID");
988     if (s && *s)
989       on_window = get_integer_resource (dpy, "windowID", "WindowID");
990     if (s) free (s);
991   }
992
993   view = get_integer_resource (dpy, "view", "view");
994   fprintf(stderr, "View %i\n", view);
995   if (on_window)
996     {
997       window = (Window) on_window;
998       XtDestroyWidget (toplevel);
999       XGetWindowAttributes (dpy, window, &xgwa);
1000       visual_warning (xgwa.screen, window, xgwa.visual, xgwa.colormap, True);
1001
1002       /* Select KeyPress and resize events on the external window.
1003        */
1004       xgwa.your_event_mask |= KeyPressMask | StructureNotifyMask;
1005       XSelectInput (dpy, window, xgwa.your_event_mask);
1006
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.)
1010        */
1011       if (! (xgwa.all_event_masks & (ButtonPressMask | ButtonReleaseMask)))
1012         XSelectInput (dpy, window,
1013                       (xgwa.your_event_mask |
1014                        ButtonPressMask | ButtonReleaseMask));
1015     }
1016   else if (root_p)
1017     {
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);
1024     }
1025   else
1026     {
1027       Widget new = make_shell (XtScreen (toplevel), toplevel,
1028                                toplevel->core.width,
1029                                toplevel->core.height);
1030       if (new != toplevel)
1031         {
1032           XtDestroyWidget (toplevel);
1033           toplevel = new;
1034         }
1035
1036       init_window (dpy, toplevel, version);
1037       window = XtWindow (toplevel);
1038       XGetWindowAttributes (dpy, window, &xgwa);
1039
1040 # ifdef DEBUG_PAIR
1041       if (get_boolean_resource (dpy, "pair", "Boolean"))
1042         {
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);
1048         }
1049 # endif /* DEBUG_PAIR */
1050     }
1051
1052   if (!dont_clear)
1053     {
1054       unsigned int bg = get_pixel_resource (dpy, xgwa.colormap,
1055                                             "background", "Background");
1056       XSetWindowBackground (dpy, window, bg);
1057       XClearWindow (dpy, window);
1058 # ifdef DEBUG_PAIR
1059       if (window2)
1060         {
1061           XSetWindowBackground (dpy, window2, bg);
1062           XClearWindow (dpy, window2);
1063         }
1064 # endif
1065     }
1066
1067   if (!root_p && !on_window)
1068     /* wait for it to be mapped */
1069     XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
1070
1071   XSync (dpy, False);
1072
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
1077   ya_rand_init (0);
1078
1079   run_screenhack_table (dpy, window, 
1080 # ifdef DEBUG_PAIR
1081                         window2,
1082 # endif
1083                         ft, view);
1084
1085   XtDestroyWidget (toplevel);
1086   XtDestroyApplicationContext (app);
1087
1088   return 0;
1089 }