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 #ifdef HAVE_CONFIG_H 29 #include "config.h" 30 #endif 31 32 #include <X11/Xos.h> 33 34 #ifndef X_NOT_POSIX 35 #ifdef _POSIX_SOURCE 36 #include <limits.h> 37 #else 38 #define _POSIX_SOURCE 39 #include <limits.h> 40 #undef _POSIX_SOURCE 41 #endif 42 #endif /* X_NOT_POSIX */ 43 #ifndef PATH_MAX 44 #include <sys/param.h> 45 #ifndef PATH_MAX 46 #ifdef MAXPATHLEN 47 #define PATH_MAX MAXPATHLEN 48 #else 49 #define PATH_MAX 1024 50 #endif 51 #endif 52 #endif /* PATH_MAX */ 53 #ifdef HAVE_MKSTEMP 54 #include <unistd.h> 55 #endif 56 57 #include <X11/Xlib.h> 58 #include <X11/SM/SMlib.h> 59 #include <X11/Xatom.h> 60 #include <stdio.h> 61 #include "twm.h" 62 #include "screen.h" 63 #include "session.h" 64 65 SmcConn smcConn = NULL; 66 static XtInputId iceInputId; 67 static char *twm_clientId; 68 static TWMWinConfigEntry *winConfigHead = NULL; 69 static Bool sent_save_done = 0; 70 static SmProp *props[5]; 71 72 #define SAVEFILE_VERSION 2 73 74 #ifndef HAVE_MKSTEMP 75 static char *unique_filename(const char *path, const char *prefix); 76 #else 77 static char *unique_filename(const char *path, const char *prefix, int *pFd); 78 #endif 79 80 static char * 81 GetClientID(Window window) 82 { 83 char *client_id = NULL; 84 Window client_leader; 85 XTextProperty tp; 86 Atom actual_type; 87 int actual_format; 88 unsigned long nitems; 89 unsigned long bytes_after; 90 unsigned char *prop = NULL; 91 92 if (XGetWindowProperty(dpy, window, _XA_WM_CLIENT_LEADER, 93 0L, 1L, False, AnyPropertyType, &actual_type, 94 &actual_format, &nitems, &bytes_after, 95 &prop) == Success) { 96 if (actual_type == XA_WINDOW && actual_format == 32 && nitems == 1 && 97 bytes_after == 0) { 98 client_leader = *((Window *) prop); 99 100 if (XGetTextProperty(dpy, client_leader, &tp, _XA_SM_CLIENT_ID)) { 101 if (tp.encoding == XA_STRING && 102 tp.format == 8 && tp.nitems != 0) 103 client_id = (char *) tp.value; 104 } 105 } 106 107 if (prop) 108 XFree(prop); 109 } 110 111 return client_id; 112 } 113 114 static char * 115 GetWindowRole(Window window) 116 { 117 XTextProperty tp; 118 119 if (XGetTextProperty(dpy, window, &tp, _XA_WM_WINDOW_ROLE)) { 120 if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0) 121 return ((char *) tp.value); 122 } 123 124 return NULL; 125 } 126 127 static int 128 write_byte(FILE *file, unsigned char b) 129 { 130 if (fwrite((char *) &b, 1, 1, file) != 1) 131 return 0; 132 return 1; 133 } 134 135 static int 136 write_ushort(FILE *file, unsigned short s) 137 { 138 unsigned char file_short[2]; 139 140 file_short[0] = (unsigned char) ((s & (unsigned) 0xff00) >> 8); 141 file_short[1] = (unsigned char) (s & 0xff); 142 if (fwrite((char *) file_short, (int) sizeof(file_short), 1, file) != 1) 143 return 0; 144 return 1; 145 } 146 147 static int 148 write_short(FILE *file, short s) 149 { 150 unsigned char file_short[2]; 151 152 file_short[0] = (unsigned char) (((unsigned) s & (unsigned) 0xff00) >> 8); 153 file_short[1] = (unsigned char) (s & 0xff); 154 if (fwrite((char *) file_short, (int) sizeof(file_short), 1, file) != 1) 155 return 0; 156 return 1; 157 } 158 159 static int 160 write_counted_string(FILE *file, char *string) 161 { 162 if (string) { 163 unsigned char count = (unsigned char) strlen(string); 164 165 if (write_byte(file, count) == 0) 166 return 0; 167 if (fwrite(string, (int) sizeof(char), (int) count, file) != count) 168 return 0; 169 } 170 else { 171 if (write_byte(file, 0) == 0) 172 return 0; 173 } 174 175 return 1; 176 } 177 178 static int 179 read_byte(FILE *file, unsigned char *bp) 180 { 181 if (fread((char *) bp, 1, 1, file) != 1) 182 return 0; 183 return 1; 184 } 185 186 static int 187 read_ushort(FILE *file, unsigned short *shortp) 188 { 189 unsigned char file_short[2]; 190 191 if (fread((char *) file_short, (int) sizeof(file_short), 1, file) != 1) 192 return 0; 193 *shortp = (unsigned short) (file_short[0] * 256 + file_short[1]); 194 return 1; 195 } 196 197 static int 198 read_short(FILE *file, short *shortp) 199 { 200 unsigned char file_short[2]; 201 202 if (fread((char *) file_short, (int) sizeof(file_short), 1, file) != 1) 203 return 0; 204 *shortp = (short) (file_short[0] * 256 + file_short[1]); 205 return 1; 206 } 207 208 static int 209 read_counted_string(FILE *file, char **stringp) 210 { 211 unsigned char len; 212 char *data; 213 214 if (read_byte(file, &len) == 0) 215 return 0; 216 if (len == 0) { 217 data = NULL; 218 } 219 else { 220 data = (char *) malloc((unsigned) len + 1); 221 if (!data) 222 return 0; 223 if (fread(data, (int) sizeof(char), (int) len, file) != len) { 224 free(data); 225 return 0; 226 } 227 data[len] = '\0'; 228 } 229 *stringp = data; 230 return 1; 231 } 232 233 /* 234 * An entry in the saved window config file looks like this: 235 * 236 * FIELD BYTES 237 * ----- ---- 238 * SM_CLIENT_ID ID len 1 (may be 0) 239 * SM_CLIENT_ID LIST of bytes (may be NULL) 240 * 241 * WM_WINDOW_ROLE length 1 (may be 0) 242 * WM_WINDOW_ROLE LIST of bytes (may be NULL) 243 * 244 * if no WM_WINDOW_ROLE (length = 0) 245 * 246 * WM_CLASS "res name" length 1 247 * WM_CLASS "res name" LIST of bytes 248 * WM_CLASS "res class" length 1 249 * WM_CLASS "res class" LIST of bytes 250 * WM_NAME length 1 (0 if name changed) 251 * WM_NAME LIST of bytes 252 * WM_COMMAND arg count 1 (0 if no SM_CLIENT_ID) 253 * For each arg in WM_COMMAND 254 * arg length 1 255 * arg LIST of bytes 256 * 257 * Iconified bool 1 258 * Icon info present bool 1 259 * 260 * if icon info present 261 * icon x 2 262 * icon y 2 263 * 264 * Geom x 2 265 * Geom y 2 266 * Geom width 2 267 * Geom height 2 268 * 269 * Width ever changed by user 1 270 * Height ever changed by user 1 271 */ 272 273 static int 274 WriteWinConfigEntry(FILE *configFile, TwmWindow *theWindow, 275 char *clientId, char *windowRole) 276 { 277 char **wm_command; 278 int wm_command_count; 279 unsigned udummy = 0; 280 281 if (!write_counted_string(configFile, clientId)) 282 return 0; 283 284 if (!write_counted_string(configFile, windowRole)) 285 return 0; 286 287 if (!windowRole) { 288 if (!write_counted_string(configFile, theWindow->xclass.res_name)) 289 return 0; 290 if (!write_counted_string(configFile, theWindow->xclass.res_class)) 291 return 0; 292 if (theWindow->nameChanged) { 293 /* 294 * If WM_NAME changed on this window, we can't use it as 295 * a criteria for looking up window configurations. See the 296 * longer explanation in the GetWindowConfig() function below. 297 */ 298 299 if (!write_counted_string(configFile, NULL)) 300 return 0; 301 } 302 else { 303 if (!write_counted_string(configFile, theWindow->name)) 304 return 0; 305 } 306 307 wm_command = NULL; 308 wm_command_count = 0; 309 XGetCommand(dpy, theWindow->w, &wm_command, &wm_command_count); 310 311 if (clientId || !wm_command || wm_command_count == 0) { 312 if (!write_byte(configFile, 0)) 313 return 0; 314 } 315 else { 316 int i; 317 318 if (!write_byte(configFile, (unsigned char) wm_command_count)) 319 return 0; 320 for (i = 0; i < wm_command_count; i++) 321 if (!write_counted_string(configFile, wm_command[i])) 322 return 0; 323 XFreeStringList(wm_command); 324 } 325 } 326 327 if (!write_byte(configFile, theWindow->icon ? 1 : 0)) /* iconified */ 328 return 0; 329 330 if (!write_byte(configFile, theWindow->icon_w ? 1 : 0)) /* icon exists */ 331 return 0; 332 333 if (theWindow->icon_w) { 334 int icon_x, icon_y; 335 Window wdummy = None; 336 337 XGetGeometry(dpy, theWindow->icon_w, &wdummy, &icon_x, 338 &icon_y, &udummy, &udummy, &udummy, &udummy); 339 340 if (!write_short(configFile, (short) icon_x)) 341 return 0; 342 if (!write_short(configFile, (short) icon_y)) 343 return 0; 344 } 345 346 if (!write_short(configFile, (short) theWindow->frame_x)) 347 return 0; 348 if (!write_short(configFile, (short) theWindow->frame_y)) 349 return 0; 350 if (!write_ushort(configFile, (unsigned short) theWindow->attr.width)) 351 return 0; 352 if (!write_ushort(configFile, (unsigned short) theWindow->attr.height)) 353 return 0; 354 355 if (!write_byte(configFile, theWindow->widthEverChangedByUser ? 1 : 0)) 356 return 0; 357 358 if (!write_byte(configFile, theWindow->heightEverChangedByUser ? 1 : 0)) 359 return 0; 360 361 return 1; 362 } 363 364 static int 365 ReadWinConfigEntry(FILE *configFile, unsigned short version, 366 TWMWinConfigEntry **pentry) 367 { 368 TWMWinConfigEntry *entry; 369 unsigned char byte; 370 int i; 371 372 *pentry = entry = (TWMWinConfigEntry *) malloc(sizeof(TWMWinConfigEntry)); 373 if (!*pentry) 374 return 0; 375 376 entry->tag = 0; 377 entry->client_id = NULL; 378 entry->window_role = NULL; 379 entry->xclass.res_name = NULL; 380 entry->xclass.res_class = NULL; 381 entry->wm_name = NULL; 382 entry->wm_command = NULL; 383 entry->wm_command_count = 0; 384 385 if (!read_counted_string(configFile, &entry->client_id)) 386 goto give_up; 387 388 if (!read_counted_string(configFile, &entry->window_role)) 389 goto give_up; 390 391 if (!entry->window_role) { 392 if (!read_counted_string(configFile, &entry->xclass.res_name)) 393 goto give_up; 394 if (!read_counted_string(configFile, &entry->xclass.res_class)) 395 goto give_up; 396 if (!read_counted_string(configFile, &entry->wm_name)) 397 goto give_up; 398 399 if (!read_byte(configFile, &byte)) 400 goto give_up; 401 entry->wm_command_count = byte; 402 403 if (entry->wm_command_count == 0) 404 entry->wm_command = NULL; 405 else { 406 entry->wm_command = (char **) 407 malloc((size_t) entry->wm_command_count * sizeof(char *)); 408 409 if (!entry->wm_command) 410 goto give_up; 411 412 for (i = 0; i < entry->wm_command_count; i++) 413 if (!read_counted_string(configFile, &entry->wm_command[i])) 414 goto give_up; 415 } 416 } 417 418 if (!read_byte(configFile, &byte)) 419 goto give_up; 420 entry->iconified = byte; 421 422 if (!read_byte(configFile, &byte)) 423 goto give_up; 424 entry->icon_info_present = byte; 425 426 if (entry->icon_info_present) { 427 if (!read_short(configFile, (short *) &entry->icon_x)) 428 goto give_up; 429 if (!read_short(configFile, (short *) &entry->icon_y)) 430 goto give_up; 431 } 432 433 if (!read_short(configFile, (short *) &entry->x)) 434 goto give_up; 435 if (!read_short(configFile, (short *) &entry->y)) 436 goto give_up; 437 if (!read_ushort(configFile, &entry->width)) 438 goto give_up; 439 if (!read_ushort(configFile, &entry->height)) 440 goto give_up; 441 442 if (version > 1) { 443 if (!read_byte(configFile, &byte)) 444 goto give_up; 445 entry->width_ever_changed_by_user = byte; 446 447 if (!read_byte(configFile, &byte)) 448 goto give_up; 449 entry->height_ever_changed_by_user = byte; 450 } 451 else { 452 entry->width_ever_changed_by_user = False; 453 entry->height_ever_changed_by_user = False; 454 } 455 456 return 1; 457 458 give_up: 459 460 if (entry->client_id) 461 free(entry->client_id); 462 if (entry->window_role) 463 free(entry->window_role); 464 if (entry->xclass.res_name) 465 free(entry->xclass.res_name); 466 if (entry->xclass.res_class) 467 free(entry->xclass.res_class); 468 if (entry->wm_name) 469 free(entry->wm_name); 470 if (entry->wm_command_count && entry->wm_command) { 471 for (i = 0; i < entry->wm_command_count; i++) 472 if (entry->wm_command[i]) 473 free(entry->wm_command[i]); 474 } 475 if (entry->wm_command) 476 free(entry->wm_command); 477 478 free(entry); 479 *pentry = NULL; 480 481 return 0; 482 } 483 484 void 485 ReadWinConfigFile(char *filename) 486 { 487 FILE *configFile; 488 TWMWinConfigEntry *entry; 489 int done = 0; 490 unsigned short version = 0; 491 492 configFile = fopen(filename, "rb"); 493 if (!configFile) 494 return; 495 496 if (!read_ushort(configFile, &version) || version > SAVEFILE_VERSION) { 497 done = 1; 498 } 499 500 while (!done) { 501 if (ReadWinConfigEntry(configFile, version, &entry)) { 502 entry->next = winConfigHead; 503 winConfigHead = entry; 504 } 505 else 506 done = 1; 507 } 508 509 fclose(configFile); 510 } 511 512 int 513 GetWindowConfig(TwmWindow *theWindow, 514 short *x, short *y, 515 unsigned short *width, unsigned short *height, 516 Bool *iconified, 517 Bool *icon_info_present, 518 short *icon_x, short *icon_y, 519 Bool *width_ever_changed_by_user, 520 Bool *height_ever_changed_by_user) 521 { 522 char *clientId, *windowRole; 523 TWMWinConfigEntry *ptr; 524 int found = 0; 525 526 ptr = winConfigHead; 527 528 if (!ptr) 529 return 0; 530 531 clientId = GetClientID(theWindow->w); 532 windowRole = GetWindowRole(theWindow->w); 533 534 while (ptr && !found) { 535 int client_id_match = (!clientId && !ptr->client_id) || 536 (clientId && ptr->client_id && 537 strcmp(clientId, ptr->client_id) == 0); 538 539 if (!ptr->tag && client_id_match) { 540 if (windowRole || ptr->window_role) { 541 found = (windowRole && ptr->window_role && 542 strcmp(windowRole, ptr->window_role) == 0); 543 } 544 else { 545 /* 546 * Compare WM_CLASS + only compare WM_NAME if the 547 * WM_NAME in the saved file is non-NULL. If the 548 * WM_NAME in the saved file is NULL, this means that 549 * the client changed the value of WM_NAME during the 550 * session, and we can not use it as a criteria for 551 * our search. For example, with xmh, at save time 552 * the window name might be "xmh: folderY". However, 553 * if xmh does not properly restore state when it is 554 * restarted, the initial window name might be 555 * "xmh: folderX". This would cause the window manager 556 * to fail in finding the saved window configuration. 557 * The best we can do is ignore WM_NAME if its value 558 * changed in the previous session. 559 */ 560 561 if (strcmp(theWindow->xclass.res_name, 562 ptr->xclass.res_name) == 0 && 563 strcmp(theWindow->xclass.res_class, 564 ptr->xclass.res_class) == 0 && 565 (ptr->wm_name == NULL || 566 strcmp(theWindow->name, ptr->wm_name) == 0)) { 567 if (clientId) { 568 /* 569 * If a client ID was present, we should not check 570 * WM_COMMAND because Xt will put a -xtsessionID arg 571 * on the command line. 572 */ 573 574 found = 1; 575 } 576 else { 577 /* 578 * For non-XSMP clients, also check WM_COMMAND. 579 */ 580 581 char **wm_command = NULL; 582 int wm_command_count = 0; 583 584 XGetCommand(dpy, theWindow->w, 585 &wm_command, &wm_command_count); 586 587 if (wm_command_count == ptr->wm_command_count) { 588 int i; 589 590 for (i = 0; i < wm_command_count; i++) 591 if (strcmp(wm_command[i], 592 ptr->wm_command[i]) != 0) 593 break; 594 595 if (i == wm_command_count) 596 found = 1; 597 } 598 } 599 } 600 } 601 } 602 603 if (!found) 604 ptr = ptr->next; 605 } 606 607 if (found) { 608 *x = ptr->x; 609 *y = ptr->y; 610 *width = ptr->width; 611 *height = ptr->height; 612 *iconified = ptr->iconified; 613 *icon_info_present = ptr->icon_info_present; 614 *width_ever_changed_by_user = ptr->width_ever_changed_by_user; 615 *height_ever_changed_by_user = ptr->height_ever_changed_by_user; 616 617 if (*icon_info_present) { 618 *icon_x = ptr->icon_x; 619 *icon_y = ptr->icon_y; 620 } 621 ptr->tag = 1; 622 } 623 else 624 *iconified = 0; 625 626 if (clientId) 627 XFree(clientId); 628 629 if (windowRole) 630 XFree(windowRole); 631 632 return found; 633 } 634 635 #ifndef HAVE_MKSTEMP 636 static char * 637 unique_filename(const char *path, const char *prefix) 638 #else 639 static char * 640 unique_filename(const char *path, const char *prefix, int *pFd) 641 #endif 642 { 643 #ifndef HAVE_MKSTEMP 644 #ifndef X_NOT_POSIX 645 return ((char *) tempnam(path, prefix)); 646 #else 647 char tempFile[PATH_MAX]; 648 char *tmp; 649 650 snprintf(tempFile, sizeof(tempFile), "%s/%sXXXXXX", path, prefix); 651 tmp = (char *) mktemp(tempFile); 652 if (tmp) 653 return strdup(tmp); 654 else 655 return (NULL); 656 #endif 657 #else 658 char tempFile[PATH_MAX]; 659 char *ptr; 660 661 snprintf(tempFile, sizeof(tempFile), "%s/%sXXXXXX", path, prefix); 662 ptr = strdup(tempFile); 663 if (ptr != NULL) 664 *pFd = mkstemp(ptr); 665 return ptr; 666 #endif 667 } 668 669 static void 670 SaveYourselfPhase2CB(SmcConn smcConn2, SmPointer clientData _X_UNUSED) 671 { 672 int scrnum; 673 ScreenInfo *theScreen; 674 TwmWindow *theWindow; 675 char *clientId, *windowRole; 676 FILE *configFile = NULL; 677 const char *path; 678 char *filename = NULL; 679 Bool success = False; 680 char discardCommand[80]; 681 int numVals, i; 682 static int first_time = 1; 683 684 #ifdef HAVE_MKSTEMP 685 int fd; 686 #endif 687 688 if (first_time) { 689 char userId[20]; 690 char *hint; 691 692 props[0] = (SmProp *) calloc(1, sizeof(SmProp)); 693 props[0]->name = strdup(SmProgram); 694 props[0]->type = strdup(SmARRAY8); 695 props[0]->num_vals = 1; 696 props[0]->vals = (SmPropValue *) calloc(1, sizeof(SmPropValue)); 697 props[0]->vals[0].value = strdup(Argv[0]); 698 props[0]->vals[0].length = (int) strlen(Argv[0]); 699 700 snprintf(userId, sizeof(userId), "%ld", (long) getuid()); 701 702 props[1] = (SmProp *) calloc(1, sizeof(SmProp)); 703 props[1]->name = strdup(SmUserID); 704 props[1]->type = strdup(SmARRAY8); 705 props[1]->num_vals = 1; 706 props[1]->vals = (SmPropValue *) calloc(1, sizeof(SmPropValue)); 707 props[1]->vals[0].value = strdup(userId); 708 props[1]->vals[0].length = (int) strlen(userId); 709 710 hint = (char *) malloc(1); 711 hint[0] = SmRestartIfRunning; 712 713 props[2] = (SmProp *) calloc(1, sizeof(SmProp)); 714 props[2]->name = strdup(SmRestartStyleHint); 715 props[2]->type = strdup(SmCARD8); 716 props[2]->num_vals = 1; 717 props[2]->vals = (SmPropValue *) calloc(1, sizeof(SmPropValue)); 718 props[2]->vals[0].value = hint; 719 props[2]->vals[0].length = 1; 720 721 SmcSetProperties(smcConn2, 3, props); 722 first_time = 0; 723 } 724 725 path = getenv("SM_SAVE_DIR"); 726 if (!path) { 727 path = getenv("HOME"); 728 if (!path) 729 path = "."; 730 } 731 #ifndef HAVE_MKSTEMP 732 if ((filename = unique_filename(path, ".twm")) == NULL) 733 goto bad; 734 735 if (!(configFile = fopen(filename, "wb"))) 736 goto bad; 737 #else 738 if ((filename = unique_filename(path, ".twm", &fd)) == NULL) 739 goto bad; 740 741 if (!(configFile = fdopen(fd, "wb"))) 742 goto bad; 743 #endif 744 745 if (!write_ushort(configFile, SAVEFILE_VERSION)) 746 goto bad; 747 748 success = True; 749 750 for (scrnum = 0; scrnum < NumScreens && success; scrnum++) { 751 if (ScreenList[scrnum] != NULL) { 752 theScreen = ScreenList[scrnum]; 753 theWindow = theScreen->TwmRoot.next; 754 755 while (theWindow && success) { 756 clientId = GetClientID(theWindow->w); 757 windowRole = GetWindowRole(theWindow->w); 758 759 if (!WriteWinConfigEntry(configFile, theWindow, 760 clientId, windowRole)) 761 success = False; 762 763 if (clientId) 764 XFree(clientId); 765 766 if (windowRole) 767 XFree(windowRole); 768 769 theWindow = theWindow->next; 770 } 771 } 772 } 773 774 props[3] = (SmProp *) calloc(1, sizeof(SmProp)); 775 props[3]->name = strdup(SmRestartCommand); 776 props[3]->type = strdup(SmLISTofARRAY8); 777 props[3]->vals = (SmPropValue *) calloc((size_t)(Argc + 4), sizeof(SmPropValue)); 778 779 if (!props[3]->vals) { 780 success = False; 781 goto bad; 782 } 783 784 numVals = 0; 785 786 for (i = 0; i < Argc; i++) { 787 if (strcmp(Argv[i], "-clientId") == 0 || 788 strcmp(Argv[i], "-restore") == 0) { 789 i++; 790 } 791 else { 792 props[3]->vals[numVals].value = (SmPointer) strdup(Argv[i]); 793 props[3]->vals[numVals++].length = (int) strlen(Argv[i]); 794 } 795 } 796 797 props[3]->vals[numVals].value = strdup("-clientId"); 798 props[3]->vals[numVals++].length = 9; 799 800 props[3]->vals[numVals].value = strdup(twm_clientId); 801 props[3]->vals[numVals++].length = (int) strlen(twm_clientId); 802 803 props[3]->vals[numVals].value = strdup("-restore"); 804 props[3]->vals[numVals++].length = 8; 805 806 props[3]->vals[numVals].value = strdup(filename); 807 props[3]->vals[numVals++].length = (int) strlen(filename); 808 809 props[3]->num_vals = numVals; 810 811 snprintf(discardCommand, sizeof(discardCommand), "rm %s", filename); 812 813 props[4] = (SmProp *) calloc(1, sizeof(SmProp)); 814 props[4]->name = strdup(SmDiscardCommand); 815 props[4]->type = strdup(SmARRAY8); 816 props[4]->num_vals = 1; 817 props[4]->vals = (SmPropValue *) calloc(1, sizeof(SmPropValue)); 818 props[4]->vals[0].value = strdup(discardCommand); 819 props[4]->vals[0].length = (int) strlen(discardCommand); 820 821 SmcSetProperties(smcConn2, 2, props + 3); 822 823 bad: 824 SmcSaveYourselfDone(smcConn2, success); 825 sent_save_done = 1; 826 827 if (configFile) 828 fclose(configFile); 829 830 if (filename) 831 free(filename); 832 } 833 834 static void 835 SaveYourselfCB(SmcConn smcConn2, 836 SmPointer clientData _X_UNUSED, 837 int saveType _X_UNUSED, 838 Bool shutdown _X_UNUSED, 839 int interactStyle _X_UNUSED, Bool fast _X_UNUSED) 840 { 841 if (!SmcRequestSaveYourselfPhase2(smcConn2, SaveYourselfPhase2CB, NULL)) { 842 SmcSaveYourselfDone(smcConn2, False); 843 sent_save_done = 1; 844 } 845 else 846 sent_save_done = 0; 847 } 848 849 static _X_NORETURN void 850 DieCB(SmcConn smcConn2, SmPointer clientData _X_UNUSED) 851 { 852 SmcCloseConnection(smcConn2, 0, NULL); 853 XtRemoveInput(iceInputId); 854 Done(NULL, NULL); 855 } 856 857 static void 858 SaveCompleteCB(SmcConn smcConnm _X_UNUSED, SmPointer clientData _X_UNUSED) 859 { 860 ; 861 } 862 863 static void 864 ShutdownCancelledCB(SmcConn smcConn2, SmPointer clientData _X_UNUSED) 865 { 866 if (!sent_save_done) { 867 SmcSaveYourselfDone(smcConn2, False); 868 sent_save_done = 1; 869 } 870 } 871 872 static void 873 ProcessIceMsgProc(XtPointer client_data, int *source _X_UNUSED, 874 XtInputId *id _X_UNUSED) 875 { 876 IceConn ice_conn = (IceConn) client_data; 877 878 IceProcessMessages(ice_conn, NULL, NULL); 879 } 880 881 void 882 ConnectToSessionManager(char *previous_id, XtAppContext appContext) 883 { 884 char errorMsg[256]; 885 unsigned long mask; 886 SmcCallbacks callbacks; 887 IceConn iceConn; 888 889 mask = SmcSaveYourselfProcMask | SmcDieProcMask | 890 SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; 891 892 callbacks.save_yourself.callback = SaveYourselfCB; 893 callbacks.save_yourself.client_data = (SmPointer) NULL; 894 895 callbacks.die.callback = DieCB; 896 callbacks.die.client_data = (SmPointer) NULL; 897 898 callbacks.save_complete.callback = SaveCompleteCB; 899 callbacks.save_complete.client_data = (SmPointer) NULL; 900 901 callbacks.shutdown_cancelled.callback = ShutdownCancelledCB; 902 callbacks.shutdown_cancelled.client_data = (SmPointer) NULL; 903 904 smcConn = SmcOpenConnection(NULL, /* use SESSION_MANAGER env */ 905 (SmPointer) appContext, 906 SmProtoMajor, 907 SmProtoMinor, 908 mask, 909 &callbacks, 910 previous_id, &twm_clientId, 256, errorMsg); 911 912 if (smcConn == NULL) 913 return; 914 915 iceConn = SmcGetIceConnection(smcConn); 916 917 iceInputId = XtAppAddInput(appContext, 918 IceConnectionNumber(iceConn), 919 (XtPointer) XtInputReadMask, 920 ProcessIceMsgProc, (XtPointer) iceConn); 921 } 922 923 void 924 DestroySession(void) 925 { 926 int i; 927 for (i = 0; i < 5; ++i) { 928 if (props[i]) { 929 SmFreeProperty(props[i]); 930 } 931 } 932 } 933