1 /* 2 3 Copyright 1989, 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 Swick, DEC/Project Athena 26 * Updated for R4: Chris D. Peterson, MIT X Consortium. 27 * Reauthored by: Keith Packard, MIT X Consortium. 28 * UTF-8 and CTEXT support: Stanislav Maslovski <stanislav.maslovski (at) gmail.com> 29 */ 30 31 #ifdef HAVE_CONFIG_H 32 #include "config.h" 33 #endif 34 35 #include <stdio.h> 36 #include <X11/Intrinsic.h> 37 #include <X11/StringDefs.h> 38 #include <X11/Xatom.h> 39 40 #include <X11/Xmu/Atoms.h> 41 #include <X11/Xmu/StdSel.h> 42 43 #include <X11/Shell.h> 44 #include <X11/Xaw/Form.h> 45 #include <X11/Xaw/Label.h> 46 #include <X11/Xaw/Command.h> 47 #include <X11/Xaw/AsciiText.h> 48 #include <X11/Xaw/Dialog.h> 49 #include <X11/Xaw/Cardinals.h> 50 #include <X11/IntrinsicP.h> 51 #include <X11/Xaw/TextP.h> 52 #include <X11/Xfuncs.h> 53 54 #ifdef XKB 55 #include <X11/extensions/XKBbells.h> 56 #endif 57 58 #include <stdlib.h> 59 60 #define Command commandWidgetClass 61 #define Label labelWidgetClass 62 #define Text asciiTextWidgetClass 63 64 #define INFINITY 10000000 /* pretty big, huh? */ 65 66 typedef struct _Clip { 67 struct _Clip *next, *prev; 68 char *clip; 69 char *filename; 70 size_t avail; 71 } ClipRec, *ClipPtr; 72 73 static Atom wm_delete_window; 74 static Atom wm_protocols; 75 76 static void EraseTextWidget ( void ); 77 static void NewCurrentClipContents ( char *data, int len ); 78 79 static String fallback_resources[] = { 80 "*international: true", 81 NULL 82 }; 83 84 static long 85 TextLength(Widget w) 86 { 87 return XawTextSourceScan (XawTextGetSource (w), 88 (XawTextPosition) 0, 89 XawstAll, XawsdRight, 1, TRUE); 90 } 91 92 static void 93 SaveClip(Widget w, ClipPtr clip) 94 { 95 Arg args[1]; 96 char *data; 97 size_t len; 98 Widget source; 99 100 source = XawTextGetSource (w); 101 XtSetArg (args[0], XtNstring, &data); 102 XtGetValues (source, args, 1); 103 len = strlen (data); 104 if (len >= clip->avail) 105 { 106 if (clip->clip) 107 free (clip->clip); 108 clip->clip = malloc (len + 1); 109 if (!clip->clip) 110 clip->avail = 0; 111 else 112 clip->avail = len + 1; 113 } 114 if (clip->avail) 115 { 116 strcpy (clip->clip, data); 117 } 118 } 119 120 static void 121 RestoreClip(Widget w, ClipPtr clip) 122 { 123 Arg args[1]; 124 Widget source; 125 126 source = XawTextGetSource (w); 127 XtSetArg (args[0], XtNstring, clip->clip); 128 XtSetValues (source, args, 1); 129 } 130 131 /*ARGSUSED*/ 132 static ClipPtr 133 NewClip(Widget w, ClipPtr old) 134 { 135 ClipPtr newClip; 136 137 newClip = calloc (1, sizeof (ClipRec)); 138 if (!newClip) { 139 XtError("Failed to allocate memory for ClipRec\n"); 140 return newClip; 141 } 142 newClip->prev = old; 143 if (old) 144 { 145 newClip->next = old->next; 146 old->next = newClip; 147 } 148 return newClip; 149 } 150 151 /*ARGSUSED*/ 152 static void 153 DeleteClip(Widget w, ClipPtr clip) 154 { 155 if (clip->prev) 156 clip->prev->next = clip->next; 157 if (clip->next) 158 clip->next->prev = clip->prev; 159 if (clip->clip) 160 free (clip->clip); 161 free ((char *) clip); 162 } 163 164 static ClipPtr currentClip; 165 static Widget top; 166 static Widget text, nextButton, prevButton, indexLabel; 167 static Widget fileDialog, fileDialogShell; 168 static Widget failDialog, failDialogShell; 169 170 static int 171 IndexCurrentClip (void) 172 { 173 int i = 0; 174 ClipPtr clip; 175 176 for (clip = currentClip; clip; clip = clip->prev) 177 i++; 178 return i; 179 } 180 181 static void 182 set_button_state (void) 183 { 184 Boolean prevvalid, nextvalid; 185 Arg arg; 186 char labelString[12]; 187 188 prevvalid = currentClip->prev != NULL; 189 nextvalid = currentClip->next != NULL; 190 XtSetArg (arg, XtNsensitive, prevvalid); 191 XtSetValues (prevButton, &arg, ONE); 192 XtSetArg (arg, XtNsensitive, nextvalid); 193 XtSetValues (nextButton, &arg, ONE); 194 snprintf (labelString, sizeof(labelString), "%d", IndexCurrentClip ()); 195 XtSetArg (arg, XtNlabel, labelString); 196 XtSetValues (indexLabel, &arg, ONE); 197 } 198 199 /* ARGSUSED */ 200 static void 201 NextCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np) 202 { 203 if (currentClip->next) 204 { 205 SaveClip (text, currentClip); 206 currentClip = currentClip->next; 207 RestoreClip (text, currentClip); 208 set_button_state (); 209 } 210 } 211 212 /* ARGSUSED */ 213 static void 214 PrevCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np) 215 { 216 if (currentClip->prev) 217 { 218 SaveClip (text, currentClip); 219 currentClip = currentClip->prev; 220 RestoreClip (text, currentClip); 221 set_button_state (); 222 } 223 } 224 225 /* ARGSUSED */ 226 static void 227 DeleteCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np) 228 { 229 ClipPtr newCurrent; 230 231 if (currentClip->prev) 232 newCurrent = currentClip->prev; 233 else 234 newCurrent = currentClip->next; 235 if (newCurrent) 236 { 237 DeleteClip (text, currentClip); 238 currentClip = newCurrent; 239 RestoreClip (text, currentClip); 240 } 241 else 242 EraseTextWidget (); 243 set_button_state (); 244 } 245 246 /* ARGSUSED */ 247 static void _X_NORETURN 248 Quit(Widget w, XEvent *ev, String *parms, Cardinal *np) 249 { 250 XtCloseDisplay (XtDisplay (text)); 251 exit (0); 252 } 253 254 static void 255 CenterWidgetAtPoint(Widget w, int x, int y) 256 { 257 Arg args[2]; 258 Dimension width, height; 259 260 XtSetArg(args[0], XtNwidth, &width); 261 XtSetArg(args[1], XtNheight, &height); 262 XtGetValues (w, args, 2); 263 x = x - (int) width / 2; 264 y = y - (int) height / 2; 265 if (x < 0) 266 x = 0; 267 else { 268 int scr_width = WidthOfScreen (XtScreen(w)); 269 if (x + (int)width > scr_width) 270 x = scr_width - width; 271 } 272 if (y < 0) 273 y = 0; 274 else { 275 int scr_height = HeightOfScreen (XtScreen(w)); 276 if (y + (int)height > scr_height) 277 y = scr_height - height; 278 } 279 XtSetArg(args[0], XtNx, x); 280 XtSetArg(args[1], XtNy, y); 281 XtSetValues (w, args, 2); 282 } 283 284 static void 285 CenterWidgetOnEvent(Widget w, XEvent *e) 286 { 287 CenterWidgetAtPoint (w, e->xbutton.x_root, e->xbutton.y_root); 288 } 289 290 static void 291 CenterWidgetOnWidget(Widget w, Widget wT) 292 { 293 Position rootX, rootY; 294 Dimension width, height; 295 Arg args[2]; 296 297 XtSetArg (args[0], XtNwidth, &width); 298 XtSetArg (args[1], XtNheight, &height); 299 XtGetValues (wT, args, 2); 300 XtTranslateCoords (wT, (Position) width/2, (Position) height/2, &rootX, &rootY); 301 CenterWidgetAtPoint (w, (int) rootX, (int) rootY); 302 } 303 304 /*ARGSUSED*/ 305 static void 306 SaveToFile(Widget w, XEvent *e, String *argv, Cardinal *argc) 307 { 308 Arg args[1]; 309 const char *filename; 310 311 filename = "clipboard"; 312 if (currentClip->filename) 313 filename = currentClip->filename; 314 XtSetArg(args[0], XtNvalue, filename); 315 XtSetValues (fileDialog, args, 1); 316 CenterWidgetOnEvent (fileDialogShell, e); 317 XtPopup (fileDialogShell, XtGrabNone); 318 } 319 320 /*ARGSUSED*/ 321 static void 322 AcceptSaveFile(Widget w, XEvent *e, String *argv, Cardinal *argc) 323 { 324 char *filename; 325 Bool success; 326 Arg args[1]; 327 328 filename = XawDialogGetValueString (fileDialog); 329 success = XawAsciiSaveAsFile (XawTextGetSource (text), filename); 330 XtPopdown (fileDialogShell); 331 if (!success) 332 { 333 char *failMessage; 334 335 XtAsprintf (&failMessage, "Can't open file \"%s\"", filename); 336 XtSetArg (args[0], XtNlabel, failMessage); 337 XtSetValues (failDialog, args, 1); 338 CenterWidgetOnEvent (failDialogShell, e); 339 XtPopup (failDialogShell, XtGrabNone); 340 XtFree (failMessage); 341 } 342 else 343 { 344 if (currentClip->filename) 345 free (currentClip->filename); 346 currentClip->filename = strdup (filename); 347 } 348 } 349 350 /* ARGSUSED */ 351 static void 352 CancelSaveFile(Widget w, XEvent *ev, String *parms, Cardinal *np) 353 { 354 XtPopdown (fileDialogShell); 355 } 356 357 /* ARGSUSED */ 358 static void 359 FailContinue(Widget w, XEvent *ev, String *parms, Cardinal *np) 360 { 361 XtPopdown (failDialogShell); 362 } 363 364 /*ARGSUSED*/ 365 static void 366 WMProtocols(Widget w, XEvent *ev, String *params, Cardinal *n) 367 { 368 if (ev->type == ClientMessage && 369 ev->xclient.message_type == wm_protocols && 370 ev->xclient.data.l[0] == (long) wm_delete_window) { 371 while (w && !XtIsShell(w)) 372 w = XtParent(w); 373 if (w == top) 374 Quit(w, ev, params, n); 375 else if (w == fileDialogShell) 376 CancelSaveFile(w, ev, params, n); 377 else if (w == failDialogShell) 378 FailContinue(w, ev, params, n); 379 } 380 } 381 382 static char empty_string[] = ""; 383 384 /* ARGUSED */ 385 static void 386 NewCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np) 387 { 388 NewCurrentClipContents (empty_string, 0); 389 } 390 391 static void 392 NewCurrentClipContents(char *data, int len) 393 { 394 XawTextBlock textBlock; 395 396 SaveClip (text, currentClip); 397 398 /* append new clips at the end */ 399 while (currentClip && currentClip->next) 400 currentClip = currentClip->next; 401 /* any trailing clips with no text get overwritten */ 402 if ((currentClip == NULL) || (strlen (currentClip->clip) != 0)) 403 currentClip = NewClip (text, currentClip); 404 405 textBlock.ptr = data; 406 textBlock.firstPos = 0; 407 textBlock.length = len; 408 textBlock.format = FMT8BIT; 409 if (XawTextReplace(text, 0, TextLength (text), &textBlock)) { 410 #ifdef XKB 411 XkbStdBell(XtDisplay(text), XtWindow(text), 0, XkbBI_Info); 412 #else 413 XBell( XtDisplay(text), 0); 414 #endif 415 } 416 set_button_state (); 417 } 418 419 static void 420 EraseTextWidget(void) 421 { 422 XawTextBlock block; 423 424 block.ptr = empty_string; 425 block.length = 0; 426 block.firstPos = 0; 427 block.format = FMT8BIT; 428 429 XawTextReplace(text, 0, INFINITY, &block); 430 /* If this fails, too bad. */ 431 } 432 433 434 static XtActionsRec xclipboard_actions[] = { 435 { "NewClip", NewCurrentClip }, 436 { "NextClip", NextCurrentClip }, 437 { "PrevClip", PrevCurrentClip }, 438 { "DeleteClip", DeleteCurrentClip }, 439 { "Save", SaveToFile }, 440 { "AcceptSave", AcceptSaveFile }, 441 { "CancelSave", CancelSaveFile }, 442 { "FailContinue", FailContinue }, 443 { "Quit", Quit }, 444 { "WMProtocols", WMProtocols } 445 }; 446 447 static XrmOptionDescRec table[] = { 448 {"-w", "wrap", XrmoptionNoArg, "on"}, 449 /* {"-nw", "wrap", XrmoptionNoArg, "False"} */ 450 }; 451 452 static Boolean ConvertSelection ( Widget w, Atom *selection, Atom *target, 453 Atom *type, XtPointer *value, 454 unsigned long *length, int *format ); 455 static void LoseSelection ( Widget w, Atom *selection ); 456 457 static Atom ManagerAtom, ClipboardAtom; 458 459 /*ARGSUSED*/ 460 static void 461 InsertClipboard(Widget w, XtPointer client_data, Atom *selection, 462 Atom *type, XtPointer value, unsigned long *length, 463 int *format) 464 { 465 Display *d = XtDisplay(w); 466 Atom target = *((Atom *)client_data); 467 Boolean convert_failed = (*type == XT_CONVERT_FAIL); 468 469 if (!convert_failed) 470 { 471 char **list; 472 int i, ret, count; 473 474 XTextProperty prop; 475 prop.value = value; 476 prop.nitems = *length; 477 prop.format = *format; 478 prop.encoding = *type; 479 ret = XmbTextPropertyToTextList(d, &prop, &list, &count); 480 if (ret >= Success) 481 { 482 /* manuals say something about multiple strings in a disjoint 483 text selection (?), it should be harmless to get them all */ 484 for (i = 0; i < count; i++) 485 NewCurrentClipContents(list[i], strlen(list[i])); 486 XFreeStringList(list); 487 } else 488 convert_failed = True; 489 XFree(value); 490 } 491 492 if (convert_failed) { 493 /* if UTF8_STRING failed try COMPOUND_TEXT */ 494 if (target == XA_UTF8_STRING(d)) 495 { 496 Atom compound_text = XA_COMPOUND_TEXT(d); 497 XtGetSelectionValue(w, *selection, compound_text, 498 InsertClipboard, 499 &compound_text, 500 CurrentTime); 501 return; 502 } 503 /* if COMPOUND_TEXT failed try STRING */ 504 else if (target == XA_COMPOUND_TEXT(d)) 505 { 506 XtGetSelectionValue(w, *selection, XA_STRING, 507 InsertClipboard, 508 NULL, 509 CurrentTime); 510 return; 511 } 512 /* all conversions failed */ 513 else 514 { 515 Arg arg; 516 XtSetArg (arg, XtNlabel, "CLIPBOARD selection conversion failed"); 517 XtSetValues (failDialog, &arg, 1); 518 CenterWidgetOnWidget (failDialogShell, text); 519 XtPopup (failDialogShell, XtGrabNone); 520 #ifdef XKB 521 XkbStdBell (d, XtWindow(w), 0, XkbBI_MinorError); 522 #else 523 XBell (d, 0); 524 #endif 525 } 526 } 527 528 XtOwnSelection(top, ClipboardAtom, CurrentTime, 529 ConvertSelection, LoseSelection, NULL); 530 } 531 532 static Boolean 533 ConvertSelection(Widget w, Atom *selection, Atom *target, 534 Atom *type, XtPointer *value, unsigned long *length, 535 int *format) 536 { 537 Display* d = XtDisplay(w); 538 XSelectionRequestEvent* req = 539 XtGetSelectionRequest(w, *selection, (XtRequestId)NULL); 540 541 if (*target == XA_TARGETS(d)) { 542 Atom* targetP; 543 Atom* std_targets; 544 unsigned long std_length; 545 XmuConvertStandardSelection(w, req->time, selection, target, type, 546 (XPointer*)&std_targets, &std_length, 547 format); 548 *value = XtMalloc(sizeof(Atom)*(std_length + 7)); 549 targetP = *(Atom**)value; 550 *targetP++ = XA_STRING; 551 *targetP++ = XA_TEXT(d); 552 *targetP++ = XA_UTF8_STRING(d); 553 *targetP++ = XA_COMPOUND_TEXT(d); 554 *targetP++ = XA_LENGTH(d); 555 *targetP++ = XA_LIST_LENGTH(d); 556 *targetP++ = XA_CHARACTER_POSITION(d); 557 *length = std_length + (targetP - (*(Atom **) value)); 558 memmove( (char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); 559 XtFree((char*)std_targets); 560 *type = XA_ATOM; 561 *format = 32; 562 return True; 563 } 564 565 if (*target == XA_LIST_LENGTH(d) || 566 *target == XA_LENGTH(d)) 567 { 568 long * temp; 569 570 temp = (long *) XtMalloc(sizeof(long)); 571 if (*target == XA_LIST_LENGTH(d)) 572 *temp = 1L; 573 else /* *target == XA_LENGTH(d) */ 574 *temp = (long) TextLength (text); 575 576 *value = (XPointer) temp; 577 *type = XA_INTEGER; 578 *length = 1L; 579 *format = 32; 580 return True; 581 } 582 583 if (*target == XA_CHARACTER_POSITION(d)) 584 { 585 long * temp; 586 587 temp = (long *) XtMalloc(2 * sizeof(long)); 588 temp[0] = (long) 0; 589 temp[1] = TextLength (text); 590 *value = (XPointer) temp; 591 *type = XA_SPAN(d); 592 *length = 2L; 593 *format = 32; 594 return True; 595 } 596 597 if (*target == XA_STRING || 598 *target == XA_TEXT(d) || 599 *target == XA_UTF8_STRING(d) || 600 *target == XA_COMPOUND_TEXT(d)) 601 { 602 Arg args[1]; 603 Widget source; 604 XTextProperty prop; 605 int ret, style = XStdICCTextStyle; /* a safe default for TEXT */ 606 char *data; 607 608 source = XawTextGetSource (text); 609 XtSetArg (args[0], XtNstring, &data); 610 XtGetValues (source, args, 1); 611 612 if (*target == XA_UTF8_STRING(d)) 613 style = XUTF8StringStyle; 614 else if (*target == XA_COMPOUND_TEXT(d)) 615 style = XCompoundTextStyle; 616 else if (*target == XA_STRING) 617 style = XStringStyle; 618 619 ret = XmbTextListToTextProperty (d, &data, 1, style, &prop); 620 if (ret >= Success) { 621 *length = prop.nitems; 622 *value = prop.value; 623 *type = prop.encoding; 624 *format = prop.format; 625 return True; 626 } else 627 return False; 628 } 629 630 if (XmuConvertStandardSelection(w, req->time, selection, target, type, 631 (XPointer *) value, length, format)) 632 return True; 633 634 return False; 635 } 636 637 static void 638 LoseSelection(Widget w, Atom *selection) 639 { 640 Display *d = XtDisplay(w); 641 Atom utf8_string = XA_UTF8_STRING(d); 642 XtGetSelectionValue(w, *selection, utf8_string, InsertClipboard, 643 &utf8_string, CurrentTime); 644 } 645 646 /*ARGSUSED*/ 647 static Boolean 648 RefuseSelection(Widget w, Atom *selection, Atom *target, 649 Atom *type, XtPointer *value, unsigned long *length, 650 int *format) 651 { 652 return False; 653 } 654 655 /*ARGSUSED*/ 656 static void 657 LoseManager(Widget w, Atom *selection) 658 { 659 XtError("another clipboard has taken over control\n"); 660 } 661 662 typedef struct { 663 Boolean wrap; 664 } ResourceData, *ResourceDataPtr; 665 666 static ResourceData userOptions; 667 668 #define Offset(field) XtOffsetOf(ResourceData, field) 669 670 static XtResource resources[] = { 671 {"wrap", "Wrap", XtRBoolean, sizeof(Boolean), 672 Offset(wrap), XtRImmediate, (XtPointer)False} 673 }; 674 675 #undef Offset 676 677 int 678 main(int argc, char *argv[]) 679 { 680 Arg args[4]; 681 Cardinal n; 682 XtAppContext xtcontext; 683 Widget parent; 684 685 XtSetLanguageProc(NULL, NULL, NULL); 686 687 top = XtAppInitialize( &xtcontext, "XClipboard", table, XtNumber(table), 688 &argc, argv, fallback_resources, NULL, 0); 689 690 XtGetApplicationResources(top, (XtPointer)&userOptions, resources, 691 XtNumber(resources), NULL, 0); 692 693 XtAppAddActions (xtcontext, 694 xclipboard_actions, XtNumber (xclipboard_actions)); 695 /* CLIPBOARD_MANAGER is a non-standard mechanism */ 696 ManagerAtom = XInternAtom(XtDisplay(top), "CLIPBOARD_MANAGER", False); 697 ClipboardAtom = XA_CLIPBOARD(XtDisplay(top)); 698 if (XGetSelectionOwner(XtDisplay(top), ManagerAtom)) 699 XtError("another clipboard is already running\n"); 700 701 parent = XtCreateManagedWidget("form", formWidgetClass, top, NULL, ZERO); 702 (void) XtCreateManagedWidget("quit", Command, parent, NULL, ZERO); 703 (void) XtCreateManagedWidget("delete", Command, parent, NULL, ZERO); 704 (void) XtCreateManagedWidget("new", Command, parent, NULL, ZERO); 705 (void) XtCreateManagedWidget("save", Command, parent, NULL, ZERO); 706 nextButton = XtCreateManagedWidget("next", Command, parent, NULL, ZERO); 707 prevButton = XtCreateManagedWidget("prev", Command, parent, NULL, ZERO); 708 indexLabel = XtCreateManagedWidget("index", Label, parent, NULL, ZERO); 709 710 n=0; 711 XtSetArg(args[n], XtNtype, XawAsciiString); n++; 712 XtSetArg(args[n], XtNeditType, XawtextEdit); n++; 713 if (userOptions.wrap) { 714 XtSetArg(args[n], XtNwrap, XawtextWrapWord); n++; 715 XtSetArg(args[n], XtNscrollHorizontal, False); n++; 716 } 717 718 text = XtCreateManagedWidget( "text", Text, parent, args, n); 719 720 currentClip = NewClip (text, (ClipPtr) 0); 721 722 set_button_state (); 723 724 fileDialogShell = XtCreatePopupShell("fileDialogShell", 725 transientShellWidgetClass, 726 top, NULL, ZERO); 727 fileDialog = XtCreateManagedWidget ("fileDialog", dialogWidgetClass, 728 fileDialogShell, NULL, ZERO); 729 XawDialogAddButton(fileDialog, "accept", NULL, NULL); 730 XawDialogAddButton(fileDialog, "cancel", NULL, NULL); 731 732 failDialogShell = XtCreatePopupShell("failDialogShell", 733 transientShellWidgetClass, 734 top, NULL, ZERO); 735 failDialog = XtCreateManagedWidget ("failDialog", dialogWidgetClass, 736 failDialogShell, NULL, ZERO); 737 XawDialogAddButton (failDialog, "continue", NULL, NULL); 738 739 XtRealizeWidget(top); 740 XtRealizeWidget(fileDialogShell); 741 XtRealizeWidget(failDialogShell); 742 XtOwnSelection(top, ManagerAtom, CurrentTime, 743 RefuseSelection, LoseManager, NULL); 744 if (XGetSelectionOwner (XtDisplay(top), ClipboardAtom)) { 745 LoseSelection (top, &ClipboardAtom); 746 } else { 747 XtOwnSelection(top, ClipboardAtom, CurrentTime, 748 ConvertSelection, LoseSelection, NULL); 749 } 750 wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW", False); 751 wm_protocols = XInternAtom(XtDisplay(top), "WM_PROTOCOLS", False); 752 (void) XSetWMProtocols(XtDisplay(top), XtWindow(top), &wm_delete_window,1); 753 (void) XSetWMProtocols(XtDisplay(top), XtWindow(fileDialogShell), 754 &wm_delete_window,1); 755 (void) XSetWMProtocols(XtDisplay(top), XtWindow(failDialogShell), 756 &wm_delete_window,1); 757 XtAppMainLoop(xtcontext); 758 exit(0); 759 } 760