choose.c revision 1a650d1e
1/* $Xorg: choose.c,v 1.4 2001/02/09 02:05:59 xorgcvs Exp $ */ 2/****************************************************************************** 3 4Copyright 1993, 1998 The Open Group 5 6Permission to use, copy, modify, distribute, and sell this software and its 7documentation for any purpose is hereby granted without fee, provided that 8the above copyright notice appear in all copies and that both that 9copyright notice and this permission notice appear in supporting 10documentation. 11 12The above copyright notice and this permission notice shall be included in 13all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall not be 23used in advertising or otherwise to promote the sale, use or other dealings 24in this Software without prior written authorization from The Open Group. 25******************************************************************************/ 26/* $XFree86: xc/programs/xsm/choose.c,v 1.6tsi Exp $ */ 27 28#include "xsm.h" 29#include "saveutil.h" 30#include "lock.h" 31#include "choose.h" 32#include <sys/types.h> 33 34#include <X11/Shell.h> 35#include <X11/Xaw/Form.h> 36#include <X11/Xaw/List.h> 37#include <X11/Xaw/Command.h> 38 39#ifndef X_NOT_POSIX 40#include <dirent.h> 41#else 42#ifdef SYSV 43#include <dirent.h> 44#else 45#ifdef USG 46#include <dirent.h> 47#else 48#include <sys/dir.h> 49#ifndef dirent 50#define dirent direct 51#endif 52#endif 53#endif 54#endif 55 56static Pixel save_message_foreground; 57static Pixel save_message_background; 58 59static int delete_session_phase = 0; 60static int break_lock_phase = 0; 61 62static Widget chooseSessionPopup; 63static Widget chooseSessionForm; 64static Widget chooseSessionLabel; 65static Widget chooseSessionListWidget; 66static Widget chooseSessionMessageLabel; 67static Widget chooseSessionLoadButton; 68static Widget chooseSessionDeleteButton; 69static Widget chooseSessionBreakLockButton; 70static Widget chooseSessionFailSafeButton; 71static Widget chooseSessionCancelButton; 72 73 74 75int 76GetSessionNames(int *count_ret, String **short_names_ret, 77 String **long_names_ret, Bool **locked_ret) 78{ 79 DIR *dir; 80 struct dirent *entry; 81 char *path; 82 int count; 83 84 path = (char *) getenv ("SM_SAVE_DIR"); 85 if (!path) 86 { 87 path = (char *) getenv ("HOME"); 88 if (!path) 89 path = "."; 90 } 91 92 *count_ret = 0; 93 *short_names_ret = NULL; 94 *locked_ret = NULL; 95 if (long_names_ret) 96 *long_names_ret = NULL; 97 98 if ((dir = opendir (path)) == NULL) 99 return 0; 100 101 count = 0; 102 103 while ((entry = readdir (dir)) != NULL) 104 { 105 if (strncmp (entry->d_name, ".XSM-", 5) == 0) 106 count++; 107 } 108 109 if (count == 0 || 110 ((*short_names_ret = (String *) XtMalloc ( 111 count * sizeof (String))) == NULL) || 112 (long_names_ret && (*long_names_ret = 113 (String *) XtMalloc (count * sizeof (String))) == NULL) || 114 ((*locked_ret = (Bool *) XtMalloc (count * sizeof (Bool))) == NULL)) 115 { 116 closedir (dir); 117 if (*short_names_ret) 118 XtFree ((char *) *short_names_ret); 119 if (long_names_ret && *long_names_ret) 120 XtFree ((char *) *long_names_ret); 121 return 0; 122 } 123 124 rewinddir (dir); 125 126 while ((entry = readdir (dir)) != NULL && *count_ret < count) 127 { 128 if (strncmp (entry->d_name, ".XSM-", 5) == 0) 129 { 130 char *name = (char *) entry->d_name + 5; 131 char *id = NULL; 132 Bool locked = CheckSessionLocked (name, long_names_ret!=NULL, &id); 133 134 (*short_names_ret)[*count_ret] = XtNewString (name); 135 (*locked_ret)[*count_ret] = locked; 136 137 if (long_names_ret) 138 { 139 if (!locked) 140 { 141 (*long_names_ret)[*count_ret] = 142 (*short_names_ret)[*count_ret]; 143 } 144 else 145 { 146 char *host = ((char *) strchr (id, '/')) + 1; 147 char *colon = (char *) strrchr (host, ':'); 148 149 /* backtrack over previous colon if there are 2 (DECnet), 150 but not three (IPv6) */ 151 if ((*(colon - 1) == ':') && (*(colon - 2) != ':')) 152 colon--; 153 154 *colon = '\0'; 155 156 (*long_names_ret)[*count_ret] = 157 XtMalloc (strlen (name) + strlen (host) + 14); 158 159 sprintf ((*long_names_ret)[*count_ret], 160 "%s (locked at %s)", name, host); 161 *colon = ':'; 162 163 XtFree (id); 164 } 165 } 166 167 (*count_ret)++; 168 } 169 } 170 171 closedir (dir); 172 173 return 1; 174} 175 176 177 178void 179FreeSessionNames(int count, String *namesShort, String *namesLong, 180 Bool *lockFlags) 181{ 182 int i; 183 184 for (i = 0; i < count; i++) 185 XtFree ((char *) namesShort[i]); 186 XtFree ((char *) namesShort); 187 188 if (namesLong) 189 { 190 for (i = 0; i < count; i++) 191 if (lockFlags[i]) 192 XtFree ((char *) namesLong[i]); 193 XtFree ((char *) namesLong); 194 } 195 196 XtFree ((char *) lockFlags); 197} 198 199 200 201static void 202SessionSelected(int number, Bool highlight) 203{ 204 if (number >= 0) 205 { 206 Bool locked = sessionsLocked[number]; 207 208 if (highlight) 209 XawListHighlight (chooseSessionListWidget, number); 210 211 XtSetSensitive (chooseSessionLoadButton, !locked); 212 XtSetSensitive (chooseSessionDeleteButton, !locked); 213 XtSetSensitive (chooseSessionBreakLockButton, locked); 214 } 215 else 216 { 217 XtSetSensitive (chooseSessionLoadButton, False); 218 XtSetSensitive (chooseSessionDeleteButton, False); 219 XtSetSensitive (chooseSessionBreakLockButton, False); 220 } 221} 222 223 224 225static void 226AddSessionNames(int count, String *names) 227{ 228 int i; 229 230 XawListChange (chooseSessionListWidget, names, count, 0, True); 231 232 /* 233 * Highlight the first unlocked session, if any. 234 */ 235 236 for (i = 0; i < sessionNameCount; i++) 237 if (!sessionsLocked[i]) 238 break; 239 240 SessionSelected (i < sessionNameCount ? i : -1, True); 241} 242 243 244 245void 246ChooseWindowStructureNotifyXtHandler(Widget w, XtPointer closure, 247 XEvent *event, 248 Boolean *continue_to_dispatch) 249{ 250 if (event->type == MapNotify) 251 { 252 /* 253 * Set the input focus to the choose window and direct all keyboard 254 * events to the list widget. This way, the user can make selections 255 * using the keyboard. 256 */ 257 258 XtSetKeyboardFocus (chooseSessionPopup, chooseSessionListWidget); 259 260 XSetInputFocus (XtDisplay (topLevel), XtWindow (chooseSessionPopup), 261 RevertToPointerRoot, CurrentTime); 262 263 XSync (XtDisplay (topLevel), 0); 264 265 XtRemoveEventHandler (chooseSessionPopup, StructureNotifyMask, False, 266 ChooseWindowStructureNotifyXtHandler, NULL); 267 } 268} 269 270 271void 272ChooseSession(void) 273{ 274 Dimension width, height; 275 Position x, y; 276 277 278 /* 279 * Add the session names to the list 280 */ 281 282 AddSessionNames (sessionNameCount, sessionNamesLong); 283 284 285 /* 286 * Center popup containing choice of sessions 287 */ 288 289 XtRealizeWidget (chooseSessionPopup); 290 291 XtVaGetValues (chooseSessionPopup, 292 XtNwidth, &width, 293 XtNheight, &height, 294 NULL); 295 296 x = (Position)(WidthOfScreen (XtScreen (topLevel)) - width) / 2; 297 y = (Position)(HeightOfScreen (XtScreen (topLevel)) - height) / 3; 298 299 XtVaSetValues (chooseSessionPopup, 300 XtNx, x, 301 XtNy, y, 302 NULL); 303 304 XtVaSetValues (chooseSessionListWidget, 305 XtNlongest, width, 306 NULL); 307 308 XtVaSetValues (chooseSessionLabel, 309 XtNwidth, width, 310 NULL); 311 312 XtVaGetValues (chooseSessionMessageLabel, 313 XtNforeground, &save_message_foreground, 314 XtNbackground, &save_message_background, 315 NULL); 316 317 XtVaSetValues (chooseSessionMessageLabel, 318 XtNwidth, width, 319 XtNforeground, save_message_background, 320 NULL); 321 322 /* 323 * Wait for a map notify on the popup, then set input focus. 324 */ 325 326 XtAddEventHandler (chooseSessionPopup, StructureNotifyMask, False, 327 ChooseWindowStructureNotifyXtHandler, NULL); 328 329 XtPopup (chooseSessionPopup, XtGrabNone); 330} 331 332 333 334static void 335CheckDeleteCancel (void) 336{ 337 if (delete_session_phase > 0) 338 { 339 XtVaSetValues (chooseSessionMessageLabel, 340 XtNforeground, save_message_background, 341 NULL); 342 343 delete_session_phase = 0; 344 } 345} 346 347 348static void 349CheckBreakLockCancel(void) 350{ 351 if (break_lock_phase > 0) 352 { 353 XtVaSetValues (chooseSessionMessageLabel, 354 XtNforeground, save_message_background, 355 NULL); 356 357 break_lock_phase = 0; 358 } 359} 360 361 362 363static void 364ChooseSessionUp(Widget w, XEvent *event, String *params, Cardinal *numParams) 365{ 366 XawListReturnStruct *current; 367 368 CheckDeleteCancel (); 369 CheckBreakLockCancel (); 370 371 current = XawListShowCurrent (chooseSessionListWidget); 372 if (current->list_index > 0) 373 SessionSelected (current->list_index - 1, True); 374 XtFree ((char *) current); 375} 376 377 378static void 379ChooseSessionDown(Widget w, XEvent *event, String *params, Cardinal *numParams) 380{ 381 XawListReturnStruct *current; 382 383 CheckDeleteCancel (); 384 CheckBreakLockCancel (); 385 386 current = XawListShowCurrent (chooseSessionListWidget); 387 if (current->list_index < sessionNameCount - 1) 388 SessionSelected (current->list_index + 1, True); 389 XtFree ((char *) current); 390} 391 392 393 394static void 395ChooseSessionBtn1Down(Widget w, XEvent *event, String *params, 396 Cardinal *numParams) 397{ 398 XawListReturnStruct *current; 399 400 CheckDeleteCancel (); 401 CheckBreakLockCancel (); 402 403 current = XawListShowCurrent (chooseSessionListWidget); 404 SessionSelected (current->list_index, False /* already highlighted */); 405 XtFree ((char *) current); 406} 407 408 409 410static void 411ChooseSessionLoadXtProc(Widget w, XtPointer client_data, XtPointer callData) 412{ 413 XawListReturnStruct *current; 414 415 CheckDeleteCancel (); 416 CheckBreakLockCancel (); 417 418 current = XawListShowCurrent (chooseSessionListWidget); 419 420 if (!current || !current->string || *(current->string) == '\0') 421 { 422 if (current) 423 XtFree ((char *) current); 424#ifdef XKB 425 XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_BadValue); 426#else 427 XBell (XtDisplay (topLevel), 0); 428#endif 429 return; 430 } 431 432 /* 433 * Pop down choice of sessions and start the specified session. 434 */ 435 436 XtPopdown (chooseSessionPopup); 437 438 if (session_name) 439 XtFree (session_name); 440 441 session_name = XtNewString (current->string); 442 443 XtFree ((char *) current); 444 445 FreeSessionNames (sessionNameCount, 446 sessionNamesShort, sessionNamesLong, sessionsLocked); 447 448 449 /* 450 * Start the session, looking for .XSM-<session name> startup file. 451 */ 452 453 if (!StartSession (session_name, False)) 454 UnableToLockSession (session_name); 455} 456 457 458 459static void 460ChooseSessionDeleteXtProc(Widget w, XtPointer client_data, XtPointer callData) 461{ 462 XawListReturnStruct *current; 463 int longest; 464 char *name; 465 466 CheckBreakLockCancel (); 467 468 current = XawListShowCurrent (chooseSessionListWidget); 469 470 if (!current || !(name = current->string) || *name == '\0') 471 { 472 if (current) 473 XtFree ((char *) current); 474#ifdef XKB 475 XkbStdBell(XtDisplay(w),XtWindow(w),0,XkbBI_BadValue); 476#else 477 XBell (XtDisplay (topLevel), 0); 478#endif 479 return; 480 } 481 482 delete_session_phase++; 483 484 if (delete_session_phase == 1) 485 { 486 XtVaSetValues (chooseSessionMessageLabel, 487 XtNforeground, save_message_foreground, 488 NULL); 489 490#ifdef XKB 491 XkbStdBell(XtDisplay(w),XtWindow(w),0,XkbBI_BadValue); 492#else 493 XBell (XtDisplay (topLevel), 0); 494#endif 495 } 496 else 497 { 498 XtVaSetValues (chooseSessionMessageLabel, 499 XtNforeground, save_message_background, 500 NULL); 501 502 if (DeleteSession (name)) 503 { 504 int i, j; 505 506 for (i = 0; i < sessionNameCount; i++) 507 { 508 if (strcmp (sessionNamesLong[i], name) == 0) 509 { 510 XtFree ((char *) sessionNamesShort[i]); 511 512 if (sessionsLocked[i]) 513 XtFree ((char *) sessionNamesLong[i]); 514 515 for (j = i; j < sessionNameCount - 1; j++) 516 { 517 sessionNamesLong[j] = sessionNamesLong[j + 1]; 518 sessionNamesShort[j] = sessionNamesShort[j + 1]; 519 sessionsLocked[j] = sessionsLocked[j + 1]; 520 } 521 sessionNameCount--; 522 break; 523 } 524 } 525 526 if (sessionNameCount == 0) 527 { 528 XtSetSensitive (chooseSessionLoadButton, 0); 529 XtSetSensitive (chooseSessionDeleteButton, 0); 530 XtUnmanageChild (chooseSessionListWidget); 531 } 532 else 533 { 534 XtVaGetValues (chooseSessionListWidget, 535 XtNlongest, &longest, 536 NULL); 537 538 XawListChange (chooseSessionListWidget, 539 sessionNamesLong, sessionNameCount, longest, True); 540 541 SessionSelected (-1, False); 542 } 543 } 544 545 delete_session_phase = 0; 546 } 547 548 XtFree ((char *) current); 549} 550 551 552 553static void 554ChooseSessionBreakLockXtProc(Widget w, XtPointer client_data, 555 XtPointer callData) 556{ 557 XawListReturnStruct *current; 558 char *name; 559 560 CheckDeleteCancel (); 561 562 current = XawListShowCurrent (chooseSessionListWidget); 563 564 if (!current || !(name = current->string) || *name == '\0') 565 { 566 if (current) 567 XtFree ((char *) current); 568#ifdef XKB 569 XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_BadValue); 570#else 571 XBell (XtDisplay (topLevel), 0); 572#endif 573 return; 574 } 575 576 break_lock_phase++; 577 578 if (break_lock_phase == 1) 579 { 580 XtVaSetValues (chooseSessionMessageLabel, 581 XtNforeground, save_message_foreground, 582 NULL); 583 584#ifdef XKB 585 XkbStdBell(XtDisplay(topLevel),XtWindow(topLevel),0,XkbBI_BadValue); 586#else 587 XBell (XtDisplay (topLevel), 0); 588#endif 589 } 590 else 591 { 592 int longest; 593 594 XtVaSetValues (chooseSessionMessageLabel, 595 XtNforeground, save_message_background, 596 NULL); 597 598 name = sessionNamesShort[current->list_index]; 599 600 (void) GetLockId (name); 601 602 UnlockSession (name); 603 604 sessionsLocked[current->list_index] = False; 605 XtFree ((char *) sessionNamesLong[current->list_index]); 606 sessionNamesLong[current->list_index] = 607 sessionNamesShort[current->list_index]; 608 609 XtVaGetValues (chooseSessionListWidget, 610 XtNlongest, &longest, 611 NULL); 612 613 XawListChange (chooseSessionListWidget, 614 sessionNamesLong, sessionNameCount, longest, True); 615 616 SessionSelected (current->list_index, True); 617 618 break_lock_phase = 0; 619 } 620 621 XtFree ((char *) current); 622} 623 624 625 626static void 627ChooseSessionFailSafeXtProc(Widget w, XtPointer client_data, 628 XtPointer callData) 629{ 630 /* 631 * Pop down choice of sessions, and start the fail safe session. 632 */ 633 634 CheckDeleteCancel (); 635 CheckBreakLockCancel (); 636 637 XtPopdown (chooseSessionPopup); 638 639 if (session_name) 640 XtFree (session_name); 641 642 session_name = XtNewString (FAILSAFE_SESSION_NAME); 643 644 FreeSessionNames (sessionNameCount, 645 sessionNamesShort, sessionNamesLong, sessionsLocked); 646 647 648 /* 649 * We don't need to check return value of StartSession in this case, 650 * because we are using the default session, and StartSession will 651 * not try to lock the session at this time. It will try to lock 652 * it as soon as the user gives the session a name. 653 */ 654 655 StartSession (session_name, 656 True /* Use ~/.xsmstartup if found, else system.xsm */); 657} 658 659 660 661static void 662ChooseSessionCancelXtProc(Widget w, XtPointer client_data, XtPointer callData) 663{ 664 if (delete_session_phase > 0 || break_lock_phase > 0) 665 { 666 XtVaSetValues (chooseSessionMessageLabel, 667 XtNforeground, save_message_background, 668 NULL); 669 670 delete_session_phase = 0; 671 break_lock_phase = 0; 672 } 673 else 674 EndSession (2); 675} 676 677 678 679void 680create_choose_session_popup(void) 681 682{ 683 static XtActionsRec choose_actions[] = { 684 {"ChooseSessionUp", ChooseSessionUp}, 685 {"ChooseSessionDown", ChooseSessionDown}, 686 {"ChooseSessionBtn1Down", ChooseSessionBtn1Down} 687 }; 688 689 /* 690 * Pop up for choosing session at startup 691 */ 692 693 chooseSessionPopup = XtVaCreatePopupShell ( 694 "chooseSessionPopup", transientShellWidgetClass, topLevel, 695 XtNallowShellResize, True, 696 NULL); 697 698 699 chooseSessionForm = XtVaCreateManagedWidget ( 700 "chooseSessionForm", formWidgetClass, chooseSessionPopup, 701 NULL); 702 703 704 chooseSessionLabel = XtVaCreateManagedWidget ( 705 "chooseSessionLabel", labelWidgetClass, chooseSessionForm, 706 XtNfromHoriz, NULL, 707 XtNfromVert, NULL, 708 XtNborderWidth, 0, 709 XtNresizable, True, 710 XtNjustify, XtJustifyCenter, 711 NULL); 712 713 chooseSessionListWidget = XtVaCreateManagedWidget ( 714 "chooseSessionListWidget", listWidgetClass, chooseSessionForm, 715 XtNresizable, True, 716 XtNdefaultColumns, 1, 717 XtNforceColumns, True, 718 XtNfromHoriz, NULL, 719 XtNfromVert, chooseSessionLabel, 720 XtNvertDistance, 25, 721 NULL); 722 723 chooseSessionMessageLabel = XtVaCreateManagedWidget ( 724 "chooseSessionMessageLabel", labelWidgetClass, chooseSessionForm, 725 XtNfromHoriz, NULL, 726 XtNfromVert, chooseSessionListWidget, 727 XtNborderWidth, 0, 728 XtNresizable, True, 729 XtNjustify, XtJustifyCenter, 730 NULL); 731 732 chooseSessionLoadButton = XtVaCreateManagedWidget ( 733 "chooseSessionLoadButton", commandWidgetClass, chooseSessionForm, 734 XtNfromHoriz, NULL, 735 XtNfromVert, chooseSessionMessageLabel, 736 NULL); 737 738 XtAddCallback (chooseSessionLoadButton, XtNcallback, 739 ChooseSessionLoadXtProc, NULL); 740 741 chooseSessionDeleteButton = XtVaCreateManagedWidget ( 742 "chooseSessionDeleteButton", commandWidgetClass, chooseSessionForm, 743 XtNfromHoriz, chooseSessionLoadButton, 744 XtNfromVert, chooseSessionMessageLabel, 745 NULL); 746 747 XtAddCallback (chooseSessionDeleteButton, XtNcallback, 748 ChooseSessionDeleteXtProc, NULL); 749 750 chooseSessionBreakLockButton = XtVaCreateManagedWidget ( 751 "chooseSessionBreakLockButton", 752 commandWidgetClass, chooseSessionForm, 753 XtNfromHoriz, chooseSessionDeleteButton, 754 XtNfromVert, chooseSessionMessageLabel, 755 NULL); 756 757 XtAddCallback (chooseSessionBreakLockButton, XtNcallback, 758 ChooseSessionBreakLockXtProc, NULL); 759 760 chooseSessionFailSafeButton = XtVaCreateManagedWidget ( 761 "chooseSessionFailSafeButton", commandWidgetClass, chooseSessionForm, 762 XtNfromHoriz, chooseSessionBreakLockButton, 763 XtNfromVert, chooseSessionMessageLabel, 764 NULL); 765 766 XtAddCallback (chooseSessionFailSafeButton, XtNcallback, 767 ChooseSessionFailSafeXtProc, NULL); 768 769 770 chooseSessionCancelButton = XtVaCreateManagedWidget ( 771 "chooseSessionCancelButton", commandWidgetClass, chooseSessionForm, 772 XtNfromHoriz, chooseSessionFailSafeButton, 773 XtNfromVert, chooseSessionMessageLabel, 774 NULL); 775 776 XtAddCallback (chooseSessionCancelButton, XtNcallback, 777 ChooseSessionCancelXtProc, NULL); 778 779 XtAppAddActions (appContext, choose_actions, XtNumber (choose_actions)); 780 781 XtInstallAllAccelerators (chooseSessionListWidget, chooseSessionPopup); 782} 783