2 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
3 * (c) Copyright 1993, 1994 International Business Machines Corp. *
4 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
5 * (c) Copyright 1993, 1994 Novell, Inc. *
8 *******************************************************************************
10 * File: ChkpntClient.c
11 * Description: CDE client-side checkpoint protocol functions. Private API
12 * functions for use by the CDE client program.
13 * Created: Mon Sep 6 09:00:00 1993
16 * $TOG: ChkpntClient.c /main/7 1998/04/09 17:49:06 mgreess $
18 * (C) Copyright 1993, Hewlett-Packard, all rights reserved.
20 *******************************************************************************
23 #define NUMPROPERTIES 8
24 #define INVALID_TIME ((Time) -1)
30 #include "Dt/ChkpntP.h"
31 #include "DtSvcLock.h"
34 Display *display; /* Display pointer */
35 Window window; /* Window id for the program */
36 char *pname; /* Actual name of the program */
37 Atom aSelection; /* Atom for root selection */
38 Atom *aProperty; /* Atom array for window props */
39 int maxprops; /* Size of above array */
40 Atom aChkpntMsg; /* Atom for Checkpoint message */
41 Boolean bChkpnt; /* Should I do checkpointing ? */
42 } dtcp_info; /* Data structure for this client*/
43 static DtChkpntMsg dtcp_msg; /* Message structure union */
46 * myCheckClientEvent --- Helper Boolean function to pass to XCheckIfEvent()
47 * Checks for PropertyNotify & SelectionNotify events in the event queue.
49 static Bool myCheckClientEvent(Display *display, XEvent *event, char *args)
53 /* Only check the client window events */
55 onMyWindow = (event->xany.window == dtcp_info.window);
56 _DtSvcProcessUnlock();
76 * myDtChkpntMsgSend --- Helper function: Send a checkpoint message to the listener
78 static myDtChkpntMsgSend(char *message, char *type)
80 static long msgcount = 0; /* Running count of messages */
81 static int propnum = 0; /* Which property are we using ? */
82 static Time oldtime = INVALID_TIME; /* Recycled from old PropertyNotify events */
83 Time timestamp= INVALID_TIME;
84 char buf_msgcount[32];
85 char buf_seconds[128];
86 struct timeval time_val;
87 struct timezone time_zone;
93 /* Check to see if checkpoint is actually on */
95 if (dtcp_info.bChkpnt == False) {
96 _DtSvcProcessUnlock();
100 /* Fill the message list. ("pname" and "window" were filled at init) */
101 dtcp_msg.record.type = type;
102 sprintf(buf_msgcount, "%ld", msgcount);
103 dtcp_msg.record.count = buf_msgcount; /* Running message count */
104 gettimeofday(&time_val, &time_zone);
105 sprintf(buf_seconds,"%lf",time_val.tv_sec + (time_val.tv_usec/1000000.0 ));
106 dtcp_msg.record.seconds = buf_seconds; /* Info from gettimeofday()*/
107 dtcp_msg.record.message = message; /* Actual message string */
110 * We maintain a list of properties and use them round robin -- hoping to
112 * The listener should then track the message count to see if messages are
116 /* Fill the window property with necessary information */
117 status = XStringListToTextProperty(dtcp_msg.array,DT_PERF_CHKPNT_MSG_SIZE, &tp);
119 /* Hang the property on the window */
120 if ( !( (status == Success) || (status > 0) )) {
121 _DtSvcProcessUnlock();
125 XSetTextProperty(dtcp_info.display, dtcp_info.window,
126 &tp, dtcp_info.aProperty[propnum]);
129 if (oldtime != INVALID_TIME) { /* Valid timestamp to be recycled */
132 else { /* Check event queue */
133 bool = XCheckIfEvent(dtcp_info.display, &event,
134 myCheckClientEvent, NULL);
136 if (event.type == PropertyNotify)
137 timestamp = event.xproperty.time;
138 else timestamp = event.xselection.time;
140 else { /* Synthesize time by generating a PropertyNotify */
141 XChangeProperty(dtcp_info.display, dtcp_info.window,
142 dtcp_info.aProperty[propnum], XA_STRING,
144 (unsigned char *) NULL, 0);
145 XFlush(dtcp_info.display);
147 XWindowEvent(dtcp_info.display, dtcp_info.window,
148 PropertyChangeMask, &event);
149 if (event.type == PropertyNotify) {
150 timestamp = event.xproperty.time;
156 * Send the checkpoint message: do a ConvertSelection()
159 /* Note: Currently listener makes no use of the "aChkpntMsg" info */
160 XConvertSelection(dtcp_info.display,dtcp_info.aSelection,
161 dtcp_info.aChkpntMsg, dtcp_info.aProperty[propnum],
162 dtcp_info.window, timestamp);
163 XFlush(dtcp_info.display);
166 * Toss SelectionNotify and PropertyNotify events from the event queue
168 oldtime = INVALID_TIME;
170 bool = XCheckIfEvent(dtcp_info.display, &event,
171 myCheckClientEvent, NULL);
172 if (event.type == PropertyNotify) /* Save timestamp for recycling */
173 oldtime = event.xproperty.time;
174 else oldtime = event.xselection.time;
175 } while(bool == True);
178 * Increment the property and message counters
180 if (++propnum >= dtcp_info.maxprops)
184 _DtSvcProcessUnlock();
189 * _DtPerfChkpntInit --- Initialize the checkpointing mechanism
191 _DtPerfChkpntInit(Display *display,
196 static char winstring[32]; /* Storage for window id */
198 char propname[80]; /* Temp buffer for property name */
203 * Fill the dtcp_info structure
206 dtcp_info.display = display;
207 dtcp_info.pname = prog_name;
208 dtcp_info.bChkpnt = bChkpnt;
209 dtcp_info.aChkpntMsg = XA_STRING;
211 /* Pre-compute Atom names and save them away in the dtcp_info structure */
212 dtcp_info.aSelection = XInternAtom(dtcp_info.display,
213 DT_PERF_CHKPNT_SEL, False);
214 dtcp_info.maxprops = NUMPROPERTIES;
215 dtcp_info.aProperty = (Atom *) malloc(dtcp_info.maxprops * sizeof(Atom));
216 for (i= 0; i < dtcp_info.maxprops; i++) {
217 sprintf(propname, "%s_%x", DT_PERF_CLIENT_CHKPNT_PROP, i);
218 dtcp_info.aProperty[i] = XInternAtom(dtcp_info.display,
223 * Check to see if listener is available
225 tmpwin = XGetSelectionOwner(dtcp_info.display, dtcp_info.aSelection);
226 if (tmpwin == None) { /* No listener */
227 dtcp_info.bChkpnt = False;
228 _DtSvcProcessUnlock();
233 * Create a permanent window for hanging messages on
235 tmpdisplay = display;
236 tmpdisplay = XOpenDisplay(""); /* Temporary display connection */
237 XSetCloseDownMode(tmpdisplay, RetainPermanent);
238 dtcp_info.window = XCreateSimpleWindow(tmpdisplay, parentwin,
240 BlackPixel(display,DefaultScreen(display)),
241 WhitePixel(display,DefaultScreen(display)));
242 { /* Hang a name on the permanent window => helps debugging */
245 XTextProperty text_prop;
247 buffer = malloc(strlen(prog_name) + 8);
248 sprintf(buffer, "DtPerf %s", prog_name);
251 XStringListToTextProperty(array, 1, &text_prop);
252 XSetWMName(tmpdisplay, dtcp_info.window, &text_prop);
253 XFree(text_prop.value);
254 if (buffer) free(buffer);
257 XCloseDisplay(tmpdisplay);
260 * Pre-fill the message structure entries for "pname" and "window"
262 dtcp_msg.record.pname = prog_name;
263 sprintf(winstring, "%lx", (long) dtcp_info.window);
264 dtcp_msg.record.window = winstring;
267 * Express interest in Property change events
269 XSelectInput(dtcp_info.display, dtcp_info.window, PropertyChangeMask);
271 /* Inform listener that you are ready to send messages */
272 myDtChkpntMsgSend("Begin checkpoint delivery", DT_PERF_CHKPNT_MSG_INIT);
273 _DtSvcProcessUnlock();
275 } /* DtChkpntInit() */
279 * _DtPerfChkpntMsgSend --- Send a checkpoint message to the listener
281 _DtPerfChkpntMsgSend(char *message)
283 myDtChkpntMsgSend(message, DT_PERF_CHKPNT_MSG_CHKPNT);
287 * myDtPerfChkpntEnd --- End the checkpointing message delivery
291 myDtChkpntMsgSend("End checkpoint delivery", DT_PERF_CHKPNT_MSG_END);