2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: Saver.c /main/8 1996/11/21 19:56:41 drk $ */
25 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
26 * (c) Copyright 1993, 1994 International Business Machines Corp. *
27 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
28 * (c) Copyright 1993, 1994 Novell, Inc. *
30 /*************************************<+>*************************************
31 *****************************************************************************
37 ** This file contains public and private screen saver utilities.
40 ** DtSaverGetWindows() - return array of windows on which saver can draw
43 ** _DtSaverStart() - launch specified screen saver
44 ** _DtSaverStop() - kill specified screen saver
46 *****************************************************************************
47 *************************************<+>*************************************/
51 #define X_INCLUDE_STRING_H
52 #define XOS_USE_XT_LOCKING
53 #include <X11/Xos_r.h>
54 #include <X11/Intrinsic.h>
57 #include "DtSvcLock.h"
60 * Constants global to this file.
62 #define DT_SAVER_MAX_SCREENS 10
65 unsigned short serial;
67 struct saver_state *next;
70 static Atom xa_saver_register;
72 static struct saver_state saver_list = {0, (Window)0, NULL};
77 static void RegisterSaverCB(
79 XtPointer client_data,
81 Boolean *continue_to_dispatch
85 /*************************************<->*************************************
87 * _DtSaverStart() - start a screen saver
91 * _DtSaverStart() is one of a suite of screen saver API's used in the
92 * desktop. These APIs are:
94 * _DtSaverStart() starts a screen saver (private)
95 * _DtSaverStop() stops a screen saver (private)
96 * DtSaverGetWindows() return array of windows on which saver can draw
98 * The _DtSaverStart() API allocates a state variable for the screen saver
99 * which contains a serial number and NIL window ID. A list of these state
100 * variables is maintained, one for each call to _DtSaverStart().
101 * DtSaverStart() then sets up the DTSAVERINFO environment variable containing
102 * the serial number, window count and window list provided. Finally, it
103 * launches the provided action and returns an opaque pointer to the state
104 * variable. The action is expected to be a screen saver which makes use
105 * of the DtSaverGetWindows() API.
107 * When the screen saver starts, it calls the DtSaverGetWindows() API. From
108 * the screen saver perspective, the API returns an array of windows on which
109 * the screen saver can draw. To to this, the API obtains the DTSAVERINFO
110 * environment variable, and parses out the window array. The API also
111 * creates a window and sends a ClientMessage to the first DTSAVERINFO window
112 * containing the serial number and newly created window id.
114 * RegisterSaverCB() is a callback called when the ClientMessage arrives from
115 * a screen saver. This callback first searches the screen saver state list
116 * by serial number. If a state variable is not found, RegisterSaverCB()
117 * assumes the screen saver must have been stopped by a call to
118 * _DtSaverStop(), so kills the client via XKillClient() using the window id
119 * provided in the message. If the state variable is located,
120 * RegisterSaverCB() stores the window id in the state variable.
122 * _DtSaverStop() searches the screen saver list using the serial number
123 * provided in the input state variable. It should always be found. When
124 * found, if the state variable window id is set, _DtSaverStop() kills the
125 * screen saver client via XKillClient(), deletes the state variable from
126 * the list and deallocates the state variable.
130 * display - display structure
131 * drawArea - array of widgets to be stored drawn upon by saver
132 * count - number of elements in drawArea array
133 * saverAction - screen saver action name to invoke
134 * wAction - widget on which possible DtActionInvoke() errors should display
141 * state - pointer to opaque state structure
145 * This function uses DtActionInvoke() to launch an action. As a result,
146 * the caller is responsible for loading and maintaining the action database
147 * using the DtDbLoad() function and procedures. The caller
148 * must call _DtSaverStop() to terminate screen saver
150 *************************************<->***********************************/
159 static char envdata[(DT_SAVER_MAX_SCREENS * 12) + 20];
160 struct saver_state *state;
161 struct saver_state *p;
166 * If first time in, insert envdata in process environment.
168 if (saver_list.serial == 0)
172 xa_saver_register = XInternAtom(display, "_DT_SAVER_REGISTER", False);
176 * Add event handler (it might already be there - that's ok).
178 XtAddEventHandler(drawArea[0], 0, True, RegisterSaverCB, NULL);
181 * Allocate state structure for this saver.
183 if (!(state = (struct saver_state *)malloc(sizeof(struct saver_state))))
185 _DtSvcProcessUnlock();
190 * Initialize state structure and append to saver_list.
192 state->serial = saver_list.serial++;
193 state->xid = (Window)0;
196 while (p->next != NULL)
203 * Set up environment. It will look like:
204 * DTSAVERINFO="<serial> <count> <win0> <win1> ... <winN>"
206 sprintf(envdata, "DTSAVERINFO=%u %i %lx",
207 state->serial, count, XtWindow(drawArea[0]));
208 for (i = 1; i < count; i++)
210 char *pe = envdata + strlen(envdata);
211 sprintf(pe, " %lx", XtWindow(drawArea[i]));
213 _DtSvcProcessUnlock();
218 DtActionInvoke(wAction, saverAction, NULL, NULL,
219 NULL, NULL, NULL, NULL, NULL, NULL);
222 * Return array as state information.
224 return((void *)state);
228 /*************************************<->*************************************
230 * _DtSaverStop() - stop a screen saver
234 * Stop an external screen saver started with DtStartSaver().
236 * _DtSaverStop() searches the screen saver list using the serial number
237 * provided in the input state variable. It should always be found. When
238 * found, if the state variable window id is set, _DtSaverStop() kills the
239 * screen saver client via XKillClient(), deletes the state variable from
240 * the list and deallocates the state variable.
244 * display - display structure
245 * state - state returned from _DtSaverStart()
256 *************************************<->***********************************/
263 struct saver_state *state = (struct saver_state *)pstate;
264 struct saver_state *p;
268 * Unlink from saver_list.
271 while (p->next != state)
275 p->next = state->next;
276 _DtSvcProcessUnlock();
279 * Kill client using window id provided by RegisterSaverCB().
281 if (state->xid != (Window)0)
283 XKillClient(display, state->xid);
287 * Free state allocated by _DtSaverStart();
293 /*************************************<->*************************************
295 * DtSaverGetWindows() - return array of windows on which saver can draw
300 * This is a PUBLIC API.
302 * When the screen saver starts, it calls the DtSaverGetWindows() API. From
303 * the screen saver perspective, the API returns an array of windows on which
304 * the screen saver can draw. To to this, the API obtains the DTSAVERINFO
305 * environment variable, and parses out the window array. The API also
306 * creates a window and sends a ClientMessage to the first DTSAVERINFO window
307 * containing the serial number and newly created window id.
311 * display - display structure
312 * window - pointer to memory in which to place pointer to array
313 * count - pointer to memory in which to place count
317 * *window - pointer to array
322 * True - window list returned
323 * False - window list not returned
327 * The array memory should be freed by the caller via free().
329 *************************************<->***********************************/
337 char *envdata, *p, *q;
338 unsigned short serial;
340 XClientMessageEvent event;
342 _Xstrtokparams strtok_buf;
343 _DtSvcDisplayToAppContext(display);
350 xa_saver_register = XInternAtom(display, "_DT_SAVER_REGISTER", False);
353 * Get invocation information from environment.
355 envdata = getenv("DTSAVERINFO");
358 _DtSvcProcessUnlock();
359 _DtSvcAppUnlock(app);
364 * Copy string for later strtok() use.
369 _DtSvcProcessUnlock();
370 _DtSvcAppUnlock(app);
377 q = _XStrtok(p, " ", strtok_buf);
378 serial = (unsigned short)strtoul(q, NULL, 10);
383 q = _XStrtok(NULL, " ", strtok_buf);
384 envcount = (int)strtoul(q, NULL, 10);
387 * Allocate memory for window array.
389 *window = (Window *)malloc((envcount)*sizeof(Window *));
393 _DtSvcProcessUnlock();
394 _DtSvcAppUnlock(app);
399 * Populate result array and envcount.
401 for (*count = 0; *count < envcount; (*count)++)
403 q = _XStrtok(NULL, " ", strtok_buf);
404 (*window)[*count] = (Window)strtoul(q, NULL, 16);
408 * Free temp copy of envdata.
413 * Create dummy window to obtain XID.
415 xid_window = XCreateWindow(display, DefaultRootWindow(display),
417 CopyFromParent, InputOutput, CopyFromParent,
420 if (xid_window == (Window)0)
423 * Could not create dummy window.
425 free((char *)*window);
428 _DtSvcProcessUnlock();
429 _DtSvcAppUnlock(app);
434 * Send client message to win0 to register.
436 event.type = ClientMessage;
437 event.window = (*window)[0];
438 event.message_type = xa_saver_register;
440 event.data.l[0] = (Atom)0;
441 event.data.l[1] = (long)serial;
442 event.data.l[2] = (long)xid_window;
443 event.data.l[3] = CurrentTime;
444 XSendEvent(display, (*window)[0], False, NoEventMask,
447 _DtSvcProcessUnlock();
449 * Ensure window creation and client message have been processed by
450 * the server before continuing.
452 XSync(display, False);
454 _DtSvcAppUnlock(app);
459 /*************************************<->*************************************
461 * RegisterSaverCB() - register a screen saver
465 * RegisterSaverCB() is a callback called when the ClientMessage arrives from
466 * a screen saver. This callback first searches the screen saver state list
467 * by serial number. If a state variable is not found, RegisterSaverCB()
468 * assumes the screen saver must have been stopped by a call to
469 * _DtSaverStop(), so kills the client via XKillClient() using the window id
470 * provided in the message. If the state variable is located,
471 * RegisterSaverCB() stores the window id in the state variable.
475 * w - widget from which we derive the display
476 * client_data - pointer to client data (unused)
477 * event - ClientMessage event structure
478 * continue_to_dispatch - dispatch to remaining event handlers (unused)
489 *************************************<->***********************************/
494 XtPointer client_data,
496 Boolean *continue_to_dispatch)
498 if (event->type == ClientMessage)
500 XClientMessageEvent *cEvent = (XClientMessageEvent *) event;
503 if (cEvent->message_type == xa_saver_register)
505 unsigned short serial = (unsigned short)cEvent->data.l[1];
506 Window win = (Window)cEvent->data.l[2];
507 struct saver_state *state;
510 * Find event in saver list.
512 state = saver_list.next;
513 while (state != NULL && state->serial != serial)
521 * _DtSaverStop() not yet called for this saver. Store xid in
522 * saver's state for _DtSaverStop()'s use.
529 * _DtSaverStop() has already been called for this saver, but at the
530 * time, the saver had not yet registered. Kill the saver client.
532 XKillClient(XtDisplay(w), win);
535 _DtSvcProcessUnlock();