1354 lines
27 KiB
C
1354 lines
27 KiB
C
|
/* $Xorg: smproxy.c,v 1.6 2001/02/09 02:05:35 xorgcvs Exp $ */
|
|||
|
/******************************************************************************
|
|||
|
|
|||
|
Copyright 1994, 1998 The Open Group
|
|||
|
|
|||
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|||
|
documentation for any purpose is hereby granted without fee, provided that
|
|||
|
the above copyright notice appear in all copies and that both that
|
|||
|
copyright notice and this permission notice appear in supporting
|
|||
|
documentation.
|
|||
|
|
|||
|
The above copyright notice and this permission notice shall be included in
|
|||
|
all copies or substantial portions of the Software.
|
|||
|
|
|||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|||
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|||
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
|
|||
|
Except as contained in this notice, the name of The Open Group shall not be
|
|||
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|||
|
in this Software without prior written authorization from The Open Group.
|
|||
|
|
|||
|
Author: Ralph Mor, X Consortium
|
|||
|
******************************************************************************/
|
|||
|
/* $XFree86: xc/programs/smproxy/smproxy.c,v 3.8 2001/10/28 03:34:25 tsi Exp $ */
|
|||
|
|
|||
|
#include "smproxy.h"
|
|||
|
#include <unistd.h>
|
|||
|
#include <X11/Xmu/WinUtil.h>
|
|||
|
|
|||
|
XtAppContext appContext;
|
|||
|
Display *disp;
|
|||
|
|
|||
|
Atom wmProtocolsAtom;
|
|||
|
Atom wmSaveYourselfAtom;
|
|||
|
Atom wmStateAtom;
|
|||
|
Atom smClientIdAtom;
|
|||
|
Atom wmClientLeaderAtom;
|
|||
|
|
|||
|
Bool debug = 0;
|
|||
|
|
|||
|
SmcConn proxy_smcConn;
|
|||
|
XtInputId proxy_iceInputId;
|
|||
|
char *proxy_clientId = NULL;
|
|||
|
|
|||
|
WinInfo *win_head = NULL;
|
|||
|
|
|||
|
int proxy_count = 0;
|
|||
|
int die_count = 0;
|
|||
|
|
|||
|
Bool ok_to_die = 0;
|
|||
|
|
|||
|
Bool caught_error = 0;
|
|||
|
|
|||
|
Bool sent_save_done = 0;
|
|||
|
|
|||
|
int Argc;
|
|||
|
char **Argv;
|
|||
|
|
|||
|
Bool HasSaveYourself ( Window window );
|
|||
|
Bool HasXSMPsupport ( Window window );
|
|||
|
WinInfo * GetClientLeader ( WinInfo *winptr );
|
|||
|
char * CheckFullyQuantifiedName ( char *name, int *newstring );
|
|||
|
void FinishSaveYourself ( WinInfo *winInfo, Bool has_WM_SAVEYOURSELF );
|
|||
|
void SaveYourselfCB ( SmcConn smcConn, SmPointer clientData, int saveType,
|
|||
|
Bool shutdown, int interactStyle, Bool fast );
|
|||
|
void DieCB ( SmcConn smcConn, SmPointer clientData );
|
|||
|
void SaveCompleteCB ( SmcConn smcConn, SmPointer clientData );
|
|||
|
void ShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData );
|
|||
|
void ProcessIceMsgProc ( XtPointer client_data, int *source, XtInputId *id );
|
|||
|
void NullIceErrorHandler ( IceConn iceConn, Bool swap,
|
|||
|
int offendingMinorOpCode,
|
|||
|
unsigned long offendingSequence,
|
|||
|
int errorClass, int severity, IcePointer values );
|
|||
|
void ConnectClientToSM ( WinInfo *winInfo );
|
|||
|
int MyErrorHandler ( Display *display, XErrorEvent *event );
|
|||
|
Bool LookupWindow ( Window window, WinInfo **ptr_ret, WinInfo **prev_ptr_ret );
|
|||
|
WinInfo * AddNewWindow ( Window window );
|
|||
|
void RemoveWindow ( WinInfo *winptr );
|
|||
|
void Got_WM_STATE ( WinInfo *winptr );
|
|||
|
void HandleCreate ( XCreateWindowEvent *event );
|
|||
|
void HandleDestroy ( XDestroyWindowEvent *event );
|
|||
|
void HandleUpdate ( XPropertyEvent *event );
|
|||
|
void ProxySaveYourselfPhase2CB ( SmcConn smcConn, SmPointer clientData );
|
|||
|
void ProxySaveYourselfCB ( SmcConn smcConn, SmPointer clientData,
|
|||
|
int saveType, Bool shutdown, int interactStyle,
|
|||
|
Bool fast );
|
|||
|
void ProxyDieCB ( SmcConn smcConn, SmPointer clientData );
|
|||
|
void ProxySaveCompleteCB ( SmcConn smcConn, SmPointer clientData );
|
|||
|
void ProxyShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData );
|
|||
|
Status ConnectProxyToSM ( char *previous_id );
|
|||
|
void CheckForExistingWindows ( Window root );
|
|||
|
|
|||
|
|
|||
|
Bool
|
|||
|
HasSaveYourself (window)
|
|||
|
|
|||
|
Window window;
|
|||
|
|
|||
|
{
|
|||
|
Atom *protocols;
|
|||
|
int numProtocols;
|
|||
|
int i, found;
|
|||
|
|
|||
|
protocols = NULL;
|
|||
|
|
|||
|
if (XGetWMProtocols (disp, window, &protocols, &numProtocols) != True)
|
|||
|
return (False);
|
|||
|
|
|||
|
found = 0;
|
|||
|
|
|||
|
if (protocols != NULL)
|
|||
|
{
|
|||
|
for (i = 0; i < numProtocols; i++)
|
|||
|
if (protocols[i] == wmSaveYourselfAtom)
|
|||
|
found = 1;
|
|||
|
|
|||
|
XFree (protocols);
|
|||
|
}
|
|||
|
|
|||
|
return (found);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Bool
|
|||
|
HasXSMPsupport (window)
|
|||
|
|
|||
|
Window window;
|
|||
|
|
|||
|
{
|
|||
|
XTextProperty tp;
|
|||
|
Bool hasIt = 0;
|
|||
|
|
|||
|
if (XGetTextProperty (disp, window, &tp, smClientIdAtom))
|
|||
|
{
|
|||
|
if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0)
|
|||
|
hasIt = 1;
|
|||
|
|
|||
|
if (tp.value)
|
|||
|
XFree ((char *) tp.value);
|
|||
|
}
|
|||
|
|
|||
|
return (hasIt);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
WinInfo *
|
|||
|
GetClientLeader (winptr)
|
|||
|
|
|||
|
WinInfo *winptr;
|
|||
|
|
|||
|
{
|
|||
|
Atom actual_type;
|
|||
|
int actual_format;
|
|||
|
unsigned long nitems, bytesafter;
|
|||
|
unsigned long *datap = NULL;
|
|||
|
WinInfo *leader_winptr = NULL;
|
|||
|
Bool failure = 0;
|
|||
|
|
|||
|
if (XGetWindowProperty (disp, winptr->window, wmClientLeaderAtom,
|
|||
|
0L, 1L, False, AnyPropertyType, &actual_type, &actual_format,
|
|||
|
&nitems, &bytesafter, (unsigned char **) &datap) == Success)
|
|||
|
{
|
|||
|
if (actual_type == XA_WINDOW && actual_format == 32 &&
|
|||
|
nitems == 1 && bytesafter == 0)
|
|||
|
{
|
|||
|
Window leader_win = *((Window *) datap);
|
|||
|
|
|||
|
if (!LookupWindow (leader_win, &leader_winptr, NULL))
|
|||
|
failure = 1;
|
|||
|
}
|
|||
|
|
|||
|
if (datap)
|
|||
|
XFree (datap);
|
|||
|
}
|
|||
|
|
|||
|
if (failure)
|
|||
|
{
|
|||
|
/* The client leader was defined, but we couldn't find the window */
|
|||
|
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
else if (leader_winptr)
|
|||
|
{
|
|||
|
/* We found the real client leader */
|
|||
|
|
|||
|
return (leader_winptr);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* There is no client leader defined, return this window */
|
|||
|
|
|||
|
return (winptr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
char *
|
|||
|
CheckFullyQuantifiedName (name, newstring)
|
|||
|
|
|||
|
char *name;
|
|||
|
int *newstring;
|
|||
|
|
|||
|
{
|
|||
|
/*
|
|||
|
* Due to a bug in Xlib (for hpux in particular), some clients
|
|||
|
* will have a WM_CLIENT_MACHINE that is not fully quantified.
|
|||
|
* For example, we might get "excon" instead of "excon.x.org".
|
|||
|
* This really stinks. The best we can do is tag on our own
|
|||
|
* domain name.
|
|||
|
*/
|
|||
|
|
|||
|
if (strchr (name, '.') != NULL)
|
|||
|
{
|
|||
|
*newstring = 0;
|
|||
|
return (name);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
char hostnamebuf[80];
|
|||
|
char *firstDot;
|
|||
|
|
|||
|
gethostname (hostnamebuf, sizeof hostnamebuf);
|
|||
|
firstDot = strchr (hostnamebuf, '.');
|
|||
|
|
|||
|
if (!firstDot)
|
|||
|
{
|
|||
|
*newstring = 0;
|
|||
|
return (name);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
int bytes = strlen (name) + strlen (firstDot + 1) + 2;
|
|||
|
char *newptr;
|
|||
|
|
|||
|
newptr = (char *) malloc (bytes);
|
|||
|
sprintf (newptr, "%s.%s", name, firstDot + 1);
|
|||
|
|
|||
|
*newstring = 1;
|
|||
|
return (newptr);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void FinishSaveYourself (winInfo, has_WM_SAVEYOURSELF)
|
|||
|
|
|||
|
WinInfo *winInfo;
|
|||
|
Bool has_WM_SAVEYOURSELF;
|
|||
|
|
|||
|
{
|
|||
|
SmProp prop1, prop2, prop3, *props[3];
|
|||
|
SmPropValue prop1val, prop2val, prop3val;
|
|||
|
int i;
|
|||
|
|
|||
|
if (!winInfo->got_first_save_yourself)
|
|||
|
{
|
|||
|
char userId[20], restartService[80];
|
|||
|
char *fullyQuantifiedName;
|
|||
|
int newstring;
|
|||
|
|
|||
|
prop1.name = SmProgram;
|
|||
|
prop1.type = SmARRAY8;
|
|||
|
prop1.num_vals = 1;
|
|||
|
prop1.vals = &prop1val;
|
|||
|
prop1val.value = (SmPointer) winInfo->wm_command[0];
|
|||
|
prop1val.length = strlen (winInfo->wm_command[0]);
|
|||
|
|
|||
|
sprintf (userId, "%ld", (long)getuid());
|
|||
|
prop2.name = SmUserID;
|
|||
|
prop2.type = SmARRAY8;
|
|||
|
prop2.num_vals = 1;
|
|||
|
prop2.vals = &prop2val;
|
|||
|
prop2val.value = (SmPointer) userId;
|
|||
|
prop2val.length = strlen (userId);
|
|||
|
|
|||
|
fullyQuantifiedName = CheckFullyQuantifiedName (
|
|||
|
(char *) winInfo->wm_client_machine.value, &newstring);
|
|||
|
sprintf (restartService, "rstart-rsh/%s", fullyQuantifiedName);
|
|||
|
if (newstring)
|
|||
|
free (fullyQuantifiedName);
|
|||
|
|
|||
|
prop3.name = "_XC_RestartService";
|
|||
|
prop3.type = SmLISTofARRAY8;
|
|||
|
prop3.num_vals = 1;
|
|||
|
prop3.vals = &prop3val;
|
|||
|
prop3val.value = (SmPointer) restartService;
|
|||
|
prop3val.length = strlen (restartService);
|
|||
|
|
|||
|
props[0] = &prop1;
|
|||
|
props[1] = &prop2;
|
|||
|
props[2] = &prop3;
|
|||
|
|
|||
|
SmcSetProperties (winInfo->smc_conn, 3, props);
|
|||
|
|
|||
|
winInfo->got_first_save_yourself = 1;
|
|||
|
}
|
|||
|
|
|||
|
prop1.name = SmRestartCommand;
|
|||
|
prop1.type = SmLISTofARRAY8;
|
|||
|
prop1.num_vals = winInfo->wm_command_count;
|
|||
|
|
|||
|
prop1.vals = (SmPropValue *) malloc (
|
|||
|
winInfo->wm_command_count * sizeof (SmPropValue));
|
|||
|
|
|||
|
if (!prop1.vals)
|
|||
|
{
|
|||
|
SmcSaveYourselfDone (winInfo->smc_conn, False);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
for (i = 0; i < winInfo->wm_command_count; i++)
|
|||
|
{
|
|||
|
prop1.vals[i].value = (SmPointer) winInfo->wm_command[i];
|
|||
|
prop1.vals[i].length = strlen (winInfo->wm_command[i]);
|
|||
|
}
|
|||
|
|
|||
|
prop2.name = SmCloneCommand;
|
|||
|
prop2.type = SmLISTofARRAY8;
|
|||
|
prop2.num_vals = winInfo->wm_command_count;
|
|||
|
prop2.vals = prop1.vals;
|
|||
|
|
|||
|
props[0] = &prop1;
|
|||
|
props[1] = &prop2;
|
|||
|
|
|||
|
SmcSetProperties (winInfo->smc_conn, 2, props);
|
|||
|
|
|||
|
free ((char *) prop1.vals);
|
|||
|
|
|||
|
/*
|
|||
|
* If the client doesn't support WM_SAVE_YOURSELF, we should
|
|||
|
* return failure for the save, since we really don't know if
|
|||
|
* the application needed to save state.
|
|||
|
*/
|
|||
|
|
|||
|
SmcSaveYourselfDone (winInfo->smc_conn, has_WM_SAVEYOURSELF);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
SaveYourselfCB (smcConn, clientData, saveType, shutdown, interactStyle, fast)
|
|||
|
|
|||
|
SmcConn smcConn;
|
|||
|
SmPointer clientData;
|
|||
|
int saveType;
|
|||
|
Bool shutdown;
|
|||
|
int interactStyle;
|
|||
|
Bool fast;
|
|||
|
|
|||
|
{
|
|||
|
WinInfo *winInfo = (WinInfo *) clientData;
|
|||
|
|
|||
|
if (!winInfo->has_save_yourself)
|
|||
|
{
|
|||
|
FinishSaveYourself (winInfo, False);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
XClientMessageEvent saveYourselfMessage;
|
|||
|
|
|||
|
|
|||
|
/* Send WM_SAVE_YOURSELF */
|
|||
|
|
|||
|
saveYourselfMessage.type = ClientMessage;
|
|||
|
saveYourselfMessage.window = winInfo->window;
|
|||
|
saveYourselfMessage.message_type = wmProtocolsAtom;
|
|||
|
saveYourselfMessage.format = 32;
|
|||
|
saveYourselfMessage.data.l[0] = wmSaveYourselfAtom;
|
|||
|
saveYourselfMessage.data.l[1] = CurrentTime;
|
|||
|
|
|||
|
if (XSendEvent (disp, winInfo->window, False, NoEventMask,
|
|||
|
(XEvent *) &saveYourselfMessage))
|
|||
|
{
|
|||
|
winInfo->waiting_for_update = 1;
|
|||
|
|
|||
|
if (debug)
|
|||
|
{
|
|||
|
printf ("Sent SAVE YOURSELF to 0x%x\n",
|
|||
|
(unsigned int)winInfo->window);
|
|||
|
printf ("\n");
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (debug)
|
|||
|
{
|
|||
|
printf ("Failed to send SAVE YOURSELF to 0x%x\n",
|
|||
|
(unsigned int)winInfo->window);
|
|||
|
printf ("\n");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
DieCB (smcConn, clientData)
|
|||
|
|
|||
|
SmcConn smcConn;
|
|||
|
SmPointer clientData;
|
|||
|
|
|||
|
{
|
|||
|
WinInfo *winInfo = (WinInfo *) clientData;
|
|||
|
|
|||
|
SmcCloseConnection (winInfo->smc_conn, 0, NULL);
|
|||
|
winInfo->smc_conn = NULL;
|
|||
|
XtRemoveInput (winInfo->input_id);
|
|||
|
|
|||
|
/* Now tell the client to die */
|
|||
|
|
|||
|
if (debug)
|
|||
|
printf ("Trying to kill 0x%x\n", (unsigned int)winInfo->window);
|
|||
|
|
|||
|
XSync (disp, 0);
|
|||
|
XKillClient (disp, winInfo->window);
|
|||
|
XSync (disp, 0);
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Proxy must exit when all clients die, and the proxy itself
|
|||
|
* must have received a Die.
|
|||
|
*/
|
|||
|
|
|||
|
die_count++;
|
|||
|
|
|||
|
if (die_count == proxy_count && ok_to_die)
|
|||
|
{
|
|||
|
exit (0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
SaveCompleteCB (smcConn, clientData)
|
|||
|
|
|||
|
SmcConn smcConn;
|
|||
|
SmPointer clientData;
|
|||
|
|
|||
|
{
|
|||
|
/*
|
|||
|
* Nothing to do here.
|
|||
|
*/
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
ShutdownCancelledCB (smcConn, clientData)
|
|||
|
|
|||
|
SmcConn smcConn;
|
|||
|
SmPointer clientData;
|
|||
|
|
|||
|
{
|
|||
|
/*
|
|||
|
* Since we did not request to interact or request save yourself
|
|||
|
* phase 2, we know we already sent the save yourself done, so
|
|||
|
* there is nothing to do here.
|
|||
|
*/
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
ProcessIceMsgProc (client_data, source, id)
|
|||
|
|
|||
|
XtPointer client_data;
|
|||
|
int *source;
|
|||
|
XtInputId *id;
|
|||
|
|
|||
|
{
|
|||
|
IceConn ice_conn = (IceConn) client_data;
|
|||
|
|
|||
|
IceProcessMessages (ice_conn, NULL, NULL);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
NullIceErrorHandler (iceConn, swap,
|
|||
|
offendingMinorOpcode, offendingSequence, errorClass, severity, values)
|
|||
|
|
|||
|
IceConn iceConn;
|
|||
|
Bool swap;
|
|||
|
int offendingMinorOpcode;
|
|||
|
unsigned long offendingSequence;
|
|||
|
int errorClass;
|
|||
|
int severity;
|
|||
|
IcePointer values;
|
|||
|
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
ConnectClientToSM (winInfo)
|
|||
|
|
|||
|
WinInfo *winInfo;
|
|||
|
|
|||
|
{
|
|||
|
char errorMsg[256];
|
|||
|
unsigned long mask;
|
|||
|
SmcCallbacks callbacks;
|
|||
|
IceConn ice_conn;
|
|||
|
char *prevId;
|
|||
|
|
|||
|
mask = SmcSaveYourselfProcMask | SmcDieProcMask |
|
|||
|
SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
|
|||
|
|
|||
|
callbacks.save_yourself.callback = SaveYourselfCB;
|
|||
|
callbacks.save_yourself.client_data = (SmPointer) winInfo;
|
|||
|
|
|||
|
callbacks.die.callback = DieCB;
|
|||
|
callbacks.die.client_data = (SmPointer) winInfo;
|
|||
|
|
|||
|
callbacks.save_complete.callback = SaveCompleteCB;
|
|||
|
callbacks.save_complete.client_data = (SmPointer) winInfo;
|
|||
|
|
|||
|
callbacks.shutdown_cancelled.callback = ShutdownCancelledCB;
|
|||
|
callbacks.shutdown_cancelled.client_data = (SmPointer) winInfo;
|
|||
|
|
|||
|
prevId = LookupClientID (winInfo);
|
|||
|
|
|||
|
/*
|
|||
|
* In case a protocol error occurs when opening the connection,
|
|||
|
* (e.g. an authentication error), we set a null error handler
|
|||
|
* before the open, then restore the default handler after the open.
|
|||
|
*/
|
|||
|
|
|||
|
IceSetErrorHandler (NullIceErrorHandler);
|
|||
|
|
|||
|
winInfo->smc_conn = SmcOpenConnection (
|
|||
|
NULL, /* use SESSION_MANAGER env */
|
|||
|
(SmPointer) winInfo, /* force a new connection */
|
|||
|
SmProtoMajor,
|
|||
|
SmProtoMinor,
|
|||
|
mask,
|
|||
|
&callbacks,
|
|||
|
prevId,
|
|||
|
&winInfo->client_id,
|
|||
|
256, errorMsg);
|
|||
|
|
|||
|
IceSetErrorHandler (NULL);
|
|||
|
|
|||
|
if (winInfo->smc_conn == NULL)
|
|||
|
return;
|
|||
|
|
|||
|
ice_conn = SmcGetIceConnection (winInfo->smc_conn);
|
|||
|
|
|||
|
winInfo->input_id = XtAppAddInput (
|
|||
|
appContext,
|
|||
|
IceConnectionNumber (ice_conn),
|
|||
|
(XtPointer) XtInputReadMask,
|
|||
|
ProcessIceMsgProc,
|
|||
|
(XtPointer) ice_conn);
|
|||
|
|
|||
|
if (debug)
|
|||
|
{
|
|||
|
printf ("Connected to SM, window = 0x%x\n",
|
|||
|
(unsigned int)winInfo->window);
|
|||
|
printf ("\n");
|
|||
|
}
|
|||
|
|
|||
|
proxy_count++;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
MyErrorHandler (display, event)
|
|||
|
|
|||
|
Display *display;
|
|||
|
XErrorEvent *event;
|
|||
|
|
|||
|
{
|
|||
|
caught_error = 1;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Bool
|
|||
|
LookupWindow (window, ptr_ret, prev_ptr_ret)
|
|||
|
|
|||
|
Window window;
|
|||
|
WinInfo **ptr_ret;
|
|||
|
WinInfo **prev_ptr_ret;
|
|||
|
|
|||
|
{
|
|||
|
WinInfo *ptr, *prev;
|
|||
|
|
|||
|
ptr = win_head;
|
|||
|
prev = NULL;
|
|||
|
|
|||
|
while (ptr)
|
|||
|
{
|
|||
|
if (ptr->window == window)
|
|||
|
break;
|
|||
|
else
|
|||
|
{
|
|||
|
prev = ptr;
|
|||
|
ptr = ptr->next;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ptr)
|
|||
|
{
|
|||
|
if (ptr_ret)
|
|||
|
*ptr_ret = ptr;
|
|||
|
if (prev_ptr_ret)
|
|||
|
*prev_ptr_ret = prev;
|
|||
|
return (1);
|
|||
|
}
|
|||
|
else
|
|||
|
return (0);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
WinInfo *
|
|||
|
AddNewWindow (window)
|
|||
|
|
|||
|
Window window;
|
|||
|
|
|||
|
{
|
|||
|
WinInfo *newptr;
|
|||
|
|
|||
|
if (LookupWindow (window, NULL, NULL))
|
|||
|
return (NULL);
|
|||
|
|
|||
|
newptr = (WinInfo *) malloc (sizeof (WinInfo));
|
|||
|
|
|||
|
if (newptr == NULL)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
newptr->next = win_head;
|
|||
|
win_head = newptr;
|
|||
|
|
|||
|
newptr->window = window;
|
|||
|
newptr->smc_conn = NULL;
|
|||
|
newptr->tested_for_sm_client_id = 0;
|
|||
|
newptr->client_id = NULL;
|
|||
|
newptr->wm_command = NULL;
|
|||
|
newptr->wm_command_count = 0;
|
|||
|
newptr->class.res_name = NULL;
|
|||
|
newptr->class.res_class = NULL;
|
|||
|
newptr->wm_name = NULL;
|
|||
|
newptr->wm_client_machine.value = NULL;
|
|||
|
newptr->wm_client_machine.nitems = 0;
|
|||
|
newptr->has_save_yourself = 0;
|
|||
|
newptr->waiting_for_update = 0;
|
|||
|
newptr->got_first_save_yourself = 0;
|
|||
|
|
|||
|
return (newptr);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
RemoveWindow (winptr)
|
|||
|
|
|||
|
WinInfo *winptr;
|
|||
|
|
|||
|
{
|
|||
|
WinInfo *ptr, *prev;
|
|||
|
|
|||
|
if (LookupWindow (winptr->window, &ptr, &prev))
|
|||
|
{
|
|||
|
if (prev == NULL)
|
|||
|
win_head = ptr->next;
|
|||
|
else
|
|||
|
prev->next = ptr->next;
|
|||
|
|
|||
|
if (ptr->client_id)
|
|||
|
free (ptr->client_id);
|
|||
|
|
|||
|
if (ptr->wm_command)
|
|||
|
XFreeStringList (ptr->wm_command);
|
|||
|
|
|||
|
if (ptr->wm_name)
|
|||
|
XFree (ptr->wm_name);
|
|||
|
|
|||
|
if (ptr->wm_client_machine.value)
|
|||
|
XFree (ptr->wm_client_machine.value);
|
|||
|
|
|||
|
if (ptr->class.res_name)
|
|||
|
XFree (ptr->class.res_name);
|
|||
|
|
|||
|
if (ptr->class.res_class)
|
|||
|
XFree (ptr->class.res_class);
|
|||
|
|
|||
|
free ((char *) ptr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
Got_WM_STATE (winptr)
|
|||
|
|
|||
|
WinInfo *winptr;
|
|||
|
|
|||
|
{
|
|||
|
WinInfo *leader_winptr;
|
|||
|
|
|||
|
/*
|
|||
|
* If we already got WM_STATE and tested for SM_CLIENT_ID, we
|
|||
|
* shouldn't do it again.
|
|||
|
*/
|
|||
|
|
|||
|
if (winptr->tested_for_sm_client_id)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Set a null error handler, in case this window goes away
|
|||
|
* behind our back.
|
|||
|
*/
|
|||
|
|
|||
|
caught_error = 0;
|
|||
|
XSetErrorHandler (MyErrorHandler);
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Get the client leader window.
|
|||
|
*/
|
|||
|
|
|||
|
leader_winptr = GetClientLeader (winptr);
|
|||
|
|
|||
|
if (caught_error)
|
|||
|
{
|
|||
|
caught_error = 0;
|
|||
|
RemoveWindow (winptr);
|
|||
|
XSetErrorHandler (NULL);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* If we already checked for SM_CLIENT_ID on the client leader
|
|||
|
* window, don't do it again.
|
|||
|
*/
|
|||
|
|
|||
|
if (!leader_winptr || leader_winptr->tested_for_sm_client_id)
|
|||
|
{
|
|||
|
caught_error = 0;
|
|||
|
XSetErrorHandler (NULL);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
leader_winptr->tested_for_sm_client_id = 1;
|
|||
|
|
|||
|
if (!HasXSMPsupport (leader_winptr->window))
|
|||
|
{
|
|||
|
XFetchName (disp, leader_winptr->window, &leader_winptr->wm_name);
|
|||
|
|
|||
|
XGetCommand (disp, leader_winptr->window,
|
|||
|
&leader_winptr->wm_command,
|
|||
|
&leader_winptr->wm_command_count);
|
|||
|
|
|||
|
XGetClassHint (disp, leader_winptr->window, &leader_winptr->class);
|
|||
|
|
|||
|
XGetWMClientMachine (disp, leader_winptr->window,
|
|||
|
&leader_winptr->wm_client_machine);
|
|||
|
|
|||
|
if (leader_winptr->wm_name != NULL &&
|
|||
|
leader_winptr->wm_command != NULL &&
|
|||
|
leader_winptr->wm_command_count > 0 &&
|
|||
|
leader_winptr->class.res_name != NULL &&
|
|||
|
leader_winptr->class.res_class != NULL &&
|
|||
|
leader_winptr->wm_client_machine.value != NULL &&
|
|||
|
leader_winptr->wm_client_machine.nitems != 0)
|
|||
|
{
|
|||
|
leader_winptr->has_save_yourself =
|
|||
|
HasSaveYourself (leader_winptr->window);
|
|||
|
|
|||
|
ConnectClientToSM (leader_winptr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
XSync (disp, 0);
|
|||
|
XSetErrorHandler (NULL);
|
|||
|
|
|||
|
if (caught_error)
|
|||
|
{
|
|||
|
caught_error = 0;
|
|||
|
RemoveWindow (leader_winptr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
HandleCreate (event)
|
|||
|
|
|||
|
XCreateWindowEvent *event;
|
|||
|
|
|||
|
{
|
|||
|
Atom actual_type;
|
|||
|
int actual_format;
|
|||
|
unsigned long nitems, bytesafter;
|
|||
|
unsigned long *datap = NULL;
|
|||
|
WinInfo *winptr;
|
|||
|
Bool got_wm_state = 0;
|
|||
|
|
|||
|
/*
|
|||
|
* We are waiting for all proxy connections to close so we can die.
|
|||
|
* Don't handle new connections.
|
|||
|
*/
|
|||
|
|
|||
|
if (ok_to_die)
|
|||
|
return;
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Add the new window
|
|||
|
*/
|
|||
|
|
|||
|
if ((winptr = AddNewWindow (event->window)) == NULL)
|
|||
|
return;
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Right after the window was created, it might have been destroyed,
|
|||
|
* so the following Xlib calls might fail. Need to catch the error
|
|||
|
* by installing an error handler.
|
|||
|
*/
|
|||
|
|
|||
|
caught_error = 0;
|
|||
|
XSetErrorHandler (MyErrorHandler);
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Select for Property Notify on the window so we can determine
|
|||
|
* when WM_STATE is defined. To avoid a race condition, we must
|
|||
|
* do this _before_ we check for WM_STATE right now.
|
|||
|
*
|
|||
|
* Select for Substructure Notify so we can determine when the
|
|||
|
* window is destroyed.
|
|||
|
*/
|
|||
|
|
|||
|
XSelectInput (disp, event->window,
|
|||
|
SubstructureNotifyMask | PropertyChangeMask);
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* WM_STATE may already be there. Check now.
|
|||
|
*/
|
|||
|
|
|||
|
if (XGetWindowProperty (disp, event->window, wmStateAtom,
|
|||
|
0L, 2L, False, AnyPropertyType,
|
|||
|
&actual_type, &actual_format, &nitems, &bytesafter,
|
|||
|
(unsigned char **) &datap) == Success && datap)
|
|||
|
{
|
|||
|
if (nitems > 0)
|
|||
|
got_wm_state = 1;
|
|||
|
|
|||
|
if (datap)
|
|||
|
XFree ((char *) datap);
|
|||
|
}
|
|||
|
|
|||
|
XSync (disp, 0);
|
|||
|
XSetErrorHandler (NULL);
|
|||
|
|
|||
|
if (caught_error)
|
|||
|
{
|
|||
|
caught_error = 0;
|
|||
|
RemoveWindow (winptr);
|
|||
|
}
|
|||
|
else if (got_wm_state)
|
|||
|
{
|
|||
|
Got_WM_STATE (winptr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
HandleDestroy (event)
|
|||
|
|
|||
|
XDestroyWindowEvent *event;
|
|||
|
|
|||
|
{
|
|||
|
WinInfo *winptr;
|
|||
|
|
|||
|
if (LookupWindow (event->window, &winptr, NULL))
|
|||
|
{
|
|||
|
if (winptr->smc_conn)
|
|||
|
{
|
|||
|
SmcCloseConnection (winptr->smc_conn, 0, NULL);
|
|||
|
XtRemoveInput (winptr->input_id);
|
|||
|
proxy_count--;
|
|||
|
}
|
|||
|
|
|||
|
if (debug)
|
|||
|
{
|
|||
|
printf ("Removed window (window = 0x%x)\n",
|
|||
|
(unsigned int)winptr->window);
|
|||
|
printf ("\n");
|
|||
|
}
|
|||
|
|
|||
|
RemoveWindow (winptr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
HandleUpdate (event)
|
|||
|
|
|||
|
XPropertyEvent *event;
|
|||
|
|
|||
|
{
|
|||
|
Window window = event->window;
|
|||
|
WinInfo *winptr;
|
|||
|
|
|||
|
if (!LookupWindow (window, &winptr, NULL))
|
|||
|
return;
|
|||
|
|
|||
|
if (event->atom == wmStateAtom)
|
|||
|
{
|
|||
|
Got_WM_STATE (winptr);
|
|||
|
}
|
|||
|
else if (event->atom == XA_WM_COMMAND && winptr->waiting_for_update)
|
|||
|
{
|
|||
|
/* Finish off the Save Yourself */
|
|||
|
|
|||
|
if (winptr->wm_command)
|
|||
|
{
|
|||
|
XFreeStringList (winptr->wm_command);
|
|||
|
winptr->wm_command = NULL;
|
|||
|
winptr->wm_command_count = 0;
|
|||
|
}
|
|||
|
|
|||
|
XGetCommand (disp, window,
|
|||
|
&winptr->wm_command,
|
|||
|
&winptr->wm_command_count);
|
|||
|
|
|||
|
winptr->waiting_for_update = 0;
|
|||
|
FinishSaveYourself (winptr, True);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
ProxySaveYourselfPhase2CB (smcConn, clientData)
|
|||
|
|
|||
|
SmcConn smcConn;
|
|||
|
SmPointer clientData;
|
|||
|
|
|||
|
{
|
|||
|
char *filename;
|
|||
|
Bool success = True;
|
|||
|
SmProp prop1, prop2, prop3, *props[3];
|
|||
|
SmPropValue prop1val, prop2val, prop3val;
|
|||
|
char discardCommand[80];
|
|||
|
int numVals, i;
|
|||
|
static int first_time = 1;
|
|||
|
|
|||
|
if (first_time)
|
|||
|
{
|
|||
|
char userId[20];
|
|||
|
char hint = SmRestartIfRunning;
|
|||
|
|
|||
|
prop1.name = SmProgram;
|
|||
|
prop1.type = SmARRAY8;
|
|||
|
prop1.num_vals = 1;
|
|||
|
prop1.vals = &prop1val;
|
|||
|
prop1val.value = Argv[0];
|
|||
|
prop1val.length = strlen (Argv[0]);
|
|||
|
|
|||
|
sprintf (userId, "%ld", (long)getuid());
|
|||
|
prop2.name = SmUserID;
|
|||
|
prop2.type = SmARRAY8;
|
|||
|
prop2.num_vals = 1;
|
|||
|
prop2.vals = &prop2val;
|
|||
|
prop2val.value = (SmPointer) userId;
|
|||
|
prop2val.length = strlen (userId);
|
|||
|
|
|||
|
prop3.name = SmRestartStyleHint;
|
|||
|
prop3.type = SmCARD8;
|
|||
|
prop3.num_vals = 1;
|
|||
|
prop3.vals = &prop3val;
|
|||
|
prop3val.value = (SmPointer) &hint;
|
|||
|
prop3val.length = 1;
|
|||
|
|
|||
|
props[0] = &prop1;
|
|||
|
props[1] = &prop2;
|
|||
|
props[2] = &prop3;
|
|||
|
|
|||
|
SmcSetProperties (smcConn, 3, props);
|
|||
|
|
|||
|
first_time = 0;
|
|||
|
}
|
|||
|
|
|||
|
if ((filename = WriteProxyFile ()) == NULL)
|
|||
|
{
|
|||
|
success = False;
|
|||
|
goto finishUp;
|
|||
|
}
|
|||
|
|
|||
|
prop1.name = SmRestartCommand;
|
|||
|
prop1.type = SmLISTofARRAY8;
|
|||
|
|
|||
|
prop1.vals = (SmPropValue *) malloc (
|
|||
|
(Argc + 4) * sizeof (SmPropValue));
|
|||
|
|
|||
|
if (!prop1.vals)
|
|||
|
{
|
|||
|
success = False;
|
|||
|
goto finishUp;
|
|||
|
}
|
|||
|
|
|||
|
numVals = 0;
|
|||
|
|
|||
|
for (i = 0; i < Argc; i++)
|
|||
|
{
|
|||
|
if (strcmp (Argv[i], "-clientId") == 0 ||
|
|||
|
strcmp (Argv[i], "-restore") == 0)
|
|||
|
{
|
|||
|
i++;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
prop1.vals[numVals].value = (SmPointer) Argv[i];
|
|||
|
prop1.vals[numVals++].length = strlen (Argv[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
prop1.vals[numVals].value = (SmPointer) "-clientId";
|
|||
|
prop1.vals[numVals++].length = 9;
|
|||
|
|
|||
|
prop1.vals[numVals].value = (SmPointer) proxy_clientId;
|
|||
|
prop1.vals[numVals++].length = strlen (proxy_clientId);
|
|||
|
|
|||
|
prop1.vals[numVals].value = (SmPointer) "-restore";
|
|||
|
prop1.vals[numVals++].length = 8;
|
|||
|
|
|||
|
prop1.vals[numVals].value = (SmPointer) filename;
|
|||
|
prop1.vals[numVals++].length = strlen (filename);
|
|||
|
|
|||
|
prop1.num_vals = numVals;
|
|||
|
|
|||
|
|
|||
|
sprintf (discardCommand, "rm %s", filename);
|
|||
|
prop2.name = SmDiscardCommand;
|
|||
|
prop2.type = SmARRAY8;
|
|||
|
prop2.num_vals = 1;
|
|||
|
prop2.vals = &prop2val;
|
|||
|
prop2val.value = (SmPointer) discardCommand;
|
|||
|
prop2val.length = strlen (discardCommand);
|
|||
|
|
|||
|
props[0] = &prop1;
|
|||
|
props[1] = &prop2;
|
|||
|
|
|||
|
SmcSetProperties (smcConn, 2, props);
|
|||
|
free ((char *) prop1.vals);
|
|||
|
|
|||
|
finishUp:
|
|||
|
|
|||
|
SmcSaveYourselfDone (smcConn, success);
|
|||
|
sent_save_done = 1;
|
|||
|
|
|||
|
if (filename)
|
|||
|
free (filename);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
ProxySaveYourselfCB (smcConn, clientData, saveType,
|
|||
|
shutdown, interactStyle, fast)
|
|||
|
|
|||
|
SmcConn smcConn;
|
|||
|
SmPointer clientData;
|
|||
|
int saveType;
|
|||
|
Bool shutdown;
|
|||
|
int interactStyle;
|
|||
|
Bool fast;
|
|||
|
|
|||
|
{
|
|||
|
/*
|
|||
|
* We want the proxy to respond to the Save Yourself after all
|
|||
|
* the regular XSMP clients have finished with the save (and possibly
|
|||
|
* interacted with the user).
|
|||
|
*/
|
|||
|
|
|||
|
if (!SmcRequestSaveYourselfPhase2 (smcConn,
|
|||
|
ProxySaveYourselfPhase2CB, NULL))
|
|||
|
{
|
|||
|
SmcSaveYourselfDone (smcConn, False);
|
|||
|
sent_save_done = 1;
|
|||
|
}
|
|||
|
else
|
|||
|
sent_save_done = 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
ProxyDieCB (smcConn, clientData)
|
|||
|
|
|||
|
SmcConn smcConn;
|
|||
|
SmPointer clientData;
|
|||
|
|
|||
|
{
|
|||
|
SmcCloseConnection (proxy_smcConn, 0, NULL);
|
|||
|
XtRemoveInput (proxy_iceInputId);
|
|||
|
|
|||
|
if (die_count == proxy_count)
|
|||
|
exit (0);
|
|||
|
else
|
|||
|
ok_to_die = 1;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
ProxySaveCompleteCB (smcConn, clientData)
|
|||
|
|
|||
|
SmcConn smcConn;
|
|||
|
SmPointer clientData;
|
|||
|
|
|||
|
{
|
|||
|
;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
ProxyShutdownCancelledCB (smcConn, clientData)
|
|||
|
|
|||
|
SmcConn smcConn;
|
|||
|
SmPointer clientData;
|
|||
|
|
|||
|
{
|
|||
|
if (!sent_save_done)
|
|||
|
{
|
|||
|
SmcSaveYourselfDone (smcConn, False);
|
|||
|
sent_save_done = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Status
|
|||
|
ConnectProxyToSM (previous_id)
|
|||
|
|
|||
|
char *previous_id;
|
|||
|
|
|||
|
{
|
|||
|
char errorMsg[256];
|
|||
|
unsigned long mask;
|
|||
|
SmcCallbacks callbacks;
|
|||
|
IceConn iceConn;
|
|||
|
|
|||
|
mask = SmcSaveYourselfProcMask | SmcDieProcMask |
|
|||
|
SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
|
|||
|
|
|||
|
callbacks.save_yourself.callback = ProxySaveYourselfCB;
|
|||
|
callbacks.save_yourself.client_data = (SmPointer) NULL;
|
|||
|
|
|||
|
callbacks.die.callback = ProxyDieCB;
|
|||
|
callbacks.die.client_data = (SmPointer) NULL;
|
|||
|
|
|||
|
callbacks.save_complete.callback = ProxySaveCompleteCB;
|
|||
|
callbacks.save_complete.client_data = (SmPointer) NULL;
|
|||
|
|
|||
|
callbacks.shutdown_cancelled.callback = ProxyShutdownCancelledCB;
|
|||
|
callbacks.shutdown_cancelled.client_data = (SmPointer) NULL;
|
|||
|
|
|||
|
proxy_smcConn = SmcOpenConnection (
|
|||
|
NULL, /* use SESSION_MANAGER env */
|
|||
|
(SmPointer) appContext,
|
|||
|
SmProtoMajor,
|
|||
|
SmProtoMinor,
|
|||
|
mask,
|
|||
|
&callbacks,
|
|||
|
previous_id,
|
|||
|
&proxy_clientId,
|
|||
|
256, errorMsg);
|
|||
|
|
|||
|
if (proxy_smcConn == NULL)
|
|||
|
return (0);
|
|||
|
|
|||
|
iceConn = SmcGetIceConnection (proxy_smcConn);
|
|||
|
|
|||
|
proxy_iceInputId = XtAppAddInput (
|
|||
|
appContext,
|
|||
|
IceConnectionNumber (iceConn),
|
|||
|
(XtPointer) XtInputReadMask,
|
|||
|
ProcessIceMsgProc,
|
|||
|
(XtPointer) iceConn);
|
|||
|
|
|||
|
return (1);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
CheckForExistingWindows (root)
|
|||
|
|
|||
|
Window root;
|
|||
|
|
|||
|
{
|
|||
|
Window dontCare1, dontCare2, *children, client_window;
|
|||
|
unsigned int nchildren, i;
|
|||
|
XCreateWindowEvent event;
|
|||
|
|
|||
|
/*
|
|||
|
* We query the root tree for all windows created thus far.
|
|||
|
* Note that at any moment after XQueryTree is called, a
|
|||
|
* window may be deleted. So we must take extra care to make
|
|||
|
* sure a window really exists.
|
|||
|
*/
|
|||
|
|
|||
|
XQueryTree (disp, root, &dontCare1, &dontCare2, &children, &nchildren);
|
|||
|
|
|||
|
for (i = 0; i < nchildren; i++)
|
|||
|
{
|
|||
|
event.window = children[i];
|
|||
|
|
|||
|
HandleCreate (&event);
|
|||
|
|
|||
|
caught_error = 0;
|
|||
|
XSetErrorHandler (MyErrorHandler);
|
|||
|
|
|||
|
client_window = XmuClientWindow (disp, children[i]);
|
|||
|
|
|||
|
XSetErrorHandler (NULL);
|
|||
|
|
|||
|
if (!caught_error && client_window != children[i])
|
|||
|
{
|
|||
|
event.window = client_window;
|
|||
|
HandleCreate (&event);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
main (int argc, char *argv[])
|
|||
|
{
|
|||
|
char *restore_filename = NULL;
|
|||
|
char *client_id = NULL;
|
|||
|
int i, zero = 0;
|
|||
|
|
|||
|
Argc = argc;
|
|||
|
Argv = argv;
|
|||
|
|
|||
|
for (i = 1; i < argc; i++)
|
|||
|
{
|
|||
|
if (argv[i][0] == '-')
|
|||
|
{
|
|||
|
switch (argv[i][1])
|
|||
|
{
|
|||
|
case 'd': /* -debug */
|
|||
|
debug = 1;
|
|||
|
continue;
|
|||
|
|
|||
|
case 'c': /* -clientId */
|
|||
|
if (++i >= argc) goto usage;
|
|||
|
client_id = argv[i];
|
|||
|
continue;
|
|||
|
|
|||
|
case 'r': /* -restore */
|
|||
|
if (++i >= argc) goto usage;
|
|||
|
restore_filename = argv[i];
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
usage:
|
|||
|
|
|||
|
fprintf (stderr,
|
|||
|
"usage: %s [-clientId id] [-restore file] [-debug]\n", argv[0]);
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
XtToolkitInitialize ();
|
|||
|
appContext = XtCreateApplicationContext ();
|
|||
|
|
|||
|
if (!(disp = XtOpenDisplay (appContext, NULL, "SM-PROXY", "SM-PROXY",
|
|||
|
NULL, 0, &zero, NULL)))
|
|||
|
{
|
|||
|
fprintf (stderr, "smproxy: unable to open display\n");
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
|
|||
|
if (restore_filename)
|
|||
|
ReadProxyFile (restore_filename);
|
|||
|
|
|||
|
if (!ConnectProxyToSM (client_id))
|
|||
|
{
|
|||
|
fprintf (stderr, "smproxy: unable to connect to session manager\n");
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
|
|||
|
wmProtocolsAtom = XInternAtom (disp, "WM_PROTOCOLS", False);
|
|||
|
wmSaveYourselfAtom = XInternAtom (disp, "WM_SAVE_YOURSELF", False);
|
|||
|
wmStateAtom = XInternAtom (disp, "WM_STATE", False);
|
|||
|
smClientIdAtom = XInternAtom (disp, "SM_CLIENT_ID", False);
|
|||
|
wmClientLeaderAtom = XInternAtom (disp, "WM_CLIENT_LEADER", False);
|
|||
|
|
|||
|
for (i = 0; i < ScreenCount (disp); i++)
|
|||
|
{
|
|||
|
Window root = RootWindow (disp, i);
|
|||
|
XSelectInput (disp, root, SubstructureNotifyMask | PropertyChangeMask);
|
|||
|
CheckForExistingWindows (root);
|
|||
|
}
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
XEvent event;
|
|||
|
|
|||
|
XtAppNextEvent (appContext, &event);
|
|||
|
|
|||
|
switch (event.type)
|
|||
|
{
|
|||
|
case CreateNotify:
|
|||
|
HandleCreate (&event.xcreatewindow);
|
|||
|
break;
|
|||
|
|
|||
|
case DestroyNotify:
|
|||
|
HandleDestroy (&event.xdestroywindow);
|
|||
|
break;
|
|||
|
|
|||
|
case PropertyNotify:
|
|||
|
HandleUpdate (&event.xproperty);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
XtDispatchEvent (&event);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
exit(0);
|
|||
|
}
|