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 libraries 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 <Dt/Action.h>
58 #include "DtSvcLock.h"
61 * Constants global to this file.
63 #define DT_SAVER_MAX_SCREENS 10
66 unsigned short serial;
68 struct saver_state *next;
71 static Atom xa_saver_register;
73 static struct saver_state saver_list = {0, (Window)0, NULL};
78 static void RegisterSaverCB(
80 XtPointer client_data,
82 Boolean *continue_to_dispatch
86 /*************************************<->*************************************
88 * _DtSaverStart() - start a screen saver
92 * _DtSaverStart() is one of a suite of screen saver API's used in the
93 * desktop. These APIs are:
95 * _DtSaverStart() starts a screen saver (private)
96 * _DtSaverStop() stops a screen saver (private)
97 * DtSaverGetWindows() return array of windows on which saver can draw
99 * The _DtSaverStart() API allocates a state variable for the screen saver
100 * which contains a serial number and NIL window ID. A list of these state
101 * variables is maintained, one for each call to _DtSaverStart().
102 * DtSaverStart() then sets up the DTSAVERINFO environment variable containing
103 * the serial number, window count and window list provided. Finally, it
104 * launches the provided action and returns an opaque pointer to the state
105 * variable. The action is expected to be a screen saver which makes use
106 * of the DtSaverGetWindows() API.
108 * When the screen saver starts, it calls the DtSaverGetWindows() API. From
109 * the screen saver perspective, the API returns an array of windows on which
110 * the screen saver can draw. To to this, the API obtains the DTSAVERINFO
111 * environment variable, and parses out the window array. The API also
112 * creates a window and sends a ClientMessage to the first DTSAVERINFO window
113 * containing the serial number and newly created window id.
115 * RegisterSaverCB() is a callback called when the ClientMessage arrives from
116 * a screen saver. This callback first searches the screen saver state list
117 * by serial number. If a state variable is not found, RegisterSaverCB()
118 * assumes the screen saver must have been stopped by a call to
119 * _DtSaverStop(), so kills the client via XKillClient() using the window id
120 * provided in the message. If the state variable is located,
121 * RegisterSaverCB() stores the window id in the state variable.
123 * _DtSaverStop() searches the screen saver list using the serial number
124 * provided in the input state variable. It should always be found. When
125 * found, if the state variable window id is set, _DtSaverStop() kills the
126 * screen saver client via XKillClient(), deletes the state variable from
127 * the list and deallocates the state variable.
131 * display - display structure
132 * drawArea - array of widgets to be stored drawn upon by saver
133 * count - number of elements in drawArea array
134 * saverAction - screen saver action name to invoke
135 * wAction - widget on which possible DtActionInvoke() errors should display
142 * state - pointer to opaque state structure
146 * This function uses DtActionInvoke() to launch an action. As a result,
147 * the caller is responsible for loading and maintaining the action database
148 * using the DtDbLoad() function and procedures. The caller
149 * must call _DtSaverStop() to terminate screen saver
151 *************************************<->***********************************/
160 static char envdata[(DT_SAVER_MAX_SCREENS * 12) + 20];
161 struct saver_state *state;
162 struct saver_state *p;
167 * If first time in, insert envdata in process environment.
169 if (saver_list.serial == 0)
171 #if !defined(__linux__) && !defined(CSRG_BASED)
172 /* JET - how can this ever work anyway? */
176 xa_saver_register = XInternAtom(display, "_DT_SAVER_REGISTER", False);
180 * Add event handler (it might already be there - that's ok).
182 XtAddEventHandler(drawArea[0], 0, True, RegisterSaverCB, NULL);
185 * Allocate state structure for this saver.
187 if (!(state = (struct saver_state *)malloc(sizeof(struct saver_state))))
189 _DtSvcProcessUnlock();
194 * Initialize state structure and append to saver_list.
196 state->serial = saver_list.serial++;
197 state->xid = (Window)0;
200 while (p->next != NULL)
207 * Set up environment. It will look like:
208 * DTSAVERINFO="<serial> <count> <win0> <win1> ... <winN>"
210 sprintf(envdata, "DTSAVERINFO=%u %i %lx",
211 state->serial, count, XtWindow(drawArea[0]));
212 for (i = 1; i < count; i++)
214 char *pe = envdata + strlen(envdata);
215 sprintf(pe, " %lx", XtWindow(drawArea[i]));
218 #if defined(__linux__) || defined(CSRG_BASED)
222 _DtSvcProcessUnlock();
227 DtActionInvoke(wAction, saverAction, NULL, 0,
228 NULL, NULL, NULL, 0, NULL, NULL);
231 * Return array as state information.
233 return((void *)state);
237 /*************************************<->*************************************
239 * _DtSaverStop() - stop a screen saver
243 * Stop an external screen saver started with DtStartSaver().
245 * _DtSaverStop() searches the screen saver list using the serial number
246 * provided in the input state variable. It should always be found. When
247 * found, if the state variable window id is set, _DtSaverStop() kills the
248 * screen saver client via XKillClient(), deletes the state variable from
249 * the list and deallocates the state variable.
253 * display - display structure
254 * state - state returned from _DtSaverStart()
265 *************************************<->***********************************/
272 struct saver_state *state = (struct saver_state *)pstate;
273 struct saver_state *p;
277 * Unlink from saver_list.
280 while (p->next != state)
284 p->next = state->next;
285 _DtSvcProcessUnlock();
288 * Kill client using window id provided by RegisterSaverCB().
290 if (state->xid != (Window)0)
292 XKillClient(display, state->xid);
296 * Free state allocated by _DtSaverStart();
302 /*************************************<->*************************************
304 * DtSaverGetWindows() - return array of windows on which saver can draw
309 * This is a PUBLIC API.
311 * When the screen saver starts, it calls the DtSaverGetWindows() API. From
312 * the screen saver perspective, the API returns an array of windows on which
313 * the screen saver can draw. To to this, the API obtains the DTSAVERINFO
314 * environment variable, and parses out the window array. The API also
315 * creates a window and sends a ClientMessage to the first DTSAVERINFO window
316 * containing the serial number and newly created window id.
320 * display - display structure
321 * window - pointer to memory in which to place pointer to array
322 * count - pointer to memory in which to place count
326 * *window - pointer to array
331 * True - window list returned
332 * False - window list not returned
336 * The array memory should be freed by the caller via free().
338 *************************************<->***********************************/
346 char *envdata, *p, *q;
347 unsigned short serial;
349 XClientMessageEvent event;
351 _Xstrtokparams strtok_buf;
352 _DtSvcDisplayToAppContext(display);
359 xa_saver_register = XInternAtom(display, "_DT_SAVER_REGISTER", False);
362 * Get invocation information from environment.
364 envdata = getenv("DTSAVERINFO");
367 _DtSvcProcessUnlock();
368 _DtSvcAppUnlock(app);
373 * Copy string for later strtok() use.
378 _DtSvcProcessUnlock();
379 _DtSvcAppUnlock(app);
386 q = _XStrtok(p, " ", strtok_buf);
387 serial = (unsigned short)strtoul(q, NULL, 10);
392 q = _XStrtok(NULL, " ", strtok_buf);
393 envcount = (int)strtoul(q, NULL, 10);
396 * Allocate memory for window array.
398 *window = (Window *)malloc((envcount)*sizeof(Window *));
402 _DtSvcProcessUnlock();
403 _DtSvcAppUnlock(app);
408 * Populate result array and envcount.
410 for (*count = 0; *count < envcount; (*count)++)
412 q = _XStrtok(NULL, " ", strtok_buf);
413 (*window)[*count] = (Window)strtoul(q, NULL, 16);
417 * Free temp copy of envdata.
422 * Create dummy window to obtain XID.
424 xid_window = XCreateWindow(display, DefaultRootWindow(display),
426 CopyFromParent, InputOutput, CopyFromParent,
429 if (xid_window == (Window)0)
432 * Could not create dummy window.
434 free((char *)*window);
437 _DtSvcProcessUnlock();
438 _DtSvcAppUnlock(app);
443 * Send client message to win0 to register.
445 event.type = ClientMessage;
446 event.window = (*window)[0];
447 event.message_type = xa_saver_register;
449 event.data.l[0] = (Atom)0;
450 event.data.l[1] = (long)serial;
451 event.data.l[2] = (long)xid_window;
452 event.data.l[3] = CurrentTime;
453 XSendEvent(display, (*window)[0], False, NoEventMask,
456 _DtSvcProcessUnlock();
458 * Ensure window creation and client message have been processed by
459 * the server before continuing.
461 XSync(display, False);
463 _DtSvcAppUnlock(app);
468 /*************************************<->*************************************
470 * RegisterSaverCB() - register a screen saver
474 * RegisterSaverCB() is a callback called when the ClientMessage arrives from
475 * a screen saver. This callback first searches the screen saver state list
476 * by serial number. If a state variable is not found, RegisterSaverCB()
477 * assumes the screen saver must have been stopped by a call to
478 * _DtSaverStop(), so kills the client via XKillClient() using the window id
479 * provided in the message. If the state variable is located,
480 * RegisterSaverCB() stores the window id in the state variable.
484 * w - widget from which we derive the display
485 * client_data - pointer to client data (unused)
486 * event - ClientMessage event structure
487 * continue_to_dispatch - dispatch to remaining event handlers (unused)
498 *************************************<->***********************************/
503 XtPointer client_data,
505 Boolean *continue_to_dispatch)
507 if (event->type == ClientMessage)
509 XClientMessageEvent *cEvent = (XClientMessageEvent *) event;
512 if (cEvent->message_type == xa_saver_register)
514 unsigned short serial = (unsigned short)cEvent->data.l[1];
515 Window win = (Window)cEvent->data.l[2];
516 struct saver_state *state;
519 * Find event in saver list.
521 state = saver_list.next;
522 while (state != NULL && state->serial != serial)
530 * _DtSaverStop() not yet called for this saver. Store xid in
531 * saver's state for _DtSaverStop()'s use.
538 * _DtSaverStop() has already been called for this saver, but at the
539 * time, the saver had not yet registered. Kill the saver client.
541 XKillClient(XtDisplay(w), win);
544 _DtSvcProcessUnlock();