smproxy.c revision 14c0a534
114c0a534Smrg/* $Xorg: smproxy.c,v 1.6 2001/02/09 02:05:35 xorgcvs Exp $ */
214c0a534Smrg/******************************************************************************
314c0a534Smrg
414c0a534SmrgCopyright 1994, 1998  The Open Group
514c0a534Smrg
614c0a534SmrgPermission to use, copy, modify, distribute, and sell this software and its
714c0a534Smrgdocumentation for any purpose is hereby granted without fee, provided that
814c0a534Smrgthe above copyright notice appear in all copies and that both that
914c0a534Smrgcopyright notice and this permission notice appear in supporting
1014c0a534Smrgdocumentation.
1114c0a534Smrg
1214c0a534SmrgThe above copyright notice and this permission notice shall be included in
1314c0a534Smrgall copies or substantial portions of the Software.
1414c0a534Smrg
1514c0a534SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1614c0a534SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1714c0a534SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1814c0a534SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1914c0a534SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2014c0a534SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2114c0a534Smrg
2214c0a534SmrgExcept as contained in this notice, the name of The Open Group shall not be
2314c0a534Smrgused in advertising or otherwise to promote the sale, use or other dealings
2414c0a534Smrgin this Software without prior written authorization from The Open Group.
2514c0a534Smrg
2614c0a534SmrgAuthor:  Ralph Mor, X Consortium
2714c0a534Smrg******************************************************************************/
2814c0a534Smrg/* $XFree86: xc/programs/smproxy/smproxy.c,v 3.8 2001/10/28 03:34:25 tsi Exp $ */
2914c0a534Smrg
3014c0a534Smrg#include "smproxy.h"
3114c0a534Smrg#include <unistd.h>
3214c0a534Smrg#include <X11/Xmu/WinUtil.h>
3314c0a534Smrg
3414c0a534SmrgXtAppContext appContext;
3514c0a534SmrgDisplay *disp;
3614c0a534Smrg
3714c0a534SmrgAtom wmProtocolsAtom;
3814c0a534SmrgAtom wmSaveYourselfAtom;
3914c0a534SmrgAtom wmStateAtom;
4014c0a534SmrgAtom smClientIdAtom;
4114c0a534SmrgAtom wmClientLeaderAtom;
4214c0a534Smrg
4314c0a534SmrgBool debug = 0;
4414c0a534Smrg
4514c0a534SmrgSmcConn proxy_smcConn;
4614c0a534SmrgXtInputId proxy_iceInputId;
4714c0a534Smrgchar *proxy_clientId = NULL;
4814c0a534Smrg
4914c0a534SmrgWinInfo *win_head = NULL;
5014c0a534Smrg
5114c0a534Smrgint proxy_count = 0;
5214c0a534Smrgint die_count = 0;
5314c0a534Smrg
5414c0a534SmrgBool ok_to_die = 0;
5514c0a534Smrg
5614c0a534SmrgBool caught_error = 0;
5714c0a534Smrg
5814c0a534SmrgBool sent_save_done = 0;
5914c0a534Smrg
6014c0a534Smrgint Argc;
6114c0a534Smrgchar **Argv;
6214c0a534Smrg
6314c0a534SmrgBool HasSaveYourself ( Window window );
6414c0a534SmrgBool HasXSMPsupport ( Window window );
6514c0a534SmrgWinInfo * GetClientLeader ( WinInfo *winptr );
6614c0a534Smrgchar * CheckFullyQuantifiedName ( char *name, int *newstring );
6714c0a534Smrgvoid FinishSaveYourself ( WinInfo *winInfo, Bool has_WM_SAVEYOURSELF );
6814c0a534Smrgvoid SaveYourselfCB ( SmcConn smcConn, SmPointer clientData, int saveType,
6914c0a534Smrg		      Bool shutdown, int interactStyle, Bool fast );
7014c0a534Smrgvoid DieCB ( SmcConn smcConn, SmPointer clientData );
7114c0a534Smrgvoid SaveCompleteCB ( SmcConn smcConn, SmPointer clientData );
7214c0a534Smrgvoid ShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData );
7314c0a534Smrgvoid ProcessIceMsgProc ( XtPointer client_data, int *source, XtInputId *id );
7414c0a534Smrgvoid NullIceErrorHandler ( IceConn iceConn, Bool swap,
7514c0a534Smrg			   int offendingMinorOpCode,
7614c0a534Smrg			   unsigned long offendingSequence,
7714c0a534Smrg			   int errorClass, int severity, IcePointer values );
7814c0a534Smrgvoid ConnectClientToSM ( WinInfo *winInfo );
7914c0a534Smrgint MyErrorHandler ( Display *display, XErrorEvent *event );
8014c0a534SmrgBool LookupWindow ( Window window, WinInfo **ptr_ret, WinInfo **prev_ptr_ret );
8114c0a534SmrgWinInfo * AddNewWindow ( Window window );
8214c0a534Smrgvoid RemoveWindow ( WinInfo *winptr );
8314c0a534Smrgvoid Got_WM_STATE ( WinInfo *winptr );
8414c0a534Smrgvoid HandleCreate ( XCreateWindowEvent *event );
8514c0a534Smrgvoid HandleDestroy ( XDestroyWindowEvent *event );
8614c0a534Smrgvoid HandleUpdate ( XPropertyEvent *event );
8714c0a534Smrgvoid ProxySaveYourselfPhase2CB ( SmcConn smcConn, SmPointer clientData );
8814c0a534Smrgvoid ProxySaveYourselfCB ( SmcConn smcConn, SmPointer clientData,
8914c0a534Smrg			   int saveType, Bool shutdown, int interactStyle,
9014c0a534Smrg			   Bool fast );
9114c0a534Smrgvoid ProxyDieCB ( SmcConn smcConn, SmPointer clientData );
9214c0a534Smrgvoid ProxySaveCompleteCB ( SmcConn smcConn, SmPointer clientData );
9314c0a534Smrgvoid ProxyShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData );
9414c0a534SmrgStatus ConnectProxyToSM ( char *previous_id );
9514c0a534Smrgvoid CheckForExistingWindows ( Window root );
9614c0a534Smrg
9714c0a534Smrg
9814c0a534SmrgBool
9914c0a534SmrgHasSaveYourself (window)
10014c0a534Smrg
10114c0a534SmrgWindow window;
10214c0a534Smrg
10314c0a534Smrg{
10414c0a534Smrg    Atom *protocols;
10514c0a534Smrg    int numProtocols;
10614c0a534Smrg    int i, found;
10714c0a534Smrg
10814c0a534Smrg    protocols = NULL;
10914c0a534Smrg
11014c0a534Smrg    if (XGetWMProtocols (disp, window, &protocols, &numProtocols) != True)
11114c0a534Smrg	return (False);
11214c0a534Smrg
11314c0a534Smrg    found = 0;
11414c0a534Smrg
11514c0a534Smrg    if (protocols != NULL)
11614c0a534Smrg    {
11714c0a534Smrg	for (i = 0; i < numProtocols; i++)
11814c0a534Smrg	    if (protocols[i] == wmSaveYourselfAtom)
11914c0a534Smrg		found = 1;
12014c0a534Smrg
12114c0a534Smrg	XFree (protocols);
12214c0a534Smrg    }
12314c0a534Smrg
12414c0a534Smrg    return (found);
12514c0a534Smrg}
12614c0a534Smrg
12714c0a534Smrg
12814c0a534Smrg
12914c0a534SmrgBool
13014c0a534SmrgHasXSMPsupport (window)
13114c0a534Smrg
13214c0a534SmrgWindow window;
13314c0a534Smrg
13414c0a534Smrg{
13514c0a534Smrg    XTextProperty tp;
13614c0a534Smrg    Bool hasIt = 0;
13714c0a534Smrg
13814c0a534Smrg    if (XGetTextProperty (disp, window, &tp, smClientIdAtom))
13914c0a534Smrg    {
14014c0a534Smrg	if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0)
14114c0a534Smrg	    hasIt = 1;
14214c0a534Smrg
14314c0a534Smrg	if (tp.value)
14414c0a534Smrg	    XFree ((char *) tp.value);
14514c0a534Smrg    }
14614c0a534Smrg
14714c0a534Smrg    return (hasIt);
14814c0a534Smrg}
14914c0a534Smrg
15014c0a534Smrg
15114c0a534Smrg
15214c0a534SmrgWinInfo *
15314c0a534SmrgGetClientLeader (winptr)
15414c0a534Smrg
15514c0a534SmrgWinInfo *winptr;
15614c0a534Smrg
15714c0a534Smrg{
15814c0a534Smrg    Atom actual_type;
15914c0a534Smrg    int actual_format;
16014c0a534Smrg    unsigned long nitems, bytesafter;
16114c0a534Smrg    unsigned long *datap = NULL;
16214c0a534Smrg    WinInfo *leader_winptr = NULL;
16314c0a534Smrg    Bool failure = 0;
16414c0a534Smrg
16514c0a534Smrg    if (XGetWindowProperty (disp, winptr->window, wmClientLeaderAtom,
16614c0a534Smrg	0L, 1L, False, AnyPropertyType,	&actual_type, &actual_format,
16714c0a534Smrg	&nitems, &bytesafter, (unsigned char **) &datap) == Success)
16814c0a534Smrg    {
16914c0a534Smrg	if (actual_type == XA_WINDOW && actual_format == 32 &&
17014c0a534Smrg	    nitems == 1 && bytesafter == 0)
17114c0a534Smrg	{
17214c0a534Smrg	    Window leader_win = *((Window *) datap);
17314c0a534Smrg
17414c0a534Smrg	    if (!LookupWindow (leader_win, &leader_winptr, NULL))
17514c0a534Smrg		failure = 1;
17614c0a534Smrg	}
17714c0a534Smrg
17814c0a534Smrg	if (datap)
17914c0a534Smrg	    XFree (datap);
18014c0a534Smrg    }
18114c0a534Smrg
18214c0a534Smrg    if (failure)
18314c0a534Smrg    {
18414c0a534Smrg	/* The client leader was defined, but we couldn't find the window */
18514c0a534Smrg
18614c0a534Smrg	return (NULL);
18714c0a534Smrg    }
18814c0a534Smrg    else if (leader_winptr)
18914c0a534Smrg    {
19014c0a534Smrg	/* We found the real client leader */
19114c0a534Smrg
19214c0a534Smrg	return (leader_winptr);
19314c0a534Smrg    }
19414c0a534Smrg    else
19514c0a534Smrg    {
19614c0a534Smrg	/* There is no client leader defined, return this window */
19714c0a534Smrg
19814c0a534Smrg	return (winptr);
19914c0a534Smrg    }
20014c0a534Smrg}
20114c0a534Smrg
20214c0a534Smrg
20314c0a534Smrg
20414c0a534Smrgchar *
20514c0a534SmrgCheckFullyQuantifiedName (name, newstring)
20614c0a534Smrg
20714c0a534Smrgchar *name;
20814c0a534Smrgint *newstring;
20914c0a534Smrg
21014c0a534Smrg{
21114c0a534Smrg    /*
21214c0a534Smrg     * Due to a bug in Xlib (for hpux in particular), some clients
21314c0a534Smrg     * will have a WM_CLIENT_MACHINE that is not fully quantified.
21414c0a534Smrg     * For example, we might get "excon" instead of "excon.x.org".
21514c0a534Smrg     * This really stinks.  The best we can do is tag on our own
21614c0a534Smrg     * domain name.
21714c0a534Smrg     */
21814c0a534Smrg
21914c0a534Smrg    if (strchr (name, '.') != NULL)
22014c0a534Smrg    {
22114c0a534Smrg	*newstring = 0;
22214c0a534Smrg	return (name);
22314c0a534Smrg    }
22414c0a534Smrg    else
22514c0a534Smrg    {
22614c0a534Smrg	char hostnamebuf[80];
22714c0a534Smrg	char *firstDot;
22814c0a534Smrg
22914c0a534Smrg	gethostname (hostnamebuf, sizeof hostnamebuf);
23014c0a534Smrg	firstDot = strchr (hostnamebuf, '.');
23114c0a534Smrg
23214c0a534Smrg	if (!firstDot)
23314c0a534Smrg	{
23414c0a534Smrg	    *newstring = 0;
23514c0a534Smrg	    return (name);
23614c0a534Smrg	}
23714c0a534Smrg	else
23814c0a534Smrg	{
23914c0a534Smrg	    int bytes = strlen (name) + strlen (firstDot + 1) + 2;
24014c0a534Smrg	    char *newptr;
24114c0a534Smrg
24214c0a534Smrg	    newptr = (char *) malloc (bytes);
24314c0a534Smrg	    sprintf (newptr, "%s.%s", name, firstDot + 1);
24414c0a534Smrg
24514c0a534Smrg	    *newstring = 1;
24614c0a534Smrg	    return (newptr);
24714c0a534Smrg	}
24814c0a534Smrg    }
24914c0a534Smrg}
25014c0a534Smrg
25114c0a534Smrg
25214c0a534Smrg
25314c0a534Smrgvoid FinishSaveYourself (winInfo, has_WM_SAVEYOURSELF)
25414c0a534Smrg
25514c0a534SmrgWinInfo *winInfo;
25614c0a534SmrgBool has_WM_SAVEYOURSELF;
25714c0a534Smrg
25814c0a534Smrg{
25914c0a534Smrg    SmProp prop1, prop2, prop3, *props[3];
26014c0a534Smrg    SmPropValue prop1val, prop2val, prop3val;
26114c0a534Smrg    int i;
26214c0a534Smrg
26314c0a534Smrg    if (!winInfo->got_first_save_yourself)
26414c0a534Smrg    {
26514c0a534Smrg	char userId[20], restartService[80];
26614c0a534Smrg	char *fullyQuantifiedName;
26714c0a534Smrg	int newstring;
26814c0a534Smrg
26914c0a534Smrg	prop1.name = SmProgram;
27014c0a534Smrg	prop1.type = SmARRAY8;
27114c0a534Smrg	prop1.num_vals = 1;
27214c0a534Smrg	prop1.vals = &prop1val;
27314c0a534Smrg	prop1val.value = (SmPointer) winInfo->wm_command[0];
27414c0a534Smrg	prop1val.length = strlen (winInfo->wm_command[0]);
27514c0a534Smrg
27614c0a534Smrg	sprintf (userId, "%ld", (long)getuid());
27714c0a534Smrg	prop2.name = SmUserID;
27814c0a534Smrg	prop2.type = SmARRAY8;
27914c0a534Smrg	prop2.num_vals = 1;
28014c0a534Smrg	prop2.vals = &prop2val;
28114c0a534Smrg	prop2val.value = (SmPointer) userId;
28214c0a534Smrg	prop2val.length = strlen (userId);
28314c0a534Smrg
28414c0a534Smrg	fullyQuantifiedName = CheckFullyQuantifiedName (
28514c0a534Smrg	    (char *) winInfo->wm_client_machine.value, &newstring);
28614c0a534Smrg	sprintf (restartService, "rstart-rsh/%s", fullyQuantifiedName);
28714c0a534Smrg	if (newstring)
28814c0a534Smrg	    free (fullyQuantifiedName);
28914c0a534Smrg
29014c0a534Smrg	prop3.name = "_XC_RestartService";
29114c0a534Smrg	prop3.type = SmLISTofARRAY8;
29214c0a534Smrg	prop3.num_vals = 1;
29314c0a534Smrg	prop3.vals = &prop3val;
29414c0a534Smrg	prop3val.value = (SmPointer) restartService;
29514c0a534Smrg	prop3val.length = strlen (restartService);
29614c0a534Smrg
29714c0a534Smrg	props[0] = &prop1;
29814c0a534Smrg	props[1] = &prop2;
29914c0a534Smrg	props[2] = &prop3;
30014c0a534Smrg
30114c0a534Smrg	SmcSetProperties (winInfo->smc_conn, 3, props);
30214c0a534Smrg
30314c0a534Smrg	winInfo->got_first_save_yourself = 1;
30414c0a534Smrg    }
30514c0a534Smrg
30614c0a534Smrg    prop1.name = SmRestartCommand;
30714c0a534Smrg    prop1.type = SmLISTofARRAY8;
30814c0a534Smrg    prop1.num_vals = winInfo->wm_command_count;
30914c0a534Smrg
31014c0a534Smrg    prop1.vals = (SmPropValue *) malloc (
31114c0a534Smrg	winInfo->wm_command_count * sizeof (SmPropValue));
31214c0a534Smrg
31314c0a534Smrg    if (!prop1.vals)
31414c0a534Smrg    {
31514c0a534Smrg	SmcSaveYourselfDone (winInfo->smc_conn, False);
31614c0a534Smrg	return;
31714c0a534Smrg    }
31814c0a534Smrg
31914c0a534Smrg    for (i = 0; i < winInfo->wm_command_count; i++)
32014c0a534Smrg    {
32114c0a534Smrg	prop1.vals[i].value = (SmPointer) winInfo->wm_command[i];
32214c0a534Smrg	prop1.vals[i].length = strlen (winInfo->wm_command[i]);
32314c0a534Smrg    }
32414c0a534Smrg
32514c0a534Smrg    prop2.name = SmCloneCommand;
32614c0a534Smrg    prop2.type = SmLISTofARRAY8;
32714c0a534Smrg    prop2.num_vals = winInfo->wm_command_count;
32814c0a534Smrg    prop2.vals = prop1.vals;
32914c0a534Smrg
33014c0a534Smrg    props[0] = &prop1;
33114c0a534Smrg    props[1] = &prop2;
33214c0a534Smrg
33314c0a534Smrg    SmcSetProperties (winInfo->smc_conn, 2, props);
33414c0a534Smrg
33514c0a534Smrg    free ((char *) prop1.vals);
33614c0a534Smrg
33714c0a534Smrg    /*
33814c0a534Smrg     * If the client doesn't support WM_SAVE_YOURSELF, we should
33914c0a534Smrg     * return failure for the save, since we really don't know if
34014c0a534Smrg     * the application needed to save state.
34114c0a534Smrg     */
34214c0a534Smrg
34314c0a534Smrg    SmcSaveYourselfDone (winInfo->smc_conn, has_WM_SAVEYOURSELF);
34414c0a534Smrg}
34514c0a534Smrg
34614c0a534Smrg
34714c0a534Smrg
34814c0a534Smrgvoid
34914c0a534SmrgSaveYourselfCB (smcConn, clientData, saveType, shutdown, interactStyle, fast)
35014c0a534Smrg
35114c0a534SmrgSmcConn smcConn;
35214c0a534SmrgSmPointer clientData;
35314c0a534Smrgint saveType;
35414c0a534SmrgBool shutdown;
35514c0a534Smrgint interactStyle;
35614c0a534SmrgBool fast;
35714c0a534Smrg
35814c0a534Smrg{
35914c0a534Smrg    WinInfo *winInfo = (WinInfo *) clientData;
36014c0a534Smrg
36114c0a534Smrg    if (!winInfo->has_save_yourself)
36214c0a534Smrg    {
36314c0a534Smrg	FinishSaveYourself (winInfo, False);
36414c0a534Smrg    }
36514c0a534Smrg    else
36614c0a534Smrg    {
36714c0a534Smrg	XClientMessageEvent saveYourselfMessage;
36814c0a534Smrg
36914c0a534Smrg
37014c0a534Smrg	/* Send WM_SAVE_YOURSELF */
37114c0a534Smrg
37214c0a534Smrg	saveYourselfMessage.type = ClientMessage;
37314c0a534Smrg	saveYourselfMessage.window = winInfo->window;
37414c0a534Smrg	saveYourselfMessage.message_type = wmProtocolsAtom;
37514c0a534Smrg	saveYourselfMessage.format = 32;
37614c0a534Smrg	saveYourselfMessage.data.l[0] = wmSaveYourselfAtom;
37714c0a534Smrg	saveYourselfMessage.data.l[1] = CurrentTime;
37814c0a534Smrg
37914c0a534Smrg	if (XSendEvent (disp, winInfo->window, False, NoEventMask,
38014c0a534Smrg	    (XEvent *) &saveYourselfMessage))
38114c0a534Smrg	{
38214c0a534Smrg	    winInfo->waiting_for_update = 1;
38314c0a534Smrg
38414c0a534Smrg	    if (debug)
38514c0a534Smrg	    {
38614c0a534Smrg		printf ("Sent SAVE YOURSELF to 0x%x\n",
38714c0a534Smrg			(unsigned int)winInfo->window);
38814c0a534Smrg		printf ("\n");
38914c0a534Smrg	    }
39014c0a534Smrg	}
39114c0a534Smrg	else
39214c0a534Smrg	{
39314c0a534Smrg	    if (debug)
39414c0a534Smrg	    {
39514c0a534Smrg		printf ("Failed to send SAVE YOURSELF to 0x%x\n",
39614c0a534Smrg		    (unsigned int)winInfo->window);
39714c0a534Smrg		printf ("\n");
39814c0a534Smrg	    }
39914c0a534Smrg	}
40014c0a534Smrg    }
40114c0a534Smrg}
40214c0a534Smrg
40314c0a534Smrg
40414c0a534Smrg
40514c0a534Smrgvoid
40614c0a534SmrgDieCB (smcConn, clientData)
40714c0a534Smrg
40814c0a534SmrgSmcConn smcConn;
40914c0a534SmrgSmPointer clientData;
41014c0a534Smrg
41114c0a534Smrg{
41214c0a534Smrg    WinInfo *winInfo = (WinInfo *) clientData;
41314c0a534Smrg
41414c0a534Smrg    SmcCloseConnection (winInfo->smc_conn, 0, NULL);
41514c0a534Smrg    winInfo->smc_conn = NULL;
41614c0a534Smrg    XtRemoveInput (winInfo->input_id);
41714c0a534Smrg
41814c0a534Smrg    /* Now tell the client to die */
41914c0a534Smrg
42014c0a534Smrg    if (debug)
42114c0a534Smrg	printf ("Trying to kill 0x%x\n", (unsigned int)winInfo->window);
42214c0a534Smrg
42314c0a534Smrg    XSync (disp, 0);
42414c0a534Smrg    XKillClient (disp, winInfo->window);
42514c0a534Smrg    XSync (disp, 0);
42614c0a534Smrg
42714c0a534Smrg
42814c0a534Smrg    /*
42914c0a534Smrg     * Proxy must exit when all clients die, and the proxy itself
43014c0a534Smrg     * must have received a Die.
43114c0a534Smrg     */
43214c0a534Smrg
43314c0a534Smrg    die_count++;
43414c0a534Smrg
43514c0a534Smrg    if (die_count == proxy_count && ok_to_die)
43614c0a534Smrg    {
43714c0a534Smrg	exit (0);
43814c0a534Smrg    }
43914c0a534Smrg}
44014c0a534Smrg
44114c0a534Smrg
44214c0a534Smrg
44314c0a534Smrgvoid
44414c0a534SmrgSaveCompleteCB (smcConn, clientData)
44514c0a534Smrg
44614c0a534SmrgSmcConn smcConn;
44714c0a534SmrgSmPointer clientData;
44814c0a534Smrg
44914c0a534Smrg{
45014c0a534Smrg    /*
45114c0a534Smrg     * Nothing to do here.
45214c0a534Smrg     */
45314c0a534Smrg}
45414c0a534Smrg
45514c0a534Smrg
45614c0a534Smrg
45714c0a534Smrgvoid
45814c0a534SmrgShutdownCancelledCB (smcConn, clientData)
45914c0a534Smrg
46014c0a534SmrgSmcConn smcConn;
46114c0a534SmrgSmPointer clientData;
46214c0a534Smrg
46314c0a534Smrg{
46414c0a534Smrg    /*
46514c0a534Smrg     * Since we did not request to interact or request save yourself
46614c0a534Smrg     * phase 2, we know we already sent the save yourself done, so
46714c0a534Smrg     * there is nothing to do here.
46814c0a534Smrg     */
46914c0a534Smrg}
47014c0a534Smrg
47114c0a534Smrg
47214c0a534Smrg
47314c0a534Smrgvoid
47414c0a534SmrgProcessIceMsgProc (client_data, source, id)
47514c0a534Smrg
47614c0a534SmrgXtPointer	client_data;
47714c0a534Smrgint 		*source;
47814c0a534SmrgXtInputId	*id;
47914c0a534Smrg
48014c0a534Smrg{
48114c0a534Smrg    IceConn	ice_conn = (IceConn) client_data;
48214c0a534Smrg
48314c0a534Smrg    IceProcessMessages (ice_conn, NULL, NULL);
48414c0a534Smrg}
48514c0a534Smrg
48614c0a534Smrg
48714c0a534Smrg
48814c0a534Smrgvoid
48914c0a534SmrgNullIceErrorHandler (iceConn, swap,
49014c0a534Smrg    offendingMinorOpcode, offendingSequence, errorClass, severity, values)
49114c0a534Smrg
49214c0a534SmrgIceConn		iceConn;
49314c0a534SmrgBool		swap;
49414c0a534Smrgint		offendingMinorOpcode;
49514c0a534Smrgunsigned long	offendingSequence;
49614c0a534Smrgint 		errorClass;
49714c0a534Smrgint		severity;
49814c0a534SmrgIcePointer	values;
49914c0a534Smrg
50014c0a534Smrg{
50114c0a534Smrg    return;
50214c0a534Smrg}
50314c0a534Smrg
50414c0a534Smrg
50514c0a534Smrgvoid
50614c0a534SmrgConnectClientToSM (winInfo)
50714c0a534Smrg
50814c0a534SmrgWinInfo *winInfo;
50914c0a534Smrg
51014c0a534Smrg{
51114c0a534Smrg    char errorMsg[256];
51214c0a534Smrg    unsigned long mask;
51314c0a534Smrg    SmcCallbacks callbacks;
51414c0a534Smrg    IceConn ice_conn;
51514c0a534Smrg    char *prevId;
51614c0a534Smrg
51714c0a534Smrg    mask = SmcSaveYourselfProcMask | SmcDieProcMask |
51814c0a534Smrg	SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
51914c0a534Smrg
52014c0a534Smrg    callbacks.save_yourself.callback = SaveYourselfCB;
52114c0a534Smrg    callbacks.save_yourself.client_data = (SmPointer) winInfo;
52214c0a534Smrg
52314c0a534Smrg    callbacks.die.callback = DieCB;
52414c0a534Smrg    callbacks.die.client_data = (SmPointer) winInfo;
52514c0a534Smrg
52614c0a534Smrg    callbacks.save_complete.callback = SaveCompleteCB;
52714c0a534Smrg    callbacks.save_complete.client_data = (SmPointer) winInfo;
52814c0a534Smrg
52914c0a534Smrg    callbacks.shutdown_cancelled.callback = ShutdownCancelledCB;
53014c0a534Smrg    callbacks.shutdown_cancelled.client_data = (SmPointer) winInfo;
53114c0a534Smrg
53214c0a534Smrg    prevId = LookupClientID (winInfo);
53314c0a534Smrg
53414c0a534Smrg    /*
53514c0a534Smrg     * In case a protocol error occurs when opening the connection,
53614c0a534Smrg     * (e.g. an authentication error), we set a null error handler
53714c0a534Smrg     * before the open, then restore the default handler after the open.
53814c0a534Smrg     */
53914c0a534Smrg
54014c0a534Smrg    IceSetErrorHandler (NullIceErrorHandler);
54114c0a534Smrg
54214c0a534Smrg    winInfo->smc_conn = SmcOpenConnection (
54314c0a534Smrg	NULL, 			/* use SESSION_MANAGER env */
54414c0a534Smrg	(SmPointer) winInfo,	/* force a new connection */
54514c0a534Smrg	SmProtoMajor,
54614c0a534Smrg	SmProtoMinor,
54714c0a534Smrg	mask,
54814c0a534Smrg	&callbacks,
54914c0a534Smrg	prevId,
55014c0a534Smrg	&winInfo->client_id,
55114c0a534Smrg	256, errorMsg);
55214c0a534Smrg
55314c0a534Smrg    IceSetErrorHandler (NULL);
55414c0a534Smrg
55514c0a534Smrg    if (winInfo->smc_conn == NULL)
55614c0a534Smrg	return;
55714c0a534Smrg
55814c0a534Smrg    ice_conn = SmcGetIceConnection (winInfo->smc_conn);
55914c0a534Smrg
56014c0a534Smrg    winInfo->input_id = XtAppAddInput (
56114c0a534Smrg	    appContext,
56214c0a534Smrg	    IceConnectionNumber (ice_conn),
56314c0a534Smrg            (XtPointer) XtInputReadMask,
56414c0a534Smrg	    ProcessIceMsgProc,
56514c0a534Smrg	    (XtPointer) ice_conn);
56614c0a534Smrg
56714c0a534Smrg    if (debug)
56814c0a534Smrg    {
56914c0a534Smrg	printf ("Connected to SM, window = 0x%x\n",
57014c0a534Smrg		(unsigned int)winInfo->window);
57114c0a534Smrg	printf ("\n");
57214c0a534Smrg    }
57314c0a534Smrg
57414c0a534Smrg    proxy_count++;
57514c0a534Smrg}
57614c0a534Smrg
57714c0a534Smrg
57814c0a534Smrg
57914c0a534Smrgint
58014c0a534SmrgMyErrorHandler (display, event)
58114c0a534Smrg
58214c0a534SmrgDisplay *display;
58314c0a534SmrgXErrorEvent *event;
58414c0a534Smrg
58514c0a534Smrg{
58614c0a534Smrg    caught_error = 1;
58714c0a534Smrg    return 0;
58814c0a534Smrg}
58914c0a534Smrg
59014c0a534Smrg
59114c0a534Smrg
59214c0a534SmrgBool
59314c0a534SmrgLookupWindow (window, ptr_ret, prev_ptr_ret)
59414c0a534Smrg
59514c0a534SmrgWindow window;
59614c0a534SmrgWinInfo **ptr_ret;
59714c0a534SmrgWinInfo **prev_ptr_ret;
59814c0a534Smrg
59914c0a534Smrg{
60014c0a534Smrg    WinInfo *ptr, *prev;
60114c0a534Smrg
60214c0a534Smrg    ptr = win_head;
60314c0a534Smrg    prev = NULL;
60414c0a534Smrg
60514c0a534Smrg    while (ptr)
60614c0a534Smrg    {
60714c0a534Smrg	if (ptr->window == window)
60814c0a534Smrg	    break;
60914c0a534Smrg	else
61014c0a534Smrg	{
61114c0a534Smrg	    prev = ptr;
61214c0a534Smrg	    ptr = ptr->next;
61314c0a534Smrg	}
61414c0a534Smrg    }
61514c0a534Smrg
61614c0a534Smrg    if (ptr)
61714c0a534Smrg    {
61814c0a534Smrg	if (ptr_ret)
61914c0a534Smrg	    *ptr_ret = ptr;
62014c0a534Smrg	if (prev_ptr_ret)
62114c0a534Smrg	    *prev_ptr_ret = prev;
62214c0a534Smrg	return (1);
62314c0a534Smrg    }
62414c0a534Smrg    else
62514c0a534Smrg	return (0);
62614c0a534Smrg}
62714c0a534Smrg
62814c0a534Smrg
62914c0a534Smrg
63014c0a534SmrgWinInfo *
63114c0a534SmrgAddNewWindow (window)
63214c0a534Smrg
63314c0a534SmrgWindow window;
63414c0a534Smrg
63514c0a534Smrg{
63614c0a534Smrg    WinInfo *newptr;
63714c0a534Smrg
63814c0a534Smrg    if (LookupWindow (window, NULL, NULL))
63914c0a534Smrg	return (NULL);
64014c0a534Smrg
64114c0a534Smrg    newptr = (WinInfo *) malloc (sizeof (WinInfo));
64214c0a534Smrg
64314c0a534Smrg    if (newptr == NULL)
64414c0a534Smrg	return (NULL);
64514c0a534Smrg
64614c0a534Smrg    newptr->next = win_head;
64714c0a534Smrg    win_head = newptr;
64814c0a534Smrg
64914c0a534Smrg    newptr->window = window;
65014c0a534Smrg    newptr->smc_conn = NULL;
65114c0a534Smrg    newptr->tested_for_sm_client_id = 0;
65214c0a534Smrg    newptr->client_id = NULL;
65314c0a534Smrg    newptr->wm_command = NULL;
65414c0a534Smrg    newptr->wm_command_count = 0;
65514c0a534Smrg    newptr->class.res_name = NULL;
65614c0a534Smrg    newptr->class.res_class = NULL;
65714c0a534Smrg    newptr->wm_name = NULL;
65814c0a534Smrg    newptr->wm_client_machine.value = NULL;
65914c0a534Smrg    newptr->wm_client_machine.nitems = 0;
66014c0a534Smrg    newptr->has_save_yourself = 0;
66114c0a534Smrg    newptr->waiting_for_update = 0;
66214c0a534Smrg    newptr->got_first_save_yourself = 0;
66314c0a534Smrg
66414c0a534Smrg    return (newptr);
66514c0a534Smrg}
66614c0a534Smrg
66714c0a534Smrg
66814c0a534Smrg
66914c0a534Smrgvoid
67014c0a534SmrgRemoveWindow (winptr)
67114c0a534Smrg
67214c0a534SmrgWinInfo *winptr;
67314c0a534Smrg
67414c0a534Smrg{
67514c0a534Smrg    WinInfo *ptr, *prev;
67614c0a534Smrg
67714c0a534Smrg    if (LookupWindow (winptr->window, &ptr, &prev))
67814c0a534Smrg    {
67914c0a534Smrg	if (prev == NULL)
68014c0a534Smrg	    win_head = ptr->next;
68114c0a534Smrg	else
68214c0a534Smrg	    prev->next = ptr->next;
68314c0a534Smrg
68414c0a534Smrg	if (ptr->client_id)
68514c0a534Smrg	    free (ptr->client_id);
68614c0a534Smrg
68714c0a534Smrg	if (ptr->wm_command)
68814c0a534Smrg	    XFreeStringList (ptr->wm_command);
68914c0a534Smrg
69014c0a534Smrg	if (ptr->wm_name)
69114c0a534Smrg	    XFree (ptr->wm_name);
69214c0a534Smrg
69314c0a534Smrg	if (ptr->wm_client_machine.value)
69414c0a534Smrg	    XFree (ptr->wm_client_machine.value);
69514c0a534Smrg
69614c0a534Smrg	if (ptr->class.res_name)
69714c0a534Smrg	    XFree (ptr->class.res_name);
69814c0a534Smrg
69914c0a534Smrg	if (ptr->class.res_class)
70014c0a534Smrg	    XFree (ptr->class.res_class);
70114c0a534Smrg
70214c0a534Smrg	free ((char *) ptr);
70314c0a534Smrg    }
70414c0a534Smrg}
70514c0a534Smrg
70614c0a534Smrg
70714c0a534Smrg
70814c0a534Smrgvoid
70914c0a534SmrgGot_WM_STATE (winptr)
71014c0a534Smrg
71114c0a534SmrgWinInfo *winptr;
71214c0a534Smrg
71314c0a534Smrg{
71414c0a534Smrg    WinInfo *leader_winptr;
71514c0a534Smrg
71614c0a534Smrg    /*
71714c0a534Smrg     * If we already got WM_STATE and tested for SM_CLIENT_ID, we
71814c0a534Smrg     * shouldn't do it again.
71914c0a534Smrg     */
72014c0a534Smrg
72114c0a534Smrg    if (winptr->tested_for_sm_client_id)
72214c0a534Smrg    {
72314c0a534Smrg	return;
72414c0a534Smrg    }
72514c0a534Smrg
72614c0a534Smrg
72714c0a534Smrg    /*
72814c0a534Smrg     * Set a null error handler, in case this window goes away
72914c0a534Smrg     * behind our back.
73014c0a534Smrg     */
73114c0a534Smrg
73214c0a534Smrg    caught_error = 0;
73314c0a534Smrg    XSetErrorHandler (MyErrorHandler);
73414c0a534Smrg
73514c0a534Smrg
73614c0a534Smrg    /*
73714c0a534Smrg     * Get the client leader window.
73814c0a534Smrg     */
73914c0a534Smrg
74014c0a534Smrg    leader_winptr = GetClientLeader (winptr);
74114c0a534Smrg
74214c0a534Smrg    if (caught_error)
74314c0a534Smrg    {
74414c0a534Smrg	caught_error = 0;
74514c0a534Smrg	RemoveWindow (winptr);
74614c0a534Smrg	XSetErrorHandler (NULL);
74714c0a534Smrg	return;
74814c0a534Smrg    }
74914c0a534Smrg
75014c0a534Smrg
75114c0a534Smrg    /*
75214c0a534Smrg     * If we already checked for SM_CLIENT_ID on the client leader
75314c0a534Smrg     * window, don't do it again.
75414c0a534Smrg     */
75514c0a534Smrg
75614c0a534Smrg    if (!leader_winptr || leader_winptr->tested_for_sm_client_id)
75714c0a534Smrg    {
75814c0a534Smrg	caught_error = 0;
75914c0a534Smrg	XSetErrorHandler (NULL);
76014c0a534Smrg	return;
76114c0a534Smrg    }
76214c0a534Smrg
76314c0a534Smrg    leader_winptr->tested_for_sm_client_id = 1;
76414c0a534Smrg
76514c0a534Smrg    if (!HasXSMPsupport (leader_winptr->window))
76614c0a534Smrg    {
76714c0a534Smrg	XFetchName (disp, leader_winptr->window, &leader_winptr->wm_name);
76814c0a534Smrg
76914c0a534Smrg	XGetCommand (disp, leader_winptr->window,
77014c0a534Smrg	    &leader_winptr->wm_command,
77114c0a534Smrg	    &leader_winptr->wm_command_count);
77214c0a534Smrg
77314c0a534Smrg	XGetClassHint (disp, leader_winptr->window, &leader_winptr->class);
77414c0a534Smrg
77514c0a534Smrg	XGetWMClientMachine (disp, leader_winptr->window,
77614c0a534Smrg	    &leader_winptr->wm_client_machine);
77714c0a534Smrg
77814c0a534Smrg	if (leader_winptr->wm_name != NULL &&
77914c0a534Smrg	    leader_winptr->wm_command != NULL &&
78014c0a534Smrg	    leader_winptr->wm_command_count > 0 &&
78114c0a534Smrg	    leader_winptr->class.res_name != NULL &&
78214c0a534Smrg	    leader_winptr->class.res_class != NULL &&
78314c0a534Smrg	    leader_winptr->wm_client_machine.value != NULL &&
78414c0a534Smrg	    leader_winptr->wm_client_machine.nitems != 0)
78514c0a534Smrg	{
78614c0a534Smrg	    leader_winptr->has_save_yourself =
78714c0a534Smrg		HasSaveYourself (leader_winptr->window);
78814c0a534Smrg
78914c0a534Smrg	    ConnectClientToSM (leader_winptr);
79014c0a534Smrg	}
79114c0a534Smrg    }
79214c0a534Smrg
79314c0a534Smrg    XSync (disp, 0);
79414c0a534Smrg    XSetErrorHandler (NULL);
79514c0a534Smrg
79614c0a534Smrg    if (caught_error)
79714c0a534Smrg    {
79814c0a534Smrg	caught_error = 0;
79914c0a534Smrg	RemoveWindow (leader_winptr);
80014c0a534Smrg    }
80114c0a534Smrg}
80214c0a534Smrg
80314c0a534Smrg
80414c0a534Smrg
80514c0a534Smrgvoid
80614c0a534SmrgHandleCreate (event)
80714c0a534Smrg
80814c0a534SmrgXCreateWindowEvent *event;
80914c0a534Smrg
81014c0a534Smrg{
81114c0a534Smrg    Atom actual_type;
81214c0a534Smrg    int actual_format;
81314c0a534Smrg    unsigned long nitems, bytesafter;
81414c0a534Smrg    unsigned long *datap = NULL;
81514c0a534Smrg    WinInfo *winptr;
81614c0a534Smrg    Bool got_wm_state = 0;
81714c0a534Smrg
81814c0a534Smrg    /*
81914c0a534Smrg     * We are waiting for all proxy connections to close so we can die.
82014c0a534Smrg     * Don't handle new connections.
82114c0a534Smrg     */
82214c0a534Smrg
82314c0a534Smrg    if (ok_to_die)
82414c0a534Smrg	return;
82514c0a534Smrg
82614c0a534Smrg
82714c0a534Smrg    /*
82814c0a534Smrg     * Add the new window
82914c0a534Smrg     */
83014c0a534Smrg
83114c0a534Smrg    if ((winptr = AddNewWindow (event->window)) == NULL)
83214c0a534Smrg	return;
83314c0a534Smrg
83414c0a534Smrg
83514c0a534Smrg    /*
83614c0a534Smrg     * Right after the window was created, it might have been destroyed,
83714c0a534Smrg     * so the following Xlib calls might fail.  Need to catch the error
83814c0a534Smrg     * by installing an error handler.
83914c0a534Smrg     */
84014c0a534Smrg
84114c0a534Smrg    caught_error = 0;
84214c0a534Smrg    XSetErrorHandler (MyErrorHandler);
84314c0a534Smrg
84414c0a534Smrg
84514c0a534Smrg    /*
84614c0a534Smrg     * Select for Property Notify on the window so we can determine
84714c0a534Smrg     * when WM_STATE is defined.  To avoid a race condition, we must
84814c0a534Smrg     * do this _before_ we check for WM_STATE right now.
84914c0a534Smrg     *
85014c0a534Smrg     * Select for Substructure Notify so we can determine when the
85114c0a534Smrg     * window is destroyed.
85214c0a534Smrg     */
85314c0a534Smrg
85414c0a534Smrg    XSelectInput (disp, event->window,
85514c0a534Smrg	SubstructureNotifyMask | PropertyChangeMask);
85614c0a534Smrg
85714c0a534Smrg
85814c0a534Smrg    /*
85914c0a534Smrg     * WM_STATE may already be there.  Check now.
86014c0a534Smrg     */
86114c0a534Smrg
86214c0a534Smrg    if (XGetWindowProperty (disp, event->window, wmStateAtom,
86314c0a534Smrg	0L, 2L, False, AnyPropertyType,
86414c0a534Smrg	&actual_type, &actual_format, &nitems, &bytesafter,
86514c0a534Smrg	(unsigned char **) &datap) == Success && datap)
86614c0a534Smrg    {
86714c0a534Smrg	if (nitems > 0)
86814c0a534Smrg	    got_wm_state = 1;
86914c0a534Smrg
87014c0a534Smrg	if (datap)
87114c0a534Smrg	    XFree ((char *) datap);
87214c0a534Smrg    }
87314c0a534Smrg
87414c0a534Smrg    XSync (disp, 0);
87514c0a534Smrg    XSetErrorHandler (NULL);
87614c0a534Smrg
87714c0a534Smrg    if (caught_error)
87814c0a534Smrg    {
87914c0a534Smrg	caught_error = 0;
88014c0a534Smrg	RemoveWindow (winptr);
88114c0a534Smrg    }
88214c0a534Smrg    else if (got_wm_state)
88314c0a534Smrg    {
88414c0a534Smrg	Got_WM_STATE (winptr);
88514c0a534Smrg    }
88614c0a534Smrg}
88714c0a534Smrg
88814c0a534Smrg
88914c0a534Smrg
89014c0a534Smrgvoid
89114c0a534SmrgHandleDestroy (event)
89214c0a534Smrg
89314c0a534SmrgXDestroyWindowEvent *event;
89414c0a534Smrg
89514c0a534Smrg{
89614c0a534Smrg    WinInfo *winptr;
89714c0a534Smrg
89814c0a534Smrg    if (LookupWindow (event->window, &winptr, NULL))
89914c0a534Smrg    {
90014c0a534Smrg	if (winptr->smc_conn)
90114c0a534Smrg	{
90214c0a534Smrg	    SmcCloseConnection (winptr->smc_conn, 0, NULL);
90314c0a534Smrg	    XtRemoveInput (winptr->input_id);
90414c0a534Smrg	    proxy_count--;
90514c0a534Smrg	}
90614c0a534Smrg
90714c0a534Smrg	if (debug)
90814c0a534Smrg	{
90914c0a534Smrg	    printf ("Removed window (window = 0x%x)\n",
91014c0a534Smrg		    (unsigned int)winptr->window);
91114c0a534Smrg	    printf ("\n");
91214c0a534Smrg	}
91314c0a534Smrg
91414c0a534Smrg	RemoveWindow (winptr);
91514c0a534Smrg    }
91614c0a534Smrg}
91714c0a534Smrg
91814c0a534Smrg
91914c0a534Smrg
92014c0a534Smrgvoid
92114c0a534SmrgHandleUpdate (event)
92214c0a534Smrg
92314c0a534SmrgXPropertyEvent *event;
92414c0a534Smrg
92514c0a534Smrg{
92614c0a534Smrg    Window window = event->window;
92714c0a534Smrg    WinInfo *winptr;
92814c0a534Smrg
92914c0a534Smrg    if (!LookupWindow (window, &winptr, NULL))
93014c0a534Smrg	return;
93114c0a534Smrg
93214c0a534Smrg    if (event->atom == wmStateAtom)
93314c0a534Smrg    {
93414c0a534Smrg	Got_WM_STATE (winptr);
93514c0a534Smrg    }
93614c0a534Smrg    else if (event->atom == XA_WM_COMMAND && winptr->waiting_for_update)
93714c0a534Smrg    {
93814c0a534Smrg	/* Finish off the Save Yourself */
93914c0a534Smrg
94014c0a534Smrg	if (winptr->wm_command)
94114c0a534Smrg	{
94214c0a534Smrg	    XFreeStringList (winptr->wm_command);
94314c0a534Smrg	    winptr->wm_command = NULL;
94414c0a534Smrg	    winptr->wm_command_count = 0;
94514c0a534Smrg	}
94614c0a534Smrg
94714c0a534Smrg	XGetCommand (disp, window,
94814c0a534Smrg	    &winptr->wm_command,
94914c0a534Smrg	    &winptr->wm_command_count);
95014c0a534Smrg
95114c0a534Smrg	winptr->waiting_for_update = 0;
95214c0a534Smrg	FinishSaveYourself (winptr, True);
95314c0a534Smrg    }
95414c0a534Smrg}
95514c0a534Smrg
95614c0a534Smrg
95714c0a534Smrg
95814c0a534Smrgvoid
95914c0a534SmrgProxySaveYourselfPhase2CB (smcConn, clientData)
96014c0a534Smrg
96114c0a534SmrgSmcConn smcConn;
96214c0a534SmrgSmPointer clientData;
96314c0a534Smrg
96414c0a534Smrg{
96514c0a534Smrg    char *filename;
96614c0a534Smrg    Bool success = True;
96714c0a534Smrg    SmProp prop1, prop2, prop3, *props[3];
96814c0a534Smrg    SmPropValue prop1val, prop2val, prop3val;
96914c0a534Smrg    char discardCommand[80];
97014c0a534Smrg    int numVals, i;
97114c0a534Smrg    static int first_time = 1;
97214c0a534Smrg
97314c0a534Smrg    if (first_time)
97414c0a534Smrg    {
97514c0a534Smrg	char userId[20];
97614c0a534Smrg	char hint = SmRestartIfRunning;
97714c0a534Smrg
97814c0a534Smrg	prop1.name = SmProgram;
97914c0a534Smrg	prop1.type = SmARRAY8;
98014c0a534Smrg	prop1.num_vals = 1;
98114c0a534Smrg	prop1.vals = &prop1val;
98214c0a534Smrg	prop1val.value = Argv[0];
98314c0a534Smrg	prop1val.length = strlen (Argv[0]);
98414c0a534Smrg
98514c0a534Smrg	sprintf (userId, "%ld", (long)getuid());
98614c0a534Smrg	prop2.name = SmUserID;
98714c0a534Smrg	prop2.type = SmARRAY8;
98814c0a534Smrg	prop2.num_vals = 1;
98914c0a534Smrg	prop2.vals = &prop2val;
99014c0a534Smrg	prop2val.value = (SmPointer) userId;
99114c0a534Smrg	prop2val.length = strlen (userId);
99214c0a534Smrg
99314c0a534Smrg	prop3.name = SmRestartStyleHint;
99414c0a534Smrg	prop3.type = SmCARD8;
99514c0a534Smrg	prop3.num_vals = 1;
99614c0a534Smrg	prop3.vals = &prop3val;
99714c0a534Smrg	prop3val.value = (SmPointer) &hint;
99814c0a534Smrg	prop3val.length = 1;
99914c0a534Smrg
100014c0a534Smrg	props[0] = &prop1;
100114c0a534Smrg	props[1] = &prop2;
100214c0a534Smrg	props[2] = &prop3;
100314c0a534Smrg
100414c0a534Smrg	SmcSetProperties (smcConn, 3, props);
100514c0a534Smrg
100614c0a534Smrg	first_time = 0;
100714c0a534Smrg    }
100814c0a534Smrg
100914c0a534Smrg    if ((filename = WriteProxyFile ()) == NULL)
101014c0a534Smrg    {
101114c0a534Smrg	success = False;
101214c0a534Smrg	goto finishUp;
101314c0a534Smrg    }
101414c0a534Smrg
101514c0a534Smrg    prop1.name = SmRestartCommand;
101614c0a534Smrg    prop1.type = SmLISTofARRAY8;
101714c0a534Smrg
101814c0a534Smrg    prop1.vals = (SmPropValue *) malloc (
101914c0a534Smrg	(Argc + 4) * sizeof (SmPropValue));
102014c0a534Smrg
102114c0a534Smrg    if (!prop1.vals)
102214c0a534Smrg    {
102314c0a534Smrg	success = False;
102414c0a534Smrg	goto finishUp;
102514c0a534Smrg    }
102614c0a534Smrg
102714c0a534Smrg    numVals = 0;
102814c0a534Smrg
102914c0a534Smrg    for (i = 0; i < Argc; i++)
103014c0a534Smrg    {
103114c0a534Smrg	if (strcmp (Argv[i], "-clientId") == 0 ||
103214c0a534Smrg	    strcmp (Argv[i], "-restore") == 0)
103314c0a534Smrg	{
103414c0a534Smrg	    i++;
103514c0a534Smrg	}
103614c0a534Smrg	else
103714c0a534Smrg	{
103814c0a534Smrg	    prop1.vals[numVals].value = (SmPointer) Argv[i];
103914c0a534Smrg	    prop1.vals[numVals++].length = strlen (Argv[i]);
104014c0a534Smrg	}
104114c0a534Smrg    }
104214c0a534Smrg
104314c0a534Smrg    prop1.vals[numVals].value = (SmPointer) "-clientId";
104414c0a534Smrg    prop1.vals[numVals++].length = 9;
104514c0a534Smrg
104614c0a534Smrg    prop1.vals[numVals].value = (SmPointer) proxy_clientId;
104714c0a534Smrg    prop1.vals[numVals++].length = strlen (proxy_clientId);
104814c0a534Smrg
104914c0a534Smrg    prop1.vals[numVals].value = (SmPointer) "-restore";
105014c0a534Smrg    prop1.vals[numVals++].length = 8;
105114c0a534Smrg
105214c0a534Smrg    prop1.vals[numVals].value = (SmPointer) filename;
105314c0a534Smrg    prop1.vals[numVals++].length = strlen (filename);
105414c0a534Smrg
105514c0a534Smrg    prop1.num_vals = numVals;
105614c0a534Smrg
105714c0a534Smrg
105814c0a534Smrg    sprintf (discardCommand, "rm %s", filename);
105914c0a534Smrg    prop2.name = SmDiscardCommand;
106014c0a534Smrg    prop2.type = SmARRAY8;
106114c0a534Smrg    prop2.num_vals = 1;
106214c0a534Smrg    prop2.vals = &prop2val;
106314c0a534Smrg    prop2val.value = (SmPointer) discardCommand;
106414c0a534Smrg    prop2val.length = strlen (discardCommand);
106514c0a534Smrg
106614c0a534Smrg    props[0] = &prop1;
106714c0a534Smrg    props[1] = &prop2;
106814c0a534Smrg
106914c0a534Smrg    SmcSetProperties (smcConn, 2, props);
107014c0a534Smrg    free ((char *) prop1.vals);
107114c0a534Smrg
107214c0a534Smrg finishUp:
107314c0a534Smrg
107414c0a534Smrg    SmcSaveYourselfDone (smcConn, success);
107514c0a534Smrg    sent_save_done = 1;
107614c0a534Smrg
107714c0a534Smrg    if (filename)
107814c0a534Smrg	free (filename);
107914c0a534Smrg}
108014c0a534Smrg
108114c0a534Smrg
108214c0a534Smrg
108314c0a534Smrgvoid
108414c0a534SmrgProxySaveYourselfCB (smcConn, clientData, saveType,
108514c0a534Smrg    shutdown, interactStyle, fast)
108614c0a534Smrg
108714c0a534SmrgSmcConn smcConn;
108814c0a534SmrgSmPointer clientData;
108914c0a534Smrgint saveType;
109014c0a534SmrgBool shutdown;
109114c0a534Smrgint interactStyle;
109214c0a534SmrgBool fast;
109314c0a534Smrg
109414c0a534Smrg{
109514c0a534Smrg    /*
109614c0a534Smrg     * We want the proxy to respond to the Save Yourself after all
109714c0a534Smrg     * the regular XSMP clients have finished with the save (and possibly
109814c0a534Smrg     * interacted with the user).
109914c0a534Smrg     */
110014c0a534Smrg
110114c0a534Smrg    if (!SmcRequestSaveYourselfPhase2 (smcConn,
110214c0a534Smrg	ProxySaveYourselfPhase2CB, NULL))
110314c0a534Smrg    {
110414c0a534Smrg	SmcSaveYourselfDone (smcConn, False);
110514c0a534Smrg	sent_save_done = 1;
110614c0a534Smrg    }
110714c0a534Smrg    else
110814c0a534Smrg	sent_save_done = 0;
110914c0a534Smrg}
111014c0a534Smrg
111114c0a534Smrg
111214c0a534Smrg
111314c0a534Smrgvoid
111414c0a534SmrgProxyDieCB (smcConn, clientData)
111514c0a534Smrg
111614c0a534SmrgSmcConn smcConn;
111714c0a534SmrgSmPointer clientData;
111814c0a534Smrg
111914c0a534Smrg{
112014c0a534Smrg    SmcCloseConnection (proxy_smcConn, 0, NULL);
112114c0a534Smrg    XtRemoveInput (proxy_iceInputId);
112214c0a534Smrg
112314c0a534Smrg    if (die_count == proxy_count)
112414c0a534Smrg	exit (0);
112514c0a534Smrg    else
112614c0a534Smrg	ok_to_die = 1;
112714c0a534Smrg}
112814c0a534Smrg
112914c0a534Smrg
113014c0a534Smrg
113114c0a534Smrgvoid
113214c0a534SmrgProxySaveCompleteCB (smcConn, clientData)
113314c0a534Smrg
113414c0a534SmrgSmcConn smcConn;
113514c0a534SmrgSmPointer clientData;
113614c0a534Smrg
113714c0a534Smrg{
113814c0a534Smrg    ;
113914c0a534Smrg}
114014c0a534Smrg
114114c0a534Smrg
114214c0a534Smrg
114314c0a534Smrgvoid
114414c0a534SmrgProxyShutdownCancelledCB (smcConn, clientData)
114514c0a534Smrg
114614c0a534SmrgSmcConn smcConn;
114714c0a534SmrgSmPointer clientData;
114814c0a534Smrg
114914c0a534Smrg{
115014c0a534Smrg    if (!sent_save_done)
115114c0a534Smrg    {
115214c0a534Smrg	SmcSaveYourselfDone (smcConn, False);
115314c0a534Smrg	sent_save_done = 1;
115414c0a534Smrg    }
115514c0a534Smrg}
115614c0a534Smrg
115714c0a534Smrg
115814c0a534Smrg
115914c0a534SmrgStatus
116014c0a534SmrgConnectProxyToSM (previous_id)
116114c0a534Smrg
116214c0a534Smrgchar *previous_id;
116314c0a534Smrg
116414c0a534Smrg{
116514c0a534Smrg    char errorMsg[256];
116614c0a534Smrg    unsigned long mask;
116714c0a534Smrg    SmcCallbacks callbacks;
116814c0a534Smrg    IceConn iceConn;
116914c0a534Smrg
117014c0a534Smrg    mask = SmcSaveYourselfProcMask | SmcDieProcMask |
117114c0a534Smrg	SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
117214c0a534Smrg
117314c0a534Smrg    callbacks.save_yourself.callback = ProxySaveYourselfCB;
117414c0a534Smrg    callbacks.save_yourself.client_data = (SmPointer) NULL;
117514c0a534Smrg
117614c0a534Smrg    callbacks.die.callback = ProxyDieCB;
117714c0a534Smrg    callbacks.die.client_data = (SmPointer) NULL;
117814c0a534Smrg
117914c0a534Smrg    callbacks.save_complete.callback = ProxySaveCompleteCB;
118014c0a534Smrg    callbacks.save_complete.client_data = (SmPointer) NULL;
118114c0a534Smrg
118214c0a534Smrg    callbacks.shutdown_cancelled.callback = ProxyShutdownCancelledCB;
118314c0a534Smrg    callbacks.shutdown_cancelled.client_data = (SmPointer) NULL;
118414c0a534Smrg
118514c0a534Smrg    proxy_smcConn = SmcOpenConnection (
118614c0a534Smrg	NULL, 			/* use SESSION_MANAGER env */
118714c0a534Smrg	(SmPointer) appContext,
118814c0a534Smrg	SmProtoMajor,
118914c0a534Smrg	SmProtoMinor,
119014c0a534Smrg	mask,
119114c0a534Smrg	&callbacks,
119214c0a534Smrg	previous_id,
119314c0a534Smrg	&proxy_clientId,
119414c0a534Smrg	256, errorMsg);
119514c0a534Smrg
119614c0a534Smrg    if (proxy_smcConn == NULL)
119714c0a534Smrg	return (0);
119814c0a534Smrg
119914c0a534Smrg    iceConn = SmcGetIceConnection (proxy_smcConn);
120014c0a534Smrg
120114c0a534Smrg    proxy_iceInputId = XtAppAddInput (
120214c0a534Smrg	    appContext,
120314c0a534Smrg	    IceConnectionNumber (iceConn),
120414c0a534Smrg            (XtPointer) XtInputReadMask,
120514c0a534Smrg	    ProcessIceMsgProc,
120614c0a534Smrg	    (XtPointer) iceConn);
120714c0a534Smrg
120814c0a534Smrg    return (1);
120914c0a534Smrg}
121014c0a534Smrg
121114c0a534Smrg
121214c0a534Smrg
121314c0a534Smrgvoid
121414c0a534SmrgCheckForExistingWindows (root)
121514c0a534Smrg
121614c0a534SmrgWindow root;
121714c0a534Smrg
121814c0a534Smrg{
121914c0a534Smrg    Window dontCare1, dontCare2, *children, client_window;
122014c0a534Smrg    unsigned int nchildren, i;
122114c0a534Smrg    XCreateWindowEvent event;
122214c0a534Smrg
122314c0a534Smrg    /*
122414c0a534Smrg     * We query the root tree for all windows created thus far.
122514c0a534Smrg     * Note that at any moment after XQueryTree is called, a
122614c0a534Smrg     * window may be deleted.  So we must take extra care to make
122714c0a534Smrg     * sure a window really exists.
122814c0a534Smrg     */
122914c0a534Smrg
123014c0a534Smrg    XQueryTree (disp, root, &dontCare1, &dontCare2, &children, &nchildren);
123114c0a534Smrg
123214c0a534Smrg    for (i = 0; i < nchildren; i++)
123314c0a534Smrg    {
123414c0a534Smrg	event.window = children[i];
123514c0a534Smrg
123614c0a534Smrg	HandleCreate (&event);
123714c0a534Smrg
123814c0a534Smrg	caught_error = 0;
123914c0a534Smrg	XSetErrorHandler (MyErrorHandler);
124014c0a534Smrg
124114c0a534Smrg	client_window = XmuClientWindow (disp, children[i]);
124214c0a534Smrg
124314c0a534Smrg	XSetErrorHandler (NULL);
124414c0a534Smrg
124514c0a534Smrg	if (!caught_error && client_window != children[i])
124614c0a534Smrg	{
124714c0a534Smrg	    event.window = client_window;
124814c0a534Smrg	    HandleCreate (&event);
124914c0a534Smrg	}
125014c0a534Smrg    }
125114c0a534Smrg}
125214c0a534Smrg
125314c0a534Smrg
125414c0a534Smrg
125514c0a534Smrgint
125614c0a534Smrgmain (int argc, char *argv[])
125714c0a534Smrg{
125814c0a534Smrg    char *restore_filename = NULL;
125914c0a534Smrg    char *client_id = NULL;
126014c0a534Smrg    int i, zero = 0;
126114c0a534Smrg
126214c0a534Smrg    Argc = argc;
126314c0a534Smrg    Argv = argv;
126414c0a534Smrg
126514c0a534Smrg    for (i = 1; i < argc; i++)
126614c0a534Smrg    {
126714c0a534Smrg	if (argv[i][0] == '-')
126814c0a534Smrg	{
126914c0a534Smrg	    switch (argv[i][1])
127014c0a534Smrg	    {
127114c0a534Smrg	      case 'd':				/* -debug */
127214c0a534Smrg		debug = 1;
127314c0a534Smrg		continue;
127414c0a534Smrg
127514c0a534Smrg	      case 'c':				/* -clientId */
127614c0a534Smrg		if (++i >= argc) goto usage;
127714c0a534Smrg		client_id = argv[i];
127814c0a534Smrg		continue;
127914c0a534Smrg
128014c0a534Smrg	      case 'r':				/* -restore */
128114c0a534Smrg		if (++i >= argc) goto usage;
128214c0a534Smrg		restore_filename = argv[i];
128314c0a534Smrg		continue;
128414c0a534Smrg	    }
128514c0a534Smrg	}
128614c0a534Smrg
128714c0a534Smrg    usage:
128814c0a534Smrg
128914c0a534Smrg	fprintf (stderr,
129014c0a534Smrg	    "usage:  %s [-clientId id] [-restore file] [-debug]\n", argv[0]);
129114c0a534Smrg	exit (1);
129214c0a534Smrg    }
129314c0a534Smrg
129414c0a534Smrg
129514c0a534Smrg    XtToolkitInitialize ();
129614c0a534Smrg    appContext = XtCreateApplicationContext ();
129714c0a534Smrg
129814c0a534Smrg    if (!(disp = XtOpenDisplay (appContext, NULL, "SM-PROXY", "SM-PROXY",
129914c0a534Smrg	NULL, 0, &zero, NULL)))
130014c0a534Smrg    {
130114c0a534Smrg	fprintf (stderr, "smproxy: unable to open display\n");
130214c0a534Smrg	exit (1);
130314c0a534Smrg    }
130414c0a534Smrg
130514c0a534Smrg    if (restore_filename)
130614c0a534Smrg	ReadProxyFile (restore_filename);
130714c0a534Smrg
130814c0a534Smrg    if (!ConnectProxyToSM (client_id))
130914c0a534Smrg    {
131014c0a534Smrg	fprintf (stderr, "smproxy: unable to connect to session manager\n");
131114c0a534Smrg	exit (1);
131214c0a534Smrg    }
131314c0a534Smrg
131414c0a534Smrg    wmProtocolsAtom = XInternAtom (disp, "WM_PROTOCOLS", False);
131514c0a534Smrg    wmSaveYourselfAtom = XInternAtom (disp, "WM_SAVE_YOURSELF", False);
131614c0a534Smrg    wmStateAtom = XInternAtom (disp, "WM_STATE", False);
131714c0a534Smrg    smClientIdAtom = XInternAtom (disp, "SM_CLIENT_ID", False);
131814c0a534Smrg    wmClientLeaderAtom = XInternAtom (disp, "WM_CLIENT_LEADER", False);
131914c0a534Smrg
132014c0a534Smrg    for (i = 0; i < ScreenCount (disp); i++)
132114c0a534Smrg    {
132214c0a534Smrg	Window root = RootWindow (disp, i);
132314c0a534Smrg	XSelectInput (disp, root, SubstructureNotifyMask | PropertyChangeMask);
132414c0a534Smrg	CheckForExistingWindows (root);
132514c0a534Smrg    }
132614c0a534Smrg
132714c0a534Smrg    while (1)
132814c0a534Smrg    {
132914c0a534Smrg	XEvent event;
133014c0a534Smrg
133114c0a534Smrg	XtAppNextEvent (appContext, &event);
133214c0a534Smrg
133314c0a534Smrg	switch (event.type)
133414c0a534Smrg	{
133514c0a534Smrg	case CreateNotify:
133614c0a534Smrg	    HandleCreate (&event.xcreatewindow);
133714c0a534Smrg	    break;
133814c0a534Smrg
133914c0a534Smrg	case DestroyNotify:
134014c0a534Smrg	    HandleDestroy (&event.xdestroywindow);
134114c0a534Smrg	    break;
134214c0a534Smrg
134314c0a534Smrg	case PropertyNotify:
134414c0a534Smrg	    HandleUpdate (&event.xproperty);
134514c0a534Smrg	    break;
134614c0a534Smrg
134714c0a534Smrg	default:
134814c0a534Smrg	    XtDispatchEvent (&event);
134914c0a534Smrg	    break;
135014c0a534Smrg	}
135114c0a534Smrg    }
135214c0a534Smrg    exit(0);
135314c0a534Smrg}
1354