| File: | smproxy.c |
| Location: | line 976, column 12 |
| Description: | Potential leak of memory pointed to by 'prop1.vals' |
| 1 | /****************************************************************************** | |||||
| 2 | ||||||
| 3 | Copyright 1994, 1998 The Open Group | |||||
| 4 | ||||||
| 5 | Permission to use, copy, modify, distribute, and sell this software and its | |||||
| 6 | documentation for any purpose is hereby granted without fee, provided that | |||||
| 7 | the above copyright notice appear in all copies and that both that | |||||
| 8 | copyright notice and this permission notice appear in supporting | |||||
| 9 | documentation. | |||||
| 10 | ||||||
| 11 | The above copyright notice and this permission notice shall be included in | |||||
| 12 | all copies or substantial portions of the Software. | |||||
| 13 | ||||||
| 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| 17 | OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | |||||
| 18 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||||
| 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||||
| 20 | ||||||
| 21 | Except as contained in this notice, the name of The Open Group shall not be | |||||
| 22 | used in advertising or otherwise to promote the sale, use or other dealings | |||||
| 23 | in this Software without prior written authorization from The Open Group. | |||||
| 24 | ||||||
| 25 | Author: Ralph Mor, X Consortium | |||||
| 26 | ******************************************************************************/ | |||||
| 27 | ||||||
| 28 | #include "smproxy.h" | |||||
| 29 | #include <unistd.h> | |||||
| 30 | #include <X11/Xmu/WinUtil.h> | |||||
| 31 | ||||||
| 32 | static XtAppContext appContext; | |||||
| 33 | static Display *disp; | |||||
| 34 | ||||||
| 35 | static Atom wmProtocolsAtom; | |||||
| 36 | static Atom wmSaveYourselfAtom; | |||||
| 37 | static Atom wmStateAtom; | |||||
| 38 | static Atom smClientIdAtom; | |||||
| 39 | static Atom wmClientLeaderAtom; | |||||
| 40 | ||||||
| 41 | static Boolint debug = 0; | |||||
| 42 | ||||||
| 43 | static SmcConn proxy_smcConn; | |||||
| 44 | static XtInputId proxy_iceInputId; | |||||
| 45 | static char *proxy_clientId = NULL((void*)0); | |||||
| 46 | ||||||
| 47 | WinInfo *win_head = NULL((void*)0); | |||||
| 48 | ||||||
| 49 | static int proxy_count = 0; | |||||
| 50 | static int die_count = 0; | |||||
| 51 | ||||||
| 52 | static Boolint ok_to_die = 0; | |||||
| 53 | ||||||
| 54 | static Boolint caught_error = 0; | |||||
| 55 | ||||||
| 56 | static Boolint sent_save_done = 0; | |||||
| 57 | ||||||
| 58 | static int Argc; | |||||
| 59 | static char **Argv; | |||||
| 60 | ||||||
| 61 | static Boolint HasSaveYourself ( Window window ); | |||||
| 62 | static Boolint HasXSMPsupport ( Window window ); | |||||
| 63 | static WinInfo * GetClientLeader ( WinInfo *winptr ); | |||||
| 64 | static char * CheckFullyQuantifiedName ( char *name, int *newstring ); | |||||
| 65 | static void FinishSaveYourself ( WinInfo *winInfo, Boolint has_WM_SAVEYOURSELF ); | |||||
| 66 | static void SaveYourselfCB ( SmcConn smcConn, SmPointer clientData, int saveType, | |||||
| 67 | Boolint shutdown, int interactStyle, Boolint fast ); | |||||
| 68 | static void DieCB ( SmcConn smcConn, SmPointer clientData ); | |||||
| 69 | static void SaveCompleteCB ( SmcConn smcConn, SmPointer clientData ); | |||||
| 70 | static void ShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData ); | |||||
| 71 | static void ProcessIceMsgProc ( XtPointer client_data, int *source, XtInputId *id ); | |||||
| 72 | static void NullIceErrorHandler ( IceConn iceConn, Boolint swap, | |||||
| 73 | int offendingMinorOpCode, | |||||
| 74 | unsigned long offendingSequence, | |||||
| 75 | int errorClass, int severity, IcePointer values ); | |||||
| 76 | static void ConnectClientToSM ( WinInfo *winInfo ); | |||||
| 77 | static int MyErrorHandler ( Display *display, XErrorEvent *event ); | |||||
| 78 | static Boolint LookupWindow ( Window window, WinInfo **ptr_ret, WinInfo **prev_ptr_ret ); | |||||
| 79 | static WinInfo * AddNewWindow ( Window window ); | |||||
| 80 | static void RemoveWindow ( WinInfo *winptr ); | |||||
| 81 | static void Got_WM_STATE ( WinInfo *winptr ); | |||||
| 82 | static void HandleCreate ( XCreateWindowEvent *event ); | |||||
| 83 | static void HandleDestroy ( XDestroyWindowEvent *event ); | |||||
| 84 | static void HandleUpdate ( XPropertyEvent *event ); | |||||
| 85 | static void ProxySaveYourselfPhase2CB ( SmcConn smcConn, SmPointer clientData ); | |||||
| 86 | static void ProxySaveYourselfCB ( SmcConn smcConn, SmPointer clientData, | |||||
| 87 | int saveType, Boolint shutdown, int interactStyle, | |||||
| 88 | Boolint fast ); | |||||
| 89 | static void ProxyDieCB ( SmcConn smcConn, SmPointer clientData ); | |||||
| 90 | static void ProxySaveCompleteCB ( SmcConn smcConn, SmPointer clientData ); | |||||
| 91 | static void ProxyShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData ); | |||||
| 92 | static Statusint ConnectProxyToSM ( char *previous_id ); | |||||
| 93 | static void CheckForExistingWindows ( Window root ); | |||||
| 94 | ||||||
| 95 | ||||||
| 96 | static Boolint | |||||
| 97 | HasSaveYourself(Window window) | |||||
| 98 | { | |||||
| 99 | Atom *protocols; | |||||
| 100 | int numProtocols; | |||||
| 101 | int i, found; | |||||
| 102 | ||||||
| 103 | protocols = NULL((void*)0); | |||||
| 104 | ||||||
| 105 | if (XGetWMProtocols (disp, window, &protocols, &numProtocols) != True1) | |||||
| 106 | return (False0); | |||||
| 107 | ||||||
| 108 | found = 0; | |||||
| 109 | ||||||
| 110 | if (protocols != NULL((void*)0)) | |||||
| 111 | { | |||||
| 112 | for (i = 0; i < numProtocols; i++) | |||||
| 113 | if (protocols[i] == wmSaveYourselfAtom) | |||||
| 114 | found = 1; | |||||
| 115 | ||||||
| 116 | XFree (protocols); | |||||
| 117 | } | |||||
| 118 | ||||||
| 119 | return (found); | |||||
| 120 | } | |||||
| 121 | ||||||
| 122 | ||||||
| 123 | ||||||
| 124 | static Boolint | |||||
| 125 | HasXSMPsupport(Window window) | |||||
| 126 | { | |||||
| 127 | XTextProperty tp; | |||||
| 128 | Boolint hasIt = 0; | |||||
| 129 | ||||||
| 130 | if (XGetTextProperty (disp, window, &tp, smClientIdAtom)) | |||||
| 131 | { | |||||
| 132 | if (tp.encoding == XA_STRING((Atom) 31) && tp.format == 8 && tp.nitems != 0) | |||||
| 133 | hasIt = 1; | |||||
| 134 | ||||||
| 135 | if (tp.value) | |||||
| 136 | XFree ((char *) tp.value); | |||||
| 137 | } | |||||
| 138 | ||||||
| 139 | return (hasIt); | |||||
| 140 | } | |||||
| 141 | ||||||
| 142 | ||||||
| 143 | ||||||
| 144 | static WinInfo * | |||||
| 145 | GetClientLeader(WinInfo *winptr) | |||||
| 146 | { | |||||
| 147 | Atom actual_type; | |||||
| 148 | int actual_format; | |||||
| 149 | unsigned long nitems, bytesafter; | |||||
| 150 | unsigned long *datap = NULL((void*)0); | |||||
| 151 | WinInfo *leader_winptr = NULL((void*)0); | |||||
| 152 | Boolint failure = 0; | |||||
| 153 | ||||||
| 154 | if (XGetWindowProperty (disp, winptr->window, wmClientLeaderAtom, | |||||
| 155 | 0L, 1L, False0, AnyPropertyType0L, &actual_type, &actual_format, | |||||
| 156 | &nitems, &bytesafter, (unsigned char **) &datap) == Success0) | |||||
| 157 | { | |||||
| 158 | if (actual_type == XA_WINDOW((Atom) 33) && actual_format == 32 && | |||||
| 159 | nitems == 1 && bytesafter == 0) | |||||
| 160 | { | |||||
| 161 | Window leader_win = *((Window *) datap); | |||||
| 162 | ||||||
| 163 | if (!LookupWindow (leader_win, &leader_winptr, NULL((void*)0))) | |||||
| 164 | failure = 1; | |||||
| 165 | } | |||||
| 166 | ||||||
| 167 | if (datap) | |||||
| 168 | XFree (datap); | |||||
| 169 | } | |||||
| 170 | ||||||
| 171 | if (failure) | |||||
| 172 | { | |||||
| 173 | /* The client leader was defined, but we couldn't find the window */ | |||||
| 174 | ||||||
| 175 | return (NULL((void*)0)); | |||||
| 176 | } | |||||
| 177 | else if (leader_winptr) | |||||
| 178 | { | |||||
| 179 | /* We found the real client leader */ | |||||
| 180 | ||||||
| 181 | return (leader_winptr); | |||||
| 182 | } | |||||
| 183 | else | |||||
| 184 | { | |||||
| 185 | /* There is no client leader defined, return this window */ | |||||
| 186 | ||||||
| 187 | return (winptr); | |||||
| 188 | } | |||||
| 189 | } | |||||
| 190 | ||||||
| 191 | ||||||
| 192 | ||||||
| 193 | static char * | |||||
| 194 | CheckFullyQuantifiedName(char *name, int *newstring) | |||||
| 195 | { | |||||
| 196 | /* | |||||
| 197 | * Due to a bug in Xlib (for hpux in particular), some clients | |||||
| 198 | * will have a WM_CLIENT_MACHINE that is not fully quantified. | |||||
| 199 | * For example, we might get "excon" instead of "excon.x.org". | |||||
| 200 | * This really stinks. The best we can do is tag on our own | |||||
| 201 | * domain name. | |||||
| 202 | */ | |||||
| 203 | ||||||
| 204 | if (strchr (name, '.') != NULL((void*)0)) | |||||
| 205 | { | |||||
| 206 | *newstring = 0; | |||||
| 207 | return (name); | |||||
| 208 | } | |||||
| 209 | else | |||||
| 210 | { | |||||
| 211 | char hostnamebuf[80]; | |||||
| 212 | char *firstDot; | |||||
| 213 | ||||||
| 214 | gethostname (hostnamebuf, sizeof hostnamebuf); | |||||
| 215 | firstDot = strchr (hostnamebuf, '.'); | |||||
| 216 | ||||||
| 217 | if (!firstDot) | |||||
| 218 | { | |||||
| 219 | *newstring = 0; | |||||
| 220 | return (name); | |||||
| 221 | } | |||||
| 222 | else | |||||
| 223 | { | |||||
| 224 | char *newptr; | |||||
| 225 | ||||||
| 226 | if (asprintf (&newptr, "%s.%s", name, firstDot + 1) == -1) { | |||||
| 227 | *newstring = 0; | |||||
| 228 | return NULL((void*)0); | |||||
| 229 | } | |||||
| 230 | *newstring = 1; | |||||
| 231 | return (newptr); | |||||
| 232 | } | |||||
| 233 | } | |||||
| 234 | } | |||||
| 235 | ||||||
| 236 | ||||||
| 237 | ||||||
| 238 | static void | |||||
| 239 | FinishSaveYourself(WinInfo *winInfo, Boolint has_WM_SAVEYOURSELF) | |||||
| 240 | { | |||||
| 241 | SmProp prop1, prop2, prop3, *props[3]; | |||||
| 242 | SmPropValue prop1val, prop2val, prop3val; | |||||
| 243 | int i; | |||||
| 244 | ||||||
| 245 | if (!winInfo->got_first_save_yourself) | |||||
| 246 | { | |||||
| 247 | char userId[20], restartService[80]; | |||||
| 248 | char *fullyQuantifiedName; | |||||
| 249 | int newstring; | |||||
| 250 | ||||||
| 251 | prop1.name = SmProgram"Program"; | |||||
| 252 | prop1.type = SmARRAY8"ARRAY8"; | |||||
| 253 | prop1.num_vals = 1; | |||||
| 254 | prop1.vals = &prop1val; | |||||
| 255 | prop1val.value = (SmPointer) winInfo->wm_command[0]; | |||||
| 256 | prop1val.length = strlen (winInfo->wm_command[0]); | |||||
| 257 | ||||||
| 258 | snprintf (userId, sizeof(userId), "%ld", (long)getuid())__builtin___snprintf_chk (userId, sizeof(userId), 0, __builtin_object_size (userId, 2 > 1 ? 1 : 0), "%ld", (long)getuid()); | |||||
| 259 | prop2.name = SmUserID"UserID"; | |||||
| 260 | prop2.type = SmARRAY8"ARRAY8"; | |||||
| 261 | prop2.num_vals = 1; | |||||
| 262 | prop2.vals = &prop2val; | |||||
| 263 | prop2val.value = (SmPointer) userId; | |||||
| 264 | prop2val.length = strlen (userId); | |||||
| 265 | ||||||
| 266 | fullyQuantifiedName = CheckFullyQuantifiedName ( | |||||
| 267 | (char *) winInfo->wm_client_machine.value, &newstring); | |||||
| 268 | snprintf (restartService, sizeof(restartService),__builtin___snprintf_chk (restartService, sizeof(restartService ), 0, __builtin_object_size (restartService, 2 > 1 ? 1 : 0 ), "rstart-rsh/%s", fullyQuantifiedName) | |||||
| 269 | "rstart-rsh/%s", fullyQuantifiedName)__builtin___snprintf_chk (restartService, sizeof(restartService ), 0, __builtin_object_size (restartService, 2 > 1 ? 1 : 0 ), "rstart-rsh/%s", fullyQuantifiedName); | |||||
| 270 | if (newstring) | |||||
| 271 | free (fullyQuantifiedName); | |||||
| 272 | ||||||
| 273 | prop3.name = "_XC_RestartService"; | |||||
| 274 | prop3.type = SmLISTofARRAY8"LISTofARRAY8"; | |||||
| 275 | prop3.num_vals = 1; | |||||
| 276 | prop3.vals = &prop3val; | |||||
| 277 | prop3val.value = (SmPointer) restartService; | |||||
| 278 | prop3val.length = strlen (restartService); | |||||
| 279 | ||||||
| 280 | props[0] = &prop1; | |||||
| 281 | props[1] = &prop2; | |||||
| 282 | props[2] = &prop3; | |||||
| 283 | ||||||
| 284 | SmcSetProperties (winInfo->smc_conn, 3, props); | |||||
| 285 | ||||||
| 286 | winInfo->got_first_save_yourself = 1; | |||||
| 287 | } | |||||
| 288 | ||||||
| 289 | prop1.name = SmRestartCommand"RestartCommand"; | |||||
| 290 | prop1.type = SmLISTofARRAY8"LISTofARRAY8"; | |||||
| 291 | prop1.num_vals = winInfo->wm_command_count; | |||||
| 292 | ||||||
| 293 | prop1.vals = (SmPropValue *) malloc ( | |||||
| 294 | winInfo->wm_command_count * sizeof (SmPropValue)); | |||||
| 295 | ||||||
| 296 | if (!prop1.vals) | |||||
| 297 | { | |||||
| 298 | SmcSaveYourselfDone (winInfo->smc_conn, False0); | |||||
| 299 | return; | |||||
| 300 | } | |||||
| 301 | ||||||
| 302 | for (i = 0; i < winInfo->wm_command_count; i++) | |||||
| 303 | { | |||||
| 304 | prop1.vals[i].value = (SmPointer) winInfo->wm_command[i]; | |||||
| 305 | prop1.vals[i].length = strlen (winInfo->wm_command[i]); | |||||
| 306 | } | |||||
| 307 | ||||||
| 308 | prop2.name = SmCloneCommand"CloneCommand"; | |||||
| 309 | prop2.type = SmLISTofARRAY8"LISTofARRAY8"; | |||||
| 310 | prop2.num_vals = winInfo->wm_command_count; | |||||
| 311 | prop2.vals = prop1.vals; | |||||
| 312 | ||||||
| 313 | props[0] = &prop1; | |||||
| 314 | props[1] = &prop2; | |||||
| 315 | ||||||
| 316 | SmcSetProperties (winInfo->smc_conn, 2, props); | |||||
| 317 | ||||||
| 318 | free ((char *) prop1.vals); | |||||
| 319 | ||||||
| 320 | /* | |||||
| 321 | * If the client doesn't support WM_SAVE_YOURSELF, we should | |||||
| 322 | * return failure for the save, since we really don't know if | |||||
| 323 | * the application needed to save state. | |||||
| 324 | */ | |||||
| 325 | ||||||
| 326 | SmcSaveYourselfDone (winInfo->smc_conn, has_WM_SAVEYOURSELF); | |||||
| 327 | } | |||||
| 328 | ||||||
| 329 | ||||||
| 330 | ||||||
| 331 | static void | |||||
| 332 | SaveYourselfCB(SmcConn smcConn, SmPointer clientData, int saveType, | |||||
| 333 | Boolint shutdown, int interactStyle, Boolint fast) | |||||
| 334 | { | |||||
| 335 | WinInfo *winInfo = (WinInfo *) clientData; | |||||
| 336 | ||||||
| 337 | if (!winInfo->has_save_yourself) | |||||
| 338 | { | |||||
| 339 | FinishSaveYourself (winInfo, False0); | |||||
| 340 | } | |||||
| 341 | else | |||||
| 342 | { | |||||
| 343 | XClientMessageEvent saveYourselfMessage; | |||||
| 344 | ||||||
| 345 | ||||||
| 346 | /* Send WM_SAVE_YOURSELF */ | |||||
| 347 | ||||||
| 348 | saveYourselfMessage.type = ClientMessage33; | |||||
| 349 | saveYourselfMessage.window = winInfo->window; | |||||
| 350 | saveYourselfMessage.message_type = wmProtocolsAtom; | |||||
| 351 | saveYourselfMessage.format = 32; | |||||
| 352 | saveYourselfMessage.data.l[0] = wmSaveYourselfAtom; | |||||
| 353 | saveYourselfMessage.data.l[1] = CurrentTime0L; | |||||
| 354 | ||||||
| 355 | if (XSendEvent (disp, winInfo->window, False0, NoEventMask0L, | |||||
| 356 | (XEvent *) &saveYourselfMessage)) | |||||
| 357 | { | |||||
| 358 | winInfo->waiting_for_update = 1; | |||||
| 359 | ||||||
| 360 | if (debug) | |||||
| 361 | { | |||||
| 362 | printf ("Sent SAVE YOURSELF to 0x%x\n", | |||||
| 363 | (unsigned int)winInfo->window); | |||||
| 364 | printf ("\n"); | |||||
| 365 | } | |||||
| 366 | } | |||||
| 367 | else | |||||
| 368 | { | |||||
| 369 | if (debug) | |||||
| 370 | { | |||||
| 371 | printf ("Failed to send SAVE YOURSELF to 0x%x\n", | |||||
| 372 | (unsigned int)winInfo->window); | |||||
| 373 | printf ("\n"); | |||||
| 374 | } | |||||
| 375 | } | |||||
| 376 | } | |||||
| 377 | } | |||||
| 378 | ||||||
| 379 | ||||||
| 380 | ||||||
| 381 | static void | |||||
| 382 | DieCB(SmcConn smcConn, SmPointer clientData) | |||||
| 383 | { | |||||
| 384 | WinInfo *winInfo = (WinInfo *) clientData; | |||||
| 385 | ||||||
| 386 | SmcCloseConnection (winInfo->smc_conn, 0, NULL((void*)0)); | |||||
| 387 | winInfo->smc_conn = NULL((void*)0); | |||||
| 388 | XtRemoveInput (winInfo->input_id); | |||||
| 389 | ||||||
| 390 | /* Now tell the client to die */ | |||||
| 391 | ||||||
| 392 | if (debug) | |||||
| 393 | printf ("Trying to kill 0x%x\n", (unsigned int)winInfo->window); | |||||
| 394 | ||||||
| 395 | XSync (disp, 0); | |||||
| 396 | XKillClient (disp, winInfo->window); | |||||
| 397 | XSync (disp, 0); | |||||
| 398 | ||||||
| 399 | ||||||
| 400 | /* | |||||
| 401 | * Proxy must exit when all clients die, and the proxy itself | |||||
| 402 | * must have received a Die. | |||||
| 403 | */ | |||||
| 404 | ||||||
| 405 | die_count++; | |||||
| 406 | ||||||
| 407 | if (die_count == proxy_count && ok_to_die) | |||||
| 408 | { | |||||
| 409 | exit (0); | |||||
| 410 | } | |||||
| 411 | } | |||||
| 412 | ||||||
| 413 | ||||||
| 414 | ||||||
| 415 | static void | |||||
| 416 | SaveCompleteCB(SmcConn smcConn, SmPointer clientData) | |||||
| 417 | { | |||||
| 418 | /* | |||||
| 419 | * Nothing to do here. | |||||
| 420 | */ | |||||
| 421 | } | |||||
| 422 | ||||||
| 423 | ||||||
| 424 | ||||||
| 425 | static void | |||||
| 426 | ShutdownCancelledCB(SmcConn smcConn, SmPointer clientData) | |||||
| 427 | { | |||||
| 428 | /* | |||||
| 429 | * Since we did not request to interact or request save yourself | |||||
| 430 | * phase 2, we know we already sent the save yourself done, so | |||||
| 431 | * there is nothing to do here. | |||||
| 432 | */ | |||||
| 433 | } | |||||
| 434 | ||||||
| 435 | ||||||
| 436 | ||||||
| 437 | static void | |||||
| 438 | ProcessIceMsgProc(XtPointer client_data, int *source, XtInputId *id) | |||||
| 439 | { | |||||
| 440 | IceConn ice_conn = (IceConn) client_data; | |||||
| 441 | ||||||
| 442 | IceProcessMessages (ice_conn, NULL((void*)0), NULL((void*)0)); | |||||
| 443 | } | |||||
| 444 | ||||||
| 445 | ||||||
| 446 | ||||||
| 447 | static void | |||||
| 448 | NullIceErrorHandler(IceConn iceConn, Boolint swap, int offendingMinorOpcode, | |||||
| 449 | unsigned long offendingSequence, int errorClass, | |||||
| 450 | int severity, IcePointer values) | |||||
| 451 | { | |||||
| 452 | return; | |||||
| 453 | } | |||||
| 454 | ||||||
| 455 | ||||||
| 456 | static void | |||||
| 457 | ConnectClientToSM(WinInfo *winInfo) | |||||
| 458 | { | |||||
| 459 | char errorMsg[256]; | |||||
| 460 | unsigned long mask; | |||||
| 461 | SmcCallbacks callbacks; | |||||
| 462 | IceConn ice_conn; | |||||
| 463 | char *prevId; | |||||
| 464 | ||||||
| 465 | mask = SmcSaveYourselfProcMask(1L << 0) | SmcDieProcMask(1L << 1) | | |||||
| 466 | SmcSaveCompleteProcMask(1L << 2) | SmcShutdownCancelledProcMask(1L << 3); | |||||
| 467 | ||||||
| 468 | callbacks.save_yourself.callback = SaveYourselfCB; | |||||
| 469 | callbacks.save_yourself.client_data = (SmPointer) winInfo; | |||||
| 470 | ||||||
| 471 | callbacks.die.callback = DieCB; | |||||
| 472 | callbacks.die.client_data = (SmPointer) winInfo; | |||||
| 473 | ||||||
| 474 | callbacks.save_complete.callback = SaveCompleteCB; | |||||
| 475 | callbacks.save_complete.client_data = (SmPointer) winInfo; | |||||
| 476 | ||||||
| 477 | callbacks.shutdown_cancelled.callback = ShutdownCancelledCB; | |||||
| 478 | callbacks.shutdown_cancelled.client_data = (SmPointer) winInfo; | |||||
| 479 | ||||||
| 480 | prevId = LookupClientID (winInfo); | |||||
| 481 | ||||||
| 482 | /* | |||||
| 483 | * In case a protocol error occurs when opening the connection, | |||||
| 484 | * (e.g. an authentication error), we set a null error handler | |||||
| 485 | * before the open, then restore the default handler after the open. | |||||
| 486 | */ | |||||
| 487 | ||||||
| 488 | IceSetErrorHandler (NullIceErrorHandler); | |||||
| 489 | ||||||
| 490 | winInfo->smc_conn = SmcOpenConnection ( | |||||
| 491 | NULL((void*)0), /* use SESSION_MANAGER env */ | |||||
| 492 | (SmPointer) winInfo, /* force a new connection */ | |||||
| 493 | SmProtoMajor1, | |||||
| 494 | SmProtoMinor0, | |||||
| 495 | mask, | |||||
| 496 | &callbacks, | |||||
| 497 | prevId, | |||||
| 498 | &winInfo->client_id, | |||||
| 499 | 256, errorMsg); | |||||
| 500 | ||||||
| 501 | IceSetErrorHandler (NULL((void*)0)); | |||||
| 502 | ||||||
| 503 | if (winInfo->smc_conn == NULL((void*)0)) | |||||
| 504 | return; | |||||
| 505 | ||||||
| 506 | ice_conn = SmcGetIceConnection (winInfo->smc_conn); | |||||
| 507 | ||||||
| 508 | winInfo->input_id = XtAppAddInput ( | |||||
| 509 | appContext, | |||||
| 510 | IceConnectionNumber (ice_conn), | |||||
| 511 | (XtPointer) XtInputReadMask(1L<<0), | |||||
| 512 | ProcessIceMsgProc, | |||||
| 513 | (XtPointer) ice_conn); | |||||
| 514 | ||||||
| 515 | if (debug) | |||||
| 516 | { | |||||
| 517 | printf ("Connected to SM, window = 0x%x\n", | |||||
| 518 | (unsigned int)winInfo->window); | |||||
| 519 | printf ("\n"); | |||||
| 520 | } | |||||
| 521 | ||||||
| 522 | proxy_count++; | |||||
| 523 | } | |||||
| 524 | ||||||
| 525 | ||||||
| 526 | ||||||
| 527 | static int | |||||
| 528 | MyErrorHandler(Display *display, XErrorEvent *event) | |||||
| 529 | { | |||||
| 530 | caught_error = 1; | |||||
| 531 | return 0; | |||||
| 532 | } | |||||
| 533 | ||||||
| 534 | ||||||
| 535 | ||||||
| 536 | static Boolint | |||||
| 537 | LookupWindow(Window window, WinInfo **ptr_ret, WinInfo **prev_ptr_ret) | |||||
| 538 | { | |||||
| 539 | WinInfo *ptr, *prev; | |||||
| 540 | ||||||
| 541 | ptr = win_head; | |||||
| 542 | prev = NULL((void*)0); | |||||
| 543 | ||||||
| 544 | while (ptr) | |||||
| 545 | { | |||||
| 546 | if (ptr->window == window) | |||||
| 547 | break; | |||||
| 548 | else | |||||
| 549 | { | |||||
| 550 | prev = ptr; | |||||
| 551 | ptr = ptr->next; | |||||
| 552 | } | |||||
| 553 | } | |||||
| 554 | ||||||
| 555 | if (ptr) | |||||
| 556 | { | |||||
| 557 | if (ptr_ret) | |||||
| 558 | *ptr_ret = ptr; | |||||
| 559 | if (prev_ptr_ret) | |||||
| 560 | *prev_ptr_ret = prev; | |||||
| 561 | return (1); | |||||
| 562 | } | |||||
| 563 | else | |||||
| 564 | return (0); | |||||
| 565 | } | |||||
| 566 | ||||||
| 567 | ||||||
| 568 | ||||||
| 569 | static WinInfo * | |||||
| 570 | AddNewWindow(Window window) | |||||
| 571 | { | |||||
| 572 | WinInfo *newptr; | |||||
| 573 | ||||||
| 574 | if (LookupWindow (window, NULL((void*)0), NULL((void*)0))) | |||||
| 575 | return (NULL((void*)0)); | |||||
| 576 | ||||||
| 577 | newptr = (WinInfo *) malloc (sizeof (WinInfo)); | |||||
| 578 | ||||||
| 579 | if (newptr == NULL((void*)0)) | |||||
| 580 | return (NULL((void*)0)); | |||||
| 581 | ||||||
| 582 | newptr->next = win_head; | |||||
| 583 | win_head = newptr; | |||||
| 584 | ||||||
| 585 | newptr->window = window; | |||||
| 586 | newptr->smc_conn = NULL((void*)0); | |||||
| 587 | newptr->tested_for_sm_client_id = 0; | |||||
| 588 | newptr->client_id = NULL((void*)0); | |||||
| 589 | newptr->wm_command = NULL((void*)0); | |||||
| 590 | newptr->wm_command_count = 0; | |||||
| 591 | newptr->class.res_name = NULL((void*)0); | |||||
| 592 | newptr->class.res_class = NULL((void*)0); | |||||
| 593 | newptr->wm_name = NULL((void*)0); | |||||
| 594 | newptr->wm_client_machine.value = NULL((void*)0); | |||||
| 595 | newptr->wm_client_machine.nitems = 0; | |||||
| 596 | newptr->has_save_yourself = 0; | |||||
| 597 | newptr->waiting_for_update = 0; | |||||
| 598 | newptr->got_first_save_yourself = 0; | |||||
| 599 | ||||||
| 600 | return (newptr); | |||||
| 601 | } | |||||
| 602 | ||||||
| 603 | ||||||
| 604 | ||||||
| 605 | static void | |||||
| 606 | RemoveWindow(WinInfo *winptr) | |||||
| 607 | { | |||||
| 608 | WinInfo *ptr, *prev; | |||||
| 609 | ||||||
| 610 | if (LookupWindow (winptr->window, &ptr, &prev)) | |||||
| 611 | { | |||||
| 612 | if (prev == NULL((void*)0)) | |||||
| 613 | win_head = ptr->next; | |||||
| 614 | else | |||||
| 615 | prev->next = ptr->next; | |||||
| 616 | ||||||
| 617 | if (ptr->client_id) | |||||
| 618 | free (ptr->client_id); | |||||
| 619 | ||||||
| 620 | if (ptr->wm_command) | |||||
| 621 | XFreeStringList (ptr->wm_command); | |||||
| 622 | ||||||
| 623 | if (ptr->wm_name) | |||||
| 624 | XFree (ptr->wm_name); | |||||
| 625 | ||||||
| 626 | if (ptr->wm_client_machine.value) | |||||
| 627 | XFree (ptr->wm_client_machine.value); | |||||
| 628 | ||||||
| 629 | if (ptr->class.res_name) | |||||
| 630 | XFree (ptr->class.res_name); | |||||
| 631 | ||||||
| 632 | if (ptr->class.res_class) | |||||
| 633 | XFree (ptr->class.res_class); | |||||
| 634 | ||||||
| 635 | free ((char *) ptr); | |||||
| 636 | } | |||||
| 637 | } | |||||
| 638 | ||||||
| 639 | ||||||
| 640 | ||||||
| 641 | static void | |||||
| 642 | Got_WM_STATE(WinInfo *winptr) | |||||
| 643 | { | |||||
| 644 | WinInfo *leader_winptr; | |||||
| 645 | ||||||
| 646 | /* | |||||
| 647 | * If we already got WM_STATE and tested for SM_CLIENT_ID, we | |||||
| 648 | * shouldn't do it again. | |||||
| 649 | */ | |||||
| 650 | ||||||
| 651 | if (winptr->tested_for_sm_client_id) | |||||
| 652 | { | |||||
| 653 | return; | |||||
| 654 | } | |||||
| 655 | ||||||
| 656 | ||||||
| 657 | /* | |||||
| 658 | * Set a null error handler, in case this window goes away | |||||
| 659 | * behind our back. | |||||
| 660 | */ | |||||
| 661 | ||||||
| 662 | caught_error = 0; | |||||
| 663 | XSetErrorHandler (MyErrorHandler); | |||||
| 664 | ||||||
| 665 | ||||||
| 666 | /* | |||||
| 667 | * Get the client leader window. | |||||
| 668 | */ | |||||
| 669 | ||||||
| 670 | leader_winptr = GetClientLeader (winptr); | |||||
| 671 | ||||||
| 672 | if (caught_error) | |||||
| 673 | { | |||||
| 674 | caught_error = 0; | |||||
| 675 | RemoveWindow (winptr); | |||||
| 676 | XSetErrorHandler (NULL((void*)0)); | |||||
| 677 | return; | |||||
| 678 | } | |||||
| 679 | ||||||
| 680 | ||||||
| 681 | /* | |||||
| 682 | * If we already checked for SM_CLIENT_ID on the client leader | |||||
| 683 | * window, don't do it again. | |||||
| 684 | */ | |||||
| 685 | ||||||
| 686 | if (!leader_winptr || leader_winptr->tested_for_sm_client_id) | |||||
| 687 | { | |||||
| 688 | caught_error = 0; | |||||
| 689 | XSetErrorHandler (NULL((void*)0)); | |||||
| 690 | return; | |||||
| 691 | } | |||||
| 692 | ||||||
| 693 | leader_winptr->tested_for_sm_client_id = 1; | |||||
| 694 | ||||||
| 695 | if (!HasXSMPsupport (leader_winptr->window)) | |||||
| 696 | { | |||||
| 697 | XFetchName (disp, leader_winptr->window, &leader_winptr->wm_name); | |||||
| 698 | ||||||
| 699 | XGetCommand (disp, leader_winptr->window, | |||||
| 700 | &leader_winptr->wm_command, | |||||
| 701 | &leader_winptr->wm_command_count); | |||||
| 702 | ||||||
| 703 | XGetClassHint (disp, leader_winptr->window, &leader_winptr->class); | |||||
| 704 | ||||||
| 705 | XGetWMClientMachine (disp, leader_winptr->window, | |||||
| 706 | &leader_winptr->wm_client_machine); | |||||
| 707 | ||||||
| 708 | if (leader_winptr->wm_name != NULL((void*)0) && | |||||
| 709 | leader_winptr->wm_command != NULL((void*)0) && | |||||
| 710 | leader_winptr->wm_command_count > 0 && | |||||
| 711 | leader_winptr->class.res_name != NULL((void*)0) && | |||||
| 712 | leader_winptr->class.res_class != NULL((void*)0) && | |||||
| 713 | leader_winptr->wm_client_machine.value != NULL((void*)0) && | |||||
| 714 | leader_winptr->wm_client_machine.nitems != 0) | |||||
| 715 | { | |||||
| 716 | leader_winptr->has_save_yourself = | |||||
| 717 | HasSaveYourself (leader_winptr->window); | |||||
| 718 | ||||||
| 719 | ConnectClientToSM (leader_winptr); | |||||
| 720 | } | |||||
| 721 | } | |||||
| 722 | ||||||
| 723 | XSync (disp, 0); | |||||
| 724 | XSetErrorHandler (NULL((void*)0)); | |||||
| 725 | ||||||
| 726 | if (caught_error) | |||||
| 727 | { | |||||
| 728 | caught_error = 0; | |||||
| 729 | RemoveWindow (leader_winptr); | |||||
| 730 | } | |||||
| 731 | } | |||||
| 732 | ||||||
| 733 | ||||||
| 734 | ||||||
| 735 | static void | |||||
| 736 | HandleCreate(XCreateWindowEvent *event) | |||||
| 737 | { | |||||
| 738 | Atom actual_type; | |||||
| 739 | int actual_format; | |||||
| 740 | unsigned long nitems, bytesafter; | |||||
| 741 | unsigned long *datap = NULL((void*)0); | |||||
| 742 | WinInfo *winptr; | |||||
| 743 | Boolint got_wm_state = 0; | |||||
| 744 | ||||||
| 745 | /* | |||||
| 746 | * We are waiting for all proxy connections to close so we can die. | |||||
| 747 | * Don't handle new connections. | |||||
| 748 | */ | |||||
| 749 | ||||||
| 750 | if (ok_to_die) | |||||
| 751 | return; | |||||
| 752 | ||||||
| 753 | ||||||
| 754 | /* | |||||
| 755 | * Add the new window | |||||
| 756 | */ | |||||
| 757 | ||||||
| 758 | if ((winptr = AddNewWindow (event->window)) == NULL((void*)0)) | |||||
| 759 | return; | |||||
| 760 | ||||||
| 761 | ||||||
| 762 | /* | |||||
| 763 | * Right after the window was created, it might have been destroyed, | |||||
| 764 | * so the following Xlib calls might fail. Need to catch the error | |||||
| 765 | * by installing an error handler. | |||||
| 766 | */ | |||||
| 767 | ||||||
| 768 | caught_error = 0; | |||||
| 769 | XSetErrorHandler (MyErrorHandler); | |||||
| 770 | ||||||
| 771 | ||||||
| 772 | /* | |||||
| 773 | * Select for Property Notify on the window so we can determine | |||||
| 774 | * when WM_STATE is defined. To avoid a race condition, we must | |||||
| 775 | * do this _before_ we check for WM_STATE right now. | |||||
| 776 | * | |||||
| 777 | * Select for Substructure Notify so we can determine when the | |||||
| 778 | * window is destroyed. | |||||
| 779 | */ | |||||
| 780 | ||||||
| 781 | XSelectInput (disp, event->window, | |||||
| 782 | SubstructureNotifyMask(1L<<19) | PropertyChangeMask(1L<<22)); | |||||
| 783 | ||||||
| 784 | ||||||
| 785 | /* | |||||
| 786 | * WM_STATE may already be there. Check now. | |||||
| 787 | */ | |||||
| 788 | ||||||
| 789 | if (XGetWindowProperty (disp, event->window, wmStateAtom, | |||||
| 790 | 0L, 2L, False0, AnyPropertyType0L, | |||||
| 791 | &actual_type, &actual_format, &nitems, &bytesafter, | |||||
| 792 | (unsigned char **) &datap) == Success0 && datap) | |||||
| 793 | { | |||||
| 794 | if (nitems > 0) | |||||
| 795 | got_wm_state = 1; | |||||
| 796 | ||||||
| 797 | if (datap) | |||||
| 798 | XFree ((char *) datap); | |||||
| 799 | } | |||||
| 800 | ||||||
| 801 | XSync (disp, 0); | |||||
| 802 | XSetErrorHandler (NULL((void*)0)); | |||||
| 803 | ||||||
| 804 | if (caught_error) | |||||
| 805 | { | |||||
| 806 | caught_error = 0; | |||||
| 807 | RemoveWindow (winptr); | |||||
| 808 | } | |||||
| 809 | else if (got_wm_state) | |||||
| 810 | { | |||||
| 811 | Got_WM_STATE (winptr); | |||||
| 812 | } | |||||
| 813 | } | |||||
| 814 | ||||||
| 815 | ||||||
| 816 | ||||||
| 817 | static void | |||||
| 818 | HandleDestroy(XDestroyWindowEvent *event) | |||||
| 819 | { | |||||
| 820 | WinInfo *winptr; | |||||
| 821 | ||||||
| 822 | if (LookupWindow (event->window, &winptr, NULL((void*)0))) | |||||
| 823 | { | |||||
| 824 | if (winptr->smc_conn) | |||||
| 825 | { | |||||
| 826 | SmcCloseConnection (winptr->smc_conn, 0, NULL((void*)0)); | |||||
| 827 | XtRemoveInput (winptr->input_id); | |||||
| 828 | proxy_count--; | |||||
| 829 | } | |||||
| 830 | ||||||
| 831 | if (debug) | |||||
| 832 | { | |||||
| 833 | printf ("Removed window (window = 0x%x)\n", | |||||
| 834 | (unsigned int)winptr->window); | |||||
| 835 | printf ("\n"); | |||||
| 836 | } | |||||
| 837 | ||||||
| 838 | RemoveWindow (winptr); | |||||
| 839 | } | |||||
| 840 | } | |||||
| 841 | ||||||
| 842 | ||||||
| 843 | ||||||
| 844 | static void | |||||
| 845 | HandleUpdate(XPropertyEvent *event) | |||||
| 846 | { | |||||
| 847 | Window window = event->window; | |||||
| 848 | WinInfo *winptr; | |||||
| 849 | ||||||
| 850 | if (!LookupWindow (window, &winptr, NULL((void*)0))) | |||||
| 851 | return; | |||||
| 852 | ||||||
| 853 | if (event->atom == wmStateAtom) | |||||
| 854 | { | |||||
| 855 | Got_WM_STATE (winptr); | |||||
| 856 | } | |||||
| 857 | else if (event->atom == XA_WM_COMMAND((Atom) 34) && winptr->waiting_for_update) | |||||
| 858 | { | |||||
| 859 | /* Finish off the Save Yourself */ | |||||
| 860 | ||||||
| 861 | if (winptr->wm_command) | |||||
| 862 | { | |||||
| 863 | XFreeStringList (winptr->wm_command); | |||||
| 864 | winptr->wm_command = NULL((void*)0); | |||||
| 865 | winptr->wm_command_count = 0; | |||||
| 866 | } | |||||
| 867 | ||||||
| 868 | XGetCommand (disp, window, | |||||
| 869 | &winptr->wm_command, | |||||
| 870 | &winptr->wm_command_count); | |||||
| 871 | ||||||
| 872 | winptr->waiting_for_update = 0; | |||||
| 873 | FinishSaveYourself (winptr, True1); | |||||
| 874 | } | |||||
| 875 | } | |||||
| 876 | ||||||
| 877 | ||||||
| 878 | ||||||
| 879 | static void | |||||
| 880 | ProxySaveYourselfPhase2CB(SmcConn smcConn, SmPointer clientData) | |||||
| 881 | { | |||||
| 882 | char *filename; | |||||
| 883 | Boolint success = True1; | |||||
| 884 | SmProp prop1, prop2, prop3, *props[3]; | |||||
| 885 | SmPropValue prop1val, prop2val, prop3val; | |||||
| 886 | char *discardCommand; | |||||
| 887 | int numVals, i; | |||||
| 888 | static int first_time = 1; | |||||
| 889 | ||||||
| 890 | if (first_time) | |||||
| ||||||
| 891 | { | |||||
| 892 | char userId[20]; | |||||
| 893 | char hint = SmRestartIfRunning0; | |||||
| 894 | ||||||
| 895 | prop1.name = SmProgram"Program"; | |||||
| 896 | prop1.type = SmARRAY8"ARRAY8"; | |||||
| 897 | prop1.num_vals = 1; | |||||
| 898 | prop1.vals = &prop1val; | |||||
| 899 | prop1val.value = Argv[0]; | |||||
| 900 | prop1val.length = strlen (Argv[0]); | |||||
| 901 | ||||||
| 902 | snprintf (userId, sizeof(userId), "%ld", (long)getuid())__builtin___snprintf_chk (userId, sizeof(userId), 0, __builtin_object_size (userId, 2 > 1 ? 1 : 0), "%ld", (long)getuid()); | |||||
| 903 | prop2.name = SmUserID"UserID"; | |||||
| 904 | prop2.type = SmARRAY8"ARRAY8"; | |||||
| 905 | prop2.num_vals = 1; | |||||
| 906 | prop2.vals = &prop2val; | |||||
| 907 | prop2val.value = (SmPointer) userId; | |||||
| 908 | prop2val.length = strlen (userId); | |||||
| 909 | ||||||
| 910 | prop3.name = SmRestartStyleHint"RestartStyleHint"; | |||||
| 911 | prop3.type = SmCARD8"CARD8"; | |||||
| 912 | prop3.num_vals = 1; | |||||
| 913 | prop3.vals = &prop3val; | |||||
| 914 | prop3val.value = (SmPointer) &hint; | |||||
| 915 | prop3val.length = 1; | |||||
| 916 | ||||||
| 917 | props[0] = &prop1; | |||||
| 918 | props[1] = &prop2; | |||||
| 919 | props[2] = &prop3; | |||||
| 920 | ||||||
| 921 | SmcSetProperties (smcConn, 3, props); | |||||
| 922 | ||||||
| 923 | first_time = 0; | |||||
| 924 | } | |||||
| 925 | ||||||
| 926 | if ((filename = WriteProxyFile ()) == NULL((void*)0)) | |||||
| 927 | { | |||||
| 928 | success = False0; | |||||
| 929 | goto finishUp; | |||||
| 930 | } | |||||
| 931 | ||||||
| 932 | prop1.name = SmRestartCommand"RestartCommand"; | |||||
| 933 | prop1.type = SmLISTofARRAY8"LISTofARRAY8"; | |||||
| 934 | ||||||
| 935 | prop1.vals = (SmPropValue *) malloc ( | |||||
| 936 | (Argc + 4) * sizeof (SmPropValue)); | |||||
| 937 | ||||||
| 938 | if (!prop1.vals) | |||||
| 939 | { | |||||
| 940 | success = False0; | |||||
| 941 | goto finishUp; | |||||
| 942 | } | |||||
| 943 | ||||||
| 944 | numVals = 0; | |||||
| 945 | ||||||
| 946 | for (i = 0; i < Argc; i++) | |||||
| 947 | { | |||||
| 948 | if (strcmp (Argv[i], "-clientId") == 0 || | |||||
| 949 | strcmp (Argv[i], "-restore") == 0) | |||||
| 950 | { | |||||
| 951 | i++; | |||||
| 952 | } | |||||
| 953 | else | |||||
| 954 | { | |||||
| 955 | prop1.vals[numVals].value = (SmPointer) Argv[i]; | |||||
| 956 | prop1.vals[numVals++].length = strlen (Argv[i]); | |||||
| 957 | } | |||||
| 958 | } | |||||
| 959 | ||||||
| 960 | prop1.vals[numVals].value = (SmPointer) "-clientId"; | |||||
| 961 | prop1.vals[numVals++].length = 9; | |||||
| 962 | ||||||
| 963 | prop1.vals[numVals].value = (SmPointer) proxy_clientId; | |||||
| 964 | prop1.vals[numVals++].length = strlen (proxy_clientId); | |||||
| 965 | ||||||
| 966 | prop1.vals[numVals].value = (SmPointer) "-restore"; | |||||
| 967 | prop1.vals[numVals++].length = 8; | |||||
| 968 | ||||||
| 969 | prop1.vals[numVals].value = (SmPointer) filename; | |||||
| 970 | prop1.vals[numVals++].length = strlen (filename); | |||||
| 971 | ||||||
| 972 | prop1.num_vals = numVals; | |||||
| 973 | ||||||
| 974 | ||||||
| 975 | if (asprintf (&discardCommand, "rm %s", filename) == -1) { | |||||
| 976 | success = False0; | |||||
| ||||||
| 977 | goto finishUp; | |||||
| 978 | } | |||||
| 979 | prop2.name = SmDiscardCommand"DiscardCommand"; | |||||
| 980 | prop2.type = SmARRAY8"ARRAY8"; | |||||
| 981 | prop2.num_vals = 1; | |||||
| 982 | prop2.vals = &prop2val; | |||||
| 983 | prop2val.value = (SmPointer) discardCommand; | |||||
| 984 | prop2val.length = strlen (discardCommand); | |||||
| 985 | ||||||
| 986 | props[0] = &prop1; | |||||
| 987 | props[1] = &prop2; | |||||
| 988 | ||||||
| 989 | SmcSetProperties (smcConn, 2, props); | |||||
| 990 | free ((char *) prop1.vals); | |||||
| 991 | free (discardCommand); | |||||
| 992 | ||||||
| 993 | finishUp: | |||||
| 994 | ||||||
| 995 | SmcSaveYourselfDone (smcConn, success); | |||||
| 996 | sent_save_done = 1; | |||||
| 997 | ||||||
| 998 | if (filename) | |||||
| 999 | free (filename); | |||||
| 1000 | } | |||||
| 1001 | ||||||
| 1002 | ||||||
| 1003 | ||||||
| 1004 | static void | |||||
| 1005 | ProxySaveYourselfCB(SmcConn smcConn, SmPointer clientData, int saveType, | |||||
| 1006 | Boolint shutdown, int interactStyle, Boolint fast) | |||||
| 1007 | { | |||||
| 1008 | /* | |||||
| 1009 | * We want the proxy to respond to the Save Yourself after all | |||||
| 1010 | * the regular XSMP clients have finished with the save (and possibly | |||||
| 1011 | * interacted with the user). | |||||
| 1012 | */ | |||||
| 1013 | ||||||
| 1014 | if (!SmcRequestSaveYourselfPhase2 (smcConn, | |||||
| 1015 | ProxySaveYourselfPhase2CB, NULL((void*)0))) | |||||
| 1016 | { | |||||
| 1017 | SmcSaveYourselfDone (smcConn, False0); | |||||
| 1018 | sent_save_done = 1; | |||||
| 1019 | } | |||||
| 1020 | else | |||||
| 1021 | sent_save_done = 0; | |||||
| 1022 | } | |||||
| 1023 | ||||||
| 1024 | ||||||
| 1025 | ||||||
| 1026 | static void | |||||
| 1027 | ProxyDieCB(SmcConn smcConn, SmPointer clientData) | |||||
| 1028 | { | |||||
| 1029 | SmcCloseConnection (proxy_smcConn, 0, NULL((void*)0)); | |||||
| 1030 | XtRemoveInput (proxy_iceInputId); | |||||
| 1031 | ||||||
| 1032 | if (die_count == proxy_count) | |||||
| 1033 | exit (0); | |||||
| 1034 | else | |||||
| 1035 | ok_to_die = 1; | |||||
| 1036 | } | |||||
| 1037 | ||||||
| 1038 | ||||||
| 1039 | ||||||
| 1040 | static void | |||||
| 1041 | ProxySaveCompleteCB(SmcConn smcConn, SmPointer clientData) | |||||
| 1042 | { | |||||
| 1043 | ; | |||||
| 1044 | } | |||||
| 1045 | ||||||
| 1046 | ||||||
| 1047 | ||||||
| 1048 | static void | |||||
| 1049 | ProxyShutdownCancelledCB(SmcConn smcConn, SmPointer clientData) | |||||
| 1050 | { | |||||
| 1051 | if (!sent_save_done) | |||||
| 1052 | { | |||||
| 1053 | SmcSaveYourselfDone (smcConn, False0); | |||||
| 1054 | sent_save_done = 1; | |||||
| 1055 | } | |||||
| 1056 | } | |||||
| 1057 | ||||||
| 1058 | ||||||
| 1059 | ||||||
| 1060 | static Statusint | |||||
| 1061 | ConnectProxyToSM(char *previous_id) | |||||
| 1062 | { | |||||
| 1063 | char errorMsg[256]; | |||||
| 1064 | unsigned long mask; | |||||
| 1065 | SmcCallbacks callbacks; | |||||
| 1066 | IceConn iceConn; | |||||
| 1067 | ||||||
| 1068 | mask = SmcSaveYourselfProcMask(1L << 0) | SmcDieProcMask(1L << 1) | | |||||
| 1069 | SmcSaveCompleteProcMask(1L << 2) | SmcShutdownCancelledProcMask(1L << 3); | |||||
| 1070 | ||||||
| 1071 | callbacks.save_yourself.callback = ProxySaveYourselfCB; | |||||
| 1072 | callbacks.save_yourself.client_data = (SmPointer) NULL((void*)0); | |||||
| 1073 | ||||||
| 1074 | callbacks.die.callback = ProxyDieCB; | |||||
| 1075 | callbacks.die.client_data = (SmPointer) NULL((void*)0); | |||||
| 1076 | ||||||
| 1077 | callbacks.save_complete.callback = ProxySaveCompleteCB; | |||||
| 1078 | callbacks.save_complete.client_data = (SmPointer) NULL((void*)0); | |||||
| 1079 | ||||||
| 1080 | callbacks.shutdown_cancelled.callback = ProxyShutdownCancelledCB; | |||||
| 1081 | callbacks.shutdown_cancelled.client_data = (SmPointer) NULL((void*)0); | |||||
| 1082 | ||||||
| 1083 | proxy_smcConn = SmcOpenConnection ( | |||||
| 1084 | NULL((void*)0), /* use SESSION_MANAGER env */ | |||||
| 1085 | (SmPointer) appContext, | |||||
| 1086 | SmProtoMajor1, | |||||
| 1087 | SmProtoMinor0, | |||||
| 1088 | mask, | |||||
| 1089 | &callbacks, | |||||
| 1090 | previous_id, | |||||
| 1091 | &proxy_clientId, | |||||
| 1092 | 256, errorMsg); | |||||
| 1093 | ||||||
| 1094 | if (proxy_smcConn == NULL((void*)0)) | |||||
| 1095 | return (0); | |||||
| 1096 | ||||||
| 1097 | iceConn = SmcGetIceConnection (proxy_smcConn); | |||||
| 1098 | ||||||
| 1099 | proxy_iceInputId = XtAppAddInput ( | |||||
| 1100 | appContext, | |||||
| 1101 | IceConnectionNumber (iceConn), | |||||
| 1102 | (XtPointer) XtInputReadMask(1L<<0), | |||||
| 1103 | ProcessIceMsgProc, | |||||
| 1104 | (XtPointer) iceConn); | |||||
| 1105 | ||||||
| 1106 | return (1); | |||||
| 1107 | } | |||||
| 1108 | ||||||
| 1109 | ||||||
| 1110 | ||||||
| 1111 | static void | |||||
| 1112 | CheckForExistingWindows(Window root) | |||||
| 1113 | { | |||||
| 1114 | Window dontCare1, dontCare2, *children, client_window; | |||||
| 1115 | unsigned int nchildren, i; | |||||
| 1116 | XCreateWindowEvent event; | |||||
| 1117 | ||||||
| 1118 | /* | |||||
| 1119 | * We query the root tree for all windows created thus far. | |||||
| 1120 | * Note that at any moment after XQueryTree is called, a | |||||
| 1121 | * window may be deleted. So we must take extra care to make | |||||
| 1122 | * sure a window really exists. | |||||
| 1123 | */ | |||||
| 1124 | ||||||
| 1125 | XQueryTree (disp, root, &dontCare1, &dontCare2, &children, &nchildren); | |||||
| 1126 | ||||||
| 1127 | for (i = 0; i < nchildren; i++) | |||||
| 1128 | { | |||||
| 1129 | event.window = children[i]; | |||||
| 1130 | ||||||
| 1131 | HandleCreate (&event); | |||||
| 1132 | ||||||
| 1133 | caught_error = 0; | |||||
| 1134 | XSetErrorHandler (MyErrorHandler); | |||||
| 1135 | ||||||
| 1136 | client_window = XmuClientWindow (disp, children[i]); | |||||
| 1137 | ||||||
| 1138 | XSetErrorHandler (NULL((void*)0)); | |||||
| 1139 | ||||||
| 1140 | if (!caught_error && client_window != children[i]) | |||||
| 1141 | { | |||||
| 1142 | event.window = client_window; | |||||
| 1143 | HandleCreate (&event); | |||||
| 1144 | } | |||||
| 1145 | } | |||||
| 1146 | } | |||||
| 1147 | ||||||
| 1148 | ||||||
| 1149 | ||||||
| 1150 | int | |||||
| 1151 | main (int argc, char *argv[]) | |||||
| 1152 | { | |||||
| 1153 | char *restore_filename = NULL((void*)0); | |||||
| 1154 | char *client_id = NULL((void*)0); | |||||
| 1155 | int i, zero = 0; | |||||
| 1156 | ||||||
| 1157 | Argc = argc; | |||||
| 1158 | Argv = argv; | |||||
| 1159 | ||||||
| 1160 | for (i = 1; i < argc; i++) | |||||
| 1161 | { | |||||
| 1162 | if (argv[i][0] == '-') | |||||
| 1163 | { | |||||
| 1164 | switch (argv[i][1]) | |||||
| 1165 | { | |||||
| 1166 | case 'd': /* -debug */ | |||||
| 1167 | debug = 1; | |||||
| 1168 | continue; | |||||
| 1169 | ||||||
| 1170 | case 'c': /* -clientId */ | |||||
| 1171 | if (++i >= argc) { | |||||
| 1172 | fprintf (stderr__stderrp, "%s: -clientId requires an argument\n", | |||||
| 1173 | argv[0]); | |||||
| 1174 | goto usage; | |||||
| 1175 | } | |||||
| 1176 | client_id = argv[i]; | |||||
| 1177 | continue; | |||||
| 1178 | ||||||
| 1179 | case 'r': /* -restore */ | |||||
| 1180 | if (++i >= argc) { | |||||
| 1181 | fprintf (stderr__stderrp, "%s: -restore requires an argument\n", | |||||
| 1182 | argv[0]); | |||||
| 1183 | goto usage; | |||||
| 1184 | } | |||||
| 1185 | restore_filename = argv[i]; | |||||
| 1186 | continue; | |||||
| 1187 | ||||||
| 1188 | case 'v': | |||||
| 1189 | puts (PACKAGE_STRING"smproxy 1.0.6"); | |||||
| 1190 | exit (0); | |||||
| 1191 | } | |||||
| 1192 | } | |||||
| 1193 | ||||||
| 1194 | fprintf (stderr__stderrp, "%s: unrecognized argument: %s\n", argv[0], argv[i]); | |||||
| 1195 | ||||||
| 1196 | usage: | |||||
| 1197 | ||||||
| 1198 | fprintf (stderr__stderrp, | |||||
| 1199 | "usage: %s [-clientId id] [-restore file] [-debug] [-version]\n", | |||||
| 1200 | argv[0]); | |||||
| 1201 | exit (1); | |||||
| 1202 | } | |||||
| 1203 | ||||||
| 1204 | ||||||
| 1205 | XtToolkitInitialize (); | |||||
| 1206 | appContext = XtCreateApplicationContext (); | |||||
| 1207 | ||||||
| 1208 | if (!(disp = XtOpenDisplay (appContext, NULL((void*)0), "SM-PROXY", "SM-PROXY", | |||||
| 1209 | NULL((void*)0), 0, &zero, NULL((void*)0)))) | |||||
| 1210 | { | |||||
| 1211 | fprintf (stderr__stderrp, "smproxy: unable to open display\n"); | |||||
| 1212 | exit (1); | |||||
| 1213 | } | |||||
| 1214 | ||||||
| 1215 | if (restore_filename) | |||||
| 1216 | ReadProxyFile (restore_filename); | |||||
| 1217 | ||||||
| 1218 | if (!ConnectProxyToSM (client_id)) | |||||
| 1219 | { | |||||
| 1220 | fprintf (stderr__stderrp, "smproxy: unable to connect to session manager\n"); | |||||
| 1221 | exit (1); | |||||
| 1222 | } | |||||
| 1223 | ||||||
| 1224 | wmProtocolsAtom = XInternAtom (disp, "WM_PROTOCOLS", False0); | |||||
| 1225 | wmSaveYourselfAtom = XInternAtom (disp, "WM_SAVE_YOURSELF", False0); | |||||
| 1226 | wmStateAtom = XInternAtom (disp, "WM_STATE", False0); | |||||
| 1227 | smClientIdAtom = XInternAtom (disp, "SM_CLIENT_ID", False0); | |||||
| 1228 | wmClientLeaderAtom = XInternAtom (disp, "WM_CLIENT_LEADER", False0); | |||||
| 1229 | ||||||
| 1230 | for (i = 0; i < ScreenCount (disp)(((_XPrivDisplay)(disp))->nscreens); i++) | |||||
| 1231 | { | |||||
| 1232 | Window root = RootWindow (disp, i)((&((_XPrivDisplay)(disp))->screens[i])->root); | |||||
| 1233 | XSelectInput (disp, root, SubstructureNotifyMask(1L<<19) | PropertyChangeMask(1L<<22)); | |||||
| 1234 | CheckForExistingWindows (root); | |||||
| 1235 | } | |||||
| 1236 | ||||||
| 1237 | while (1) | |||||
| 1238 | { | |||||
| 1239 | XEvent event; | |||||
| 1240 | ||||||
| 1241 | XtAppNextEvent (appContext, &event); | |||||
| 1242 | ||||||
| 1243 | switch (event.type) | |||||
| 1244 | { | |||||
| 1245 | case CreateNotify16: | |||||
| 1246 | HandleCreate (&event.xcreatewindow); | |||||
| 1247 | break; | |||||
| 1248 | ||||||
| 1249 | case DestroyNotify17: | |||||
| 1250 | HandleDestroy (&event.xdestroywindow); | |||||
| 1251 | break; | |||||
| 1252 | ||||||
| 1253 | case PropertyNotify28: | |||||
| 1254 | HandleUpdate (&event.xproperty); | |||||
| 1255 | break; | |||||
| 1256 | ||||||
| 1257 | default: | |||||
| 1258 | XtDispatchEvent (&event); | |||||
| 1259 | break; | |||||
| 1260 | } | |||||
| 1261 | } | |||||
| 1262 | exit(0); | |||||
| 1263 | } |