#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)
{
return (NULL);
}
else if (leader_winptr)
{
return (leader_winptr);
}
else
{
return (winptr);
}
}
char *
CheckFullyQuantifiedName (name, newstring)
char *name;
int *newstring;
{
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);
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;
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);
if (debug)
printf ("Trying to kill 0x%x\n", (unsigned int)winInfo->window);
XSync (disp, 0);
XKillClient (disp, winInfo->window);
XSync (disp, 0);
die_count++;
if (die_count == proxy_count && ok_to_die)
{
exit (0);
}
}
void
SaveCompleteCB (smcConn, clientData)
SmcConn smcConn;
SmPointer clientData;
{
}
void
ShutdownCancelledCB (smcConn, clientData)
SmcConn smcConn;
SmPointer clientData;
{
}
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);
IceSetErrorHandler (NullIceErrorHandler);
winInfo->smc_conn = SmcOpenConnection (
NULL,
(SmPointer) winInfo,
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 (winptr->tested_for_sm_client_id)
{
return;
}
caught_error = 0;
XSetErrorHandler (MyErrorHandler);
leader_winptr = GetClientLeader (winptr);
if (caught_error)
{
caught_error = 0;
RemoveWindow (winptr);
XSetErrorHandler (NULL);
return;
}
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;
if (ok_to_die)
return;
if ((winptr = AddNewWindow (event->window)) == NULL)
return;
caught_error = 0;
XSetErrorHandler (MyErrorHandler);
XSelectInput (disp, event->window,
SubstructureNotifyMask | PropertyChangeMask);
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)
{
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;
{
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,
(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;
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 = 1;
continue;
case 'c':
if (++i >= argc) goto usage;
client_id = argv[i];
continue;
case 'r':
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);
}