http://ftp.aanet.ru/pub/Linux/X11/apps/xscreensaver-2.31.tar.gz
[xscreensaver] / driver / splash.c
1 /* xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski <jwz@netscape.com>
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
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
15
16 #include <X11/Intrinsic.h>
17 #include <X11/StringDefs.h>
18
19 #ifdef HAVE_MOTIF
20 # include <Xm/Xm.h>
21
22 #else  /* HAVE_ATHENA */
23 # include <X11/Shell.h>
24 # include <X11/Xaw/Form.h>
25 # include <X11/Xaw/Box.h>
26 # include <X11/Xaw/Command.h>
27 # include <X11/Xaw/Dialog.h>
28 #endif /* HAVE_ATHENA */
29
30 #include "xscreensaver.h"
31 #include "visual.h"
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35
36 extern void skull (Display *, Window, GC, GC, int, int, int, int);
37
38 void
39 roger (Widget button, XtPointer client_data, XtPointer call_data)
40 {
41   Display *dpy = XtDisplay (button);
42   Screen *screen = XtScreen (button);
43   Window window = XtWindow (button);
44   Arg av [10];
45   int ac = 0;
46   XGCValues gcv;
47   Colormap cmap;
48   GC draw_gc, erase_gc;
49   unsigned int fg, bg;
50   int x, y, size;
51   XWindowAttributes xgwa;
52   XGetWindowAttributes (dpy, window, &xgwa);
53   cmap = xgwa.colormap;
54   if (xgwa.width > xgwa.height) size = xgwa.height;
55   else size = xgwa.width;
56   if (size > 40) size -= 30;
57   x = (xgwa.width - size) / 2;
58   y = (xgwa.height - size) / 2;
59   XtSetArg (av [ac], XtNforeground, &fg); ac++;
60   XtSetArg (av [ac], XtNbackground, &bg); ac++;
61   XtGetValues (button, av, ac);
62   /* if it's black on white, swap it cause it looks better (hack hack) */
63   if (fg == BlackPixelOfScreen (screen) && bg == WhitePixelOfScreen (screen))
64     fg = WhitePixelOfScreen (screen), bg = BlackPixelOfScreen (screen);
65   gcv.foreground = bg;
66   erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
67   gcv.foreground = fg;
68   draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
69   XFillRectangle (dpy, window, erase_gc, 0, 0, xgwa.width, xgwa.height);
70   skull (dpy, window, draw_gc, erase_gc, x, y, size, size);
71   XFreeGC (dpy, draw_gc);
72   XFreeGC (dpy, erase_gc);
73 }
74
75
76 static Widget splash_shell;
77 extern Widget splash_dialog;
78 extern Widget splash_form;
79 extern Widget splash_roger_label;
80 extern Widget splash_label1;
81 extern Widget splash_label3;
82 extern Widget splash_demo;
83 extern Widget splash_prefs;
84 extern Widget splash_help;
85
86 static void
87 splash_sink(saver_info *si)
88 {
89   if (si->splash_dialog)
90     {
91       XtDestroyWidget(si->splash_dialog);
92       XtDestroyWidget(splash_shell);
93       si->splash_dialog = 0;
94       splash_shell = 0;
95     }
96 }
97
98 static void
99 splash_sink_timer (XtPointer closure, XtIntervalId *id)
100 {
101   saver_info *si = (saver_info *) closure;
102   splash_sink(si);
103 }
104
105
106 static void
107 send_self_clientmessage (saver_info *si, Atom command)
108 {
109   Display *dpy = si->dpy;
110   Window window = si->default_screen->screensaver_window;
111   XEvent event;
112   event.xany.type = ClientMessage;
113   event.xclient.display = si->dpy;
114   event.xclient.window = window;
115   event.xclient.message_type = XA_SCREENSAVER;
116   event.xclient.format = 32;
117   event.xclient.data.l[0] = (long) command;
118   if (! XSendEvent (dpy, window, False, 0L, &event))
119     fprintf (stderr, "%s: XSendEvent(dpy, 0x%x ...) failed.\n",
120              progname, (unsigned int) window);
121 }
122
123 static void
124 splash_demo_cb (Widget button, XtPointer client_data, XtPointer call_data)
125 {
126   saver_info *si = (saver_info *) client_data;
127   splash_sink(si);
128   send_self_clientmessage (si, XA_DEMO);
129 }
130
131 static void
132 splash_prefs_cb (Widget button, XtPointer client_data, XtPointer call_data)
133 {
134   saver_info *si = (saver_info *) client_data;
135   splash_sink(si);
136   send_self_clientmessage (si, XA_PREFS);
137 }
138
139 static void
140 splash_help_cb (Widget button, XtPointer client_data, XtPointer call_data)
141 {
142   saver_info *si = (saver_info *) client_data;
143   saver_preferences *p = &si->prefs;
144
145   splash_sink(si);
146
147   if (!p->help_url || !*p->help_url)
148     fprintf(stderr, "%s: no Help URL has been specified.\n");
149   else if (!p->load_url_command || !*p->load_url_command)
150     fprintf(stderr, "%s: no URL-loading command has been specified.\n");
151   else
152     {
153       char *buf = (char *) malloc (strlen(p->load_url_command) +
154                                    (strlen(p->help_url) * 2) + 10);
155       sprintf(buf, p->load_url_command, p->help_url, p->help_url);
156       system(buf);
157     }
158 }
159
160 static void
161 make_splash_dialog (saver_info *si)
162 {
163   saver_screen_info *ssi = si->default_screen;
164   Visual *v = DefaultVisualOfScreen(ssi->screen);
165
166   /* The splash dialog must always be created on the default visual and
167      with the default colormap, so that it shows up in the right colors
168      when viewed along with the rest of the desktop.  The other xscreensaver
169      dialogs don't have this constraint, since they are only seen when the
170      blackout window is also exposed.
171
172      To accomplish this, we need our own ApplicationShell, since the shell
173      in si->default_screen->toplevel_shell might have a non-default visual.
174    */
175   splash_shell = XtVaAppCreateShell (progname, progclass,
176                                      applicationShellWidgetClass,
177                                      si->dpy,
178                                      XtNscreen, ssi->screen,
179                                      XtNvisual, v,
180                                      XtNdepth,  visual_depth(ssi->screen, v),
181                                      0);
182
183   create_splash_dialog (splash_shell, v,
184                         DefaultColormapOfScreen (ssi->screen));
185   si->splash_dialog = splash_dialog; /* gaaah... */
186
187 #ifdef HAVE_ATHENA
188   XawDialogAddButton(splash_form,"demo",  splash_demo_cb, si);
189   XawDialogAddButton(splash_form,"prefs", splash_prefs_cb, si);
190   XawDialogAddButton(splash_form,"help",  splash_help_cb, si);
191   splash_demo  = XtNameToWidget(splash_form,"demo");
192   splash_prefs = XtNameToWidget(splash_form,"prefs");
193   splash_help  = XtNameToWidget(splash_form,"help");
194
195   /* Lose the label on the inner dialog. */
196   {
197     Widget w = XtNameToWidget(splash_form, "label");
198     if (w) XtUnmanageChild(w);
199   }
200
201 #else  /* HAVE_MOTIF */
202   /* Another random thing necessary in 1.2.1 but not 1.1.5... */
203   XtVaSetValues (splash_roger_label, XmNborderWidth, 1, 0);
204
205   XtAddCallback (splash_demo, XmNactivateCallback, splash_demo_cb, si);
206   XtAddCallback (splash_prefs, XmNactivateCallback, splash_prefs_cb, si);
207   XtAddCallback (splash_help, XmNactivateCallback, splash_help_cb, si);
208   XtAddCallback (splash_roger_label, XmNexposeCallback, roger, si);
209
210 #endif /* HAVE_MOTIF */
211
212   format_into_label (splash_label1, si->version);
213
214   XtRealizeWidget(splash_dialog);
215 }
216
217 void
218 pop_splash_dialog (saver_info *si)
219 {
220   XtIntervalId splash_sink_id;
221
222   if (si->prefs.splash_duration <= 0)
223     return;
224
225   if (! si->splash_dialog)
226     make_splash_dialog (si);
227
228 #ifdef HAVE_ATHENA
229   splash_form = splash_dialog; /* kludge */
230 #endif
231
232   pop_up_dialog_box (splash_dialog, splash_form,
233                      /* for debugging -- don't ask */
234                      (si->prefs.debug_p ? 69 : 0) +
235                      3);
236   XtManageChild (splash_form);
237
238 #ifdef HAVE_ATHENA
239   if (splash_roger_label)
240     roger (splash_roger_label, 0, 0);
241 #endif /* HAVE_ATHENA */
242
243   splash_sink_id = XtAppAddTimeOut (si->app, si->prefs.splash_duration,
244                                     splash_sink_timer, (XtPointer) si);
245 }