Selection.c revision 35525df4
1444c061aSmrg/*********************************************************** 2fdf6a26fSmrgCopyright (c) 1993, Oracle and/or its affiliates. 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 80a3bd7f05Smrgvoid 81a3bd7f05Smrg_XtSetDefaultSelectionTimeout(unsigned long *timeout) 82444c061aSmrg{ 83a3bd7f05Smrg *timeout = 5000; /* default to 5 seconds */ 84444c061aSmrg} 85444c061aSmrg 86a3bd7f05Smrgvoid 87a3bd7f05SmrgXtSetSelectionTimeout(unsigned long timeout) 88444c061aSmrg{ 89a3bd7f05Smrg XtAppSetSelectionTimeout(_XtDefaultAppContext(), timeout); 90444c061aSmrg} 91444c061aSmrg 92a3bd7f05Smrgvoid 93a3bd7f05SmrgXtAppSetSelectionTimeout(XtAppContext app, unsigned long timeout) 94444c061aSmrg{ 95a3bd7f05Smrg LOCK_APP(app); 96a3bd7f05Smrg app->selectionTimeout = timeout; 97a3bd7f05Smrg UNLOCK_APP(app); 98444c061aSmrg} 99444c061aSmrg 100a3bd7f05Smrgunsigned long 101a3bd7f05SmrgXtGetSelectionTimeout(void) 102444c061aSmrg{ 103a3bd7f05Smrg return XtAppGetSelectionTimeout(_XtDefaultAppContext()); 104444c061aSmrg} 105444c061aSmrg 106a3bd7f05Smrgunsigned long 107a3bd7f05SmrgXtAppGetSelectionTimeout(XtAppContext app) 108444c061aSmrg{ 109a3bd7f05Smrg unsigned long retval; 110444c061aSmrg 111a3bd7f05Smrg LOCK_APP(app); 112a3bd7f05Smrg retval = app->selectionTimeout; 113a3bd7f05Smrg UNLOCK_APP(app); 114a3bd7f05Smrg return retval; 115444c061aSmrg} 116444c061aSmrg 117444c061aSmrg/* General utilities */ 118444c061aSmrg 119444c061aSmrgstatic void HandleSelectionReplies(Widget, XtPointer, XEvent *, Boolean *); 120444c061aSmrgstatic void ReqTimedOut(XtPointer, XtIntervalId *); 121444c061aSmrgstatic void HandlePropertyGone(Widget, XtPointer, XEvent *, Boolean *); 122444c061aSmrgstatic void HandleGetIncrement(Widget, XtPointer, XEvent *, Boolean *); 123a3bd7f05Smrgstatic void HandleIncremental(Display *, Widget, Atom, CallBackInfo, 124a3bd7f05Smrg unsigned long); 125444c061aSmrg 126444c061aSmrgstatic XContext selectPropertyContext = 0; 127444c061aSmrgstatic XContext paramPropertyContext = 0; 128444c061aSmrgstatic XContext multipleContext = 0; 129444c061aSmrg 130444c061aSmrg/* Multiple utilities */ 131a3bd7f05Smrgstatic void AddSelectionRequests(Widget, Atom, int, Atom *, 132a3bd7f05Smrg XtSelectionCallbackProc *, int, XtPointer *, 133a3bd7f05Smrg Boolean *, Atom *); 134444c061aSmrgstatic Boolean IsGatheringRequest(Widget, Atom); 135444c061aSmrg 136444c061aSmrg#define PREALLOCED 32 137444c061aSmrg 138444c061aSmrg/* Parameter utilities */ 139444c061aSmrgstatic void AddParamInfo(Widget, Atom, Atom); 140444c061aSmrgstatic void RemoveParamInfo(Widget, Atom); 141444c061aSmrgstatic Atom GetParamInfo(Widget, Atom); 142444c061aSmrg 143a3bd7f05Smrgstatic int StorageSize[3] = { 1, sizeof(short), sizeof(long) }; 144a3bd7f05Smrg 1450568f49bSmrg#define BYTELENGTH(length, format) ((length) * (size_t)StorageSize[(format)>>4]) 146444c061aSmrg#define NUMELEM(bytelength, format) ((bytelength) / StorageSize[(format)>>4]) 1470568f49bSmrg#define NUMELEM2(bytelength, format) ((unsigned long)(bytelength) / (unsigned long) StorageSize[(format)>>4]) 148444c061aSmrg 149444c061aSmrg/* Xlib and Xt are permitted to have different memory allocators, and in the 150444c061aSmrg * XtSelectionCallbackProc the client is instructed to free the selection 151444c061aSmrg * value with XtFree, so the selection value received from XGetWindowProperty 152444c061aSmrg * should be copied to memory allocated through Xt. But copying is 153444c061aSmrg * undesirable since the selection value may be large, and, under normal 154444c061aSmrg * library configuration copying is unnecessary. 155444c061aSmrg */ 156444c061aSmrg#ifdef XTTRACEMEMORY 157a3bd7f05Smrg#define XT_COPY_SELECTION 1 158444c061aSmrg#endif 159444c061aSmrg 160a3bd7f05Smrgstatic void 161a3bd7f05SmrgFreePropList(Widget w _X_UNUSED, 162a3bd7f05Smrg XtPointer closure, 163a3bd7f05Smrg XtPointer callData _X_UNUSED) 164444c061aSmrg{ 165a3bd7f05Smrg PropList sarray = (PropList) closure; 166a3bd7f05Smrg 167444c061aSmrg LOCK_PROCESS; 168444c061aSmrg XDeleteContext(sarray->dpy, DefaultRootWindow(sarray->dpy), 169a3bd7f05Smrg selectPropertyContext); 170444c061aSmrg UNLOCK_PROCESS; 171a3bd7f05Smrg XtFree((char *) sarray->list); 172a3bd7f05Smrg XtFree((char *) closure); 173444c061aSmrg} 174444c061aSmrg 175a3bd7f05Smrgstatic PropList 176a3bd7f05SmrgGetPropList(Display *dpy) 177444c061aSmrg{ 178444c061aSmrg PropList sarray; 179444c061aSmrg 180444c061aSmrg LOCK_PROCESS; 181444c061aSmrg if (selectPropertyContext == 0) 182a3bd7f05Smrg selectPropertyContext = XUniqueContext(); 183444c061aSmrg if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, 184a3bd7f05Smrg (XPointer *) &sarray)) { 185a3bd7f05Smrg Atom atoms[4]; 186a3bd7f05Smrg 187a3bd7f05Smrg static char *names[] = { 188a3bd7f05Smrg "INCR", 189a3bd7f05Smrg "MULTIPLE", 190a3bd7f05Smrg "TIMESTAMP", 191a3bd7f05Smrg "_XT_SELECTION_0" 192a3bd7f05Smrg }; 193a3bd7f05Smrg 194a3bd7f05Smrg XtPerDisplay pd = _XtGetPerDisplay(dpy); 195a3bd7f05Smrg 196a3bd7f05Smrg sarray = (PropList) __XtMalloc((unsigned) sizeof(PropListRec)); 197a3bd7f05Smrg sarray->dpy = dpy; 198a3bd7f05Smrg XInternAtoms(dpy, names, 4, FALSE, atoms); 199a3bd7f05Smrg sarray->incr_atom = atoms[0]; 200a3bd7f05Smrg sarray->indirect_atom = atoms[1]; 201a3bd7f05Smrg sarray->timestamp_atom = atoms[2]; 202a3bd7f05Smrg sarray->propCount = 1; 203a3bd7f05Smrg sarray->list = 204a3bd7f05Smrg (SelectionProp) __XtMalloc((unsigned) sizeof(SelectionPropRec)); 205a3bd7f05Smrg sarray->list[0].prop = atoms[3]; 206a3bd7f05Smrg sarray->list[0].avail = TRUE; 207a3bd7f05Smrg (void) XSaveContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, 208a3bd7f05Smrg (char *) sarray); 209a3bd7f05Smrg _XtAddCallback(&pd->destroy_callbacks, 210a3bd7f05Smrg FreePropList, (XtPointer) sarray); 211444c061aSmrg } 212444c061aSmrg UNLOCK_PROCESS; 213444c061aSmrg return sarray; 214444c061aSmrg} 215444c061aSmrg 216a3bd7f05Smrgstatic Atom 217a3bd7f05SmrgGetSelectionProperty(Display *dpy) 218444c061aSmrg{ 219a3bd7f05Smrg SelectionProp p; 220a3bd7f05Smrg int propCount; 221a3bd7f05Smrg char propname[80]; 222a3bd7f05Smrg PropList sarray = GetPropList(dpy); 223a3bd7f05Smrg 224a3bd7f05Smrg for (p = sarray->list, propCount = sarray->propCount; 225a3bd7f05Smrg propCount; p++, propCount--) { 226a3bd7f05Smrg if (p->avail) { 227a3bd7f05Smrg p->avail = FALSE; 228a3bd7f05Smrg return (p->prop); 229a3bd7f05Smrg } 230a3bd7f05Smrg } 231a3bd7f05Smrg propCount = sarray->propCount++; 232fdf6a26fSmrg sarray->list = XtReallocArray(sarray->list, (Cardinal) sarray->propCount, 233fdf6a26fSmrg (Cardinal) sizeof(SelectionPropRec)); 234a3bd7f05Smrg (void) snprintf(propname, sizeof(propname), "_XT_SELECTION_%d", propCount); 235a3bd7f05Smrg sarray->list[propCount].prop = XInternAtom(dpy, propname, FALSE); 236a3bd7f05Smrg sarray->list[propCount].avail = FALSE; 237a3bd7f05Smrg return (sarray->list[propCount].prop); 238444c061aSmrg} 239444c061aSmrg 240a3bd7f05Smrgstatic void 241a3bd7f05SmrgFreeSelectionProperty(Display *dpy, Atom prop) 242444c061aSmrg{ 243a3bd7f05Smrg SelectionProp p; 244a3bd7f05Smrg int propCount; 245a3bd7f05Smrg PropList sarray; 246a3bd7f05Smrg 247a3bd7f05Smrg if (prop == None) 248a3bd7f05Smrg return; 249a3bd7f05Smrg LOCK_PROCESS; 250a3bd7f05Smrg if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, 251a3bd7f05Smrg (XPointer *) &sarray)) 252a3bd7f05Smrg XtAppErrorMsg(XtDisplayToApplicationContext(dpy), 253a3bd7f05Smrg "noSelectionProperties", "freeSelectionProperty", 254a3bd7f05Smrg XtCXtToolkitError, 255a3bd7f05Smrg "internal error: no selection property context for display", 256a3bd7f05Smrg NULL, NULL); 257a3bd7f05Smrg UNLOCK_PROCESS; 258a3bd7f05Smrg for (p = sarray->list, propCount = sarray->propCount; 259a3bd7f05Smrg propCount; p++, propCount--) 260a3bd7f05Smrg if (p->prop == prop) { 261a3bd7f05Smrg p->avail = TRUE; 262a3bd7f05Smrg return; 263a3bd7f05Smrg } 264444c061aSmrg} 265444c061aSmrg 266a3bd7f05Smrgstatic void 267a3bd7f05SmrgFreeInfo(CallBackInfo info) 268444c061aSmrg{ 269a3bd7f05Smrg XtFree((char *) info->incremental); 270a3bd7f05Smrg XtFree((char *) info->callbacks); 271a3bd7f05Smrg XtFree((char *) info->req_closure); 272a3bd7f05Smrg XtFree((char *) info->target); 273a3bd7f05Smrg XtFree((char *) info); 274444c061aSmrg} 275444c061aSmrg 276a3bd7f05Smrgstatic CallBackInfo 277a3bd7f05SmrgMakeInfo(Select ctx, 278a3bd7f05Smrg XtSelectionCallbackProc *callbacks, 279a3bd7f05Smrg XtPointer *closures, 280a3bd7f05Smrg int count, 281a3bd7f05Smrg Widget widget, 282a3bd7f05Smrg Time time, 283a3bd7f05Smrg Boolean *incremental, 284a3bd7f05Smrg Atom *properties) 285444c061aSmrg{ 286a3bd7f05Smrg CallBackInfo info = XtNew(CallBackInfoRec); 287a3bd7f05Smrg 288a3bd7f05Smrg info->ctx = ctx; 289fdf6a26fSmrg info->callbacks = XtMallocArray((Cardinal) count, 290fdf6a26fSmrg (Cardinal) sizeof(XtSelectionCallbackProc)); 291fdf6a26fSmrg (void) memcpy(info->callbacks, callbacks, 292fdf6a26fSmrg (size_t) count * sizeof(XtSelectionCallbackProc)); 293fdf6a26fSmrg info->req_closure = XtMallocArray((Cardinal) count, 294fdf6a26fSmrg (Cardinal) sizeof(XtPointer)); 295fdf6a26fSmrg (void) memcpy(info->req_closure, closures, 296fdf6a26fSmrg (size_t) count * sizeof(XtPointer)); 297a3bd7f05Smrg if (count == 1 && properties != NULL && properties[0] != None) 298a3bd7f05Smrg info->property = properties[0]; 299a3bd7f05Smrg else { 300a3bd7f05Smrg info->property = GetSelectionProperty(XtDisplay(widget)); 301a3bd7f05Smrg XDeleteProperty(XtDisplay(widget), XtWindow(widget), info->property); 302a3bd7f05Smrg } 303a3bd7f05Smrg info->proc = HandleSelectionReplies; 304a3bd7f05Smrg info->widget = widget; 305a3bd7f05Smrg info->time = time; 306fdf6a26fSmrg info->incremental = XtMallocArray((Cardinal) count, 307fdf6a26fSmrg (Cardinal) sizeof(Boolean)); 308fdf6a26fSmrg (void) memcpy(info->incremental, incremental, 309fdf6a26fSmrg (size_t) count * sizeof(Boolean)); 310a3bd7f05Smrg info->current = 0; 311a3bd7f05Smrg info->value = NULL; 312a3bd7f05Smrg return (info); 313444c061aSmrg} 314444c061aSmrg 315a3bd7f05Smrgstatic void 316a3bd7f05SmrgRequestSelectionValue(CallBackInfo info, Atom selection, Atom target) 317444c061aSmrg{ 318444c061aSmrg#ifndef DEBUG_WO_TIMERS 319444c061aSmrg XtAppContext app = XtWidgetToApplicationContext(info->widget); 320a3bd7f05Smrg 321a3bd7f05Smrg info->timeout = XtAppAddTimeOut(app, 322a3bd7f05Smrg app->selectionTimeout, ReqTimedOut, 323a3bd7f05Smrg (XtPointer) info); 324444c061aSmrg#endif 325a3bd7f05Smrg XtAddEventHandler(info->widget, (EventMask) 0, TRUE, 326a3bd7f05Smrg HandleSelectionReplies, (XtPointer) info); 327a3bd7f05Smrg XConvertSelection(info->ctx->dpy, selection, target, 328a3bd7f05Smrg info->property, XtWindow(info->widget), info->time); 329444c061aSmrg} 330444c061aSmrg 331444c061aSmrgstatic XContext selectContext = 0; 332444c061aSmrg 333a3bd7f05Smrgstatic Select 334a3bd7f05SmrgNewContext(Display *dpy, Atom selection) 335444c061aSmrg{ 336444c061aSmrg /* assert(selectContext != 0) */ 337444c061aSmrg Select ctx = XtNew(SelectRec); 338a3bd7f05Smrg 339444c061aSmrg ctx->dpy = dpy; 340444c061aSmrg ctx->selection = selection; 341444c061aSmrg ctx->widget = NULL; 342444c061aSmrg ctx->prop_list = GetPropList(dpy); 343444c061aSmrg ctx->ref_count = 0; 344444c061aSmrg ctx->free_when_done = FALSE; 345444c061aSmrg ctx->was_disowned = FALSE; 346444c061aSmrg LOCK_PROCESS; 347a3bd7f05Smrg (void) XSaveContext(dpy, (Window) selection, selectContext, (char *) ctx); 348444c061aSmrg UNLOCK_PROCESS; 349444c061aSmrg return ctx; 350444c061aSmrg} 351444c061aSmrg 352a3bd7f05Smrgstatic Select 353a3bd7f05SmrgFindCtx(Display *dpy, Atom selection) 354444c061aSmrg{ 355444c061aSmrg Select ctx; 356444c061aSmrg 357444c061aSmrg LOCK_PROCESS; 358444c061aSmrg if (selectContext == 0) 359a3bd7f05Smrg selectContext = XUniqueContext(); 360a3bd7f05Smrg if (XFindContext(dpy, (Window) selection, selectContext, (XPointer *) &ctx)) 361a3bd7f05Smrg ctx = NewContext(dpy, selection); 362444c061aSmrg UNLOCK_PROCESS; 363444c061aSmrg return ctx; 364444c061aSmrg} 365444c061aSmrg 366a3bd7f05Smrgstatic void 367a3bd7f05SmrgWidgetDestroyed(Widget widget, XtPointer closure, XtPointer data _X_UNUSED) 368444c061aSmrg{ 369444c061aSmrg Select ctx = (Select) closure; 370a3bd7f05Smrg 371444c061aSmrg if (ctx->widget == widget) { 372a3bd7f05Smrg if (ctx->free_when_done) 373a3bd7f05Smrg XtFree((char *) ctx); 374a3bd7f05Smrg else 375a3bd7f05Smrg ctx->widget = NULL; 376444c061aSmrg } 377444c061aSmrg} 378444c061aSmrg 379444c061aSmrg/* Selection Owner code */ 380444c061aSmrg 381444c061aSmrgstatic void HandleSelectionEvents(Widget, XtPointer, XEvent *, Boolean *); 382444c061aSmrg 383a3bd7f05Smrgstatic Boolean 384a3bd7f05SmrgLoseSelection(Select ctx, Widget widget, Atom selection, Time time) 385444c061aSmrg{ 386a3bd7f05Smrg if ((ctx->widget == widget) && (ctx->selection == selection) && /* paranoia */ 387a3bd7f05Smrg !ctx->was_disowned && ((time == CurrentTime) || (time >= ctx->time))) { 388a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) 0, TRUE, 389a3bd7f05Smrg HandleSelectionEvents, (XtPointer) ctx); 390a3bd7f05Smrg XtRemoveCallback(widget, XtNdestroyCallback, 391a3bd7f05Smrg WidgetDestroyed, (XtPointer) ctx); 392a3bd7f05Smrg ctx->was_disowned = TRUE; /* widget officially loses ownership */ 393a3bd7f05Smrg /* now inform widget */ 394a3bd7f05Smrg if (ctx->loses) { 395a3bd7f05Smrg if (ctx->incremental) 396a3bd7f05Smrg (*(XtLoseSelectionIncrProc) ctx->loses) 397a3bd7f05Smrg (widget, &ctx->selection, ctx->owner_closure); 398a3bd7f05Smrg else 399a3bd7f05Smrg (*ctx->loses) (widget, &ctx->selection); 400a3bd7f05Smrg } 401a3bd7f05Smrg return (TRUE); 402a3bd7f05Smrg } 403a3bd7f05Smrg else 404a3bd7f05Smrg return (FALSE); 405444c061aSmrg} 406444c061aSmrg 407444c061aSmrgstatic XContext selectWindowContext = 0; 408444c061aSmrg 409444c061aSmrg/* %%% Xlib.h should make this public! */ 410a3bd7f05Smrgtypedef int (*xErrorHandler) (Display *, XErrorEvent *); 411444c061aSmrg 412444c061aSmrgstatic xErrorHandler oldErrorHandler = NULL; 413444c061aSmrgstatic unsigned long firstProtectRequest; 414444c061aSmrgstatic Window errorWindow; 415444c061aSmrg 416a3bd7f05Smrgstatic int 417a3bd7f05SmrgLocalErrorHandler(Display *dpy, XErrorEvent *error) 418444c061aSmrg{ 419444c061aSmrg int retval; 420444c061aSmrg 421444c061aSmrg /* If BadWindow error on selection requestor, nothing to do but let 422444c061aSmrg * the transfer timeout. Otherwise, invoke saved error handler. */ 423444c061aSmrg 424444c061aSmrg LOCK_PROCESS; 425444c061aSmrg 426444c061aSmrg if (error->error_code == BadWindow && error->resourceid == errorWindow && 427a3bd7f05Smrg error->serial >= firstProtectRequest) { 428a3bd7f05Smrg UNLOCK_PROCESS; 429a3bd7f05Smrg return 0; 430444c061aSmrg } 431444c061aSmrg 432444c061aSmrg if (oldErrorHandler == NULL) { 433a3bd7f05Smrg UNLOCK_PROCESS; 434a3bd7f05Smrg return 0; /* should never happen */ 435444c061aSmrg } 436444c061aSmrg 437a3bd7f05Smrg retval = (*oldErrorHandler) (dpy, error); 438444c061aSmrg UNLOCK_PROCESS; 439444c061aSmrg return retval; 440444c061aSmrg} 441444c061aSmrg 442a3bd7f05Smrgstatic void 443a3bd7f05SmrgStartProtectedSection(Display *dpy, Window window) 444444c061aSmrg{ 445444c061aSmrg /* protect ourselves against request window being destroyed 446444c061aSmrg * before completion of transfer */ 447444c061aSmrg 448444c061aSmrg LOCK_PROCESS; 449444c061aSmrg oldErrorHandler = XSetErrorHandler(LocalErrorHandler); 450444c061aSmrg firstProtectRequest = NextRequest(dpy); 451444c061aSmrg errorWindow = window; 452444c061aSmrg UNLOCK_PROCESS; 453444c061aSmrg} 454444c061aSmrg 455a3bd7f05Smrgstatic void 456a3bd7f05SmrgEndProtectedSection(Display *dpy) 457444c061aSmrg{ 458444c061aSmrg /* flush any generated errors on requestor and 459444c061aSmrg * restore original error handler */ 460444c061aSmrg 461444c061aSmrg XSync(dpy, False); 462444c061aSmrg 463444c061aSmrg LOCK_PROCESS; 464444c061aSmrg XSetErrorHandler(oldErrorHandler); 465444c061aSmrg oldErrorHandler = NULL; 466444c061aSmrg UNLOCK_PROCESS; 467444c061aSmrg} 468444c061aSmrg 469a3bd7f05Smrgstatic void 470a3bd7f05SmrgAddHandler(Request req, EventMask mask, XtEventHandler proc, XtPointer closure) 471444c061aSmrg{ 472444c061aSmrg Display *dpy = req->ctx->dpy; 473444c061aSmrg Window window = req->requestor; 474444c061aSmrg Widget widget = XtWindowToWidget(dpy, window); 475444c061aSmrg 476a3bd7f05Smrg if (widget != NULL) 477a3bd7f05Smrg req->widget = widget; 478a3bd7f05Smrg else 479a3bd7f05Smrg widget = req->widget; 480444c061aSmrg 481444c061aSmrg if (XtWindow(widget) == window) 482a3bd7f05Smrg XtAddEventHandler(widget, mask, False, proc, closure); 483444c061aSmrg else { 484a3bd7f05Smrg RequestWindowRec *requestWindowRec; 485a3bd7f05Smrg 486a3bd7f05Smrg LOCK_PROCESS; 487a3bd7f05Smrg if (selectWindowContext == 0) 488a3bd7f05Smrg selectWindowContext = XUniqueContext(); 489a3bd7f05Smrg if (XFindContext(dpy, window, selectWindowContext, 490a3bd7f05Smrg (XPointer *) &requestWindowRec)) { 491a3bd7f05Smrg requestWindowRec = XtNew(RequestWindowRec); 492a3bd7f05Smrg requestWindowRec->active_transfer_count = 0; 493a3bd7f05Smrg (void) XSaveContext(dpy, window, selectWindowContext, 494a3bd7f05Smrg (char *) requestWindowRec); 495a3bd7f05Smrg } 496a3bd7f05Smrg UNLOCK_PROCESS; 497a3bd7f05Smrg if (requestWindowRec->active_transfer_count++ == 0) { 498a3bd7f05Smrg XtRegisterDrawable(dpy, window, widget); 499a3bd7f05Smrg XSelectInput(dpy, window, (long) mask); 500a3bd7f05Smrg } 501a3bd7f05Smrg XtAddRawEventHandler(widget, mask, FALSE, proc, closure); 502444c061aSmrg } 503444c061aSmrg} 504444c061aSmrg 505a3bd7f05Smrgstatic void 506a3bd7f05SmrgRemoveHandler(Request req, 507a3bd7f05Smrg EventMask mask, 508a3bd7f05Smrg XtEventHandler proc, 509a3bd7f05Smrg XtPointer closure) 510444c061aSmrg{ 511444c061aSmrg Display *dpy = req->ctx->dpy; 512444c061aSmrg Window window = req->requestor; 513444c061aSmrg Widget widget = req->widget; 514444c061aSmrg 515444c061aSmrg if ((XtWindowToWidget(dpy, window) == widget) && 516444c061aSmrg (XtWindow(widget) != window)) { 517a3bd7f05Smrg /* we had to hang this window onto our widget; take it off */ 518a3bd7f05Smrg RequestWindowRec *requestWindowRec; 519a3bd7f05Smrg 520a3bd7f05Smrg XtRemoveRawEventHandler(widget, mask, TRUE, proc, closure); 521a3bd7f05Smrg LOCK_PROCESS; 522a3bd7f05Smrg (void) XFindContext(dpy, window, selectWindowContext, 523a3bd7f05Smrg (XPointer *) &requestWindowRec); 524a3bd7f05Smrg UNLOCK_PROCESS; 525a3bd7f05Smrg if (--requestWindowRec->active_transfer_count == 0) { 526a3bd7f05Smrg XtUnregisterDrawable(dpy, window); 527a3bd7f05Smrg StartProtectedSection(dpy, window); 528a3bd7f05Smrg XSelectInput(dpy, window, 0L); 529a3bd7f05Smrg EndProtectedSection(dpy); 530a3bd7f05Smrg LOCK_PROCESS; 531a3bd7f05Smrg (void) XDeleteContext(dpy, window, selectWindowContext); 532a3bd7f05Smrg UNLOCK_PROCESS; 533a3bd7f05Smrg XtFree((char *) requestWindowRec); 534a3bd7f05Smrg } 535a3bd7f05Smrg } 536a3bd7f05Smrg else { 537a3bd7f05Smrg XtRemoveEventHandler(widget, mask, TRUE, proc, closure); 538444c061aSmrg } 539444c061aSmrg} 540444c061aSmrg 541a3bd7f05Smrgstatic void 542a3bd7f05SmrgOwnerTimedOut(XtPointer closure, XtIntervalId *id _X_UNUSED) 543444c061aSmrg{ 544a3bd7f05Smrg Request req = (Request) closure; 545444c061aSmrg Select ctx = req->ctx; 546444c061aSmrg 547444c061aSmrg if (ctx->incremental && (ctx->owner_cancel != NULL)) { 548a3bd7f05Smrg (*ctx->owner_cancel) (ctx->widget, &ctx->selection, 549a3bd7f05Smrg &req->target, (XtRequestId *) &req, 550a3bd7f05Smrg ctx->owner_closure); 551a3bd7f05Smrg } 552a3bd7f05Smrg else { 553a3bd7f05Smrg if (ctx->notify == NULL) 554a3bd7f05Smrg XtFree((char *) req->value); 555a3bd7f05Smrg else { 556a3bd7f05Smrg /* the requestor hasn't deleted the property, but 557a3bd7f05Smrg * the owner needs to free the value. 558a3bd7f05Smrg */ 559a3bd7f05Smrg if (ctx->incremental) 560a3bd7f05Smrg (*(XtSelectionDoneIncrProc) ctx->notify) 561a3bd7f05Smrg (ctx->widget, &ctx->selection, &req->target, 562a3bd7f05Smrg (XtRequestId *) &req, ctx->owner_closure); 563a3bd7f05Smrg else 564a3bd7f05Smrg (*ctx->notify) (ctx->widget, &ctx->selection, &req->target); 565a3bd7f05Smrg } 566a3bd7f05Smrg } 567a3bd7f05Smrg 568a3bd7f05Smrg RemoveHandler(req, (EventMask) PropertyChangeMask, 569a3bd7f05Smrg HandlePropertyGone, closure); 570a3bd7f05Smrg XtFree((char *) req); 571444c061aSmrg if (--ctx->ref_count == 0 && ctx->free_when_done) 572a3bd7f05Smrg XtFree((char *) ctx); 573444c061aSmrg} 574444c061aSmrg 575a3bd7f05Smrgstatic void 576a3bd7f05SmrgSendIncrement(Request incr) 577444c061aSmrg{ 578444c061aSmrg Display *dpy = incr->ctx->dpy; 579444c061aSmrg 5800568f49bSmrg unsigned long incrSize = (unsigned long) MAX_SELECTION_INCR(dpy); 581a3bd7f05Smrg 582444c061aSmrg if (incrSize > incr->bytelength - incr->offset) 583444c061aSmrg incrSize = incr->bytelength - incr->offset; 584444c061aSmrg StartProtectedSection(dpy, incr->requestor); 585444c061aSmrg XChangeProperty(dpy, incr->requestor, incr->property, 586a3bd7f05Smrg incr->type, incr->format, PropModeReplace, 587a3bd7f05Smrg (unsigned char *) incr->value + incr->offset, 588a3bd7f05Smrg NUMELEM((int) incrSize, incr->format)); 589444c061aSmrg EndProtectedSection(dpy); 590444c061aSmrg incr->offset += incrSize; 591444c061aSmrg} 592444c061aSmrg 593a3bd7f05Smrgstatic void 594a3bd7f05SmrgAllSent(Request req) 595444c061aSmrg{ 596444c061aSmrg Select ctx = req->ctx; 597a3bd7f05Smrg 598444c061aSmrg StartProtectedSection(ctx->dpy, req->requestor); 599444c061aSmrg XChangeProperty(ctx->dpy, req->requestor, 600a3bd7f05Smrg req->property, req->type, req->format, 601a3bd7f05Smrg PropModeReplace, (unsigned char *) NULL, 0); 602444c061aSmrg EndProtectedSection(ctx->dpy); 603444c061aSmrg req->allSent = TRUE; 604444c061aSmrg 605a3bd7f05Smrg if (ctx->notify == NULL) 606a3bd7f05Smrg XtFree((char *) req->value); 607444c061aSmrg} 608444c061aSmrg 609a3bd7f05Smrgstatic void 610a3bd7f05SmrgHandlePropertyGone(Widget widget _X_UNUSED, 611a3bd7f05Smrg XtPointer closure, 612a3bd7f05Smrg XEvent *ev, 613a3bd7f05Smrg Boolean *cont _X_UNUSED) 614444c061aSmrg{ 615444c061aSmrg XPropertyEvent *event = (XPropertyEvent *) ev; 616a3bd7f05Smrg Request req = (Request) closure; 617444c061aSmrg Select ctx = req->ctx; 618444c061aSmrg 619444c061aSmrg if ((event->type != PropertyNotify) || 620444c061aSmrg (event->state != PropertyDelete) || 621a3bd7f05Smrg (event->atom != req->property) || (event->window != req->requestor)) 622a3bd7f05Smrg return; 623444c061aSmrg#ifndef DEBUG_WO_TIMERS 624444c061aSmrg XtRemoveTimeOut(req->timeout); 625444c061aSmrg#endif 626444c061aSmrg if (req->allSent) { 627a3bd7f05Smrg if (ctx->notify) { 628a3bd7f05Smrg if (ctx->incremental) { 629a3bd7f05Smrg (*(XtSelectionDoneIncrProc) ctx->notify) 630a3bd7f05Smrg (ctx->widget, &ctx->selection, &req->target, 631a3bd7f05Smrg (XtRequestId *) &req, ctx->owner_closure); 632a3bd7f05Smrg } 633a3bd7f05Smrg else 634a3bd7f05Smrg (*ctx->notify) (ctx->widget, &ctx->selection, &req->target); 635a3bd7f05Smrg } 636a3bd7f05Smrg RemoveHandler(req, (EventMask) PropertyChangeMask, 637a3bd7f05Smrg HandlePropertyGone, closure); 638a3bd7f05Smrg XtFree((char *) req); 639a3bd7f05Smrg if (--ctx->ref_count == 0 && ctx->free_when_done) 640a3bd7f05Smrg XtFree((char *) ctx); 641a3bd7f05Smrg } 642a3bd7f05Smrg else { /* is this part of an incremental transfer? */ 643a3bd7f05Smrg if (ctx->incremental) { 644a3bd7f05Smrg if (req->bytelength == 0) 645a3bd7f05Smrg AllSent(req); 646a3bd7f05Smrg else { 647a3bd7f05Smrg unsigned long size = 648a3bd7f05Smrg (unsigned long) MAX_SELECTION_INCR(ctx->dpy); 649a3bd7f05Smrg SendIncrement(req); 650a3bd7f05Smrg (*(XtConvertSelectionIncrProc) ctx->convert) 651a3bd7f05Smrg (ctx->widget, &ctx->selection, &req->target, 652a3bd7f05Smrg &req->type, &req->value, 653a3bd7f05Smrg &req->bytelength, &req->format, 654a3bd7f05Smrg &size, ctx->owner_closure, (XtPointer *) &req); 655a3bd7f05Smrg if (req->bytelength) 656a3bd7f05Smrg req->bytelength = BYTELENGTH(req->bytelength, req->format); 657a3bd7f05Smrg req->offset = 0; 658a3bd7f05Smrg } 659a3bd7f05Smrg } 660a3bd7f05Smrg else { 661a3bd7f05Smrg if (req->offset < req->bytelength) 662a3bd7f05Smrg SendIncrement(req); 663a3bd7f05Smrg else 664a3bd7f05Smrg AllSent(req); 665a3bd7f05Smrg } 666444c061aSmrg#ifndef DEBUG_WO_TIMERS 667a3bd7f05Smrg { 668a3bd7f05Smrg XtAppContext app = XtWidgetToApplicationContext(req->widget); 669a3bd7f05Smrg 670a3bd7f05Smrg req->timeout = XtAppAddTimeOut(app, 671a3bd7f05Smrg app->selectionTimeout, OwnerTimedOut, 672a3bd7f05Smrg (XtPointer) req); 673a3bd7f05Smrg } 674444c061aSmrg#endif 675444c061aSmrg } 676444c061aSmrg} 677444c061aSmrg 678a3bd7f05Smrgstatic void 679a3bd7f05SmrgPrepareIncremental(Request req, 680a3bd7f05Smrg Widget widget, 681a3bd7f05Smrg Window window, 682a3bd7f05Smrg Atom property _X_UNUSED, 683a3bd7f05Smrg Atom target, 684a3bd7f05Smrg Atom targetType, 685a3bd7f05Smrg XtPointer value, 686a3bd7f05Smrg unsigned long length, 687a3bd7f05Smrg int format) 688444c061aSmrg{ 689a3bd7f05Smrg req->type = targetType; 690a3bd7f05Smrg req->value = value; 691a3bd7f05Smrg req->bytelength = BYTELENGTH(length, format); 692a3bd7f05Smrg req->format = format; 693a3bd7f05Smrg req->offset = 0; 694a3bd7f05Smrg req->target = target; 695a3bd7f05Smrg req->widget = widget; 696a3bd7f05Smrg req->allSent = FALSE; 697444c061aSmrg#ifndef DEBUG_WO_TIMERS 698a3bd7f05Smrg { 699a3bd7f05Smrg XtAppContext app = XtWidgetToApplicationContext(widget); 700a3bd7f05Smrg 701a3bd7f05Smrg req->timeout = XtAppAddTimeOut(app, 702a3bd7f05Smrg app->selectionTimeout, OwnerTimedOut, 703a3bd7f05Smrg (XtPointer) req); 704a3bd7f05Smrg } 705444c061aSmrg#endif 706a3bd7f05Smrg AddHandler(req, (EventMask) PropertyChangeMask, 707a3bd7f05Smrg HandlePropertyGone, (XtPointer) req); 708444c061aSmrg/* now send client INCR property */ 709a3bd7f05Smrg XChangeProperty(req->ctx->dpy, window, req->property, 710a3bd7f05Smrg req->ctx->prop_list->incr_atom, 711a3bd7f05Smrg 32, PropModeReplace, (unsigned char *) &req->bytelength, 1); 712444c061aSmrg} 713444c061aSmrg 714a3bd7f05Smrgstatic Boolean 715a3bd7f05SmrgGetConversion(Select ctx, /* logical owner */ 716a3bd7f05Smrg XSelectionRequestEvent *event, 717a3bd7f05Smrg Atom target, 718a3bd7f05Smrg Atom property, /* requestor's property */ 719a3bd7f05Smrg Widget widget) /* physical owner (receives events) */ 720a3bd7f05Smrg{ 721444c061aSmrg XtPointer value = NULL; 722444c061aSmrg unsigned long length; 723444c061aSmrg int format; 724444c061aSmrg Atom targetType; 725444c061aSmrg Request req = XtNew(RequestRec); 726444c061aSmrg Boolean timestamp_target = (target == ctx->prop_list->timestamp_atom); 727444c061aSmrg 728444c061aSmrg req->ctx = ctx; 729444c061aSmrg req->event = *event; 730444c061aSmrg req->property = property; 731444c061aSmrg req->requestor = event->requestor; 732444c061aSmrg 733444c061aSmrg if (timestamp_target) { 734a3bd7f05Smrg value = __XtMalloc(sizeof(long)); 735a3bd7f05Smrg *(long *) value = (long) ctx->time; 736a3bd7f05Smrg targetType = XA_INTEGER; 737a3bd7f05Smrg length = 1; 738a3bd7f05Smrg format = 32; 739444c061aSmrg } 740444c061aSmrg else { 741a3bd7f05Smrg ctx->ref_count++; 742a3bd7f05Smrg if (ctx->incremental == TRUE) { 743a3bd7f05Smrg unsigned long size = (unsigned long) MAX_SELECTION_INCR(ctx->dpy); 744a3bd7f05Smrg 745a3bd7f05Smrg if ((*(XtConvertSelectionIncrProc) ctx->convert) 746a3bd7f05Smrg (ctx->widget, &event->selection, &target, 747a3bd7f05Smrg &targetType, &value, &length, &format, 748a3bd7f05Smrg &size, ctx->owner_closure, (XtRequestId *) &req) 749a3bd7f05Smrg == FALSE) { 750a3bd7f05Smrg XtFree((char *) req); 751a3bd7f05Smrg ctx->ref_count--; 752a3bd7f05Smrg return (FALSE); 753a3bd7f05Smrg } 754a3bd7f05Smrg StartProtectedSection(ctx->dpy, event->requestor); 755a3bd7f05Smrg PrepareIncremental(req, widget, event->requestor, property, 756a3bd7f05Smrg target, targetType, value, length, format); 757a3bd7f05Smrg return (TRUE); 758a3bd7f05Smrg } 759a3bd7f05Smrg ctx->req = req; 760a3bd7f05Smrg if ((*ctx->convert) (ctx->widget, &event->selection, &target, 761a3bd7f05Smrg &targetType, &value, &length, &format) == FALSE) { 762a3bd7f05Smrg XtFree((char *) req); 763a3bd7f05Smrg ctx->req = NULL; 764a3bd7f05Smrg ctx->ref_count--; 765a3bd7f05Smrg return (FALSE); 766a3bd7f05Smrg } 767a3bd7f05Smrg ctx->req = NULL; 768444c061aSmrg } 769444c061aSmrg StartProtectedSection(ctx->dpy, event->requestor); 770a3bd7f05Smrg if (BYTELENGTH(length, format) <= 771a3bd7f05Smrg (unsigned long) MAX_SELECTION_INCR(ctx->dpy)) { 772a3bd7f05Smrg if (!timestamp_target) { 773a3bd7f05Smrg if (ctx->notify != NULL) { 774a3bd7f05Smrg req->target = target; 775a3bd7f05Smrg req->widget = widget; 776a3bd7f05Smrg req->allSent = TRUE; 777444c061aSmrg#ifndef DEBUG_WO_TIMERS 778a3bd7f05Smrg { 779a3bd7f05Smrg XtAppContext app = 780a3bd7f05Smrg XtWidgetToApplicationContext(req->widget); 781a3bd7f05Smrg req->timeout = 782a3bd7f05Smrg XtAppAddTimeOut(app, app->selectionTimeout, 783a3bd7f05Smrg OwnerTimedOut, (XtPointer) req); 784a3bd7f05Smrg } 785444c061aSmrg#endif 786a3bd7f05Smrg AddHandler(req, (EventMask) PropertyChangeMask, 787a3bd7f05Smrg HandlePropertyGone, (XtPointer) req); 788a3bd7f05Smrg } 789a3bd7f05Smrg else 790a3bd7f05Smrg ctx->ref_count--; 791444c061aSmrg } 792a3bd7f05Smrg XChangeProperty(ctx->dpy, event->requestor, property, 793a3bd7f05Smrg targetType, format, PropModeReplace, 794a3bd7f05Smrg (unsigned char *) value, (int) length); 795a3bd7f05Smrg /* free storage for client if no notify proc */ 796a3bd7f05Smrg if (timestamp_target || ctx->notify == NULL) { 797a3bd7f05Smrg XtFree((char *) value); 798a3bd7f05Smrg XtFree((char *) req); 799a3bd7f05Smrg } 800a3bd7f05Smrg } 801a3bd7f05Smrg else { 802a3bd7f05Smrg PrepareIncremental(req, widget, event->requestor, property, 803a3bd7f05Smrg target, targetType, value, length, format); 804a3bd7f05Smrg } 805a3bd7f05Smrg return (TRUE); 806444c061aSmrg} 807444c061aSmrg 808a3bd7f05Smrgstatic void 809a3bd7f05SmrgHandleSelectionEvents(Widget widget, 810a3bd7f05Smrg XtPointer closure, 811a3bd7f05Smrg XEvent *event, 812a3bd7f05Smrg Boolean *cont _X_UNUSED) 813444c061aSmrg{ 814444c061aSmrg Select ctx; 815444c061aSmrg XSelectionEvent ev; 816444c061aSmrg Atom target; 817444c061aSmrg 818444c061aSmrg ctx = (Select) closure; 819444c061aSmrg switch (event->type) { 820a3bd7f05Smrg case SelectionClear: 821a3bd7f05Smrg /* if this event is not for the selection we registered for, 822a3bd7f05Smrg * don't do anything */ 823a3bd7f05Smrg if (ctx->selection != event->xselectionclear.selection || 824a3bd7f05Smrg ctx->serial > event->xselectionclear.serial) 825a3bd7f05Smrg break; 826a3bd7f05Smrg (void) LoseSelection(ctx, widget, event->xselectionclear.selection, 827a3bd7f05Smrg event->xselectionclear.time); 828a3bd7f05Smrg break; 829a3bd7f05Smrg case SelectionRequest: 830a3bd7f05Smrg /* if this event is not for the selection we registered for, 831a3bd7f05Smrg * don't do anything */ 832a3bd7f05Smrg if (ctx->selection != event->xselectionrequest.selection) 833a3bd7f05Smrg break; 834a3bd7f05Smrg ev.type = SelectionNotify; 835a3bd7f05Smrg ev.display = event->xselectionrequest.display; 836a3bd7f05Smrg 837a3bd7f05Smrg ev.requestor = event->xselectionrequest.requestor; 838a3bd7f05Smrg ev.selection = event->xselectionrequest.selection; 839a3bd7f05Smrg ev.time = event->xselectionrequest.time; 840a3bd7f05Smrg ev.target = event->xselectionrequest.target; 841a3bd7f05Smrg if (event->xselectionrequest.property == None) /* obsolete requestor */ 842a3bd7f05Smrg event->xselectionrequest.property = event->xselectionrequest.target; 843a3bd7f05Smrg if (ctx->widget != widget || ctx->was_disowned 844a3bd7f05Smrg || ((event->xselectionrequest.time != CurrentTime) 845a3bd7f05Smrg && (event->xselectionrequest.time < ctx->time))) { 846a3bd7f05Smrg ev.property = None; 847a3bd7f05Smrg StartProtectedSection(ev.display, ev.requestor); 848a3bd7f05Smrg } 849a3bd7f05Smrg else { 850a3bd7f05Smrg if (ev.target == ctx->prop_list->indirect_atom) { 851a3bd7f05Smrg IndirectPair *p; 852a3bd7f05Smrg int format; 853a3bd7f05Smrg unsigned long bytesafter, length; 854a3bd7f05Smrg unsigned char *value = NULL; 855a3bd7f05Smrg int count; 856a3bd7f05Smrg Boolean writeback = FALSE; 857a3bd7f05Smrg 858a3bd7f05Smrg ev.property = event->xselectionrequest.property; 859a3bd7f05Smrg StartProtectedSection(ev.display, ev.requestor); 860a3bd7f05Smrg if (XGetWindowProperty(ev.display, ev.requestor, 861a3bd7f05Smrg event->xselectionrequest.property, 0L, 862a3bd7f05Smrg 1000000, False, (Atom) AnyPropertyType, 863a3bd7f05Smrg &target, &format, &length, &bytesafter, 864a3bd7f05Smrg &value) == Success) 865a3bd7f05Smrg count = 866a3bd7f05Smrg (int) (BYTELENGTH(length, format) / 867a3bd7f05Smrg sizeof(IndirectPair)); 868a3bd7f05Smrg else 869a3bd7f05Smrg count = 0; 870a3bd7f05Smrg for (p = (IndirectPair *) value; count; p++, count--) { 871a3bd7f05Smrg EndProtectedSection(ctx->dpy); 872a3bd7f05Smrg if (!GetConversion(ctx, (XSelectionRequestEvent *) event, 873a3bd7f05Smrg p->target, p->property, widget)) { 874a3bd7f05Smrg 875a3bd7f05Smrg p->target = None; 876a3bd7f05Smrg writeback = TRUE; 877a3bd7f05Smrg StartProtectedSection(ctx->dpy, ev.requestor); 878a3bd7f05Smrg } 879a3bd7f05Smrg } 880a3bd7f05Smrg if (writeback) 881a3bd7f05Smrg XChangeProperty(ev.display, ev.requestor, 882a3bd7f05Smrg event->xselectionrequest.property, target, 883a3bd7f05Smrg format, PropModeReplace, value, 884a3bd7f05Smrg (int) length); 885a3bd7f05Smrg XFree((char *) value); 886a3bd7f05Smrg } 887a3bd7f05Smrg else { /* not multiple */ 888a3bd7f05Smrg 889a3bd7f05Smrg if (GetConversion(ctx, (XSelectionRequestEvent *) event, 890a3bd7f05Smrg event->xselectionrequest.target, 891a3bd7f05Smrg event->xselectionrequest.property, widget)) 892a3bd7f05Smrg ev.property = event->xselectionrequest.property; 893a3bd7f05Smrg else { 894a3bd7f05Smrg ev.property = None; 895a3bd7f05Smrg StartProtectedSection(ctx->dpy, ev.requestor); 896a3bd7f05Smrg } 897a3bd7f05Smrg } 898a3bd7f05Smrg } 899a3bd7f05Smrg (void) XSendEvent(ctx->dpy, ev.requestor, False, (unsigned long) NULL, 900a3bd7f05Smrg (XEvent *) &ev); 901a3bd7f05Smrg 902a3bd7f05Smrg EndProtectedSection(ctx->dpy); 903a3bd7f05Smrg 904a3bd7f05Smrg break; 905444c061aSmrg } 906444c061aSmrg} 907444c061aSmrg 908a3bd7f05Smrgstatic Boolean 909a3bd7f05SmrgOwnSelection(Widget widget, 910a3bd7f05Smrg Atom selection, 911a3bd7f05Smrg Time time, 912a3bd7f05Smrg XtConvertSelectionProc convert, 913a3bd7f05Smrg XtLoseSelectionProc lose, 914a3bd7f05Smrg XtSelectionDoneProc notify, 915a3bd7f05Smrg XtCancelConvertSelectionProc cancel, 916a3bd7f05Smrg XtPointer closure, 917a3bd7f05Smrg Boolean incremental) 918444c061aSmrg{ 919444c061aSmrg Select ctx; 920444c061aSmrg Select oldctx = NULL; 921444c061aSmrg 922a3bd7f05Smrg if (!XtIsRealized(widget)) 923a3bd7f05Smrg return False; 924444c061aSmrg 925444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 926444c061aSmrg if (ctx->widget != widget || ctx->time != time || 927a3bd7f05Smrg ctx->ref_count || ctx->was_disowned) { 928a3bd7f05Smrg Boolean replacement = FALSE; 929a3bd7f05Smrg Window window = XtWindow(widget); 930a3bd7f05Smrg unsigned long serial = XNextRequest(ctx->dpy); 931a3bd7f05Smrg 932444c061aSmrg XSetSelectionOwner(ctx->dpy, selection, window, time); 933444c061aSmrg if (XGetSelectionOwner(ctx->dpy, selection) != window) 934a3bd7f05Smrg return FALSE; 935a3bd7f05Smrg if (ctx->ref_count) { /* exchange is in-progress */ 936444c061aSmrg#ifdef DEBUG_ACTIVE 937a3bd7f05Smrg printf 938a3bd7f05Smrg ("Active exchange for widget \"%s\"; selection=0x%lx, ref_count=%d\n", 939a3bd7f05Smrg XtName(widget), (long) selection, ctx->ref_count); 940444c061aSmrg#endif 941a3bd7f05Smrg if (ctx->widget != widget || 942a3bd7f05Smrg ctx->convert != convert || 943a3bd7f05Smrg ctx->loses != lose || 944a3bd7f05Smrg ctx->notify != notify || 945a3bd7f05Smrg ctx->owner_cancel != cancel || 946a3bd7f05Smrg ctx->incremental != incremental || 947a3bd7f05Smrg ctx->owner_closure != closure) { 948a3bd7f05Smrg if (ctx->widget == widget) { 949a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) 0, TRUE, 950a3bd7f05Smrg HandleSelectionEvents, 951a3bd7f05Smrg (XtPointer) ctx); 952a3bd7f05Smrg XtRemoveCallback(widget, XtNdestroyCallback, 953a3bd7f05Smrg WidgetDestroyed, (XtPointer) ctx); 954a3bd7f05Smrg replacement = TRUE; 955a3bd7f05Smrg } 956a3bd7f05Smrg else if (!ctx->was_disowned) { 957a3bd7f05Smrg oldctx = ctx; 958a3bd7f05Smrg } 959a3bd7f05Smrg ctx->free_when_done = TRUE; 960a3bd7f05Smrg ctx = NewContext(XtDisplay(widget), selection); 961a3bd7f05Smrg } 962a3bd7f05Smrg else if (!ctx->was_disowned) { /* current owner is new owner */ 963a3bd7f05Smrg ctx->time = time; 964a3bd7f05Smrg return TRUE; 965a3bd7f05Smrg } 966a3bd7f05Smrg } 967a3bd7f05Smrg if (ctx->widget != widget || ctx->was_disowned || replacement) { 968a3bd7f05Smrg if (ctx->widget && !ctx->was_disowned && !replacement) { 969a3bd7f05Smrg oldctx = ctx; 970a3bd7f05Smrg oldctx->free_when_done = TRUE; 971a3bd7f05Smrg ctx = NewContext(XtDisplay(widget), selection); 972a3bd7f05Smrg } 973a3bd7f05Smrg XtAddEventHandler(widget, (EventMask) 0, TRUE, 974a3bd7f05Smrg HandleSelectionEvents, (XtPointer) ctx); 975a3bd7f05Smrg XtAddCallback(widget, XtNdestroyCallback, 976a3bd7f05Smrg WidgetDestroyed, (XtPointer) ctx); 977a3bd7f05Smrg } 978fdf6a26fSmrg ctx->widget = widget; /* Selection officially changes hands. */ 979a3bd7f05Smrg ctx->time = time; 980a3bd7f05Smrg ctx->serial = serial; 981444c061aSmrg } 982444c061aSmrg ctx->convert = convert; 983444c061aSmrg ctx->loses = lose; 984444c061aSmrg ctx->notify = notify; 985444c061aSmrg ctx->owner_cancel = cancel; 9860568f49bSmrg XtSetBit(ctx->incremental, incremental); 987444c061aSmrg ctx->owner_closure = closure; 988444c061aSmrg ctx->was_disowned = FALSE; 989444c061aSmrg 990444c061aSmrg /* Defer calling the previous selection owner's lose selection procedure 991444c061aSmrg * until the new selection is established, to allow the previous 992444c061aSmrg * selection owner to ask for the new selection to be converted in 993444c061aSmrg * the lose selection procedure. The context pointer is the closure 994444c061aSmrg * of the event handler and the destroy callback, so the old context 995444c061aSmrg * pointer and the record contents must be preserved for LoseSelection. 996444c061aSmrg */ 997444c061aSmrg if (oldctx) { 998a3bd7f05Smrg (void) LoseSelection(oldctx, oldctx->widget, selection, oldctx->time); 999a3bd7f05Smrg if (!oldctx->ref_count && oldctx->free_when_done) 1000a3bd7f05Smrg XtFree((char *) oldctx); 1001444c061aSmrg } 1002444c061aSmrg return TRUE; 1003444c061aSmrg} 1004444c061aSmrg 1005a3bd7f05SmrgBoolean 1006a3bd7f05SmrgXtOwnSelection(Widget widget, 1007a3bd7f05Smrg Atom selection, 1008a3bd7f05Smrg Time time, 1009a3bd7f05Smrg XtConvertSelectionProc convert, 1010a3bd7f05Smrg XtLoseSelectionProc lose, 1011a3bd7f05Smrg XtSelectionDoneProc notify) 1012444c061aSmrg{ 1013444c061aSmrg Boolean retval; 1014a3bd7f05Smrg 1015444c061aSmrg WIDGET_TO_APPCON(widget); 1016444c061aSmrg 1017444c061aSmrg LOCK_APP(app); 1018444c061aSmrg retval = OwnSelection(widget, selection, time, convert, lose, notify, 1019a3bd7f05Smrg (XtCancelConvertSelectionProc) NULL, 1020a3bd7f05Smrg (XtPointer) NULL, FALSE); 1021444c061aSmrg UNLOCK_APP(app); 1022444c061aSmrg return retval; 1023444c061aSmrg} 1024444c061aSmrg 1025a3bd7f05SmrgBoolean 1026a3bd7f05SmrgXtOwnSelectionIncremental(Widget widget, 1027a3bd7f05Smrg Atom selection, 1028a3bd7f05Smrg Time time, 1029a3bd7f05Smrg XtConvertSelectionIncrProc convert, 1030a3bd7f05Smrg XtLoseSelectionIncrProc lose, 1031a3bd7f05Smrg XtSelectionDoneIncrProc notify, 1032a3bd7f05Smrg XtCancelConvertSelectionProc cancel, 1033a3bd7f05Smrg XtPointer closure) 1034444c061aSmrg{ 1035444c061aSmrg Boolean retval; 1036a3bd7f05Smrg 1037444c061aSmrg WIDGET_TO_APPCON(widget); 1038444c061aSmrg 1039444c061aSmrg LOCK_APP(app); 1040444c061aSmrg retval = OwnSelection(widget, selection, time, 1041a3bd7f05Smrg (XtConvertSelectionProc) convert, 1042a3bd7f05Smrg (XtLoseSelectionProc) lose, 1043a3bd7f05Smrg (XtSelectionDoneProc) notify, cancel, closure, TRUE); 1044444c061aSmrg UNLOCK_APP(app); 1045444c061aSmrg return retval; 1046444c061aSmrg} 1047444c061aSmrg 1048a3bd7f05Smrgvoid 1049a3bd7f05SmrgXtDisownSelection(Widget widget, Atom selection, Time time) 1050444c061aSmrg{ 1051444c061aSmrg Select ctx; 1052a3bd7f05Smrg 1053444c061aSmrg WIDGET_TO_APPCON(widget); 1054444c061aSmrg 1055444c061aSmrg LOCK_APP(app); 1056444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 1057444c061aSmrg if (LoseSelection(ctx, widget, selection, time)) 1058a3bd7f05Smrg XSetSelectionOwner(XtDisplay(widget), selection, None, time); 1059444c061aSmrg UNLOCK_APP(app); 1060444c061aSmrg} 1061444c061aSmrg 1062444c061aSmrg/* Selection Requestor code */ 1063444c061aSmrg 1064a3bd7f05Smrgstatic Boolean 1065a3bd7f05SmrgIsINCRtype(CallBackInfo info, Window window, Atom prop) 1066444c061aSmrg{ 1067444c061aSmrg unsigned long bytesafter; 1068444c061aSmrg unsigned long length; 1069444c061aSmrg int format; 1070444c061aSmrg Atom type; 1071444c061aSmrg unsigned char *value; 1072444c061aSmrg 1073a3bd7f05Smrg if (prop == None) 1074a3bd7f05Smrg return False; 1075444c061aSmrg 10769e7bcd65Smrg if (XGetWindowProperty(XtDisplay(info->widget), window, prop, 0L, 0L, 1077a3bd7f05Smrg False, info->ctx->prop_list->incr_atom, &type, 1078a3bd7f05Smrg &format, &length, &bytesafter, &value) != Success) 1079a3bd7f05Smrg return False; 1080444c061aSmrg 1081444c061aSmrg return (type == info->ctx->prop_list->incr_atom); 1082444c061aSmrg} 1083444c061aSmrg 1084a3bd7f05Smrgstatic void 1085a3bd7f05SmrgReqCleanup(Widget widget, 1086a3bd7f05Smrg XtPointer closure, 1087a3bd7f05Smrg XEvent *ev, 1088a3bd7f05Smrg Boolean *cont _X_UNUSED) 1089444c061aSmrg{ 1090a3bd7f05Smrg CallBackInfo info = (CallBackInfo) closure; 1091444c061aSmrg unsigned long bytesafter, length; 1092444c061aSmrg int format; 1093444c061aSmrg Atom target; 1094444c061aSmrg 1095444c061aSmrg if (ev->type == SelectionNotify) { 1096a3bd7f05Smrg XSelectionEvent *event = (XSelectionEvent *) ev; 1097a3bd7f05Smrg 1098a3bd7f05Smrg if (!MATCH_SELECT(event, info)) 1099a3bd7f05Smrg return; /* not really for us */ 1100a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) 0, TRUE, 1101a3bd7f05Smrg ReqCleanup, (XtPointer) info); 1102a3bd7f05Smrg if (IsINCRtype(info, XtWindow(widget), event->property)) { 1103a3bd7f05Smrg info->proc = HandleGetIncrement; 1104a3bd7f05Smrg XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask, 1105a3bd7f05Smrg FALSE, ReqCleanup, (XtPointer) info); 1106a3bd7f05Smrg } 1107a3bd7f05Smrg else { 1108a3bd7f05Smrg if (event->property != None) 1109a3bd7f05Smrg XDeleteProperty(event->display, XtWindow(widget), 1110a3bd7f05Smrg event->property); 1111a3bd7f05Smrg FreeSelectionProperty(XtDisplay(widget), info->property); 1112a3bd7f05Smrg FreeInfo(info); 1113a3bd7f05Smrg } 1114a3bd7f05Smrg } 1115a3bd7f05Smrg else if ((ev->type == PropertyNotify) && 1116a3bd7f05Smrg (ev->xproperty.state == PropertyNewValue) && 1117a3bd7f05Smrg (ev->xproperty.atom == info->property)) { 1118a3bd7f05Smrg XPropertyEvent *event = (XPropertyEvent *) ev; 1119a3bd7f05Smrg char *value = NULL; 1120a3bd7f05Smrg 1121a3bd7f05Smrg if (XGetWindowProperty(event->display, XtWindow(widget), 1122a3bd7f05Smrg event->atom, 0L, 1000000, True, AnyPropertyType, 1123a3bd7f05Smrg &target, &format, &length, &bytesafter, 1124a3bd7f05Smrg (unsigned char **) &value) == Success) { 1125a3bd7f05Smrg XFree(value); 1126a3bd7f05Smrg if (length == 0) { 1127a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, 1128a3bd7f05Smrg FALSE, ReqCleanup, (XtPointer) info); 1129a3bd7f05Smrg FreeSelectionProperty(XtDisplay(widget), info->property); 1130a3bd7f05Smrg XtFree(info->value); /* requestor never got this, so free now */ 1131a3bd7f05Smrg FreeInfo(info); 1132a3bd7f05Smrg } 1133a3bd7f05Smrg } 1134444c061aSmrg } 1135444c061aSmrg} 1136444c061aSmrg 1137a3bd7f05Smrgstatic void 1138a3bd7f05SmrgReqTimedOut(XtPointer closure, XtIntervalId *id _X_UNUSED) 1139444c061aSmrg{ 1140444c061aSmrg XtPointer value = NULL; 1141444c061aSmrg unsigned long length = 0; 1142444c061aSmrg int format = 8; 1143444c061aSmrg Atom resulttype = XT_CONVERT_FAIL; 1144a3bd7f05Smrg CallBackInfo info = (CallBackInfo) closure; 1145444c061aSmrg unsigned long bytesafter; 1146444c061aSmrg unsigned long proplength; 1147444c061aSmrg Atom type; 1148444c061aSmrg 1149444c061aSmrg if (*info->target == info->ctx->prop_list->indirect_atom) { 1150a3bd7f05Smrg IndirectPair *pairs = NULL; 1151a3bd7f05Smrg 1152a3bd7f05Smrg if (XGetWindowProperty(XtDisplay(info->widget), XtWindow(info->widget), 1153a3bd7f05Smrg info->property, 0L, 10000000, True, 1154a3bd7f05Smrg AnyPropertyType, &type, &format, &proplength, 1155a3bd7f05Smrg &bytesafter, (unsigned char **) &pairs) 1156a3bd7f05Smrg == Success) { 1157a3bd7f05Smrg XtPointer *c; 1158a3bd7f05Smrg int i; 1159a3bd7f05Smrg 1160a3bd7f05Smrg XFree(pairs); 1161a3bd7f05Smrg for (proplength = proplength / IndirectPairWordSize, i = 0, 1162a3bd7f05Smrg c = info->req_closure; proplength; proplength--, c++, i++) 1163a3bd7f05Smrg (*info->callbacks[i]) (info->widget, *c, &info->ctx->selection, 1164a3bd7f05Smrg &resulttype, value, &length, &format); 1165a3bd7f05Smrg } 1166a3bd7f05Smrg } 1167a3bd7f05Smrg else { 1168a3bd7f05Smrg (*info->callbacks[0]) (info->widget, *info->req_closure, 1169a3bd7f05Smrg &info->ctx->selection, &resulttype, value, 1170a3bd7f05Smrg &length, &format); 1171444c061aSmrg } 1172444c061aSmrg 1173444c061aSmrg /* change event handlers for straggler events */ 117435525df4Smrg if (info->proc == HandleSelectionReplies) { 1175a3bd7f05Smrg XtRemoveEventHandler(info->widget, (EventMask) 0, 1176a3bd7f05Smrg TRUE, info->proc, (XtPointer) info); 1177a3bd7f05Smrg XtAddEventHandler(info->widget, (EventMask) 0, TRUE, 1178a3bd7f05Smrg ReqCleanup, (XtPointer) info); 1179a3bd7f05Smrg } 1180a3bd7f05Smrg else { 1181a3bd7f05Smrg XtRemoveEventHandler(info->widget, (EventMask) PropertyChangeMask, 1182a3bd7f05Smrg FALSE, info->proc, (XtPointer) info); 1183a3bd7f05Smrg XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask, 1184a3bd7f05Smrg FALSE, ReqCleanup, (XtPointer) info); 1185444c061aSmrg } 1186444c061aSmrg 1187444c061aSmrg} 1188444c061aSmrg 1189a3bd7f05Smrgstatic void 1190a3bd7f05SmrgHandleGetIncrement(Widget widget, 1191a3bd7f05Smrg XtPointer closure, 1192a3bd7f05Smrg XEvent *ev, 1193a3bd7f05Smrg Boolean *cont _X_UNUSED) 1194444c061aSmrg{ 1195444c061aSmrg XPropertyEvent *event = (XPropertyEvent *) ev; 1196444c061aSmrg CallBackInfo info = (CallBackInfo) closure; 1197444c061aSmrg Select ctx = info->ctx; 1198444c061aSmrg char *value; 1199444c061aSmrg unsigned long bytesafter; 1200444c061aSmrg unsigned long length; 1201444c061aSmrg int bad; 1202444c061aSmrg int n = info->current; 1203444c061aSmrg 1204444c061aSmrg if ((event->state != PropertyNewValue) || (event->atom != info->property)) 1205a3bd7f05Smrg return; 1206444c061aSmrg 1207444c061aSmrg bad = XGetWindowProperty(event->display, XtWindow(widget), 1208a3bd7f05Smrg event->atom, 0L, 1209a3bd7f05Smrg 10000000, True, AnyPropertyType, &info->type, 1210a3bd7f05Smrg &info->format, &length, &bytesafter, 1211a3bd7f05Smrg (unsigned char **)&value); 1212444c061aSmrg if (bad) 1213a3bd7f05Smrg return; 1214444c061aSmrg#ifndef DEBUG_WO_TIMERS 1215444c061aSmrg XtRemoveTimeOut(info->timeout); 1216444c061aSmrg#endif 1217444c061aSmrg if (length == 0) { 1218a3bd7f05Smrg unsigned long u_offset = NUMELEM2(info->offset, info->format); 1219a3bd7f05Smrg 1220a3bd7f05Smrg (*info->callbacks[n]) (widget, *info->req_closure, &ctx->selection, 1221a3bd7f05Smrg &info->type, 1222a3bd7f05Smrg (info->offset == 0 ? value : info->value), 1223a3bd7f05Smrg &u_offset, &info->format); 1224a3bd7f05Smrg /* assert ((info->offset != 0) == (info->incremental[n]) */ 1225a3bd7f05Smrg if (info->offset != 0) 1226a3bd7f05Smrg XFree(value); 1227a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, 1228a3bd7f05Smrg HandleGetIncrement, (XtPointer) info); 1229a3bd7f05Smrg FreeSelectionProperty(event->display, info->property); 1230a3bd7f05Smrg 1231a3bd7f05Smrg FreeInfo(info); 1232a3bd7f05Smrg } 1233a3bd7f05Smrg else { /* add increment to collection */ 1234a3bd7f05Smrg if (info->incremental[n]) { 1235444c061aSmrg#ifdef XT_COPY_SELECTION 1236a3bd7f05Smrg int size = (int) BYTELENGTH(length, info->format) + 1; 1237a3bd7f05Smrg char *tmp = __XtMalloc((Cardinal) size); 1238a3bd7f05Smrg 1239fdf6a26fSmrg (void) memcpy(tmp, value, (size_t) size); 1240a3bd7f05Smrg XFree(value); 1241a3bd7f05Smrg value = tmp; 1242444c061aSmrg#endif 1243a3bd7f05Smrg (*info->callbacks[n]) (widget, *info->req_closure, &ctx->selection, 1244a3bd7f05Smrg &info->type, value, &length, &info->format); 1245a3bd7f05Smrg } 1246a3bd7f05Smrg else { 1247a3bd7f05Smrg int size = (int) BYTELENGTH(length, info->format); 1248a3bd7f05Smrg 1249a3bd7f05Smrg if (info->offset + size > info->bytelength) { 1250a3bd7f05Smrg /* allocate enough for this and the next increment */ 1251a3bd7f05Smrg info->bytelength = info->offset + size * 2; 1252a3bd7f05Smrg info->value = XtRealloc(info->value, 1253a3bd7f05Smrg (Cardinal) info->bytelength); 1254a3bd7f05Smrg } 1255fdf6a26fSmrg (void) memcpy(&info->value[info->offset], value, (size_t) size); 1256a3bd7f05Smrg info->offset += size; 1257a3bd7f05Smrg XFree(value); 1258a3bd7f05Smrg } 1259a3bd7f05Smrg /* reset timer */ 1260444c061aSmrg#ifndef DEBUG_WO_TIMERS 1261a3bd7f05Smrg { 1262a3bd7f05Smrg XtAppContext app = XtWidgetToApplicationContext(info->widget); 1263a3bd7f05Smrg 1264a3bd7f05Smrg info->timeout = XtAppAddTimeOut(app, 1265a3bd7f05Smrg app->selectionTimeout, ReqTimedOut, 1266a3bd7f05Smrg (XtPointer) info); 1267a3bd7f05Smrg } 1268444c061aSmrg#endif 1269a3bd7f05Smrg } 1270444c061aSmrg} 1271444c061aSmrg 1272a3bd7f05Smrgstatic void 1273a3bd7f05SmrgHandleNone(Widget widget, 1274a3bd7f05Smrg XtSelectionCallbackProc callback, 1275a3bd7f05Smrg XtPointer closure, 1276a3bd7f05Smrg Atom selection) 1277444c061aSmrg{ 1278444c061aSmrg unsigned long length = 0; 1279444c061aSmrg int format = 8; 1280444c061aSmrg Atom type = None; 1281444c061aSmrg 1282a3bd7f05Smrg (*callback) (widget, closure, &selection, &type, NULL, &length, &format); 1283444c061aSmrg} 1284444c061aSmrg 1285a3bd7f05Smrgstatic unsigned long 1286a3bd7f05SmrgIncrPropSize(Widget widget, 1287a3bd7f05Smrg unsigned char *value, 1288a3bd7f05Smrg int format, 1289a3bd7f05Smrg unsigned long length) 1290444c061aSmrg{ 1291444c061aSmrg if (format == 32) { 1292a3bd7f05Smrg unsigned long size; 1293a3bd7f05Smrg 1294a3bd7f05Smrg size = ((unsigned long *) value)[length - 1]; /* %%% what order for longs? */ 1295a3bd7f05Smrg return size; 1296444c061aSmrg } 1297444c061aSmrg else { 1298a3bd7f05Smrg XtAppWarningMsg(XtWidgetToApplicationContext(widget), 1299a3bd7f05Smrg "badFormat", "xtGetSelectionValue", XtCXtToolkitError, 1300a3bd7f05Smrg "Selection owner returned type INCR property with format != 32", 1301a3bd7f05Smrg NULL, NULL); 1302a3bd7f05Smrg return 0; 1303444c061aSmrg } 1304444c061aSmrg} 1305444c061aSmrg 1306444c061aSmrgstatic 1307a3bd7f05Smrg Boolean 1308a3bd7f05SmrgHandleNormal(Display *dpy, 1309a3bd7f05Smrg Widget widget, 1310a3bd7f05Smrg Atom property, 1311a3bd7f05Smrg CallBackInfo info, 1312a3bd7f05Smrg XtPointer closure, 1313a3bd7f05Smrg Atom selection) 1314444c061aSmrg{ 1315444c061aSmrg unsigned long bytesafter; 1316444c061aSmrg unsigned long length; 1317444c061aSmrg int format; 1318444c061aSmrg Atom type; 13199e7bcd65Smrg unsigned char *value = NULL; 1320444c061aSmrg int number = info->current; 1321444c061aSmrg 13229e7bcd65Smrg if (XGetWindowProperty(dpy, XtWindow(widget), property, 0L, 10000000, 1323a3bd7f05Smrg False, AnyPropertyType, &type, &format, &length, 1324a3bd7f05Smrg &bytesafter, &value) != Success) 1325a3bd7f05Smrg return FALSE; 1326444c061aSmrg 1327444c061aSmrg if (type == info->ctx->prop_list->incr_atom) { 1328a3bd7f05Smrg unsigned long size = IncrPropSize(widget, value, format, length); 1329a3bd7f05Smrg 1330a3bd7f05Smrg XFree((char *) value); 1331a3bd7f05Smrg if (info->property != property) { 1332a3bd7f05Smrg /* within MULTIPLE */ 1333a3bd7f05Smrg CallBackInfo ninfo; 1334a3bd7f05Smrg 1335a3bd7f05Smrg ninfo = MakeInfo(info->ctx, &info->callbacks[number], 1336a3bd7f05Smrg &info->req_closure[number], 1, widget, 1337a3bd7f05Smrg info->time, &info->incremental[number], &property); 1338a3bd7f05Smrg ninfo->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom)); 1339a3bd7f05Smrg *ninfo->target = info->target[number + 1]; 1340a3bd7f05Smrg info = ninfo; 1341a3bd7f05Smrg } 1342a3bd7f05Smrg HandleIncremental(dpy, widget, property, info, size); 1343a3bd7f05Smrg return FALSE; 1344444c061aSmrg } 1345444c061aSmrg 1346444c061aSmrg XDeleteProperty(dpy, XtWindow(widget), property); 1347444c061aSmrg#ifdef XT_COPY_SELECTION 1348a3bd7f05Smrg if (value) { /* it could have been deleted after the SelectionNotify */ 1349a3bd7f05Smrg int size = (int) BYTELENGTH(length, info->format) + 1; 1350a3bd7f05Smrg char *tmp = __XtMalloc((Cardinal) size); 1351a3bd7f05Smrg 1352fdf6a26fSmrg (void) memcpy(tmp, value, (size_t) size); 1353a3bd7f05Smrg XFree(value); 1354a3bd7f05Smrg value = (unsigned char *) tmp; 1355444c061aSmrg } 1356444c061aSmrg#endif 1357a3bd7f05Smrg (*info->callbacks[number]) (widget, closure, &selection, 1358a3bd7f05Smrg &type, (XtPointer) value, &length, &format); 1359444c061aSmrg 1360444c061aSmrg if (info->incremental[number]) { 1361a3bd7f05Smrg /* let requestor know the whole thing has been received */ 1362a3bd7f05Smrg value = (unsigned char *) __XtMalloc((unsigned) 1); 1363a3bd7f05Smrg length = 0; 1364a3bd7f05Smrg (*info->callbacks[number]) (widget, closure, &selection, 1365a3bd7f05Smrg &type, (XtPointer) value, &length, &format); 1366444c061aSmrg } 1367444c061aSmrg return TRUE; 1368444c061aSmrg} 1369444c061aSmrg 1370a3bd7f05Smrgstatic void 1371a3bd7f05SmrgHandleIncremental(Display *dpy, 1372a3bd7f05Smrg Widget widget, 1373a3bd7f05Smrg Atom property, 1374a3bd7f05Smrg CallBackInfo info, 1375a3bd7f05Smrg unsigned long size) 1376444c061aSmrg{ 1377444c061aSmrg XtAddEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, 1378a3bd7f05Smrg HandleGetIncrement, (XtPointer) info); 1379444c061aSmrg 1380444c061aSmrg /* now start the transfer */ 1381444c061aSmrg XDeleteProperty(dpy, XtWindow(widget), property); 1382444c061aSmrg XFlush(dpy); 1383444c061aSmrg 13840568f49bSmrg info->bytelength = (int) size; 1385a3bd7f05Smrg if (info->incremental[info->current]) /* requestor wants incremental too */ 1386a3bd7f05Smrg info->value = NULL; /* so no need for buffer to assemble value */ 1387444c061aSmrg else 1388a3bd7f05Smrg info->value = (char *) __XtMalloc((unsigned) info->bytelength); 1389444c061aSmrg info->offset = 0; 1390444c061aSmrg 1391444c061aSmrg /* reset the timer */ 1392444c061aSmrg info->proc = HandleGetIncrement; 1393444c061aSmrg#ifndef DEBUG_WO_TIMERS 1394444c061aSmrg { 1395a3bd7f05Smrg XtAppContext app = XtWidgetToApplicationContext(info->widget); 1396a3bd7f05Smrg 1397a3bd7f05Smrg info->timeout = XtAppAddTimeOut(app, 1398a3bd7f05Smrg app->selectionTimeout, ReqTimedOut, 1399a3bd7f05Smrg (XtPointer) info); 1400444c061aSmrg } 1401444c061aSmrg#endif 1402444c061aSmrg} 1403444c061aSmrg 1404a3bd7f05Smrgstatic void 1405a3bd7f05SmrgHandleSelectionReplies(Widget widget, 1406a3bd7f05Smrg XtPointer closure, 1407a3bd7f05Smrg XEvent *ev, 1408a3bd7f05Smrg Boolean *cont _X_UNUSED) 1409444c061aSmrg{ 1410444c061aSmrg XSelectionEvent *event = (XSelectionEvent *) ev; 1411444c061aSmrg Display *dpy = event->display; 1412444c061aSmrg CallBackInfo info = (CallBackInfo) closure; 1413444c061aSmrg Select ctx = info->ctx; 1414444c061aSmrg unsigned long bytesafter; 1415444c061aSmrg unsigned long length; 1416444c061aSmrg int format; 1417444c061aSmrg Atom type; 1418444c061aSmrg 1419a3bd7f05Smrg if (event->type != SelectionNotify) 1420a3bd7f05Smrg return; 1421a3bd7f05Smrg if (!MATCH_SELECT(event, info)) 1422a3bd7f05Smrg return; /* not really for us */ 1423444c061aSmrg#ifndef DEBUG_WO_TIMERS 1424444c061aSmrg XtRemoveTimeOut(info->timeout); 1425444c061aSmrg#endif 1426a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) 0, TRUE, 1427a3bd7f05Smrg HandleSelectionReplies, (XtPointer) info); 1428444c061aSmrg if (event->target == ctx->prop_list->indirect_atom) { 1429a3bd7f05Smrg IndirectPair *pairs = NULL, *p; 1430a3bd7f05Smrg XtPointer *c; 1431a3bd7f05Smrg 1432a3bd7f05Smrg if (XGetWindowProperty(dpy, XtWindow(widget), info->property, 0L, 1433a3bd7f05Smrg 10000000, True, AnyPropertyType, &type, &format, 1434a3bd7f05Smrg &length, &bytesafter, (unsigned char **) &pairs) 1435a3bd7f05Smrg != Success) 1436a3bd7f05Smrg length = 0; 1437a3bd7f05Smrg for (length = length / IndirectPairWordSize, p = pairs, 1438a3bd7f05Smrg c = info->req_closure; 1439a3bd7f05Smrg length; length--, p++, c++, info->current++) { 1440a3bd7f05Smrg if (event->property == None || format != 32 || p->target == None 1441a3bd7f05Smrg || /* bug compatibility */ p->property == None) { 1442a3bd7f05Smrg HandleNone(widget, info->callbacks[info->current], 1443a3bd7f05Smrg *c, event->selection); 1444a3bd7f05Smrg if (p->property != None) 1445a3bd7f05Smrg FreeSelectionProperty(XtDisplay(widget), p->property); 1446a3bd7f05Smrg } 1447a3bd7f05Smrg else { 1448a3bd7f05Smrg if (HandleNormal(dpy, widget, p->property, info, *c, 1449a3bd7f05Smrg event->selection)) { 1450444c061aSmrg FreeSelectionProperty(XtDisplay(widget), p->property); 1451a3bd7f05Smrg } 1452a3bd7f05Smrg } 1453a3bd7f05Smrg } 1454a3bd7f05Smrg XFree((char *) pairs); 1455a3bd7f05Smrg FreeSelectionProperty(dpy, info->property); 1456a3bd7f05Smrg FreeInfo(info); 1457a3bd7f05Smrg } 1458a3bd7f05Smrg else if (event->property == None) { 1459a3bd7f05Smrg HandleNone(widget, info->callbacks[0], *info->req_closure, 1460a3bd7f05Smrg event->selection); 1461444c061aSmrg FreeSelectionProperty(XtDisplay(widget), info->property); 1462a3bd7f05Smrg FreeInfo(info); 1463a3bd7f05Smrg } 1464a3bd7f05Smrg else { 1465a3bd7f05Smrg if (HandleNormal(dpy, widget, event->property, info, 1466a3bd7f05Smrg *info->req_closure, event->selection)) { 1467a3bd7f05Smrg FreeSelectionProperty(XtDisplay(widget), info->property); 1468a3bd7f05Smrg FreeInfo(info); 1469a3bd7f05Smrg } 1470444c061aSmrg } 1471444c061aSmrg} 1472444c061aSmrg 1473a3bd7f05Smrgstatic void 1474a3bd7f05SmrgDoLocalTransfer(Request req, 1475a3bd7f05Smrg Atom selection, 1476a3bd7f05Smrg Atom target, 1477a3bd7f05Smrg Widget widget, /* The widget requesting the value. */ 1478a3bd7f05Smrg XtSelectionCallbackProc callback, 1479a3bd7f05Smrg XtPointer closure, /* the closure for the callback, not the conversion */ 1480a3bd7f05Smrg Boolean incremental, Atom property) 1481444c061aSmrg{ 1482444c061aSmrg Select ctx = req->ctx; 1483444c061aSmrg XtPointer value = NULL, temp, total = NULL; 1484444c061aSmrg unsigned long length; 1485444c061aSmrg int format; 1486444c061aSmrg Atom resulttype; 1487444c061aSmrg unsigned long totallength = 0; 1488444c061aSmrg 1489a3bd7f05Smrg req->event.type = 0; 1490a3bd7f05Smrg req->event.target = target; 1491a3bd7f05Smrg req->event.property = req->property = property; 1492a3bd7f05Smrg req->event.requestor = req->requestor = XtWindow(widget); 1493a3bd7f05Smrg 1494a3bd7f05Smrg if (ctx->incremental) { 1495a3bd7f05Smrg unsigned long size = (unsigned long) MAX_SELECTION_INCR(ctx->dpy); 1496a3bd7f05Smrg 1497a3bd7f05Smrg if (!(*(XtConvertSelectionIncrProc) ctx->convert) 1498a3bd7f05Smrg (ctx->widget, &selection, &target, 1499a3bd7f05Smrg &resulttype, &value, &length, &format, 1500a3bd7f05Smrg &size, ctx->owner_closure, (XtRequestId *) &req)) { 1501a3bd7f05Smrg HandleNone(widget, callback, closure, selection); 1502a3bd7f05Smrg } 1503a3bd7f05Smrg else { 1504a3bd7f05Smrg if (incremental) { 1505a3bd7f05Smrg Boolean allSent = FALSE; 1506a3bd7f05Smrg 1507a3bd7f05Smrg while (!allSent) { 1508a3bd7f05Smrg if (ctx->notify && (value != NULL)) { 1509a3bd7f05Smrg int bytelength = (int) BYTELENGTH(length, format); 1510a3bd7f05Smrg 1511a3bd7f05Smrg /* both sides think they own this storage */ 1512a3bd7f05Smrg temp = __XtMalloc((unsigned) bytelength); 1513fdf6a26fSmrg (void) memcpy(temp, value, (size_t) bytelength); 1514a3bd7f05Smrg value = temp; 1515a3bd7f05Smrg } 1516a3bd7f05Smrg /* use care; older clients were never warned that 1517a3bd7f05Smrg * they must return a value even if length==0 1518a3bd7f05Smrg */ 1519a3bd7f05Smrg if (value == NULL) 1520a3bd7f05Smrg value = __XtMalloc((unsigned) 1); 1521a3bd7f05Smrg (*callback) (widget, closure, &selection, 1522a3bd7f05Smrg &resulttype, value, &length, &format); 1523a3bd7f05Smrg if (length) { 1524a3bd7f05Smrg /* should owner be notified on end-of-piece? 1525a3bd7f05Smrg * Spec is unclear, but non-local transfers don't. 1526a3bd7f05Smrg */ 1527a3bd7f05Smrg (*(XtConvertSelectionIncrProc) ctx->convert) 1528a3bd7f05Smrg (ctx->widget, &selection, &target, 1529a3bd7f05Smrg &resulttype, &value, &length, &format, 1530a3bd7f05Smrg &size, ctx->owner_closure, (XtRequestId *) &req); 1531a3bd7f05Smrg } 1532a3bd7f05Smrg else 1533a3bd7f05Smrg allSent = TRUE; 1534a3bd7f05Smrg } 1535a3bd7f05Smrg } 1536a3bd7f05Smrg else { 1537a3bd7f05Smrg while (length) { 1538a3bd7f05Smrg int bytelength = (int) BYTELENGTH(length, format); 1539a3bd7f05Smrg 1540a3bd7f05Smrg total = XtRealloc(total, 1541a3bd7f05Smrg (Cardinal) (totallength = 1542a3bd7f05Smrg totallength + 1543a3bd7f05Smrg (unsigned long) bytelength)); 1544fdf6a26fSmrg (void) memcpy((char *) total + totallength - bytelength, 1545a3bd7f05Smrg value, (size_t) bytelength); 1546a3bd7f05Smrg (*(XtConvertSelectionIncrProc) ctx->convert) 1547a3bd7f05Smrg (ctx->widget, &selection, &target, 1548a3bd7f05Smrg &resulttype, &value, &length, &format, 1549a3bd7f05Smrg &size, ctx->owner_closure, (XtRequestId *) &req); 1550a3bd7f05Smrg } 1551a3bd7f05Smrg if (total == NULL) 1552a3bd7f05Smrg total = __XtMalloc(1); 1553a3bd7f05Smrg totallength = NUMELEM2(totallength, format); 1554a3bd7f05Smrg (*callback) (widget, closure, &selection, &resulttype, 1555a3bd7f05Smrg total, &totallength, &format); 1556a3bd7f05Smrg } 1557a3bd7f05Smrg if (ctx->notify) 1558a3bd7f05Smrg (*(XtSelectionDoneIncrProc) ctx->notify) 1559a3bd7f05Smrg (ctx->widget, &selection, &target, 1560a3bd7f05Smrg (XtRequestId *) &req, ctx->owner_closure); 1561a3bd7f05Smrg else 1562a3bd7f05Smrg XtFree((char *) value); 1563a3bd7f05Smrg } 1564a3bd7f05Smrg } 1565a3bd7f05Smrg else { /* not incremental owner */ 1566a3bd7f05Smrg if (!(*ctx->convert) (ctx->widget, &selection, &target, 1567a3bd7f05Smrg &resulttype, &value, &length, &format)) { 1568a3bd7f05Smrg HandleNone(widget, callback, closure, selection); 1569a3bd7f05Smrg } 1570a3bd7f05Smrg else { 1571a3bd7f05Smrg if (ctx->notify && (value != NULL)) { 1572a3bd7f05Smrg int bytelength = (int) BYTELENGTH(length, format); 1573a3bd7f05Smrg 1574a3bd7f05Smrg /* both sides think they own this storage; better copy */ 1575a3bd7f05Smrg temp = __XtMalloc((unsigned) bytelength); 1576fdf6a26fSmrg (void) memcpy(temp, value, (size_t) bytelength); 1577a3bd7f05Smrg value = temp; 1578a3bd7f05Smrg } 1579a3bd7f05Smrg if (value == NULL) 1580a3bd7f05Smrg value = __XtMalloc((unsigned) 1); 1581a3bd7f05Smrg (*callback) (widget, closure, &selection, &resulttype, 1582a3bd7f05Smrg value, &length, &format); 1583a3bd7f05Smrg if (ctx->notify) 1584a3bd7f05Smrg (*ctx->notify) (ctx->widget, &selection, &target); 1585a3bd7f05Smrg } 1586a3bd7f05Smrg } 1587444c061aSmrg} 1588444c061aSmrg 1589a3bd7f05Smrgstatic void 1590a3bd7f05SmrgGetSelectionValue(Widget widget, 1591a3bd7f05Smrg Atom selection, 1592a3bd7f05Smrg Atom target, 1593a3bd7f05Smrg XtSelectionCallbackProc callback, 1594a3bd7f05Smrg XtPointer closure, 1595a3bd7f05Smrg Time time, 1596a3bd7f05Smrg Boolean incremental, 1597a3bd7f05Smrg Atom property) 1598444c061aSmrg{ 1599444c061aSmrg Select ctx; 1600444c061aSmrg Atom properties[1]; 1601444c061aSmrg 1602444c061aSmrg properties[0] = property; 1603444c061aSmrg 1604444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 1605444c061aSmrg if (ctx->widget && !ctx->was_disowned) { 1606a3bd7f05Smrg RequestRec req; 1607a3bd7f05Smrg 1608a3bd7f05Smrg ctx->req = &req; 1609fdf6a26fSmrg memset(&req, 0, sizeof(req)); 1610a3bd7f05Smrg req.ctx = ctx; 1611a3bd7f05Smrg req.event.time = time; 1612a3bd7f05Smrg ctx->ref_count++; 1613a3bd7f05Smrg DoLocalTransfer(&req, selection, target, widget, 1614a3bd7f05Smrg callback, closure, incremental, property); 1615a3bd7f05Smrg if (--ctx->ref_count == 0 && ctx->free_when_done) 1616a3bd7f05Smrg XtFree((char *) ctx); 1617a3bd7f05Smrg else 1618a3bd7f05Smrg ctx->req = NULL; 1619444c061aSmrg } 1620444c061aSmrg else { 1621a3bd7f05Smrg CallBackInfo info; 1622a3bd7f05Smrg 1623a3bd7f05Smrg info = MakeInfo(ctx, &callback, &closure, 1, widget, 1624a3bd7f05Smrg time, &incremental, properties); 1625a3bd7f05Smrg info->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom)); 1626a3bd7f05Smrg *(info->target) = target; 1627a3bd7f05Smrg RequestSelectionValue(info, selection, target); 1628444c061aSmrg } 1629444c061aSmrg} 1630444c061aSmrg 1631a3bd7f05Smrgvoid 1632a3bd7f05SmrgXtGetSelectionValue(Widget widget, 1633a3bd7f05Smrg Atom selection, 1634a3bd7f05Smrg Atom target, 1635a3bd7f05Smrg XtSelectionCallbackProc callback, 1636a3bd7f05Smrg XtPointer closure, 1637a3bd7f05Smrg Time time) 1638444c061aSmrg{ 1639444c061aSmrg Atom property; 1640444c061aSmrg Boolean incr = False; 1641a3bd7f05Smrg 1642444c061aSmrg WIDGET_TO_APPCON(widget); 1643444c061aSmrg 1644444c061aSmrg LOCK_APP(app); 1645444c061aSmrg property = GetParamInfo(widget, selection); 1646444c061aSmrg RemoveParamInfo(widget, selection); 1647444c061aSmrg 1648444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1649a3bd7f05Smrg AddSelectionRequests(widget, selection, 1, &target, &callback, 1, 1650a3bd7f05Smrg &closure, &incr, &property); 1651a3bd7f05Smrg } 1652a3bd7f05Smrg else { 1653a3bd7f05Smrg GetSelectionValue(widget, selection, target, callback, 1654a3bd7f05Smrg closure, time, FALSE, property); 1655444c061aSmrg } 1656444c061aSmrg UNLOCK_APP(app); 1657444c061aSmrg} 1658444c061aSmrg 1659a3bd7f05Smrgvoid 1660a3bd7f05SmrgXtGetSelectionValueIncremental(Widget widget, 1661a3bd7f05Smrg Atom selection, 1662a3bd7f05Smrg Atom target, 1663a3bd7f05Smrg XtSelectionCallbackProc callback, 1664a3bd7f05Smrg XtPointer closure, 1665a3bd7f05Smrg Time time) 1666444c061aSmrg{ 1667444c061aSmrg Atom property; 1668444c061aSmrg Boolean incr = TRUE; 1669a3bd7f05Smrg 1670444c061aSmrg WIDGET_TO_APPCON(widget); 1671444c061aSmrg 1672444c061aSmrg LOCK_APP(app); 1673444c061aSmrg property = GetParamInfo(widget, selection); 1674444c061aSmrg RemoveParamInfo(widget, selection); 1675444c061aSmrg 1676444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1677a3bd7f05Smrg AddSelectionRequests(widget, selection, 1, &target, &callback, 1, 1678a3bd7f05Smrg &closure, &incr, &property); 1679a3bd7f05Smrg } 1680a3bd7f05Smrg else { 1681a3bd7f05Smrg GetSelectionValue(widget, selection, target, callback, 1682a3bd7f05Smrg closure, time, TRUE, property); 1683444c061aSmrg } 1684444c061aSmrg 1685444c061aSmrg UNLOCK_APP(app); 1686444c061aSmrg} 1687444c061aSmrg 1688a3bd7f05Smrgstatic void 1689a3bd7f05SmrgGetSelectionValues(Widget widget, 1690a3bd7f05Smrg Atom selection, 1691a3bd7f05Smrg Atom *targets, 1692a3bd7f05Smrg int count, 1693a3bd7f05Smrg XtSelectionCallbackProc *callbacks, 1694a3bd7f05Smrg int num_callbacks, 1695a3bd7f05Smrg XtPointer *closures, 1696a3bd7f05Smrg Time time, 1697a3bd7f05Smrg Boolean *incremental, 1698a3bd7f05Smrg Atom *properties) 1699444c061aSmrg{ 1700444c061aSmrg Select ctx; 17010568f49bSmrg IndirectPair *pairs; 1702444c061aSmrg 1703a3bd7f05Smrg if (count == 0) 1704a3bd7f05Smrg return; 1705444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 1706444c061aSmrg if (ctx->widget && !ctx->was_disowned) { 1707444c061aSmrg int j, i; 1708a3bd7f05Smrg RequestRec req; 1709a3bd7f05Smrg 1710a3bd7f05Smrg ctx->req = &req; 1711a3bd7f05Smrg req.ctx = ctx; 1712a3bd7f05Smrg req.event.time = time; 1713a3bd7f05Smrg ctx->ref_count++; 1714fdf6a26fSmrg for (i = 0, j = 0; count > 0; count--, i++, j++) { 1715a3bd7f05Smrg if (j >= num_callbacks) 1716a3bd7f05Smrg j = 0; 1717a3bd7f05Smrg 1718a3bd7f05Smrg DoLocalTransfer(&req, selection, targets[i], widget, 1719a3bd7f05Smrg callbacks[j], closures[i], incremental[i], 1720a3bd7f05Smrg properties ? properties[i] : None); 1721a3bd7f05Smrg 1722a3bd7f05Smrg } 1723a3bd7f05Smrg if (--ctx->ref_count == 0 && ctx->free_when_done) 1724a3bd7f05Smrg XtFree((char *) ctx); 1725a3bd7f05Smrg else 1726a3bd7f05Smrg ctx->req = NULL; 1727a3bd7f05Smrg } 1728a3bd7f05Smrg else { 1729444c061aSmrg XtSelectionCallbackProc *passed_callbacks; 1730a3bd7f05Smrg XtSelectionCallbackProc stack_cbs[32]; 1731a3bd7f05Smrg CallBackInfo info; 1732a3bd7f05Smrg IndirectPair *p; 1733a3bd7f05Smrg Atom *t; 1734444c061aSmrg int i = 0, j = 0; 1735444c061aSmrg 1736a3bd7f05Smrg passed_callbacks = (XtSelectionCallbackProc *) 1737a3bd7f05Smrg XtStackAlloc(sizeof(XtSelectionCallbackProc) * (size_t) count, 1738a3bd7f05Smrg stack_cbs); 1739a3bd7f05Smrg 1740a3bd7f05Smrg /* To deal with the old calls from XtGetSelectionValues* we 1741a3bd7f05Smrg will repeat however many callbacks have been passed into 1742a3bd7f05Smrg the array */ 1743a3bd7f05Smrg for (i = 0; i < count; i++) { 1744a3bd7f05Smrg if (j >= num_callbacks) 1745a3bd7f05Smrg j = 0; 1746a3bd7f05Smrg passed_callbacks[i] = callbacks[j]; 1747a3bd7f05Smrg j++; 1748a3bd7f05Smrg } 1749a3bd7f05Smrg info = MakeInfo(ctx, passed_callbacks, closures, count, widget, 1750a3bd7f05Smrg time, incremental, properties); 1751a3bd7f05Smrg XtStackFree((XtPointer) passed_callbacks, stack_cbs); 1752a3bd7f05Smrg 1753fdf6a26fSmrg info->target = XtMallocArray ((Cardinal) count + 1, 1754fdf6a26fSmrg (Cardinal) sizeof(Atom)); 1755444c061aSmrg (*info->target) = ctx->prop_list->indirect_atom; 1756fdf6a26fSmrg (void) memcpy((char *) info->target + sizeof(Atom), targets, 1757a3bd7f05Smrg (size_t) count * sizeof(Atom)); 1758fdf6a26fSmrg pairs = XtMallocArray ((Cardinal) count + 1, 1759fdf6a26fSmrg (Cardinal) sizeof(IndirectPair)); 1760a3bd7f05Smrg for (p = &pairs[count - 1], t = &targets[count - 1], i = count - 1; 1761a3bd7f05Smrg p >= pairs; p--, t--, i--) { 1762a3bd7f05Smrg p->target = *t; 1763a3bd7f05Smrg if (properties == NULL || properties[i] == None) { 1764a3bd7f05Smrg p->property = GetSelectionProperty(XtDisplay(widget)); 1765a3bd7f05Smrg XDeleteProperty(XtDisplay(widget), XtWindow(widget), 1766a3bd7f05Smrg p->property); 1767a3bd7f05Smrg } 1768a3bd7f05Smrg else { 1769a3bd7f05Smrg p->property = properties[i]; 1770a3bd7f05Smrg } 1771a3bd7f05Smrg } 1772a3bd7f05Smrg XChangeProperty(XtDisplay(widget), XtWindow(widget), 1773a3bd7f05Smrg info->property, info->property, 1774a3bd7f05Smrg 32, PropModeReplace, (unsigned char *) pairs, 1775a3bd7f05Smrg count * IndirectPairWordSize); 1776a3bd7f05Smrg XtFree((char *) pairs); 1777a3bd7f05Smrg RequestSelectionValue(info, selection, ctx->prop_list->indirect_atom); 1778444c061aSmrg } 1779444c061aSmrg} 1780444c061aSmrg 1781a3bd7f05Smrgvoid 1782a3bd7f05SmrgXtGetSelectionValues(Widget widget, 1783a3bd7f05Smrg Atom selection, 1784a3bd7f05Smrg Atom *targets, 1785a3bd7f05Smrg int count, 1786a3bd7f05Smrg XtSelectionCallbackProc callback, 1787a3bd7f05Smrg XtPointer *closures, 1788a3bd7f05Smrg Time time) 1789444c061aSmrg{ 1790444c061aSmrg Boolean incremental_values[32]; 1791444c061aSmrg Boolean *incremental; 1792444c061aSmrg int i; 1793a3bd7f05Smrg 1794444c061aSmrg WIDGET_TO_APPCON(widget); 1795444c061aSmrg 1796444c061aSmrg LOCK_APP(app); 1797a3bd7f05Smrg incremental = 1798a3bd7f05Smrg XtStackAlloc((size_t) count * sizeof(Boolean), incremental_values); 1799a3bd7f05Smrg for (i = 0; i < count; i++) 1800a3bd7f05Smrg incremental[i] = FALSE; 1801444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1802a3bd7f05Smrg AddSelectionRequests(widget, selection, count, targets, &callback, 1803a3bd7f05Smrg 1, closures, incremental, NULL); 1804a3bd7f05Smrg } 1805a3bd7f05Smrg else { 1806a3bd7f05Smrg GetSelectionValues(widget, selection, targets, count, &callback, 1, 1807a3bd7f05Smrg closures, time, incremental, NULL); 1808444c061aSmrg } 1809444c061aSmrg XtStackFree((XtPointer) incremental, incremental_values); 1810444c061aSmrg UNLOCK_APP(app); 1811444c061aSmrg} 1812444c061aSmrg 1813a3bd7f05Smrgvoid 1814a3bd7f05SmrgXtGetSelectionValuesIncremental(Widget widget, 1815a3bd7f05Smrg Atom selection, 1816a3bd7f05Smrg Atom *targets, 1817a3bd7f05Smrg int count, 1818a3bd7f05Smrg XtSelectionCallbackProc callback, 1819a3bd7f05Smrg XtPointer *closures, 1820a3bd7f05Smrg Time time) 1821444c061aSmrg{ 1822444c061aSmrg Boolean incremental_values[32]; 1823444c061aSmrg Boolean *incremental; 1824444c061aSmrg int i; 1825a3bd7f05Smrg 1826444c061aSmrg WIDGET_TO_APPCON(widget); 1827444c061aSmrg 1828444c061aSmrg LOCK_APP(app); 1829a3bd7f05Smrg incremental = 1830a3bd7f05Smrg XtStackAlloc((size_t) count * sizeof(Boolean), incremental_values); 1831a3bd7f05Smrg for (i = 0; i < count; i++) 1832a3bd7f05Smrg incremental[i] = TRUE; 1833444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1834a3bd7f05Smrg AddSelectionRequests(widget, selection, count, targets, &callback, 1835a3bd7f05Smrg 1, closures, incremental, NULL); 1836a3bd7f05Smrg } 1837a3bd7f05Smrg else { 1838a3bd7f05Smrg GetSelectionValues(widget, selection, targets, count, 1839a3bd7f05Smrg &callback, 1, closures, time, incremental, NULL); 1840444c061aSmrg } 1841444c061aSmrg XtStackFree((XtPointer) incremental, incremental_values); 1842444c061aSmrg UNLOCK_APP(app); 1843444c061aSmrg} 1844444c061aSmrg 1845a3bd7f05Smrgstatic Request 1846a3bd7f05SmrgGetRequestRecord(Widget widget, Atom selection, XtRequestId id) 1847444c061aSmrg{ 1848a3bd7f05Smrg Request req = (Request) id; 1849444c061aSmrg Select ctx = NULL; 1850444c061aSmrg 1851a3bd7f05Smrg if ((req == NULL 1852a3bd7f05Smrg && ((ctx = FindCtx(XtDisplay(widget), selection)) == NULL 1853a3bd7f05Smrg || ctx->req == NULL 1854a3bd7f05Smrg || ctx->selection != selection || ctx->widget == NULL)) 1855a3bd7f05Smrg || (req != NULL 1856a3bd7f05Smrg && (req->ctx == NULL 1857a3bd7f05Smrg || req->ctx->selection != selection 1858a3bd7f05Smrg || req->ctx->widget != widget))) { 1859a3bd7f05Smrg String params = XtName(widget); 1860a3bd7f05Smrg Cardinal num_params = 1; 1861a3bd7f05Smrg 1862a3bd7f05Smrg XtAppWarningMsg(XtWidgetToApplicationContext(widget), 1863a3bd7f05Smrg "notInConvertSelection", "xtGetSelectionRequest", 1864a3bd7f05Smrg XtCXtToolkitError, 1865a3bd7f05Smrg "XtGetSelectionRequest or XtGetSelectionParameters called for widget \"%s\" outside of ConvertSelection proc", 1866a3bd7f05Smrg ¶ms, &num_params); 1867a3bd7f05Smrg return NULL; 1868444c061aSmrg } 1869444c061aSmrg 1870444c061aSmrg if (req == NULL) { 1871a3bd7f05Smrg /* non-incremental owner; only one request can be 1872a3bd7f05Smrg * outstanding at a time, so it's safe to keep ptr in ctx */ 1873a3bd7f05Smrg req = ctx->req; 1874444c061aSmrg } 1875444c061aSmrg return req; 1876444c061aSmrg} 1877444c061aSmrg 1878a3bd7f05SmrgXSelectionRequestEvent * 1879a3bd7f05SmrgXtGetSelectionRequest(Widget widget, Atom selection, XtRequestId id) 1880444c061aSmrg{ 1881a3bd7f05Smrg Request req = (Request) id; 1882a3bd7f05Smrg 1883444c061aSmrg WIDGET_TO_APPCON(widget); 1884444c061aSmrg 1885444c061aSmrg LOCK_APP(app); 1886444c061aSmrg 1887444c061aSmrg req = GetRequestRecord(widget, selection, id); 1888444c061aSmrg 1889a3bd7f05Smrg if (!req) { 1890a3bd7f05Smrg UNLOCK_APP(app); 1891a3bd7f05Smrg return (XSelectionRequestEvent *) NULL; 1892444c061aSmrg } 1893444c061aSmrg 1894444c061aSmrg if (req->event.type == 0) { 1895a3bd7f05Smrg /* owner is local; construct the remainder of the event */ 1896a3bd7f05Smrg req->event.type = SelectionRequest; 1897a3bd7f05Smrg req->event.serial = LastKnownRequestProcessed(XtDisplay(widget)); 1898a3bd7f05Smrg req->event.send_event = True; 1899a3bd7f05Smrg req->event.display = XtDisplay(widget); 1900a3bd7f05Smrg 1901a3bd7f05Smrg req->event.owner = XtWindow(req->ctx->widget); 1902a3bd7f05Smrg req->event.selection = selection; 1903444c061aSmrg } 1904444c061aSmrg UNLOCK_APP(app); 1905444c061aSmrg return &req->event; 1906444c061aSmrg} 1907444c061aSmrg 1908444c061aSmrg/* Property atom access */ 1909a3bd7f05SmrgAtom 1910a3bd7f05SmrgXtReservePropertyAtom(Widget w) 1911444c061aSmrg{ 1912a3bd7f05Smrg return (GetSelectionProperty(XtDisplay(w))); 1913444c061aSmrg} 1914444c061aSmrg 1915a3bd7f05Smrgvoid 1916a3bd7f05SmrgXtReleasePropertyAtom(Widget w, Atom atom) 1917444c061aSmrg{ 1918a3bd7f05Smrg FreeSelectionProperty(XtDisplay(w), atom); 1919444c061aSmrg} 1920444c061aSmrg 1921444c061aSmrg/* Multiple utilities */ 1922444c061aSmrg 1923444c061aSmrg/* All requests are put in a single list per widget. It is 1924444c061aSmrg very unlikely anyone will be gathering multiple MULTIPLE 1925444c061aSmrg requests at the same time, so the loss in efficiency for 1926444c061aSmrg this case is acceptable */ 1927444c061aSmrg 1928444c061aSmrg/* Queue one or more requests to the one we're gathering */ 1929a3bd7f05Smrgstatic void 1930a3bd7f05SmrgAddSelectionRequests(Widget wid, 1931a3bd7f05Smrg Atom sel, 1932a3bd7f05Smrg int count, 1933a3bd7f05Smrg Atom *targets, 1934a3bd7f05Smrg XtSelectionCallbackProc *callbacks, 1935a3bd7f05Smrg int num_cb, 1936a3bd7f05Smrg XtPointer *closures, 1937a3bd7f05Smrg Boolean *incrementals, 1938a3bd7f05Smrg Atom *properties) 1939444c061aSmrg{ 1940a3bd7f05Smrg QueuedRequestInfo qi; 1941a3bd7f05Smrg Window window = XtWindow(wid); 1942a3bd7f05Smrg Display *dpy = XtDisplay(wid); 1943444c061aSmrg 1944a3bd7f05Smrg LOCK_PROCESS; 1945a3bd7f05Smrg if (multipleContext == 0) 1946a3bd7f05Smrg multipleContext = XUniqueContext(); 1947a3bd7f05Smrg 1948a3bd7f05Smrg qi = NULL; 1949a3bd7f05Smrg (void) XFindContext(dpy, window, multipleContext, (XPointer *) &qi); 1950a3bd7f05Smrg 1951a3bd7f05Smrg if (qi != NULL) { 1952a3bd7f05Smrg QueuedRequest *req = qi->requests; 1953a3bd7f05Smrg int start = qi->count; 1954a3bd7f05Smrg int i = 0; 1955a3bd7f05Smrg int j = 0; 1956a3bd7f05Smrg 1957a3bd7f05Smrg qi->count += count; 1958fdf6a26fSmrg req = XtReallocArray(req, (Cardinal) (start + count), 1959fdf6a26fSmrg (Cardinal) sizeof(QueuedRequest)); 1960a3bd7f05Smrg while (i < count) { 1961a3bd7f05Smrg QueuedRequest newreq = (QueuedRequest) 1962a3bd7f05Smrg __XtMalloc(sizeof(QueuedRequestRec)); 1963a3bd7f05Smrg 1964a3bd7f05Smrg newreq->selection = sel; 1965a3bd7f05Smrg newreq->target = targets[i]; 1966a3bd7f05Smrg if (properties != NULL) 1967a3bd7f05Smrg newreq->param = properties[i]; 1968a3bd7f05Smrg else { 1969a3bd7f05Smrg newreq->param = GetSelectionProperty(dpy); 1970a3bd7f05Smrg XDeleteProperty(dpy, window, newreq->param); 1971a3bd7f05Smrg } 1972a3bd7f05Smrg newreq->callback = callbacks[j]; 1973a3bd7f05Smrg newreq->closure = closures[i]; 1974a3bd7f05Smrg newreq->incremental = incrementals[i]; 1975a3bd7f05Smrg 1976a3bd7f05Smrg req[start] = newreq; 1977a3bd7f05Smrg start++; 1978a3bd7f05Smrg i++; 1979a3bd7f05Smrg j++; 1980a3bd7f05Smrg if (j > num_cb) 1981a3bd7f05Smrg j = 0; 1982a3bd7f05Smrg } 1983444c061aSmrg 1984a3bd7f05Smrg qi->requests = req; 1985a3bd7f05Smrg } 1986a3bd7f05Smrg else { 1987a3bd7f05Smrg /* Impossible */ 1988a3bd7f05Smrg } 1989444c061aSmrg 1990a3bd7f05Smrg UNLOCK_PROCESS; 1991a3bd7f05Smrg} 1992444c061aSmrg 1993a3bd7f05Smrg/* Only call IsGatheringRequest when we have a lock already */ 1994444c061aSmrg 1995a3bd7f05Smrgstatic Boolean 1996a3bd7f05SmrgIsGatheringRequest(Widget wid, Atom sel) 1997a3bd7f05Smrg{ 1998a3bd7f05Smrg QueuedRequestInfo qi; 1999a3bd7f05Smrg Window window = XtWindow(wid); 2000a3bd7f05Smrg Display *dpy = XtDisplay(wid); 2001a3bd7f05Smrg Boolean found = False; 2002a3bd7f05Smrg 2003a3bd7f05Smrg if (multipleContext == 0) 2004a3bd7f05Smrg multipleContext = XUniqueContext(); 2005a3bd7f05Smrg 2006a3bd7f05Smrg qi = NULL; 2007a3bd7f05Smrg (void) XFindContext(dpy, window, multipleContext, (XPointer *) &qi); 2008a3bd7f05Smrg 2009a3bd7f05Smrg if (qi != NULL) { 2010a3bd7f05Smrg int i = 0; 2011a3bd7f05Smrg 2012a3bd7f05Smrg while (qi->selections[i] != None) { 2013a3bd7f05Smrg if (qi->selections[i] == sel) { 2014a3bd7f05Smrg found = True; 2015a3bd7f05Smrg break; 2016a3bd7f05Smrg } 2017a3bd7f05Smrg i++; 2018a3bd7f05Smrg } 2019444c061aSmrg } 2020444c061aSmrg 2021a3bd7f05Smrg return (found); 2022444c061aSmrg} 2023444c061aSmrg 2024444c061aSmrg/* Cleanup request scans the request queue and releases any 2025444c061aSmrg properties queued, and removes any requests queued */ 2026a3bd7f05Smrgstatic void 2027a3bd7f05SmrgCleanupRequest(Display *dpy, QueuedRequestInfo qi, Atom sel) 2028444c061aSmrg{ 2029a3bd7f05Smrg int i, j, n; 2030a3bd7f05Smrg 2031fdf6a26fSmrg if (qi == NULL) 2032fdf6a26fSmrg return; 2033fdf6a26fSmrg 2034a3bd7f05Smrg i = 0; 2035a3bd7f05Smrg 2036a3bd7f05Smrg /* Remove this selection from the list */ 2037a3bd7f05Smrg n = 0; 2038a3bd7f05Smrg while (qi->selections[n] != sel && qi->selections[n] != None) 2039a3bd7f05Smrg n++; 2040a3bd7f05Smrg if (qi->selections[n] == sel) { 2041a3bd7f05Smrg while (qi->selections[n] != None) { 2042a3bd7f05Smrg qi->selections[n] = qi->selections[n + 1]; 2043a3bd7f05Smrg n++; 2044a3bd7f05Smrg } 2045444c061aSmrg } 2046444c061aSmrg 2047a3bd7f05Smrg while (i < qi->count) { 2048a3bd7f05Smrg QueuedRequest req = qi->requests[i]; 2049444c061aSmrg 2050a3bd7f05Smrg if (req->selection == sel) { 2051a3bd7f05Smrg /* Match */ 2052a3bd7f05Smrg if (req->param != None) 2053a3bd7f05Smrg FreeSelectionProperty(dpy, req->param); 2054a3bd7f05Smrg qi->count--; 2055444c061aSmrg 2056a3bd7f05Smrg for (j = i; j < qi->count; j++) 2057a3bd7f05Smrg qi->requests[j] = qi->requests[j + 1]; 2058444c061aSmrg 2059a3bd7f05Smrg XtFree((char *) req); 2060a3bd7f05Smrg } 2061a3bd7f05Smrg else { 2062a3bd7f05Smrg i++; 2063a3bd7f05Smrg } 2064444c061aSmrg } 2065444c061aSmrg} 2066444c061aSmrg 2067a3bd7f05Smrgvoid 2068a3bd7f05SmrgXtCreateSelectionRequest(Widget widget, Atom selection) 2069444c061aSmrg{ 2070a3bd7f05Smrg QueuedRequestInfo queueInfo; 2071a3bd7f05Smrg Window window = XtWindow(widget); 2072a3bd7f05Smrg Display *dpy = XtDisplay(widget); 2073fdf6a26fSmrg Cardinal n; 2074444c061aSmrg 2075a3bd7f05Smrg LOCK_PROCESS; 2076a3bd7f05Smrg if (multipleContext == 0) 2077a3bd7f05Smrg multipleContext = XUniqueContext(); 2078444c061aSmrg 2079a3bd7f05Smrg queueInfo = NULL; 2080a3bd7f05Smrg (void) XFindContext(dpy, window, multipleContext, (XPointer *) &queueInfo); 2081444c061aSmrg 2082a3bd7f05Smrg /* If there is one, then cancel it */ 2083a3bd7f05Smrg if (queueInfo != NULL) 2084a3bd7f05Smrg CleanupRequest(dpy, queueInfo, selection); 2085a3bd7f05Smrg else { 2086a3bd7f05Smrg /* Create it */ 2087a3bd7f05Smrg queueInfo = 2088a3bd7f05Smrg (QueuedRequestInfo) __XtMalloc(sizeof(QueuedRequestInfoRec)); 2089a3bd7f05Smrg queueInfo->count = 0; 2090fdf6a26fSmrg queueInfo->selections = XtMallocArray(2, (Cardinal) sizeof(Atom)); 2091a3bd7f05Smrg queueInfo->selections[0] = None; 2092a3bd7f05Smrg queueInfo->requests = (QueuedRequest *) 2093a3bd7f05Smrg __XtMalloc(sizeof(QueuedRequest)); 2094a3bd7f05Smrg } 2095a3bd7f05Smrg 2096a3bd7f05Smrg /* Append this selection to list */ 2097a3bd7f05Smrg n = 0; 2098a3bd7f05Smrg while (queueInfo->selections[n] != None) 2099a3bd7f05Smrg n++; 2100fdf6a26fSmrg queueInfo->selections = XtReallocArray(queueInfo->selections, (n + 2), 2101fdf6a26fSmrg (Cardinal) sizeof(Atom)); 2102a3bd7f05Smrg queueInfo->selections[n] = selection; 2103a3bd7f05Smrg queueInfo->selections[n + 1] = None; 2104a3bd7f05Smrg 2105a3bd7f05Smrg (void) XSaveContext(dpy, window, multipleContext, (char *) queueInfo); 2106a3bd7f05Smrg UNLOCK_PROCESS; 2107444c061aSmrg} 2108444c061aSmrg 2109a3bd7f05Smrgvoid 2110a3bd7f05SmrgXtSendSelectionRequest(Widget widget, Atom selection, Time time) 2111444c061aSmrg{ 2112a3bd7f05Smrg QueuedRequestInfo queueInfo; 2113a3bd7f05Smrg Window window = XtWindow(widget); 2114a3bd7f05Smrg Display *dpy = XtDisplay(widget); 2115444c061aSmrg 2116a3bd7f05Smrg LOCK_PROCESS; 2117a3bd7f05Smrg if (multipleContext == 0) 2118a3bd7f05Smrg multipleContext = XUniqueContext(); 2119a3bd7f05Smrg 2120a3bd7f05Smrg queueInfo = NULL; 2121a3bd7f05Smrg (void) XFindContext(dpy, window, multipleContext, (XPointer *) &queueInfo); 2122a3bd7f05Smrg if (queueInfo != NULL) { 2123a3bd7f05Smrg int i; 2124a3bd7f05Smrg int count = 0; 2125a3bd7f05Smrg QueuedRequest *req = queueInfo->requests; 2126a3bd7f05Smrg 2127a3bd7f05Smrg /* Construct the requests and send it using 2128a3bd7f05Smrg GetSelectionValues */ 2129a3bd7f05Smrg for (i = 0; i < queueInfo->count; i++) 2130a3bd7f05Smrg if (req[i]->selection == selection) 2131a3bd7f05Smrg count++; 2132a3bd7f05Smrg 2133a3bd7f05Smrg if (count > 0) { 2134a3bd7f05Smrg if (count == 1) { 2135a3bd7f05Smrg for (i = 0; i < queueInfo->count; i++) 2136a3bd7f05Smrg if (req[i]->selection == selection) 2137a3bd7f05Smrg break; 2138a3bd7f05Smrg 2139a3bd7f05Smrg /* special case a multiple which isn't needed */ 2140a3bd7f05Smrg GetSelectionValue(widget, selection, req[i]->target, 2141a3bd7f05Smrg req[i]->callback, req[i]->closure, time, 2142a3bd7f05Smrg req[i]->incremental, req[i]->param); 2143a3bd7f05Smrg } 2144a3bd7f05Smrg else { 2145a3bd7f05Smrg Atom *targets; 2146a3bd7f05Smrg Atom t[PREALLOCED]; 2147a3bd7f05Smrg XtSelectionCallbackProc *cbs; 2148a3bd7f05Smrg XtSelectionCallbackProc c[PREALLOCED]; 2149a3bd7f05Smrg XtPointer *closures; 2150a3bd7f05Smrg XtPointer cs[PREALLOCED]; 2151a3bd7f05Smrg Boolean *incrs; 2152a3bd7f05Smrg Boolean ins[PREALLOCED]; 2153a3bd7f05Smrg Atom *props; 2154a3bd7f05Smrg Atom p[PREALLOCED]; 2155a3bd7f05Smrg int j = 0; 2156a3bd7f05Smrg 2157a3bd7f05Smrg /* Allocate */ 2158a3bd7f05Smrg targets = 2159a3bd7f05Smrg (Atom *) XtStackAlloc((size_t) count * sizeof(Atom), t); 2160a3bd7f05Smrg cbs = (XtSelectionCallbackProc *) 2161a3bd7f05Smrg XtStackAlloc((size_t) count * 2162a3bd7f05Smrg sizeof(XtSelectionCallbackProc), c); 2163a3bd7f05Smrg closures = 2164a3bd7f05Smrg (XtPointer *) XtStackAlloc((size_t) count * 2165a3bd7f05Smrg sizeof(XtPointer), cs); 2166a3bd7f05Smrg incrs = 2167a3bd7f05Smrg (Boolean *) XtStackAlloc((size_t) count * sizeof(Boolean), 2168a3bd7f05Smrg ins); 2169a3bd7f05Smrg props = (Atom *) XtStackAlloc((size_t) count * sizeof(Atom), p); 2170a3bd7f05Smrg 2171a3bd7f05Smrg /* Copy */ 2172a3bd7f05Smrg for (i = 0; i < queueInfo->count; i++) { 2173a3bd7f05Smrg if (req[i]->selection == selection) { 2174a3bd7f05Smrg targets[j] = req[i]->target; 2175a3bd7f05Smrg cbs[j] = req[i]->callback; 2176a3bd7f05Smrg closures[j] = req[i]->closure; 2177a3bd7f05Smrg incrs[j] = req[i]->incremental; 2178a3bd7f05Smrg props[j] = req[i]->param; 2179a3bd7f05Smrg j++; 2180a3bd7f05Smrg } 2181a3bd7f05Smrg } 2182a3bd7f05Smrg 2183a3bd7f05Smrg /* Make the request */ 2184a3bd7f05Smrg GetSelectionValues(widget, selection, targets, count, 2185a3bd7f05Smrg cbs, count, closures, time, incrs, props); 2186a3bd7f05Smrg 2187a3bd7f05Smrg /* Free */ 2188a3bd7f05Smrg XtStackFree((XtPointer) targets, t); 2189a3bd7f05Smrg XtStackFree((XtPointer) cbs, c); 2190a3bd7f05Smrg XtStackFree((XtPointer) closures, cs); 2191a3bd7f05Smrg XtStackFree((XtPointer) incrs, ins); 2192a3bd7f05Smrg XtStackFree((XtPointer) props, p); 2193a3bd7f05Smrg } 2194a3bd7f05Smrg } 2195a3bd7f05Smrg } 2196444c061aSmrg 2197a3bd7f05Smrg CleanupRequest(dpy, queueInfo, selection); 2198a3bd7f05Smrg UNLOCK_PROCESS; 2199444c061aSmrg} 2200444c061aSmrg 2201a3bd7f05Smrgvoid 2202a3bd7f05SmrgXtCancelSelectionRequest(Widget widget, Atom selection) 2203444c061aSmrg{ 2204a3bd7f05Smrg QueuedRequestInfo queueInfo; 2205a3bd7f05Smrg Window window = XtWindow(widget); 2206a3bd7f05Smrg Display *dpy = XtDisplay(widget); 2207444c061aSmrg 2208a3bd7f05Smrg LOCK_PROCESS; 2209a3bd7f05Smrg if (multipleContext == 0) 2210a3bd7f05Smrg multipleContext = XUniqueContext(); 2211a3bd7f05Smrg 2212a3bd7f05Smrg queueInfo = NULL; 2213a3bd7f05Smrg (void) XFindContext(dpy, window, multipleContext, (XPointer *) &queueInfo); 2214a3bd7f05Smrg /* If there is one, then cancel it */ 2215a3bd7f05Smrg if (queueInfo != NULL) 2216a3bd7f05Smrg CleanupRequest(dpy, queueInfo, selection); 2217a3bd7f05Smrg UNLOCK_PROCESS; 2218444c061aSmrg} 2219444c061aSmrg 2220444c061aSmrg/* Parameter utilities */ 2221444c061aSmrg 2222444c061aSmrg/* Parameters on a selection request */ 2223444c061aSmrg/* Places data on allocated parameter atom, then records the 2224444c061aSmrg parameter atom data for use in the next call to one of 2225444c061aSmrg the XtGetSelectionValue functions. */ 2226a3bd7f05Smrgvoid 2227a3bd7f05SmrgXtSetSelectionParameters(Widget requestor, 2228a3bd7f05Smrg Atom selection, 2229a3bd7f05Smrg Atom type, 2230a3bd7f05Smrg XtPointer value, 2231a3bd7f05Smrg unsigned long length, 2232a3bd7f05Smrg int format) 2233444c061aSmrg{ 2234a3bd7f05Smrg Display *dpy = XtDisplay(requestor); 2235a3bd7f05Smrg Window window = XtWindow(requestor); 2236a3bd7f05Smrg Atom property = GetParamInfo(requestor, selection); 2237a3bd7f05Smrg 2238a3bd7f05Smrg if (property == None) { 2239a3bd7f05Smrg property = GetSelectionProperty(dpy); 2240a3bd7f05Smrg AddParamInfo(requestor, selection, property); 2241a3bd7f05Smrg } 2242a3bd7f05Smrg 2243a3bd7f05Smrg XChangeProperty(dpy, window, property, 2244a3bd7f05Smrg type, format, PropModeReplace, 2245a3bd7f05Smrg (unsigned char *) value, (int) length); 2246444c061aSmrg} 2247444c061aSmrg 2248444c061aSmrg/* Retrieves data passed in a parameter. Data for this is stored 2249444c061aSmrg on the originator's window */ 2250a3bd7f05Smrgvoid 2251a3bd7f05SmrgXtGetSelectionParameters(Widget owner, 2252a3bd7f05Smrg Atom selection, 2253a3bd7f05Smrg XtRequestId request_id, 2254a3bd7f05Smrg Atom *type_return, 2255a3bd7f05Smrg XtPointer *value_return, 2256a3bd7f05Smrg unsigned long *length_return, 2257a3bd7f05Smrg int *format_return) 2258444c061aSmrg{ 2259444c061aSmrg Request req; 2260444c061aSmrg Display *dpy = XtDisplay(owner); 2261a3bd7f05Smrg 2262444c061aSmrg WIDGET_TO_APPCON(owner); 2263444c061aSmrg 2264444c061aSmrg *value_return = NULL; 22650568f49bSmrg *length_return = (unsigned long) (*format_return = 0); 2266444c061aSmrg *type_return = None; 2267444c061aSmrg 2268444c061aSmrg LOCK_APP(app); 2269444c061aSmrg 2270444c061aSmrg req = GetRequestRecord(owner, selection, request_id); 2271444c061aSmrg 2272444c061aSmrg if (req && req->property) { 2273a3bd7f05Smrg unsigned long bytes_after; /* unused */ 2274a3bd7f05Smrg 2275a3bd7f05Smrg StartProtectedSection(dpy, req->requestor); 2276a3bd7f05Smrg XGetWindowProperty(dpy, req->requestor, req->property, 0L, 10000000, 2277a3bd7f05Smrg False, AnyPropertyType, type_return, format_return, 2278a3bd7f05Smrg length_return, &bytes_after, 2279a3bd7f05Smrg (unsigned char **) value_return); 2280a3bd7f05Smrg EndProtectedSection(dpy); 2281444c061aSmrg#ifdef XT_COPY_SELECTION 2282a3bd7f05Smrg if (*value_return) { 2283a3bd7f05Smrg int size = (int) BYTELENGTH(*length_return, *format_return) + 1; 2284a3bd7f05Smrg char *tmp = __XtMalloc((Cardinal) size); 2285a3bd7f05Smrg 2286fdf6a26fSmrg (void) memcpy(tmp, *value_return, (size_t) size); 2287a3bd7f05Smrg XFree(*value_return); 2288a3bd7f05Smrg *value_return = tmp; 2289a3bd7f05Smrg } 2290444c061aSmrg#endif 2291444c061aSmrg } 2292444c061aSmrg UNLOCK_APP(app); 2293444c061aSmrg} 2294444c061aSmrg 2295444c061aSmrg/* Parameters are temporarily stashed in an XContext. A list is used because 2296444c061aSmrg * there may be more than one selection request in progress. The context 2297444c061aSmrg * data is deleted when the list is empty. In the future, the parameter 2298444c061aSmrg * context could be merged with other contexts used during selections. 2299444c061aSmrg */ 2300444c061aSmrg 2301a3bd7f05Smrgstatic void 2302a3bd7f05SmrgAddParamInfo(Widget w, Atom selection, Atom param_atom) 2303444c061aSmrg{ 2304444c061aSmrg Param p; 2305444c061aSmrg ParamInfo pinfo; 2306444c061aSmrg 2307444c061aSmrg LOCK_PROCESS; 2308444c061aSmrg if (paramPropertyContext == 0) 2309a3bd7f05Smrg paramPropertyContext = XUniqueContext(); 2310444c061aSmrg 2311444c061aSmrg if (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2312a3bd7f05Smrg (XPointer *) &pinfo)) { 2313a3bd7f05Smrg pinfo = (ParamInfo) __XtMalloc(sizeof(ParamInfoRec)); 2314a3bd7f05Smrg pinfo->count = 1; 2315a3bd7f05Smrg pinfo->paramlist = XtNew(ParamRec); 2316a3bd7f05Smrg p = pinfo->paramlist; 2317a3bd7f05Smrg (void) XSaveContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2318a3bd7f05Smrg (char *) pinfo); 2319444c061aSmrg } 2320444c061aSmrg else { 2321a3bd7f05Smrg int n; 2322a3bd7f05Smrg 2323a3bd7f05Smrg for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++) { 2324a3bd7f05Smrg if (p->selection == None || p->selection == selection) 2325a3bd7f05Smrg break; 2326a3bd7f05Smrg } 2327a3bd7f05Smrg if (n == 0) { 2328a3bd7f05Smrg pinfo->count++; 2329fdf6a26fSmrg pinfo->paramlist = XtReallocArray(pinfo->paramlist, pinfo->count, 2330fdf6a26fSmrg (Cardinal) sizeof(ParamRec)); 2331a3bd7f05Smrg p = &pinfo->paramlist[pinfo->count - 1]; 2332a3bd7f05Smrg (void) XSaveContext(XtDisplay(w), XtWindow(w), 2333a3bd7f05Smrg paramPropertyContext, (char *) pinfo); 2334a3bd7f05Smrg } 2335444c061aSmrg } 2336444c061aSmrg p->selection = selection; 2337444c061aSmrg p->param = param_atom; 2338444c061aSmrg UNLOCK_PROCESS; 2339444c061aSmrg} 2340444c061aSmrg 2341a3bd7f05Smrgstatic void 2342a3bd7f05SmrgRemoveParamInfo(Widget w, Atom selection) 2343444c061aSmrg{ 2344444c061aSmrg ParamInfo pinfo; 2345444c061aSmrg Boolean retain = False; 2346444c061aSmrg 2347444c061aSmrg LOCK_PROCESS; 2348444c061aSmrg if (paramPropertyContext 2349a3bd7f05Smrg && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2350a3bd7f05Smrg (XPointer *) &pinfo) == 0)) { 2351a3bd7f05Smrg Param p; 2352a3bd7f05Smrg int n; 2353a3bd7f05Smrg 2354a3bd7f05Smrg /* Find and invalidate the parameter data. */ 2355a3bd7f05Smrg for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++) { 2356a3bd7f05Smrg if (p->selection != None) { 2357a3bd7f05Smrg if (p->selection == selection) 2358a3bd7f05Smrg p->selection = None; 2359a3bd7f05Smrg else 2360a3bd7f05Smrg retain = True; 2361a3bd7f05Smrg } 2362a3bd7f05Smrg } 2363a3bd7f05Smrg /* If there's no valid data remaining, release the context entry. */ 2364a3bd7f05Smrg if (!retain) { 2365a3bd7f05Smrg XtFree((char *) pinfo->paramlist); 2366a3bd7f05Smrg XtFree((char *) pinfo); 2367a3bd7f05Smrg XDeleteContext(XtDisplay(w), XtWindow(w), paramPropertyContext); 2368a3bd7f05Smrg } 2369444c061aSmrg } 2370444c061aSmrg UNLOCK_PROCESS; 2371444c061aSmrg} 2372444c061aSmrg 2373a3bd7f05Smrgstatic Atom 2374a3bd7f05SmrgGetParamInfo(Widget w, Atom selection) 2375444c061aSmrg{ 2376444c061aSmrg ParamInfo pinfo; 2377444c061aSmrg Atom atom = None; 2378444c061aSmrg 2379444c061aSmrg LOCK_PROCESS; 2380444c061aSmrg if (paramPropertyContext 2381a3bd7f05Smrg && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2382a3bd7f05Smrg (XPointer *) &pinfo) == 0)) { 2383a3bd7f05Smrg Param p; 2384a3bd7f05Smrg int n; 2385a3bd7f05Smrg 2386a3bd7f05Smrg for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++) 2387a3bd7f05Smrg if (p->selection == selection) { 2388a3bd7f05Smrg atom = p->param; 2389a3bd7f05Smrg break; 2390a3bd7f05Smrg } 2391444c061aSmrg } 2392444c061aSmrg UNLOCK_PROCESS; 2393444c061aSmrg return atom; 2394444c061aSmrg} 2395