Selection.c revision 9e7bcd65
1444c061aSmrg/*********************************************************** 2249c3046SmrgCopyright (c) 1993, Oracle and/or its affiliates. All rights reserved. 31477040fSmrg 41477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a 51477040fSmrgcopy of this software and associated documentation files (the "Software"), 61477040fSmrgto deal in the Software without restriction, including without limitation 71477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense, 81477040fSmrgand/or sell copies of the Software, and to permit persons to whom the 91477040fSmrgSoftware is furnished to do so, subject to the following conditions: 101477040fSmrg 111477040fSmrgThe above copyright notice and this permission notice (including the next 121477040fSmrgparagraph) shall be included in all copies or substantial portions of the 131477040fSmrgSoftware. 141477040fSmrg 151477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 171477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 181477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 191477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 201477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 211477040fSmrgDEALINGS IN THE SOFTWARE. 221477040fSmrg 231477040fSmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 24444c061aSmrg 25444c061aSmrg All Rights Reserved 26444c061aSmrg 27444c061aSmrgPermission to use, copy, modify, and distribute this software and its 28444c061aSmrgdocumentation for any purpose and without fee is hereby granted, 29444c061aSmrgprovided that the above copyright notice appear in all copies and that 30444c061aSmrgboth that copyright notice and this permission notice appear in 311477040fSmrgsupporting documentation, and that the name of Digital not be 32444c061aSmrgused in advertising or publicity pertaining to distribution of the 33444c061aSmrgsoftware without specific, written prior permission. 34444c061aSmrg 35444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 37444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 38444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 39444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 40444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 41444c061aSmrgSOFTWARE. 42444c061aSmrg 43444c061aSmrg******************************************************************/ 44444c061aSmrg 45444c061aSmrg/* 46444c061aSmrg 47444c061aSmrgCopyright 1987, 1988, 1994, 1998 The Open Group 48444c061aSmrg 49444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its 50444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that 51444c061aSmrgthe above copyright notice appear in all copies and that both that 52444c061aSmrgcopyright notice and this permission notice appear in supporting 53444c061aSmrgdocumentation. 54444c061aSmrg 55444c061aSmrgThe above copyright notice and this permission notice shall be included in 56444c061aSmrgall copies or substantial portions of the Software. 57444c061aSmrg 58444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 62444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 63444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64444c061aSmrg 65444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be 66444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings 67444c061aSmrgin this Software without prior written authorization from The Open Group. 68444c061aSmrg 69444c061aSmrg*/ 70444c061aSmrg 71444c061aSmrg#ifdef HAVE_CONFIG_H 72444c061aSmrg#include <config.h> 73444c061aSmrg#endif 74444c061aSmrg#include "IntrinsicI.h" 75444c061aSmrg#include "StringDefs.h" 76444c061aSmrg#include "SelectionI.h" 77444c061aSmrg#include <X11/Xatom.h> 78444c061aSmrg#include <stdio.h> 79444c061aSmrg 80444c061aSmrgvoid _XtSetDefaultSelectionTimeout( 81444c061aSmrg unsigned long *timeout) 82444c061aSmrg{ 83444c061aSmrg *timeout = 5000; /* default to 5 seconds */ 84444c061aSmrg} 85444c061aSmrg 86444c061aSmrgvoid XtSetSelectionTimeout( 87444c061aSmrg unsigned long timeout) 88444c061aSmrg{ 89444c061aSmrg XtAppSetSelectionTimeout(_XtDefaultAppContext(), timeout); 90444c061aSmrg} 91444c061aSmrg 92444c061aSmrgvoid XtAppSetSelectionTimeout( 93444c061aSmrg XtAppContext app, 94444c061aSmrg unsigned long timeout) 95444c061aSmrg{ 96444c061aSmrg LOCK_APP(app); 97444c061aSmrg app->selectionTimeout = timeout; 98444c061aSmrg UNLOCK_APP(app); 99444c061aSmrg} 100444c061aSmrg 101444c061aSmrgunsigned long XtGetSelectionTimeout(void) 102444c061aSmrg{ 103444c061aSmrg return XtAppGetSelectionTimeout(_XtDefaultAppContext()); 104444c061aSmrg} 105444c061aSmrg 106444c061aSmrgunsigned long XtAppGetSelectionTimeout( 107444c061aSmrg XtAppContext app) 108444c061aSmrg{ 109444c061aSmrg unsigned long retval; 110444c061aSmrg 111444c061aSmrg LOCK_APP(app); 112444c061aSmrg retval = app->selectionTimeout; 113444c061aSmrg UNLOCK_APP(app); 114444c061aSmrg return retval; 115444c061aSmrg} 116444c061aSmrg 117444c061aSmrg 118444c061aSmrg/* General utilities */ 119444c061aSmrg 120444c061aSmrgstatic void HandleSelectionReplies(Widget, XtPointer, XEvent *, Boolean *); 121444c061aSmrgstatic void ReqTimedOut(XtPointer, XtIntervalId *); 122444c061aSmrgstatic void HandlePropertyGone(Widget, XtPointer, XEvent *, Boolean *); 123444c061aSmrgstatic void HandleGetIncrement(Widget, XtPointer, XEvent *, Boolean *); 124444c061aSmrgstatic void HandleIncremental(Display *, Widget, Atom, CallBackInfo, unsigned long); 125444c061aSmrg 126444c061aSmrgstatic XContext selectPropertyContext = 0; 127444c061aSmrgstatic XContext paramPropertyContext = 0; 128444c061aSmrgstatic XContext multipleContext = 0; 129444c061aSmrg 130444c061aSmrg/* Multiple utilities */ 131444c061aSmrgstatic void AddSelectionRequests(Widget, Atom, int, Atom *, XtSelectionCallbackProc *, int, XtPointer *, Boolean *, Atom *); 132444c061aSmrgstatic Boolean IsGatheringRequest(Widget, Atom); 133444c061aSmrg 134444c061aSmrg#define PREALLOCED 32 135444c061aSmrg 136444c061aSmrg/* Parameter utilities */ 137444c061aSmrgstatic void AddParamInfo(Widget, Atom, Atom); 138444c061aSmrgstatic void RemoveParamInfo(Widget, Atom); 139444c061aSmrgstatic Atom GetParamInfo(Widget, Atom); 140444c061aSmrg 141444c061aSmrgstatic int StorageSize[3] = {1, sizeof(short), sizeof(long)}; 142444c061aSmrg#define BYTELENGTH(length, format) ((length) * StorageSize[(format)>>4]) 143444c061aSmrg#define NUMELEM(bytelength, format) ((bytelength) / StorageSize[(format)>>4]) 144444c061aSmrg 145444c061aSmrg/* Xlib and Xt are permitted to have different memory allocators, and in the 146444c061aSmrg * XtSelectionCallbackProc the client is instructed to free the selection 147444c061aSmrg * value with XtFree, so the selection value received from XGetWindowProperty 148444c061aSmrg * should be copied to memory allocated through Xt. But copying is 149444c061aSmrg * undesirable since the selection value may be large, and, under normal 150444c061aSmrg * library configuration copying is unnecessary. 151444c061aSmrg */ 152444c061aSmrg#ifdef XTTRACEMEMORY 153444c061aSmrg#define XT_COPY_SELECTION 1 154444c061aSmrg#endif 155444c061aSmrg 156444c061aSmrg/*ARGSUSED*/ 157444c061aSmrgstatic void FreePropList( 158444c061aSmrg Widget w, /* unused */ 159444c061aSmrg XtPointer closure, 160444c061aSmrg XtPointer callData) /* unused */ 161444c061aSmrg{ 162444c061aSmrg PropList sarray = (PropList)closure; 163444c061aSmrg LOCK_PROCESS; 164444c061aSmrg XDeleteContext(sarray->dpy, DefaultRootWindow(sarray->dpy), 165444c061aSmrg selectPropertyContext); 166444c061aSmrg UNLOCK_PROCESS; 167444c061aSmrg XtFree((char*)sarray->list); 168444c061aSmrg XtFree((char*)closure); 169444c061aSmrg} 170444c061aSmrg 171444c061aSmrg 172444c061aSmrgstatic PropList GetPropList( 173444c061aSmrg Display *dpy) 174444c061aSmrg{ 175444c061aSmrg PropList sarray; 176444c061aSmrg Atom atoms[4]; 177444c061aSmrg static char* names[] = { 178444c061aSmrg "INCR", 179444c061aSmrg "MULTIPLE", 180444c061aSmrg "TIMESTAMP", 181444c061aSmrg "_XT_SELECTION_0" }; 182444c061aSmrg 183444c061aSmrg LOCK_PROCESS; 184444c061aSmrg if (selectPropertyContext == 0) 185444c061aSmrg selectPropertyContext = XUniqueContext(); 186444c061aSmrg if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, 187444c061aSmrg (XPointer *)&sarray)) { 188444c061aSmrg XtPerDisplay pd = _XtGetPerDisplay(dpy); 189444c061aSmrg sarray = (PropList) __XtMalloc((unsigned) sizeof(PropListRec)); 190444c061aSmrg sarray->dpy = dpy; 191444c061aSmrg XInternAtoms(dpy, names, 4, FALSE, atoms); 192444c061aSmrg sarray->incr_atom = atoms[0]; 193444c061aSmrg sarray->indirect_atom = atoms[1]; 194444c061aSmrg sarray->timestamp_atom = atoms[2]; 195444c061aSmrg sarray->propCount = 1; 196444c061aSmrg sarray->list = 197444c061aSmrg (SelectionProp)__XtMalloc((unsigned) sizeof(SelectionPropRec)); 198444c061aSmrg sarray->list[0].prop = atoms[3]; 199444c061aSmrg sarray->list[0].avail = TRUE; 200444c061aSmrg (void) XSaveContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, 201444c061aSmrg (char *) sarray); 202444c061aSmrg _XtAddCallback( &pd->destroy_callbacks, 203444c061aSmrg FreePropList, (XtPointer)sarray ); 204444c061aSmrg } 205444c061aSmrg UNLOCK_PROCESS; 206444c061aSmrg return sarray; 207444c061aSmrg} 208444c061aSmrg 209444c061aSmrg 210444c061aSmrgstatic Atom GetSelectionProperty( 211444c061aSmrg Display *dpy) 212444c061aSmrg{ 213444c061aSmrg SelectionProp p; 214444c061aSmrg int propCount; 215444c061aSmrg char propname[80]; 216444c061aSmrg PropList sarray = GetPropList(dpy); 217444c061aSmrg 218444c061aSmrg for (p = sarray->list, propCount=sarray->propCount; 219444c061aSmrg propCount; 220444c061aSmrg p++, propCount--) { 221444c061aSmrg if (p->avail) { 222444c061aSmrg p->avail = FALSE; 223444c061aSmrg return(p->prop); 224444c061aSmrg } 225444c061aSmrg } 226444c061aSmrg propCount = sarray->propCount++; 227444c061aSmrg sarray->list = (SelectionProp) XtRealloc((XtPointer)sarray->list, 228444c061aSmrg (unsigned)(sarray->propCount*sizeof(SelectionPropRec))); 229bdf0f55dSmrg (void) snprintf(propname, sizeof(propname), "_XT_SELECTION_%d", propCount); 230444c061aSmrg sarray->list[propCount].prop = XInternAtom(dpy, propname, FALSE); 231444c061aSmrg sarray->list[propCount].avail = FALSE; 232444c061aSmrg return(sarray->list[propCount].prop); 233444c061aSmrg} 234444c061aSmrg 235444c061aSmrgstatic void FreeSelectionProperty( 236444c061aSmrg Display *dpy, 237444c061aSmrg Atom prop) 238444c061aSmrg{ 239444c061aSmrg SelectionProp p; 2409e7bcd65Smrg int propCount; 241444c061aSmrg PropList sarray; 242444c061aSmrg if (prop == None) return; 243444c061aSmrg LOCK_PROCESS; 244444c061aSmrg if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, 245444c061aSmrg (XPointer *)&sarray)) 246444c061aSmrg XtAppErrorMsg(XtDisplayToApplicationContext(dpy), 247444c061aSmrg "noSelectionProperties", "freeSelectionProperty", XtCXtToolkitError, 248444c061aSmrg "internal error: no selection property context for display", 249444c061aSmrg (String *)NULL, (Cardinal *)NULL ); 250444c061aSmrg UNLOCK_PROCESS; 2519e7bcd65Smrg for (p = sarray->list, propCount=sarray->propCount; 2529e7bcd65Smrg propCount; 2539e7bcd65Smrg p++, propCount--) 254444c061aSmrg if (p->prop == prop) { 255444c061aSmrg p->avail = TRUE; 256444c061aSmrg return; 257444c061aSmrg } 258444c061aSmrg} 259444c061aSmrg 260444c061aSmrgstatic void FreeInfo( 261444c061aSmrg CallBackInfo info) 262444c061aSmrg{ 263444c061aSmrg XtFree((char*)info->incremental); 264444c061aSmrg XtFree((char*)info->callbacks); 265444c061aSmrg XtFree((char*)info->req_closure); 266444c061aSmrg XtFree((char*)info->target); 267444c061aSmrg XtFree((char*)info); 268444c061aSmrg} 269444c061aSmrg 270444c061aSmrgstatic CallBackInfo MakeInfo( 271444c061aSmrg Select ctx, 272444c061aSmrg XtSelectionCallbackProc *callbacks, 273444c061aSmrg XtPointer *closures, 274444c061aSmrg int count, 275444c061aSmrg Widget widget, 276444c061aSmrg Time time, 277444c061aSmrg Boolean *incremental, 278444c061aSmrg Atom *properties) 279444c061aSmrg{ 280444c061aSmrg CallBackInfo info = XtNew(CallBackInfoRec); 281444c061aSmrg 282444c061aSmrg info->ctx = ctx; 283444c061aSmrg info->callbacks = (XtSelectionCallbackProc *) 284444c061aSmrg __XtMalloc((unsigned) (count * sizeof(XtSelectionCallbackProc))); 285444c061aSmrg (void) memmove((char*)info->callbacks, (char*)callbacks, 286444c061aSmrg count * sizeof(XtSelectionCallbackProc)); 287444c061aSmrg info->req_closure = 288444c061aSmrg (XtPointer*)__XtMalloc((unsigned) (count * sizeof(XtPointer))); 289444c061aSmrg (void) memmove((char*)info->req_closure, (char*)closures, 290444c061aSmrg count * sizeof(XtPointer)); 291444c061aSmrg if (count == 1 && properties != NULL && properties[0] != None) 292444c061aSmrg info->property = properties[0]; 293444c061aSmrg else { 294444c061aSmrg info->property = GetSelectionProperty(XtDisplay(widget)); 295444c061aSmrg XDeleteProperty(XtDisplay(widget), XtWindow(widget), 296444c061aSmrg info->property); 297444c061aSmrg } 298444c061aSmrg info->proc = HandleSelectionReplies; 299444c061aSmrg info->widget = widget; 300444c061aSmrg info->time = time; 301444c061aSmrg info->incremental = (Boolean*) __XtMalloc(count * sizeof(Boolean)); 302444c061aSmrg (void) memmove((char*)info->incremental, (char*) incremental, 303444c061aSmrg count * sizeof(Boolean)); 304444c061aSmrg info->current = 0; 305444c061aSmrg info->value = NULL; 306444c061aSmrg return (info); 307444c061aSmrg} 308444c061aSmrg 309444c061aSmrgstatic void RequestSelectionValue( 310444c061aSmrg CallBackInfo info, 311444c061aSmrg Atom selection, 312444c061aSmrg Atom target) 313444c061aSmrg{ 314444c061aSmrg#ifndef DEBUG_WO_TIMERS 315444c061aSmrg XtAppContext app = XtWidgetToApplicationContext(info->widget); 316444c061aSmrg info->timeout = XtAppAddTimeOut(app, 317444c061aSmrg app->selectionTimeout, ReqTimedOut, (XtPointer)info); 318444c061aSmrg#endif 319444c061aSmrg XtAddEventHandler(info->widget, (EventMask)0, TRUE, 320444c061aSmrg HandleSelectionReplies, (XtPointer)info); 321444c061aSmrg XConvertSelection(info->ctx->dpy, selection, target, 322444c061aSmrg info->property, XtWindow(info->widget), info->time); 323444c061aSmrg} 324444c061aSmrg 325444c061aSmrg 326444c061aSmrgstatic XContext selectContext = 0; 327444c061aSmrg 328444c061aSmrgstatic Select NewContext( 329444c061aSmrg Display *dpy, 330444c061aSmrg Atom selection) 331444c061aSmrg{ 332444c061aSmrg /* assert(selectContext != 0) */ 333444c061aSmrg Select ctx = XtNew(SelectRec); 334444c061aSmrg ctx->dpy = dpy; 335444c061aSmrg ctx->selection = selection; 336444c061aSmrg ctx->widget = NULL; 337444c061aSmrg ctx->prop_list = GetPropList(dpy); 338444c061aSmrg ctx->ref_count = 0; 339444c061aSmrg ctx->free_when_done = FALSE; 340444c061aSmrg ctx->was_disowned = FALSE; 341444c061aSmrg LOCK_PROCESS; 342444c061aSmrg (void)XSaveContext(dpy, (Window)selection, selectContext, (char *)ctx); 343444c061aSmrg UNLOCK_PROCESS; 344444c061aSmrg return ctx; 345444c061aSmrg} 346444c061aSmrg 347444c061aSmrgstatic Select FindCtx( 348444c061aSmrg Display *dpy, 349444c061aSmrg Atom selection) 350444c061aSmrg{ 351444c061aSmrg Select ctx; 352444c061aSmrg 353444c061aSmrg LOCK_PROCESS; 354444c061aSmrg if (selectContext == 0) 355444c061aSmrg selectContext = XUniqueContext(); 356444c061aSmrg if (XFindContext(dpy, (Window)selection, selectContext, (XPointer *)&ctx)) 357444c061aSmrg ctx = NewContext(dpy, selection); 358444c061aSmrg UNLOCK_PROCESS; 359444c061aSmrg return ctx; 360444c061aSmrg} 361444c061aSmrg 362444c061aSmrg/*ARGSUSED*/ 363444c061aSmrgstatic void WidgetDestroyed( 364444c061aSmrg Widget widget, 365444c061aSmrg XtPointer closure, XtPointer data) 366444c061aSmrg{ 367444c061aSmrg Select ctx = (Select) closure; 368444c061aSmrg if (ctx->widget == widget) { 369444c061aSmrg if (ctx->free_when_done) 370444c061aSmrg XtFree((char*)ctx); 371444c061aSmrg else 372444c061aSmrg ctx->widget = NULL; 373444c061aSmrg } 374444c061aSmrg} 375444c061aSmrg 376444c061aSmrg/* Selection Owner code */ 377444c061aSmrg 378444c061aSmrgstatic void HandleSelectionEvents(Widget, XtPointer, XEvent *, Boolean *); 379444c061aSmrg 380444c061aSmrgstatic Boolean LoseSelection( 381444c061aSmrg Select ctx, 382444c061aSmrg Widget widget, 383444c061aSmrg Atom selection, 384444c061aSmrg Time time) 385444c061aSmrg{ 386444c061aSmrg if ((ctx->widget == widget) && 387444c061aSmrg (ctx->selection == selection) && /* paranoia */ 388444c061aSmrg !ctx->was_disowned && 389444c061aSmrg ((time == CurrentTime) || (time >= ctx->time))) 390444c061aSmrg { 391444c061aSmrg XtRemoveEventHandler(widget, (EventMask)0, TRUE, 392444c061aSmrg HandleSelectionEvents, (XtPointer)ctx); 393444c061aSmrg XtRemoveCallback(widget, XtNdestroyCallback, 394444c061aSmrg WidgetDestroyed, (XtPointer)ctx); 395444c061aSmrg ctx->was_disowned = TRUE; /* widget officially loses ownership */ 396444c061aSmrg /* now inform widget */ 397444c061aSmrg if (ctx->loses) { 398444c061aSmrg if (ctx->incremental) 399444c061aSmrg (*(XtLoseSelectionIncrProc)ctx->loses) 400444c061aSmrg (widget, &ctx->selection, ctx->owner_closure); 401444c061aSmrg else (*ctx->loses)(widget, &ctx->selection); 402444c061aSmrg } 403444c061aSmrg return(TRUE); 404444c061aSmrg } 405444c061aSmrg else return(FALSE); 406444c061aSmrg} 407444c061aSmrg 408444c061aSmrgstatic XContext selectWindowContext = 0; 409444c061aSmrg 410444c061aSmrg/* %%% Xlib.h should make this public! */ 411444c061aSmrgtypedef int (*xErrorHandler)(Display*, XErrorEvent*); 412444c061aSmrg 413444c061aSmrgstatic xErrorHandler oldErrorHandler = NULL; 414444c061aSmrgstatic unsigned long firstProtectRequest; 415444c061aSmrgstatic Window errorWindow; 416444c061aSmrg 417444c061aSmrgstatic int LocalErrorHandler ( 418444c061aSmrg Display *dpy, 419444c061aSmrg XErrorEvent *error) 420444c061aSmrg{ 421444c061aSmrg int retval; 422444c061aSmrg 423444c061aSmrg /* If BadWindow error on selection requestor, nothing to do but let 424444c061aSmrg * the transfer timeout. Otherwise, invoke saved error handler. */ 425444c061aSmrg 426444c061aSmrg LOCK_PROCESS; 427444c061aSmrg 428444c061aSmrg if (error->error_code == BadWindow && error->resourceid == errorWindow && 429444c061aSmrg error->serial >= firstProtectRequest) { 430444c061aSmrg UNLOCK_PROCESS; 431444c061aSmrg return 0; 432444c061aSmrg } 433444c061aSmrg 434444c061aSmrg if (oldErrorHandler == NULL) { 435444c061aSmrg UNLOCK_PROCESS; 436444c061aSmrg return 0; /* should never happen */ 437444c061aSmrg } 438444c061aSmrg 439444c061aSmrg retval = (*oldErrorHandler)(dpy, error); 440444c061aSmrg UNLOCK_PROCESS; 441444c061aSmrg return retval; 442444c061aSmrg} 443444c061aSmrg 444444c061aSmrgstatic void StartProtectedSection( 445444c061aSmrg Display *dpy, 446444c061aSmrg Window window) 447444c061aSmrg{ 448444c061aSmrg /* protect ourselves against request window being destroyed 449444c061aSmrg * before completion of transfer */ 450444c061aSmrg 451444c061aSmrg LOCK_PROCESS; 452444c061aSmrg oldErrorHandler = XSetErrorHandler(LocalErrorHandler); 453444c061aSmrg firstProtectRequest = NextRequest(dpy); 454444c061aSmrg errorWindow = window; 455444c061aSmrg UNLOCK_PROCESS; 456444c061aSmrg} 457444c061aSmrg 458444c061aSmrgstatic void EndProtectedSection( 459444c061aSmrg Display *dpy) 460444c061aSmrg{ 461444c061aSmrg /* flush any generated errors on requestor and 462444c061aSmrg * restore original error handler */ 463444c061aSmrg 464444c061aSmrg XSync(dpy, False); 465444c061aSmrg 466444c061aSmrg LOCK_PROCESS; 467444c061aSmrg XSetErrorHandler(oldErrorHandler); 468444c061aSmrg oldErrorHandler = NULL; 469444c061aSmrg UNLOCK_PROCESS; 470444c061aSmrg} 471444c061aSmrg 472444c061aSmrgstatic void AddHandler( 473444c061aSmrg Request req, 474444c061aSmrg EventMask mask, 475444c061aSmrg XtEventHandler proc, 476444c061aSmrg XtPointer closure) 477444c061aSmrg{ 478444c061aSmrg Display *dpy = req->ctx->dpy; 479444c061aSmrg Window window = req->requestor; 480444c061aSmrg Widget widget = XtWindowToWidget(dpy, window); 481444c061aSmrg 482444c061aSmrg if (widget != NULL) req->widget = widget; 483444c061aSmrg else widget = req->widget; 484444c061aSmrg 485444c061aSmrg if (XtWindow(widget) == window) 486444c061aSmrg XtAddEventHandler(widget, mask, False, proc, closure); 487444c061aSmrg else { 488444c061aSmrg RequestWindowRec *requestWindowRec; 489444c061aSmrg LOCK_PROCESS; 490444c061aSmrg if (selectWindowContext == 0) 491444c061aSmrg selectWindowContext = XUniqueContext(); 492444c061aSmrg if (XFindContext(dpy, window, selectWindowContext, 493444c061aSmrg (XPointer *)&requestWindowRec)) { 494444c061aSmrg requestWindowRec = XtNew(RequestWindowRec); 495444c061aSmrg requestWindowRec->active_transfer_count = 0; 496444c061aSmrg (void)XSaveContext(dpy, window, selectWindowContext, 497444c061aSmrg (char *)requestWindowRec); 498444c061aSmrg } 499444c061aSmrg UNLOCK_PROCESS; 500444c061aSmrg if (requestWindowRec->active_transfer_count++ == 0) { 501444c061aSmrg XtRegisterDrawable(dpy, window, widget); 502444c061aSmrg XSelectInput(dpy, window, mask); 503444c061aSmrg } 504444c061aSmrg XtAddRawEventHandler(widget, mask, FALSE, proc, closure); 505444c061aSmrg } 506444c061aSmrg} 507444c061aSmrg 508444c061aSmrgstatic void RemoveHandler( 509444c061aSmrg Request req, 510444c061aSmrg EventMask mask, 511444c061aSmrg XtEventHandler proc, 512444c061aSmrg XtPointer closure) 513444c061aSmrg{ 514444c061aSmrg Display *dpy = req->ctx->dpy; 515444c061aSmrg Window window = req->requestor; 516444c061aSmrg Widget widget = req->widget; 517444c061aSmrg 518444c061aSmrg if ((XtWindowToWidget(dpy, window) == widget) && 519444c061aSmrg (XtWindow(widget) != window)) { 520444c061aSmrg /* we had to hang this window onto our widget; take it off */ 521444c061aSmrg RequestWindowRec* requestWindowRec; 522444c061aSmrg XtRemoveRawEventHandler(widget, mask, TRUE, proc, closure); 523444c061aSmrg LOCK_PROCESS; 524444c061aSmrg (void)XFindContext(dpy, window, selectWindowContext, 525444c061aSmrg (XPointer *)&requestWindowRec); 526444c061aSmrg UNLOCK_PROCESS; 527444c061aSmrg if (--requestWindowRec->active_transfer_count == 0) { 528444c061aSmrg XtUnregisterDrawable(dpy, window); 529444c061aSmrg StartProtectedSection(dpy, window); 530444c061aSmrg XSelectInput(dpy, window, 0L); 531444c061aSmrg EndProtectedSection(dpy); 532444c061aSmrg LOCK_PROCESS; 533444c061aSmrg (void)XDeleteContext(dpy, window, selectWindowContext); 534444c061aSmrg UNLOCK_PROCESS; 535444c061aSmrg XtFree((char*)requestWindowRec); 536444c061aSmrg } 537444c061aSmrg } else { 538444c061aSmrg XtRemoveEventHandler(widget, mask, TRUE, proc, closure); 539444c061aSmrg } 540444c061aSmrg} 541444c061aSmrg 542444c061aSmrg/* ARGSUSED */ 543444c061aSmrgstatic void OwnerTimedOut( 544444c061aSmrg XtPointer closure, 545444c061aSmrg XtIntervalId *id) 546444c061aSmrg{ 547444c061aSmrg Request req = (Request)closure; 548444c061aSmrg Select ctx = req->ctx; 549444c061aSmrg 550444c061aSmrg if (ctx->incremental && (ctx->owner_cancel != NULL)) { 551444c061aSmrg (*ctx->owner_cancel)(ctx->widget, &ctx->selection, 552444c061aSmrg &req->target, (XtRequestId*)&req, 553444c061aSmrg ctx->owner_closure); 554444c061aSmrg } else { 555444c061aSmrg if (ctx->notify == NULL) 556444c061aSmrg XtFree((char*)req->value); 557444c061aSmrg else { 558444c061aSmrg /* the requestor hasn't deleted the property, but 559444c061aSmrg * the owner needs to free the value. 560444c061aSmrg */ 561444c061aSmrg if (ctx->incremental) 562444c061aSmrg (*(XtSelectionDoneIncrProc)ctx->notify) 563444c061aSmrg (ctx->widget, &ctx->selection, &req->target, 564444c061aSmrg (XtRequestId*)&req, ctx->owner_closure); 565444c061aSmrg else 566444c061aSmrg (*ctx->notify)(ctx->widget, &ctx->selection, &req->target); 567444c061aSmrg } 568444c061aSmrg } 569444c061aSmrg 570444c061aSmrg RemoveHandler(req, (EventMask)PropertyChangeMask, 571444c061aSmrg HandlePropertyGone, closure); 572444c061aSmrg XtFree((char*)req); 573444c061aSmrg if (--ctx->ref_count == 0 && ctx->free_when_done) 574444c061aSmrg XtFree((char*)ctx); 575444c061aSmrg} 576444c061aSmrg 577444c061aSmrgstatic void SendIncrement( 578444c061aSmrg Request incr) 579444c061aSmrg{ 580444c061aSmrg Display *dpy = incr->ctx->dpy; 581444c061aSmrg 582444c061aSmrg unsigned long incrSize = MAX_SELECTION_INCR(dpy); 583444c061aSmrg if (incrSize > incr->bytelength - incr->offset) 584444c061aSmrg incrSize = incr->bytelength - incr->offset; 585444c061aSmrg StartProtectedSection(dpy, incr->requestor); 586444c061aSmrg XChangeProperty(dpy, incr->requestor, incr->property, 587444c061aSmrg incr->type, incr->format, PropModeReplace, 588444c061aSmrg (unsigned char *)incr->value + incr->offset, 589444c061aSmrg NUMELEM((int)incrSize, incr->format)); 590444c061aSmrg EndProtectedSection(dpy); 591444c061aSmrg incr->offset += incrSize; 592444c061aSmrg} 593444c061aSmrg 594444c061aSmrgstatic void AllSent( 595444c061aSmrg Request req) 596444c061aSmrg{ 597444c061aSmrg Select ctx = req->ctx; 598444c061aSmrg StartProtectedSection(ctx->dpy, req->requestor); 599444c061aSmrg XChangeProperty(ctx->dpy, req->requestor, 600444c061aSmrg req->property, req->type, req->format, 601444c061aSmrg PropModeReplace, (unsigned char *) NULL, 0); 602444c061aSmrg EndProtectedSection(ctx->dpy); 603444c061aSmrg req->allSent = TRUE; 604444c061aSmrg 605444c061aSmrg if (ctx->notify == NULL) XtFree((char*)req->value); 606444c061aSmrg} 607444c061aSmrg 608444c061aSmrg/*ARGSUSED*/ 609444c061aSmrgstatic void HandlePropertyGone( 610444c061aSmrg Widget widget, 611444c061aSmrg XtPointer closure, 612444c061aSmrg XEvent *ev, 613444c061aSmrg Boolean *cont) 614444c061aSmrg{ 615444c061aSmrg XPropertyEvent *event = (XPropertyEvent *) ev; 616444c061aSmrg Request req = (Request)closure; 617444c061aSmrg Select ctx = req->ctx; 618444c061aSmrg 619444c061aSmrg if ((event->type != PropertyNotify) || 620444c061aSmrg (event->state != PropertyDelete) || 621444c061aSmrg (event->atom != req->property) || 622444c061aSmrg (event->window != req->requestor)) 623444c061aSmrg return; 624444c061aSmrg#ifndef DEBUG_WO_TIMERS 625444c061aSmrg XtRemoveTimeOut(req->timeout); 626444c061aSmrg#endif 627444c061aSmrg if (req->allSent) { 628444c061aSmrg if (ctx->notify) { 629444c061aSmrg if (ctx->incremental) { 630444c061aSmrg (*(XtSelectionDoneIncrProc)ctx->notify) 631444c061aSmrg (ctx->widget, &ctx->selection, &req->target, 632444c061aSmrg (XtRequestId*)&req, ctx->owner_closure); 633444c061aSmrg } 634444c061aSmrg else (*ctx->notify)(ctx->widget, &ctx->selection, &req->target); 635444c061aSmrg } 636444c061aSmrg RemoveHandler(req, (EventMask)PropertyChangeMask, 637444c061aSmrg HandlePropertyGone, closure); 638444c061aSmrg XtFree((char*)req); 639444c061aSmrg if (--ctx->ref_count == 0 && ctx->free_when_done) 640444c061aSmrg XtFree((char*)ctx); 641444c061aSmrg } else { /* is this part of an incremental transfer? */ 642444c061aSmrg if (ctx->incremental) { 643444c061aSmrg if (req->bytelength == 0) 644444c061aSmrg AllSent(req); 645444c061aSmrg else { 646444c061aSmrg unsigned long size = MAX_SELECTION_INCR(ctx->dpy); 647444c061aSmrg SendIncrement(req); 648444c061aSmrg (*(XtConvertSelectionIncrProc)ctx->convert) 649444c061aSmrg (ctx->widget, &ctx->selection, &req->target, 650444c061aSmrg &req->type, &req->value, 651444c061aSmrg &req->bytelength, &req->format, 652444c061aSmrg &size, ctx->owner_closure, (XtPointer*)&req); 653444c061aSmrg if (req->bytelength) 654444c061aSmrg req->bytelength = BYTELENGTH(req->bytelength, req->format); 655444c061aSmrg req->offset = 0; 656444c061aSmrg } 657444c061aSmrg } else { 658444c061aSmrg if (req->offset < req->bytelength) 659444c061aSmrg SendIncrement(req); 660444c061aSmrg else AllSent(req); 661444c061aSmrg } 662444c061aSmrg#ifndef DEBUG_WO_TIMERS 663444c061aSmrg { 664444c061aSmrg XtAppContext app = XtWidgetToApplicationContext(req->widget); 665444c061aSmrg req->timeout = XtAppAddTimeOut(app, 666444c061aSmrg app->selectionTimeout, OwnerTimedOut, (XtPointer)req); 667444c061aSmrg } 668444c061aSmrg#endif 669444c061aSmrg } 670444c061aSmrg} 671444c061aSmrg 672444c061aSmrgstatic void PrepareIncremental( 673444c061aSmrg Request req, 674444c061aSmrg Widget widget, 675444c061aSmrg Window window, 676444c061aSmrg Atom property, 677444c061aSmrg Atom target, 678444c061aSmrg Atom targetType, 679444c061aSmrg XtPointer value, 680444c061aSmrg unsigned long length, 681444c061aSmrg int format) 682444c061aSmrg{ 683444c061aSmrg req->type = targetType; 684444c061aSmrg req->value = value; 685444c061aSmrg req->bytelength = BYTELENGTH(length,format); 686444c061aSmrg req->format = format; 687444c061aSmrg req->offset = 0; 688444c061aSmrg req->target = target; 689444c061aSmrg req->widget = widget; 690444c061aSmrg req->allSent = FALSE; 691444c061aSmrg#ifndef DEBUG_WO_TIMERS 692444c061aSmrg { 693444c061aSmrg XtAppContext app = XtWidgetToApplicationContext(widget); 694444c061aSmrg req->timeout = XtAppAddTimeOut(app, 695444c061aSmrg app->selectionTimeout, OwnerTimedOut, (XtPointer)req); 696444c061aSmrg } 697444c061aSmrg#endif 698444c061aSmrg AddHandler(req, (EventMask)PropertyChangeMask, 699444c061aSmrg HandlePropertyGone, (XtPointer)req); 700444c061aSmrg/* now send client INCR property */ 701444c061aSmrg XChangeProperty(req->ctx->dpy, window, req->property, 702444c061aSmrg req->ctx->prop_list->incr_atom, 703444c061aSmrg 32, PropModeReplace, 704444c061aSmrg (unsigned char *)&req->bytelength, 1); 705444c061aSmrg} 706444c061aSmrg 707444c061aSmrgstatic Boolean GetConversion( 708444c061aSmrg Select ctx, /* logical owner */ 709444c061aSmrg XSelectionRequestEvent* event, 710444c061aSmrg Atom target, 711444c061aSmrg Atom property, /* requestor's property */ 712444c061aSmrg Widget widget) /* physical owner (receives events) */ 713444c061aSmrg{ 714444c061aSmrg XtPointer value = NULL; 715444c061aSmrg unsigned long length; 716444c061aSmrg int format; 717444c061aSmrg Atom targetType; 718444c061aSmrg Request req = XtNew(RequestRec); 719444c061aSmrg Boolean timestamp_target = (target == ctx->prop_list->timestamp_atom); 720444c061aSmrg 721444c061aSmrg req->ctx = ctx; 722444c061aSmrg req->event = *event; 723444c061aSmrg req->property = property; 724444c061aSmrg req->requestor = event->requestor; 725444c061aSmrg 726444c061aSmrg if (timestamp_target) { 727444c061aSmrg value = __XtMalloc(sizeof(long)); 728444c061aSmrg *(long*)value = ctx->time; 729444c061aSmrg targetType = XA_INTEGER; 730444c061aSmrg length = 1; 731444c061aSmrg format = 32; 732444c061aSmrg } 733444c061aSmrg else { 734444c061aSmrg ctx->ref_count++; 735444c061aSmrg if (ctx->incremental == TRUE) { 736444c061aSmrg unsigned long size = MAX_SELECTION_INCR(ctx->dpy); 737444c061aSmrg if ((*(XtConvertSelectionIncrProc)ctx->convert) 738444c061aSmrg (ctx->widget, &event->selection, &target, 739444c061aSmrg &targetType, &value, &length, &format, 740444c061aSmrg &size, ctx->owner_closure, (XtRequestId*)&req) 741444c061aSmrg == FALSE) { 742444c061aSmrg XtFree((char*)req); 743444c061aSmrg ctx->ref_count--; 744444c061aSmrg return(FALSE); 745444c061aSmrg } 746444c061aSmrg StartProtectedSection(ctx->dpy, event->requestor); 747444c061aSmrg PrepareIncremental(req, widget, event->requestor, property, 748444c061aSmrg target, targetType, value, length, format); 749444c061aSmrg return(TRUE); 750444c061aSmrg } 751444c061aSmrg ctx->req = req; 752444c061aSmrg if ((*ctx->convert)(ctx->widget, &event->selection, &target, 753444c061aSmrg &targetType, &value, &length, &format) == FALSE) { 754444c061aSmrg XtFree((char*)req); 755444c061aSmrg ctx->req = NULL; 756444c061aSmrg ctx->ref_count--; 757444c061aSmrg return(FALSE); 758444c061aSmrg } 759444c061aSmrg ctx->req = NULL; 760444c061aSmrg } 761444c061aSmrg StartProtectedSection(ctx->dpy, event->requestor); 762444c061aSmrg if (BYTELENGTH(length,format) <= (unsigned long) MAX_SELECTION_INCR(ctx->dpy)) { 763444c061aSmrg if (! timestamp_target) { 764444c061aSmrg if (ctx->notify != NULL) { 765444c061aSmrg req->target = target; 766444c061aSmrg req->widget = widget; 767444c061aSmrg req->allSent = TRUE; 768444c061aSmrg#ifndef DEBUG_WO_TIMERS 769444c061aSmrg { 770444c061aSmrg XtAppContext app = XtWidgetToApplicationContext(req->widget); 771444c061aSmrg req->timeout = XtAppAddTimeOut(app, 772444c061aSmrg app->selectionTimeout, OwnerTimedOut, (XtPointer)req); 773444c061aSmrg } 774444c061aSmrg#endif 775444c061aSmrg AddHandler(req, (EventMask)PropertyChangeMask, 776444c061aSmrg HandlePropertyGone, (XtPointer)req); 777444c061aSmrg } 778444c061aSmrg else ctx->ref_count--; 779444c061aSmrg } 780444c061aSmrg XChangeProperty(ctx->dpy, event->requestor, property, 781444c061aSmrg targetType, format, PropModeReplace, 782444c061aSmrg (unsigned char *)value, (int)length); 783444c061aSmrg /* free storage for client if no notify proc */ 784444c061aSmrg if (timestamp_target || ctx->notify == NULL) { 785444c061aSmrg XtFree((char*)value); 786444c061aSmrg XtFree((char*)req); 787444c061aSmrg } 788444c061aSmrg } else { 789444c061aSmrg PrepareIncremental(req, widget, event->requestor, property, 790444c061aSmrg target, targetType, value, length, format); 791444c061aSmrg } 792444c061aSmrg return(TRUE); 793444c061aSmrg} 794444c061aSmrg 795444c061aSmrg/*ARGSUSED*/ 796444c061aSmrgstatic void HandleSelectionEvents( 797444c061aSmrg Widget widget, 798444c061aSmrg XtPointer closure, 799444c061aSmrg XEvent *event, 800444c061aSmrg Boolean *cont) 801444c061aSmrg{ 802444c061aSmrg Select ctx; 803444c061aSmrg XSelectionEvent ev; 804444c061aSmrg Atom target; 805444c061aSmrg int count; 806444c061aSmrg Boolean writeback = FALSE; 807444c061aSmrg 808444c061aSmrg ctx = (Select) closure; 809444c061aSmrg switch (event->type) { 810444c061aSmrg case SelectionClear: 811444c061aSmrg /* if this event is not for the selection we registered for, 812444c061aSmrg * don't do anything */ 813444c061aSmrg if (ctx->selection != event->xselectionclear.selection || 814444c061aSmrg ctx->serial > event->xselectionclear.serial) 815444c061aSmrg break; 816444c061aSmrg (void) LoseSelection(ctx, widget, event->xselectionclear.selection, 817444c061aSmrg event->xselectionclear.time); 818444c061aSmrg break; 819444c061aSmrg case SelectionRequest: 820444c061aSmrg /* if this event is not for the selection we registered for, 821444c061aSmrg * don't do anything */ 822444c061aSmrg if (ctx->selection != event->xselectionrequest.selection) 823444c061aSmrg break; 824444c061aSmrg ev.type = SelectionNotify; 825444c061aSmrg ev.display = event->xselectionrequest.display; 826444c061aSmrg ev.requestor = event->xselectionrequest.requestor; 827444c061aSmrg ev.selection = event->xselectionrequest.selection; 828444c061aSmrg ev.time = event->xselectionrequest.time; 829444c061aSmrg ev.target = event->xselectionrequest.target; 830444c061aSmrg if (event->xselectionrequest.property == None) /* obsolete requestor */ 831444c061aSmrg event->xselectionrequest.property = event->xselectionrequest.target; 832444c061aSmrg if (ctx->widget != widget || ctx->was_disowned 833444c061aSmrg || ((event->xselectionrequest.time != CurrentTime) 834249c3046Smrg && (event->xselectionrequest.time < ctx->time))) { 835444c061aSmrg ev.property = None; 836249c3046Smrg StartProtectedSection(ev.display, ev.requestor); 837249c3046Smrg } else { 838444c061aSmrg if (ev.target == ctx->prop_list->indirect_atom) { 839444c061aSmrg IndirectPair *p; 840444c061aSmrg int format; 841444c061aSmrg unsigned long bytesafter, length; 8429e7bcd65Smrg unsigned char *value = NULL; 843444c061aSmrg ev.property = event->xselectionrequest.property; 844444c061aSmrg StartProtectedSection(ev.display, ev.requestor); 8459e7bcd65Smrg if (XGetWindowProperty(ev.display, ev.requestor, 846444c061aSmrg event->xselectionrequest.property, 0L, 1000000, 847444c061aSmrg False,(Atom)AnyPropertyType, &target, &format, &length, 8489e7bcd65Smrg &bytesafter, &value) == Success) 8499e7bcd65Smrg count = BYTELENGTH(length, format) / sizeof(IndirectPair); 8509e7bcd65Smrg else 8519e7bcd65Smrg count = 0; 852444c061aSmrg for (p = (IndirectPair *)value; count; p++, count--) { 853444c061aSmrg EndProtectedSection(ctx->dpy); 854444c061aSmrg if (!GetConversion(ctx, (XSelectionRequestEvent*)event, 855444c061aSmrg p->target, p->property, widget)) { 856444c061aSmrg 857444c061aSmrg p->target = None; 858444c061aSmrg writeback = TRUE; 859444c061aSmrg StartProtectedSection(ctx->dpy, ev.requestor); 860444c061aSmrg } 861444c061aSmrg } 862444c061aSmrg if (writeback) 863444c061aSmrg XChangeProperty(ev.display, ev.requestor, 864444c061aSmrg event->xselectionrequest.property, target, 865444c061aSmrg format, PropModeReplace, value, (int)length); 866444c061aSmrg XFree((char *)value); 867444c061aSmrg } else /* not multiple */ { 868444c061aSmrg if (GetConversion(ctx, (XSelectionRequestEvent*)event, 869444c061aSmrg event->xselectionrequest.target, 870444c061aSmrg event->xselectionrequest.property, 871444c061aSmrg widget)) 872444c061aSmrg ev.property = event->xselectionrequest.property; 873444c061aSmrg else { 874444c061aSmrg ev.property = None; 875444c061aSmrg StartProtectedSection(ctx->dpy, ev.requestor); 876444c061aSmrg } 877444c061aSmrg } 878444c061aSmrg } 879444c061aSmrg (void) XSendEvent(ctx->dpy, ev.requestor, False, (unsigned long)NULL, 880444c061aSmrg (XEvent *) &ev); 881444c061aSmrg 882444c061aSmrg EndProtectedSection(ctx->dpy); 883444c061aSmrg 884444c061aSmrg break; 885444c061aSmrg } 886444c061aSmrg} 887444c061aSmrg 888444c061aSmrgstatic Boolean OwnSelection( 889444c061aSmrg Widget widget, 890444c061aSmrg Atom selection, 891444c061aSmrg Time time, 892444c061aSmrg XtConvertSelectionProc convert, 893444c061aSmrg XtLoseSelectionProc lose, 894444c061aSmrg XtSelectionDoneProc notify, 895444c061aSmrg XtCancelConvertSelectionProc cancel, 896444c061aSmrg XtPointer closure, 897444c061aSmrg Boolean incremental) 898444c061aSmrg{ 899444c061aSmrg Select ctx; 900444c061aSmrg Select oldctx = NULL; 901444c061aSmrg 902444c061aSmrg if (!XtIsRealized(widget)) return False; 903444c061aSmrg 904444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 905444c061aSmrg if (ctx->widget != widget || ctx->time != time || 906444c061aSmrg ctx->ref_count || ctx->was_disowned) 907444c061aSmrg { 908444c061aSmrg Boolean replacement = FALSE; 909444c061aSmrg Window window = XtWindow(widget); 910444c061aSmrg unsigned long serial = XNextRequest(ctx->dpy); 911444c061aSmrg XSetSelectionOwner(ctx->dpy, selection, window, time); 912444c061aSmrg if (XGetSelectionOwner(ctx->dpy, selection) != window) 913444c061aSmrg return FALSE; 914444c061aSmrg if (ctx->ref_count) { /* exchange is in-progress */ 915444c061aSmrg#ifdef DEBUG_ACTIVE 916444c061aSmrg printf( "Active exchange for widget \"%s\"; selection=0x%lx, ref_count=%d\n", 917444c061aSmrg XtName(widget), (long)selection, ctx->ref_count ); 918444c061aSmrg#endif 919444c061aSmrg if (ctx->widget != widget || 920444c061aSmrg ctx->convert != convert || 921444c061aSmrg ctx->loses != lose || 922444c061aSmrg ctx->notify != notify || 923444c061aSmrg ctx->owner_cancel != cancel || 924444c061aSmrg ctx->incremental != incremental || 925444c061aSmrg ctx->owner_closure != closure) 926444c061aSmrg { 927444c061aSmrg if (ctx->widget == widget) { 928444c061aSmrg XtRemoveEventHandler(widget, (EventMask)0, TRUE, 929444c061aSmrg HandleSelectionEvents, (XtPointer)ctx); 930444c061aSmrg XtRemoveCallback(widget, XtNdestroyCallback, 931444c061aSmrg WidgetDestroyed, (XtPointer)ctx); 932444c061aSmrg replacement = TRUE; 933444c061aSmrg } 934444c061aSmrg else if (!ctx->was_disowned) { 935444c061aSmrg oldctx = ctx; 936444c061aSmrg } 937444c061aSmrg ctx->free_when_done = TRUE; 938444c061aSmrg ctx = NewContext(XtDisplay(widget), selection); 939444c061aSmrg } 940444c061aSmrg else if (!ctx->was_disowned) { /* current owner is new owner */ 941444c061aSmrg ctx->time = time; 942444c061aSmrg return TRUE; 943444c061aSmrg } 944444c061aSmrg } 945444c061aSmrg if (ctx->widget != widget || ctx->was_disowned || replacement) { 946444c061aSmrg if (ctx->widget && !ctx->was_disowned && !replacement) { 947444c061aSmrg oldctx = ctx; 948444c061aSmrg oldctx->free_when_done = TRUE; 949444c061aSmrg ctx = NewContext(XtDisplay(widget), selection); 950444c061aSmrg } 951444c061aSmrg XtAddEventHandler(widget, (EventMask)0, TRUE, 952444c061aSmrg HandleSelectionEvents, (XtPointer)ctx); 953444c061aSmrg XtAddCallback(widget, XtNdestroyCallback, 954444c061aSmrg WidgetDestroyed, (XtPointer)ctx); 955444c061aSmrg } 956444c061aSmrg ctx->widget = widget; /* Selection offically changes hands. */ 957444c061aSmrg ctx->time = time; 958444c061aSmrg ctx->serial = serial; 959444c061aSmrg } 960444c061aSmrg ctx->convert = convert; 961444c061aSmrg ctx->loses = lose; 962444c061aSmrg ctx->notify = notify; 963444c061aSmrg ctx->owner_cancel = cancel; 964444c061aSmrg ctx->incremental = incremental; 965444c061aSmrg ctx->owner_closure = closure; 966444c061aSmrg ctx->was_disowned = FALSE; 967444c061aSmrg 968444c061aSmrg /* Defer calling the previous selection owner's lose selection procedure 969444c061aSmrg * until the new selection is established, to allow the previous 970444c061aSmrg * selection owner to ask for the new selection to be converted in 971444c061aSmrg * the lose selection procedure. The context pointer is the closure 972444c061aSmrg * of the event handler and the destroy callback, so the old context 973444c061aSmrg * pointer and the record contents must be preserved for LoseSelection. 974444c061aSmrg */ 975444c061aSmrg if (oldctx) { 976444c061aSmrg (void) LoseSelection(oldctx, oldctx->widget, selection, oldctx->time); 977444c061aSmrg if (!oldctx->ref_count && oldctx->free_when_done) 978444c061aSmrg XtFree((char*)oldctx); 979444c061aSmrg } 980444c061aSmrg return TRUE; 981444c061aSmrg} 982444c061aSmrg 983444c061aSmrg 984444c061aSmrgBoolean XtOwnSelection( 985444c061aSmrg Widget widget, 986444c061aSmrg Atom selection, 987444c061aSmrg Time time, 988444c061aSmrg XtConvertSelectionProc convert, 989444c061aSmrg XtLoseSelectionProc lose, 990444c061aSmrg XtSelectionDoneProc notify) 991444c061aSmrg{ 992444c061aSmrg Boolean retval; 993444c061aSmrg WIDGET_TO_APPCON(widget); 994444c061aSmrg 995444c061aSmrg LOCK_APP(app); 996444c061aSmrg retval = OwnSelection(widget, selection, time, convert, lose, notify, 997444c061aSmrg (XtCancelConvertSelectionProc)NULL, 998444c061aSmrg (XtPointer)NULL, FALSE); 999444c061aSmrg UNLOCK_APP(app); 1000444c061aSmrg return retval; 1001444c061aSmrg} 1002444c061aSmrg 1003444c061aSmrg 1004444c061aSmrgBoolean XtOwnSelectionIncremental( 1005444c061aSmrg Widget widget, 1006444c061aSmrg Atom selection, 1007444c061aSmrg Time time, 1008444c061aSmrg XtConvertSelectionIncrProc convert, 1009444c061aSmrg XtLoseSelectionIncrProc lose, 1010444c061aSmrg XtSelectionDoneIncrProc notify, 1011444c061aSmrg XtCancelConvertSelectionProc cancel, 1012444c061aSmrg XtPointer closure) 1013444c061aSmrg{ 1014444c061aSmrg Boolean retval; 1015444c061aSmrg WIDGET_TO_APPCON(widget); 1016444c061aSmrg 1017444c061aSmrg LOCK_APP(app); 1018444c061aSmrg retval = OwnSelection(widget, selection, time, 1019444c061aSmrg (XtConvertSelectionProc)convert, 1020444c061aSmrg (XtLoseSelectionProc)lose, 1021444c061aSmrg (XtSelectionDoneProc)notify, 1022444c061aSmrg cancel, closure, TRUE); 1023444c061aSmrg UNLOCK_APP(app); 1024444c061aSmrg return retval; 1025444c061aSmrg} 1026444c061aSmrg 1027444c061aSmrg 10282265a131Smrgvoid XtDisownSelection( 10292265a131Smrg Widget widget, 10302265a131Smrg Atom selection, 10312265a131Smrg Time time) 1032444c061aSmrg{ 1033444c061aSmrg Select ctx; 1034444c061aSmrg WIDGET_TO_APPCON(widget); 1035444c061aSmrg 1036444c061aSmrg LOCK_APP(app); 1037444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 1038444c061aSmrg if (LoseSelection(ctx, widget, selection, time)) 1039444c061aSmrg XSetSelectionOwner(XtDisplay(widget), selection, None, time); 1040444c061aSmrg UNLOCK_APP(app); 1041444c061aSmrg} 1042444c061aSmrg 1043444c061aSmrg/* Selection Requestor code */ 1044444c061aSmrg 1045444c061aSmrgstatic Boolean IsINCRtype( 1046444c061aSmrg CallBackInfo info, 1047444c061aSmrg Window window, 1048444c061aSmrg Atom prop) 1049444c061aSmrg{ 1050444c061aSmrg unsigned long bytesafter; 1051444c061aSmrg unsigned long length; 1052444c061aSmrg int format; 1053444c061aSmrg Atom type; 1054444c061aSmrg unsigned char *value; 1055444c061aSmrg 1056444c061aSmrg if (prop == None) return False; 1057444c061aSmrg 10589e7bcd65Smrg if (XGetWindowProperty(XtDisplay(info->widget), window, prop, 0L, 0L, 10599e7bcd65Smrg False, info->ctx->prop_list->incr_atom, &type, 10609e7bcd65Smrg &format, &length, &bytesafter, &value) != Success) 10619e7bcd65Smrg return False; 1062444c061aSmrg 1063444c061aSmrg return (type == info->ctx->prop_list->incr_atom); 1064444c061aSmrg} 1065444c061aSmrg 1066444c061aSmrg/*ARGSUSED*/ 1067444c061aSmrgstatic void ReqCleanup( 1068444c061aSmrg Widget widget, 1069444c061aSmrg XtPointer closure, 1070444c061aSmrg XEvent *ev, 1071444c061aSmrg Boolean *cont) 1072444c061aSmrg{ 1073444c061aSmrg CallBackInfo info = (CallBackInfo)closure; 1074444c061aSmrg unsigned long bytesafter, length; 1075444c061aSmrg int format; 1076444c061aSmrg Atom target; 1077444c061aSmrg 1078444c061aSmrg if (ev->type == SelectionNotify) { 1079444c061aSmrg XSelectionEvent *event = (XSelectionEvent *) ev; 1080444c061aSmrg if (!MATCH_SELECT(event, info)) return; /* not really for us */ 1081444c061aSmrg XtRemoveEventHandler(widget, (EventMask)0, TRUE, 1082444c061aSmrg ReqCleanup, (XtPointer) info ); 1083444c061aSmrg if (IsINCRtype(info, XtWindow(widget), event->property)) { 1084444c061aSmrg info->proc = HandleGetIncrement; 1085444c061aSmrg XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask, 1086444c061aSmrg FALSE, ReqCleanup, (XtPointer) info); 1087444c061aSmrg } else { 1088444c061aSmrg if (event->property != None) 1089444c061aSmrg XDeleteProperty(event->display, XtWindow(widget), 1090444c061aSmrg event->property); 1091444c061aSmrg FreeSelectionProperty(XtDisplay(widget), info->property); 1092444c061aSmrg FreeInfo(info); 1093444c061aSmrg } 1094444c061aSmrg } else if ((ev->type == PropertyNotify) && 1095444c061aSmrg (ev->xproperty.state == PropertyNewValue) && 1096444c061aSmrg (ev->xproperty.atom == info->property)) { 1097444c061aSmrg XPropertyEvent *event = (XPropertyEvent *) ev; 10989e7bcd65Smrg char *value = NULL; 10999e7bcd65Smrg if (XGetWindowProperty(event->display, XtWindow(widget), 11009e7bcd65Smrg event->atom, 0L, 1000000, True, AnyPropertyType, 11019e7bcd65Smrg &target, &format, &length, &bytesafter, 11029e7bcd65Smrg (unsigned char **) &value) == Success) { 11039e7bcd65Smrg XFree(value); 11049e7bcd65Smrg if (length == 0) { 11059e7bcd65Smrg XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, 11069e7bcd65Smrg FALSE, ReqCleanup, (XtPointer) info ); 11079e7bcd65Smrg FreeSelectionProperty(XtDisplay(widget), info->property); 11089e7bcd65Smrg XtFree(info->value); /* requestor never got this, so free now */ 11099e7bcd65Smrg FreeInfo(info); 11109e7bcd65Smrg } 1111444c061aSmrg } 1112444c061aSmrg } 1113444c061aSmrg} 1114444c061aSmrg 1115444c061aSmrg/* ARGSUSED */ 1116444c061aSmrgstatic void ReqTimedOut( 1117444c061aSmrg XtPointer closure, 1118444c061aSmrg XtIntervalId *id) 1119444c061aSmrg{ 1120444c061aSmrg XtPointer value = NULL; 1121444c061aSmrg unsigned long length = 0; 1122444c061aSmrg int format = 8; 1123444c061aSmrg Atom resulttype = XT_CONVERT_FAIL; 1124444c061aSmrg CallBackInfo info = (CallBackInfo)closure; 1125444c061aSmrg unsigned long bytesafter; 1126444c061aSmrg unsigned long proplength; 1127444c061aSmrg Atom type; 1128444c061aSmrg XtPointer *c; 1129444c061aSmrg int i; 1130444c061aSmrg 1131444c061aSmrg if (*info->target == info->ctx->prop_list->indirect_atom) { 11329e7bcd65Smrg IndirectPair *pairs = NULL; 11339e7bcd65Smrg if (XGetWindowProperty(XtDisplay(info->widget), XtWindow(info->widget), 11349e7bcd65Smrg info->property, 0L, 10000000, True, 11359e7bcd65Smrg AnyPropertyType, &type, &format, &proplength, 11369e7bcd65Smrg &bytesafter, (unsigned char **) &pairs) 11379e7bcd65Smrg == Success) { 11389e7bcd65Smrg XFree(pairs); 11399e7bcd65Smrg for (proplength = proplength / IndirectPairWordSize, i = 0, 11409e7bcd65Smrg c = info->req_closure; 11419e7bcd65Smrg proplength; proplength--, c++, i++) 11429e7bcd65Smrg (*info->callbacks[i])(info->widget, *c, &info->ctx->selection, 11439e7bcd65Smrg &resulttype, value, &length, &format); 11449e7bcd65Smrg } 1145444c061aSmrg } else { 1146444c061aSmrg (*info->callbacks[0])(info->widget, *info->req_closure, 1147444c061aSmrg &info->ctx->selection, &resulttype, value, &length, &format); 1148444c061aSmrg } 1149444c061aSmrg 1150444c061aSmrg /* change event handlers for straggler events */ 1151444c061aSmrg if (info->proc == (XtEventHandler)HandleSelectionReplies) { 1152444c061aSmrg XtRemoveEventHandler(info->widget, (EventMask)0, 1153444c061aSmrg TRUE, info->proc, (XtPointer) info); 1154444c061aSmrg XtAddEventHandler(info->widget, (EventMask)0, TRUE, 1155444c061aSmrg ReqCleanup, (XtPointer) info); 1156444c061aSmrg } else { 1157444c061aSmrg XtRemoveEventHandler(info->widget,(EventMask) PropertyChangeMask, 1158444c061aSmrg FALSE, info->proc, (XtPointer) info); 1159444c061aSmrg XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask, 1160444c061aSmrg FALSE, ReqCleanup, (XtPointer) info); 1161444c061aSmrg } 1162444c061aSmrg 1163444c061aSmrg} 1164444c061aSmrg 1165444c061aSmrg/*ARGSUSED*/ 1166444c061aSmrgstatic void HandleGetIncrement( 1167444c061aSmrg Widget widget, 1168444c061aSmrg XtPointer closure, 1169444c061aSmrg XEvent *ev, 1170444c061aSmrg Boolean *cont) 1171444c061aSmrg{ 1172444c061aSmrg XPropertyEvent *event = (XPropertyEvent *) ev; 1173444c061aSmrg CallBackInfo info = (CallBackInfo) closure; 1174444c061aSmrg Select ctx = info->ctx; 1175444c061aSmrg char *value; 1176444c061aSmrg unsigned long bytesafter; 1177444c061aSmrg unsigned long length; 1178444c061aSmrg int bad; 1179444c061aSmrg int n = info->current; 1180444c061aSmrg 1181444c061aSmrg if ((event->state != PropertyNewValue) || (event->atom != info->property)) 1182444c061aSmrg return; 1183444c061aSmrg 1184444c061aSmrg bad = XGetWindowProperty(event->display, XtWindow(widget), 1185444c061aSmrg event->atom, 0L, 1186444c061aSmrg 10000000, True, AnyPropertyType, &info->type, 1187444c061aSmrg &info->format, &length, &bytesafter, 1188444c061aSmrg (unsigned char **) &value); 1189444c061aSmrg if (bad) 1190444c061aSmrg return; 1191444c061aSmrg#ifndef DEBUG_WO_TIMERS 1192444c061aSmrg XtRemoveTimeOut(info->timeout); 1193444c061aSmrg#endif 1194444c061aSmrg if (length == 0) { 1195444c061aSmrg unsigned long u_offset = NUMELEM(info->offset, info->format); 1196444c061aSmrg (*info->callbacks[n])(widget, *info->req_closure, &ctx->selection, 1197444c061aSmrg &info->type, 1198444c061aSmrg (info->offset == 0 ? value : info->value), 1199444c061aSmrg &u_offset, &info->format); 1200444c061aSmrg /* assert ((info->offset != 0) == (info->incremental[n]) */ 1201444c061aSmrg if (info->offset != 0) XFree(value); 1202444c061aSmrg XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, 1203444c061aSmrg HandleGetIncrement, (XtPointer) info); 1204444c061aSmrg FreeSelectionProperty(event->display, info->property); 1205444c061aSmrg FreeInfo(info); 1206444c061aSmrg } else { /* add increment to collection */ 1207444c061aSmrg if (info->incremental[n]) { 1208444c061aSmrg#ifdef XT_COPY_SELECTION 1209444c061aSmrg int size = BYTELENGTH(length, info->format) + 1; 1210444c061aSmrg char *tmp = __XtMalloc((Cardinal) size); 1211444c061aSmrg (void) memmove(tmp, value, size); 1212444c061aSmrg XFree(value); 1213444c061aSmrg value = tmp; 1214444c061aSmrg#endif 1215444c061aSmrg (*info->callbacks[n])(widget, *info->req_closure, &ctx->selection, 1216444c061aSmrg &info->type, value, &length, &info->format); 1217444c061aSmrg } else { 1218444c061aSmrg int size = BYTELENGTH(length, info->format); 1219444c061aSmrg if (info->offset + size > info->bytelength) { 1220444c061aSmrg /* allocate enough for this and the next increment */ 1221444c061aSmrg info->bytelength = info->offset + size * 2; 1222444c061aSmrg info->value = XtRealloc(info->value, 1223444c061aSmrg (Cardinal) info->bytelength); 1224444c061aSmrg } 1225444c061aSmrg (void) memmove(&info->value[info->offset], value, size); 1226444c061aSmrg info->offset += size; 1227444c061aSmrg XFree(value); 1228444c061aSmrg } 1229444c061aSmrg /* reset timer */ 1230444c061aSmrg#ifndef DEBUG_WO_TIMERS 1231444c061aSmrg { 1232444c061aSmrg XtAppContext app = XtWidgetToApplicationContext(info->widget); 1233444c061aSmrg info->timeout = XtAppAddTimeOut(app, 1234444c061aSmrg app->selectionTimeout, ReqTimedOut, (XtPointer) info); 1235444c061aSmrg } 1236444c061aSmrg#endif 1237444c061aSmrg } 1238444c061aSmrg} 1239444c061aSmrg 1240444c061aSmrg 1241444c061aSmrgstatic void HandleNone( 1242444c061aSmrg Widget widget, 1243444c061aSmrg XtSelectionCallbackProc callback, 1244444c061aSmrg XtPointer closure, 1245444c061aSmrg Atom selection) 1246444c061aSmrg{ 1247444c061aSmrg unsigned long length = 0; 1248444c061aSmrg int format = 8; 1249444c061aSmrg Atom type = None; 1250444c061aSmrg 1251444c061aSmrg (*callback)(widget, closure, &selection, 1252444c061aSmrg &type, NULL, &length, &format); 1253444c061aSmrg} 1254444c061aSmrg 1255444c061aSmrg 1256444c061aSmrgstatic long IncrPropSize( 1257444c061aSmrg Widget widget, 1258444c061aSmrg unsigned char* value, 1259444c061aSmrg int format, 1260444c061aSmrg unsigned long length) 1261444c061aSmrg{ 1262444c061aSmrg unsigned long size; 1263444c061aSmrg if (format == 32) { 1264444c061aSmrg size = ((long*)value)[length-1]; /* %%% what order for longs? */ 1265444c061aSmrg return size; 1266444c061aSmrg } 1267444c061aSmrg else { 1268444c061aSmrg XtAppWarningMsg( XtWidgetToApplicationContext(widget), 1269444c061aSmrg "badFormat","xtGetSelectionValue",XtCXtToolkitError, 1270444c061aSmrg "Selection owner returned type INCR property with format != 32", 1271444c061aSmrg (String*)NULL, (Cardinal*)NULL ); 1272444c061aSmrg return 0; 1273444c061aSmrg } 1274444c061aSmrg} 1275444c061aSmrg 1276444c061aSmrg 1277444c061aSmrgstatic 1278444c061aSmrgBoolean HandleNormal( 1279444c061aSmrg Display *dpy, 1280444c061aSmrg Widget widget, 1281444c061aSmrg Atom property, 1282444c061aSmrg CallBackInfo info, 1283444c061aSmrg XtPointer closure, 1284444c061aSmrg Atom selection) 1285444c061aSmrg{ 1286444c061aSmrg unsigned long bytesafter; 1287444c061aSmrg unsigned long length; 1288444c061aSmrg int format; 1289444c061aSmrg Atom type; 12909e7bcd65Smrg unsigned char *value = NULL; 1291444c061aSmrg int number = info->current; 1292444c061aSmrg 12939e7bcd65Smrg if (XGetWindowProperty(dpy, XtWindow(widget), property, 0L, 10000000, 12949e7bcd65Smrg False, AnyPropertyType, &type, &format, &length, 12959e7bcd65Smrg &bytesafter, &value) != Success) 12969e7bcd65Smrg return FALSE; 1297444c061aSmrg 1298444c061aSmrg if (type == info->ctx->prop_list->incr_atom) { 1299444c061aSmrg unsigned long size = IncrPropSize(widget, value, format, length); 1300444c061aSmrg XFree((char *)value); 1301444c061aSmrg if (info->property != property) { 1302444c061aSmrg /* within MULTIPLE */ 1303444c061aSmrg CallBackInfo ninfo; 1304444c061aSmrg ninfo = MakeInfo(info->ctx, &info->callbacks[number], 1305444c061aSmrg &info->req_closure[number], 1, widget, 1306444c061aSmrg info->time, &info->incremental[number], &property); 1307444c061aSmrg ninfo->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom)); 1308444c061aSmrg *ninfo->target = info->target[number + 1]; 1309444c061aSmrg info = ninfo; 1310444c061aSmrg } 1311444c061aSmrg HandleIncremental(dpy, widget, property, info, size); 1312444c061aSmrg return FALSE; 1313444c061aSmrg } 1314444c061aSmrg 1315444c061aSmrg XDeleteProperty(dpy, XtWindow(widget), property); 1316444c061aSmrg#ifdef XT_COPY_SELECTION 1317444c061aSmrg if (value) { /* it could have been deleted after the SelectionNotify */ 1318444c061aSmrg int size = BYTELENGTH(length, info->format) + 1; 1319444c061aSmrg char *tmp = __XtMalloc((Cardinal) size); 1320444c061aSmrg (void) memmove(tmp, value, size); 1321444c061aSmrg XFree(value); 1322444c061aSmrg value = (unsigned char *) tmp; 1323444c061aSmrg } 1324444c061aSmrg#endif 1325444c061aSmrg (*info->callbacks[number])(widget, closure, &selection, 1326444c061aSmrg &type, (XtPointer)value, &length, &format); 1327444c061aSmrg 1328444c061aSmrg if (info->incremental[number]) { 1329444c061aSmrg /* let requestor know the whole thing has been received */ 1330444c061aSmrg value = (unsigned char*)__XtMalloc((unsigned)1); 1331444c061aSmrg length = 0; 1332444c061aSmrg (*info->callbacks[number])(widget, closure, &selection, 1333444c061aSmrg &type, (XtPointer)value, &length, &format); 1334444c061aSmrg } 1335444c061aSmrg return TRUE; 1336444c061aSmrg} 1337444c061aSmrg 1338444c061aSmrgstatic void HandleIncremental( 1339444c061aSmrg Display *dpy, 1340444c061aSmrg Widget widget, 1341444c061aSmrg Atom property, 1342444c061aSmrg CallBackInfo info, 1343444c061aSmrg unsigned long size) 1344444c061aSmrg{ 1345444c061aSmrg XtAddEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, 1346444c061aSmrg HandleGetIncrement, (XtPointer) info); 1347444c061aSmrg 1348444c061aSmrg /* now start the transfer */ 1349444c061aSmrg XDeleteProperty(dpy, XtWindow(widget), property); 1350444c061aSmrg XFlush(dpy); 1351444c061aSmrg 1352444c061aSmrg info->bytelength = size; 1353444c061aSmrg if (info->incremental[info->current]) /* requestor wants incremental too */ 1354444c061aSmrg info->value = NULL; /* so no need for buffer to assemble value */ 1355444c061aSmrg else 1356444c061aSmrg info->value = (char *) __XtMalloc((unsigned) info->bytelength); 1357444c061aSmrg info->offset = 0; 1358444c061aSmrg 1359444c061aSmrg /* reset the timer */ 1360444c061aSmrg info->proc = HandleGetIncrement; 1361444c061aSmrg#ifndef DEBUG_WO_TIMERS 1362444c061aSmrg { 1363444c061aSmrg XtAppContext app = XtWidgetToApplicationContext(info->widget); 1364444c061aSmrg info->timeout = XtAppAddTimeOut(app, 1365444c061aSmrg app->selectionTimeout, ReqTimedOut, (XtPointer) info); 1366444c061aSmrg } 1367444c061aSmrg#endif 1368444c061aSmrg} 1369444c061aSmrg 1370444c061aSmrg/*ARGSUSED*/ 1371444c061aSmrgstatic void HandleSelectionReplies( 1372444c061aSmrg Widget widget, 1373444c061aSmrg XtPointer closure, 1374444c061aSmrg XEvent *ev, 1375444c061aSmrg Boolean *cont) 1376444c061aSmrg{ 1377444c061aSmrg XSelectionEvent *event = (XSelectionEvent *) ev; 1378444c061aSmrg Display *dpy = event->display; 1379444c061aSmrg CallBackInfo info = (CallBackInfo) closure; 1380444c061aSmrg Select ctx = info->ctx; 1381444c061aSmrg unsigned long bytesafter; 1382444c061aSmrg unsigned long length; 1383444c061aSmrg int format; 1384444c061aSmrg Atom type; 1385444c061aSmrg XtPointer *c; 1386444c061aSmrg 1387444c061aSmrg if (event->type != SelectionNotify) return; 1388444c061aSmrg if (!MATCH_SELECT(event, info)) return; /* not really for us */ 1389444c061aSmrg#ifndef DEBUG_WO_TIMERS 1390444c061aSmrg XtRemoveTimeOut(info->timeout); 1391444c061aSmrg#endif 1392444c061aSmrg XtRemoveEventHandler(widget, (EventMask)0, TRUE, 1393444c061aSmrg HandleSelectionReplies, (XtPointer) info ); 1394444c061aSmrg if (event->target == ctx->prop_list->indirect_atom) { 13959e7bcd65Smrg IndirectPair *pairs = NULL, *p; 13969e7bcd65Smrg if (XGetWindowProperty(dpy, XtWindow(widget), info->property, 0L, 13979e7bcd65Smrg 10000000, True, AnyPropertyType, &type, &format, 13989e7bcd65Smrg &length, &bytesafter, (unsigned char **) &pairs) 13999e7bcd65Smrg != Success) 14009e7bcd65Smrg length = 0; 1401444c061aSmrg for (length = length / IndirectPairWordSize, p = pairs, 1402444c061aSmrg c = info->req_closure; 1403444c061aSmrg length; length--, p++, c++, info->current++) { 1404444c061aSmrg if (event->property == None || format != 32 || p->target == None 1405444c061aSmrg || /* bug compatibility */ p->property == None) { 1406444c061aSmrg HandleNone(widget, info->callbacks[info->current], 1407444c061aSmrg *c, event->selection); 1408444c061aSmrg if (p->property != None) 1409444c061aSmrg FreeSelectionProperty(XtDisplay(widget), p->property); 1410444c061aSmrg } else { 1411444c061aSmrg if (HandleNormal(dpy, widget, p->property, info, *c, 1412444c061aSmrg event->selection)) { 1413444c061aSmrg FreeSelectionProperty(XtDisplay(widget), p->property); 1414444c061aSmrg } 1415444c061aSmrg } 1416444c061aSmrg } 1417444c061aSmrg XFree((char*)pairs); 1418444c061aSmrg FreeSelectionProperty(dpy, info->property); 1419444c061aSmrg FreeInfo(info); 1420444c061aSmrg } else if (event->property == None) { 1421444c061aSmrg HandleNone(widget, info->callbacks[0], *info->req_closure, event->selection); 1422444c061aSmrg FreeSelectionProperty(XtDisplay(widget), info->property); 1423444c061aSmrg FreeInfo(info); 1424444c061aSmrg } else { 1425444c061aSmrg if (HandleNormal(dpy, widget, event->property, info, 1426444c061aSmrg *info->req_closure, event->selection)) { 1427444c061aSmrg FreeSelectionProperty(XtDisplay(widget), info->property); 1428444c061aSmrg FreeInfo(info); 1429444c061aSmrg } 1430444c061aSmrg } 1431444c061aSmrg} 1432444c061aSmrg 1433444c061aSmrgstatic void DoLocalTransfer( 1434444c061aSmrg Request req, 1435444c061aSmrg Atom selection, 1436444c061aSmrg Atom target, 1437444c061aSmrg Widget widget, /* The widget requesting the value. */ 1438444c061aSmrg XtSelectionCallbackProc callback, 1439444c061aSmrg XtPointer closure, /* the closure for the callback, not the conversion */ 1440444c061aSmrg Boolean incremental, 1441444c061aSmrg Atom property) 1442444c061aSmrg{ 1443444c061aSmrg Select ctx = req->ctx; 1444444c061aSmrg XtPointer value = NULL, temp, total = NULL; 1445444c061aSmrg unsigned long length; 1446444c061aSmrg int format; 1447444c061aSmrg Atom resulttype; 1448444c061aSmrg unsigned long totallength = 0; 1449444c061aSmrg 1450444c061aSmrg req->event.type = 0; 1451444c061aSmrg req->event.target = target; 1452444c061aSmrg req->event.property = req->property = property; 1453444c061aSmrg req->event.requestor = req->requestor = XtWindow(widget); 1454444c061aSmrg 1455444c061aSmrg if (ctx->incremental) { 1456444c061aSmrg unsigned long size = MAX_SELECTION_INCR(ctx->dpy); 1457444c061aSmrg if (!(*(XtConvertSelectionIncrProc)ctx->convert) 1458444c061aSmrg (ctx->widget, &selection, &target, 1459444c061aSmrg &resulttype, &value, &length, &format, 1460444c061aSmrg &size, ctx->owner_closure, (XtRequestId*)&req)) { 1461444c061aSmrg HandleNone(widget, callback, closure, selection); 1462444c061aSmrg } 1463444c061aSmrg else { 1464444c061aSmrg if (incremental) { 1465444c061aSmrg Boolean allSent = FALSE; 1466444c061aSmrg while (!allSent) { 1467444c061aSmrg if (ctx->notify && (value != NULL)) { 1468444c061aSmrg int bytelength = BYTELENGTH(length,format); 1469444c061aSmrg /* both sides think they own this storage */ 1470444c061aSmrg temp = __XtMalloc((unsigned)bytelength); 1471444c061aSmrg (void) memmove(temp, value, bytelength); 1472444c061aSmrg value = temp; 1473444c061aSmrg } 1474444c061aSmrg /* use care; older clients were never warned that 1475444c061aSmrg * they must return a value even if length==0 1476444c061aSmrg */ 1477444c061aSmrg if (value == NULL) value = __XtMalloc((unsigned)1); 1478444c061aSmrg (*callback)(widget, closure, &selection, 1479444c061aSmrg &resulttype, value, &length, &format); 1480444c061aSmrg if (length) { 1481444c061aSmrg /* should owner be notified on end-of-piece? 1482444c061aSmrg * Spec is unclear, but non-local transfers don't. 1483444c061aSmrg */ 1484444c061aSmrg (*(XtConvertSelectionIncrProc)ctx->convert) 1485444c061aSmrg (ctx->widget, &selection, &target, 1486444c061aSmrg &resulttype, &value, &length, &format, 1487444c061aSmrg &size, ctx->owner_closure, 1488444c061aSmrg (XtRequestId*)&req); 1489444c061aSmrg } 1490444c061aSmrg else allSent = TRUE; 1491444c061aSmrg } 1492444c061aSmrg } else { 1493444c061aSmrg while (length) { 1494444c061aSmrg int bytelength = BYTELENGTH(length, format); 1495444c061aSmrg total = XtRealloc(total, 1496444c061aSmrg (unsigned) (totallength += bytelength)); 1497444c061aSmrg (void) memmove((char*)total + totallength - bytelength, 1498444c061aSmrg value, 1499444c061aSmrg bytelength); 1500444c061aSmrg (*(XtConvertSelectionIncrProc)ctx->convert) 1501444c061aSmrg (ctx->widget, &selection, &target, 1502444c061aSmrg &resulttype, &value, &length, &format, 1503444c061aSmrg &size, ctx->owner_closure, (XtRequestId*)&req); 1504444c061aSmrg } 1505444c061aSmrg if (total == NULL) total = __XtMalloc(1); 1506444c061aSmrg totallength = NUMELEM(totallength, format); 1507444c061aSmrg (*callback)(widget, closure, &selection, &resulttype, 1508444c061aSmrg total, &totallength, &format); 1509444c061aSmrg } 1510444c061aSmrg if (ctx->notify) 1511444c061aSmrg (*(XtSelectionDoneIncrProc)ctx->notify) 1512444c061aSmrg (ctx->widget, &selection, &target, 1513444c061aSmrg (XtRequestId*)&req, ctx->owner_closure); 1514444c061aSmrg else XtFree((char*)value); 1515444c061aSmrg } 1516444c061aSmrg } else { /* not incremental owner */ 1517444c061aSmrg if (!(*ctx->convert)(ctx->widget, &selection, &target, 1518444c061aSmrg &resulttype, &value, &length, &format)) { 1519444c061aSmrg HandleNone(widget, callback, closure, selection); 1520444c061aSmrg } else { 1521444c061aSmrg if (ctx->notify && (value != NULL)) { 1522444c061aSmrg int bytelength = BYTELENGTH(length,format); 1523444c061aSmrg /* both sides think they own this storage; better copy */ 1524444c061aSmrg temp = __XtMalloc((unsigned)bytelength); 1525444c061aSmrg (void) memmove(temp, value, bytelength); 1526444c061aSmrg value = temp; 1527444c061aSmrg } 1528444c061aSmrg if (value == NULL) value = __XtMalloc((unsigned)1); 1529444c061aSmrg (*callback)(widget, closure, &selection, &resulttype, 1530444c061aSmrg value, &length, &format); 1531444c061aSmrg if (ctx->notify) 1532444c061aSmrg (*ctx->notify)(ctx->widget, &selection, &target); 1533444c061aSmrg } 1534444c061aSmrg } 1535444c061aSmrg} 1536444c061aSmrg 1537444c061aSmrgstatic void GetSelectionValue( 1538444c061aSmrg Widget widget, 1539444c061aSmrg Atom selection, 1540444c061aSmrg Atom target, 1541444c061aSmrg XtSelectionCallbackProc callback, 1542444c061aSmrg XtPointer closure, 1543444c061aSmrg Time time, 1544444c061aSmrg Boolean incremental, 1545444c061aSmrg Atom property) 1546444c061aSmrg{ 1547444c061aSmrg Select ctx; 1548444c061aSmrg CallBackInfo info; 1549444c061aSmrg Atom properties[1]; 1550444c061aSmrg 1551444c061aSmrg properties[0] = property; 1552444c061aSmrg 1553444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 1554444c061aSmrg if (ctx->widget && !ctx->was_disowned) { 1555444c061aSmrg RequestRec req; 1556444c061aSmrg ctx->req = &req; 1557444c061aSmrg req.ctx = ctx; 1558444c061aSmrg req.event.time = time; 1559444c061aSmrg ctx->ref_count++; 1560444c061aSmrg DoLocalTransfer(&req, selection, target, widget, 1561444c061aSmrg callback, closure, incremental, property); 1562444c061aSmrg if (--ctx->ref_count == 0 && ctx->free_when_done) 1563444c061aSmrg XtFree((char*)ctx); 1564444c061aSmrg else 1565444c061aSmrg ctx->req = NULL; 1566444c061aSmrg } 1567444c061aSmrg else { 1568444c061aSmrg info = MakeInfo(ctx, &callback, &closure, 1, widget, 1569444c061aSmrg time, &incremental, properties); 1570444c061aSmrg info->target = (Atom *)__XtMalloc((unsigned) sizeof(Atom)); 1571444c061aSmrg *(info->target) = target; 1572444c061aSmrg RequestSelectionValue(info, selection, target); 1573444c061aSmrg } 1574444c061aSmrg} 1575444c061aSmrg 1576444c061aSmrg 1577444c061aSmrgvoid XtGetSelectionValue( 1578444c061aSmrg Widget widget, 1579444c061aSmrg Atom selection, 1580444c061aSmrg Atom target, 1581444c061aSmrg XtSelectionCallbackProc callback, 1582444c061aSmrg XtPointer closure, 1583444c061aSmrg Time time) 1584444c061aSmrg{ 1585444c061aSmrg Atom property; 1586444c061aSmrg Boolean incr = False; 1587444c061aSmrg WIDGET_TO_APPCON(widget); 1588444c061aSmrg 1589444c061aSmrg LOCK_APP(app); 1590444c061aSmrg property = GetParamInfo(widget, selection); 1591444c061aSmrg RemoveParamInfo(widget, selection); 1592444c061aSmrg 1593444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1594444c061aSmrg AddSelectionRequests(widget, selection, 1, &target, &callback, 1, 1595444c061aSmrg &closure, &incr, &property); 1596444c061aSmrg } else { 1597444c061aSmrg GetSelectionValue(widget, selection, target, callback, 1598444c061aSmrg closure, time, FALSE, property); 1599444c061aSmrg } 1600444c061aSmrg UNLOCK_APP(app); 1601444c061aSmrg} 1602444c061aSmrg 1603444c061aSmrg 1604444c061aSmrgvoid XtGetSelectionValueIncremental( 1605444c061aSmrg Widget widget, 1606444c061aSmrg Atom selection, 1607444c061aSmrg Atom target, 1608444c061aSmrg XtSelectionCallbackProc callback, 1609444c061aSmrg XtPointer closure, 1610444c061aSmrg Time time) 1611444c061aSmrg{ 1612444c061aSmrg Atom property; 1613444c061aSmrg Boolean incr = TRUE; 1614444c061aSmrg WIDGET_TO_APPCON(widget); 1615444c061aSmrg 1616444c061aSmrg LOCK_APP(app); 1617444c061aSmrg property = GetParamInfo(widget, selection); 1618444c061aSmrg RemoveParamInfo(widget, selection); 1619444c061aSmrg 1620444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1621444c061aSmrg AddSelectionRequests(widget, selection, 1, &target, &callback, 1, 1622444c061aSmrg &closure, &incr, &property); 1623444c061aSmrg } else { 1624444c061aSmrg GetSelectionValue(widget, selection, target, callback, 1625444c061aSmrg closure, time, TRUE, property); 1626444c061aSmrg } 1627444c061aSmrg 1628444c061aSmrg UNLOCK_APP(app); 1629444c061aSmrg} 1630444c061aSmrg 1631444c061aSmrg 1632444c061aSmrgstatic void GetSelectionValues( 1633444c061aSmrg Widget widget, 1634444c061aSmrg Atom selection, 1635444c061aSmrg Atom *targets, 1636444c061aSmrg int count, 1637444c061aSmrg XtSelectionCallbackProc *callbacks, 1638444c061aSmrg int num_callbacks, 1639444c061aSmrg XtPointer *closures, 1640444c061aSmrg Time time, 1641444c061aSmrg Boolean *incremental, 1642444c061aSmrg Atom *properties) 1643444c061aSmrg{ 1644444c061aSmrg Select ctx; 1645444c061aSmrg CallBackInfo info; 1646444c061aSmrg IndirectPair *pairs, *p; 1647444c061aSmrg Atom *t; 1648444c061aSmrg 1649444c061aSmrg if (count == 0) return; 1650444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 1651444c061aSmrg if (ctx->widget && !ctx->was_disowned) { 1652444c061aSmrg int j, i; 1653444c061aSmrg RequestRec req; 1654444c061aSmrg ctx->req = &req; 1655444c061aSmrg req.ctx = ctx; 1656444c061aSmrg req.event.time = time; 1657444c061aSmrg ctx->ref_count++; 1658444c061aSmrg for (i = 0, j = 0; count; count--, i++, j++ ) { 1659444c061aSmrg if (j >= num_callbacks) j = 0; 1660444c061aSmrg 1661444c061aSmrg DoLocalTransfer(&req, selection, targets[i], widget, 1662444c061aSmrg callbacks[j], closures[i], incremental[i], 1663444c061aSmrg properties ? properties[i] : None); 1664444c061aSmrg 1665444c061aSmrg } 1666444c061aSmrg if (--ctx->ref_count == 0 && ctx->free_when_done) 1667444c061aSmrg XtFree((char*)ctx); 1668444c061aSmrg else 1669444c061aSmrg ctx->req = NULL; 1670444c061aSmrg } else { 1671444c061aSmrg XtSelectionCallbackProc *passed_callbacks; 1672444c061aSmrg XtSelectionCallbackProc stack_cbs[32]; 1673444c061aSmrg int i = 0, j = 0; 1674444c061aSmrg 1675444c061aSmrg passed_callbacks = (XtSelectionCallbackProc *) 1676444c061aSmrg XtStackAlloc(sizeof(XtSelectionCallbackProc) * count, stack_cbs); 1677444c061aSmrg 1678444c061aSmrg /* To deal with the old calls from XtGetSelectionValues* we 1679444c061aSmrg will repeat however many callbacks have been passed into 1680444c061aSmrg the array */ 1681444c061aSmrg for(i = 0; i < count; i++) { 1682444c061aSmrg if (j >= num_callbacks) j = 0; 1683444c061aSmrg passed_callbacks[i] = callbacks[j]; 1684444c061aSmrg j++; 1685444c061aSmrg } 1686444c061aSmrg info = MakeInfo(ctx, passed_callbacks, closures, count, widget, 1687444c061aSmrg time, incremental, properties); 1688444c061aSmrg XtStackFree((XtPointer) passed_callbacks, stack_cbs); 1689444c061aSmrg 1690444c061aSmrg info->target = (Atom *)__XtMalloc((unsigned) ((count+1) * sizeof(Atom))); 1691444c061aSmrg (*info->target) = ctx->prop_list->indirect_atom; 1692444c061aSmrg (void) memmove((char *) info->target+sizeof(Atom), (char *) targets, 1693444c061aSmrg count * sizeof(Atom)); 1694444c061aSmrg pairs = (IndirectPair*)__XtMalloc((unsigned)(count*sizeof(IndirectPair))); 1695444c061aSmrg for (p = &pairs[count-1], t = &targets[count-1], i = count - 1; 1696444c061aSmrg p >= pairs; p--, t--, i--) { 1697444c061aSmrg p->target = *t; 1698444c061aSmrg if (properties == NULL || properties[i] == None) { 1699444c061aSmrg p->property = GetSelectionProperty(XtDisplay(widget)); 1700444c061aSmrg XDeleteProperty(XtDisplay(widget), XtWindow(widget), 1701444c061aSmrg p->property); 1702444c061aSmrg } else { 1703444c061aSmrg p->property = properties[i]; 1704444c061aSmrg } 1705444c061aSmrg } 1706444c061aSmrg XChangeProperty(XtDisplay(widget), XtWindow(widget), 1707444c061aSmrg info->property, info->property, 1708444c061aSmrg 32, PropModeReplace, (unsigned char *) pairs, 1709444c061aSmrg count * IndirectPairWordSize); 1710444c061aSmrg XtFree((char*)pairs); 1711444c061aSmrg RequestSelectionValue(info, selection, ctx->prop_list->indirect_atom); 1712444c061aSmrg } 1713444c061aSmrg} 1714444c061aSmrg 1715444c061aSmrg 1716444c061aSmrgvoid XtGetSelectionValues( 1717444c061aSmrg Widget widget, 1718444c061aSmrg Atom selection, 1719444c061aSmrg Atom *targets, 1720444c061aSmrg int count, 1721444c061aSmrg XtSelectionCallbackProc callback, 1722444c061aSmrg XtPointer *closures, 1723444c061aSmrg Time time) 1724444c061aSmrg{ 1725444c061aSmrg Boolean incremental_values[32]; 1726444c061aSmrg Boolean *incremental; 1727444c061aSmrg int i; 1728444c061aSmrg WIDGET_TO_APPCON(widget); 1729444c061aSmrg 1730444c061aSmrg LOCK_APP(app); 1731444c061aSmrg incremental = XtStackAlloc(count * sizeof(Boolean), incremental_values); 1732444c061aSmrg for(i = 0; i < count; i++) incremental[i] = FALSE; 1733444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1734444c061aSmrg AddSelectionRequests(widget, selection, count, targets, &callback, 1735444c061aSmrg 1, closures, incremental, NULL); 1736444c061aSmrg } else { 1737444c061aSmrg GetSelectionValues(widget, selection, targets, count, &callback, 1, 1738444c061aSmrg closures, time, incremental, NULL); 1739444c061aSmrg } 1740444c061aSmrg XtStackFree((XtPointer) incremental, incremental_values); 1741444c061aSmrg UNLOCK_APP(app); 1742444c061aSmrg} 1743444c061aSmrg 1744444c061aSmrg 1745444c061aSmrgvoid XtGetSelectionValuesIncremental( 1746444c061aSmrg Widget widget, 1747444c061aSmrg Atom selection, 1748444c061aSmrg Atom *targets, 1749444c061aSmrg int count, 1750444c061aSmrg XtSelectionCallbackProc callback, 1751444c061aSmrg XtPointer *closures, 1752444c061aSmrg Time time) 1753444c061aSmrg{ 1754444c061aSmrg Boolean incremental_values[32]; 1755444c061aSmrg Boolean *incremental; 1756444c061aSmrg int i; 1757444c061aSmrg WIDGET_TO_APPCON(widget); 1758444c061aSmrg 1759444c061aSmrg LOCK_APP(app); 1760444c061aSmrg incremental = XtStackAlloc(count * sizeof(Boolean), incremental_values); 1761444c061aSmrg for(i = 0; i < count; i++) incremental[i] = TRUE; 1762444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1763444c061aSmrg AddSelectionRequests(widget, selection, count, targets, &callback, 1764444c061aSmrg 1, closures, incremental, NULL); 1765444c061aSmrg } else { 1766444c061aSmrg GetSelectionValues(widget, selection, targets, count, 1767444c061aSmrg &callback, 1, closures, time, incremental, NULL); 1768444c061aSmrg } 1769444c061aSmrg XtStackFree((XtPointer) incremental, incremental_values); 1770444c061aSmrg UNLOCK_APP(app); 1771444c061aSmrg} 1772444c061aSmrg 1773444c061aSmrg 1774444c061aSmrgstatic Request GetRequestRecord( 1775444c061aSmrg Widget widget, 1776444c061aSmrg Atom selection, 1777444c061aSmrg XtRequestId id) 1778444c061aSmrg{ 1779444c061aSmrg Request req = (Request)id; 1780444c061aSmrg Select ctx = NULL; 1781444c061aSmrg 1782444c061aSmrg if ( (req == NULL 1783444c061aSmrg && ((ctx = FindCtx( XtDisplay(widget), selection )) == NULL 1784444c061aSmrg || ctx->req == NULL 1785444c061aSmrg || ctx->selection != selection 1786444c061aSmrg || ctx->widget == NULL)) 1787444c061aSmrg || (req != NULL 1788444c061aSmrg && (req->ctx == NULL 1789444c061aSmrg || req->ctx->selection != selection 1790444c061aSmrg || req->ctx->widget != widget))) 1791444c061aSmrg { 1792444c061aSmrg String params = XtName(widget); 1793444c061aSmrg Cardinal num_params = 1; 1794444c061aSmrg XtAppWarningMsg(XtWidgetToApplicationContext(widget), 1795444c061aSmrg "notInConvertSelection", "xtGetSelectionRequest", 1796444c061aSmrg XtCXtToolkitError, 1797444c061aSmrg "XtGetSelectionRequest or XtGetSelectionParameters called for widget \"%s\" outside of ConvertSelection proc", 1798444c061aSmrg ¶ms, &num_params 1799444c061aSmrg ); 1800444c061aSmrg return NULL; 1801444c061aSmrg } 1802444c061aSmrg 1803444c061aSmrg if (req == NULL) { 1804444c061aSmrg /* non-incremental owner; only one request can be 1805444c061aSmrg * outstanding at a time, so it's safe to keep ptr in ctx */ 1806444c061aSmrg req = ctx->req; 1807444c061aSmrg } 1808444c061aSmrg return req; 1809444c061aSmrg} 1810444c061aSmrg 1811444c061aSmrgXSelectionRequestEvent *XtGetSelectionRequest( 1812444c061aSmrg Widget widget, 1813444c061aSmrg Atom selection, 1814444c061aSmrg XtRequestId id) 1815444c061aSmrg{ 1816444c061aSmrg Request req = (Request)id; 1817444c061aSmrg WIDGET_TO_APPCON(widget); 1818444c061aSmrg 1819444c061aSmrg LOCK_APP(app); 1820444c061aSmrg 1821444c061aSmrg req = GetRequestRecord(widget, selection, id); 1822444c061aSmrg 1823444c061aSmrg if (! req) { 1824444c061aSmrg UNLOCK_APP(app); 1825444c061aSmrg return (XSelectionRequestEvent*) NULL; 1826444c061aSmrg } 1827444c061aSmrg 1828444c061aSmrg if (req->event.type == 0) { 1829444c061aSmrg /* owner is local; construct the remainder of the event */ 1830444c061aSmrg req->event.type = SelectionRequest; 1831444c061aSmrg req->event.serial = LastKnownRequestProcessed(XtDisplay(widget)); 1832444c061aSmrg req->event.send_event = True; 1833444c061aSmrg req->event.display = XtDisplay(widget); 1834444c061aSmrg req->event.owner = XtWindow(req->ctx->widget); 1835444c061aSmrg req->event.selection = selection; 1836444c061aSmrg } 1837444c061aSmrg UNLOCK_APP(app); 1838444c061aSmrg return &req->event; 1839444c061aSmrg} 1840444c061aSmrg 1841444c061aSmrg/* Property atom access */ 1842444c061aSmrgAtom XtReservePropertyAtom( 1843444c061aSmrg Widget w) 1844444c061aSmrg{ 1845444c061aSmrg return(GetSelectionProperty(XtDisplay(w))); 1846444c061aSmrg} 1847444c061aSmrg 1848444c061aSmrgvoid XtReleasePropertyAtom( 1849444c061aSmrg Widget w, 1850444c061aSmrg Atom atom) 1851444c061aSmrg{ 1852444c061aSmrg FreeSelectionProperty(XtDisplay(w), atom); 1853444c061aSmrg} 1854444c061aSmrg 1855444c061aSmrg 1856444c061aSmrg/* Multiple utilities */ 1857444c061aSmrg 1858444c061aSmrg/* All requests are put in a single list per widget. It is 1859444c061aSmrg very unlikely anyone will be gathering multiple MULTIPLE 1860444c061aSmrg requests at the same time, so the loss in efficiency for 1861444c061aSmrg this case is acceptable */ 1862444c061aSmrg 1863444c061aSmrg/* Queue one or more requests to the one we're gathering */ 1864444c061aSmrgstatic void AddSelectionRequests( 1865444c061aSmrg Widget wid, 1866444c061aSmrg Atom sel, 1867444c061aSmrg int count, 1868444c061aSmrg Atom *targets, 1869444c061aSmrg XtSelectionCallbackProc *callbacks, 1870444c061aSmrg int num_cb, 1871444c061aSmrg XtPointer *closures, 1872444c061aSmrg Boolean *incrementals, 1873444c061aSmrg Atom *properties) 1874444c061aSmrg{ 1875444c061aSmrg QueuedRequestInfo qi; 1876444c061aSmrg Window window = XtWindow(wid); 1877444c061aSmrg Display *dpy = XtDisplay(wid); 1878444c061aSmrg 1879444c061aSmrg LOCK_PROCESS; 1880444c061aSmrg if (multipleContext == 0) multipleContext = XUniqueContext(); 1881444c061aSmrg 1882444c061aSmrg qi = NULL; 1883444c061aSmrg (void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi); 1884444c061aSmrg 1885444c061aSmrg if (qi != NULL) { 1886444c061aSmrg QueuedRequest *req = qi->requests; 1887444c061aSmrg int start = qi->count; 1888444c061aSmrg int i = 0; 1889444c061aSmrg int j = 0; 1890444c061aSmrg 1891444c061aSmrg qi->count += count; 1892444c061aSmrg req = (QueuedRequest*) XtRealloc((char*) req, 1893444c061aSmrg (start + count) * 1894444c061aSmrg sizeof(QueuedRequest)); 1895444c061aSmrg while(i < count) { 1896444c061aSmrg QueuedRequest newreq = (QueuedRequest) 1897444c061aSmrg __XtMalloc(sizeof(QueuedRequestRec)); 1898444c061aSmrg newreq->selection = sel; 1899444c061aSmrg newreq->target = targets[i]; 1900444c061aSmrg if (properties != NULL) 1901444c061aSmrg newreq->param = properties[i]; 1902444c061aSmrg else { 1903444c061aSmrg newreq->param = GetSelectionProperty(dpy); 1904444c061aSmrg XDeleteProperty(dpy, window, newreq->param); 1905444c061aSmrg } 1906444c061aSmrg newreq->callback = callbacks[j]; 1907444c061aSmrg newreq->closure = closures[i]; 1908444c061aSmrg newreq->incremental = incrementals[i]; 1909444c061aSmrg 1910444c061aSmrg req[start] = newreq; 1911444c061aSmrg start++; 1912444c061aSmrg i++; 1913444c061aSmrg j++; 1914444c061aSmrg if (j > num_cb) j = 0; 1915444c061aSmrg } 1916444c061aSmrg 1917444c061aSmrg qi->requests = req; 1918444c061aSmrg } else { 1919444c061aSmrg /* Impossible */ 1920444c061aSmrg } 1921444c061aSmrg 1922444c061aSmrg UNLOCK_PROCESS; 1923444c061aSmrg} 1924444c061aSmrg 1925444c061aSmrg/* Only call IsGatheringRequest when we have a lock already */ 1926444c061aSmrg 1927444c061aSmrgstatic Boolean IsGatheringRequest( 1928444c061aSmrg Widget wid, 1929444c061aSmrg Atom sel) 1930444c061aSmrg{ 1931444c061aSmrg QueuedRequestInfo qi; 1932444c061aSmrg Window window = XtWindow(wid); 1933444c061aSmrg Display *dpy = XtDisplay(wid); 1934444c061aSmrg Boolean found = False; 1935444c061aSmrg int i; 1936444c061aSmrg 1937444c061aSmrg if (multipleContext == 0) multipleContext = XUniqueContext(); 1938444c061aSmrg 1939444c061aSmrg qi = NULL; 1940444c061aSmrg (void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi); 1941444c061aSmrg 1942444c061aSmrg if (qi != NULL) { 1943444c061aSmrg i = 0; 1944444c061aSmrg while(qi->selections[i] != None) { 1945444c061aSmrg if (qi->selections[i] == sel) { 1946444c061aSmrg found = True; 1947444c061aSmrg break; 1948444c061aSmrg } 1949444c061aSmrg i++; 1950444c061aSmrg } 1951444c061aSmrg } 1952444c061aSmrg 1953444c061aSmrg return(found); 1954444c061aSmrg} 1955444c061aSmrg 1956444c061aSmrg/* Cleanup request scans the request queue and releases any 1957444c061aSmrg properties queued, and removes any requests queued */ 1958444c061aSmrgstatic void CleanupRequest( 1959444c061aSmrg Display *dpy, 1960444c061aSmrg QueuedRequestInfo qi, 1961444c061aSmrg Atom sel) 1962444c061aSmrg{ 1963444c061aSmrg int i, j, n; 1964444c061aSmrg 1965444c061aSmrg i = 0; 1966444c061aSmrg 1967444c061aSmrg /* Remove this selection from the list */ 1968444c061aSmrg n = 0; 1969444c061aSmrg while(qi->selections[n] != sel && 1970444c061aSmrg qi->selections[n] != None) n++; 1971444c061aSmrg if (qi->selections[n] == sel) { 1972444c061aSmrg while(qi->selections[n] != None) { 1973444c061aSmrg qi->selections[n] = qi->selections[n + 1]; 1974444c061aSmrg n++; 1975444c061aSmrg } 1976444c061aSmrg } 1977444c061aSmrg 1978444c061aSmrg while(i < qi->count) { 1979444c061aSmrg QueuedRequest req = qi->requests[i]; 1980444c061aSmrg 1981444c061aSmrg if (req->selection == sel) { 1982444c061aSmrg /* Match */ 1983444c061aSmrg if (req->param != None) 1984444c061aSmrg FreeSelectionProperty(dpy, req->param); 1985444c061aSmrg qi->count--; 1986444c061aSmrg 1987444c061aSmrg for(j = i; j < qi->count; j++) 1988444c061aSmrg qi->requests[j] = qi->requests[j + 1]; 1989444c061aSmrg 1990444c061aSmrg XtFree((char*) req); 1991444c061aSmrg } else { 1992444c061aSmrg i++; 1993444c061aSmrg } 1994444c061aSmrg } 1995444c061aSmrg} 1996444c061aSmrg 19972265a131Smrgvoid XtCreateSelectionRequest( 1998444c061aSmrg Widget widget, 1999444c061aSmrg Atom selection) 2000444c061aSmrg{ 2001444c061aSmrg QueuedRequestInfo queueInfo; 2002444c061aSmrg Window window = XtWindow(widget); 2003444c061aSmrg Display *dpy = XtDisplay(widget); 2004444c061aSmrg int n; 2005444c061aSmrg 2006444c061aSmrg LOCK_PROCESS; 2007444c061aSmrg if (multipleContext == 0) multipleContext = XUniqueContext(); 2008444c061aSmrg 2009444c061aSmrg queueInfo = NULL; 2010444c061aSmrg (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo); 2011444c061aSmrg 2012444c061aSmrg /* If there is one, then cancel it */ 20132265a131Smrg if (queueInfo != NULL) 2014444c061aSmrg CleanupRequest(dpy, queueInfo, selection); 2015444c061aSmrg else { 2016444c061aSmrg /* Create it */ 2017444c061aSmrg queueInfo = (QueuedRequestInfo) __XtMalloc(sizeof(QueuedRequestInfoRec)); 2018444c061aSmrg queueInfo->count = 0; 2019444c061aSmrg queueInfo->selections = (Atom*) __XtMalloc(sizeof(Atom) * 2); 2020444c061aSmrg queueInfo->selections[0] = None; 2021444c061aSmrg queueInfo->requests = (QueuedRequest *) 2022444c061aSmrg __XtMalloc(sizeof(QueuedRequest)); 2023444c061aSmrg } 2024444c061aSmrg 2025444c061aSmrg /* Append this selection to list */ 2026444c061aSmrg n = 0; 2027444c061aSmrg while(queueInfo->selections[n] != None) n++; 2028444c061aSmrg queueInfo->selections = 2029444c061aSmrg (Atom*) XtRealloc((char*) queueInfo->selections, 2030444c061aSmrg (n + 2) * sizeof(Atom)); 2031444c061aSmrg queueInfo->selections[n] = selection; 2032444c061aSmrg queueInfo->selections[n + 1] = None; 2033444c061aSmrg 2034444c061aSmrg (void) XSaveContext(dpy, window, multipleContext, (char*) queueInfo); 2035444c061aSmrg UNLOCK_PROCESS; 2036444c061aSmrg} 2037444c061aSmrg 20382265a131Smrgvoid XtSendSelectionRequest( 2039444c061aSmrg Widget widget, 2040444c061aSmrg Atom selection, 2041444c061aSmrg Time time) 2042444c061aSmrg{ 2043444c061aSmrg QueuedRequestInfo queueInfo; 2044444c061aSmrg Window window = XtWindow(widget); 2045444c061aSmrg Display *dpy = XtDisplay(widget); 2046444c061aSmrg 2047444c061aSmrg LOCK_PROCESS; 2048444c061aSmrg if (multipleContext == 0) multipleContext = XUniqueContext(); 2049444c061aSmrg 2050444c061aSmrg queueInfo = NULL; 2051444c061aSmrg (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo); 2052444c061aSmrg if (queueInfo != NULL) { 2053444c061aSmrg int count = 0; 2054444c061aSmrg int i; 2055444c061aSmrg QueuedRequest *req = queueInfo->requests; 2056444c061aSmrg 2057444c061aSmrg /* Construct the requests and send it using 2058444c061aSmrg GetSelectionValues */ 2059444c061aSmrg for(i = 0; i < queueInfo->count; i++) 2060444c061aSmrg if (req[i]->selection == selection) count++; 2061444c061aSmrg 2062444c061aSmrg if (count > 0) { 2063444c061aSmrg if (count == 1) { 2064444c061aSmrg for(i = 0; i < queueInfo->count; i++) 2065444c061aSmrg if (req[i]->selection == selection) break; 2066444c061aSmrg 2067444c061aSmrg /* special case a multiple which isn't needed */ 2068444c061aSmrg GetSelectionValue(widget, selection, req[i]->target, 2069444c061aSmrg req[i]->callback, req[i]->closure, time, 2070444c061aSmrg req[i]->incremental, req[i]->param); 2071444c061aSmrg } else { 2072444c061aSmrg Atom *targets; 2073444c061aSmrg Atom t[PREALLOCED]; 2074444c061aSmrg XtSelectionCallbackProc *cbs; 2075444c061aSmrg XtSelectionCallbackProc c[PREALLOCED]; 2076444c061aSmrg XtPointer *closures; 2077444c061aSmrg XtPointer cs[PREALLOCED]; 2078444c061aSmrg Boolean *incrs; 2079444c061aSmrg Boolean ins[PREALLOCED]; 2080444c061aSmrg Atom *props; 2081444c061aSmrg Atom p[PREALLOCED]; 2082444c061aSmrg int i = 0; 2083444c061aSmrg int j = 0; 2084444c061aSmrg 2085444c061aSmrg /* Allocate */ 2086444c061aSmrg targets = (Atom *) XtStackAlloc(count * sizeof(Atom), t); 2087444c061aSmrg cbs = (XtSelectionCallbackProc *) 2088444c061aSmrg XtStackAlloc(count * sizeof(XtSelectionCallbackProc), c); 2089444c061aSmrg closures = (XtPointer *) XtStackAlloc(count * sizeof(XtPointer), cs); 2090444c061aSmrg incrs = (Boolean *) XtStackAlloc(count * sizeof(Boolean), ins); 2091444c061aSmrg props = (Atom *) XtStackAlloc(count * sizeof(Atom), p); 2092444c061aSmrg 2093444c061aSmrg /* Copy */ 2094444c061aSmrg for(i = 0; i < queueInfo->count; i++) { 2095444c061aSmrg if (req[i]->selection == selection) { 2096444c061aSmrg targets[j] = req[i]->target; 2097444c061aSmrg cbs[j] = req[i]->callback; 2098444c061aSmrg closures[j] = req[i]->closure; 2099444c061aSmrg incrs[j] = req[i]->incremental; 2100444c061aSmrg props[j] = req[i]->param; 2101444c061aSmrg j++; 2102444c061aSmrg } 2103444c061aSmrg } 2104444c061aSmrg 2105444c061aSmrg /* Make the request */ 2106444c061aSmrg GetSelectionValues(widget, selection, targets, count, 2107444c061aSmrg cbs, count, closures, time, incrs, props); 2108444c061aSmrg 2109444c061aSmrg /* Free */ 2110444c061aSmrg XtStackFree((XtPointer) targets, t); 2111444c061aSmrg XtStackFree((XtPointer) cbs, c); 2112444c061aSmrg XtStackFree((XtPointer) closures, cs); 2113444c061aSmrg XtStackFree((XtPointer) incrs, ins); 2114444c061aSmrg XtStackFree((XtPointer) props, p); 2115444c061aSmrg } 2116444c061aSmrg } 2117444c061aSmrg } 2118444c061aSmrg 2119444c061aSmrg CleanupRequest(dpy, queueInfo, selection); 2120444c061aSmrg UNLOCK_PROCESS; 2121444c061aSmrg} 2122444c061aSmrg 21232265a131Smrgvoid XtCancelSelectionRequest( 2124444c061aSmrg Widget widget, 2125444c061aSmrg Atom selection) 2126444c061aSmrg{ 2127444c061aSmrg QueuedRequestInfo queueInfo; 2128444c061aSmrg Window window = XtWindow(widget); 2129444c061aSmrg Display *dpy = XtDisplay(widget); 2130444c061aSmrg 2131444c061aSmrg LOCK_PROCESS; 2132444c061aSmrg if (multipleContext == 0) multipleContext = XUniqueContext(); 2133444c061aSmrg 2134444c061aSmrg queueInfo = NULL; 2135444c061aSmrg (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo); 2136444c061aSmrg /* If there is one, then cancel it */ 21372265a131Smrg if (queueInfo != NULL) 2138444c061aSmrg CleanupRequest(dpy, queueInfo, selection); 2139444c061aSmrg UNLOCK_PROCESS; 2140444c061aSmrg} 2141444c061aSmrg 2142444c061aSmrg/* Parameter utilities */ 2143444c061aSmrg 2144444c061aSmrg/* Parameters on a selection request */ 2145444c061aSmrg/* Places data on allocated parameter atom, then records the 2146444c061aSmrg parameter atom data for use in the next call to one of 2147444c061aSmrg the XtGetSelectionValue functions. */ 2148444c061aSmrgvoid XtSetSelectionParameters( 2149444c061aSmrg Widget requestor, 2150444c061aSmrg Atom selection, 2151444c061aSmrg Atom type, 2152444c061aSmrg XtPointer value, 2153444c061aSmrg unsigned long length, 2154444c061aSmrg int format) 2155444c061aSmrg{ 2156444c061aSmrg Display *dpy = XtDisplay(requestor); 2157444c061aSmrg Window window = XtWindow(requestor); 2158444c061aSmrg Atom property = GetParamInfo(requestor, selection); 2159444c061aSmrg 2160444c061aSmrg if (property == None) { 2161444c061aSmrg property = GetSelectionProperty(dpy); 2162444c061aSmrg AddParamInfo(requestor, selection, property); 2163444c061aSmrg } 2164444c061aSmrg 2165444c061aSmrg XChangeProperty(dpy, window, property, 2166444c061aSmrg type, format, PropModeReplace, 2167444c061aSmrg (unsigned char *) value, length); 2168444c061aSmrg} 2169444c061aSmrg 2170444c061aSmrg/* Retrieves data passed in a parameter. Data for this is stored 2171444c061aSmrg on the originator's window */ 2172444c061aSmrgvoid XtGetSelectionParameters( 2173444c061aSmrg Widget owner, 2174444c061aSmrg Atom selection, 2175444c061aSmrg XtRequestId request_id, 2176444c061aSmrg Atom* type_return, 2177444c061aSmrg XtPointer* value_return, 2178444c061aSmrg unsigned long* length_return, 2179444c061aSmrg int* format_return) 2180444c061aSmrg{ 2181444c061aSmrg Request req; 2182444c061aSmrg Display *dpy = XtDisplay(owner); 2183444c061aSmrg WIDGET_TO_APPCON(owner); 2184444c061aSmrg 2185444c061aSmrg *value_return = NULL; 2186444c061aSmrg *length_return = *format_return = 0; 2187444c061aSmrg *type_return = None; 2188444c061aSmrg 2189444c061aSmrg LOCK_APP(app); 2190444c061aSmrg 2191444c061aSmrg req = GetRequestRecord(owner, selection, request_id); 2192444c061aSmrg 2193444c061aSmrg if (req && req->property) { 2194444c061aSmrg unsigned long bytes_after; /* unused */ 2195444c061aSmrg StartProtectedSection(dpy, req->requestor); 2196444c061aSmrg XGetWindowProperty(dpy, req->requestor, req->property, 0L, 10000000, 2197444c061aSmrg False, AnyPropertyType, type_return, format_return, 2198444c061aSmrg length_return, &bytes_after, 2199444c061aSmrg (unsigned char**) value_return); 2200444c061aSmrg EndProtectedSection(dpy); 2201444c061aSmrg#ifdef XT_COPY_SELECTION 2202444c061aSmrg if (*value_return) { 2203444c061aSmrg int size = BYTELENGTH(*length_return, *format_return) + 1; 2204444c061aSmrg char *tmp = __XtMalloc((Cardinal) size); 2205444c061aSmrg (void) memmove(tmp, *value_return, size); 2206444c061aSmrg XFree(*value_return); 2207444c061aSmrg *value_return = tmp; 2208444c061aSmrg } 2209444c061aSmrg#endif 2210444c061aSmrg } 2211444c061aSmrg UNLOCK_APP(app); 2212444c061aSmrg} 2213444c061aSmrg 2214444c061aSmrg/* Parameters are temporarily stashed in an XContext. A list is used because 2215444c061aSmrg * there may be more than one selection request in progress. The context 2216444c061aSmrg * data is deleted when the list is empty. In the future, the parameter 2217444c061aSmrg * context could be merged with other contexts used during selections. 2218444c061aSmrg */ 2219444c061aSmrg 2220444c061aSmrgstatic void AddParamInfo( 2221444c061aSmrg Widget w, 2222444c061aSmrg Atom selection, 2223444c061aSmrg Atom param_atom) 2224444c061aSmrg{ 2225444c061aSmrg int n; 2226444c061aSmrg Param p; 2227444c061aSmrg ParamInfo pinfo; 2228444c061aSmrg 2229444c061aSmrg LOCK_PROCESS; 2230444c061aSmrg if (paramPropertyContext == 0) 2231444c061aSmrg paramPropertyContext = XUniqueContext(); 2232444c061aSmrg 2233444c061aSmrg if (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2234444c061aSmrg (XPointer *) &pinfo)) { 2235444c061aSmrg pinfo = (ParamInfo) __XtMalloc(sizeof(ParamInfoRec)); 2236444c061aSmrg pinfo->count = 1; 2237444c061aSmrg pinfo->paramlist = XtNew(ParamRec); 2238444c061aSmrg p = pinfo->paramlist; 2239444c061aSmrg (void) XSaveContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2240444c061aSmrg (char *)pinfo); 2241444c061aSmrg } 2242444c061aSmrg else { 2243444c061aSmrg for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) { 2244444c061aSmrg if (p->selection == None || p->selection == selection) 2245444c061aSmrg break; 2246444c061aSmrg } 2247444c061aSmrg if (n == 0) { 2248444c061aSmrg pinfo->count++; 2249444c061aSmrg pinfo->paramlist = (Param) 2250444c061aSmrg XtRealloc((char*) pinfo->paramlist, 2251444c061aSmrg pinfo->count * sizeof(ParamRec)); 2252444c061aSmrg p = &pinfo->paramlist[pinfo->count - 1]; 2253444c061aSmrg (void) XSaveContext(XtDisplay(w), XtWindow(w), 2254444c061aSmrg paramPropertyContext, (char *)pinfo); 2255444c061aSmrg } 2256444c061aSmrg } 2257444c061aSmrg p->selection = selection; 2258444c061aSmrg p->param = param_atom; 2259444c061aSmrg UNLOCK_PROCESS; 2260444c061aSmrg} 2261444c061aSmrg 2262444c061aSmrgstatic void RemoveParamInfo( 2263444c061aSmrg Widget w, 2264444c061aSmrg Atom selection) 2265444c061aSmrg{ 2266444c061aSmrg int n; 2267444c061aSmrg Param p; 2268444c061aSmrg ParamInfo pinfo; 2269444c061aSmrg Boolean retain = False; 2270444c061aSmrg 2271444c061aSmrg LOCK_PROCESS; 2272444c061aSmrg if (paramPropertyContext 2273444c061aSmrg && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2274444c061aSmrg (XPointer *) &pinfo) == 0)) { 2275444c061aSmrg 2276444c061aSmrg /* Find and invalidate the parameter data. */ 2277444c061aSmrg for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) { 2278444c061aSmrg if (p->selection != None) { 2279444c061aSmrg if (p->selection == selection) 2280444c061aSmrg p->selection = None; 2281444c061aSmrg else 2282444c061aSmrg retain = True; 2283444c061aSmrg } 2284444c061aSmrg } 2285444c061aSmrg /* If there's no valid data remaining, release the context entry. */ 2286444c061aSmrg if (! retain) { 2287444c061aSmrg XtFree((char*) pinfo->paramlist); 2288444c061aSmrg XtFree((char*) pinfo); 2289444c061aSmrg XDeleteContext(XtDisplay(w), XtWindow(w), paramPropertyContext); 2290444c061aSmrg } 2291444c061aSmrg } 2292444c061aSmrg UNLOCK_PROCESS; 2293444c061aSmrg} 2294444c061aSmrg 2295444c061aSmrgstatic Atom GetParamInfo( 2296444c061aSmrg Widget w, 2297444c061aSmrg Atom selection) 2298444c061aSmrg{ 2299444c061aSmrg int n; 2300444c061aSmrg Param p; 2301444c061aSmrg ParamInfo pinfo; 2302444c061aSmrg Atom atom = None; 2303444c061aSmrg 2304444c061aSmrg LOCK_PROCESS; 2305444c061aSmrg if (paramPropertyContext 2306444c061aSmrg && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2307444c061aSmrg (XPointer *) &pinfo) == 0)) { 2308444c061aSmrg 2309444c061aSmrg for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) 2310444c061aSmrg if (p->selection == selection) { 2311444c061aSmrg atom = p->param; 2312444c061aSmrg break; 2313444c061aSmrg } 2314444c061aSmrg } 2315444c061aSmrg UNLOCK_PROCESS; 2316444c061aSmrg return atom; 2317444c061aSmrg} 2318