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