smproxy.c revision 24047306
114c0a534Smrg/****************************************************************************** 214c0a534Smrg 314c0a534SmrgCopyright 1994, 1998 The Open Group 414c0a534Smrg 514c0a534SmrgPermission to use, copy, modify, distribute, and sell this software and its 614c0a534Smrgdocumentation for any purpose is hereby granted without fee, provided that 714c0a534Smrgthe above copyright notice appear in all copies and that both that 814c0a534Smrgcopyright notice and this permission notice appear in supporting 914c0a534Smrgdocumentation. 1014c0a534Smrg 1114c0a534SmrgThe above copyright notice and this permission notice shall be included in 1214c0a534Smrgall copies or substantial portions of the Software. 1314c0a534Smrg 1414c0a534SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1514c0a534SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1614c0a534SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1714c0a534SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 1814c0a534SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1914c0a534SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2014c0a534Smrg 2114c0a534SmrgExcept as contained in this notice, the name of The Open Group shall not be 2214c0a534Smrgused in advertising or otherwise to promote the sale, use or other dealings 2314c0a534Smrgin this Software without prior written authorization from The Open Group. 2414c0a534Smrg 2514c0a534SmrgAuthor: Ralph Mor, X Consortium 2614c0a534Smrg******************************************************************************/ 2714c0a534Smrg 2814c0a534Smrg#include "smproxy.h" 2914c0a534Smrg#include <unistd.h> 3014c0a534Smrg#include <X11/Xmu/WinUtil.h> 3114c0a534Smrg 32bf2eeab3Smrgstatic XtAppContext appContext; 33bf2eeab3Smrgstatic Display *disp; 3414c0a534Smrg 35bf2eeab3Smrgstatic Atom wmProtocolsAtom; 36bf2eeab3Smrgstatic Atom wmSaveYourselfAtom; 37bf2eeab3Smrgstatic Atom wmStateAtom; 38bf2eeab3Smrgstatic Atom smClientIdAtom; 39bf2eeab3Smrgstatic Atom wmClientLeaderAtom; 4014c0a534Smrg 41bf2eeab3Smrgstatic Bool debug = 0; 4214c0a534Smrg 43bf2eeab3Smrgstatic SmcConn proxy_smcConn; 44bf2eeab3Smrgstatic XtInputId proxy_iceInputId; 45bf2eeab3Smrgstatic char *proxy_clientId = NULL; 4614c0a534Smrg 4714c0a534SmrgWinInfo *win_head = NULL; 4814c0a534Smrg 49bf2eeab3Smrgstatic int proxy_count = 0; 50bf2eeab3Smrgstatic int die_count = 0; 5114c0a534Smrg 52bf2eeab3Smrgstatic Bool ok_to_die = 0; 5314c0a534Smrg 54bf2eeab3Smrgstatic Bool caught_error = 0; 5514c0a534Smrg 56bf2eeab3Smrgstatic Bool sent_save_done = 0; 5714c0a534Smrg 58bf2eeab3Smrgstatic int Argc; 59bf2eeab3Smrgstatic char **Argv; 6014c0a534Smrg 61bf2eeab3Smrgstatic Bool HasSaveYourself ( Window window ); 62bf2eeab3Smrgstatic Bool HasXSMPsupport ( Window window ); 63bf2eeab3Smrgstatic WinInfo * GetClientLeader ( WinInfo *winptr ); 64bf2eeab3Smrgstatic char * CheckFullyQuantifiedName ( char *name, int *newstring ); 65bf2eeab3Smrgstatic void FinishSaveYourself ( WinInfo *winInfo, Bool has_WM_SAVEYOURSELF ); 66bf2eeab3Smrgstatic void SaveYourselfCB ( SmcConn smcConn, SmPointer clientData, int saveType, 67bf2eeab3Smrg Bool shutdown, int interactStyle, Bool fast ); 68bf2eeab3Smrgstatic void DieCB ( SmcConn smcConn, SmPointer clientData ); 69bf2eeab3Smrgstatic void SaveCompleteCB ( SmcConn smcConn, SmPointer clientData ); 70bf2eeab3Smrgstatic void ShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData ); 71bf2eeab3Smrgstatic void ProcessIceMsgProc ( XtPointer client_data, int *source, XtInputId *id ); 72bf2eeab3Smrgstatic void NullIceErrorHandler ( IceConn iceConn, Bool swap, 7314c0a534Smrg int offendingMinorOpCode, 7414c0a534Smrg unsigned long offendingSequence, 7514c0a534Smrg int errorClass, int severity, IcePointer values ); 76bf2eeab3Smrgstatic void ConnectClientToSM ( WinInfo *winInfo ); 77bf2eeab3Smrgstatic int MyErrorHandler ( Display *display, XErrorEvent *event ); 78bf2eeab3Smrgstatic Bool LookupWindow ( Window window, WinInfo **ptr_ret, WinInfo **prev_ptr_ret ); 79bf2eeab3Smrgstatic WinInfo * AddNewWindow ( Window window ); 80bf2eeab3Smrgstatic void RemoveWindow ( WinInfo *winptr ); 81bf2eeab3Smrgstatic void Got_WM_STATE ( WinInfo *winptr ); 82bf2eeab3Smrgstatic void HandleCreate ( XCreateWindowEvent *event ); 83bf2eeab3Smrgstatic void HandleDestroy ( XDestroyWindowEvent *event ); 84bf2eeab3Smrgstatic void HandleUpdate ( XPropertyEvent *event ); 85bf2eeab3Smrgstatic void ProxySaveYourselfPhase2CB ( SmcConn smcConn, SmPointer clientData ); 86bf2eeab3Smrgstatic void ProxySaveYourselfCB ( SmcConn smcConn, SmPointer clientData, 8714c0a534Smrg int saveType, Bool shutdown, int interactStyle, 8814c0a534Smrg Bool fast ); 89bf2eeab3Smrgstatic void ProxyDieCB ( SmcConn smcConn, SmPointer clientData ); 90bf2eeab3Smrgstatic void ProxySaveCompleteCB ( SmcConn smcConn, SmPointer clientData ); 91bf2eeab3Smrgstatic void ProxyShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData ); 92bf2eeab3Smrgstatic Status ConnectProxyToSM ( char *previous_id ); 93bf2eeab3Smrgstatic void CheckForExistingWindows ( Window root ); 9414c0a534Smrg 9514c0a534Smrg 96bf2eeab3Smrgstatic Bool 97bf2eeab3SmrgHasSaveYourself(Window window) 9814c0a534Smrg{ 9914c0a534Smrg Atom *protocols; 10014c0a534Smrg int numProtocols; 10114c0a534Smrg int i, found; 10214c0a534Smrg 10314c0a534Smrg protocols = NULL; 10414c0a534Smrg 10514c0a534Smrg if (XGetWMProtocols (disp, window, &protocols, &numProtocols) != True) 10614c0a534Smrg return (False); 10714c0a534Smrg 10814c0a534Smrg found = 0; 10914c0a534Smrg 11014c0a534Smrg if (protocols != NULL) 11114c0a534Smrg { 11214c0a534Smrg for (i = 0; i < numProtocols; i++) 11314c0a534Smrg if (protocols[i] == wmSaveYourselfAtom) 11414c0a534Smrg found = 1; 11514c0a534Smrg 11614c0a534Smrg XFree (protocols); 11714c0a534Smrg } 11814c0a534Smrg 11914c0a534Smrg return (found); 12014c0a534Smrg} 12114c0a534Smrg 12214c0a534Smrg 12314c0a534Smrg 124bf2eeab3Smrgstatic Bool 125bf2eeab3SmrgHasXSMPsupport(Window window) 12614c0a534Smrg{ 12714c0a534Smrg XTextProperty tp; 12814c0a534Smrg Bool hasIt = 0; 12914c0a534Smrg 13014c0a534Smrg if (XGetTextProperty (disp, window, &tp, smClientIdAtom)) 13114c0a534Smrg { 13214c0a534Smrg if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0) 13314c0a534Smrg hasIt = 1; 13414c0a534Smrg 13514c0a534Smrg if (tp.value) 13614c0a534Smrg XFree ((char *) tp.value); 13714c0a534Smrg } 13814c0a534Smrg 13914c0a534Smrg return (hasIt); 14014c0a534Smrg} 14114c0a534Smrg 14214c0a534Smrg 14314c0a534Smrg 144bf2eeab3Smrgstatic WinInfo * 145bf2eeab3SmrgGetClientLeader(WinInfo *winptr) 14614c0a534Smrg{ 14714c0a534Smrg Atom actual_type; 14814c0a534Smrg int actual_format; 14914c0a534Smrg unsigned long nitems, bytesafter; 15014c0a534Smrg unsigned long *datap = NULL; 15114c0a534Smrg WinInfo *leader_winptr = NULL; 15214c0a534Smrg Bool failure = 0; 15314c0a534Smrg 15414c0a534Smrg if (XGetWindowProperty (disp, winptr->window, wmClientLeaderAtom, 15514c0a534Smrg 0L, 1L, False, AnyPropertyType, &actual_type, &actual_format, 15614c0a534Smrg &nitems, &bytesafter, (unsigned char **) &datap) == Success) 15714c0a534Smrg { 15814c0a534Smrg if (actual_type == XA_WINDOW && actual_format == 32 && 15914c0a534Smrg nitems == 1 && bytesafter == 0) 16014c0a534Smrg { 16114c0a534Smrg Window leader_win = *((Window *) datap); 16214c0a534Smrg 16314c0a534Smrg if (!LookupWindow (leader_win, &leader_winptr, NULL)) 16414c0a534Smrg failure = 1; 16514c0a534Smrg } 16614c0a534Smrg 16714c0a534Smrg if (datap) 16814c0a534Smrg XFree (datap); 16914c0a534Smrg } 17014c0a534Smrg 17114c0a534Smrg if (failure) 17214c0a534Smrg { 17314c0a534Smrg /* The client leader was defined, but we couldn't find the window */ 17414c0a534Smrg 17514c0a534Smrg return (NULL); 17614c0a534Smrg } 17714c0a534Smrg else if (leader_winptr) 17814c0a534Smrg { 17914c0a534Smrg /* We found the real client leader */ 18014c0a534Smrg 18114c0a534Smrg return (leader_winptr); 18214c0a534Smrg } 18314c0a534Smrg else 18414c0a534Smrg { 18514c0a534Smrg /* There is no client leader defined, return this window */ 18614c0a534Smrg 18714c0a534Smrg return (winptr); 18814c0a534Smrg } 18914c0a534Smrg} 19014c0a534Smrg 19114c0a534Smrg 19214c0a534Smrg 193bf2eeab3Smrgstatic char * 194bf2eeab3SmrgCheckFullyQuantifiedName(char *name, int *newstring) 19514c0a534Smrg{ 19614c0a534Smrg /* 19714c0a534Smrg * Due to a bug in Xlib (for hpux in particular), some clients 19814c0a534Smrg * will have a WM_CLIENT_MACHINE that is not fully quantified. 19914c0a534Smrg * For example, we might get "excon" instead of "excon.x.org". 20014c0a534Smrg * This really stinks. The best we can do is tag on our own 20114c0a534Smrg * domain name. 20214c0a534Smrg */ 20314c0a534Smrg 20414c0a534Smrg if (strchr (name, '.') != NULL) 20514c0a534Smrg { 20614c0a534Smrg *newstring = 0; 20714c0a534Smrg return (name); 20814c0a534Smrg } 20914c0a534Smrg else 21014c0a534Smrg { 21114c0a534Smrg char hostnamebuf[80]; 21214c0a534Smrg char *firstDot; 21314c0a534Smrg 21414c0a534Smrg gethostname (hostnamebuf, sizeof hostnamebuf); 21514c0a534Smrg firstDot = strchr (hostnamebuf, '.'); 21614c0a534Smrg 21714c0a534Smrg if (!firstDot) 21814c0a534Smrg { 21914c0a534Smrg *newstring = 0; 22014c0a534Smrg return (name); 22114c0a534Smrg } 22214c0a534Smrg else 22314c0a534Smrg { 22414c0a534Smrg char *newptr; 22514c0a534Smrg 22624047306Smrg if (asprintf (&newptr, "%s.%s", name, firstDot + 1) == -1) { 22724047306Smrg *newstring = 0; 22824047306Smrg return NULL; 22924047306Smrg } 23014c0a534Smrg *newstring = 1; 23114c0a534Smrg return (newptr); 23214c0a534Smrg } 23314c0a534Smrg } 23414c0a534Smrg} 23514c0a534Smrg 23614c0a534Smrg 23714c0a534Smrg 238bf2eeab3Smrgstatic void 239bf2eeab3SmrgFinishSaveYourself(WinInfo *winInfo, Bool has_WM_SAVEYOURSELF) 24014c0a534Smrg{ 24114c0a534Smrg SmProp prop1, prop2, prop3, *props[3]; 24214c0a534Smrg SmPropValue prop1val, prop2val, prop3val; 24314c0a534Smrg int i; 24414c0a534Smrg 24514c0a534Smrg if (!winInfo->got_first_save_yourself) 24614c0a534Smrg { 24714c0a534Smrg char userId[20], restartService[80]; 24814c0a534Smrg char *fullyQuantifiedName; 24914c0a534Smrg int newstring; 25014c0a534Smrg 25114c0a534Smrg prop1.name = SmProgram; 25214c0a534Smrg prop1.type = SmARRAY8; 25314c0a534Smrg prop1.num_vals = 1; 25414c0a534Smrg prop1.vals = &prop1val; 25514c0a534Smrg prop1val.value = (SmPointer) winInfo->wm_command[0]; 25614c0a534Smrg prop1val.length = strlen (winInfo->wm_command[0]); 25714c0a534Smrg 25824047306Smrg snprintf (userId, sizeof(userId), "%ld", (long)getuid()); 25914c0a534Smrg prop2.name = SmUserID; 26014c0a534Smrg prop2.type = SmARRAY8; 26114c0a534Smrg prop2.num_vals = 1; 26214c0a534Smrg prop2.vals = &prop2val; 26314c0a534Smrg prop2val.value = (SmPointer) userId; 26414c0a534Smrg prop2val.length = strlen (userId); 26514c0a534Smrg 26614c0a534Smrg fullyQuantifiedName = CheckFullyQuantifiedName ( 26714c0a534Smrg (char *) winInfo->wm_client_machine.value, &newstring); 26824047306Smrg snprintf (restartService, sizeof(restartService), 26924047306Smrg "rstart-rsh/%s", fullyQuantifiedName); 27014c0a534Smrg if (newstring) 27114c0a534Smrg free (fullyQuantifiedName); 27214c0a534Smrg 27314c0a534Smrg prop3.name = "_XC_RestartService"; 27414c0a534Smrg prop3.type = SmLISTofARRAY8; 27514c0a534Smrg prop3.num_vals = 1; 27614c0a534Smrg prop3.vals = &prop3val; 27714c0a534Smrg prop3val.value = (SmPointer) restartService; 27814c0a534Smrg prop3val.length = strlen (restartService); 27914c0a534Smrg 28014c0a534Smrg props[0] = &prop1; 28114c0a534Smrg props[1] = &prop2; 28214c0a534Smrg props[2] = &prop3; 28314c0a534Smrg 28414c0a534Smrg SmcSetProperties (winInfo->smc_conn, 3, props); 28514c0a534Smrg 28614c0a534Smrg winInfo->got_first_save_yourself = 1; 28714c0a534Smrg } 28814c0a534Smrg 28914c0a534Smrg prop1.name = SmRestartCommand; 29014c0a534Smrg prop1.type = SmLISTofARRAY8; 29114c0a534Smrg prop1.num_vals = winInfo->wm_command_count; 29214c0a534Smrg 29314c0a534Smrg prop1.vals = (SmPropValue *) malloc ( 29414c0a534Smrg winInfo->wm_command_count * sizeof (SmPropValue)); 29514c0a534Smrg 29614c0a534Smrg if (!prop1.vals) 29714c0a534Smrg { 29814c0a534Smrg SmcSaveYourselfDone (winInfo->smc_conn, False); 29914c0a534Smrg return; 30014c0a534Smrg } 30114c0a534Smrg 30214c0a534Smrg for (i = 0; i < winInfo->wm_command_count; i++) 30314c0a534Smrg { 30414c0a534Smrg prop1.vals[i].value = (SmPointer) winInfo->wm_command[i]; 30514c0a534Smrg prop1.vals[i].length = strlen (winInfo->wm_command[i]); 30614c0a534Smrg } 30714c0a534Smrg 30814c0a534Smrg prop2.name = SmCloneCommand; 30914c0a534Smrg prop2.type = SmLISTofARRAY8; 31014c0a534Smrg prop2.num_vals = winInfo->wm_command_count; 31114c0a534Smrg prop2.vals = prop1.vals; 31214c0a534Smrg 31314c0a534Smrg props[0] = &prop1; 31414c0a534Smrg props[1] = &prop2; 31514c0a534Smrg 31614c0a534Smrg SmcSetProperties (winInfo->smc_conn, 2, props); 31714c0a534Smrg 31814c0a534Smrg free ((char *) prop1.vals); 31914c0a534Smrg 32014c0a534Smrg /* 32114c0a534Smrg * If the client doesn't support WM_SAVE_YOURSELF, we should 32214c0a534Smrg * return failure for the save, since we really don't know if 32314c0a534Smrg * the application needed to save state. 32414c0a534Smrg */ 32514c0a534Smrg 32614c0a534Smrg SmcSaveYourselfDone (winInfo->smc_conn, has_WM_SAVEYOURSELF); 32714c0a534Smrg} 32814c0a534Smrg 32914c0a534Smrg 33014c0a534Smrg 331bf2eeab3Smrgstatic void 332bf2eeab3SmrgSaveYourselfCB(SmcConn smcConn, SmPointer clientData, int saveType, 333bf2eeab3Smrg Bool shutdown, int interactStyle, Bool fast) 33414c0a534Smrg{ 33514c0a534Smrg WinInfo *winInfo = (WinInfo *) clientData; 33614c0a534Smrg 33714c0a534Smrg if (!winInfo->has_save_yourself) 33814c0a534Smrg { 33914c0a534Smrg FinishSaveYourself (winInfo, False); 34014c0a534Smrg } 34114c0a534Smrg else 34214c0a534Smrg { 34314c0a534Smrg XClientMessageEvent saveYourselfMessage; 34414c0a534Smrg 34514c0a534Smrg 34614c0a534Smrg /* Send WM_SAVE_YOURSELF */ 34714c0a534Smrg 34814c0a534Smrg saveYourselfMessage.type = ClientMessage; 34914c0a534Smrg saveYourselfMessage.window = winInfo->window; 35014c0a534Smrg saveYourselfMessage.message_type = wmProtocolsAtom; 35114c0a534Smrg saveYourselfMessage.format = 32; 35214c0a534Smrg saveYourselfMessage.data.l[0] = wmSaveYourselfAtom; 35314c0a534Smrg saveYourselfMessage.data.l[1] = CurrentTime; 35414c0a534Smrg 35514c0a534Smrg if (XSendEvent (disp, winInfo->window, False, NoEventMask, 35614c0a534Smrg (XEvent *) &saveYourselfMessage)) 35714c0a534Smrg { 35814c0a534Smrg winInfo->waiting_for_update = 1; 35914c0a534Smrg 36014c0a534Smrg if (debug) 36114c0a534Smrg { 36214c0a534Smrg printf ("Sent SAVE YOURSELF to 0x%x\n", 36314c0a534Smrg (unsigned int)winInfo->window); 36414c0a534Smrg printf ("\n"); 36514c0a534Smrg } 36614c0a534Smrg } 36714c0a534Smrg else 36814c0a534Smrg { 36914c0a534Smrg if (debug) 37014c0a534Smrg { 37114c0a534Smrg printf ("Failed to send SAVE YOURSELF to 0x%x\n", 37214c0a534Smrg (unsigned int)winInfo->window); 37314c0a534Smrg printf ("\n"); 37414c0a534Smrg } 37514c0a534Smrg } 37614c0a534Smrg } 37714c0a534Smrg} 37814c0a534Smrg 37914c0a534Smrg 38014c0a534Smrg 381bf2eeab3Smrgstatic void 382bf2eeab3SmrgDieCB(SmcConn smcConn, SmPointer clientData) 38314c0a534Smrg{ 38414c0a534Smrg WinInfo *winInfo = (WinInfo *) clientData; 38514c0a534Smrg 38614c0a534Smrg SmcCloseConnection (winInfo->smc_conn, 0, NULL); 38714c0a534Smrg winInfo->smc_conn = NULL; 38814c0a534Smrg XtRemoveInput (winInfo->input_id); 38914c0a534Smrg 39014c0a534Smrg /* Now tell the client to die */ 39114c0a534Smrg 39214c0a534Smrg if (debug) 39314c0a534Smrg printf ("Trying to kill 0x%x\n", (unsigned int)winInfo->window); 39414c0a534Smrg 39514c0a534Smrg XSync (disp, 0); 39614c0a534Smrg XKillClient (disp, winInfo->window); 39714c0a534Smrg XSync (disp, 0); 39814c0a534Smrg 39914c0a534Smrg 40014c0a534Smrg /* 40114c0a534Smrg * Proxy must exit when all clients die, and the proxy itself 40214c0a534Smrg * must have received a Die. 40314c0a534Smrg */ 40414c0a534Smrg 40514c0a534Smrg die_count++; 40614c0a534Smrg 40714c0a534Smrg if (die_count == proxy_count && ok_to_die) 40814c0a534Smrg { 40914c0a534Smrg exit (0); 41014c0a534Smrg } 41114c0a534Smrg} 41214c0a534Smrg 41314c0a534Smrg 41414c0a534Smrg 415bf2eeab3Smrgstatic void 416bf2eeab3SmrgSaveCompleteCB(SmcConn smcConn, SmPointer clientData) 41714c0a534Smrg{ 41814c0a534Smrg /* 41914c0a534Smrg * Nothing to do here. 42014c0a534Smrg */ 42114c0a534Smrg} 42214c0a534Smrg 42314c0a534Smrg 42414c0a534Smrg 425bf2eeab3Smrgstatic void 426bf2eeab3SmrgShutdownCancelledCB(SmcConn smcConn, SmPointer clientData) 42714c0a534Smrg{ 42814c0a534Smrg /* 42914c0a534Smrg * Since we did not request to interact or request save yourself 43014c0a534Smrg * phase 2, we know we already sent the save yourself done, so 43114c0a534Smrg * there is nothing to do here. 43214c0a534Smrg */ 43314c0a534Smrg} 43414c0a534Smrg 43514c0a534Smrg 43614c0a534Smrg 437bf2eeab3Smrgstatic void 438bf2eeab3SmrgProcessIceMsgProc(XtPointer client_data, int *source, XtInputId *id) 43914c0a534Smrg{ 44014c0a534Smrg IceConn ice_conn = (IceConn) client_data; 44114c0a534Smrg 44214c0a534Smrg IceProcessMessages (ice_conn, NULL, NULL); 44314c0a534Smrg} 44414c0a534Smrg 44514c0a534Smrg 44614c0a534Smrg 447bf2eeab3Smrgstatic void 448bf2eeab3SmrgNullIceErrorHandler(IceConn iceConn, Bool swap, int offendingMinorOpcode, 449bf2eeab3Smrg unsigned long offendingSequence, int errorClass, 450bf2eeab3Smrg int severity, IcePointer values) 45114c0a534Smrg{ 45214c0a534Smrg return; 45314c0a534Smrg} 45414c0a534Smrg 45514c0a534Smrg 456bf2eeab3Smrgstatic void 457bf2eeab3SmrgConnectClientToSM(WinInfo *winInfo) 45814c0a534Smrg{ 45914c0a534Smrg char errorMsg[256]; 46014c0a534Smrg unsigned long mask; 46114c0a534Smrg SmcCallbacks callbacks; 46214c0a534Smrg IceConn ice_conn; 46314c0a534Smrg char *prevId; 46414c0a534Smrg 46514c0a534Smrg mask = SmcSaveYourselfProcMask | SmcDieProcMask | 46614c0a534Smrg SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; 46714c0a534Smrg 46814c0a534Smrg callbacks.save_yourself.callback = SaveYourselfCB; 46914c0a534Smrg callbacks.save_yourself.client_data = (SmPointer) winInfo; 47014c0a534Smrg 47114c0a534Smrg callbacks.die.callback = DieCB; 47214c0a534Smrg callbacks.die.client_data = (SmPointer) winInfo; 47314c0a534Smrg 47414c0a534Smrg callbacks.save_complete.callback = SaveCompleteCB; 47514c0a534Smrg callbacks.save_complete.client_data = (SmPointer) winInfo; 47614c0a534Smrg 47714c0a534Smrg callbacks.shutdown_cancelled.callback = ShutdownCancelledCB; 47814c0a534Smrg callbacks.shutdown_cancelled.client_data = (SmPointer) winInfo; 47914c0a534Smrg 48014c0a534Smrg prevId = LookupClientID (winInfo); 48114c0a534Smrg 48214c0a534Smrg /* 48314c0a534Smrg * In case a protocol error occurs when opening the connection, 48414c0a534Smrg * (e.g. an authentication error), we set a null error handler 48514c0a534Smrg * before the open, then restore the default handler after the open. 48614c0a534Smrg */ 48714c0a534Smrg 48814c0a534Smrg IceSetErrorHandler (NullIceErrorHandler); 48914c0a534Smrg 49014c0a534Smrg winInfo->smc_conn = SmcOpenConnection ( 49114c0a534Smrg NULL, /* use SESSION_MANAGER env */ 49214c0a534Smrg (SmPointer) winInfo, /* force a new connection */ 49314c0a534Smrg SmProtoMajor, 49414c0a534Smrg SmProtoMinor, 49514c0a534Smrg mask, 49614c0a534Smrg &callbacks, 49714c0a534Smrg prevId, 49814c0a534Smrg &winInfo->client_id, 49914c0a534Smrg 256, errorMsg); 50014c0a534Smrg 50114c0a534Smrg IceSetErrorHandler (NULL); 50214c0a534Smrg 50314c0a534Smrg if (winInfo->smc_conn == NULL) 50414c0a534Smrg return; 50514c0a534Smrg 50614c0a534Smrg ice_conn = SmcGetIceConnection (winInfo->smc_conn); 50714c0a534Smrg 50814c0a534Smrg winInfo->input_id = XtAppAddInput ( 50914c0a534Smrg appContext, 51014c0a534Smrg IceConnectionNumber (ice_conn), 51114c0a534Smrg (XtPointer) XtInputReadMask, 51214c0a534Smrg ProcessIceMsgProc, 51314c0a534Smrg (XtPointer) ice_conn); 51414c0a534Smrg 51514c0a534Smrg if (debug) 51614c0a534Smrg { 51714c0a534Smrg printf ("Connected to SM, window = 0x%x\n", 51814c0a534Smrg (unsigned int)winInfo->window); 51914c0a534Smrg printf ("\n"); 52014c0a534Smrg } 52114c0a534Smrg 52214c0a534Smrg proxy_count++; 52314c0a534Smrg} 52414c0a534Smrg 52514c0a534Smrg 52614c0a534Smrg 527bf2eeab3Smrgstatic int 528bf2eeab3SmrgMyErrorHandler(Display *display, XErrorEvent *event) 52914c0a534Smrg{ 53014c0a534Smrg caught_error = 1; 53114c0a534Smrg return 0; 53214c0a534Smrg} 53314c0a534Smrg 53414c0a534Smrg 53514c0a534Smrg 536bf2eeab3Smrgstatic Bool 537bf2eeab3SmrgLookupWindow(Window window, WinInfo **ptr_ret, WinInfo **prev_ptr_ret) 53814c0a534Smrg{ 53914c0a534Smrg WinInfo *ptr, *prev; 54014c0a534Smrg 54114c0a534Smrg ptr = win_head; 54214c0a534Smrg prev = NULL; 54314c0a534Smrg 54414c0a534Smrg while (ptr) 54514c0a534Smrg { 54614c0a534Smrg if (ptr->window == window) 54714c0a534Smrg break; 54814c0a534Smrg else 54914c0a534Smrg { 55014c0a534Smrg prev = ptr; 55114c0a534Smrg ptr = ptr->next; 55214c0a534Smrg } 55314c0a534Smrg } 55414c0a534Smrg 55514c0a534Smrg if (ptr) 55614c0a534Smrg { 55714c0a534Smrg if (ptr_ret) 55814c0a534Smrg *ptr_ret = ptr; 55914c0a534Smrg if (prev_ptr_ret) 56014c0a534Smrg *prev_ptr_ret = prev; 56114c0a534Smrg return (1); 56214c0a534Smrg } 56314c0a534Smrg else 56414c0a534Smrg return (0); 56514c0a534Smrg} 56614c0a534Smrg 56714c0a534Smrg 56814c0a534Smrg 569bf2eeab3Smrgstatic WinInfo * 570bf2eeab3SmrgAddNewWindow(Window window) 57114c0a534Smrg{ 57214c0a534Smrg WinInfo *newptr; 57314c0a534Smrg 57414c0a534Smrg if (LookupWindow (window, NULL, NULL)) 57514c0a534Smrg return (NULL); 57614c0a534Smrg 57714c0a534Smrg newptr = (WinInfo *) malloc (sizeof (WinInfo)); 57814c0a534Smrg 57914c0a534Smrg if (newptr == NULL) 58014c0a534Smrg return (NULL); 58114c0a534Smrg 58214c0a534Smrg newptr->next = win_head; 58314c0a534Smrg win_head = newptr; 58414c0a534Smrg 58514c0a534Smrg newptr->window = window; 58614c0a534Smrg newptr->smc_conn = NULL; 58714c0a534Smrg newptr->tested_for_sm_client_id = 0; 58814c0a534Smrg newptr->client_id = NULL; 58914c0a534Smrg newptr->wm_command = NULL; 59014c0a534Smrg newptr->wm_command_count = 0; 59114c0a534Smrg newptr->class.res_name = NULL; 59214c0a534Smrg newptr->class.res_class = NULL; 59314c0a534Smrg newptr->wm_name = NULL; 59414c0a534Smrg newptr->wm_client_machine.value = NULL; 59514c0a534Smrg newptr->wm_client_machine.nitems = 0; 59614c0a534Smrg newptr->has_save_yourself = 0; 59714c0a534Smrg newptr->waiting_for_update = 0; 59814c0a534Smrg newptr->got_first_save_yourself = 0; 59914c0a534Smrg 60014c0a534Smrg return (newptr); 60114c0a534Smrg} 60214c0a534Smrg 60314c0a534Smrg 60414c0a534Smrg 605bf2eeab3Smrgstatic void 606bf2eeab3SmrgRemoveWindow(WinInfo *winptr) 60714c0a534Smrg{ 60814c0a534Smrg WinInfo *ptr, *prev; 60914c0a534Smrg 61014c0a534Smrg if (LookupWindow (winptr->window, &ptr, &prev)) 61114c0a534Smrg { 61214c0a534Smrg if (prev == NULL) 61314c0a534Smrg win_head = ptr->next; 61414c0a534Smrg else 61514c0a534Smrg prev->next = ptr->next; 61614c0a534Smrg 61714c0a534Smrg if (ptr->client_id) 61814c0a534Smrg free (ptr->client_id); 61914c0a534Smrg 62014c0a534Smrg if (ptr->wm_command) 62114c0a534Smrg XFreeStringList (ptr->wm_command); 62214c0a534Smrg 62314c0a534Smrg if (ptr->wm_name) 62414c0a534Smrg XFree (ptr->wm_name); 62514c0a534Smrg 62614c0a534Smrg if (ptr->wm_client_machine.value) 62714c0a534Smrg XFree (ptr->wm_client_machine.value); 62814c0a534Smrg 62914c0a534Smrg if (ptr->class.res_name) 63014c0a534Smrg XFree (ptr->class.res_name); 63114c0a534Smrg 63214c0a534Smrg if (ptr->class.res_class) 63314c0a534Smrg XFree (ptr->class.res_class); 63414c0a534Smrg 63514c0a534Smrg free ((char *) ptr); 63614c0a534Smrg } 63714c0a534Smrg} 63814c0a534Smrg 63914c0a534Smrg 64014c0a534Smrg 641bf2eeab3Smrgstatic void 642bf2eeab3SmrgGot_WM_STATE(WinInfo *winptr) 64314c0a534Smrg{ 64414c0a534Smrg WinInfo *leader_winptr; 64514c0a534Smrg 64614c0a534Smrg /* 64714c0a534Smrg * If we already got WM_STATE and tested for SM_CLIENT_ID, we 64814c0a534Smrg * shouldn't do it again. 64914c0a534Smrg */ 65014c0a534Smrg 65114c0a534Smrg if (winptr->tested_for_sm_client_id) 65214c0a534Smrg { 65314c0a534Smrg return; 65414c0a534Smrg } 65514c0a534Smrg 65614c0a534Smrg 65714c0a534Smrg /* 65814c0a534Smrg * Set a null error handler, in case this window goes away 65914c0a534Smrg * behind our back. 66014c0a534Smrg */ 66114c0a534Smrg 66214c0a534Smrg caught_error = 0; 66314c0a534Smrg XSetErrorHandler (MyErrorHandler); 66414c0a534Smrg 66514c0a534Smrg 66614c0a534Smrg /* 66714c0a534Smrg * Get the client leader window. 66814c0a534Smrg */ 66914c0a534Smrg 67014c0a534Smrg leader_winptr = GetClientLeader (winptr); 67114c0a534Smrg 67214c0a534Smrg if (caught_error) 67314c0a534Smrg { 67414c0a534Smrg caught_error = 0; 67514c0a534Smrg RemoveWindow (winptr); 67614c0a534Smrg XSetErrorHandler (NULL); 67714c0a534Smrg return; 67814c0a534Smrg } 67914c0a534Smrg 68014c0a534Smrg 68114c0a534Smrg /* 68214c0a534Smrg * If we already checked for SM_CLIENT_ID on the client leader 68314c0a534Smrg * window, don't do it again. 68414c0a534Smrg */ 68514c0a534Smrg 68614c0a534Smrg if (!leader_winptr || leader_winptr->tested_for_sm_client_id) 68714c0a534Smrg { 68814c0a534Smrg caught_error = 0; 68914c0a534Smrg XSetErrorHandler (NULL); 69014c0a534Smrg return; 69114c0a534Smrg } 69214c0a534Smrg 69314c0a534Smrg leader_winptr->tested_for_sm_client_id = 1; 69414c0a534Smrg 69514c0a534Smrg if (!HasXSMPsupport (leader_winptr->window)) 69614c0a534Smrg { 69714c0a534Smrg XFetchName (disp, leader_winptr->window, &leader_winptr->wm_name); 69814c0a534Smrg 69914c0a534Smrg XGetCommand (disp, leader_winptr->window, 70014c0a534Smrg &leader_winptr->wm_command, 70114c0a534Smrg &leader_winptr->wm_command_count); 70214c0a534Smrg 70314c0a534Smrg XGetClassHint (disp, leader_winptr->window, &leader_winptr->class); 70414c0a534Smrg 70514c0a534Smrg XGetWMClientMachine (disp, leader_winptr->window, 70614c0a534Smrg &leader_winptr->wm_client_machine); 70714c0a534Smrg 70814c0a534Smrg if (leader_winptr->wm_name != NULL && 70914c0a534Smrg leader_winptr->wm_command != NULL && 71014c0a534Smrg leader_winptr->wm_command_count > 0 && 71114c0a534Smrg leader_winptr->class.res_name != NULL && 71214c0a534Smrg leader_winptr->class.res_class != NULL && 71314c0a534Smrg leader_winptr->wm_client_machine.value != NULL && 71414c0a534Smrg leader_winptr->wm_client_machine.nitems != 0) 71514c0a534Smrg { 71614c0a534Smrg leader_winptr->has_save_yourself = 71714c0a534Smrg HasSaveYourself (leader_winptr->window); 71814c0a534Smrg 71914c0a534Smrg ConnectClientToSM (leader_winptr); 72014c0a534Smrg } 72114c0a534Smrg } 72214c0a534Smrg 72314c0a534Smrg XSync (disp, 0); 72414c0a534Smrg XSetErrorHandler (NULL); 72514c0a534Smrg 72614c0a534Smrg if (caught_error) 72714c0a534Smrg { 72814c0a534Smrg caught_error = 0; 72914c0a534Smrg RemoveWindow (leader_winptr); 73014c0a534Smrg } 73114c0a534Smrg} 73214c0a534Smrg 73314c0a534Smrg 73414c0a534Smrg 735bf2eeab3Smrgstatic void 736bf2eeab3SmrgHandleCreate(XCreateWindowEvent *event) 73714c0a534Smrg{ 73814c0a534Smrg Atom actual_type; 73914c0a534Smrg int actual_format; 74014c0a534Smrg unsigned long nitems, bytesafter; 74114c0a534Smrg unsigned long *datap = NULL; 74214c0a534Smrg WinInfo *winptr; 74314c0a534Smrg Bool got_wm_state = 0; 74414c0a534Smrg 74514c0a534Smrg /* 74614c0a534Smrg * We are waiting for all proxy connections to close so we can die. 74714c0a534Smrg * Don't handle new connections. 74814c0a534Smrg */ 74914c0a534Smrg 75014c0a534Smrg if (ok_to_die) 75114c0a534Smrg return; 75214c0a534Smrg 75314c0a534Smrg 75414c0a534Smrg /* 75514c0a534Smrg * Add the new window 75614c0a534Smrg */ 75714c0a534Smrg 75814c0a534Smrg if ((winptr = AddNewWindow (event->window)) == NULL) 75914c0a534Smrg return; 76014c0a534Smrg 76114c0a534Smrg 76214c0a534Smrg /* 76314c0a534Smrg * Right after the window was created, it might have been destroyed, 76414c0a534Smrg * so the following Xlib calls might fail. Need to catch the error 76514c0a534Smrg * by installing an error handler. 76614c0a534Smrg */ 76714c0a534Smrg 76814c0a534Smrg caught_error = 0; 76914c0a534Smrg XSetErrorHandler (MyErrorHandler); 77014c0a534Smrg 77114c0a534Smrg 77214c0a534Smrg /* 77314c0a534Smrg * Select for Property Notify on the window so we can determine 77414c0a534Smrg * when WM_STATE is defined. To avoid a race condition, we must 77514c0a534Smrg * do this _before_ we check for WM_STATE right now. 77614c0a534Smrg * 77714c0a534Smrg * Select for Substructure Notify so we can determine when the 77814c0a534Smrg * window is destroyed. 77914c0a534Smrg */ 78014c0a534Smrg 78114c0a534Smrg XSelectInput (disp, event->window, 78214c0a534Smrg SubstructureNotifyMask | PropertyChangeMask); 78314c0a534Smrg 78414c0a534Smrg 78514c0a534Smrg /* 78614c0a534Smrg * WM_STATE may already be there. Check now. 78714c0a534Smrg */ 78814c0a534Smrg 78914c0a534Smrg if (XGetWindowProperty (disp, event->window, wmStateAtom, 79014c0a534Smrg 0L, 2L, False, AnyPropertyType, 79114c0a534Smrg &actual_type, &actual_format, &nitems, &bytesafter, 79214c0a534Smrg (unsigned char **) &datap) == Success && datap) 79314c0a534Smrg { 79414c0a534Smrg if (nitems > 0) 79514c0a534Smrg got_wm_state = 1; 79614c0a534Smrg 79714c0a534Smrg if (datap) 79814c0a534Smrg XFree ((char *) datap); 79914c0a534Smrg } 80014c0a534Smrg 80114c0a534Smrg XSync (disp, 0); 80214c0a534Smrg XSetErrorHandler (NULL); 80314c0a534Smrg 80414c0a534Smrg if (caught_error) 80514c0a534Smrg { 80614c0a534Smrg caught_error = 0; 80714c0a534Smrg RemoveWindow (winptr); 80814c0a534Smrg } 80914c0a534Smrg else if (got_wm_state) 81014c0a534Smrg { 81114c0a534Smrg Got_WM_STATE (winptr); 81214c0a534Smrg } 81314c0a534Smrg} 81414c0a534Smrg 81514c0a534Smrg 81614c0a534Smrg 817bf2eeab3Smrgstatic void 818bf2eeab3SmrgHandleDestroy(XDestroyWindowEvent *event) 81914c0a534Smrg{ 82014c0a534Smrg WinInfo *winptr; 82114c0a534Smrg 82214c0a534Smrg if (LookupWindow (event->window, &winptr, NULL)) 82314c0a534Smrg { 82414c0a534Smrg if (winptr->smc_conn) 82514c0a534Smrg { 82614c0a534Smrg SmcCloseConnection (winptr->smc_conn, 0, NULL); 82714c0a534Smrg XtRemoveInput (winptr->input_id); 82814c0a534Smrg proxy_count--; 82914c0a534Smrg } 83014c0a534Smrg 83114c0a534Smrg if (debug) 83214c0a534Smrg { 83314c0a534Smrg printf ("Removed window (window = 0x%x)\n", 83414c0a534Smrg (unsigned int)winptr->window); 83514c0a534Smrg printf ("\n"); 83614c0a534Smrg } 83714c0a534Smrg 83814c0a534Smrg RemoveWindow (winptr); 83914c0a534Smrg } 84014c0a534Smrg} 84114c0a534Smrg 84214c0a534Smrg 84314c0a534Smrg 844bf2eeab3Smrgstatic void 845bf2eeab3SmrgHandleUpdate(XPropertyEvent *event) 84614c0a534Smrg{ 84714c0a534Smrg Window window = event->window; 84814c0a534Smrg WinInfo *winptr; 84914c0a534Smrg 85014c0a534Smrg if (!LookupWindow (window, &winptr, NULL)) 85114c0a534Smrg return; 85214c0a534Smrg 85314c0a534Smrg if (event->atom == wmStateAtom) 85414c0a534Smrg { 85514c0a534Smrg Got_WM_STATE (winptr); 85614c0a534Smrg } 85714c0a534Smrg else if (event->atom == XA_WM_COMMAND && winptr->waiting_for_update) 85814c0a534Smrg { 85914c0a534Smrg /* Finish off the Save Yourself */ 86014c0a534Smrg 86114c0a534Smrg if (winptr->wm_command) 86214c0a534Smrg { 86314c0a534Smrg XFreeStringList (winptr->wm_command); 86414c0a534Smrg winptr->wm_command = NULL; 86514c0a534Smrg winptr->wm_command_count = 0; 86614c0a534Smrg } 86714c0a534Smrg 86814c0a534Smrg XGetCommand (disp, window, 86914c0a534Smrg &winptr->wm_command, 87014c0a534Smrg &winptr->wm_command_count); 87114c0a534Smrg 87214c0a534Smrg winptr->waiting_for_update = 0; 87314c0a534Smrg FinishSaveYourself (winptr, True); 87414c0a534Smrg } 87514c0a534Smrg} 87614c0a534Smrg 87714c0a534Smrg 87814c0a534Smrg 879bf2eeab3Smrgstatic void 880bf2eeab3SmrgProxySaveYourselfPhase2CB(SmcConn smcConn, SmPointer clientData) 88114c0a534Smrg{ 88214c0a534Smrg char *filename; 88314c0a534Smrg Bool success = True; 88414c0a534Smrg SmProp prop1, prop2, prop3, *props[3]; 88514c0a534Smrg SmPropValue prop1val, prop2val, prop3val; 88624047306Smrg char *discardCommand; 88714c0a534Smrg int numVals, i; 88814c0a534Smrg static int first_time = 1; 88914c0a534Smrg 89014c0a534Smrg if (first_time) 89114c0a534Smrg { 89214c0a534Smrg char userId[20]; 89314c0a534Smrg char hint = SmRestartIfRunning; 89414c0a534Smrg 89514c0a534Smrg prop1.name = SmProgram; 89614c0a534Smrg prop1.type = SmARRAY8; 89714c0a534Smrg prop1.num_vals = 1; 89814c0a534Smrg prop1.vals = &prop1val; 89914c0a534Smrg prop1val.value = Argv[0]; 90014c0a534Smrg prop1val.length = strlen (Argv[0]); 90114c0a534Smrg 90224047306Smrg snprintf (userId, sizeof(userId), "%ld", (long)getuid()); 90314c0a534Smrg prop2.name = SmUserID; 90414c0a534Smrg prop2.type = SmARRAY8; 90514c0a534Smrg prop2.num_vals = 1; 90614c0a534Smrg prop2.vals = &prop2val; 90714c0a534Smrg prop2val.value = (SmPointer) userId; 90814c0a534Smrg prop2val.length = strlen (userId); 90914c0a534Smrg 91014c0a534Smrg prop3.name = SmRestartStyleHint; 91114c0a534Smrg prop3.type = SmCARD8; 91214c0a534Smrg prop3.num_vals = 1; 91314c0a534Smrg prop3.vals = &prop3val; 91414c0a534Smrg prop3val.value = (SmPointer) &hint; 91514c0a534Smrg prop3val.length = 1; 91614c0a534Smrg 91714c0a534Smrg props[0] = &prop1; 91814c0a534Smrg props[1] = &prop2; 91914c0a534Smrg props[2] = &prop3; 92014c0a534Smrg 92114c0a534Smrg SmcSetProperties (smcConn, 3, props); 92214c0a534Smrg 92314c0a534Smrg first_time = 0; 92414c0a534Smrg } 92514c0a534Smrg 92614c0a534Smrg if ((filename = WriteProxyFile ()) == NULL) 92714c0a534Smrg { 92814c0a534Smrg success = False; 92914c0a534Smrg goto finishUp; 93014c0a534Smrg } 93114c0a534Smrg 93214c0a534Smrg prop1.name = SmRestartCommand; 93314c0a534Smrg prop1.type = SmLISTofARRAY8; 93414c0a534Smrg 93514c0a534Smrg prop1.vals = (SmPropValue *) malloc ( 93614c0a534Smrg (Argc + 4) * sizeof (SmPropValue)); 93714c0a534Smrg 93814c0a534Smrg if (!prop1.vals) 93914c0a534Smrg { 94014c0a534Smrg success = False; 94114c0a534Smrg goto finishUp; 94214c0a534Smrg } 94314c0a534Smrg 94414c0a534Smrg numVals = 0; 94514c0a534Smrg 94614c0a534Smrg for (i = 0; i < Argc; i++) 94714c0a534Smrg { 94814c0a534Smrg if (strcmp (Argv[i], "-clientId") == 0 || 94914c0a534Smrg strcmp (Argv[i], "-restore") == 0) 95014c0a534Smrg { 95114c0a534Smrg i++; 95214c0a534Smrg } 95314c0a534Smrg else 95414c0a534Smrg { 95514c0a534Smrg prop1.vals[numVals].value = (SmPointer) Argv[i]; 95614c0a534Smrg prop1.vals[numVals++].length = strlen (Argv[i]); 95714c0a534Smrg } 95814c0a534Smrg } 95914c0a534Smrg 96014c0a534Smrg prop1.vals[numVals].value = (SmPointer) "-clientId"; 96114c0a534Smrg prop1.vals[numVals++].length = 9; 96214c0a534Smrg 96314c0a534Smrg prop1.vals[numVals].value = (SmPointer) proxy_clientId; 96414c0a534Smrg prop1.vals[numVals++].length = strlen (proxy_clientId); 96514c0a534Smrg 96614c0a534Smrg prop1.vals[numVals].value = (SmPointer) "-restore"; 96714c0a534Smrg prop1.vals[numVals++].length = 8; 96814c0a534Smrg 96914c0a534Smrg prop1.vals[numVals].value = (SmPointer) filename; 97014c0a534Smrg prop1.vals[numVals++].length = strlen (filename); 97114c0a534Smrg 97214c0a534Smrg prop1.num_vals = numVals; 97314c0a534Smrg 97414c0a534Smrg 97524047306Smrg if (asprintf (&discardCommand, "rm %s", filename) == -1) { 97624047306Smrg success = False; 97724047306Smrg goto finishUp; 97824047306Smrg } 97914c0a534Smrg prop2.name = SmDiscardCommand; 98014c0a534Smrg prop2.type = SmARRAY8; 98114c0a534Smrg prop2.num_vals = 1; 98214c0a534Smrg prop2.vals = &prop2val; 98314c0a534Smrg prop2val.value = (SmPointer) discardCommand; 98414c0a534Smrg prop2val.length = strlen (discardCommand); 98514c0a534Smrg 98614c0a534Smrg props[0] = &prop1; 98714c0a534Smrg props[1] = &prop2; 98814c0a534Smrg 98914c0a534Smrg SmcSetProperties (smcConn, 2, props); 99014c0a534Smrg free ((char *) prop1.vals); 99124047306Smrg free (discardCommand); 99214c0a534Smrg 99314c0a534Smrg finishUp: 99414c0a534Smrg 99514c0a534Smrg SmcSaveYourselfDone (smcConn, success); 99614c0a534Smrg sent_save_done = 1; 99714c0a534Smrg 99814c0a534Smrg if (filename) 99914c0a534Smrg free (filename); 100014c0a534Smrg} 100114c0a534Smrg 100214c0a534Smrg 100314c0a534Smrg 1004bf2eeab3Smrgstatic void 1005bf2eeab3SmrgProxySaveYourselfCB(SmcConn smcConn, SmPointer clientData, int saveType, 1006bf2eeab3Smrg Bool shutdown, int interactStyle, Bool fast) 100714c0a534Smrg{ 100814c0a534Smrg /* 100914c0a534Smrg * We want the proxy to respond to the Save Yourself after all 101014c0a534Smrg * the regular XSMP clients have finished with the save (and possibly 101114c0a534Smrg * interacted with the user). 101214c0a534Smrg */ 101314c0a534Smrg 101414c0a534Smrg if (!SmcRequestSaveYourselfPhase2 (smcConn, 101514c0a534Smrg ProxySaveYourselfPhase2CB, NULL)) 101614c0a534Smrg { 101714c0a534Smrg SmcSaveYourselfDone (smcConn, False); 101814c0a534Smrg sent_save_done = 1; 101914c0a534Smrg } 102014c0a534Smrg else 102114c0a534Smrg sent_save_done = 0; 102214c0a534Smrg} 102314c0a534Smrg 102414c0a534Smrg 102514c0a534Smrg 1026bf2eeab3Smrgstatic void 1027bf2eeab3SmrgProxyDieCB(SmcConn smcConn, SmPointer clientData) 102814c0a534Smrg{ 102914c0a534Smrg SmcCloseConnection (proxy_smcConn, 0, NULL); 103014c0a534Smrg XtRemoveInput (proxy_iceInputId); 103114c0a534Smrg 103214c0a534Smrg if (die_count == proxy_count) 103314c0a534Smrg exit (0); 103414c0a534Smrg else 103514c0a534Smrg ok_to_die = 1; 103614c0a534Smrg} 103714c0a534Smrg 103814c0a534Smrg 103914c0a534Smrg 1040bf2eeab3Smrgstatic void 1041bf2eeab3SmrgProxySaveCompleteCB(SmcConn smcConn, SmPointer clientData) 104214c0a534Smrg{ 104314c0a534Smrg ; 104414c0a534Smrg} 104514c0a534Smrg 104614c0a534Smrg 104714c0a534Smrg 1048bf2eeab3Smrgstatic void 1049bf2eeab3SmrgProxyShutdownCancelledCB(SmcConn smcConn, SmPointer clientData) 105014c0a534Smrg{ 105114c0a534Smrg if (!sent_save_done) 105214c0a534Smrg { 105314c0a534Smrg SmcSaveYourselfDone (smcConn, False); 105414c0a534Smrg sent_save_done = 1; 105514c0a534Smrg } 105614c0a534Smrg} 105714c0a534Smrg 105814c0a534Smrg 105914c0a534Smrg 1060bf2eeab3Smrgstatic Status 1061bf2eeab3SmrgConnectProxyToSM(char *previous_id) 106214c0a534Smrg{ 106314c0a534Smrg char errorMsg[256]; 106414c0a534Smrg unsigned long mask; 106514c0a534Smrg SmcCallbacks callbacks; 106614c0a534Smrg IceConn iceConn; 106714c0a534Smrg 106814c0a534Smrg mask = SmcSaveYourselfProcMask | SmcDieProcMask | 106914c0a534Smrg SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; 107014c0a534Smrg 107114c0a534Smrg callbacks.save_yourself.callback = ProxySaveYourselfCB; 107214c0a534Smrg callbacks.save_yourself.client_data = (SmPointer) NULL; 107314c0a534Smrg 107414c0a534Smrg callbacks.die.callback = ProxyDieCB; 107514c0a534Smrg callbacks.die.client_data = (SmPointer) NULL; 107614c0a534Smrg 107714c0a534Smrg callbacks.save_complete.callback = ProxySaveCompleteCB; 107814c0a534Smrg callbacks.save_complete.client_data = (SmPointer) NULL; 107914c0a534Smrg 108014c0a534Smrg callbacks.shutdown_cancelled.callback = ProxyShutdownCancelledCB; 108114c0a534Smrg callbacks.shutdown_cancelled.client_data = (SmPointer) NULL; 108214c0a534Smrg 108314c0a534Smrg proxy_smcConn = SmcOpenConnection ( 108414c0a534Smrg NULL, /* use SESSION_MANAGER env */ 108514c0a534Smrg (SmPointer) appContext, 108614c0a534Smrg SmProtoMajor, 108714c0a534Smrg SmProtoMinor, 108814c0a534Smrg mask, 108914c0a534Smrg &callbacks, 109014c0a534Smrg previous_id, 109114c0a534Smrg &proxy_clientId, 109214c0a534Smrg 256, errorMsg); 109314c0a534Smrg 109414c0a534Smrg if (proxy_smcConn == NULL) 109514c0a534Smrg return (0); 109614c0a534Smrg 109714c0a534Smrg iceConn = SmcGetIceConnection (proxy_smcConn); 109814c0a534Smrg 109914c0a534Smrg proxy_iceInputId = XtAppAddInput ( 110014c0a534Smrg appContext, 110114c0a534Smrg IceConnectionNumber (iceConn), 110214c0a534Smrg (XtPointer) XtInputReadMask, 110314c0a534Smrg ProcessIceMsgProc, 110414c0a534Smrg (XtPointer) iceConn); 110514c0a534Smrg 110614c0a534Smrg return (1); 110714c0a534Smrg} 110814c0a534Smrg 110914c0a534Smrg 111014c0a534Smrg 1111bf2eeab3Smrgstatic void 1112bf2eeab3SmrgCheckForExistingWindows(Window root) 111314c0a534Smrg{ 111414c0a534Smrg Window dontCare1, dontCare2, *children, client_window; 111514c0a534Smrg unsigned int nchildren, i; 111614c0a534Smrg XCreateWindowEvent event; 111714c0a534Smrg 111814c0a534Smrg /* 111914c0a534Smrg * We query the root tree for all windows created thus far. 112014c0a534Smrg * Note that at any moment after XQueryTree is called, a 112114c0a534Smrg * window may be deleted. So we must take extra care to make 112214c0a534Smrg * sure a window really exists. 112314c0a534Smrg */ 112414c0a534Smrg 112514c0a534Smrg XQueryTree (disp, root, &dontCare1, &dontCare2, &children, &nchildren); 112614c0a534Smrg 112714c0a534Smrg for (i = 0; i < nchildren; i++) 112814c0a534Smrg { 112914c0a534Smrg event.window = children[i]; 113014c0a534Smrg 113114c0a534Smrg HandleCreate (&event); 113214c0a534Smrg 113314c0a534Smrg caught_error = 0; 113414c0a534Smrg XSetErrorHandler (MyErrorHandler); 113514c0a534Smrg 113614c0a534Smrg client_window = XmuClientWindow (disp, children[i]); 113714c0a534Smrg 113814c0a534Smrg XSetErrorHandler (NULL); 113914c0a534Smrg 114014c0a534Smrg if (!caught_error && client_window != children[i]) 114114c0a534Smrg { 114214c0a534Smrg event.window = client_window; 114314c0a534Smrg HandleCreate (&event); 114414c0a534Smrg } 114514c0a534Smrg } 114614c0a534Smrg} 114714c0a534Smrg 114814c0a534Smrg 114914c0a534Smrg 115014c0a534Smrgint 115114c0a534Smrgmain (int argc, char *argv[]) 115214c0a534Smrg{ 115314c0a534Smrg char *restore_filename = NULL; 115414c0a534Smrg char *client_id = NULL; 115514c0a534Smrg int i, zero = 0; 115614c0a534Smrg 115714c0a534Smrg Argc = argc; 115814c0a534Smrg Argv = argv; 115914c0a534Smrg 116014c0a534Smrg for (i = 1; i < argc; i++) 116114c0a534Smrg { 116214c0a534Smrg if (argv[i][0] == '-') 116314c0a534Smrg { 116414c0a534Smrg switch (argv[i][1]) 116514c0a534Smrg { 116614c0a534Smrg case 'd': /* -debug */ 116714c0a534Smrg debug = 1; 116814c0a534Smrg continue; 116914c0a534Smrg 117014c0a534Smrg case 'c': /* -clientId */ 117124047306Smrg if (++i >= argc) { 117224047306Smrg fprintf (stderr, "%s: -clientId requires an argument\n", 117324047306Smrg argv[0]); 117424047306Smrg goto usage; 117524047306Smrg } 117614c0a534Smrg client_id = argv[i]; 117714c0a534Smrg continue; 117814c0a534Smrg 117914c0a534Smrg case 'r': /* -restore */ 118024047306Smrg if (++i >= argc) { 118124047306Smrg fprintf (stderr, "%s: -restore requires an argument\n", 118224047306Smrg argv[0]); 118324047306Smrg goto usage; 118424047306Smrg } 118514c0a534Smrg restore_filename = argv[i]; 118614c0a534Smrg continue; 118724047306Smrg 118824047306Smrg case 'v': 118924047306Smrg puts (PACKAGE_STRING); 119024047306Smrg exit (0); 119114c0a534Smrg } 119214c0a534Smrg } 119314c0a534Smrg 119424047306Smrg fprintf (stderr, "%s: unrecognized argument: %s\n", argv[0], argv[i]); 119524047306Smrg 119614c0a534Smrg usage: 119714c0a534Smrg 119814c0a534Smrg fprintf (stderr, 119924047306Smrg "usage: %s [-clientId id] [-restore file] [-debug] [-version]\n", 120024047306Smrg argv[0]); 120114c0a534Smrg exit (1); 120214c0a534Smrg } 120314c0a534Smrg 120414c0a534Smrg 120514c0a534Smrg XtToolkitInitialize (); 120614c0a534Smrg appContext = XtCreateApplicationContext (); 120714c0a534Smrg 120814c0a534Smrg if (!(disp = XtOpenDisplay (appContext, NULL, "SM-PROXY", "SM-PROXY", 120914c0a534Smrg NULL, 0, &zero, NULL))) 121014c0a534Smrg { 121114c0a534Smrg fprintf (stderr, "smproxy: unable to open display\n"); 121214c0a534Smrg exit (1); 121314c0a534Smrg } 121414c0a534Smrg 121514c0a534Smrg if (restore_filename) 121614c0a534Smrg ReadProxyFile (restore_filename); 121714c0a534Smrg 121814c0a534Smrg if (!ConnectProxyToSM (client_id)) 121914c0a534Smrg { 122014c0a534Smrg fprintf (stderr, "smproxy: unable to connect to session manager\n"); 122114c0a534Smrg exit (1); 122214c0a534Smrg } 122314c0a534Smrg 122414c0a534Smrg wmProtocolsAtom = XInternAtom (disp, "WM_PROTOCOLS", False); 122514c0a534Smrg wmSaveYourselfAtom = XInternAtom (disp, "WM_SAVE_YOURSELF", False); 122614c0a534Smrg wmStateAtom = XInternAtom (disp, "WM_STATE", False); 122714c0a534Smrg smClientIdAtom = XInternAtom (disp, "SM_CLIENT_ID", False); 122814c0a534Smrg wmClientLeaderAtom = XInternAtom (disp, "WM_CLIENT_LEADER", False); 122914c0a534Smrg 123014c0a534Smrg for (i = 0; i < ScreenCount (disp); i++) 123114c0a534Smrg { 123214c0a534Smrg Window root = RootWindow (disp, i); 123314c0a534Smrg XSelectInput (disp, root, SubstructureNotifyMask | PropertyChangeMask); 123414c0a534Smrg CheckForExistingWindows (root); 123514c0a534Smrg } 123614c0a534Smrg 123714c0a534Smrg while (1) 123814c0a534Smrg { 123914c0a534Smrg XEvent event; 124014c0a534Smrg 124114c0a534Smrg XtAppNextEvent (appContext, &event); 124214c0a534Smrg 124314c0a534Smrg switch (event.type) 124414c0a534Smrg { 124514c0a534Smrg case CreateNotify: 124614c0a534Smrg HandleCreate (&event.xcreatewindow); 124714c0a534Smrg break; 124814c0a534Smrg 124914c0a534Smrg case DestroyNotify: 125014c0a534Smrg HandleDestroy (&event.xdestroywindow); 125114c0a534Smrg break; 125214c0a534Smrg 125314c0a534Smrg case PropertyNotify: 125414c0a534Smrg HandleUpdate (&event.xproperty); 125514c0a534Smrg break; 125614c0a534Smrg 125714c0a534Smrg default: 125814c0a534Smrg XtDispatchEvent (&event); 125914c0a534Smrg break; 126014c0a534Smrg } 126114c0a534Smrg } 126214c0a534Smrg exit(0); 126314c0a534Smrg} 1264