Selection.c revision 2265a131
1/* $Xorg: Selection.c,v 1.4 2001/02/09 02:03:56 xorgcvs Exp $ */ 2 3/*********************************************************** 4Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, 5Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. 6 7 All Rights Reserved 8 9Permission to use, copy, modify, and distribute this software and its 10documentation for any purpose and without fee is hereby granted, 11provided that the above copyright notice appear in all copies and that 12both that copyright notice and this permission notice appear in 13supporting documentation, and that the names of Digital or Sun not be 14used in advertising or publicity pertaining to distribution of the 15software without specific, written prior permission. 16 17DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 18ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 19DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 20ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 21WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 22ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 23SOFTWARE. 24 25SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 26INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- 27NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- 28ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 29ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 30PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 31OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 32THE USE OR PERFORMANCE OF THIS SOFTWARE. 33 34******************************************************************/ 35 36/* 37 38Copyright 1987, 1988, 1994, 1998 The Open Group 39 40Permission to use, copy, modify, distribute, and sell this software and its 41documentation for any purpose is hereby granted without fee, provided that 42the above copyright notice appear in all copies and that both that 43copyright notice and this permission notice appear in supporting 44documentation. 45 46The above copyright notice and this permission notice shall be included in 47all copies or substantial portions of the Software. 48 49THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 53AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 54CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 55 56Except as contained in this notice, the name of The Open Group shall not be 57used in advertising or otherwise to promote the sale, use or other dealings 58in this Software without prior written authorization from The Open Group. 59 60*/ 61/* $XFree86: xc/lib/Xt/Selection.c,v 3.9 2001/12/14 19:56:29 dawes Exp $ */ 62 63#ifdef HAVE_CONFIG_H 64#include <config.h> 65#endif 66#include "IntrinsicI.h" 67#include "StringDefs.h" 68#include "SelectionI.h" 69#include <X11/Xatom.h> 70#include <stdio.h> 71 72void _XtSetDefaultSelectionTimeout( 73 unsigned long *timeout) 74{ 75 *timeout = 5000; /* default to 5 seconds */ 76} 77 78void XtSetSelectionTimeout( 79 unsigned long timeout) 80{ 81 XtAppSetSelectionTimeout(_XtDefaultAppContext(), timeout); 82} 83 84void XtAppSetSelectionTimeout( 85 XtAppContext app, 86 unsigned long timeout) 87{ 88 LOCK_APP(app); 89 app->selectionTimeout = timeout; 90 UNLOCK_APP(app); 91} 92 93unsigned long XtGetSelectionTimeout(void) 94{ 95 return XtAppGetSelectionTimeout(_XtDefaultAppContext()); 96} 97 98unsigned long XtAppGetSelectionTimeout( 99 XtAppContext app) 100{ 101 unsigned long retval; 102 103 LOCK_APP(app); 104 retval = app->selectionTimeout; 105 UNLOCK_APP(app); 106 return retval; 107} 108 109 110/* General utilities */ 111 112static void HandleSelectionReplies(Widget, XtPointer, XEvent *, Boolean *); 113static void ReqTimedOut(XtPointer, XtIntervalId *); 114static void HandlePropertyGone(Widget, XtPointer, XEvent *, Boolean *); 115static void HandleGetIncrement(Widget, XtPointer, XEvent *, Boolean *); 116static void HandleIncremental(Display *, Widget, Atom, CallBackInfo, unsigned long); 117 118static XContext selectPropertyContext = 0; 119static XContext paramPropertyContext = 0; 120static XContext multipleContext = 0; 121 122/* Multiple utilities */ 123static void AddSelectionRequests(Widget, Atom, int, Atom *, XtSelectionCallbackProc *, int, XtPointer *, Boolean *, Atom *); 124static Boolean IsGatheringRequest(Widget, Atom); 125 126#define PREALLOCED 32 127 128/* Parameter utilities */ 129static void AddParamInfo(Widget, Atom, Atom); 130static void RemoveParamInfo(Widget, Atom); 131static Atom GetParamInfo(Widget, Atom); 132 133static int StorageSize[3] = {1, sizeof(short), sizeof(long)}; 134#define BYTELENGTH(length, format) ((length) * StorageSize[(format)>>4]) 135#define NUMELEM(bytelength, format) ((bytelength) / StorageSize[(format)>>4]) 136 137/* Xlib and Xt are permitted to have different memory allocators, and in the 138 * XtSelectionCallbackProc the client is instructed to free the selection 139 * value with XtFree, so the selection value received from XGetWindowProperty 140 * should be copied to memory allocated through Xt. But copying is 141 * undesirable since the selection value may be large, and, under normal 142 * library configuration copying is unnecessary. 143 */ 144#ifdef XTTRACEMEMORY 145#define XT_COPY_SELECTION 1 146#endif 147 148/*ARGSUSED*/ 149static void FreePropList( 150 Widget w, /* unused */ 151 XtPointer closure, 152 XtPointer callData) /* unused */ 153{ 154 PropList sarray = (PropList)closure; 155 LOCK_PROCESS; 156 XDeleteContext(sarray->dpy, DefaultRootWindow(sarray->dpy), 157 selectPropertyContext); 158 UNLOCK_PROCESS; 159 XtFree((char*)sarray->list); 160 XtFree((char*)closure); 161} 162 163 164static PropList GetPropList( 165 Display *dpy) 166{ 167 PropList sarray; 168 Atom atoms[4]; 169 static char* names[] = { 170 "INCR", 171 "MULTIPLE", 172 "TIMESTAMP", 173 "_XT_SELECTION_0" }; 174 175 LOCK_PROCESS; 176 if (selectPropertyContext == 0) 177 selectPropertyContext = XUniqueContext(); 178 if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, 179 (XPointer *)&sarray)) { 180 XtPerDisplay pd = _XtGetPerDisplay(dpy); 181 sarray = (PropList) __XtMalloc((unsigned) sizeof(PropListRec)); 182 sarray->dpy = dpy; 183 XInternAtoms(dpy, names, 4, FALSE, atoms); 184 sarray->incr_atom = atoms[0]; 185 sarray->indirect_atom = atoms[1]; 186 sarray->timestamp_atom = atoms[2]; 187 sarray->propCount = 1; 188 sarray->list = 189 (SelectionProp)__XtMalloc((unsigned) sizeof(SelectionPropRec)); 190 sarray->list[0].prop = atoms[3]; 191 sarray->list[0].avail = TRUE; 192 (void) XSaveContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, 193 (char *) sarray); 194 _XtAddCallback( &pd->destroy_callbacks, 195 FreePropList, (XtPointer)sarray ); 196 } 197 UNLOCK_PROCESS; 198 return sarray; 199} 200 201 202static Atom GetSelectionProperty( 203 Display *dpy) 204{ 205 SelectionProp p; 206 int propCount; 207 char propname[80]; 208 PropList sarray = GetPropList(dpy); 209 210 for (p = sarray->list, propCount=sarray->propCount; 211 propCount; 212 p++, propCount--) { 213 if (p->avail) { 214 p->avail = FALSE; 215 return(p->prop); 216 } 217 } 218 propCount = sarray->propCount++; 219 sarray->list = (SelectionProp) XtRealloc((XtPointer)sarray->list, 220 (unsigned)(sarray->propCount*sizeof(SelectionPropRec))); 221 (void) sprintf(propname, "%s%d", "_XT_SELECTION_", propCount); 222 sarray->list[propCount].prop = XInternAtom(dpy, propname, FALSE); 223 sarray->list[propCount].avail = FALSE; 224 return(sarray->list[propCount].prop); 225} 226 227static void FreeSelectionProperty( 228 Display *dpy, 229 Atom prop) 230{ 231 SelectionProp p; 232 PropList sarray; 233 if (prop == None) return; 234 LOCK_PROCESS; 235 if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, 236 (XPointer *)&sarray)) 237 XtAppErrorMsg(XtDisplayToApplicationContext(dpy), 238 "noSelectionProperties", "freeSelectionProperty", XtCXtToolkitError, 239 "internal error: no selection property context for display", 240 (String *)NULL, (Cardinal *)NULL ); 241 UNLOCK_PROCESS; 242 for (p = sarray->list; p; p++) 243 if (p->prop == prop) { 244 p->avail = TRUE; 245 return; 246 } 247} 248 249static void FreeInfo( 250 CallBackInfo info) 251{ 252 XtFree((char*)info->incremental); 253 XtFree((char*)info->callbacks); 254 XtFree((char*)info->req_closure); 255 XtFree((char*)info->target); 256 XtFree((char*)info); 257} 258 259static CallBackInfo MakeInfo( 260 Select ctx, 261 XtSelectionCallbackProc *callbacks, 262 XtPointer *closures, 263 int count, 264 Widget widget, 265 Time time, 266 Boolean *incremental, 267 Atom *properties) 268{ 269 CallBackInfo info = XtNew(CallBackInfoRec); 270 271 info->ctx = ctx; 272 info->callbacks = (XtSelectionCallbackProc *) 273 __XtMalloc((unsigned) (count * sizeof(XtSelectionCallbackProc))); 274 (void) memmove((char*)info->callbacks, (char*)callbacks, 275 count * sizeof(XtSelectionCallbackProc)); 276 info->req_closure = 277 (XtPointer*)__XtMalloc((unsigned) (count * sizeof(XtPointer))); 278 (void) memmove((char*)info->req_closure, (char*)closures, 279 count * sizeof(XtPointer)); 280 if (count == 1 && properties != NULL && properties[0] != None) 281 info->property = properties[0]; 282 else { 283 info->property = GetSelectionProperty(XtDisplay(widget)); 284 XDeleteProperty(XtDisplay(widget), XtWindow(widget), 285 info->property); 286 } 287 info->proc = HandleSelectionReplies; 288 info->widget = widget; 289 info->time = time; 290 info->incremental = (Boolean*) __XtMalloc(count * sizeof(Boolean)); 291 (void) memmove((char*)info->incremental, (char*) incremental, 292 count * sizeof(Boolean)); 293 info->current = 0; 294 info->value = NULL; 295 return (info); 296} 297 298static void RequestSelectionValue( 299 CallBackInfo info, 300 Atom selection, 301 Atom target) 302{ 303#ifndef DEBUG_WO_TIMERS 304 XtAppContext app = XtWidgetToApplicationContext(info->widget); 305 info->timeout = XtAppAddTimeOut(app, 306 app->selectionTimeout, ReqTimedOut, (XtPointer)info); 307#endif 308 XtAddEventHandler(info->widget, (EventMask)0, TRUE, 309 HandleSelectionReplies, (XtPointer)info); 310 XConvertSelection(info->ctx->dpy, selection, target, 311 info->property, XtWindow(info->widget), info->time); 312} 313 314 315static XContext selectContext = 0; 316 317static Select NewContext( 318 Display *dpy, 319 Atom selection) 320{ 321 /* assert(selectContext != 0) */ 322 Select ctx = XtNew(SelectRec); 323 ctx->dpy = dpy; 324 ctx->selection = selection; 325 ctx->widget = NULL; 326 ctx->prop_list = GetPropList(dpy); 327 ctx->ref_count = 0; 328 ctx->free_when_done = FALSE; 329 ctx->was_disowned = FALSE; 330 LOCK_PROCESS; 331 (void)XSaveContext(dpy, (Window)selection, selectContext, (char *)ctx); 332 UNLOCK_PROCESS; 333 return ctx; 334} 335 336static Select FindCtx( 337 Display *dpy, 338 Atom selection) 339{ 340 Select ctx; 341 342 LOCK_PROCESS; 343 if (selectContext == 0) 344 selectContext = XUniqueContext(); 345 if (XFindContext(dpy, (Window)selection, selectContext, (XPointer *)&ctx)) 346 ctx = NewContext(dpy, selection); 347 UNLOCK_PROCESS; 348 return ctx; 349} 350 351/*ARGSUSED*/ 352static void WidgetDestroyed( 353 Widget widget, 354 XtPointer closure, XtPointer data) 355{ 356 Select ctx = (Select) closure; 357 if (ctx->widget == widget) { 358 if (ctx->free_when_done) 359 XtFree((char*)ctx); 360 else 361 ctx->widget = NULL; 362 } 363} 364 365/* Selection Owner code */ 366 367static void HandleSelectionEvents(Widget, XtPointer, XEvent *, Boolean *); 368 369static Boolean LoseSelection( 370 Select ctx, 371 Widget widget, 372 Atom selection, 373 Time time) 374{ 375 if ((ctx->widget == widget) && 376 (ctx->selection == selection) && /* paranoia */ 377 !ctx->was_disowned && 378 ((time == CurrentTime) || (time >= ctx->time))) 379 { 380 XtRemoveEventHandler(widget, (EventMask)0, TRUE, 381 HandleSelectionEvents, (XtPointer)ctx); 382 XtRemoveCallback(widget, XtNdestroyCallback, 383 WidgetDestroyed, (XtPointer)ctx); 384 ctx->was_disowned = TRUE; /* widget officially loses ownership */ 385 /* now inform widget */ 386 if (ctx->loses) { 387 if (ctx->incremental) 388 (*(XtLoseSelectionIncrProc)ctx->loses) 389 (widget, &ctx->selection, ctx->owner_closure); 390 else (*ctx->loses)(widget, &ctx->selection); 391 } 392 return(TRUE); 393 } 394 else return(FALSE); 395} 396 397static XContext selectWindowContext = 0; 398 399/* %%% Xlib.h should make this public! */ 400typedef int (*xErrorHandler)(Display*, XErrorEvent*); 401 402static xErrorHandler oldErrorHandler = NULL; 403static unsigned long firstProtectRequest; 404static Window errorWindow; 405 406static int LocalErrorHandler ( 407 Display *dpy, 408 XErrorEvent *error) 409{ 410 int retval; 411 412 /* If BadWindow error on selection requestor, nothing to do but let 413 * the transfer timeout. Otherwise, invoke saved error handler. */ 414 415 LOCK_PROCESS; 416 417 if (error->error_code == BadWindow && error->resourceid == errorWindow && 418 error->serial >= firstProtectRequest) { 419 UNLOCK_PROCESS; 420 return 0; 421 } 422 423 if (oldErrorHandler == NULL) { 424 UNLOCK_PROCESS; 425 return 0; /* should never happen */ 426 } 427 428 retval = (*oldErrorHandler)(dpy, error); 429 UNLOCK_PROCESS; 430 return retval; 431} 432 433static void StartProtectedSection( 434 Display *dpy, 435 Window window) 436{ 437 /* protect ourselves against request window being destroyed 438 * before completion of transfer */ 439 440 LOCK_PROCESS; 441 oldErrorHandler = XSetErrorHandler(LocalErrorHandler); 442 firstProtectRequest = NextRequest(dpy); 443 errorWindow = window; 444 UNLOCK_PROCESS; 445} 446 447static void EndProtectedSection( 448 Display *dpy) 449{ 450 /* flush any generated errors on requestor and 451 * restore original error handler */ 452 453 XSync(dpy, False); 454 455 LOCK_PROCESS; 456 XSetErrorHandler(oldErrorHandler); 457 oldErrorHandler = NULL; 458 UNLOCK_PROCESS; 459} 460 461static void AddHandler( 462 Request req, 463 EventMask mask, 464 XtEventHandler proc, 465 XtPointer closure) 466{ 467 Display *dpy = req->ctx->dpy; 468 Window window = req->requestor; 469 Widget widget = XtWindowToWidget(dpy, window); 470 471 if (widget != NULL) req->widget = widget; 472 else widget = req->widget; 473 474 if (XtWindow(widget) == window) 475 XtAddEventHandler(widget, mask, False, proc, closure); 476 else { 477 RequestWindowRec *requestWindowRec; 478 LOCK_PROCESS; 479 if (selectWindowContext == 0) 480 selectWindowContext = XUniqueContext(); 481 if (XFindContext(dpy, window, selectWindowContext, 482 (XPointer *)&requestWindowRec)) { 483 requestWindowRec = XtNew(RequestWindowRec); 484 requestWindowRec->active_transfer_count = 0; 485 (void)XSaveContext(dpy, window, selectWindowContext, 486 (char *)requestWindowRec); 487 } 488 UNLOCK_PROCESS; 489 if (requestWindowRec->active_transfer_count++ == 0) { 490 XtRegisterDrawable(dpy, window, widget); 491 XSelectInput(dpy, window, mask); 492 } 493 XtAddRawEventHandler(widget, mask, FALSE, proc, closure); 494 } 495} 496 497static void RemoveHandler( 498 Request req, 499 EventMask mask, 500 XtEventHandler proc, 501 XtPointer closure) 502{ 503 Display *dpy = req->ctx->dpy; 504 Window window = req->requestor; 505 Widget widget = req->widget; 506 507 if ((XtWindowToWidget(dpy, window) == widget) && 508 (XtWindow(widget) != window)) { 509 /* we had to hang this window onto our widget; take it off */ 510 RequestWindowRec* requestWindowRec; 511 XtRemoveRawEventHandler(widget, mask, TRUE, proc, closure); 512 LOCK_PROCESS; 513 (void)XFindContext(dpy, window, selectWindowContext, 514 (XPointer *)&requestWindowRec); 515 UNLOCK_PROCESS; 516 if (--requestWindowRec->active_transfer_count == 0) { 517 XtUnregisterDrawable(dpy, window); 518 StartProtectedSection(dpy, window); 519 XSelectInput(dpy, window, 0L); 520 EndProtectedSection(dpy); 521 LOCK_PROCESS; 522 (void)XDeleteContext(dpy, window, selectWindowContext); 523 UNLOCK_PROCESS; 524 XtFree((char*)requestWindowRec); 525 } 526 } else { 527 XtRemoveEventHandler(widget, mask, TRUE, proc, closure); 528 } 529} 530 531/* ARGSUSED */ 532static void OwnerTimedOut( 533 XtPointer closure, 534 XtIntervalId *id) 535{ 536 Request req = (Request)closure; 537 Select ctx = req->ctx; 538 539 if (ctx->incremental && (ctx->owner_cancel != NULL)) { 540 (*ctx->owner_cancel)(ctx->widget, &ctx->selection, 541 &req->target, (XtRequestId*)&req, 542 ctx->owner_closure); 543 } else { 544 if (ctx->notify == NULL) 545 XtFree((char*)req->value); 546 else { 547 /* the requestor hasn't deleted the property, but 548 * the owner needs to free the value. 549 */ 550 if (ctx->incremental) 551 (*(XtSelectionDoneIncrProc)ctx->notify) 552 (ctx->widget, &ctx->selection, &req->target, 553 (XtRequestId*)&req, ctx->owner_closure); 554 else 555 (*ctx->notify)(ctx->widget, &ctx->selection, &req->target); 556 } 557 } 558 559 RemoveHandler(req, (EventMask)PropertyChangeMask, 560 HandlePropertyGone, closure); 561 XtFree((char*)req); 562 if (--ctx->ref_count == 0 && ctx->free_when_done) 563 XtFree((char*)ctx); 564} 565 566static void SendIncrement( 567 Request incr) 568{ 569 Display *dpy = incr->ctx->dpy; 570 571 unsigned long incrSize = MAX_SELECTION_INCR(dpy); 572 if (incrSize > incr->bytelength - incr->offset) 573 incrSize = incr->bytelength - incr->offset; 574 StartProtectedSection(dpy, incr->requestor); 575 XChangeProperty(dpy, incr->requestor, incr->property, 576 incr->type, incr->format, PropModeReplace, 577 (unsigned char *)incr->value + incr->offset, 578 NUMELEM((int)incrSize, incr->format)); 579 EndProtectedSection(dpy); 580 incr->offset += incrSize; 581} 582 583static void AllSent( 584 Request req) 585{ 586 Select ctx = req->ctx; 587 StartProtectedSection(ctx->dpy, req->requestor); 588 XChangeProperty(ctx->dpy, req->requestor, 589 req->property, req->type, req->format, 590 PropModeReplace, (unsigned char *) NULL, 0); 591 EndProtectedSection(ctx->dpy); 592 req->allSent = TRUE; 593 594 if (ctx->notify == NULL) XtFree((char*)req->value); 595} 596 597/*ARGSUSED*/ 598static void HandlePropertyGone( 599 Widget widget, 600 XtPointer closure, 601 XEvent *ev, 602 Boolean *cont) 603{ 604 XPropertyEvent *event = (XPropertyEvent *) ev; 605 Request req = (Request)closure; 606 Select ctx = req->ctx; 607 608 if ((event->type != PropertyNotify) || 609 (event->state != PropertyDelete) || 610 (event->atom != req->property) || 611 (event->window != req->requestor)) 612 return; 613#ifndef DEBUG_WO_TIMERS 614 XtRemoveTimeOut(req->timeout); 615#endif 616 if (req->allSent) { 617 if (ctx->notify) { 618 if (ctx->incremental) { 619 (*(XtSelectionDoneIncrProc)ctx->notify) 620 (ctx->widget, &ctx->selection, &req->target, 621 (XtRequestId*)&req, ctx->owner_closure); 622 } 623 else (*ctx->notify)(ctx->widget, &ctx->selection, &req->target); 624 } 625 RemoveHandler(req, (EventMask)PropertyChangeMask, 626 HandlePropertyGone, closure); 627 XtFree((char*)req); 628 if (--ctx->ref_count == 0 && ctx->free_when_done) 629 XtFree((char*)ctx); 630 } else { /* is this part of an incremental transfer? */ 631 if (ctx->incremental) { 632 if (req->bytelength == 0) 633 AllSent(req); 634 else { 635 unsigned long size = MAX_SELECTION_INCR(ctx->dpy); 636 SendIncrement(req); 637 (*(XtConvertSelectionIncrProc)ctx->convert) 638 (ctx->widget, &ctx->selection, &req->target, 639 &req->type, &req->value, 640 &req->bytelength, &req->format, 641 &size, ctx->owner_closure, (XtPointer*)&req); 642 if (req->bytelength) 643 req->bytelength = BYTELENGTH(req->bytelength, req->format); 644 req->offset = 0; 645 } 646 } else { 647 if (req->offset < req->bytelength) 648 SendIncrement(req); 649 else AllSent(req); 650 } 651#ifndef DEBUG_WO_TIMERS 652 { 653 XtAppContext app = XtWidgetToApplicationContext(req->widget); 654 req->timeout = XtAppAddTimeOut(app, 655 app->selectionTimeout, OwnerTimedOut, (XtPointer)req); 656 } 657#endif 658 } 659} 660 661static void PrepareIncremental( 662 Request req, 663 Widget widget, 664 Window window, 665 Atom property, 666 Atom target, 667 Atom targetType, 668 XtPointer value, 669 unsigned long length, 670 int format) 671{ 672 req->type = targetType; 673 req->value = value; 674 req->bytelength = BYTELENGTH(length,format); 675 req->format = format; 676 req->offset = 0; 677 req->target = target; 678 req->widget = widget; 679 req->allSent = FALSE; 680#ifndef DEBUG_WO_TIMERS 681 { 682 XtAppContext app = XtWidgetToApplicationContext(widget); 683 req->timeout = XtAppAddTimeOut(app, 684 app->selectionTimeout, OwnerTimedOut, (XtPointer)req); 685 } 686#endif 687 AddHandler(req, (EventMask)PropertyChangeMask, 688 HandlePropertyGone, (XtPointer)req); 689/* now send client INCR property */ 690 XChangeProperty(req->ctx->dpy, window, req->property, 691 req->ctx->prop_list->incr_atom, 692 32, PropModeReplace, 693 (unsigned char *)&req->bytelength, 1); 694} 695 696static Boolean GetConversion( 697 Select ctx, /* logical owner */ 698 XSelectionRequestEvent* event, 699 Atom target, 700 Atom property, /* requestor's property */ 701 Widget widget) /* physical owner (receives events) */ 702{ 703 XtPointer value = NULL; 704 unsigned long length; 705 int format; 706 Atom targetType; 707 Request req = XtNew(RequestRec); 708 Boolean timestamp_target = (target == ctx->prop_list->timestamp_atom); 709 710 req->ctx = ctx; 711 req->event = *event; 712 req->property = property; 713 req->requestor = event->requestor; 714 715 if (timestamp_target) { 716 value = __XtMalloc(sizeof(long)); 717 *(long*)value = ctx->time; 718 targetType = XA_INTEGER; 719 length = 1; 720 format = 32; 721 } 722 else { 723 ctx->ref_count++; 724 if (ctx->incremental == TRUE) { 725 unsigned long size = MAX_SELECTION_INCR(ctx->dpy); 726 if ((*(XtConvertSelectionIncrProc)ctx->convert) 727 (ctx->widget, &event->selection, &target, 728 &targetType, &value, &length, &format, 729 &size, ctx->owner_closure, (XtRequestId*)&req) 730 == FALSE) { 731 XtFree((char*)req); 732 ctx->ref_count--; 733 return(FALSE); 734 } 735 StartProtectedSection(ctx->dpy, event->requestor); 736 PrepareIncremental(req, widget, event->requestor, property, 737 target, targetType, value, length, format); 738 return(TRUE); 739 } 740 ctx->req = req; 741 if ((*ctx->convert)(ctx->widget, &event->selection, &target, 742 &targetType, &value, &length, &format) == FALSE) { 743 XtFree((char*)req); 744 ctx->req = NULL; 745 ctx->ref_count--; 746 return(FALSE); 747 } 748 ctx->req = NULL; 749 } 750 StartProtectedSection(ctx->dpy, event->requestor); 751 if (BYTELENGTH(length,format) <= (unsigned long) MAX_SELECTION_INCR(ctx->dpy)) { 752 if (! timestamp_target) { 753 if (ctx->notify != NULL) { 754 req->target = target; 755 req->widget = widget; 756 req->allSent = TRUE; 757#ifndef DEBUG_WO_TIMERS 758 { 759 XtAppContext app = XtWidgetToApplicationContext(req->widget); 760 req->timeout = XtAppAddTimeOut(app, 761 app->selectionTimeout, OwnerTimedOut, (XtPointer)req); 762 } 763#endif 764 AddHandler(req, (EventMask)PropertyChangeMask, 765 HandlePropertyGone, (XtPointer)req); 766 } 767 else ctx->ref_count--; 768 } 769 XChangeProperty(ctx->dpy, event->requestor, property, 770 targetType, format, PropModeReplace, 771 (unsigned char *)value, (int)length); 772 /* free storage for client if no notify proc */ 773 if (timestamp_target || ctx->notify == NULL) { 774 XtFree((char*)value); 775 XtFree((char*)req); 776 } 777 } else { 778 PrepareIncremental(req, widget, event->requestor, property, 779 target, targetType, value, length, format); 780 } 781 return(TRUE); 782} 783 784/*ARGSUSED*/ 785static void HandleSelectionEvents( 786 Widget widget, 787 XtPointer closure, 788 XEvent *event, 789 Boolean *cont) 790{ 791 Select ctx; 792 XSelectionEvent ev; 793 Atom target; 794 int count; 795 Boolean writeback = FALSE; 796 797 ctx = (Select) closure; 798 switch (event->type) { 799 case SelectionClear: 800 /* if this event is not for the selection we registered for, 801 * don't do anything */ 802 if (ctx->selection != event->xselectionclear.selection || 803 ctx->serial > event->xselectionclear.serial) 804 break; 805 (void) LoseSelection(ctx, widget, event->xselectionclear.selection, 806 event->xselectionclear.time); 807 break; 808 case SelectionRequest: 809 /* if this event is not for the selection we registered for, 810 * don't do anything */ 811 if (ctx->selection != event->xselectionrequest.selection) 812 break; 813 ev.type = SelectionNotify; 814 ev.display = event->xselectionrequest.display; 815 ev.requestor = event->xselectionrequest.requestor; 816 ev.selection = event->xselectionrequest.selection; 817 ev.time = event->xselectionrequest.time; 818 ev.target = event->xselectionrequest.target; 819 if (event->xselectionrequest.property == None) /* obsolete requestor */ 820 event->xselectionrequest.property = event->xselectionrequest.target; 821 if (ctx->widget != widget || ctx->was_disowned 822 || ((event->xselectionrequest.time != CurrentTime) 823 && (event->xselectionrequest.time < ctx->time))) 824 ev.property = None; 825 else { 826 if (ev.target == ctx->prop_list->indirect_atom) { 827 IndirectPair *p; 828 int format; 829 unsigned long bytesafter, length; 830 unsigned char *value; 831 ev.property = event->xselectionrequest.property; 832 StartProtectedSection(ev.display, ev.requestor); 833 (void) XGetWindowProperty(ev.display, ev.requestor, 834 event->xselectionrequest.property, 0L, 1000000, 835 False,(Atom)AnyPropertyType, &target, &format, &length, 836 &bytesafter, &value); 837 count = BYTELENGTH(length, format) / sizeof(IndirectPair); 838 for (p = (IndirectPair *)value; count; p++, count--) { 839 EndProtectedSection(ctx->dpy); 840 if (!GetConversion(ctx, (XSelectionRequestEvent*)event, 841 p->target, p->property, widget)) { 842 843 p->target = None; 844 writeback = TRUE; 845 StartProtectedSection(ctx->dpy, ev.requestor); 846 } 847 } 848 if (writeback) 849 XChangeProperty(ev.display, ev.requestor, 850 event->xselectionrequest.property, target, 851 format, PropModeReplace, value, (int)length); 852 XFree((char *)value); 853 } else /* not multiple */ { 854 if (GetConversion(ctx, (XSelectionRequestEvent*)event, 855 event->xselectionrequest.target, 856 event->xselectionrequest.property, 857 widget)) 858 ev.property = event->xselectionrequest.property; 859 else { 860 ev.property = None; 861 StartProtectedSection(ctx->dpy, ev.requestor); 862 } 863 } 864 } 865 (void) XSendEvent(ctx->dpy, ev.requestor, False, (unsigned long)NULL, 866 (XEvent *) &ev); 867 868 EndProtectedSection(ctx->dpy); 869 870 break; 871 } 872} 873 874static Boolean OwnSelection( 875 Widget widget, 876 Atom selection, 877 Time time, 878 XtConvertSelectionProc convert, 879 XtLoseSelectionProc lose, 880 XtSelectionDoneProc notify, 881 XtCancelConvertSelectionProc cancel, 882 XtPointer closure, 883 Boolean incremental) 884{ 885 Select ctx; 886 Select oldctx = NULL; 887 888 if (!XtIsRealized(widget)) return False; 889 890 ctx = FindCtx(XtDisplay(widget), selection); 891 if (ctx->widget != widget || ctx->time != time || 892 ctx->ref_count || ctx->was_disowned) 893 { 894 Boolean replacement = FALSE; 895 Window window = XtWindow(widget); 896 unsigned long serial = XNextRequest(ctx->dpy); 897 XSetSelectionOwner(ctx->dpy, selection, window, time); 898 if (XGetSelectionOwner(ctx->dpy, selection) != window) 899 return FALSE; 900 if (ctx->ref_count) { /* exchange is in-progress */ 901#ifdef DEBUG_ACTIVE 902 printf( "Active exchange for widget \"%s\"; selection=0x%lx, ref_count=%d\n", 903 XtName(widget), (long)selection, ctx->ref_count ); 904#endif 905 if (ctx->widget != widget || 906 ctx->convert != convert || 907 ctx->loses != lose || 908 ctx->notify != notify || 909 ctx->owner_cancel != cancel || 910 ctx->incremental != incremental || 911 ctx->owner_closure != closure) 912 { 913 if (ctx->widget == widget) { 914 XtRemoveEventHandler(widget, (EventMask)0, TRUE, 915 HandleSelectionEvents, (XtPointer)ctx); 916 XtRemoveCallback(widget, XtNdestroyCallback, 917 WidgetDestroyed, (XtPointer)ctx); 918 replacement = TRUE; 919 } 920 else if (!ctx->was_disowned) { 921 oldctx = ctx; 922 } 923 ctx->free_when_done = TRUE; 924 ctx = NewContext(XtDisplay(widget), selection); 925 } 926 else if (!ctx->was_disowned) { /* current owner is new owner */ 927 ctx->time = time; 928 return TRUE; 929 } 930 } 931 if (ctx->widget != widget || ctx->was_disowned || replacement) { 932 if (ctx->widget && !ctx->was_disowned && !replacement) { 933 oldctx = ctx; 934 oldctx->free_when_done = TRUE; 935 ctx = NewContext(XtDisplay(widget), selection); 936 } 937 XtAddEventHandler(widget, (EventMask)0, TRUE, 938 HandleSelectionEvents, (XtPointer)ctx); 939 XtAddCallback(widget, XtNdestroyCallback, 940 WidgetDestroyed, (XtPointer)ctx); 941 } 942 ctx->widget = widget; /* Selection offically changes hands. */ 943 ctx->time = time; 944 ctx->serial = serial; 945 } 946 ctx->convert = convert; 947 ctx->loses = lose; 948 ctx->notify = notify; 949 ctx->owner_cancel = cancel; 950 ctx->incremental = incremental; 951 ctx->owner_closure = closure; 952 ctx->was_disowned = FALSE; 953 954 /* Defer calling the previous selection owner's lose selection procedure 955 * until the new selection is established, to allow the previous 956 * selection owner to ask for the new selection to be converted in 957 * the lose selection procedure. The context pointer is the closure 958 * of the event handler and the destroy callback, so the old context 959 * pointer and the record contents must be preserved for LoseSelection. 960 */ 961 if (oldctx) { 962 (void) LoseSelection(oldctx, oldctx->widget, selection, oldctx->time); 963 if (!oldctx->ref_count && oldctx->free_when_done) 964 XtFree((char*)oldctx); 965 } 966 return TRUE; 967} 968 969 970Boolean XtOwnSelection( 971 Widget widget, 972 Atom selection, 973 Time time, 974 XtConvertSelectionProc convert, 975 XtLoseSelectionProc lose, 976 XtSelectionDoneProc notify) 977{ 978 Boolean retval; 979 WIDGET_TO_APPCON(widget); 980 981 LOCK_APP(app); 982 retval = OwnSelection(widget, selection, time, convert, lose, notify, 983 (XtCancelConvertSelectionProc)NULL, 984 (XtPointer)NULL, FALSE); 985 UNLOCK_APP(app); 986 return retval; 987} 988 989 990Boolean XtOwnSelectionIncremental( 991 Widget widget, 992 Atom selection, 993 Time time, 994 XtConvertSelectionIncrProc convert, 995 XtLoseSelectionIncrProc lose, 996 XtSelectionDoneIncrProc notify, 997 XtCancelConvertSelectionProc cancel, 998 XtPointer closure) 999{ 1000 Boolean retval; 1001 WIDGET_TO_APPCON(widget); 1002 1003 LOCK_APP(app); 1004 retval = OwnSelection(widget, selection, time, 1005 (XtConvertSelectionProc)convert, 1006 (XtLoseSelectionProc)lose, 1007 (XtSelectionDoneProc)notify, 1008 cancel, closure, TRUE); 1009 UNLOCK_APP(app); 1010 return retval; 1011} 1012 1013 1014void XtDisownSelection( 1015 Widget widget, 1016 Atom selection, 1017 Time time) 1018{ 1019 Select ctx; 1020 WIDGET_TO_APPCON(widget); 1021 1022 LOCK_APP(app); 1023 ctx = FindCtx(XtDisplay(widget), selection); 1024 if (LoseSelection(ctx, widget, selection, time)) 1025 XSetSelectionOwner(XtDisplay(widget), selection, None, time); 1026 UNLOCK_APP(app); 1027} 1028 1029/* Selection Requestor code */ 1030 1031static Boolean IsINCRtype( 1032 CallBackInfo info, 1033 Window window, 1034 Atom prop) 1035{ 1036 unsigned long bytesafter; 1037 unsigned long length; 1038 int format; 1039 Atom type; 1040 unsigned char *value; 1041 1042 if (prop == None) return False; 1043 1044 (void)XGetWindowProperty(XtDisplay(info->widget), window, prop, 0L, 0L, 1045 False, info->ctx->prop_list->incr_atom, 1046 &type, &format, &length, &bytesafter, &value); 1047 1048 return (type == info->ctx->prop_list->incr_atom); 1049} 1050 1051/*ARGSUSED*/ 1052static void ReqCleanup( 1053 Widget widget, 1054 XtPointer closure, 1055 XEvent *ev, 1056 Boolean *cont) 1057{ 1058 CallBackInfo info = (CallBackInfo)closure; 1059 unsigned long bytesafter, length; 1060 char *value; 1061 int format; 1062 Atom target; 1063 1064 if (ev->type == SelectionNotify) { 1065 XSelectionEvent *event = (XSelectionEvent *) ev; 1066 if (!MATCH_SELECT(event, info)) return; /* not really for us */ 1067 XtRemoveEventHandler(widget, (EventMask)0, TRUE, 1068 ReqCleanup, (XtPointer) info ); 1069 if (IsINCRtype(info, XtWindow(widget), event->property)) { 1070 info->proc = HandleGetIncrement; 1071 XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask, 1072 FALSE, ReqCleanup, (XtPointer) info); 1073 } else { 1074 if (event->property != None) 1075 XDeleteProperty(event->display, XtWindow(widget), 1076 event->property); 1077 FreeSelectionProperty(XtDisplay(widget), info->property); 1078 FreeInfo(info); 1079 } 1080 } else if ((ev->type == PropertyNotify) && 1081 (ev->xproperty.state == PropertyNewValue) && 1082 (ev->xproperty.atom == info->property)) { 1083 XPropertyEvent *event = (XPropertyEvent *) ev; 1084 (void) XGetWindowProperty(event->display, XtWindow(widget), 1085 event->atom, 0L, 1000000, True, AnyPropertyType, 1086 &target, &format, &length, &bytesafter, 1087 (unsigned char **) &value); 1088 XFree(value); 1089 if (length == 0) { 1090 XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, 1091 ReqCleanup, (XtPointer) info ); 1092 FreeSelectionProperty(XtDisplay(widget), info->property); 1093 XtFree(info->value); /* requestor never got this, so free now */ 1094 FreeInfo(info); 1095 } 1096 } 1097} 1098 1099/* ARGSUSED */ 1100static void ReqTimedOut( 1101 XtPointer closure, 1102 XtIntervalId *id) 1103{ 1104 XtPointer value = NULL; 1105 unsigned long length = 0; 1106 int format = 8; 1107 Atom resulttype = XT_CONVERT_FAIL; 1108 CallBackInfo info = (CallBackInfo)closure; 1109 unsigned long bytesafter; 1110 unsigned long proplength; 1111 Atom type; 1112 IndirectPair *pairs; 1113 XtPointer *c; 1114 int i; 1115 1116 if (*info->target == info->ctx->prop_list->indirect_atom) { 1117 (void) XGetWindowProperty(XtDisplay(info->widget), 1118 XtWindow(info->widget), info->property, 0L, 1119 10000000, True, AnyPropertyType, &type, &format, 1120 &proplength, &bytesafter, (unsigned char **) &pairs); 1121 XFree((char*)pairs); 1122 for (proplength = proplength / IndirectPairWordSize, i = 0, c = info->req_closure; 1123 proplength; proplength--, c++, i++) 1124 (*info->callbacks[i])(info->widget, *c, 1125 &info->ctx->selection, &resulttype, value, &length, &format); 1126 } else { 1127 (*info->callbacks[0])(info->widget, *info->req_closure, 1128 &info->ctx->selection, &resulttype, value, &length, &format); 1129 } 1130 1131 /* change event handlers for straggler events */ 1132 if (info->proc == (XtEventHandler)HandleSelectionReplies) { 1133 XtRemoveEventHandler(info->widget, (EventMask)0, 1134 TRUE, info->proc, (XtPointer) info); 1135 XtAddEventHandler(info->widget, (EventMask)0, TRUE, 1136 ReqCleanup, (XtPointer) info); 1137 } else { 1138 XtRemoveEventHandler(info->widget,(EventMask) PropertyChangeMask, 1139 FALSE, info->proc, (XtPointer) info); 1140 XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask, 1141 FALSE, ReqCleanup, (XtPointer) info); 1142 } 1143 1144} 1145 1146/*ARGSUSED*/ 1147static void HandleGetIncrement( 1148 Widget widget, 1149 XtPointer closure, 1150 XEvent *ev, 1151 Boolean *cont) 1152{ 1153 XPropertyEvent *event = (XPropertyEvent *) ev; 1154 CallBackInfo info = (CallBackInfo) closure; 1155 Select ctx = info->ctx; 1156 char *value; 1157 unsigned long bytesafter; 1158 unsigned long length; 1159 int bad; 1160 int n = info->current; 1161 1162 if ((event->state != PropertyNewValue) || (event->atom != info->property)) 1163 return; 1164 1165 bad = XGetWindowProperty(event->display, XtWindow(widget), 1166 event->atom, 0L, 1167 10000000, True, AnyPropertyType, &info->type, 1168 &info->format, &length, &bytesafter, 1169 (unsigned char **) &value); 1170 if (bad) 1171 return; 1172#ifndef DEBUG_WO_TIMERS 1173 XtRemoveTimeOut(info->timeout); 1174#endif 1175 if (length == 0) { 1176 unsigned long u_offset = NUMELEM(info->offset, info->format); 1177 (*info->callbacks[n])(widget, *info->req_closure, &ctx->selection, 1178 &info->type, 1179 (info->offset == 0 ? value : info->value), 1180 &u_offset, &info->format); 1181 /* assert ((info->offset != 0) == (info->incremental[n]) */ 1182 if (info->offset != 0) XFree(value); 1183 XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, 1184 HandleGetIncrement, (XtPointer) info); 1185 FreeSelectionProperty(event->display, info->property); 1186 FreeInfo(info); 1187 } else { /* add increment to collection */ 1188 if (info->incremental[n]) { 1189#ifdef XT_COPY_SELECTION 1190 int size = BYTELENGTH(length, info->format) + 1; 1191 char *tmp = __XtMalloc((Cardinal) size); 1192 (void) memmove(tmp, value, size); 1193 XFree(value); 1194 value = tmp; 1195#endif 1196 (*info->callbacks[n])(widget, *info->req_closure, &ctx->selection, 1197 &info->type, value, &length, &info->format); 1198 } else { 1199 int size = BYTELENGTH(length, info->format); 1200 if (info->offset + size > info->bytelength) { 1201 /* allocate enough for this and the next increment */ 1202 info->bytelength = info->offset + size * 2; 1203 info->value = XtRealloc(info->value, 1204 (Cardinal) info->bytelength); 1205 } 1206 (void) memmove(&info->value[info->offset], value, size); 1207 info->offset += size; 1208 XFree(value); 1209 } 1210 /* reset timer */ 1211#ifndef DEBUG_WO_TIMERS 1212 { 1213 XtAppContext app = XtWidgetToApplicationContext(info->widget); 1214 info->timeout = XtAppAddTimeOut(app, 1215 app->selectionTimeout, ReqTimedOut, (XtPointer) info); 1216 } 1217#endif 1218 } 1219} 1220 1221 1222static void HandleNone( 1223 Widget widget, 1224 XtSelectionCallbackProc callback, 1225 XtPointer closure, 1226 Atom selection) 1227{ 1228 unsigned long length = 0; 1229 int format = 8; 1230 Atom type = None; 1231 1232 (*callback)(widget, closure, &selection, 1233 &type, NULL, &length, &format); 1234} 1235 1236 1237static long IncrPropSize( 1238 Widget widget, 1239 unsigned char* value, 1240 int format, 1241 unsigned long length) 1242{ 1243 unsigned long size; 1244 if (format == 32) { 1245 size = ((long*)value)[length-1]; /* %%% what order for longs? */ 1246 return size; 1247 } 1248 else { 1249 XtAppWarningMsg( XtWidgetToApplicationContext(widget), 1250 "badFormat","xtGetSelectionValue",XtCXtToolkitError, 1251 "Selection owner returned type INCR property with format != 32", 1252 (String*)NULL, (Cardinal*)NULL ); 1253 return 0; 1254 } 1255} 1256 1257 1258static 1259Boolean HandleNormal( 1260 Display *dpy, 1261 Widget widget, 1262 Atom property, 1263 CallBackInfo info, 1264 XtPointer closure, 1265 Atom selection) 1266{ 1267 unsigned long bytesafter; 1268 unsigned long length; 1269 int format; 1270 Atom type; 1271 unsigned char *value; 1272 int number = info->current; 1273 1274 (void) XGetWindowProperty(dpy, XtWindow(widget), property, 0L, 1275 10000000, False, AnyPropertyType, 1276 &type, &format, &length, &bytesafter, &value); 1277 1278 if (type == info->ctx->prop_list->incr_atom) { 1279 unsigned long size = IncrPropSize(widget, value, format, length); 1280 XFree((char *)value); 1281 if (info->property != property) { 1282 /* within MULTIPLE */ 1283 CallBackInfo ninfo; 1284 ninfo = MakeInfo(info->ctx, &info->callbacks[number], 1285 &info->req_closure[number], 1, widget, 1286 info->time, &info->incremental[number], &property); 1287 ninfo->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom)); 1288 *ninfo->target = info->target[number + 1]; 1289 info = ninfo; 1290 } 1291 HandleIncremental(dpy, widget, property, info, size); 1292 return FALSE; 1293 } 1294 1295 XDeleteProperty(dpy, XtWindow(widget), property); 1296#ifdef XT_COPY_SELECTION 1297 if (value) { /* it could have been deleted after the SelectionNotify */ 1298 int size = BYTELENGTH(length, info->format) + 1; 1299 char *tmp = __XtMalloc((Cardinal) size); 1300 (void) memmove(tmp, value, size); 1301 XFree(value); 1302 value = (unsigned char *) tmp; 1303 } 1304#endif 1305 (*info->callbacks[number])(widget, closure, &selection, 1306 &type, (XtPointer)value, &length, &format); 1307 1308 if (info->incremental[number]) { 1309 /* let requestor know the whole thing has been received */ 1310 value = (unsigned char*)__XtMalloc((unsigned)1); 1311 length = 0; 1312 (*info->callbacks[number])(widget, closure, &selection, 1313 &type, (XtPointer)value, &length, &format); 1314 } 1315 return TRUE; 1316} 1317 1318static void HandleIncremental( 1319 Display *dpy, 1320 Widget widget, 1321 Atom property, 1322 CallBackInfo info, 1323 unsigned long size) 1324{ 1325 XtAddEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, 1326 HandleGetIncrement, (XtPointer) info); 1327 1328 /* now start the transfer */ 1329 XDeleteProperty(dpy, XtWindow(widget), property); 1330 XFlush(dpy); 1331 1332 info->bytelength = size; 1333 if (info->incremental[info->current]) /* requestor wants incremental too */ 1334 info->value = NULL; /* so no need for buffer to assemble value */ 1335 else 1336 info->value = (char *) __XtMalloc((unsigned) info->bytelength); 1337 info->offset = 0; 1338 1339 /* reset the timer */ 1340 info->proc = HandleGetIncrement; 1341#ifndef DEBUG_WO_TIMERS 1342 { 1343 XtAppContext app = XtWidgetToApplicationContext(info->widget); 1344 info->timeout = XtAppAddTimeOut(app, 1345 app->selectionTimeout, ReqTimedOut, (XtPointer) info); 1346 } 1347#endif 1348} 1349 1350/*ARGSUSED*/ 1351static void HandleSelectionReplies( 1352 Widget widget, 1353 XtPointer closure, 1354 XEvent *ev, 1355 Boolean *cont) 1356{ 1357 XSelectionEvent *event = (XSelectionEvent *) ev; 1358 Display *dpy = event->display; 1359 CallBackInfo info = (CallBackInfo) closure; 1360 Select ctx = info->ctx; 1361 IndirectPair *pairs, *p; 1362 unsigned long bytesafter; 1363 unsigned long length; 1364 int format; 1365 Atom type; 1366 XtPointer *c; 1367 1368 if (event->type != SelectionNotify) return; 1369 if (!MATCH_SELECT(event, info)) return; /* not really for us */ 1370#ifndef DEBUG_WO_TIMERS 1371 XtRemoveTimeOut(info->timeout); 1372#endif 1373 XtRemoveEventHandler(widget, (EventMask)0, TRUE, 1374 HandleSelectionReplies, (XtPointer) info ); 1375 if (event->target == ctx->prop_list->indirect_atom) { 1376 (void) XGetWindowProperty(dpy, XtWindow(widget), info->property, 0L, 1377 10000000, True, AnyPropertyType, &type, &format, 1378 &length, &bytesafter, (unsigned char **) &pairs); 1379 for (length = length / IndirectPairWordSize, p = pairs, 1380 c = info->req_closure; 1381 length; length--, p++, c++, info->current++) { 1382 if (event->property == None || format != 32 || p->target == None 1383 || /* bug compatibility */ p->property == None) { 1384 HandleNone(widget, info->callbacks[info->current], 1385 *c, event->selection); 1386 if (p->property != None) 1387 FreeSelectionProperty(XtDisplay(widget), p->property); 1388 } else { 1389 if (HandleNormal(dpy, widget, p->property, info, *c, 1390 event->selection)) { 1391 FreeSelectionProperty(XtDisplay(widget), p->property); 1392 } 1393 } 1394 } 1395 XFree((char*)pairs); 1396 FreeSelectionProperty(dpy, info->property); 1397 FreeInfo(info); 1398 } else if (event->property == None) { 1399 HandleNone(widget, info->callbacks[0], *info->req_closure, event->selection); 1400 FreeSelectionProperty(XtDisplay(widget), info->property); 1401 FreeInfo(info); 1402 } else { 1403 if (HandleNormal(dpy, widget, event->property, info, 1404 *info->req_closure, event->selection)) { 1405 FreeSelectionProperty(XtDisplay(widget), info->property); 1406 FreeInfo(info); 1407 } 1408 } 1409} 1410 1411static void DoLocalTransfer( 1412 Request req, 1413 Atom selection, 1414 Atom target, 1415 Widget widget, /* The widget requesting the value. */ 1416 XtSelectionCallbackProc callback, 1417 XtPointer closure, /* the closure for the callback, not the conversion */ 1418 Boolean incremental, 1419 Atom property) 1420{ 1421 Select ctx = req->ctx; 1422 XtPointer value = NULL, temp, total = NULL; 1423 unsigned long length; 1424 int format; 1425 Atom resulttype; 1426 unsigned long totallength = 0; 1427 1428 req->event.type = 0; 1429 req->event.target = target; 1430 req->event.property = req->property = property; 1431 req->event.requestor = req->requestor = XtWindow(widget); 1432 1433 if (ctx->incremental) { 1434 unsigned long size = MAX_SELECTION_INCR(ctx->dpy); 1435 if (!(*(XtConvertSelectionIncrProc)ctx->convert) 1436 (ctx->widget, &selection, &target, 1437 &resulttype, &value, &length, &format, 1438 &size, ctx->owner_closure, (XtRequestId*)&req)) { 1439 HandleNone(widget, callback, closure, selection); 1440 } 1441 else { 1442 if (incremental) { 1443 Boolean allSent = FALSE; 1444 while (!allSent) { 1445 if (ctx->notify && (value != NULL)) { 1446 int bytelength = BYTELENGTH(length,format); 1447 /* both sides think they own this storage */ 1448 temp = __XtMalloc((unsigned)bytelength); 1449 (void) memmove(temp, value, bytelength); 1450 value = temp; 1451 } 1452 /* use care; older clients were never warned that 1453 * they must return a value even if length==0 1454 */ 1455 if (value == NULL) value = __XtMalloc((unsigned)1); 1456 (*callback)(widget, closure, &selection, 1457 &resulttype, value, &length, &format); 1458 if (length) { 1459 /* should owner be notified on end-of-piece? 1460 * Spec is unclear, but non-local transfers don't. 1461 */ 1462 (*(XtConvertSelectionIncrProc)ctx->convert) 1463 (ctx->widget, &selection, &target, 1464 &resulttype, &value, &length, &format, 1465 &size, ctx->owner_closure, 1466 (XtRequestId*)&req); 1467 } 1468 else allSent = TRUE; 1469 } 1470 } else { 1471 while (length) { 1472 int bytelength = BYTELENGTH(length, format); 1473 total = XtRealloc(total, 1474 (unsigned) (totallength += bytelength)); 1475 (void) memmove((char*)total + totallength - bytelength, 1476 value, 1477 bytelength); 1478 (*(XtConvertSelectionIncrProc)ctx->convert) 1479 (ctx->widget, &selection, &target, 1480 &resulttype, &value, &length, &format, 1481 &size, ctx->owner_closure, (XtRequestId*)&req); 1482 } 1483 if (total == NULL) total = __XtMalloc(1); 1484 totallength = NUMELEM(totallength, format); 1485 (*callback)(widget, closure, &selection, &resulttype, 1486 total, &totallength, &format); 1487 } 1488 if (ctx->notify) 1489 (*(XtSelectionDoneIncrProc)ctx->notify) 1490 (ctx->widget, &selection, &target, 1491 (XtRequestId*)&req, ctx->owner_closure); 1492 else XtFree((char*)value); 1493 } 1494 } else { /* not incremental owner */ 1495 if (!(*ctx->convert)(ctx->widget, &selection, &target, 1496 &resulttype, &value, &length, &format)) { 1497 HandleNone(widget, callback, closure, selection); 1498 } else { 1499 if (ctx->notify && (value != NULL)) { 1500 int bytelength = BYTELENGTH(length,format); 1501 /* both sides think they own this storage; better copy */ 1502 temp = __XtMalloc((unsigned)bytelength); 1503 (void) memmove(temp, value, bytelength); 1504 value = temp; 1505 } 1506 if (value == NULL) value = __XtMalloc((unsigned)1); 1507 (*callback)(widget, closure, &selection, &resulttype, 1508 value, &length, &format); 1509 if (ctx->notify) 1510 (*ctx->notify)(ctx->widget, &selection, &target); 1511 } 1512 } 1513} 1514 1515static void GetSelectionValue( 1516 Widget widget, 1517 Atom selection, 1518 Atom target, 1519 XtSelectionCallbackProc callback, 1520 XtPointer closure, 1521 Time time, 1522 Boolean incremental, 1523 Atom property) 1524{ 1525 Select ctx; 1526 CallBackInfo info; 1527 Atom properties[1]; 1528 1529 properties[0] = property; 1530 1531 ctx = FindCtx(XtDisplay(widget), selection); 1532 if (ctx->widget && !ctx->was_disowned) { 1533 RequestRec req; 1534 ctx->req = &req; 1535 req.ctx = ctx; 1536 req.event.time = time; 1537 ctx->ref_count++; 1538 DoLocalTransfer(&req, selection, target, widget, 1539 callback, closure, incremental, property); 1540 if (--ctx->ref_count == 0 && ctx->free_when_done) 1541 XtFree((char*)ctx); 1542 else 1543 ctx->req = NULL; 1544 } 1545 else { 1546 info = MakeInfo(ctx, &callback, &closure, 1, widget, 1547 time, &incremental, properties); 1548 info->target = (Atom *)__XtMalloc((unsigned) sizeof(Atom)); 1549 *(info->target) = target; 1550 RequestSelectionValue(info, selection, target); 1551 } 1552} 1553 1554 1555void XtGetSelectionValue( 1556 Widget widget, 1557 Atom selection, 1558 Atom target, 1559 XtSelectionCallbackProc callback, 1560 XtPointer closure, 1561 Time time) 1562{ 1563 Atom property; 1564 Boolean incr = False; 1565 WIDGET_TO_APPCON(widget); 1566 1567 LOCK_APP(app); 1568 property = GetParamInfo(widget, selection); 1569 RemoveParamInfo(widget, selection); 1570 1571 if (IsGatheringRequest(widget, selection)) { 1572 AddSelectionRequests(widget, selection, 1, &target, &callback, 1, 1573 &closure, &incr, &property); 1574 } else { 1575 GetSelectionValue(widget, selection, target, callback, 1576 closure, time, FALSE, property); 1577 } 1578 UNLOCK_APP(app); 1579} 1580 1581 1582void XtGetSelectionValueIncremental( 1583 Widget widget, 1584 Atom selection, 1585 Atom target, 1586 XtSelectionCallbackProc callback, 1587 XtPointer closure, 1588 Time time) 1589{ 1590 Atom property; 1591 Boolean incr = TRUE; 1592 WIDGET_TO_APPCON(widget); 1593 1594 LOCK_APP(app); 1595 property = GetParamInfo(widget, selection); 1596 RemoveParamInfo(widget, selection); 1597 1598 if (IsGatheringRequest(widget, selection)) { 1599 AddSelectionRequests(widget, selection, 1, &target, &callback, 1, 1600 &closure, &incr, &property); 1601 } else { 1602 GetSelectionValue(widget, selection, target, callback, 1603 closure, time, TRUE, property); 1604 } 1605 1606 UNLOCK_APP(app); 1607} 1608 1609 1610static void GetSelectionValues( 1611 Widget widget, 1612 Atom selection, 1613 Atom *targets, 1614 int count, 1615 XtSelectionCallbackProc *callbacks, 1616 int num_callbacks, 1617 XtPointer *closures, 1618 Time time, 1619 Boolean *incremental, 1620 Atom *properties) 1621{ 1622 Select ctx; 1623 CallBackInfo info; 1624 IndirectPair *pairs, *p; 1625 Atom *t; 1626 1627 if (count == 0) return; 1628 ctx = FindCtx(XtDisplay(widget), selection); 1629 if (ctx->widget && !ctx->was_disowned) { 1630 int j, i; 1631 RequestRec req; 1632 ctx->req = &req; 1633 req.ctx = ctx; 1634 req.event.time = time; 1635 ctx->ref_count++; 1636 for (i = 0, j = 0; count; count--, i++, j++ ) { 1637 if (j >= num_callbacks) j = 0; 1638 1639 DoLocalTransfer(&req, selection, targets[i], widget, 1640 callbacks[j], closures[i], incremental[i], 1641 properties ? properties[i] : None); 1642 1643 } 1644 if (--ctx->ref_count == 0 && ctx->free_when_done) 1645 XtFree((char*)ctx); 1646 else 1647 ctx->req = NULL; 1648 } else { 1649 XtSelectionCallbackProc *passed_callbacks; 1650 XtSelectionCallbackProc stack_cbs[32]; 1651 int i = 0, j = 0; 1652 1653 passed_callbacks = (XtSelectionCallbackProc *) 1654 XtStackAlloc(sizeof(XtSelectionCallbackProc) * count, stack_cbs); 1655 1656 /* To deal with the old calls from XtGetSelectionValues* we 1657 will repeat however many callbacks have been passed into 1658 the array */ 1659 for(i = 0; i < count; i++) { 1660 if (j >= num_callbacks) j = 0; 1661 passed_callbacks[i] = callbacks[j]; 1662 j++; 1663 } 1664 info = MakeInfo(ctx, passed_callbacks, closures, count, widget, 1665 time, incremental, properties); 1666 XtStackFree((XtPointer) passed_callbacks, stack_cbs); 1667 1668 info->target = (Atom *)__XtMalloc((unsigned) ((count+1) * sizeof(Atom))); 1669 (*info->target) = ctx->prop_list->indirect_atom; 1670 (void) memmove((char *) info->target+sizeof(Atom), (char *) targets, 1671 count * sizeof(Atom)); 1672 pairs = (IndirectPair*)__XtMalloc((unsigned)(count*sizeof(IndirectPair))); 1673 for (p = &pairs[count-1], t = &targets[count-1], i = count - 1; 1674 p >= pairs; p--, t--, i--) { 1675 p->target = *t; 1676 if (properties == NULL || properties[i] == None) { 1677 p->property = GetSelectionProperty(XtDisplay(widget)); 1678 XDeleteProperty(XtDisplay(widget), XtWindow(widget), 1679 p->property); 1680 } else { 1681 p->property = properties[i]; 1682 } 1683 } 1684 XChangeProperty(XtDisplay(widget), XtWindow(widget), 1685 info->property, info->property, 1686 32, PropModeReplace, (unsigned char *) pairs, 1687 count * IndirectPairWordSize); 1688 XtFree((char*)pairs); 1689 RequestSelectionValue(info, selection, ctx->prop_list->indirect_atom); 1690 } 1691} 1692 1693 1694void XtGetSelectionValues( 1695 Widget widget, 1696 Atom selection, 1697 Atom *targets, 1698 int count, 1699 XtSelectionCallbackProc callback, 1700 XtPointer *closures, 1701 Time time) 1702{ 1703 Boolean incremental_values[32]; 1704 Boolean *incremental; 1705 int i; 1706 WIDGET_TO_APPCON(widget); 1707 1708 LOCK_APP(app); 1709 incremental = XtStackAlloc(count * sizeof(Boolean), incremental_values); 1710 for(i = 0; i < count; i++) incremental[i] = FALSE; 1711 if (IsGatheringRequest(widget, selection)) { 1712 AddSelectionRequests(widget, selection, count, targets, &callback, 1713 1, closures, incremental, NULL); 1714 } else { 1715 GetSelectionValues(widget, selection, targets, count, &callback, 1, 1716 closures, time, incremental, NULL); 1717 } 1718 XtStackFree((XtPointer) incremental, incremental_values); 1719 UNLOCK_APP(app); 1720} 1721 1722 1723void XtGetSelectionValuesIncremental( 1724 Widget widget, 1725 Atom selection, 1726 Atom *targets, 1727 int count, 1728 XtSelectionCallbackProc callback, 1729 XtPointer *closures, 1730 Time time) 1731{ 1732 Boolean incremental_values[32]; 1733 Boolean *incremental; 1734 int i; 1735 WIDGET_TO_APPCON(widget); 1736 1737 LOCK_APP(app); 1738 incremental = XtStackAlloc(count * sizeof(Boolean), incremental_values); 1739 for(i = 0; i < count; i++) incremental[i] = TRUE; 1740 if (IsGatheringRequest(widget, selection)) { 1741 AddSelectionRequests(widget, selection, count, targets, &callback, 1742 1, closures, incremental, NULL); 1743 } else { 1744 GetSelectionValues(widget, selection, targets, count, 1745 &callback, 1, closures, time, incremental, NULL); 1746 } 1747 XtStackFree((XtPointer) incremental, incremental_values); 1748 UNLOCK_APP(app); 1749} 1750 1751 1752static Request GetRequestRecord( 1753 Widget widget, 1754 Atom selection, 1755 XtRequestId id) 1756{ 1757 Request req = (Request)id; 1758 Select ctx = NULL; 1759 1760 if ( (req == NULL 1761 && ((ctx = FindCtx( XtDisplay(widget), selection )) == NULL 1762 || ctx->req == NULL 1763 || ctx->selection != selection 1764 || ctx->widget == NULL)) 1765 || (req != NULL 1766 && (req->ctx == NULL 1767 || req->ctx->selection != selection 1768 || req->ctx->widget != widget))) 1769 { 1770 String params = XtName(widget); 1771 Cardinal num_params = 1; 1772 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 1773 "notInConvertSelection", "xtGetSelectionRequest", 1774 XtCXtToolkitError, 1775 "XtGetSelectionRequest or XtGetSelectionParameters called for widget \"%s\" outside of ConvertSelection proc", 1776 ¶ms, &num_params 1777 ); 1778 return NULL; 1779 } 1780 1781 if (req == NULL) { 1782 /* non-incremental owner; only one request can be 1783 * outstanding at a time, so it's safe to keep ptr in ctx */ 1784 req = ctx->req; 1785 } 1786 return req; 1787} 1788 1789XSelectionRequestEvent *XtGetSelectionRequest( 1790 Widget widget, 1791 Atom selection, 1792 XtRequestId id) 1793{ 1794 Request req = (Request)id; 1795 WIDGET_TO_APPCON(widget); 1796 1797 LOCK_APP(app); 1798 1799 req = GetRequestRecord(widget, selection, id); 1800 1801 if (! req) { 1802 UNLOCK_APP(app); 1803 return (XSelectionRequestEvent*) NULL; 1804 } 1805 1806 if (req->event.type == 0) { 1807 /* owner is local; construct the remainder of the event */ 1808 req->event.type = SelectionRequest; 1809 req->event.serial = LastKnownRequestProcessed(XtDisplay(widget)); 1810 req->event.send_event = True; 1811 req->event.display = XtDisplay(widget); 1812 req->event.owner = XtWindow(req->ctx->widget); 1813 req->event.selection = selection; 1814 } 1815 UNLOCK_APP(app); 1816 return &req->event; 1817} 1818 1819/* Property atom access */ 1820Atom XtReservePropertyAtom( 1821 Widget w) 1822{ 1823 return(GetSelectionProperty(XtDisplay(w))); 1824} 1825 1826void XtReleasePropertyAtom( 1827 Widget w, 1828 Atom atom) 1829{ 1830 FreeSelectionProperty(XtDisplay(w), atom); 1831} 1832 1833 1834/* Multiple utilities */ 1835 1836/* All requests are put in a single list per widget. It is 1837 very unlikely anyone will be gathering multiple MULTIPLE 1838 requests at the same time, so the loss in efficiency for 1839 this case is acceptable */ 1840 1841/* Queue one or more requests to the one we're gathering */ 1842static void AddSelectionRequests( 1843 Widget wid, 1844 Atom sel, 1845 int count, 1846 Atom *targets, 1847 XtSelectionCallbackProc *callbacks, 1848 int num_cb, 1849 XtPointer *closures, 1850 Boolean *incrementals, 1851 Atom *properties) 1852{ 1853 QueuedRequestInfo qi; 1854 Window window = XtWindow(wid); 1855 Display *dpy = XtDisplay(wid); 1856 1857 LOCK_PROCESS; 1858 if (multipleContext == 0) multipleContext = XUniqueContext(); 1859 1860 qi = NULL; 1861 (void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi); 1862 1863 if (qi != NULL) { 1864 QueuedRequest *req = qi->requests; 1865 int start = qi->count; 1866 int i = 0; 1867 int j = 0; 1868 1869 qi->count += count; 1870 req = (QueuedRequest*) XtRealloc((char*) req, 1871 (start + count) * 1872 sizeof(QueuedRequest)); 1873 while(i < count) { 1874 QueuedRequest newreq = (QueuedRequest) 1875 __XtMalloc(sizeof(QueuedRequestRec)); 1876 newreq->selection = sel; 1877 newreq->target = targets[i]; 1878 if (properties != NULL) 1879 newreq->param = properties[i]; 1880 else { 1881 newreq->param = GetSelectionProperty(dpy); 1882 XDeleteProperty(dpy, window, newreq->param); 1883 } 1884 newreq->callback = callbacks[j]; 1885 newreq->closure = closures[i]; 1886 newreq->incremental = incrementals[i]; 1887 1888 req[start] = newreq; 1889 start++; 1890 i++; 1891 j++; 1892 if (j > num_cb) j = 0; 1893 } 1894 1895 qi->requests = req; 1896 } else { 1897 /* Impossible */ 1898 } 1899 1900 UNLOCK_PROCESS; 1901} 1902 1903/* Only call IsGatheringRequest when we have a lock already */ 1904 1905static Boolean IsGatheringRequest( 1906 Widget wid, 1907 Atom sel) 1908{ 1909 QueuedRequestInfo qi; 1910 Window window = XtWindow(wid); 1911 Display *dpy = XtDisplay(wid); 1912 Boolean found = False; 1913 int i; 1914 1915 if (multipleContext == 0) multipleContext = XUniqueContext(); 1916 1917 qi = NULL; 1918 (void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi); 1919 1920 if (qi != NULL) { 1921 i = 0; 1922 while(qi->selections[i] != None) { 1923 if (qi->selections[i] == sel) { 1924 found = True; 1925 break; 1926 } 1927 i++; 1928 } 1929 } 1930 1931 return(found); 1932} 1933 1934/* Cleanup request scans the request queue and releases any 1935 properties queued, and removes any requests queued */ 1936static void CleanupRequest( 1937 Display *dpy, 1938 QueuedRequestInfo qi, 1939 Atom sel) 1940{ 1941 int i, j, n; 1942 1943 i = 0; 1944 1945 /* Remove this selection from the list */ 1946 n = 0; 1947 while(qi->selections[n] != sel && 1948 qi->selections[n] != None) n++; 1949 if (qi->selections[n] == sel) { 1950 while(qi->selections[n] != None) { 1951 qi->selections[n] = qi->selections[n + 1]; 1952 n++; 1953 } 1954 } 1955 1956 while(i < qi->count) { 1957 QueuedRequest req = qi->requests[i]; 1958 1959 if (req->selection == sel) { 1960 /* Match */ 1961 if (req->param != None) 1962 FreeSelectionProperty(dpy, req->param); 1963 qi->count--; 1964 1965 for(j = i; j < qi->count; j++) 1966 qi->requests[j] = qi->requests[j + 1]; 1967 1968 XtFree((char*) req); 1969 } else { 1970 i++; 1971 } 1972 } 1973} 1974 1975void XtCreateSelectionRequest( 1976 Widget widget, 1977 Atom selection) 1978{ 1979 QueuedRequestInfo queueInfo; 1980 Window window = XtWindow(widget); 1981 Display *dpy = XtDisplay(widget); 1982 int n; 1983 1984 LOCK_PROCESS; 1985 if (multipleContext == 0) multipleContext = XUniqueContext(); 1986 1987 queueInfo = NULL; 1988 (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo); 1989 1990 /* If there is one, then cancel it */ 1991 if (queueInfo != NULL) 1992 CleanupRequest(dpy, queueInfo, selection); 1993 else { 1994 /* Create it */ 1995 queueInfo = (QueuedRequestInfo) __XtMalloc(sizeof(QueuedRequestInfoRec)); 1996 queueInfo->count = 0; 1997 queueInfo->selections = (Atom*) __XtMalloc(sizeof(Atom) * 2); 1998 queueInfo->selections[0] = None; 1999 queueInfo->requests = (QueuedRequest *) 2000 __XtMalloc(sizeof(QueuedRequest)); 2001 } 2002 2003 /* Append this selection to list */ 2004 n = 0; 2005 while(queueInfo->selections[n] != None) n++; 2006 queueInfo->selections = 2007 (Atom*) XtRealloc((char*) queueInfo->selections, 2008 (n + 2) * sizeof(Atom)); 2009 queueInfo->selections[n] = selection; 2010 queueInfo->selections[n + 1] = None; 2011 2012 (void) XSaveContext(dpy, window, multipleContext, (char*) queueInfo); 2013 UNLOCK_PROCESS; 2014} 2015 2016void XtSendSelectionRequest( 2017 Widget widget, 2018 Atom selection, 2019 Time time) 2020{ 2021 QueuedRequestInfo queueInfo; 2022 Window window = XtWindow(widget); 2023 Display *dpy = XtDisplay(widget); 2024 2025 LOCK_PROCESS; 2026 if (multipleContext == 0) multipleContext = XUniqueContext(); 2027 2028 queueInfo = NULL; 2029 (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo); 2030 if (queueInfo != NULL) { 2031 int count = 0; 2032 int i; 2033 QueuedRequest *req = queueInfo->requests; 2034 2035 /* Construct the requests and send it using 2036 GetSelectionValues */ 2037 for(i = 0; i < queueInfo->count; i++) 2038 if (req[i]->selection == selection) count++; 2039 2040 if (count > 0) { 2041 if (count == 1) { 2042 for(i = 0; i < queueInfo->count; i++) 2043 if (req[i]->selection == selection) break; 2044 2045 /* special case a multiple which isn't needed */ 2046 GetSelectionValue(widget, selection, req[i]->target, 2047 req[i]->callback, req[i]->closure, time, 2048 req[i]->incremental, req[i]->param); 2049 } else { 2050 Atom *targets; 2051 Atom t[PREALLOCED]; 2052 XtSelectionCallbackProc *cbs; 2053 XtSelectionCallbackProc c[PREALLOCED]; 2054 XtPointer *closures; 2055 XtPointer cs[PREALLOCED]; 2056 Boolean *incrs; 2057 Boolean ins[PREALLOCED]; 2058 Atom *props; 2059 Atom p[PREALLOCED]; 2060 int i = 0; 2061 int j = 0; 2062 2063 /* Allocate */ 2064 targets = (Atom *) XtStackAlloc(count * sizeof(Atom), t); 2065 cbs = (XtSelectionCallbackProc *) 2066 XtStackAlloc(count * sizeof(XtSelectionCallbackProc), c); 2067 closures = (XtPointer *) XtStackAlloc(count * sizeof(XtPointer), cs); 2068 incrs = (Boolean *) XtStackAlloc(count * sizeof(Boolean), ins); 2069 props = (Atom *) XtStackAlloc(count * sizeof(Atom), p); 2070 2071 /* Copy */ 2072 for(i = 0; i < queueInfo->count; i++) { 2073 if (req[i]->selection == selection) { 2074 targets[j] = req[i]->target; 2075 cbs[j] = req[i]->callback; 2076 closures[j] = req[i]->closure; 2077 incrs[j] = req[i]->incremental; 2078 props[j] = req[i]->param; 2079 j++; 2080 } 2081 } 2082 2083 /* Make the request */ 2084 GetSelectionValues(widget, selection, targets, count, 2085 cbs, count, closures, time, incrs, props); 2086 2087 /* Free */ 2088 XtStackFree((XtPointer) targets, t); 2089 XtStackFree((XtPointer) cbs, c); 2090 XtStackFree((XtPointer) closures, cs); 2091 XtStackFree((XtPointer) incrs, ins); 2092 XtStackFree((XtPointer) props, p); 2093 } 2094 } 2095 } 2096 2097 CleanupRequest(dpy, queueInfo, selection); 2098 UNLOCK_PROCESS; 2099} 2100 2101void XtCancelSelectionRequest( 2102 Widget widget, 2103 Atom selection) 2104{ 2105 QueuedRequestInfo queueInfo; 2106 Window window = XtWindow(widget); 2107 Display *dpy = XtDisplay(widget); 2108 2109 LOCK_PROCESS; 2110 if (multipleContext == 0) multipleContext = XUniqueContext(); 2111 2112 queueInfo = NULL; 2113 (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo); 2114 /* If there is one, then cancel it */ 2115 if (queueInfo != NULL) 2116 CleanupRequest(dpy, queueInfo, selection); 2117 UNLOCK_PROCESS; 2118} 2119 2120/* Parameter utilities */ 2121 2122/* Parameters on a selection request */ 2123/* Places data on allocated parameter atom, then records the 2124 parameter atom data for use in the next call to one of 2125 the XtGetSelectionValue functions. */ 2126void XtSetSelectionParameters( 2127 Widget requestor, 2128 Atom selection, 2129 Atom type, 2130 XtPointer value, 2131 unsigned long length, 2132 int format) 2133{ 2134 Display *dpy = XtDisplay(requestor); 2135 Window window = XtWindow(requestor); 2136 Atom property = GetParamInfo(requestor, selection); 2137 2138 if (property == None) { 2139 property = GetSelectionProperty(dpy); 2140 AddParamInfo(requestor, selection, property); 2141 } 2142 2143 XChangeProperty(dpy, window, property, 2144 type, format, PropModeReplace, 2145 (unsigned char *) value, length); 2146} 2147 2148/* Retrieves data passed in a parameter. Data for this is stored 2149 on the originator's window */ 2150void XtGetSelectionParameters( 2151 Widget owner, 2152 Atom selection, 2153 XtRequestId request_id, 2154 Atom* type_return, 2155 XtPointer* value_return, 2156 unsigned long* length_return, 2157 int* format_return) 2158{ 2159 Request req; 2160 Display *dpy = XtDisplay(owner); 2161 WIDGET_TO_APPCON(owner); 2162 2163 *value_return = NULL; 2164 *length_return = *format_return = 0; 2165 *type_return = None; 2166 2167 LOCK_APP(app); 2168 2169 req = GetRequestRecord(owner, selection, request_id); 2170 2171 if (req && req->property) { 2172 unsigned long bytes_after; /* unused */ 2173 StartProtectedSection(dpy, req->requestor); 2174 XGetWindowProperty(dpy, req->requestor, req->property, 0L, 10000000, 2175 False, AnyPropertyType, type_return, format_return, 2176 length_return, &bytes_after, 2177 (unsigned char**) value_return); 2178 EndProtectedSection(dpy); 2179#ifdef XT_COPY_SELECTION 2180 if (*value_return) { 2181 int size = BYTELENGTH(*length_return, *format_return) + 1; 2182 char *tmp = __XtMalloc((Cardinal) size); 2183 (void) memmove(tmp, *value_return, size); 2184 XFree(*value_return); 2185 *value_return = tmp; 2186 } 2187#endif 2188 } 2189 UNLOCK_APP(app); 2190} 2191 2192/* Parameters are temporarily stashed in an XContext. A list is used because 2193 * there may be more than one selection request in progress. The context 2194 * data is deleted when the list is empty. In the future, the parameter 2195 * context could be merged with other contexts used during selections. 2196 */ 2197 2198static void AddParamInfo( 2199 Widget w, 2200 Atom selection, 2201 Atom param_atom) 2202{ 2203 int n; 2204 Param p; 2205 ParamInfo pinfo; 2206 2207 LOCK_PROCESS; 2208 if (paramPropertyContext == 0) 2209 paramPropertyContext = XUniqueContext(); 2210 2211 if (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2212 (XPointer *) &pinfo)) { 2213 pinfo = (ParamInfo) __XtMalloc(sizeof(ParamInfoRec)); 2214 pinfo->count = 1; 2215 pinfo->paramlist = XtNew(ParamRec); 2216 p = pinfo->paramlist; 2217 (void) XSaveContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2218 (char *)pinfo); 2219 } 2220 else { 2221 for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) { 2222 if (p->selection == None || p->selection == selection) 2223 break; 2224 } 2225 if (n == 0) { 2226 pinfo->count++; 2227 pinfo->paramlist = (Param) 2228 XtRealloc((char*) pinfo->paramlist, 2229 pinfo->count * sizeof(ParamRec)); 2230 p = &pinfo->paramlist[pinfo->count - 1]; 2231 (void) XSaveContext(XtDisplay(w), XtWindow(w), 2232 paramPropertyContext, (char *)pinfo); 2233 } 2234 } 2235 p->selection = selection; 2236 p->param = param_atom; 2237 UNLOCK_PROCESS; 2238} 2239 2240static void RemoveParamInfo( 2241 Widget w, 2242 Atom selection) 2243{ 2244 int n; 2245 Param p; 2246 ParamInfo pinfo; 2247 Boolean retain = False; 2248 2249 LOCK_PROCESS; 2250 if (paramPropertyContext 2251 && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2252 (XPointer *) &pinfo) == 0)) { 2253 2254 /* Find and invalidate the parameter data. */ 2255 for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) { 2256 if (p->selection != None) { 2257 if (p->selection == selection) 2258 p->selection = None; 2259 else 2260 retain = True; 2261 } 2262 } 2263 /* If there's no valid data remaining, release the context entry. */ 2264 if (! retain) { 2265 XtFree((char*) pinfo->paramlist); 2266 XtFree((char*) pinfo); 2267 XDeleteContext(XtDisplay(w), XtWindow(w), paramPropertyContext); 2268 } 2269 } 2270 UNLOCK_PROCESS; 2271} 2272 2273static Atom GetParamInfo( 2274 Widget w, 2275 Atom selection) 2276{ 2277 int n; 2278 Param p; 2279 ParamInfo pinfo; 2280 Atom atom = None; 2281 2282 LOCK_PROCESS; 2283 if (paramPropertyContext 2284 && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2285 (XPointer *) &pinfo) == 0)) { 2286 2287 for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) 2288 if (p->selection == selection) { 2289 atom = p->param; 2290 break; 2291 } 2292 } 2293 UNLOCK_PROCESS; 2294 return atom; 2295} 2296