xclipboard.c revision d7accfef
1/* 2 * $Xorg: xclipboard.c,v 1.4 2001/02/09 02:05:38 xorgcvs Exp $ 3 * 4 * 5Copyright 1989, 1998 The Open Group 6 7Permission to use, copy, modify, distribute, and sell this software and its 8documentation for any purpose is hereby granted without fee, provided that 9the above copyright notice appear in all copies and that both that 10copyright notice and this permission notice appear in supporting 11documentation. 12 13The above copyright notice and this permission notice shall be included in 14all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23Except as contained in this notice, the name of The Open Group shall not be 24used in advertising or otherwise to promote the sale, use or other dealings 25in this Software without prior written authorization from The Open Group. 26 * * 27 * Author: Ralph Swick, DEC/Project Athena 28 * Updated for R4: Chris D. Peterson, MIT X Consortium. 29 * Reauthored by: Keith Packard, MIT X Consortium. 30 * UTF-8 and CTEXT support: Stanislav Maslovski <stanislav.maslovski@gmail.com> 31 */ 32/* $XFree86: xc/programs/xclipboard/xclipboard.c,v 1.8tsi Exp $ */ 33 34#include <stdio.h> 35#include <X11/Intrinsic.h> 36#include <X11/StringDefs.h> 37#include <X11/Xatom.h> 38 39#include <X11/Xmu/Atoms.h> 40#include <X11/Xmu/StdSel.h> 41 42#include <X11/Shell.h> 43#include <X11/Xaw/Form.h> 44#include <X11/Xaw/Label.h> 45#include <X11/Xaw/Command.h> 46#include <X11/Xaw/AsciiText.h> 47#include <X11/Xaw/Dialog.h> 48#include <X11/Xaw/Cardinals.h> 49#include <X11/IntrinsicP.h> 50#include <X11/Xaw/TextP.h> 51#include <X11/Xfuncs.h> 52 53#ifdef XKB 54#include <X11/extensions/XKBbells.h> 55#endif 56 57#include <stdlib.h> 58 59#define Command commandWidgetClass 60#define Label labelWidgetClass 61#define Text asciiTextWidgetClass 62 63#define INFINITY 10000000 /* pretty big, huh? */ 64 65typedef struct _Clip { 66 struct _Clip *next, *prev; 67 char *clip; 68 char *filename; 69 int avail; 70} ClipRec, *ClipPtr; 71 72static Atom wm_delete_window; 73static Atom wm_protocols; 74 75static void EraseTextWidget ( void ); 76static void NewCurrentClipContents ( char *data, int len ); 77 78static String fallback_resources[] = { 79 "*international: true", 80 NULL 81}; 82 83static long 84TextLength(Widget w) 85{ 86 return XawTextSourceScan (XawTextGetSource (w), 87 (XawTextPosition) 0, 88 XawstAll, XawsdRight, 1, TRUE); 89} 90 91static void 92SaveClip(Widget w, ClipPtr clip) 93{ 94 Arg args[1]; 95 char *data; 96 int len; 97 Widget source; 98 99 source = XawTextGetSource (w); 100 XtSetArg (args[0], XtNstring, &data); 101 XtGetValues (source, args, 1); 102 len = strlen (data); 103 if (len >= clip->avail) 104 { 105 if (clip->clip) 106 free (clip->clip); 107 clip->clip = malloc (len + 1); 108 if (!clip->clip) 109 clip->avail = 0; 110 else 111 clip->avail = len + 1; 112 } 113 if (clip->avail) 114 { 115 strcpy (clip->clip, data); 116 } 117} 118 119static void 120RestoreClip(Widget w, ClipPtr clip) 121{ 122 Arg args[1]; 123 Widget source; 124 125 source = XawTextGetSource (w); 126 XtSetArg (args[0], XtNstring, clip->clip); 127 XtSetValues (source, args, 1); 128} 129 130/*ARGSUSED*/ 131static ClipPtr 132NewClip(Widget w, ClipPtr old) 133{ 134 ClipPtr newClip; 135 136 newClip = (ClipPtr) malloc (sizeof (ClipRec)); 137 if (!newClip) 138 return newClip; 139 newClip->clip = NULL; 140 newClip->avail = 0; 141 newClip->prev = old; 142 newClip->next = NULL; 143 newClip->filename = NULL; 144 if (old) 145 { 146 newClip->next = old->next; 147 old->next = newClip; 148 } 149 return newClip; 150} 151 152/*ARGSUSED*/ 153static void 154DeleteClip(Widget w, ClipPtr clip) 155{ 156 if (clip->prev) 157 clip->prev->next = clip->next; 158 if (clip->next) 159 clip->next->prev = clip->prev; 160 if (clip->clip) 161 free (clip->clip); 162 free ((char *) clip); 163} 164 165static ClipPtr currentClip; 166static Widget top; 167static Widget text, nextButton, prevButton, indexLabel; 168static Widget fileDialog, fileDialogShell; 169static Widget failDialog, failDialogShell; 170 171static int 172IndexCurrentClip (void) 173{ 174 int i = 0; 175 ClipPtr clip; 176 177 for (clip = currentClip; clip; clip = clip->prev) 178 i++; 179 return i; 180} 181 182static void 183set_button_state (void) 184{ 185 Boolean prevvalid, nextvalid; 186 Arg arg; 187 char labelString[10]; 188 189 prevvalid = currentClip->prev != NULL; 190 nextvalid = currentClip->next != NULL; 191 XtSetArg (arg, XtNsensitive, prevvalid); 192 XtSetValues (prevButton, &arg, ONE); 193 XtSetArg (arg, XtNsensitive, nextvalid); 194 XtSetValues (nextButton, &arg, ONE); 195 sprintf (labelString, "%d", IndexCurrentClip ()); 196 XtSetArg (arg, XtNlabel, labelString); 197 XtSetValues (indexLabel, &arg, ONE); 198} 199 200/* ARGSUSED */ 201static void 202NextCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np) 203{ 204 if (currentClip->next) 205 { 206 SaveClip (text, currentClip); 207 currentClip = currentClip->next; 208 RestoreClip (text, currentClip); 209 set_button_state (); 210 } 211} 212 213/* ARGSUSED */ 214static void 215PrevCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np) 216{ 217 if (currentClip->prev) 218 { 219 SaveClip (text, currentClip); 220 currentClip = currentClip->prev; 221 RestoreClip (text, currentClip); 222 set_button_state (); 223 } 224} 225 226/* ARGSUSED */ 227static void 228DeleteCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np) 229{ 230 ClipPtr newCurrent; 231 232 if (currentClip->prev) 233 newCurrent = currentClip->prev; 234 else 235 newCurrent = currentClip->next; 236 if (newCurrent) 237 { 238 DeleteClip (text, currentClip); 239 currentClip = newCurrent; 240 RestoreClip (text, currentClip); 241 } 242 else 243 EraseTextWidget (); 244 set_button_state (); 245} 246 247/* ARGSUSED */ 248static void 249Quit(Widget w, XEvent *ev, String *parms, Cardinal *np) 250{ 251 XtCloseDisplay (XtDisplay (text)); 252 exit (0); 253} 254 255static void 256CenterWidgetAtPoint(Widget w, int x, int y) 257{ 258 Arg args[2]; 259 Dimension width, height; 260 261 XtSetArg(args[0], XtNwidth, &width); 262 XtSetArg(args[1], XtNheight, &height); 263 XtGetValues (w, args, 2); 264 x = x - (int) width / 2; 265 y = y - (int) height / 2; 266 if (x < 0) 267 x = 0; 268 else { 269 int scr_width = WidthOfScreen (XtScreen(w)); 270 if (x + (int)width > scr_width) 271 x = scr_width - width; 272 } 273 if (y < 0) 274 y = 0; 275 else { 276 int scr_height = HeightOfScreen (XtScreen(w)); 277 if (y + (int)height > scr_height) 278 y = scr_height - height; 279 } 280 XtSetArg(args[0], XtNx, x); 281 XtSetArg(args[1], XtNy, y); 282 XtSetValues (w, args, 2); 283} 284 285static void 286CenterWidgetOnEvent(Widget w, XEvent *e) 287{ 288 CenterWidgetAtPoint (w, e->xbutton.x_root, e->xbutton.y_root); 289} 290 291static void 292CenterWidgetOnWidget(Widget w, Widget wT) 293{ 294 Position rootX, rootY; 295 Dimension width, height; 296 Arg args[2]; 297 298 XtSetArg (args[0], XtNwidth, &width); 299 XtSetArg (args[1], XtNheight, &height); 300 XtGetValues (wT, args, 2); 301 XtTranslateCoords (wT, (Position) width/2, (Position) height/2, &rootX, &rootY); 302 CenterWidgetAtPoint (w, (int) rootX, (int) rootY); 303} 304 305/*ARGSUSED*/ 306static void 307SaveToFile(Widget w, XEvent *e, String *argv, Cardinal *argc) 308{ 309 Arg args[1]; 310 char *filename; 311 312 filename = "clipboard"; 313 if (currentClip->filename) 314 filename = currentClip->filename; 315 XtSetArg(args[0], XtNvalue, filename); 316 XtSetValues (fileDialog, args, 1); 317 CenterWidgetOnEvent (fileDialogShell, e); 318 XtPopup (fileDialogShell, XtGrabNone); 319} 320 321/*ARGSUSED*/ 322static void 323AcceptSaveFile(Widget w, XEvent *e, String *argv, Cardinal *argc) 324{ 325 char *filename; 326 Boolean success; 327 Arg args[1]; 328 329 filename = XawDialogGetValueString (fileDialog); 330 success = XawAsciiSaveAsFile (XawTextGetSource (text), filename); 331 XtPopdown (fileDialogShell); 332 if (!success) 333 { 334 char failMessage[1024]; 335 336 sprintf (failMessage, "Can't open file \"%s\"", filename); 337 XtSetArg (args[0], XtNlabel, failMessage); 338 XtSetValues (failDialog, args, 1); 339 CenterWidgetOnEvent (failDialogShell, e); 340 XtPopup (failDialogShell, XtGrabNone); 341 } 342 else 343 { 344 if (currentClip->filename) 345 free (currentClip->filename); 346 currentClip->filename = malloc (strlen (filename) + 1); 347 if (currentClip->filename) 348 strcpy (currentClip->filename, filename); 349 } 350} 351 352/* ARGSUSED */ 353static void 354CancelSaveFile(Widget w, XEvent *ev, String *parms, Cardinal *np) 355{ 356 XtPopdown (fileDialogShell); 357} 358 359/* ARGSUSED */ 360static void 361FailContinue(Widget w, XEvent *ev, String *parms, Cardinal *np) 362{ 363 XtPopdown (failDialogShell); 364} 365 366/*ARGSUSED*/ 367static void 368WMProtocols(Widget w, XEvent *ev, String *params, Cardinal *n) 369{ 370 if (ev->type == ClientMessage && 371 ev->xclient.message_type == wm_protocols && 372 ev->xclient.data.l[0] == (long) wm_delete_window) { 373 while (w && !XtIsShell(w)) 374 w = XtParent(w); 375 if (w == top) 376 Quit(w, ev, params, n); 377 else if (w == fileDialogShell) 378 CancelSaveFile(w, ev, params, n); 379 else if (w == failDialogShell) 380 FailContinue(w, ev, params, n); 381 } 382} 383 384/* ARGUSED */ 385static void 386NewCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np) 387{ 388 NewCurrentClipContents ("", 0); 389} 390 391static void 392NewCurrentClipContents(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 (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 419static void 420EraseTextWidget(void) 421{ 422 XawTextBlock block; 423 424 block.ptr = ""; 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 434static 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 447static XrmOptionDescRec table[] = { 448 {"-w", "wrap", XrmoptionNoArg, "on"}, 449/* {"-nw", "wrap", XrmoptionNoArg, "False"} */ 450}; 451 452static Boolean ConvertSelection ( Widget w, Atom *selection, Atom *target, 453 Atom *type, XtPointer *value, 454 unsigned long *length, int *format ); 455static void LoseSelection ( Widget w, Atom *selection ); 456 457static Atom ManagerAtom, ClipboardAtom; 458 459/*ARGSUSED*/ 460static void 461InsertClipboard(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 XtGetSelectionValue(w, *selection, XA_COMPOUND_TEXT(d), 497 InsertClipboard, 498 (XtPointer)(XA_COMPOUND_TEXT(d)), 499 CurrentTime); 500 return; 501 } 502 /* if COMPOUND_TEXT failed try STRING */ 503 else if (target == XA_COMPOUND_TEXT(d)) 504 { 505 XtGetSelectionValue(w, *selection, XA_STRING, 506 InsertClipboard, 507 NULL, 508 CurrentTime); 509 return; 510 } 511 /* all conversions failed */ 512 else 513 { 514 Arg arg; 515 XtSetArg (arg, XtNlabel, "CLIPBOARD selection conversion failed"); 516 XtSetValues (failDialog, &arg, 1); 517 CenterWidgetOnWidget (failDialogShell, text); 518 XtPopup (failDialogShell, XtGrabNone); 519#ifdef XKB 520 XkbStdBell (d, XtWindow(w), 0, XkbBI_MinorError); 521#else 522 XBell (d, 0); 523#endif 524 } 525 } 526 527 XtOwnSelection(top, ClipboardAtom, CurrentTime, 528 ConvertSelection, LoseSelection, NULL); 529} 530 531static Boolean 532ConvertSelection(Widget w, Atom *selection, Atom *target, 533 Atom *type, XtPointer *value, unsigned long *length, 534 int *format) 535{ 536 Display* d = XtDisplay(w); 537 XSelectionRequestEvent* req = 538 XtGetSelectionRequest(w, *selection, (XtRequestId)NULL); 539 540 if (*target == XA_TARGETS(d)) { 541 Atom* targetP; 542 Atom* std_targets; 543 unsigned long std_length; 544 XmuConvertStandardSelection(w, req->time, selection, target, type, 545 (XPointer*)&std_targets, &std_length, 546 format); 547 *value = XtMalloc(sizeof(Atom)*(std_length + 7)); 548 targetP = *(Atom**)value; 549 *targetP++ = XA_STRING; 550 *targetP++ = XA_TEXT(d); 551 *targetP++ = XA_UTF8_STRING(d); 552 *targetP++ = XA_COMPOUND_TEXT(d); 553 *targetP++ = XA_LENGTH(d); 554 *targetP++ = XA_LIST_LENGTH(d); 555 *targetP++ = XA_CHARACTER_POSITION(d); 556 *length = std_length + (targetP - (*(Atom **) value)); 557 memmove( (char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); 558 XtFree((char*)std_targets); 559 *type = XA_ATOM; 560 *format = 32; 561 return True; 562 } 563 564 if (*target == XA_LIST_LENGTH(d) || 565 *target == XA_LENGTH(d)) 566 { 567 long * temp; 568 569 temp = (long *) XtMalloc(sizeof(long)); 570 if (*target == XA_LIST_LENGTH(d)) 571 *temp = 1L; 572 else /* *target == XA_LENGTH(d) */ 573 *temp = (long) TextLength (text); 574 575 *value = (XPointer) temp; 576 *type = XA_INTEGER; 577 *length = 1L; 578 *format = 32; 579 return True; 580 } 581 582 if (*target == XA_CHARACTER_POSITION(d)) 583 { 584 long * temp; 585 586 temp = (long *) XtMalloc(2 * sizeof(long)); 587 temp[0] = (long) 0; 588 temp[1] = TextLength (text); 589 *value = (XPointer) temp; 590 *type = XA_SPAN(d); 591 *length = 2L; 592 *format = 32; 593 return True; 594 } 595 596 if (*target == XA_STRING || 597 *target == XA_TEXT(d) || 598 *target == XA_UTF8_STRING(d) || 599 *target == XA_COMPOUND_TEXT(d)) 600 { 601 Arg args[1]; 602 Widget source; 603 XTextProperty prop; 604 int ret, style = XStdICCTextStyle; /* a safe default for TEXT */ 605 char *data; 606 607 source = XawTextGetSource (text); 608 XtSetArg (args[0], XtNstring, &data); 609 XtGetValues (source, args, 1); 610 611 if (*target == XA_UTF8_STRING(d)) 612 style = XUTF8StringStyle; 613 else if (*target == XA_COMPOUND_TEXT(d)) 614 style = XCompoundTextStyle; 615 else if (*target == XA_STRING) 616 style = XStringStyle; 617 618 ret = XmbTextListToTextProperty (d, &data, 1, style, &prop); 619 if (ret >= Success) { 620 *length = prop.nitems; 621 *value = prop.value; 622 *type = prop.encoding; 623 *format = prop.format; 624 return True; 625 } else 626 return False; 627 } 628 629 if (XmuConvertStandardSelection(w, req->time, selection, target, type, 630 (XPointer *) value, length, format)) 631 return True; 632 633 return False; 634} 635 636static void 637LoseSelection(Widget w, Atom *selection) 638{ 639 Display *d = XtDisplay(w); 640 XtGetSelectionValue(w, *selection, XA_UTF8_STRING(d), InsertClipboard, 641 (XtPointer)(XA_UTF8_STRING(d)), CurrentTime); 642} 643 644/*ARGSUSED*/ 645static Boolean 646RefuseSelection(Widget w, Atom *selection, Atom *target, 647 Atom *type, XtPointer *value, unsigned long *length, 648 int *format) 649{ 650 return False; 651} 652 653/*ARGSUSED*/ 654static void 655LoseManager(Widget w, Atom *selection) 656{ 657 XtError("another clipboard has taken over control\n"); 658} 659 660typedef struct { 661 Boolean wrap; 662} ResourceData, *ResourceDataPtr; 663 664static ResourceData userOptions; 665 666#define Offset(field) XtOffsetOf(ResourceData, field) 667 668static XtResource resources[] = { 669 {"wrap", "Wrap", XtRBoolean, sizeof(Boolean), 670 Offset(wrap), XtRImmediate, (XtPointer)False} 671}; 672 673#undef Offset 674 675int 676main(int argc, char *argv[]) 677{ 678 Arg args[4]; 679 Cardinal n; 680 XtAppContext xtcontext; 681 Widget parent; 682 683 XtSetLanguageProc(NULL, NULL, NULL); 684 685 top = XtAppInitialize( &xtcontext, "XClipboard", table, XtNumber(table), 686 &argc, argv, fallback_resources, NULL, 0); 687 688 XtGetApplicationResources(top, (XtPointer)&userOptions, resources, 689 XtNumber(resources), NULL, 0); 690 691 XtAppAddActions (xtcontext, 692 xclipboard_actions, XtNumber (xclipboard_actions)); 693 /* CLIPBOARD_MANAGER is a non-standard mechanism */ 694 ManagerAtom = XInternAtom(XtDisplay(top), "CLIPBOARD_MANAGER", False); 695 ClipboardAtom = XA_CLIPBOARD(XtDisplay(top)); 696 if (XGetSelectionOwner(XtDisplay(top), ManagerAtom)) 697 XtError("another clipboard is already running\n"); 698 699 parent = XtCreateManagedWidget("form", formWidgetClass, top, NULL, ZERO); 700 (void) XtCreateManagedWidget("quit", Command, parent, NULL, ZERO); 701 (void) XtCreateManagedWidget("delete", Command, parent, NULL, ZERO); 702 (void) XtCreateManagedWidget("new", Command, parent, NULL, ZERO); 703 (void) XtCreateManagedWidget("save", Command, parent, NULL, ZERO); 704 nextButton = XtCreateManagedWidget("next", Command, parent, NULL, ZERO); 705 prevButton = XtCreateManagedWidget("prev", Command, parent, NULL, ZERO); 706 indexLabel = XtCreateManagedWidget("index", Label, parent, NULL, ZERO); 707 708 n=0; 709 XtSetArg(args[n], XtNtype, XawAsciiString); n++; 710 XtSetArg(args[n], XtNeditType, XawtextEdit); n++; 711 if (userOptions.wrap) { 712 XtSetArg(args[n], XtNwrap, XawtextWrapWord); n++; 713 XtSetArg(args[n], XtNscrollHorizontal, False); n++; 714 } 715 716 text = XtCreateManagedWidget( "text", Text, parent, args, n); 717 718 currentClip = NewClip (text, (ClipPtr) 0); 719 720 set_button_state (); 721 722 fileDialogShell = XtCreatePopupShell("fileDialogShell", 723 transientShellWidgetClass, 724 top, NULL, ZERO); 725 fileDialog = XtCreateManagedWidget ("fileDialog", dialogWidgetClass, 726 fileDialogShell, NULL, ZERO); 727 XawDialogAddButton(fileDialog, "accept", NULL, NULL); 728 XawDialogAddButton(fileDialog, "cancel", NULL, NULL); 729 730 failDialogShell = XtCreatePopupShell("failDialogShell", 731 transientShellWidgetClass, 732 top, NULL, ZERO); 733 failDialog = XtCreateManagedWidget ("failDialog", dialogWidgetClass, 734 failDialogShell, NULL, ZERO); 735 XawDialogAddButton (failDialog, "continue", NULL, NULL); 736 737 XtRealizeWidget(top); 738 XtRealizeWidget(fileDialogShell); 739 XtRealizeWidget(failDialogShell); 740 XtOwnSelection(top, ManagerAtom, CurrentTime, 741 RefuseSelection, LoseManager, NULL); 742 if (XGetSelectionOwner (XtDisplay(top), ClipboardAtom)) { 743 LoseSelection (top, &ClipboardAtom); 744 } else { 745 XtOwnSelection(top, ClipboardAtom, CurrentTime, 746 ConvertSelection, LoseSelection, NULL); 747 } 748 wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW", False); 749 wm_protocols = XInternAtom(XtDisplay(top), "WM_PROTOCOLS", False); 750 (void) XSetWMProtocols(XtDisplay(top), XtWindow(top), &wm_delete_window,1); 751 (void) XSetWMProtocols(XtDisplay(top), XtWindow(fileDialogShell), 752 &wm_delete_window,1); 753 (void) XSetWMProtocols(XtDisplay(top), XtWindow(failDialogShell), 754 &wm_delete_window,1); 755 XtAppMainLoop(xtcontext); 756 exit(0); 757} 758