Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtSvc / DtUtil2 / ChkpntClient.c
1 /*
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.                                *
6  */
7 /* -*-C-*-
8 *******************************************************************************
9 *
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
14 * Language:     C
15 *
16 * $TOG: ChkpntClient.c /main/7 1998/04/09 17:49:06 mgreess $
17 *
18 * (C) Copyright 1993, Hewlett-Packard, all rights reserved.
19 *
20 *******************************************************************************
21 */
22
23 #define NUMPROPERTIES 8
24 #define INVALID_TIME    ((Time) -1)
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/time.h>
29 #include <time.h>
30 #include "Dt/ChkpntP.h"
31 #include "DtSvcLock.h"
32
33 static struct {
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      */
44
45 /*
46  * myCheckClientEvent --- Helper Boolean function to pass to XCheckIfEvent()
47  * Checks for PropertyNotify & SelectionNotify events in the event queue.
48  */
49 static Bool myCheckClientEvent(Display *display, XEvent *event, char *args)
50 {
51     Boolean onMyWindow;
52
53     /* Only check the client window events */
54     _DtSvcProcessLock();
55     onMyWindow = (event->xany.window == dtcp_info.window);
56     _DtSvcProcessUnlock();
57
58     if (!onMyWindow)
59         return(False);
60
61     switch(event->type)
62     {
63         case PropertyNotify:
64         case SelectionNotify:
65             return(True);
66             break;
67
68         default:
69             break;
70     }
71
72     return (False);
73 }
74
75 /*
76  * myDtChkpntMsgSend --- Helper function: Send a checkpoint message to the listener
77  */
78 static myDtChkpntMsgSend(char *message, char *type) 
79 {
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;
88     XTextProperty   tp;
89     Status          status;
90     Bool            bool;
91     XEvent          event;
92
93     /* Check to see if checkpoint is actually on */
94     _DtSvcProcessLock();
95     if (dtcp_info.bChkpnt == False) {
96         _DtSvcProcessUnlock();
97         return(0);
98     }
99
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 */
108
109     /*
110      * We maintain a list of properties and use them round robin -- hoping to
111      * never run out.
112      * The listener should then track the message count to see if messages are
113      * getting dropped.
114      */
115
116     /* Fill the window property with necessary information */
117     status = XStringListToTextProperty(dtcp_msg.array,DT_PERF_CHKPNT_MSG_SIZE, &tp);
118
119     /* Hang the property on the window */
120     if ( !( (status == Success) || (status > 0) )) {
121         _DtSvcProcessUnlock();
122         return(0);
123     }
124
125     XSetTextProperty(dtcp_info.display, dtcp_info.window,
126                         &tp,             dtcp_info.aProperty[propnum]);
127     XFree(tp.value);
128
129     if (oldtime != INVALID_TIME) {  /* Valid timestamp to be recycled */
130         timestamp = oldtime;
131     }
132     else {                   /* Check event queue */
133         bool = XCheckIfEvent(dtcp_info.display, &event,
134                          myCheckClientEvent, NULL);
135         if (bool == True) {
136             if (event.type == PropertyNotify)
137                  timestamp = event.xproperty.time; 
138             else timestamp = event.xselection.time;
139             }
140         else {     /* Synthesize time by generating a PropertyNotify */
141             XChangeProperty(dtcp_info.display,     dtcp_info.window,
142                     dtcp_info.aProperty[propnum],   XA_STRING,
143                     8,                      PropModeAppend,
144                     (unsigned char *) NULL, 0);
145             XFlush(dtcp_info.display);
146             loop:
147             XWindowEvent(dtcp_info.display, dtcp_info.window,
148                         PropertyChangeMask,  &event);
149             if (event.type == PropertyNotify) {
150                 timestamp = event.xproperty.time;
151             }
152             else goto loop;
153         }
154     }
155     /*
156      * Send the checkpoint message: do a ConvertSelection()
157      */
158
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);
164
165     /*
166      * Toss SelectionNotify and PropertyNotify events from the event queue
167      */
168     oldtime = INVALID_TIME;
169     do {
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);
176
177     /*
178      * Increment the property and message counters
179      */
180     if (++propnum >= dtcp_info.maxprops)
181         propnum = 0;
182     msgcount++;
183
184     _DtSvcProcessUnlock();
185     return(1);
186 }
187
188 /*
189  * _DtPerfChkpntInit --- Initialize the checkpointing mechanism
190  */
191 _DtPerfChkpntInit(Display      *display,
192              Window       parentwin,
193              char         *prog_name,
194              Boolean      bChkpnt)
195 {
196     static        char winstring[32];   /* Storage for window id */
197     Window        tmpwin;
198     char          propname[80]; /* Temp buffer for property name */
199     Display       *tmpdisplay;
200     int    i;
201
202     /*
203      * Fill the dtcp_info structure 
204      */
205     _DtSvcProcessLock();
206     dtcp_info.display    = display;
207     dtcp_info.pname      = prog_name;
208     dtcp_info.bChkpnt    = bChkpnt;
209     dtcp_info.aChkpntMsg = XA_STRING;
210
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,
219                                             propname, False);
220     }
221
222     /*
223      * Check to see if listener is available
224      */
225     tmpwin  = XGetSelectionOwner(dtcp_info.display, dtcp_info.aSelection);
226     if (tmpwin == None) {       /* No listener */
227         dtcp_info.bChkpnt   = False;
228         _DtSvcProcessUnlock();
229         return(0);
230     }
231
232     /*
233      * Create a permanent window for hanging messages on
234      */
235     tmpdisplay = display;
236     tmpdisplay = XOpenDisplay("");      /* Temporary display connection */
237     XSetCloseDownMode(tmpdisplay, RetainPermanent);
238     dtcp_info.window     = XCreateSimpleWindow(tmpdisplay, parentwin, 
239                             1, 1, 100, 100, 1,
240                             BlackPixel(display,DefaultScreen(display)),
241                             WhitePixel(display,DefaultScreen(display)));
242     {   /* Hang a name on the permanent window => helps debugging */
243         char *buffer;
244         char *array[2];
245         XTextProperty text_prop;
246
247         buffer = malloc(strlen(prog_name) + 8);
248         sprintf(buffer, "DtPerf %s", prog_name);
249         array[0] = buffer;
250         array[1] = "";
251         XStringListToTextProperty(array, 1, &text_prop);
252         XSetWMName(tmpdisplay, dtcp_info.window, &text_prop);
253         XFree(text_prop.value);
254         if (buffer) free(buffer);
255     }
256
257     XCloseDisplay(tmpdisplay);
258
259     /*
260      * Pre-fill the message structure entries for "pname" and "window"
261      */
262     dtcp_msg.record.pname  = prog_name;
263     sprintf(winstring, "%lx", (long) dtcp_info.window);
264     dtcp_msg.record.window = winstring;
265
266     /*
267      * Express interest in Property change events
268      */
269     XSelectInput(dtcp_info.display, dtcp_info.window, PropertyChangeMask);
270
271     /* Inform listener that you are ready to send messages */
272     myDtChkpntMsgSend("Begin checkpoint delivery", DT_PERF_CHKPNT_MSG_INIT);
273     _DtSvcProcessUnlock();
274     return(1);
275 }       /* DtChkpntInit() */
276
277
278 /*
279  * _DtPerfChkpntMsgSend --- Send a checkpoint message to the listener
280  */
281 _DtPerfChkpntMsgSend(char *message) 
282 {
283     myDtChkpntMsgSend(message, DT_PERF_CHKPNT_MSG_CHKPNT);
284 }
285
286 /*
287  * myDtPerfChkpntEnd --- End the checkpointing message delivery
288  */
289 _DtPerfChkpntEnd() 
290 {
291     myDtChkpntMsgSend("End checkpoint delivery", DT_PERF_CHKPNT_MSG_END);
292     return(1);
293 }
294