dtfile: remove register keyword
[oweals/cde.git] / cde / programs / dtsession / SmWindow.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* $TOG: SmWindow.c /main/6 1997/03/07 10:25:30 barstow $ */
24 /*                                                                      *
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.                                *
29  */
30 /*************************************<+>*************************************
31  *****************************************************************************
32  **
33  **  File:        SmWindow.c
34  **
35  **  Project:     HP DT Session Manager (dtsession)
36  **
37  **  Description:
38  **  -----------
39  **  This file contains all routines needed to query the window tree.
40  **  The window tree needs to be queried to find all top level windows.
41  **
42  **
43  *******************************************************************
44  **  (c) Copyright Hewlett-Packard Company, 1990.  All rights are  
45  **  reserved.  Copying or other reproduction of this program      
46  **  except for archival purposes is prohibited without prior      
47  **  written consent of Hewlett-Packard Company.                     
48  ********************************************************************
49  **
50  **
51  **
52  *****************************************************************************
53  *************************************<+>*************************************/
54
55 #include <stdio.h>
56 #include <X11/Intrinsic.h>
57 #include <X11/Xutil.h>
58 #include <X11/Xatom.h>
59 #include <Dt/UserMsg.h>
60 #include <Dt/WsmP.h>
61 #include "Sm.h"
62 #include "SmError.h"
63 #include "SmWindow.h"
64 #include "SmProtocol.h"
65 #include "SmGlobals.h"
66
67
68 /*
69  * Variables global to this module only
70  */
71 static Boolean commandTimeout;
72
73 /*
74  * Local Function declarations
75  */
76
77 static WindowInfo GetTopLevelWindowInfo( 
78                         Window window) ;
79 static void WaitForCommand( 
80                         Window window) ;
81 static void WaitTimeout( XtPointer , XtIntervalId *) ;
82
83
84
85 \f
86 /*************************************<->*************************************
87  *
88  *  GetTopLevelWindowInfo (window)
89  *
90  *
91  *  Description:
92  *  -----------
93  *  Given a child of the root - find the top level window for that child.
94  *
95  *
96  *  Inputs:
97  *  ------
98  *  window = the current window that is being queried about
99  *
100  * 
101  *  Outputs:
102  *  -------
103  *  retInfo = a WindowInfo structure (a window id + state of the window) that
104  *            gives the top level window information.
105  *
106  *  Comments:
107  *  --------
108  * 
109  *************************************<->***********************************/
110 static WindowInfo 
111 GetTopLevelWindowInfo(
112         Window window )
113 {
114     register int i;
115     Window parent,root,*children;
116     WindowInfo retInfo;
117     Atom actualType;
118     int actualFormat;
119     unsigned long nitems;
120     unsigned long leftover;
121     unsigned int nchildren;
122     WM_STATE *wmState = NULL;
123     XWindowAttributes windowAttr;
124
125     if ((XGetWindowAttributes(smGD.display, window,&windowAttr)) == 0)
126     {
127         retInfo.wid = 0;
128         retInfo.termState = 0;
129         return(retInfo);
130     }
131
132     /*
133      * If WM_STATE could not be interned at the beginning - the window manager
134      * may have been slow in coming up.  Try it again now.
135      */
136     if(XaWmState == None)
137     {
138         XaWmState = XInternAtom(smGD.display, _XA_WM_STATE, True);
139     }
140
141     XGetWindowProperty(smGD.display,window,XaWmState,
142                        0L,(long)BUFSIZ,False,
143                        XaWmState,&actualType,&actualFormat,
144                        &nitems,
145                        &leftover,(unsigned char **) &wmState);
146     if (actualType==XaWmState)
147     {
148         retInfo.wid = window;
149         retInfo.termState = wmState->state;
150
151         /*
152          * This data needs to be freed up!
153          */
154         SM_FREE((char *) wmState);
155         return(retInfo);
156     }
157     else 
158     {
159         /*
160          * Be sure to free the window property each time we get it
161          * if the property exists
162          */
163         if(actualType != None)
164         {
165             SM_FREE((char *) wmState);
166         }
167         
168         if(XQueryTree(smGD.display,window,&root,
169                       &parent,&children,&nchildren) != 0)
170         {
171             if(nchildren > 0)
172             {
173                 i = 0;
174                 while (nchildren--) 
175                 {
176                     retInfo = GetTopLevelWindowInfo(children[i++]);
177                     if(retInfo.wid != 0)
178                     {
179                         SM_FREE((char *) children);
180                         return(retInfo);
181                     }
182                 }
183                 SM_FREE((char *) children);
184             }
185         }
186         retInfo.wid = 0;
187         retInfo.termState = 0;
188         return(retInfo);
189     }
190 }
191
192
193 \f
194 /*************************************<->*************************************
195  *
196  *  WaitForCommand (window)
197  *
198  *
199  *  Description:
200  *  -----------
201  *  This routine waits for an update on the WM_COMMAND property of a top
202  *  level window after a WM_SAVE_YOURSELF has been placed on that window.
203  *
204  *
205  *  Inputs:
206  *  ------
207  *  window = window id for the
208  *
209  * 
210  *  Outputs:
211  *  -------
212  *
213  *  Comments:
214  *  --------
215  * 
216  *************************************<->***********************************/
217 static void 
218 WaitForCommand(
219         Window window )
220 {
221     XtInputMask isThere;
222     XEvent event;
223     XPropertyEvent *pEvent=(XPropertyEvent *)&event;
224     XtIntervalId        comTimerId;
225     Boolean commandUpdated;
226
227     /*
228      * Set a configurable timer which stops the block
229      */
230     commandUpdated = False;
231     commandTimeout = False;
232     comTimerId = XtAppAddTimeOut(smGD.appCon, smRes.saveYourselfTimeout,
233                                  WaitTimeout, (XtPointer) window);
234
235     while((commandUpdated == False) && (commandTimeout == False))
236     {
237         if((isThere = XtAppPending(smGD.appCon)) != 0)
238         {
239             if(isThere & XtIMXEvent)
240             {
241                 XtAppPeekEvent(smGD.appCon, &event);
242                 if (event.type==PropertyNotify&&pEvent->window==window&&
243                     pEvent->atom==XA_WM_COMMAND)
244                 {
245                     commandUpdated = True;
246                 }
247             }
248             if(commandTimeout == False)
249             {
250                 XtAppProcessEvent(smGD.appCon, XtIMXEvent | XtIMTimer);
251             }
252         }
253     }
254
255     XtRemoveTimeOut(comTimerId);
256     XSelectInput(smGD.display, window,NoEventMask);
257
258     return;
259 }
260
261
262 \f
263 /*************************************<->*************************************
264  *
265  *  SaveYourself (windowInfo)
266  *
267  *
268  *  Description:
269  *  -----------
270  *  Places the WM_SAVE_YOURSELF property on each top level window.  It then
271  *  waits for the window to update its WM_COMMAND property.
272  *
273  *
274  *  Inputs:
275  *  ------
276  *  windowInfo = window id for the top level wincow and the state of that
277  *               window.
278  *
279  * 
280  *  Outputs:
281  *  -------
282  *
283  *  Comments:
284  *  --------
285  * 
286  *************************************<->***********************************/
287 int 
288 SaveYourself(
289         WindowInfo windowInfo )
290 {
291
292     int i;
293     Atom *protoRet;
294     int nitems;
295     XClientMessageEvent saveYourselfMessage;
296     
297     /*
298      * Get the WM_PROTOCOLS property on the clients top-level window.
299      */
300     if(XGetWMProtocols(smGD.display, windowInfo.wid, &protoRet, &nitems) == 0)
301     {
302         /*
303          * If the client doesn't have a WM_PROTOCOLS property,
304          * it doesn't support any protocols.
305          */
306         return (-1);    
307     }
308         
309     /* Look for WM_SAVE_YOURSELF atom.  */
310     for (i=0;i<nitems;++i) 
311     {
312         if (protoRet[i]==XaWmSaveYourself) 
313             break;
314     }
315
316     if (i==nitems)
317     {
318         SM_FREE((char *) protoRet);
319         return(-1);     /* doesn't participate in WM_SAVE_YOURSELF */
320     }
321
322     /* Construct the ClientMessage. */
323     saveYourselfMessage.type=ClientMessage;
324     saveYourselfMessage.window=windowInfo.wid;
325     saveYourselfMessage.message_type=XaWmProtocols;
326     saveYourselfMessage.format=32;
327     saveYourselfMessage.data.l[0]=XaWmSaveYourself;
328     saveYourselfMessage.data.l[1]=CurrentTime;
329     
330     /*
331      * look for changes in WM_COMMAND property
332      */
333     XSelectInput(smGD.display,windowInfo.wid,PropertyChangeMask);
334     XFlush(smGD.display);
335
336     /*
337      * Send the ClientMessage to the client.  XSendEvent returns a 1 if it
338      * is successful in converting the event to a wire event.
339      */
340     if (XSendEvent(smGD.display,windowInfo.wid,False,NoEventMask,
341                    (XEvent *) &saveYourselfMessage) != 1)
342     {
343         PrintError(DtError, GETMESSAGE(20, 1, "Client message failed.  Client information will not be saved."));
344         return(-1);
345     }
346
347     /* Wait for client to update WM_COMMAND. */
348     WaitForCommand(windowInfo.wid);
349
350     SM_FREE((char *) protoRet);
351     
352     return (0);
353 }
354
355
356 \f
357 /*************************************<->*************************************
358  *
359  *  GetTopLevelWindows (screen, toplist, toplistlength, containedListLength)
360  *
361  *
362  *  Description:
363  *  -----------
364  *  Querys the window tree and constructs a list of all top level windows
365  *
366  *
367  *  Inputs:
368  *  ------
369  *  screen = pointer to the screen we're currently querying on
370  *
371  * 
372  *  Outputs:
373  *  -------
374  *  toplist = a pointer to the list of top level windows
375  *  toplistlength = the length of the list of top level windows
376  *  containedListLength = the length of the list of contained windows
377  *
378  *  Comments:
379  *  --------
380  * 
381  *************************************<->***********************************/
382 int 
383 GetTopLevelWindows(
384         int screen,
385         WindowInfo **topList,
386         unsigned int *topListLength,
387         unsigned int *containedListLength )
388 {
389     Window rootWindow, parentWindow, *tmpChild;
390     Window *childList, *embeddedList, *tmpList;
391     WindowInfo topLevelWindowInfo;
392     int i;
393     unsigned long numEmbedded;
394
395     /*
396      * Get a list of children of the root window
397      */
398     if (XQueryTree(smGD.display, RootWindow(smGD.display, screen),&rootWindow,
399             &parentWindow, &childList, topListLength) == 0)
400     {
401         PrintError(DtError, GETMESSAGE(20, 2, "Invalid root window.  Can not save client information."));
402         SM_EXIT(-1);
403     }
404
405     /*
406      * add in the list of top level windows embedded in the front panel
407      */
408     if(_DtGetEmbeddedClients(smGD.display, RootWindow(smGD.display, screen),
409                              &embeddedList, &numEmbedded) != Success)
410     {
411         numEmbedded = 0;
412     }
413     
414     if (*topListLength) 
415         *topList=(WindowInfo *) SM_MALLOC(sizeof(WindowInfo)*
416                                        (*topListLength + numEmbedded));
417
418     tmpChild = childList;
419     /* scan list */
420     for (i=0 ; i<*topListLength; ++i, tmpChild++) 
421     {
422         topLevelWindowInfo = GetTopLevelWindowInfo(*tmpChild);
423         if (!topLevelWindowInfo.wid)
424         {
425             topLevelWindowInfo.wid = (*tmpChild);
426             /*
427              * Assume if you can't find a state that it is "don't care"
428              * this could be a faulty assumption CHECK IT OUT
429              */
430             topLevelWindowInfo.termState = 0;
431         }
432         (*topList)[i] = topLevelWindowInfo;
433     }
434
435     /*
436      * Now add in the extra window id's to check
437      */
438     tmpList = embeddedList;
439     for(i = *topListLength;i < (*topListLength + numEmbedded);i++)
440     {
441         (*topList)[i].wid = *tmpList;tmpList++;
442         (*topList)[i].termState = NormalState;
443     }
444
445     if(numEmbedded > 0)
446     {
447         SM_FREE((char *) embeddedList);
448     }
449
450     if(*topListLength)
451     {
452         SM_FREE((char *) childList);
453     }
454    
455    *containedListLength = numEmbedded;
456     
457     return(0);
458 }
459
460
461 \f
462 /*************************************<->*************************************
463  *
464  *  WaitTimeout
465  *
466  *
467  *  Description:
468  *  -----------
469  *  Timeout procedure the WaitForCommand routine.  It stops a loop waiting
470  *  for an update of the WM_COMMAND property from a client.
471  *
472  *
473  *  Inputs:
474  *  ------
475  *
476  * 
477  *  Outputs:
478  *  -------
479  *  commandTimeout = (global) flag that stops the loop
480  *
481  *  Comments:
482  *  --------
483  * 
484  *************************************<->***********************************/
485 static void 
486 WaitTimeout(
487         XtPointer client_data,
488         XtIntervalId *id )
489 {
490     String tmpString, tmpError;
491     char   *winName;
492     Status success;
493
494     success = XFetchName(smGD.display, (Window) client_data, &winName);
495     if (success && winName)
496     {
497         tmpString = GETMESSAGE(20, 4, "Session restoration information not updated for client %s.  Invalid information may be saved.");
498         tmpError = SM_MALLOC(strlen(winName) + strlen(tmpString) + 5);
499         if (tmpError)
500         {
501             sprintf(tmpError, tmpString, winName);
502             PrintError(DtError, tmpError);
503             SM_FREE(tmpError);
504         }
505         SM_FREE(winName);
506     }
507     commandTimeout = True;
508     return;
509 } /* END OF FUNCTION WaitTimeout */
510