Selection.c revision a3bd7f05
1444c061aSmrg/*********************************************************** 2249c3046SmrgCopyright (c) 1993, Oracle and/or its affiliates. All rights reserved. 31477040fSmrg 41477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a 51477040fSmrgcopy of this software and associated documentation files (the "Software"), 61477040fSmrgto deal in the Software without restriction, including without limitation 71477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense, 81477040fSmrgand/or sell copies of the Software, and to permit persons to whom the 91477040fSmrgSoftware is furnished to do so, subject to the following conditions: 101477040fSmrg 111477040fSmrgThe above copyright notice and this permission notice (including the next 121477040fSmrgparagraph) shall be included in all copies or substantial portions of the 131477040fSmrgSoftware. 141477040fSmrg 151477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 171477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 181477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 191477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 201477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 211477040fSmrgDEALINGS IN THE SOFTWARE. 221477040fSmrg 231477040fSmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 24444c061aSmrg 25444c061aSmrg All Rights Reserved 26444c061aSmrg 27444c061aSmrgPermission to use, copy, modify, and distribute this software and its 28444c061aSmrgdocumentation for any purpose and without fee is hereby granted, 29444c061aSmrgprovided that the above copyright notice appear in all copies and that 30444c061aSmrgboth that copyright notice and this permission notice appear in 311477040fSmrgsupporting documentation, and that the name of Digital not be 32444c061aSmrgused in advertising or publicity pertaining to distribution of the 33444c061aSmrgsoftware without specific, written prior permission. 34444c061aSmrg 35444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 37444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 38444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 39444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 40444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 41444c061aSmrgSOFTWARE. 42444c061aSmrg 43444c061aSmrg******************************************************************/ 44444c061aSmrg 45444c061aSmrg/* 46444c061aSmrg 47444c061aSmrgCopyright 1987, 1988, 1994, 1998 The Open Group 48444c061aSmrg 49444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its 50444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that 51444c061aSmrgthe above copyright notice appear in all copies and that both that 52444c061aSmrgcopyright notice and this permission notice appear in supporting 53444c061aSmrgdocumentation. 54444c061aSmrg 55444c061aSmrgThe above copyright notice and this permission notice shall be included in 56444c061aSmrgall copies or substantial portions of the Software. 57444c061aSmrg 58444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 62444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 63444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64444c061aSmrg 65444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be 66444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings 67444c061aSmrgin this Software without prior written authorization from The Open Group. 68444c061aSmrg 69444c061aSmrg*/ 70444c061aSmrg 71444c061aSmrg#ifdef HAVE_CONFIG_H 72444c061aSmrg#include <config.h> 73444c061aSmrg#endif 74444c061aSmrg#include "IntrinsicI.h" 75444c061aSmrg#include "StringDefs.h" 76444c061aSmrg#include "SelectionI.h" 77444c061aSmrg#include <X11/Xatom.h> 78444c061aSmrg#include <stdio.h> 79444c061aSmrg 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++; 232a3bd7f05Smrg sarray->list = (SelectionProp) XtRealloc((XtPointer) sarray->list, 233a3bd7f05Smrg (Cardinal) ((size_t) sarray-> 234a3bd7f05Smrg propCount * 235a3bd7f05Smrg sizeof 236a3bd7f05Smrg (SelectionPropRec))); 237a3bd7f05Smrg (void) snprintf(propname, sizeof(propname), "_XT_SELECTION_%d", propCount); 238a3bd7f05Smrg sarray->list[propCount].prop = XInternAtom(dpy, propname, FALSE); 239a3bd7f05Smrg sarray->list[propCount].avail = FALSE; 240a3bd7f05Smrg return (sarray->list[propCount].prop); 241444c061aSmrg} 242444c061aSmrg 243a3bd7f05Smrgstatic void 244a3bd7f05SmrgFreeSelectionProperty(Display *dpy, Atom prop) 245444c061aSmrg{ 246a3bd7f05Smrg SelectionProp p; 247a3bd7f05Smrg int propCount; 248a3bd7f05Smrg PropList sarray; 249a3bd7f05Smrg 250a3bd7f05Smrg if (prop == None) 251a3bd7f05Smrg return; 252a3bd7f05Smrg LOCK_PROCESS; 253a3bd7f05Smrg if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, 254a3bd7f05Smrg (XPointer *) &sarray)) 255a3bd7f05Smrg XtAppErrorMsg(XtDisplayToApplicationContext(dpy), 256a3bd7f05Smrg "noSelectionProperties", "freeSelectionProperty", 257a3bd7f05Smrg XtCXtToolkitError, 258a3bd7f05Smrg "internal error: no selection property context for display", 259a3bd7f05Smrg NULL, NULL); 260a3bd7f05Smrg UNLOCK_PROCESS; 261a3bd7f05Smrg for (p = sarray->list, propCount = sarray->propCount; 262a3bd7f05Smrg propCount; p++, propCount--) 263a3bd7f05Smrg if (p->prop == prop) { 264a3bd7f05Smrg p->avail = TRUE; 265a3bd7f05Smrg return; 266a3bd7f05Smrg } 267444c061aSmrg} 268444c061aSmrg 269a3bd7f05Smrgstatic void 270a3bd7f05SmrgFreeInfo(CallBackInfo info) 271444c061aSmrg{ 272a3bd7f05Smrg XtFree((char *) info->incremental); 273a3bd7f05Smrg XtFree((char *) info->callbacks); 274a3bd7f05Smrg XtFree((char *) info->req_closure); 275a3bd7f05Smrg XtFree((char *) info->target); 276a3bd7f05Smrg XtFree((char *) info); 277444c061aSmrg} 278444c061aSmrg 279a3bd7f05Smrgstatic CallBackInfo 280a3bd7f05SmrgMakeInfo(Select ctx, 281a3bd7f05Smrg XtSelectionCallbackProc *callbacks, 282a3bd7f05Smrg XtPointer *closures, 283a3bd7f05Smrg int count, 284a3bd7f05Smrg Widget widget, 285a3bd7f05Smrg Time time, 286a3bd7f05Smrg Boolean *incremental, 287a3bd7f05Smrg Atom *properties) 288444c061aSmrg{ 289a3bd7f05Smrg CallBackInfo info = XtNew(CallBackInfoRec); 290a3bd7f05Smrg 291a3bd7f05Smrg info->ctx = ctx; 292a3bd7f05Smrg info->callbacks = (XtSelectionCallbackProc *) 293a3bd7f05Smrg __XtMalloc((unsigned) 294a3bd7f05Smrg ((size_t) count * sizeof(XtSelectionCallbackProc))); 295a3bd7f05Smrg (void) memmove((char *) info->callbacks, (char *) callbacks, 296a3bd7f05Smrg (size_t) count * sizeof(XtSelectionCallbackProc)); 297a3bd7f05Smrg info->req_closure = (XtPointer *) 298a3bd7f05Smrg __XtMalloc((unsigned) ((size_t) count * sizeof(XtPointer))); 299a3bd7f05Smrg (void) memmove((char *) info->req_closure, (char *) closures, 300a3bd7f05Smrg (size_t) count * sizeof(XtPointer)); 301a3bd7f05Smrg if (count == 1 && properties != NULL && properties[0] != None) 302a3bd7f05Smrg info->property = properties[0]; 303a3bd7f05Smrg else { 304a3bd7f05Smrg info->property = GetSelectionProperty(XtDisplay(widget)); 305a3bd7f05Smrg XDeleteProperty(XtDisplay(widget), XtWindow(widget), info->property); 306a3bd7f05Smrg } 307a3bd7f05Smrg info->proc = HandleSelectionReplies; 308a3bd7f05Smrg info->widget = widget; 309a3bd7f05Smrg info->time = time; 310a3bd7f05Smrg info->incremental = 311a3bd7f05Smrg (Boolean *) __XtMalloc((Cardinal) ((size_t) count * sizeof(Boolean))); 312a3bd7f05Smrg (void) memmove((char *) info->incremental, (char *) incremental, 313a3bd7f05Smrg (size_t) count * sizeof(Boolean)); 314a3bd7f05Smrg info->current = 0; 315a3bd7f05Smrg info->value = NULL; 316a3bd7f05Smrg return (info); 317444c061aSmrg} 318444c061aSmrg 319a3bd7f05Smrgstatic void 320a3bd7f05SmrgRequestSelectionValue(CallBackInfo info, Atom selection, Atom target) 321444c061aSmrg{ 322444c061aSmrg#ifndef DEBUG_WO_TIMERS 323444c061aSmrg XtAppContext app = XtWidgetToApplicationContext(info->widget); 324a3bd7f05Smrg 325a3bd7f05Smrg info->timeout = XtAppAddTimeOut(app, 326a3bd7f05Smrg app->selectionTimeout, ReqTimedOut, 327a3bd7f05Smrg (XtPointer) info); 328444c061aSmrg#endif 329a3bd7f05Smrg XtAddEventHandler(info->widget, (EventMask) 0, TRUE, 330a3bd7f05Smrg HandleSelectionReplies, (XtPointer) info); 331a3bd7f05Smrg XConvertSelection(info->ctx->dpy, selection, target, 332a3bd7f05Smrg info->property, XtWindow(info->widget), info->time); 333444c061aSmrg} 334444c061aSmrg 335444c061aSmrgstatic XContext selectContext = 0; 336444c061aSmrg 337a3bd7f05Smrgstatic Select 338a3bd7f05SmrgNewContext(Display *dpy, Atom selection) 339444c061aSmrg{ 340444c061aSmrg /* assert(selectContext != 0) */ 341444c061aSmrg Select ctx = XtNew(SelectRec); 342a3bd7f05Smrg 343444c061aSmrg ctx->dpy = dpy; 344444c061aSmrg ctx->selection = selection; 345444c061aSmrg ctx->widget = NULL; 346444c061aSmrg ctx->prop_list = GetPropList(dpy); 347444c061aSmrg ctx->ref_count = 0; 348444c061aSmrg ctx->free_when_done = FALSE; 349444c061aSmrg ctx->was_disowned = FALSE; 350444c061aSmrg LOCK_PROCESS; 351a3bd7f05Smrg (void) XSaveContext(dpy, (Window) selection, selectContext, (char *) ctx); 352444c061aSmrg UNLOCK_PROCESS; 353444c061aSmrg return ctx; 354444c061aSmrg} 355444c061aSmrg 356a3bd7f05Smrgstatic Select 357a3bd7f05SmrgFindCtx(Display *dpy, Atom selection) 358444c061aSmrg{ 359444c061aSmrg Select ctx; 360444c061aSmrg 361444c061aSmrg LOCK_PROCESS; 362444c061aSmrg if (selectContext == 0) 363a3bd7f05Smrg selectContext = XUniqueContext(); 364a3bd7f05Smrg if (XFindContext(dpy, (Window) selection, selectContext, (XPointer *) &ctx)) 365a3bd7f05Smrg ctx = NewContext(dpy, selection); 366444c061aSmrg UNLOCK_PROCESS; 367444c061aSmrg return ctx; 368444c061aSmrg} 369444c061aSmrg 370a3bd7f05Smrgstatic void 371a3bd7f05SmrgWidgetDestroyed(Widget widget, XtPointer closure, XtPointer data _X_UNUSED) 372444c061aSmrg{ 373444c061aSmrg Select ctx = (Select) closure; 374a3bd7f05Smrg 375444c061aSmrg if (ctx->widget == widget) { 376a3bd7f05Smrg if (ctx->free_when_done) 377a3bd7f05Smrg XtFree((char *) ctx); 378a3bd7f05Smrg else 379a3bd7f05Smrg ctx->widget = NULL; 380444c061aSmrg } 381444c061aSmrg} 382444c061aSmrg 383444c061aSmrg/* Selection Owner code */ 384444c061aSmrg 385444c061aSmrgstatic void HandleSelectionEvents(Widget, XtPointer, XEvent *, Boolean *); 386444c061aSmrg 387a3bd7f05Smrgstatic Boolean 388a3bd7f05SmrgLoseSelection(Select ctx, Widget widget, Atom selection, Time time) 389444c061aSmrg{ 390a3bd7f05Smrg if ((ctx->widget == widget) && (ctx->selection == selection) && /* paranoia */ 391a3bd7f05Smrg !ctx->was_disowned && ((time == CurrentTime) || (time >= ctx->time))) { 392a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) 0, TRUE, 393a3bd7f05Smrg HandleSelectionEvents, (XtPointer) ctx); 394a3bd7f05Smrg XtRemoveCallback(widget, XtNdestroyCallback, 395a3bd7f05Smrg WidgetDestroyed, (XtPointer) ctx); 396a3bd7f05Smrg ctx->was_disowned = TRUE; /* widget officially loses ownership */ 397a3bd7f05Smrg /* now inform widget */ 398a3bd7f05Smrg if (ctx->loses) { 399a3bd7f05Smrg if (ctx->incremental) 400a3bd7f05Smrg (*(XtLoseSelectionIncrProc) ctx->loses) 401a3bd7f05Smrg (widget, &ctx->selection, ctx->owner_closure); 402a3bd7f05Smrg else 403a3bd7f05Smrg (*ctx->loses) (widget, &ctx->selection); 404a3bd7f05Smrg } 405a3bd7f05Smrg return (TRUE); 406a3bd7f05Smrg } 407a3bd7f05Smrg else 408a3bd7f05Smrg return (FALSE); 409444c061aSmrg} 410444c061aSmrg 411444c061aSmrgstatic XContext selectWindowContext = 0; 412444c061aSmrg 413444c061aSmrg/* %%% Xlib.h should make this public! */ 414a3bd7f05Smrgtypedef int (*xErrorHandler) (Display *, XErrorEvent *); 415444c061aSmrg 416444c061aSmrgstatic xErrorHandler oldErrorHandler = NULL; 417444c061aSmrgstatic unsigned long firstProtectRequest; 418444c061aSmrgstatic Window errorWindow; 419444c061aSmrg 420a3bd7f05Smrgstatic int 421a3bd7f05SmrgLocalErrorHandler(Display *dpy, XErrorEvent *error) 422444c061aSmrg{ 423444c061aSmrg int retval; 424444c061aSmrg 425444c061aSmrg /* If BadWindow error on selection requestor, nothing to do but let 426444c061aSmrg * the transfer timeout. Otherwise, invoke saved error handler. */ 427444c061aSmrg 428444c061aSmrg LOCK_PROCESS; 429444c061aSmrg 430444c061aSmrg if (error->error_code == BadWindow && error->resourceid == errorWindow && 431a3bd7f05Smrg error->serial >= firstProtectRequest) { 432a3bd7f05Smrg UNLOCK_PROCESS; 433a3bd7f05Smrg return 0; 434444c061aSmrg } 435444c061aSmrg 436444c061aSmrg if (oldErrorHandler == NULL) { 437a3bd7f05Smrg UNLOCK_PROCESS; 438a3bd7f05Smrg return 0; /* should never happen */ 439444c061aSmrg } 440444c061aSmrg 441a3bd7f05Smrg retval = (*oldErrorHandler) (dpy, error); 442444c061aSmrg UNLOCK_PROCESS; 443444c061aSmrg return retval; 444444c061aSmrg} 445444c061aSmrg 446a3bd7f05Smrgstatic void 447a3bd7f05SmrgStartProtectedSection(Display *dpy, Window window) 448444c061aSmrg{ 449444c061aSmrg /* protect ourselves against request window being destroyed 450444c061aSmrg * before completion of transfer */ 451444c061aSmrg 452444c061aSmrg LOCK_PROCESS; 453444c061aSmrg oldErrorHandler = XSetErrorHandler(LocalErrorHandler); 454444c061aSmrg firstProtectRequest = NextRequest(dpy); 455444c061aSmrg errorWindow = window; 456444c061aSmrg UNLOCK_PROCESS; 457444c061aSmrg} 458444c061aSmrg 459a3bd7f05Smrgstatic void 460a3bd7f05SmrgEndProtectedSection(Display *dpy) 461444c061aSmrg{ 462444c061aSmrg /* flush any generated errors on requestor and 463444c061aSmrg * restore original error handler */ 464444c061aSmrg 465444c061aSmrg XSync(dpy, False); 466444c061aSmrg 467444c061aSmrg LOCK_PROCESS; 468444c061aSmrg XSetErrorHandler(oldErrorHandler); 469444c061aSmrg oldErrorHandler = NULL; 470444c061aSmrg UNLOCK_PROCESS; 471444c061aSmrg} 472444c061aSmrg 473a3bd7f05Smrgstatic void 474a3bd7f05SmrgAddHandler(Request req, EventMask mask, XtEventHandler proc, XtPointer closure) 475444c061aSmrg{ 476444c061aSmrg Display *dpy = req->ctx->dpy; 477444c061aSmrg Window window = req->requestor; 478444c061aSmrg Widget widget = XtWindowToWidget(dpy, window); 479444c061aSmrg 480a3bd7f05Smrg if (widget != NULL) 481a3bd7f05Smrg req->widget = widget; 482a3bd7f05Smrg else 483a3bd7f05Smrg widget = req->widget; 484444c061aSmrg 485444c061aSmrg if (XtWindow(widget) == window) 486a3bd7f05Smrg XtAddEventHandler(widget, mask, False, proc, closure); 487444c061aSmrg else { 488a3bd7f05Smrg RequestWindowRec *requestWindowRec; 489a3bd7f05Smrg 490a3bd7f05Smrg LOCK_PROCESS; 491a3bd7f05Smrg if (selectWindowContext == 0) 492a3bd7f05Smrg selectWindowContext = XUniqueContext(); 493a3bd7f05Smrg if (XFindContext(dpy, window, selectWindowContext, 494a3bd7f05Smrg (XPointer *) &requestWindowRec)) { 495a3bd7f05Smrg requestWindowRec = XtNew(RequestWindowRec); 496a3bd7f05Smrg requestWindowRec->active_transfer_count = 0; 497a3bd7f05Smrg (void) XSaveContext(dpy, window, selectWindowContext, 498a3bd7f05Smrg (char *) requestWindowRec); 499a3bd7f05Smrg } 500a3bd7f05Smrg UNLOCK_PROCESS; 501a3bd7f05Smrg if (requestWindowRec->active_transfer_count++ == 0) { 502a3bd7f05Smrg XtRegisterDrawable(dpy, window, widget); 503a3bd7f05Smrg XSelectInput(dpy, window, (long) mask); 504a3bd7f05Smrg } 505a3bd7f05Smrg XtAddRawEventHandler(widget, mask, FALSE, proc, closure); 506444c061aSmrg } 507444c061aSmrg} 508444c061aSmrg 509a3bd7f05Smrgstatic void 510a3bd7f05SmrgRemoveHandler(Request req, 511a3bd7f05Smrg EventMask mask, 512a3bd7f05Smrg XtEventHandler proc, 513a3bd7f05Smrg XtPointer closure) 514444c061aSmrg{ 515444c061aSmrg Display *dpy = req->ctx->dpy; 516444c061aSmrg Window window = req->requestor; 517444c061aSmrg Widget widget = req->widget; 518444c061aSmrg 519444c061aSmrg if ((XtWindowToWidget(dpy, window) == widget) && 520444c061aSmrg (XtWindow(widget) != window)) { 521a3bd7f05Smrg /* we had to hang this window onto our widget; take it off */ 522a3bd7f05Smrg RequestWindowRec *requestWindowRec; 523a3bd7f05Smrg 524a3bd7f05Smrg XtRemoveRawEventHandler(widget, mask, TRUE, proc, closure); 525a3bd7f05Smrg LOCK_PROCESS; 526a3bd7f05Smrg (void) XFindContext(dpy, window, selectWindowContext, 527a3bd7f05Smrg (XPointer *) &requestWindowRec); 528a3bd7f05Smrg UNLOCK_PROCESS; 529a3bd7f05Smrg if (--requestWindowRec->active_transfer_count == 0) { 530a3bd7f05Smrg XtUnregisterDrawable(dpy, window); 531a3bd7f05Smrg StartProtectedSection(dpy, window); 532a3bd7f05Smrg XSelectInput(dpy, window, 0L); 533a3bd7f05Smrg EndProtectedSection(dpy); 534a3bd7f05Smrg LOCK_PROCESS; 535a3bd7f05Smrg (void) XDeleteContext(dpy, window, selectWindowContext); 536a3bd7f05Smrg UNLOCK_PROCESS; 537a3bd7f05Smrg XtFree((char *) requestWindowRec); 538a3bd7f05Smrg } 539a3bd7f05Smrg } 540a3bd7f05Smrg else { 541a3bd7f05Smrg XtRemoveEventHandler(widget, mask, TRUE, proc, closure); 542444c061aSmrg } 543444c061aSmrg} 544444c061aSmrg 545a3bd7f05Smrgstatic void 546a3bd7f05SmrgOwnerTimedOut(XtPointer closure, XtIntervalId *id _X_UNUSED) 547444c061aSmrg{ 548a3bd7f05Smrg Request req = (Request) closure; 549444c061aSmrg Select ctx = req->ctx; 550444c061aSmrg 551444c061aSmrg if (ctx->incremental && (ctx->owner_cancel != NULL)) { 552a3bd7f05Smrg (*ctx->owner_cancel) (ctx->widget, &ctx->selection, 553a3bd7f05Smrg &req->target, (XtRequestId *) &req, 554a3bd7f05Smrg ctx->owner_closure); 555a3bd7f05Smrg } 556a3bd7f05Smrg else { 557a3bd7f05Smrg if (ctx->notify == NULL) 558a3bd7f05Smrg XtFree((char *) req->value); 559a3bd7f05Smrg else { 560a3bd7f05Smrg /* the requestor hasn't deleted the property, but 561a3bd7f05Smrg * the owner needs to free the value. 562a3bd7f05Smrg */ 563a3bd7f05Smrg if (ctx->incremental) 564a3bd7f05Smrg (*(XtSelectionDoneIncrProc) ctx->notify) 565a3bd7f05Smrg (ctx->widget, &ctx->selection, &req->target, 566a3bd7f05Smrg (XtRequestId *) &req, ctx->owner_closure); 567a3bd7f05Smrg else 568a3bd7f05Smrg (*ctx->notify) (ctx->widget, &ctx->selection, &req->target); 569a3bd7f05Smrg } 570a3bd7f05Smrg } 571a3bd7f05Smrg 572a3bd7f05Smrg RemoveHandler(req, (EventMask) PropertyChangeMask, 573a3bd7f05Smrg HandlePropertyGone, closure); 574a3bd7f05Smrg XtFree((char *) req); 575444c061aSmrg if (--ctx->ref_count == 0 && ctx->free_when_done) 576a3bd7f05Smrg XtFree((char *) ctx); 577444c061aSmrg} 578444c061aSmrg 579a3bd7f05Smrgstatic void 580a3bd7f05SmrgSendIncrement(Request incr) 581444c061aSmrg{ 582444c061aSmrg Display *dpy = incr->ctx->dpy; 583444c061aSmrg 5840568f49bSmrg unsigned long incrSize = (unsigned long) MAX_SELECTION_INCR(dpy); 585a3bd7f05Smrg 586444c061aSmrg if (incrSize > incr->bytelength - incr->offset) 587444c061aSmrg incrSize = incr->bytelength - incr->offset; 588444c061aSmrg StartProtectedSection(dpy, incr->requestor); 589444c061aSmrg XChangeProperty(dpy, incr->requestor, incr->property, 590a3bd7f05Smrg incr->type, incr->format, PropModeReplace, 591a3bd7f05Smrg (unsigned char *) incr->value + incr->offset, 592a3bd7f05Smrg NUMELEM((int) incrSize, incr->format)); 593444c061aSmrg EndProtectedSection(dpy); 594444c061aSmrg incr->offset += incrSize; 595444c061aSmrg} 596444c061aSmrg 597a3bd7f05Smrgstatic void 598a3bd7f05SmrgAllSent(Request req) 599444c061aSmrg{ 600444c061aSmrg Select ctx = req->ctx; 601a3bd7f05Smrg 602444c061aSmrg StartProtectedSection(ctx->dpy, req->requestor); 603444c061aSmrg XChangeProperty(ctx->dpy, req->requestor, 604a3bd7f05Smrg req->property, req->type, req->format, 605a3bd7f05Smrg PropModeReplace, (unsigned char *) NULL, 0); 606444c061aSmrg EndProtectedSection(ctx->dpy); 607444c061aSmrg req->allSent = TRUE; 608444c061aSmrg 609a3bd7f05Smrg if (ctx->notify == NULL) 610a3bd7f05Smrg XtFree((char *) req->value); 611444c061aSmrg} 612444c061aSmrg 613a3bd7f05Smrgstatic void 614a3bd7f05SmrgHandlePropertyGone(Widget widget _X_UNUSED, 615a3bd7f05Smrg XtPointer closure, 616a3bd7f05Smrg XEvent *ev, 617a3bd7f05Smrg Boolean *cont _X_UNUSED) 618444c061aSmrg{ 619444c061aSmrg XPropertyEvent *event = (XPropertyEvent *) ev; 620a3bd7f05Smrg Request req = (Request) closure; 621444c061aSmrg Select ctx = req->ctx; 622444c061aSmrg 623444c061aSmrg if ((event->type != PropertyNotify) || 624444c061aSmrg (event->state != PropertyDelete) || 625a3bd7f05Smrg (event->atom != req->property) || (event->window != req->requestor)) 626a3bd7f05Smrg return; 627444c061aSmrg#ifndef DEBUG_WO_TIMERS 628444c061aSmrg XtRemoveTimeOut(req->timeout); 629444c061aSmrg#endif 630444c061aSmrg if (req->allSent) { 631a3bd7f05Smrg if (ctx->notify) { 632a3bd7f05Smrg if (ctx->incremental) { 633a3bd7f05Smrg (*(XtSelectionDoneIncrProc) ctx->notify) 634a3bd7f05Smrg (ctx->widget, &ctx->selection, &req->target, 635a3bd7f05Smrg (XtRequestId *) &req, ctx->owner_closure); 636a3bd7f05Smrg } 637a3bd7f05Smrg else 638a3bd7f05Smrg (*ctx->notify) (ctx->widget, &ctx->selection, &req->target); 639a3bd7f05Smrg } 640a3bd7f05Smrg RemoveHandler(req, (EventMask) PropertyChangeMask, 641a3bd7f05Smrg HandlePropertyGone, closure); 642a3bd7f05Smrg XtFree((char *) req); 643a3bd7f05Smrg if (--ctx->ref_count == 0 && ctx->free_when_done) 644a3bd7f05Smrg XtFree((char *) ctx); 645a3bd7f05Smrg } 646a3bd7f05Smrg else { /* is this part of an incremental transfer? */ 647a3bd7f05Smrg if (ctx->incremental) { 648a3bd7f05Smrg if (req->bytelength == 0) 649a3bd7f05Smrg AllSent(req); 650a3bd7f05Smrg else { 651a3bd7f05Smrg unsigned long size = 652a3bd7f05Smrg (unsigned long) MAX_SELECTION_INCR(ctx->dpy); 653a3bd7f05Smrg SendIncrement(req); 654a3bd7f05Smrg (*(XtConvertSelectionIncrProc) ctx->convert) 655a3bd7f05Smrg (ctx->widget, &ctx->selection, &req->target, 656a3bd7f05Smrg &req->type, &req->value, 657a3bd7f05Smrg &req->bytelength, &req->format, 658a3bd7f05Smrg &size, ctx->owner_closure, (XtPointer *) &req); 659a3bd7f05Smrg if (req->bytelength) 660a3bd7f05Smrg req->bytelength = BYTELENGTH(req->bytelength, req->format); 661a3bd7f05Smrg req->offset = 0; 662a3bd7f05Smrg } 663a3bd7f05Smrg } 664a3bd7f05Smrg else { 665a3bd7f05Smrg if (req->offset < req->bytelength) 666a3bd7f05Smrg SendIncrement(req); 667a3bd7f05Smrg else 668a3bd7f05Smrg AllSent(req); 669a3bd7f05Smrg } 670444c061aSmrg#ifndef DEBUG_WO_TIMERS 671a3bd7f05Smrg { 672a3bd7f05Smrg XtAppContext app = XtWidgetToApplicationContext(req->widget); 673a3bd7f05Smrg 674a3bd7f05Smrg req->timeout = XtAppAddTimeOut(app, 675a3bd7f05Smrg app->selectionTimeout, OwnerTimedOut, 676a3bd7f05Smrg (XtPointer) req); 677a3bd7f05Smrg } 678444c061aSmrg#endif 679444c061aSmrg } 680444c061aSmrg} 681444c061aSmrg 682a3bd7f05Smrgstatic void 683a3bd7f05SmrgPrepareIncremental(Request req, 684a3bd7f05Smrg Widget widget, 685a3bd7f05Smrg Window window, 686a3bd7f05Smrg Atom property _X_UNUSED, 687a3bd7f05Smrg Atom target, 688a3bd7f05Smrg Atom targetType, 689a3bd7f05Smrg XtPointer value, 690a3bd7f05Smrg unsigned long length, 691a3bd7f05Smrg int format) 692444c061aSmrg{ 693a3bd7f05Smrg req->type = targetType; 694a3bd7f05Smrg req->value = value; 695a3bd7f05Smrg req->bytelength = BYTELENGTH(length, format); 696a3bd7f05Smrg req->format = format; 697a3bd7f05Smrg req->offset = 0; 698a3bd7f05Smrg req->target = target; 699a3bd7f05Smrg req->widget = widget; 700a3bd7f05Smrg req->allSent = FALSE; 701444c061aSmrg#ifndef DEBUG_WO_TIMERS 702a3bd7f05Smrg { 703a3bd7f05Smrg XtAppContext app = XtWidgetToApplicationContext(widget); 704a3bd7f05Smrg 705a3bd7f05Smrg req->timeout = XtAppAddTimeOut(app, 706a3bd7f05Smrg app->selectionTimeout, OwnerTimedOut, 707a3bd7f05Smrg (XtPointer) req); 708a3bd7f05Smrg } 709444c061aSmrg#endif 710a3bd7f05Smrg AddHandler(req, (EventMask) PropertyChangeMask, 711a3bd7f05Smrg HandlePropertyGone, (XtPointer) req); 712444c061aSmrg/* now send client INCR property */ 713a3bd7f05Smrg XChangeProperty(req->ctx->dpy, window, req->property, 714a3bd7f05Smrg req->ctx->prop_list->incr_atom, 715a3bd7f05Smrg 32, PropModeReplace, (unsigned char *) &req->bytelength, 1); 716444c061aSmrg} 717444c061aSmrg 718a3bd7f05Smrgstatic Boolean 719a3bd7f05SmrgGetConversion(Select ctx, /* logical owner */ 720a3bd7f05Smrg XSelectionRequestEvent *event, 721a3bd7f05Smrg Atom target, 722a3bd7f05Smrg Atom property, /* requestor's property */ 723a3bd7f05Smrg Widget widget) /* physical owner (receives events) */ 724a3bd7f05Smrg{ 725444c061aSmrg XtPointer value = NULL; 726444c061aSmrg unsigned long length; 727444c061aSmrg int format; 728444c061aSmrg Atom targetType; 729444c061aSmrg Request req = XtNew(RequestRec); 730444c061aSmrg Boolean timestamp_target = (target == ctx->prop_list->timestamp_atom); 731444c061aSmrg 732444c061aSmrg req->ctx = ctx; 733444c061aSmrg req->event = *event; 734444c061aSmrg req->property = property; 735444c061aSmrg req->requestor = event->requestor; 736444c061aSmrg 737444c061aSmrg if (timestamp_target) { 738a3bd7f05Smrg value = __XtMalloc(sizeof(long)); 739a3bd7f05Smrg *(long *) value = (long) ctx->time; 740a3bd7f05Smrg targetType = XA_INTEGER; 741a3bd7f05Smrg length = 1; 742a3bd7f05Smrg format = 32; 743444c061aSmrg } 744444c061aSmrg else { 745a3bd7f05Smrg ctx->ref_count++; 746a3bd7f05Smrg if (ctx->incremental == TRUE) { 747a3bd7f05Smrg unsigned long size = (unsigned long) MAX_SELECTION_INCR(ctx->dpy); 748a3bd7f05Smrg 749a3bd7f05Smrg if ((*(XtConvertSelectionIncrProc) ctx->convert) 750a3bd7f05Smrg (ctx->widget, &event->selection, &target, 751a3bd7f05Smrg &targetType, &value, &length, &format, 752a3bd7f05Smrg &size, ctx->owner_closure, (XtRequestId *) &req) 753a3bd7f05Smrg == FALSE) { 754a3bd7f05Smrg XtFree((char *) req); 755a3bd7f05Smrg ctx->ref_count--; 756a3bd7f05Smrg return (FALSE); 757a3bd7f05Smrg } 758a3bd7f05Smrg StartProtectedSection(ctx->dpy, event->requestor); 759a3bd7f05Smrg PrepareIncremental(req, widget, event->requestor, property, 760a3bd7f05Smrg target, targetType, value, length, format); 761a3bd7f05Smrg return (TRUE); 762a3bd7f05Smrg } 763a3bd7f05Smrg ctx->req = req; 764a3bd7f05Smrg if ((*ctx->convert) (ctx->widget, &event->selection, &target, 765a3bd7f05Smrg &targetType, &value, &length, &format) == FALSE) { 766a3bd7f05Smrg XtFree((char *) req); 767a3bd7f05Smrg ctx->req = NULL; 768a3bd7f05Smrg ctx->ref_count--; 769a3bd7f05Smrg return (FALSE); 770a3bd7f05Smrg } 771a3bd7f05Smrg ctx->req = NULL; 772444c061aSmrg } 773444c061aSmrg StartProtectedSection(ctx->dpy, event->requestor); 774a3bd7f05Smrg if (BYTELENGTH(length, format) <= 775a3bd7f05Smrg (unsigned long) MAX_SELECTION_INCR(ctx->dpy)) { 776a3bd7f05Smrg if (!timestamp_target) { 777a3bd7f05Smrg if (ctx->notify != NULL) { 778a3bd7f05Smrg req->target = target; 779a3bd7f05Smrg req->widget = widget; 780a3bd7f05Smrg req->allSent = TRUE; 781444c061aSmrg#ifndef DEBUG_WO_TIMERS 782a3bd7f05Smrg { 783a3bd7f05Smrg XtAppContext app = 784a3bd7f05Smrg XtWidgetToApplicationContext(req->widget); 785a3bd7f05Smrg req->timeout = 786a3bd7f05Smrg XtAppAddTimeOut(app, app->selectionTimeout, 787a3bd7f05Smrg OwnerTimedOut, (XtPointer) req); 788a3bd7f05Smrg } 789444c061aSmrg#endif 790a3bd7f05Smrg AddHandler(req, (EventMask) PropertyChangeMask, 791a3bd7f05Smrg HandlePropertyGone, (XtPointer) req); 792a3bd7f05Smrg } 793a3bd7f05Smrg else 794a3bd7f05Smrg ctx->ref_count--; 795444c061aSmrg } 796a3bd7f05Smrg XChangeProperty(ctx->dpy, event->requestor, property, 797a3bd7f05Smrg targetType, format, PropModeReplace, 798a3bd7f05Smrg (unsigned char *) value, (int) length); 799a3bd7f05Smrg /* free storage for client if no notify proc */ 800a3bd7f05Smrg if (timestamp_target || ctx->notify == NULL) { 801a3bd7f05Smrg XtFree((char *) value); 802a3bd7f05Smrg XtFree((char *) req); 803a3bd7f05Smrg } 804a3bd7f05Smrg } 805a3bd7f05Smrg else { 806a3bd7f05Smrg PrepareIncremental(req, widget, event->requestor, property, 807a3bd7f05Smrg target, targetType, value, length, format); 808a3bd7f05Smrg } 809a3bd7f05Smrg return (TRUE); 810444c061aSmrg} 811444c061aSmrg 812a3bd7f05Smrgstatic void 813a3bd7f05SmrgHandleSelectionEvents(Widget widget, 814a3bd7f05Smrg XtPointer closure, 815a3bd7f05Smrg XEvent *event, 816a3bd7f05Smrg Boolean *cont _X_UNUSED) 817444c061aSmrg{ 818444c061aSmrg Select ctx; 819444c061aSmrg XSelectionEvent ev; 820444c061aSmrg Atom target; 821444c061aSmrg 822444c061aSmrg ctx = (Select) closure; 823444c061aSmrg switch (event->type) { 824a3bd7f05Smrg case SelectionClear: 825a3bd7f05Smrg /* if this event is not for the selection we registered for, 826a3bd7f05Smrg * don't do anything */ 827a3bd7f05Smrg if (ctx->selection != event->xselectionclear.selection || 828a3bd7f05Smrg ctx->serial > event->xselectionclear.serial) 829a3bd7f05Smrg break; 830a3bd7f05Smrg (void) LoseSelection(ctx, widget, event->xselectionclear.selection, 831a3bd7f05Smrg event->xselectionclear.time); 832a3bd7f05Smrg break; 833a3bd7f05Smrg case SelectionRequest: 834a3bd7f05Smrg /* if this event is not for the selection we registered for, 835a3bd7f05Smrg * don't do anything */ 836a3bd7f05Smrg if (ctx->selection != event->xselectionrequest.selection) 837a3bd7f05Smrg break; 838a3bd7f05Smrg ev.type = SelectionNotify; 839a3bd7f05Smrg ev.display = event->xselectionrequest.display; 840a3bd7f05Smrg 841a3bd7f05Smrg ev.requestor = event->xselectionrequest.requestor; 842a3bd7f05Smrg ev.selection = event->xselectionrequest.selection; 843a3bd7f05Smrg ev.time = event->xselectionrequest.time; 844a3bd7f05Smrg ev.target = event->xselectionrequest.target; 845a3bd7f05Smrg if (event->xselectionrequest.property == None) /* obsolete requestor */ 846a3bd7f05Smrg event->xselectionrequest.property = event->xselectionrequest.target; 847a3bd7f05Smrg if (ctx->widget != widget || ctx->was_disowned 848a3bd7f05Smrg || ((event->xselectionrequest.time != CurrentTime) 849a3bd7f05Smrg && (event->xselectionrequest.time < ctx->time))) { 850a3bd7f05Smrg ev.property = None; 851a3bd7f05Smrg StartProtectedSection(ev.display, ev.requestor); 852a3bd7f05Smrg } 853a3bd7f05Smrg else { 854a3bd7f05Smrg if (ev.target == ctx->prop_list->indirect_atom) { 855a3bd7f05Smrg IndirectPair *p; 856a3bd7f05Smrg int format; 857a3bd7f05Smrg unsigned long bytesafter, length; 858a3bd7f05Smrg unsigned char *value = NULL; 859a3bd7f05Smrg int count; 860a3bd7f05Smrg Boolean writeback = FALSE; 861a3bd7f05Smrg 862a3bd7f05Smrg ev.property = event->xselectionrequest.property; 863a3bd7f05Smrg StartProtectedSection(ev.display, ev.requestor); 864a3bd7f05Smrg if (XGetWindowProperty(ev.display, ev.requestor, 865a3bd7f05Smrg event->xselectionrequest.property, 0L, 866a3bd7f05Smrg 1000000, False, (Atom) AnyPropertyType, 867a3bd7f05Smrg &target, &format, &length, &bytesafter, 868a3bd7f05Smrg &value) == Success) 869a3bd7f05Smrg count = 870a3bd7f05Smrg (int) (BYTELENGTH(length, format) / 871a3bd7f05Smrg sizeof(IndirectPair)); 872a3bd7f05Smrg else 873a3bd7f05Smrg count = 0; 874a3bd7f05Smrg for (p = (IndirectPair *) value; count; p++, count--) { 875a3bd7f05Smrg EndProtectedSection(ctx->dpy); 876a3bd7f05Smrg if (!GetConversion(ctx, (XSelectionRequestEvent *) event, 877a3bd7f05Smrg p->target, p->property, widget)) { 878a3bd7f05Smrg 879a3bd7f05Smrg p->target = None; 880a3bd7f05Smrg writeback = TRUE; 881a3bd7f05Smrg StartProtectedSection(ctx->dpy, ev.requestor); 882a3bd7f05Smrg } 883a3bd7f05Smrg } 884a3bd7f05Smrg if (writeback) 885a3bd7f05Smrg XChangeProperty(ev.display, ev.requestor, 886a3bd7f05Smrg event->xselectionrequest.property, target, 887a3bd7f05Smrg format, PropModeReplace, value, 888a3bd7f05Smrg (int) length); 889a3bd7f05Smrg XFree((char *) value); 890a3bd7f05Smrg } 891a3bd7f05Smrg else { /* not multiple */ 892a3bd7f05Smrg 893a3bd7f05Smrg if (GetConversion(ctx, (XSelectionRequestEvent *) event, 894a3bd7f05Smrg event->xselectionrequest.target, 895a3bd7f05Smrg event->xselectionrequest.property, widget)) 896a3bd7f05Smrg ev.property = event->xselectionrequest.property; 897a3bd7f05Smrg else { 898a3bd7f05Smrg ev.property = None; 899a3bd7f05Smrg StartProtectedSection(ctx->dpy, ev.requestor); 900a3bd7f05Smrg } 901a3bd7f05Smrg } 902a3bd7f05Smrg } 903a3bd7f05Smrg (void) XSendEvent(ctx->dpy, ev.requestor, False, (unsigned long) NULL, 904a3bd7f05Smrg (XEvent *) &ev); 905a3bd7f05Smrg 906a3bd7f05Smrg EndProtectedSection(ctx->dpy); 907a3bd7f05Smrg 908a3bd7f05Smrg break; 909444c061aSmrg } 910444c061aSmrg} 911444c061aSmrg 912a3bd7f05Smrgstatic Boolean 913a3bd7f05SmrgOwnSelection(Widget widget, 914a3bd7f05Smrg Atom selection, 915a3bd7f05Smrg Time time, 916a3bd7f05Smrg XtConvertSelectionProc convert, 917a3bd7f05Smrg XtLoseSelectionProc lose, 918a3bd7f05Smrg XtSelectionDoneProc notify, 919a3bd7f05Smrg XtCancelConvertSelectionProc cancel, 920a3bd7f05Smrg XtPointer closure, 921a3bd7f05Smrg Boolean incremental) 922444c061aSmrg{ 923444c061aSmrg Select ctx; 924444c061aSmrg Select oldctx = NULL; 925444c061aSmrg 926a3bd7f05Smrg if (!XtIsRealized(widget)) 927a3bd7f05Smrg return False; 928444c061aSmrg 929444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 930444c061aSmrg if (ctx->widget != widget || ctx->time != time || 931a3bd7f05Smrg ctx->ref_count || ctx->was_disowned) { 932a3bd7f05Smrg Boolean replacement = FALSE; 933a3bd7f05Smrg Window window = XtWindow(widget); 934a3bd7f05Smrg unsigned long serial = XNextRequest(ctx->dpy); 935a3bd7f05Smrg 936444c061aSmrg XSetSelectionOwner(ctx->dpy, selection, window, time); 937444c061aSmrg if (XGetSelectionOwner(ctx->dpy, selection) != window) 938a3bd7f05Smrg return FALSE; 939a3bd7f05Smrg if (ctx->ref_count) { /* exchange is in-progress */ 940444c061aSmrg#ifdef DEBUG_ACTIVE 941a3bd7f05Smrg printf 942a3bd7f05Smrg ("Active exchange for widget \"%s\"; selection=0x%lx, ref_count=%d\n", 943a3bd7f05Smrg XtName(widget), (long) selection, ctx->ref_count); 944444c061aSmrg#endif 945a3bd7f05Smrg if (ctx->widget != widget || 946a3bd7f05Smrg ctx->convert != convert || 947a3bd7f05Smrg ctx->loses != lose || 948a3bd7f05Smrg ctx->notify != notify || 949a3bd7f05Smrg ctx->owner_cancel != cancel || 950a3bd7f05Smrg ctx->incremental != incremental || 951a3bd7f05Smrg ctx->owner_closure != closure) { 952a3bd7f05Smrg if (ctx->widget == widget) { 953a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) 0, TRUE, 954a3bd7f05Smrg HandleSelectionEvents, 955a3bd7f05Smrg (XtPointer) ctx); 956a3bd7f05Smrg XtRemoveCallback(widget, XtNdestroyCallback, 957a3bd7f05Smrg WidgetDestroyed, (XtPointer) ctx); 958a3bd7f05Smrg replacement = TRUE; 959a3bd7f05Smrg } 960a3bd7f05Smrg else if (!ctx->was_disowned) { 961a3bd7f05Smrg oldctx = ctx; 962a3bd7f05Smrg } 963a3bd7f05Smrg ctx->free_when_done = TRUE; 964a3bd7f05Smrg ctx = NewContext(XtDisplay(widget), selection); 965a3bd7f05Smrg } 966a3bd7f05Smrg else if (!ctx->was_disowned) { /* current owner is new owner */ 967a3bd7f05Smrg ctx->time = time; 968a3bd7f05Smrg return TRUE; 969a3bd7f05Smrg } 970a3bd7f05Smrg } 971a3bd7f05Smrg if (ctx->widget != widget || ctx->was_disowned || replacement) { 972a3bd7f05Smrg if (ctx->widget && !ctx->was_disowned && !replacement) { 973a3bd7f05Smrg oldctx = ctx; 974a3bd7f05Smrg oldctx->free_when_done = TRUE; 975a3bd7f05Smrg ctx = NewContext(XtDisplay(widget), selection); 976a3bd7f05Smrg } 977a3bd7f05Smrg XtAddEventHandler(widget, (EventMask) 0, TRUE, 978a3bd7f05Smrg HandleSelectionEvents, (XtPointer) ctx); 979a3bd7f05Smrg XtAddCallback(widget, XtNdestroyCallback, 980a3bd7f05Smrg WidgetDestroyed, (XtPointer) ctx); 981a3bd7f05Smrg } 982a3bd7f05Smrg ctx->widget = widget; /* Selection offically changes hands. */ 983a3bd7f05Smrg ctx->time = time; 984a3bd7f05Smrg ctx->serial = serial; 985444c061aSmrg } 986444c061aSmrg ctx->convert = convert; 987444c061aSmrg ctx->loses = lose; 988444c061aSmrg ctx->notify = notify; 989444c061aSmrg ctx->owner_cancel = cancel; 9900568f49bSmrg XtSetBit(ctx->incremental, incremental); 991444c061aSmrg ctx->owner_closure = closure; 992444c061aSmrg ctx->was_disowned = FALSE; 993444c061aSmrg 994444c061aSmrg /* Defer calling the previous selection owner's lose selection procedure 995444c061aSmrg * until the new selection is established, to allow the previous 996444c061aSmrg * selection owner to ask for the new selection to be converted in 997444c061aSmrg * the lose selection procedure. The context pointer is the closure 998444c061aSmrg * of the event handler and the destroy callback, so the old context 999444c061aSmrg * pointer and the record contents must be preserved for LoseSelection. 1000444c061aSmrg */ 1001444c061aSmrg if (oldctx) { 1002a3bd7f05Smrg (void) LoseSelection(oldctx, oldctx->widget, selection, oldctx->time); 1003a3bd7f05Smrg if (!oldctx->ref_count && oldctx->free_when_done) 1004a3bd7f05Smrg XtFree((char *) oldctx); 1005444c061aSmrg } 1006444c061aSmrg return TRUE; 1007444c061aSmrg} 1008444c061aSmrg 1009a3bd7f05SmrgBoolean 1010a3bd7f05SmrgXtOwnSelection(Widget widget, 1011a3bd7f05Smrg Atom selection, 1012a3bd7f05Smrg Time time, 1013a3bd7f05Smrg XtConvertSelectionProc convert, 1014a3bd7f05Smrg XtLoseSelectionProc lose, 1015a3bd7f05Smrg XtSelectionDoneProc notify) 1016444c061aSmrg{ 1017444c061aSmrg Boolean retval; 1018a3bd7f05Smrg 1019444c061aSmrg WIDGET_TO_APPCON(widget); 1020444c061aSmrg 1021444c061aSmrg LOCK_APP(app); 1022444c061aSmrg retval = OwnSelection(widget, selection, time, convert, lose, notify, 1023a3bd7f05Smrg (XtCancelConvertSelectionProc) NULL, 1024a3bd7f05Smrg (XtPointer) NULL, FALSE); 1025444c061aSmrg UNLOCK_APP(app); 1026444c061aSmrg return retval; 1027444c061aSmrg} 1028444c061aSmrg 1029a3bd7f05SmrgBoolean 1030a3bd7f05SmrgXtOwnSelectionIncremental(Widget widget, 1031a3bd7f05Smrg Atom selection, 1032a3bd7f05Smrg Time time, 1033a3bd7f05Smrg XtConvertSelectionIncrProc convert, 1034a3bd7f05Smrg XtLoseSelectionIncrProc lose, 1035a3bd7f05Smrg XtSelectionDoneIncrProc notify, 1036a3bd7f05Smrg XtCancelConvertSelectionProc cancel, 1037a3bd7f05Smrg XtPointer closure) 1038444c061aSmrg{ 1039444c061aSmrg Boolean retval; 1040a3bd7f05Smrg 1041444c061aSmrg WIDGET_TO_APPCON(widget); 1042444c061aSmrg 1043444c061aSmrg LOCK_APP(app); 1044444c061aSmrg retval = OwnSelection(widget, selection, time, 1045a3bd7f05Smrg (XtConvertSelectionProc) convert, 1046a3bd7f05Smrg (XtLoseSelectionProc) lose, 1047a3bd7f05Smrg (XtSelectionDoneProc) notify, cancel, closure, TRUE); 1048444c061aSmrg UNLOCK_APP(app); 1049444c061aSmrg return retval; 1050444c061aSmrg} 1051444c061aSmrg 1052a3bd7f05Smrgvoid 1053a3bd7f05SmrgXtDisownSelection(Widget widget, Atom selection, Time time) 1054444c061aSmrg{ 1055444c061aSmrg Select ctx; 1056a3bd7f05Smrg 1057444c061aSmrg WIDGET_TO_APPCON(widget); 1058444c061aSmrg 1059444c061aSmrg LOCK_APP(app); 1060444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 1061444c061aSmrg if (LoseSelection(ctx, widget, selection, time)) 1062a3bd7f05Smrg XSetSelectionOwner(XtDisplay(widget), selection, None, time); 1063444c061aSmrg UNLOCK_APP(app); 1064444c061aSmrg} 1065444c061aSmrg 1066444c061aSmrg/* Selection Requestor code */ 1067444c061aSmrg 1068a3bd7f05Smrgstatic Boolean 1069a3bd7f05SmrgIsINCRtype(CallBackInfo info, Window window, Atom prop) 1070444c061aSmrg{ 1071444c061aSmrg unsigned long bytesafter; 1072444c061aSmrg unsigned long length; 1073444c061aSmrg int format; 1074444c061aSmrg Atom type; 1075444c061aSmrg unsigned char *value; 1076444c061aSmrg 1077a3bd7f05Smrg if (prop == None) 1078a3bd7f05Smrg return False; 1079444c061aSmrg 10809e7bcd65Smrg if (XGetWindowProperty(XtDisplay(info->widget), window, prop, 0L, 0L, 1081a3bd7f05Smrg False, info->ctx->prop_list->incr_atom, &type, 1082a3bd7f05Smrg &format, &length, &bytesafter, &value) != Success) 1083a3bd7f05Smrg return False; 1084444c061aSmrg 1085444c061aSmrg return (type == info->ctx->prop_list->incr_atom); 1086444c061aSmrg} 1087444c061aSmrg 1088a3bd7f05Smrgstatic void 1089a3bd7f05SmrgReqCleanup(Widget widget, 1090a3bd7f05Smrg XtPointer closure, 1091a3bd7f05Smrg XEvent *ev, 1092a3bd7f05Smrg Boolean *cont _X_UNUSED) 1093444c061aSmrg{ 1094a3bd7f05Smrg CallBackInfo info = (CallBackInfo) closure; 1095444c061aSmrg unsigned long bytesafter, length; 1096444c061aSmrg int format; 1097444c061aSmrg Atom target; 1098444c061aSmrg 1099444c061aSmrg if (ev->type == SelectionNotify) { 1100a3bd7f05Smrg XSelectionEvent *event = (XSelectionEvent *) ev; 1101a3bd7f05Smrg 1102a3bd7f05Smrg if (!MATCH_SELECT(event, info)) 1103a3bd7f05Smrg return; /* not really for us */ 1104a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) 0, TRUE, 1105a3bd7f05Smrg ReqCleanup, (XtPointer) info); 1106a3bd7f05Smrg if (IsINCRtype(info, XtWindow(widget), event->property)) { 1107a3bd7f05Smrg info->proc = HandleGetIncrement; 1108a3bd7f05Smrg XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask, 1109a3bd7f05Smrg FALSE, ReqCleanup, (XtPointer) info); 1110a3bd7f05Smrg } 1111a3bd7f05Smrg else { 1112a3bd7f05Smrg if (event->property != None) 1113a3bd7f05Smrg XDeleteProperty(event->display, XtWindow(widget), 1114a3bd7f05Smrg event->property); 1115a3bd7f05Smrg FreeSelectionProperty(XtDisplay(widget), info->property); 1116a3bd7f05Smrg FreeInfo(info); 1117a3bd7f05Smrg } 1118a3bd7f05Smrg } 1119a3bd7f05Smrg else if ((ev->type == PropertyNotify) && 1120a3bd7f05Smrg (ev->xproperty.state == PropertyNewValue) && 1121a3bd7f05Smrg (ev->xproperty.atom == info->property)) { 1122a3bd7f05Smrg XPropertyEvent *event = (XPropertyEvent *) ev; 1123a3bd7f05Smrg char *value = NULL; 1124a3bd7f05Smrg 1125a3bd7f05Smrg if (XGetWindowProperty(event->display, XtWindow(widget), 1126a3bd7f05Smrg event->atom, 0L, 1000000, True, AnyPropertyType, 1127a3bd7f05Smrg &target, &format, &length, &bytesafter, 1128a3bd7f05Smrg (unsigned char **) &value) == Success) { 1129a3bd7f05Smrg XFree(value); 1130a3bd7f05Smrg if (length == 0) { 1131a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, 1132a3bd7f05Smrg FALSE, ReqCleanup, (XtPointer) info); 1133a3bd7f05Smrg FreeSelectionProperty(XtDisplay(widget), info->property); 1134a3bd7f05Smrg XtFree(info->value); /* requestor never got this, so free now */ 1135a3bd7f05Smrg FreeInfo(info); 1136a3bd7f05Smrg } 1137a3bd7f05Smrg } 1138444c061aSmrg } 1139444c061aSmrg} 1140444c061aSmrg 1141a3bd7f05Smrgstatic void 1142a3bd7f05SmrgReqTimedOut(XtPointer closure, XtIntervalId *id _X_UNUSED) 1143444c061aSmrg{ 1144444c061aSmrg XtPointer value = NULL; 1145444c061aSmrg unsigned long length = 0; 1146444c061aSmrg int format = 8; 1147444c061aSmrg Atom resulttype = XT_CONVERT_FAIL; 1148a3bd7f05Smrg CallBackInfo info = (CallBackInfo) closure; 1149444c061aSmrg unsigned long bytesafter; 1150444c061aSmrg unsigned long proplength; 1151444c061aSmrg Atom type; 1152444c061aSmrg 1153444c061aSmrg if (*info->target == info->ctx->prop_list->indirect_atom) { 1154a3bd7f05Smrg IndirectPair *pairs = NULL; 1155a3bd7f05Smrg 1156a3bd7f05Smrg if (XGetWindowProperty(XtDisplay(info->widget), XtWindow(info->widget), 1157a3bd7f05Smrg info->property, 0L, 10000000, True, 1158a3bd7f05Smrg AnyPropertyType, &type, &format, &proplength, 1159a3bd7f05Smrg &bytesafter, (unsigned char **) &pairs) 1160a3bd7f05Smrg == Success) { 1161a3bd7f05Smrg XtPointer *c; 1162a3bd7f05Smrg int i; 1163a3bd7f05Smrg 1164a3bd7f05Smrg XFree(pairs); 1165a3bd7f05Smrg for (proplength = proplength / IndirectPairWordSize, i = 0, 1166a3bd7f05Smrg c = info->req_closure; proplength; proplength--, c++, i++) 1167a3bd7f05Smrg (*info->callbacks[i]) (info->widget, *c, &info->ctx->selection, 1168a3bd7f05Smrg &resulttype, value, &length, &format); 1169a3bd7f05Smrg } 1170a3bd7f05Smrg } 1171a3bd7f05Smrg else { 1172a3bd7f05Smrg (*info->callbacks[0]) (info->widget, *info->req_closure, 1173a3bd7f05Smrg &info->ctx->selection, &resulttype, value, 1174a3bd7f05Smrg &length, &format); 1175444c061aSmrg } 1176444c061aSmrg 1177444c061aSmrg /* change event handlers for straggler events */ 1178a3bd7f05Smrg if (info->proc == (XtEventHandler) HandleSelectionReplies) { 1179a3bd7f05Smrg XtRemoveEventHandler(info->widget, (EventMask) 0, 1180a3bd7f05Smrg TRUE, info->proc, (XtPointer) info); 1181a3bd7f05Smrg XtAddEventHandler(info->widget, (EventMask) 0, TRUE, 1182a3bd7f05Smrg ReqCleanup, (XtPointer) info); 1183a3bd7f05Smrg } 1184a3bd7f05Smrg else { 1185a3bd7f05Smrg XtRemoveEventHandler(info->widget, (EventMask) PropertyChangeMask, 1186a3bd7f05Smrg FALSE, info->proc, (XtPointer) info); 1187a3bd7f05Smrg XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask, 1188a3bd7f05Smrg FALSE, ReqCleanup, (XtPointer) info); 1189444c061aSmrg } 1190444c061aSmrg 1191444c061aSmrg} 1192444c061aSmrg 1193a3bd7f05Smrgstatic void 1194a3bd7f05SmrgHandleGetIncrement(Widget widget, 1195a3bd7f05Smrg XtPointer closure, 1196a3bd7f05Smrg XEvent *ev, 1197a3bd7f05Smrg Boolean *cont _X_UNUSED) 1198444c061aSmrg{ 1199444c061aSmrg XPropertyEvent *event = (XPropertyEvent *) ev; 1200444c061aSmrg CallBackInfo info = (CallBackInfo) closure; 1201444c061aSmrg Select ctx = info->ctx; 1202444c061aSmrg char *value; 1203444c061aSmrg unsigned long bytesafter; 1204444c061aSmrg unsigned long length; 1205444c061aSmrg int bad; 1206444c061aSmrg int n = info->current; 1207444c061aSmrg 1208444c061aSmrg if ((event->state != PropertyNewValue) || (event->atom != info->property)) 1209a3bd7f05Smrg return; 1210444c061aSmrg 1211444c061aSmrg bad = XGetWindowProperty(event->display, XtWindow(widget), 1212a3bd7f05Smrg event->atom, 0L, 1213a3bd7f05Smrg 10000000, True, AnyPropertyType, &info->type, 1214a3bd7f05Smrg &info->format, &length, &bytesafter, 1215a3bd7f05Smrg (unsigned char **)&value); 1216444c061aSmrg if (bad) 1217a3bd7f05Smrg return; 1218444c061aSmrg#ifndef DEBUG_WO_TIMERS 1219444c061aSmrg XtRemoveTimeOut(info->timeout); 1220444c061aSmrg#endif 1221444c061aSmrg if (length == 0) { 1222a3bd7f05Smrg unsigned long u_offset = NUMELEM2(info->offset, info->format); 1223a3bd7f05Smrg 1224a3bd7f05Smrg (*info->callbacks[n]) (widget, *info->req_closure, &ctx->selection, 1225a3bd7f05Smrg &info->type, 1226a3bd7f05Smrg (info->offset == 0 ? value : info->value), 1227a3bd7f05Smrg &u_offset, &info->format); 1228a3bd7f05Smrg /* assert ((info->offset != 0) == (info->incremental[n]) */ 1229a3bd7f05Smrg if (info->offset != 0) 1230a3bd7f05Smrg XFree(value); 1231a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, 1232a3bd7f05Smrg HandleGetIncrement, (XtPointer) info); 1233a3bd7f05Smrg FreeSelectionProperty(event->display, info->property); 1234a3bd7f05Smrg 1235a3bd7f05Smrg FreeInfo(info); 1236a3bd7f05Smrg } 1237a3bd7f05Smrg else { /* add increment to collection */ 1238a3bd7f05Smrg if (info->incremental[n]) { 1239444c061aSmrg#ifdef XT_COPY_SELECTION 1240a3bd7f05Smrg int size = (int) BYTELENGTH(length, info->format) + 1; 1241a3bd7f05Smrg char *tmp = __XtMalloc((Cardinal) size); 1242a3bd7f05Smrg 1243a3bd7f05Smrg (void) memmove(tmp, value, (size_t) size); 1244a3bd7f05Smrg XFree(value); 1245a3bd7f05Smrg value = tmp; 1246444c061aSmrg#endif 1247a3bd7f05Smrg (*info->callbacks[n]) (widget, *info->req_closure, &ctx->selection, 1248a3bd7f05Smrg &info->type, value, &length, &info->format); 1249a3bd7f05Smrg } 1250a3bd7f05Smrg else { 1251a3bd7f05Smrg int size = (int) BYTELENGTH(length, info->format); 1252a3bd7f05Smrg 1253a3bd7f05Smrg if (info->offset + size > info->bytelength) { 1254a3bd7f05Smrg /* allocate enough for this and the next increment */ 1255a3bd7f05Smrg info->bytelength = info->offset + size * 2; 1256a3bd7f05Smrg info->value = XtRealloc(info->value, 1257a3bd7f05Smrg (Cardinal) info->bytelength); 1258a3bd7f05Smrg } 1259a3bd7f05Smrg (void) memmove(&info->value[info->offset], value, (size_t) size); 1260a3bd7f05Smrg info->offset += size; 1261a3bd7f05Smrg XFree(value); 1262a3bd7f05Smrg } 1263a3bd7f05Smrg /* reset timer */ 1264444c061aSmrg#ifndef DEBUG_WO_TIMERS 1265a3bd7f05Smrg { 1266a3bd7f05Smrg XtAppContext app = XtWidgetToApplicationContext(info->widget); 1267a3bd7f05Smrg 1268a3bd7f05Smrg info->timeout = XtAppAddTimeOut(app, 1269a3bd7f05Smrg app->selectionTimeout, ReqTimedOut, 1270a3bd7f05Smrg (XtPointer) info); 1271a3bd7f05Smrg } 1272444c061aSmrg#endif 1273a3bd7f05Smrg } 1274444c061aSmrg} 1275444c061aSmrg 1276a3bd7f05Smrgstatic void 1277a3bd7f05SmrgHandleNone(Widget widget, 1278a3bd7f05Smrg XtSelectionCallbackProc callback, 1279a3bd7f05Smrg XtPointer closure, 1280a3bd7f05Smrg Atom selection) 1281444c061aSmrg{ 1282444c061aSmrg unsigned long length = 0; 1283444c061aSmrg int format = 8; 1284444c061aSmrg Atom type = None; 1285444c061aSmrg 1286a3bd7f05Smrg (*callback) (widget, closure, &selection, &type, NULL, &length, &format); 1287444c061aSmrg} 1288444c061aSmrg 1289a3bd7f05Smrgstatic unsigned long 1290a3bd7f05SmrgIncrPropSize(Widget widget, 1291a3bd7f05Smrg unsigned char *value, 1292a3bd7f05Smrg int format, 1293a3bd7f05Smrg unsigned long length) 1294444c061aSmrg{ 1295444c061aSmrg if (format == 32) { 1296a3bd7f05Smrg unsigned long size; 1297a3bd7f05Smrg 1298a3bd7f05Smrg size = ((unsigned long *) value)[length - 1]; /* %%% what order for longs? */ 1299a3bd7f05Smrg return size; 1300444c061aSmrg } 1301444c061aSmrg else { 1302a3bd7f05Smrg XtAppWarningMsg(XtWidgetToApplicationContext(widget), 1303a3bd7f05Smrg "badFormat", "xtGetSelectionValue", XtCXtToolkitError, 1304a3bd7f05Smrg "Selection owner returned type INCR property with format != 32", 1305a3bd7f05Smrg NULL, NULL); 1306a3bd7f05Smrg return 0; 1307444c061aSmrg } 1308444c061aSmrg} 1309444c061aSmrg 1310444c061aSmrgstatic 1311a3bd7f05Smrg Boolean 1312a3bd7f05SmrgHandleNormal(Display *dpy, 1313a3bd7f05Smrg Widget widget, 1314a3bd7f05Smrg Atom property, 1315a3bd7f05Smrg CallBackInfo info, 1316a3bd7f05Smrg XtPointer closure, 1317a3bd7f05Smrg Atom selection) 1318444c061aSmrg{ 1319444c061aSmrg unsigned long bytesafter; 1320444c061aSmrg unsigned long length; 1321444c061aSmrg int format; 1322444c061aSmrg Atom type; 13239e7bcd65Smrg unsigned char *value = NULL; 1324444c061aSmrg int number = info->current; 1325444c061aSmrg 13269e7bcd65Smrg if (XGetWindowProperty(dpy, XtWindow(widget), property, 0L, 10000000, 1327a3bd7f05Smrg False, AnyPropertyType, &type, &format, &length, 1328a3bd7f05Smrg &bytesafter, &value) != Success) 1329a3bd7f05Smrg return FALSE; 1330444c061aSmrg 1331444c061aSmrg if (type == info->ctx->prop_list->incr_atom) { 1332a3bd7f05Smrg unsigned long size = IncrPropSize(widget, value, format, length); 1333a3bd7f05Smrg 1334a3bd7f05Smrg XFree((char *) value); 1335a3bd7f05Smrg if (info->property != property) { 1336a3bd7f05Smrg /* within MULTIPLE */ 1337a3bd7f05Smrg CallBackInfo ninfo; 1338a3bd7f05Smrg 1339a3bd7f05Smrg ninfo = MakeInfo(info->ctx, &info->callbacks[number], 1340a3bd7f05Smrg &info->req_closure[number], 1, widget, 1341a3bd7f05Smrg info->time, &info->incremental[number], &property); 1342a3bd7f05Smrg ninfo->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom)); 1343a3bd7f05Smrg *ninfo->target = info->target[number + 1]; 1344a3bd7f05Smrg info = ninfo; 1345a3bd7f05Smrg } 1346a3bd7f05Smrg HandleIncremental(dpy, widget, property, info, size); 1347a3bd7f05Smrg return FALSE; 1348444c061aSmrg } 1349444c061aSmrg 1350444c061aSmrg XDeleteProperty(dpy, XtWindow(widget), property); 1351444c061aSmrg#ifdef XT_COPY_SELECTION 1352a3bd7f05Smrg if (value) { /* it could have been deleted after the SelectionNotify */ 1353a3bd7f05Smrg int size = (int) BYTELENGTH(length, info->format) + 1; 1354a3bd7f05Smrg char *tmp = __XtMalloc((Cardinal) size); 1355a3bd7f05Smrg 1356a3bd7f05Smrg (void) memmove(tmp, value, (size_t) size); 1357a3bd7f05Smrg XFree(value); 1358a3bd7f05Smrg value = (unsigned char *) tmp; 1359444c061aSmrg } 1360444c061aSmrg#endif 1361a3bd7f05Smrg (*info->callbacks[number]) (widget, closure, &selection, 1362a3bd7f05Smrg &type, (XtPointer) value, &length, &format); 1363444c061aSmrg 1364444c061aSmrg if (info->incremental[number]) { 1365a3bd7f05Smrg /* let requestor know the whole thing has been received */ 1366a3bd7f05Smrg value = (unsigned char *) __XtMalloc((unsigned) 1); 1367a3bd7f05Smrg length = 0; 1368a3bd7f05Smrg (*info->callbacks[number]) (widget, closure, &selection, 1369a3bd7f05Smrg &type, (XtPointer) value, &length, &format); 1370444c061aSmrg } 1371444c061aSmrg return TRUE; 1372444c061aSmrg} 1373444c061aSmrg 1374a3bd7f05Smrgstatic void 1375a3bd7f05SmrgHandleIncremental(Display *dpy, 1376a3bd7f05Smrg Widget widget, 1377a3bd7f05Smrg Atom property, 1378a3bd7f05Smrg CallBackInfo info, 1379a3bd7f05Smrg unsigned long size) 1380444c061aSmrg{ 1381444c061aSmrg XtAddEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, 1382a3bd7f05Smrg HandleGetIncrement, (XtPointer) info); 1383444c061aSmrg 1384444c061aSmrg /* now start the transfer */ 1385444c061aSmrg XDeleteProperty(dpy, XtWindow(widget), property); 1386444c061aSmrg XFlush(dpy); 1387444c061aSmrg 13880568f49bSmrg info->bytelength = (int) size; 1389a3bd7f05Smrg if (info->incremental[info->current]) /* requestor wants incremental too */ 1390a3bd7f05Smrg info->value = NULL; /* so no need for buffer to assemble value */ 1391444c061aSmrg else 1392a3bd7f05Smrg info->value = (char *) __XtMalloc((unsigned) info->bytelength); 1393444c061aSmrg info->offset = 0; 1394444c061aSmrg 1395444c061aSmrg /* reset the timer */ 1396444c061aSmrg info->proc = HandleGetIncrement; 1397444c061aSmrg#ifndef DEBUG_WO_TIMERS 1398444c061aSmrg { 1399a3bd7f05Smrg XtAppContext app = XtWidgetToApplicationContext(info->widget); 1400a3bd7f05Smrg 1401a3bd7f05Smrg info->timeout = XtAppAddTimeOut(app, 1402a3bd7f05Smrg app->selectionTimeout, ReqTimedOut, 1403a3bd7f05Smrg (XtPointer) info); 1404444c061aSmrg } 1405444c061aSmrg#endif 1406444c061aSmrg} 1407444c061aSmrg 1408a3bd7f05Smrgstatic void 1409a3bd7f05SmrgHandleSelectionReplies(Widget widget, 1410a3bd7f05Smrg XtPointer closure, 1411a3bd7f05Smrg XEvent *ev, 1412a3bd7f05Smrg Boolean *cont _X_UNUSED) 1413444c061aSmrg{ 1414444c061aSmrg XSelectionEvent *event = (XSelectionEvent *) ev; 1415444c061aSmrg Display *dpy = event->display; 1416444c061aSmrg CallBackInfo info = (CallBackInfo) closure; 1417444c061aSmrg Select ctx = info->ctx; 1418444c061aSmrg unsigned long bytesafter; 1419444c061aSmrg unsigned long length; 1420444c061aSmrg int format; 1421444c061aSmrg Atom type; 1422444c061aSmrg 1423a3bd7f05Smrg if (event->type != SelectionNotify) 1424a3bd7f05Smrg return; 1425a3bd7f05Smrg if (!MATCH_SELECT(event, info)) 1426a3bd7f05Smrg return; /* not really for us */ 1427444c061aSmrg#ifndef DEBUG_WO_TIMERS 1428444c061aSmrg XtRemoveTimeOut(info->timeout); 1429444c061aSmrg#endif 1430a3bd7f05Smrg XtRemoveEventHandler(widget, (EventMask) 0, TRUE, 1431a3bd7f05Smrg HandleSelectionReplies, (XtPointer) info); 1432444c061aSmrg if (event->target == ctx->prop_list->indirect_atom) { 1433a3bd7f05Smrg IndirectPair *pairs = NULL, *p; 1434a3bd7f05Smrg XtPointer *c; 1435a3bd7f05Smrg 1436a3bd7f05Smrg if (XGetWindowProperty(dpy, XtWindow(widget), info->property, 0L, 1437a3bd7f05Smrg 10000000, True, AnyPropertyType, &type, &format, 1438a3bd7f05Smrg &length, &bytesafter, (unsigned char **) &pairs) 1439a3bd7f05Smrg != Success) 1440a3bd7f05Smrg length = 0; 1441a3bd7f05Smrg for (length = length / IndirectPairWordSize, p = pairs, 1442a3bd7f05Smrg c = info->req_closure; 1443a3bd7f05Smrg length; length--, p++, c++, info->current++) { 1444a3bd7f05Smrg if (event->property == None || format != 32 || p->target == None 1445a3bd7f05Smrg || /* bug compatibility */ p->property == None) { 1446a3bd7f05Smrg HandleNone(widget, info->callbacks[info->current], 1447a3bd7f05Smrg *c, event->selection); 1448a3bd7f05Smrg if (p->property != None) 1449a3bd7f05Smrg FreeSelectionProperty(XtDisplay(widget), p->property); 1450a3bd7f05Smrg } 1451a3bd7f05Smrg else { 1452a3bd7f05Smrg if (HandleNormal(dpy, widget, p->property, info, *c, 1453a3bd7f05Smrg event->selection)) { 1454444c061aSmrg FreeSelectionProperty(XtDisplay(widget), p->property); 1455a3bd7f05Smrg } 1456a3bd7f05Smrg } 1457a3bd7f05Smrg } 1458a3bd7f05Smrg XFree((char *) pairs); 1459a3bd7f05Smrg FreeSelectionProperty(dpy, info->property); 1460a3bd7f05Smrg FreeInfo(info); 1461a3bd7f05Smrg } 1462a3bd7f05Smrg else if (event->property == None) { 1463a3bd7f05Smrg HandleNone(widget, info->callbacks[0], *info->req_closure, 1464a3bd7f05Smrg event->selection); 1465444c061aSmrg FreeSelectionProperty(XtDisplay(widget), info->property); 1466a3bd7f05Smrg FreeInfo(info); 1467a3bd7f05Smrg } 1468a3bd7f05Smrg else { 1469a3bd7f05Smrg if (HandleNormal(dpy, widget, event->property, info, 1470a3bd7f05Smrg *info->req_closure, event->selection)) { 1471a3bd7f05Smrg FreeSelectionProperty(XtDisplay(widget), info->property); 1472a3bd7f05Smrg FreeInfo(info); 1473a3bd7f05Smrg } 1474444c061aSmrg } 1475444c061aSmrg} 1476444c061aSmrg 1477a3bd7f05Smrgstatic void 1478a3bd7f05SmrgDoLocalTransfer(Request req, 1479a3bd7f05Smrg Atom selection, 1480a3bd7f05Smrg Atom target, 1481a3bd7f05Smrg Widget widget, /* The widget requesting the value. */ 1482a3bd7f05Smrg XtSelectionCallbackProc callback, 1483a3bd7f05Smrg XtPointer closure, /* the closure for the callback, not the conversion */ 1484a3bd7f05Smrg Boolean incremental, Atom property) 1485444c061aSmrg{ 1486444c061aSmrg Select ctx = req->ctx; 1487444c061aSmrg XtPointer value = NULL, temp, total = NULL; 1488444c061aSmrg unsigned long length; 1489444c061aSmrg int format; 1490444c061aSmrg Atom resulttype; 1491444c061aSmrg unsigned long totallength = 0; 1492444c061aSmrg 1493a3bd7f05Smrg req->event.type = 0; 1494a3bd7f05Smrg req->event.target = target; 1495a3bd7f05Smrg req->event.property = req->property = property; 1496a3bd7f05Smrg req->event.requestor = req->requestor = XtWindow(widget); 1497a3bd7f05Smrg 1498a3bd7f05Smrg if (ctx->incremental) { 1499a3bd7f05Smrg unsigned long size = (unsigned long) MAX_SELECTION_INCR(ctx->dpy); 1500a3bd7f05Smrg 1501a3bd7f05Smrg if (!(*(XtConvertSelectionIncrProc) ctx->convert) 1502a3bd7f05Smrg (ctx->widget, &selection, &target, 1503a3bd7f05Smrg &resulttype, &value, &length, &format, 1504a3bd7f05Smrg &size, ctx->owner_closure, (XtRequestId *) &req)) { 1505a3bd7f05Smrg HandleNone(widget, callback, closure, selection); 1506a3bd7f05Smrg } 1507a3bd7f05Smrg else { 1508a3bd7f05Smrg if (incremental) { 1509a3bd7f05Smrg Boolean allSent = FALSE; 1510a3bd7f05Smrg 1511a3bd7f05Smrg while (!allSent) { 1512a3bd7f05Smrg if (ctx->notify && (value != NULL)) { 1513a3bd7f05Smrg int bytelength = (int) BYTELENGTH(length, format); 1514a3bd7f05Smrg 1515a3bd7f05Smrg /* both sides think they own this storage */ 1516a3bd7f05Smrg temp = __XtMalloc((unsigned) bytelength); 1517a3bd7f05Smrg (void) memmove(temp, value, (size_t) bytelength); 1518a3bd7f05Smrg value = temp; 1519a3bd7f05Smrg } 1520a3bd7f05Smrg /* use care; older clients were never warned that 1521a3bd7f05Smrg * they must return a value even if length==0 1522a3bd7f05Smrg */ 1523a3bd7f05Smrg if (value == NULL) 1524a3bd7f05Smrg value = __XtMalloc((unsigned) 1); 1525a3bd7f05Smrg (*callback) (widget, closure, &selection, 1526a3bd7f05Smrg &resulttype, value, &length, &format); 1527a3bd7f05Smrg if (length) { 1528a3bd7f05Smrg /* should owner be notified on end-of-piece? 1529a3bd7f05Smrg * Spec is unclear, but non-local transfers don't. 1530a3bd7f05Smrg */ 1531a3bd7f05Smrg (*(XtConvertSelectionIncrProc) ctx->convert) 1532a3bd7f05Smrg (ctx->widget, &selection, &target, 1533a3bd7f05Smrg &resulttype, &value, &length, &format, 1534a3bd7f05Smrg &size, ctx->owner_closure, (XtRequestId *) &req); 1535a3bd7f05Smrg } 1536a3bd7f05Smrg else 1537a3bd7f05Smrg allSent = TRUE; 1538a3bd7f05Smrg } 1539a3bd7f05Smrg } 1540a3bd7f05Smrg else { 1541a3bd7f05Smrg while (length) { 1542a3bd7f05Smrg int bytelength = (int) BYTELENGTH(length, format); 1543a3bd7f05Smrg 1544a3bd7f05Smrg total = XtRealloc(total, 1545a3bd7f05Smrg (Cardinal) (totallength = 1546a3bd7f05Smrg totallength + 1547a3bd7f05Smrg (unsigned long) bytelength)); 1548a3bd7f05Smrg (void) memmove((char *) total + totallength - bytelength, 1549a3bd7f05Smrg value, (size_t) bytelength); 1550a3bd7f05Smrg (*(XtConvertSelectionIncrProc) ctx->convert) 1551a3bd7f05Smrg (ctx->widget, &selection, &target, 1552a3bd7f05Smrg &resulttype, &value, &length, &format, 1553a3bd7f05Smrg &size, ctx->owner_closure, (XtRequestId *) &req); 1554a3bd7f05Smrg } 1555a3bd7f05Smrg if (total == NULL) 1556a3bd7f05Smrg total = __XtMalloc(1); 1557a3bd7f05Smrg totallength = NUMELEM2(totallength, format); 1558a3bd7f05Smrg (*callback) (widget, closure, &selection, &resulttype, 1559a3bd7f05Smrg total, &totallength, &format); 1560a3bd7f05Smrg } 1561a3bd7f05Smrg if (ctx->notify) 1562a3bd7f05Smrg (*(XtSelectionDoneIncrProc) ctx->notify) 1563a3bd7f05Smrg (ctx->widget, &selection, &target, 1564a3bd7f05Smrg (XtRequestId *) &req, ctx->owner_closure); 1565a3bd7f05Smrg else 1566a3bd7f05Smrg XtFree((char *) value); 1567a3bd7f05Smrg } 1568a3bd7f05Smrg } 1569a3bd7f05Smrg else { /* not incremental owner */ 1570a3bd7f05Smrg if (!(*ctx->convert) (ctx->widget, &selection, &target, 1571a3bd7f05Smrg &resulttype, &value, &length, &format)) { 1572a3bd7f05Smrg HandleNone(widget, callback, closure, selection); 1573a3bd7f05Smrg } 1574a3bd7f05Smrg else { 1575a3bd7f05Smrg if (ctx->notify && (value != NULL)) { 1576a3bd7f05Smrg int bytelength = (int) BYTELENGTH(length, format); 1577a3bd7f05Smrg 1578a3bd7f05Smrg /* both sides think they own this storage; better copy */ 1579a3bd7f05Smrg temp = __XtMalloc((unsigned) bytelength); 1580a3bd7f05Smrg (void) memmove(temp, value, (size_t) bytelength); 1581a3bd7f05Smrg value = temp; 1582a3bd7f05Smrg } 1583a3bd7f05Smrg if (value == NULL) 1584a3bd7f05Smrg value = __XtMalloc((unsigned) 1); 1585a3bd7f05Smrg (*callback) (widget, closure, &selection, &resulttype, 1586a3bd7f05Smrg value, &length, &format); 1587a3bd7f05Smrg if (ctx->notify) 1588a3bd7f05Smrg (*ctx->notify) (ctx->widget, &selection, &target); 1589a3bd7f05Smrg } 1590a3bd7f05Smrg } 1591444c061aSmrg} 1592444c061aSmrg 1593a3bd7f05Smrgstatic void 1594a3bd7f05SmrgGetSelectionValue(Widget widget, 1595a3bd7f05Smrg Atom selection, 1596a3bd7f05Smrg Atom target, 1597a3bd7f05Smrg XtSelectionCallbackProc callback, 1598a3bd7f05Smrg XtPointer closure, 1599a3bd7f05Smrg Time time, 1600a3bd7f05Smrg Boolean incremental, 1601a3bd7f05Smrg Atom property) 1602444c061aSmrg{ 1603444c061aSmrg Select ctx; 1604444c061aSmrg Atom properties[1]; 1605444c061aSmrg 1606444c061aSmrg properties[0] = property; 1607444c061aSmrg 1608444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 1609444c061aSmrg if (ctx->widget && !ctx->was_disowned) { 1610a3bd7f05Smrg RequestRec req; 1611a3bd7f05Smrg 1612a3bd7f05Smrg ctx->req = &req; 1613a3bd7f05Smrg req.ctx = ctx; 1614a3bd7f05Smrg req.event.time = time; 1615a3bd7f05Smrg ctx->ref_count++; 1616a3bd7f05Smrg DoLocalTransfer(&req, selection, target, widget, 1617a3bd7f05Smrg callback, closure, incremental, property); 1618a3bd7f05Smrg if (--ctx->ref_count == 0 && ctx->free_when_done) 1619a3bd7f05Smrg XtFree((char *) ctx); 1620a3bd7f05Smrg else 1621a3bd7f05Smrg ctx->req = NULL; 1622444c061aSmrg } 1623444c061aSmrg else { 1624a3bd7f05Smrg CallBackInfo info; 1625a3bd7f05Smrg 1626a3bd7f05Smrg info = MakeInfo(ctx, &callback, &closure, 1, widget, 1627a3bd7f05Smrg time, &incremental, properties); 1628a3bd7f05Smrg info->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom)); 1629a3bd7f05Smrg *(info->target) = target; 1630a3bd7f05Smrg RequestSelectionValue(info, selection, target); 1631444c061aSmrg } 1632444c061aSmrg} 1633444c061aSmrg 1634a3bd7f05Smrgvoid 1635a3bd7f05SmrgXtGetSelectionValue(Widget widget, 1636a3bd7f05Smrg Atom selection, 1637a3bd7f05Smrg Atom target, 1638a3bd7f05Smrg XtSelectionCallbackProc callback, 1639a3bd7f05Smrg XtPointer closure, 1640a3bd7f05Smrg Time time) 1641444c061aSmrg{ 1642444c061aSmrg Atom property; 1643444c061aSmrg Boolean incr = False; 1644a3bd7f05Smrg 1645444c061aSmrg WIDGET_TO_APPCON(widget); 1646444c061aSmrg 1647444c061aSmrg LOCK_APP(app); 1648444c061aSmrg property = GetParamInfo(widget, selection); 1649444c061aSmrg RemoveParamInfo(widget, selection); 1650444c061aSmrg 1651444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1652a3bd7f05Smrg AddSelectionRequests(widget, selection, 1, &target, &callback, 1, 1653a3bd7f05Smrg &closure, &incr, &property); 1654a3bd7f05Smrg } 1655a3bd7f05Smrg else { 1656a3bd7f05Smrg GetSelectionValue(widget, selection, target, callback, 1657a3bd7f05Smrg closure, time, FALSE, property); 1658444c061aSmrg } 1659444c061aSmrg UNLOCK_APP(app); 1660444c061aSmrg} 1661444c061aSmrg 1662a3bd7f05Smrgvoid 1663a3bd7f05SmrgXtGetSelectionValueIncremental(Widget widget, 1664a3bd7f05Smrg Atom selection, 1665a3bd7f05Smrg Atom target, 1666a3bd7f05Smrg XtSelectionCallbackProc callback, 1667a3bd7f05Smrg XtPointer closure, 1668a3bd7f05Smrg Time time) 1669444c061aSmrg{ 1670444c061aSmrg Atom property; 1671444c061aSmrg Boolean incr = TRUE; 1672a3bd7f05Smrg 1673444c061aSmrg WIDGET_TO_APPCON(widget); 1674444c061aSmrg 1675444c061aSmrg LOCK_APP(app); 1676444c061aSmrg property = GetParamInfo(widget, selection); 1677444c061aSmrg RemoveParamInfo(widget, selection); 1678444c061aSmrg 1679444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1680a3bd7f05Smrg AddSelectionRequests(widget, selection, 1, &target, &callback, 1, 1681a3bd7f05Smrg &closure, &incr, &property); 1682a3bd7f05Smrg } 1683a3bd7f05Smrg else { 1684a3bd7f05Smrg GetSelectionValue(widget, selection, target, callback, 1685a3bd7f05Smrg closure, time, TRUE, property); 1686444c061aSmrg } 1687444c061aSmrg 1688444c061aSmrg UNLOCK_APP(app); 1689444c061aSmrg} 1690444c061aSmrg 1691a3bd7f05Smrgstatic void 1692a3bd7f05SmrgGetSelectionValues(Widget widget, 1693a3bd7f05Smrg Atom selection, 1694a3bd7f05Smrg Atom *targets, 1695a3bd7f05Smrg int count, 1696a3bd7f05Smrg XtSelectionCallbackProc *callbacks, 1697a3bd7f05Smrg int num_callbacks, 1698a3bd7f05Smrg XtPointer *closures, 1699a3bd7f05Smrg Time time, 1700a3bd7f05Smrg Boolean *incremental, 1701a3bd7f05Smrg Atom *properties) 1702444c061aSmrg{ 1703444c061aSmrg Select ctx; 17040568f49bSmrg IndirectPair *pairs; 1705444c061aSmrg 1706a3bd7f05Smrg if (count == 0) 1707a3bd7f05Smrg return; 1708444c061aSmrg ctx = FindCtx(XtDisplay(widget), selection); 1709444c061aSmrg if (ctx->widget && !ctx->was_disowned) { 1710444c061aSmrg int j, i; 1711a3bd7f05Smrg RequestRec req; 1712a3bd7f05Smrg 1713a3bd7f05Smrg ctx->req = &req; 1714a3bd7f05Smrg req.ctx = ctx; 1715a3bd7f05Smrg req.event.time = time; 1716a3bd7f05Smrg ctx->ref_count++; 1717a3bd7f05Smrg for (i = 0, j = 0; count; count--, i++, j++) { 1718a3bd7f05Smrg if (j >= num_callbacks) 1719a3bd7f05Smrg j = 0; 1720a3bd7f05Smrg 1721a3bd7f05Smrg DoLocalTransfer(&req, selection, targets[i], widget, 1722a3bd7f05Smrg callbacks[j], closures[i], incremental[i], 1723a3bd7f05Smrg properties ? properties[i] : None); 1724a3bd7f05Smrg 1725a3bd7f05Smrg } 1726a3bd7f05Smrg if (--ctx->ref_count == 0 && ctx->free_when_done) 1727a3bd7f05Smrg XtFree((char *) ctx); 1728a3bd7f05Smrg else 1729a3bd7f05Smrg ctx->req = NULL; 1730a3bd7f05Smrg } 1731a3bd7f05Smrg else { 1732444c061aSmrg XtSelectionCallbackProc *passed_callbacks; 1733a3bd7f05Smrg XtSelectionCallbackProc stack_cbs[32]; 1734a3bd7f05Smrg CallBackInfo info; 1735a3bd7f05Smrg IndirectPair *p; 1736a3bd7f05Smrg Atom *t; 1737444c061aSmrg int i = 0, j = 0; 1738444c061aSmrg 1739a3bd7f05Smrg passed_callbacks = (XtSelectionCallbackProc *) 1740a3bd7f05Smrg XtStackAlloc(sizeof(XtSelectionCallbackProc) * (size_t) count, 1741a3bd7f05Smrg stack_cbs); 1742a3bd7f05Smrg 1743a3bd7f05Smrg /* To deal with the old calls from XtGetSelectionValues* we 1744a3bd7f05Smrg will repeat however many callbacks have been passed into 1745a3bd7f05Smrg the array */ 1746a3bd7f05Smrg for (i = 0; i < count; i++) { 1747a3bd7f05Smrg if (j >= num_callbacks) 1748a3bd7f05Smrg j = 0; 1749a3bd7f05Smrg passed_callbacks[i] = callbacks[j]; 1750a3bd7f05Smrg j++; 1751a3bd7f05Smrg } 1752a3bd7f05Smrg info = MakeInfo(ctx, passed_callbacks, closures, count, widget, 1753a3bd7f05Smrg time, incremental, properties); 1754a3bd7f05Smrg XtStackFree((XtPointer) passed_callbacks, stack_cbs); 1755a3bd7f05Smrg 1756a3bd7f05Smrg info->target = (Atom *) 1757a3bd7f05Smrg __XtMalloc((unsigned) ((size_t) (count + 1) * sizeof(Atom))); 1758444c061aSmrg (*info->target) = ctx->prop_list->indirect_atom; 1759a3bd7f05Smrg (void) memmove((char *) info->target + sizeof(Atom), (char *) targets, 1760a3bd7f05Smrg (size_t) count * sizeof(Atom)); 1761a3bd7f05Smrg pairs = (IndirectPair *) 1762a3bd7f05Smrg __XtMalloc((unsigned) ((size_t) count * sizeof(IndirectPair))); 1763a3bd7f05Smrg for (p = &pairs[count - 1], t = &targets[count - 1], i = count - 1; 1764a3bd7f05Smrg p >= pairs; p--, t--, i--) { 1765a3bd7f05Smrg p->target = *t; 1766a3bd7f05Smrg if (properties == NULL || properties[i] == None) { 1767a3bd7f05Smrg p->property = GetSelectionProperty(XtDisplay(widget)); 1768a3bd7f05Smrg XDeleteProperty(XtDisplay(widget), XtWindow(widget), 1769a3bd7f05Smrg p->property); 1770a3bd7f05Smrg } 1771a3bd7f05Smrg else { 1772a3bd7f05Smrg p->property = properties[i]; 1773a3bd7f05Smrg } 1774a3bd7f05Smrg } 1775a3bd7f05Smrg XChangeProperty(XtDisplay(widget), XtWindow(widget), 1776a3bd7f05Smrg info->property, info->property, 1777a3bd7f05Smrg 32, PropModeReplace, (unsigned char *) pairs, 1778a3bd7f05Smrg count * IndirectPairWordSize); 1779a3bd7f05Smrg XtFree((char *) pairs); 1780a3bd7f05Smrg RequestSelectionValue(info, selection, ctx->prop_list->indirect_atom); 1781444c061aSmrg } 1782444c061aSmrg} 1783444c061aSmrg 1784a3bd7f05Smrgvoid 1785a3bd7f05SmrgXtGetSelectionValues(Widget widget, 1786a3bd7f05Smrg Atom selection, 1787a3bd7f05Smrg Atom *targets, 1788a3bd7f05Smrg int count, 1789a3bd7f05Smrg XtSelectionCallbackProc callback, 1790a3bd7f05Smrg XtPointer *closures, 1791a3bd7f05Smrg Time time) 1792444c061aSmrg{ 1793444c061aSmrg Boolean incremental_values[32]; 1794444c061aSmrg Boolean *incremental; 1795444c061aSmrg int i; 1796a3bd7f05Smrg 1797444c061aSmrg WIDGET_TO_APPCON(widget); 1798444c061aSmrg 1799444c061aSmrg LOCK_APP(app); 1800a3bd7f05Smrg incremental = 1801a3bd7f05Smrg XtStackAlloc((size_t) count * sizeof(Boolean), incremental_values); 1802a3bd7f05Smrg for (i = 0; i < count; i++) 1803a3bd7f05Smrg incremental[i] = FALSE; 1804444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1805a3bd7f05Smrg AddSelectionRequests(widget, selection, count, targets, &callback, 1806a3bd7f05Smrg 1, closures, incremental, NULL); 1807a3bd7f05Smrg } 1808a3bd7f05Smrg else { 1809a3bd7f05Smrg GetSelectionValues(widget, selection, targets, count, &callback, 1, 1810a3bd7f05Smrg closures, time, incremental, NULL); 1811444c061aSmrg } 1812444c061aSmrg XtStackFree((XtPointer) incremental, incremental_values); 1813444c061aSmrg UNLOCK_APP(app); 1814444c061aSmrg} 1815444c061aSmrg 1816a3bd7f05Smrgvoid 1817a3bd7f05SmrgXtGetSelectionValuesIncremental(Widget widget, 1818a3bd7f05Smrg Atom selection, 1819a3bd7f05Smrg Atom *targets, 1820a3bd7f05Smrg int count, 1821a3bd7f05Smrg XtSelectionCallbackProc callback, 1822a3bd7f05Smrg XtPointer *closures, 1823a3bd7f05Smrg Time time) 1824444c061aSmrg{ 1825444c061aSmrg Boolean incremental_values[32]; 1826444c061aSmrg Boolean *incremental; 1827444c061aSmrg int i; 1828a3bd7f05Smrg 1829444c061aSmrg WIDGET_TO_APPCON(widget); 1830444c061aSmrg 1831444c061aSmrg LOCK_APP(app); 1832a3bd7f05Smrg incremental = 1833a3bd7f05Smrg XtStackAlloc((size_t) count * sizeof(Boolean), incremental_values); 1834a3bd7f05Smrg for (i = 0; i < count; i++) 1835a3bd7f05Smrg incremental[i] = TRUE; 1836444c061aSmrg if (IsGatheringRequest(widget, selection)) { 1837a3bd7f05Smrg AddSelectionRequests(widget, selection, count, targets, &callback, 1838a3bd7f05Smrg 1, closures, incremental, NULL); 1839a3bd7f05Smrg } 1840a3bd7f05Smrg else { 1841a3bd7f05Smrg GetSelectionValues(widget, selection, targets, count, 1842a3bd7f05Smrg &callback, 1, closures, time, incremental, NULL); 1843444c061aSmrg } 1844444c061aSmrg XtStackFree((XtPointer) incremental, incremental_values); 1845444c061aSmrg UNLOCK_APP(app); 1846444c061aSmrg} 1847444c061aSmrg 1848a3bd7f05Smrgstatic Request 1849a3bd7f05SmrgGetRequestRecord(Widget widget, Atom selection, XtRequestId id) 1850444c061aSmrg{ 1851a3bd7f05Smrg Request req = (Request) id; 1852444c061aSmrg Select ctx = NULL; 1853444c061aSmrg 1854a3bd7f05Smrg if ((req == NULL 1855a3bd7f05Smrg && ((ctx = FindCtx(XtDisplay(widget), selection)) == NULL 1856a3bd7f05Smrg || ctx->req == NULL 1857a3bd7f05Smrg || ctx->selection != selection || ctx->widget == NULL)) 1858a3bd7f05Smrg || (req != NULL 1859a3bd7f05Smrg && (req->ctx == NULL 1860a3bd7f05Smrg || req->ctx->selection != selection 1861a3bd7f05Smrg || req->ctx->widget != widget))) { 1862a3bd7f05Smrg String params = XtName(widget); 1863a3bd7f05Smrg Cardinal num_params = 1; 1864a3bd7f05Smrg 1865a3bd7f05Smrg XtAppWarningMsg(XtWidgetToApplicationContext(widget), 1866a3bd7f05Smrg "notInConvertSelection", "xtGetSelectionRequest", 1867a3bd7f05Smrg XtCXtToolkitError, 1868a3bd7f05Smrg "XtGetSelectionRequest or XtGetSelectionParameters called for widget \"%s\" outside of ConvertSelection proc", 1869a3bd7f05Smrg ¶ms, &num_params); 1870a3bd7f05Smrg return NULL; 1871444c061aSmrg } 1872444c061aSmrg 1873444c061aSmrg if (req == NULL) { 1874a3bd7f05Smrg /* non-incremental owner; only one request can be 1875a3bd7f05Smrg * outstanding at a time, so it's safe to keep ptr in ctx */ 1876a3bd7f05Smrg req = ctx->req; 1877444c061aSmrg } 1878444c061aSmrg return req; 1879444c061aSmrg} 1880444c061aSmrg 1881a3bd7f05SmrgXSelectionRequestEvent * 1882a3bd7f05SmrgXtGetSelectionRequest(Widget widget, Atom selection, XtRequestId id) 1883444c061aSmrg{ 1884a3bd7f05Smrg Request req = (Request) id; 1885a3bd7f05Smrg 1886444c061aSmrg WIDGET_TO_APPCON(widget); 1887444c061aSmrg 1888444c061aSmrg LOCK_APP(app); 1889444c061aSmrg 1890444c061aSmrg req = GetRequestRecord(widget, selection, id); 1891444c061aSmrg 1892a3bd7f05Smrg if (!req) { 1893a3bd7f05Smrg UNLOCK_APP(app); 1894a3bd7f05Smrg return (XSelectionRequestEvent *) NULL; 1895444c061aSmrg } 1896444c061aSmrg 1897444c061aSmrg if (req->event.type == 0) { 1898a3bd7f05Smrg /* owner is local; construct the remainder of the event */ 1899a3bd7f05Smrg req->event.type = SelectionRequest; 1900a3bd7f05Smrg req->event.serial = LastKnownRequestProcessed(XtDisplay(widget)); 1901a3bd7f05Smrg req->event.send_event = True; 1902a3bd7f05Smrg req->event.display = XtDisplay(widget); 1903a3bd7f05Smrg 1904a3bd7f05Smrg req->event.owner = XtWindow(req->ctx->widget); 1905a3bd7f05Smrg req->event.selection = selection; 1906444c061aSmrg } 1907444c061aSmrg UNLOCK_APP(app); 1908444c061aSmrg return &req->event; 1909444c061aSmrg} 1910444c061aSmrg 1911444c061aSmrg/* Property atom access */ 1912a3bd7f05SmrgAtom 1913a3bd7f05SmrgXtReservePropertyAtom(Widget w) 1914444c061aSmrg{ 1915a3bd7f05Smrg return (GetSelectionProperty(XtDisplay(w))); 1916444c061aSmrg} 1917444c061aSmrg 1918a3bd7f05Smrgvoid 1919a3bd7f05SmrgXtReleasePropertyAtom(Widget w, Atom atom) 1920444c061aSmrg{ 1921a3bd7f05Smrg FreeSelectionProperty(XtDisplay(w), atom); 1922444c061aSmrg} 1923444c061aSmrg 1924444c061aSmrg/* Multiple utilities */ 1925444c061aSmrg 1926444c061aSmrg/* All requests are put in a single list per widget. It is 1927444c061aSmrg very unlikely anyone will be gathering multiple MULTIPLE 1928444c061aSmrg requests at the same time, so the loss in efficiency for 1929444c061aSmrg this case is acceptable */ 1930444c061aSmrg 1931444c061aSmrg/* Queue one or more requests to the one we're gathering */ 1932a3bd7f05Smrgstatic void 1933a3bd7f05SmrgAddSelectionRequests(Widget wid, 1934a3bd7f05Smrg Atom sel, 1935a3bd7f05Smrg int count, 1936a3bd7f05Smrg Atom *targets, 1937a3bd7f05Smrg XtSelectionCallbackProc *callbacks, 1938a3bd7f05Smrg int num_cb, 1939a3bd7f05Smrg XtPointer *closures, 1940a3bd7f05Smrg Boolean *incrementals, 1941a3bd7f05Smrg Atom *properties) 1942444c061aSmrg{ 1943a3bd7f05Smrg QueuedRequestInfo qi; 1944a3bd7f05Smrg Window window = XtWindow(wid); 1945a3bd7f05Smrg Display *dpy = XtDisplay(wid); 1946444c061aSmrg 1947a3bd7f05Smrg LOCK_PROCESS; 1948a3bd7f05Smrg if (multipleContext == 0) 1949a3bd7f05Smrg multipleContext = XUniqueContext(); 1950a3bd7f05Smrg 1951a3bd7f05Smrg qi = NULL; 1952a3bd7f05Smrg (void) XFindContext(dpy, window, multipleContext, (XPointer *) &qi); 1953a3bd7f05Smrg 1954a3bd7f05Smrg if (qi != NULL) { 1955a3bd7f05Smrg QueuedRequest *req = qi->requests; 1956a3bd7f05Smrg int start = qi->count; 1957a3bd7f05Smrg int i = 0; 1958a3bd7f05Smrg int j = 0; 1959a3bd7f05Smrg 1960a3bd7f05Smrg qi->count += count; 1961a3bd7f05Smrg req = (QueuedRequest *) XtRealloc((char *) req, 1962a3bd7f05Smrg (Cardinal) ((size_t) (start + count) * 1963a3bd7f05Smrg sizeof(QueuedRequest))); 1964a3bd7f05Smrg while (i < count) { 1965a3bd7f05Smrg QueuedRequest newreq = (QueuedRequest) 1966a3bd7f05Smrg __XtMalloc(sizeof(QueuedRequestRec)); 1967a3bd7f05Smrg 1968a3bd7f05Smrg newreq->selection = sel; 1969a3bd7f05Smrg newreq->target = targets[i]; 1970a3bd7f05Smrg if (properties != NULL) 1971a3bd7f05Smrg newreq->param = properties[i]; 1972a3bd7f05Smrg else { 1973a3bd7f05Smrg newreq->param = GetSelectionProperty(dpy); 1974a3bd7f05Smrg XDeleteProperty(dpy, window, newreq->param); 1975a3bd7f05Smrg } 1976a3bd7f05Smrg newreq->callback = callbacks[j]; 1977a3bd7f05Smrg newreq->closure = closures[i]; 1978a3bd7f05Smrg newreq->incremental = incrementals[i]; 1979a3bd7f05Smrg 1980a3bd7f05Smrg req[start] = newreq; 1981a3bd7f05Smrg start++; 1982a3bd7f05Smrg i++; 1983a3bd7f05Smrg j++; 1984a3bd7f05Smrg if (j > num_cb) 1985a3bd7f05Smrg j = 0; 1986a3bd7f05Smrg } 1987444c061aSmrg 1988a3bd7f05Smrg qi->requests = req; 1989a3bd7f05Smrg } 1990a3bd7f05Smrg else { 1991a3bd7f05Smrg /* Impossible */ 1992a3bd7f05Smrg } 1993444c061aSmrg 1994a3bd7f05Smrg UNLOCK_PROCESS; 1995a3bd7f05Smrg} 1996444c061aSmrg 1997a3bd7f05Smrg/* Only call IsGatheringRequest when we have a lock already */ 1998444c061aSmrg 1999a3bd7f05Smrgstatic Boolean 2000a3bd7f05SmrgIsGatheringRequest(Widget wid, Atom sel) 2001a3bd7f05Smrg{ 2002a3bd7f05Smrg QueuedRequestInfo qi; 2003a3bd7f05Smrg Window window = XtWindow(wid); 2004a3bd7f05Smrg Display *dpy = XtDisplay(wid); 2005a3bd7f05Smrg Boolean found = False; 2006a3bd7f05Smrg 2007a3bd7f05Smrg if (multipleContext == 0) 2008a3bd7f05Smrg multipleContext = XUniqueContext(); 2009a3bd7f05Smrg 2010a3bd7f05Smrg qi = NULL; 2011a3bd7f05Smrg (void) XFindContext(dpy, window, multipleContext, (XPointer *) &qi); 2012a3bd7f05Smrg 2013a3bd7f05Smrg if (qi != NULL) { 2014a3bd7f05Smrg int i = 0; 2015a3bd7f05Smrg 2016a3bd7f05Smrg while (qi->selections[i] != None) { 2017a3bd7f05Smrg if (qi->selections[i] == sel) { 2018a3bd7f05Smrg found = True; 2019a3bd7f05Smrg break; 2020a3bd7f05Smrg } 2021a3bd7f05Smrg i++; 2022a3bd7f05Smrg } 2023444c061aSmrg } 2024444c061aSmrg 2025a3bd7f05Smrg return (found); 2026444c061aSmrg} 2027444c061aSmrg 2028444c061aSmrg/* Cleanup request scans the request queue and releases any 2029444c061aSmrg properties queued, and removes any requests queued */ 2030a3bd7f05Smrgstatic void 2031a3bd7f05SmrgCleanupRequest(Display *dpy, QueuedRequestInfo qi, Atom sel) 2032444c061aSmrg{ 2033a3bd7f05Smrg int i, j, n; 2034a3bd7f05Smrg 2035a3bd7f05Smrg i = 0; 2036a3bd7f05Smrg 2037a3bd7f05Smrg /* Remove this selection from the list */ 2038a3bd7f05Smrg n = 0; 2039a3bd7f05Smrg while (qi->selections[n] != sel && qi->selections[n] != None) 2040a3bd7f05Smrg n++; 2041a3bd7f05Smrg if (qi->selections[n] == sel) { 2042a3bd7f05Smrg while (qi->selections[n] != None) { 2043a3bd7f05Smrg qi->selections[n] = qi->selections[n + 1]; 2044a3bd7f05Smrg n++; 2045a3bd7f05Smrg } 2046444c061aSmrg } 2047444c061aSmrg 2048a3bd7f05Smrg while (i < qi->count) { 2049a3bd7f05Smrg QueuedRequest req = qi->requests[i]; 2050444c061aSmrg 2051a3bd7f05Smrg if (req->selection == sel) { 2052a3bd7f05Smrg /* Match */ 2053a3bd7f05Smrg if (req->param != None) 2054a3bd7f05Smrg FreeSelectionProperty(dpy, req->param); 2055a3bd7f05Smrg qi->count--; 2056444c061aSmrg 2057a3bd7f05Smrg for (j = i; j < qi->count; j++) 2058a3bd7f05Smrg qi->requests[j] = qi->requests[j + 1]; 2059444c061aSmrg 2060a3bd7f05Smrg XtFree((char *) req); 2061a3bd7f05Smrg } 2062a3bd7f05Smrg else { 2063a3bd7f05Smrg i++; 2064a3bd7f05Smrg } 2065444c061aSmrg } 2066444c061aSmrg} 2067444c061aSmrg 2068a3bd7f05Smrgvoid 2069a3bd7f05SmrgXtCreateSelectionRequest(Widget widget, Atom selection) 2070444c061aSmrg{ 2071a3bd7f05Smrg QueuedRequestInfo queueInfo; 2072a3bd7f05Smrg Window window = XtWindow(widget); 2073a3bd7f05Smrg Display *dpy = XtDisplay(widget); 2074a3bd7f05Smrg int n; 2075444c061aSmrg 2076a3bd7f05Smrg LOCK_PROCESS; 2077a3bd7f05Smrg if (multipleContext == 0) 2078a3bd7f05Smrg multipleContext = XUniqueContext(); 2079444c061aSmrg 2080a3bd7f05Smrg queueInfo = NULL; 2081a3bd7f05Smrg (void) XFindContext(dpy, window, multipleContext, (XPointer *) &queueInfo); 2082444c061aSmrg 2083a3bd7f05Smrg /* If there is one, then cancel it */ 2084a3bd7f05Smrg if (queueInfo != NULL) 2085a3bd7f05Smrg CleanupRequest(dpy, queueInfo, selection); 2086a3bd7f05Smrg else { 2087a3bd7f05Smrg /* Create it */ 2088a3bd7f05Smrg queueInfo = 2089a3bd7f05Smrg (QueuedRequestInfo) __XtMalloc(sizeof(QueuedRequestInfoRec)); 2090a3bd7f05Smrg queueInfo->count = 0; 2091a3bd7f05Smrg queueInfo->selections = (Atom *) __XtMalloc(sizeof(Atom) * 2); 2092a3bd7f05Smrg queueInfo->selections[0] = None; 2093a3bd7f05Smrg queueInfo->requests = (QueuedRequest *) 2094a3bd7f05Smrg __XtMalloc(sizeof(QueuedRequest)); 2095a3bd7f05Smrg } 2096a3bd7f05Smrg 2097a3bd7f05Smrg /* Append this selection to list */ 2098a3bd7f05Smrg n = 0; 2099a3bd7f05Smrg while (queueInfo->selections[n] != None) 2100a3bd7f05Smrg n++; 2101a3bd7f05Smrg queueInfo->selections = 2102a3bd7f05Smrg (Atom *) XtRealloc((char *) queueInfo->selections, 2103a3bd7f05Smrg (Cardinal) ((size_t) (n + 2) * sizeof(Atom))); 2104a3bd7f05Smrg queueInfo->selections[n] = selection; 2105a3bd7f05Smrg queueInfo->selections[n + 1] = None; 2106a3bd7f05Smrg 2107a3bd7f05Smrg (void) XSaveContext(dpy, window, multipleContext, (char *) queueInfo); 2108a3bd7f05Smrg UNLOCK_PROCESS; 2109444c061aSmrg} 2110444c061aSmrg 2111a3bd7f05Smrgvoid 2112a3bd7f05SmrgXtSendSelectionRequest(Widget widget, Atom selection, Time time) 2113444c061aSmrg{ 2114a3bd7f05Smrg QueuedRequestInfo queueInfo; 2115a3bd7f05Smrg Window window = XtWindow(widget); 2116a3bd7f05Smrg Display *dpy = XtDisplay(widget); 2117444c061aSmrg 2118a3bd7f05Smrg LOCK_PROCESS; 2119a3bd7f05Smrg if (multipleContext == 0) 2120a3bd7f05Smrg multipleContext = XUniqueContext(); 2121a3bd7f05Smrg 2122a3bd7f05Smrg queueInfo = NULL; 2123a3bd7f05Smrg (void) XFindContext(dpy, window, multipleContext, (XPointer *) &queueInfo); 2124a3bd7f05Smrg if (queueInfo != NULL) { 2125a3bd7f05Smrg int i; 2126a3bd7f05Smrg int count = 0; 2127a3bd7f05Smrg QueuedRequest *req = queueInfo->requests; 2128a3bd7f05Smrg 2129a3bd7f05Smrg /* Construct the requests and send it using 2130a3bd7f05Smrg GetSelectionValues */ 2131a3bd7f05Smrg for (i = 0; i < queueInfo->count; i++) 2132a3bd7f05Smrg if (req[i]->selection == selection) 2133a3bd7f05Smrg count++; 2134a3bd7f05Smrg 2135a3bd7f05Smrg if (count > 0) { 2136a3bd7f05Smrg if (count == 1) { 2137a3bd7f05Smrg for (i = 0; i < queueInfo->count; i++) 2138a3bd7f05Smrg if (req[i]->selection == selection) 2139a3bd7f05Smrg break; 2140a3bd7f05Smrg 2141a3bd7f05Smrg /* special case a multiple which isn't needed */ 2142a3bd7f05Smrg GetSelectionValue(widget, selection, req[i]->target, 2143a3bd7f05Smrg req[i]->callback, req[i]->closure, time, 2144a3bd7f05Smrg req[i]->incremental, req[i]->param); 2145a3bd7f05Smrg } 2146a3bd7f05Smrg else { 2147a3bd7f05Smrg Atom *targets; 2148a3bd7f05Smrg Atom t[PREALLOCED]; 2149a3bd7f05Smrg XtSelectionCallbackProc *cbs; 2150a3bd7f05Smrg XtSelectionCallbackProc c[PREALLOCED]; 2151a3bd7f05Smrg XtPointer *closures; 2152a3bd7f05Smrg XtPointer cs[PREALLOCED]; 2153a3bd7f05Smrg Boolean *incrs; 2154a3bd7f05Smrg Boolean ins[PREALLOCED]; 2155a3bd7f05Smrg Atom *props; 2156a3bd7f05Smrg Atom p[PREALLOCED]; 2157a3bd7f05Smrg int j = 0; 2158a3bd7f05Smrg 2159a3bd7f05Smrg /* Allocate */ 2160a3bd7f05Smrg targets = 2161a3bd7f05Smrg (Atom *) XtStackAlloc((size_t) count * sizeof(Atom), t); 2162a3bd7f05Smrg cbs = (XtSelectionCallbackProc *) 2163a3bd7f05Smrg XtStackAlloc((size_t) count * 2164a3bd7f05Smrg sizeof(XtSelectionCallbackProc), c); 2165a3bd7f05Smrg closures = 2166a3bd7f05Smrg (XtPointer *) XtStackAlloc((size_t) count * 2167a3bd7f05Smrg sizeof(XtPointer), cs); 2168a3bd7f05Smrg incrs = 2169a3bd7f05Smrg (Boolean *) XtStackAlloc((size_t) count * sizeof(Boolean), 2170a3bd7f05Smrg ins); 2171a3bd7f05Smrg props = (Atom *) XtStackAlloc((size_t) count * sizeof(Atom), p); 2172a3bd7f05Smrg 2173a3bd7f05Smrg /* Copy */ 2174a3bd7f05Smrg for (i = 0; i < queueInfo->count; i++) { 2175a3bd7f05Smrg if (req[i]->selection == selection) { 2176a3bd7f05Smrg targets[j] = req[i]->target; 2177a3bd7f05Smrg cbs[j] = req[i]->callback; 2178a3bd7f05Smrg closures[j] = req[i]->closure; 2179a3bd7f05Smrg incrs[j] = req[i]->incremental; 2180a3bd7f05Smrg props[j] = req[i]->param; 2181a3bd7f05Smrg j++; 2182a3bd7f05Smrg } 2183a3bd7f05Smrg } 2184a3bd7f05Smrg 2185a3bd7f05Smrg /* Make the request */ 2186a3bd7f05Smrg GetSelectionValues(widget, selection, targets, count, 2187a3bd7f05Smrg cbs, count, closures, time, incrs, props); 2188a3bd7f05Smrg 2189a3bd7f05Smrg /* Free */ 2190a3bd7f05Smrg XtStackFree((XtPointer) targets, t); 2191a3bd7f05Smrg XtStackFree((XtPointer) cbs, c); 2192a3bd7f05Smrg XtStackFree((XtPointer) closures, cs); 2193a3bd7f05Smrg XtStackFree((XtPointer) incrs, ins); 2194a3bd7f05Smrg XtStackFree((XtPointer) props, p); 2195a3bd7f05Smrg } 2196a3bd7f05Smrg } 2197a3bd7f05Smrg } 2198444c061aSmrg 2199a3bd7f05Smrg CleanupRequest(dpy, queueInfo, selection); 2200a3bd7f05Smrg UNLOCK_PROCESS; 2201444c061aSmrg} 2202444c061aSmrg 2203a3bd7f05Smrgvoid 2204a3bd7f05SmrgXtCancelSelectionRequest(Widget widget, Atom selection) 2205444c061aSmrg{ 2206a3bd7f05Smrg QueuedRequestInfo queueInfo; 2207a3bd7f05Smrg Window window = XtWindow(widget); 2208a3bd7f05Smrg Display *dpy = XtDisplay(widget); 2209444c061aSmrg 2210a3bd7f05Smrg LOCK_PROCESS; 2211a3bd7f05Smrg if (multipleContext == 0) 2212a3bd7f05Smrg multipleContext = XUniqueContext(); 2213a3bd7f05Smrg 2214a3bd7f05Smrg queueInfo = NULL; 2215a3bd7f05Smrg (void) XFindContext(dpy, window, multipleContext, (XPointer *) &queueInfo); 2216a3bd7f05Smrg /* If there is one, then cancel it */ 2217a3bd7f05Smrg if (queueInfo != NULL) 2218a3bd7f05Smrg CleanupRequest(dpy, queueInfo, selection); 2219a3bd7f05Smrg UNLOCK_PROCESS; 2220444c061aSmrg} 2221444c061aSmrg 2222444c061aSmrg/* Parameter utilities */ 2223444c061aSmrg 2224444c061aSmrg/* Parameters on a selection request */ 2225444c061aSmrg/* Places data on allocated parameter atom, then records the 2226444c061aSmrg parameter atom data for use in the next call to one of 2227444c061aSmrg the XtGetSelectionValue functions. */ 2228a3bd7f05Smrgvoid 2229a3bd7f05SmrgXtSetSelectionParameters(Widget requestor, 2230a3bd7f05Smrg Atom selection, 2231a3bd7f05Smrg Atom type, 2232a3bd7f05Smrg XtPointer value, 2233a3bd7f05Smrg unsigned long length, 2234a3bd7f05Smrg int format) 2235444c061aSmrg{ 2236a3bd7f05Smrg Display *dpy = XtDisplay(requestor); 2237a3bd7f05Smrg Window window = XtWindow(requestor); 2238a3bd7f05Smrg Atom property = GetParamInfo(requestor, selection); 2239a3bd7f05Smrg 2240a3bd7f05Smrg if (property == None) { 2241a3bd7f05Smrg property = GetSelectionProperty(dpy); 2242a3bd7f05Smrg AddParamInfo(requestor, selection, property); 2243a3bd7f05Smrg } 2244a3bd7f05Smrg 2245a3bd7f05Smrg XChangeProperty(dpy, window, property, 2246a3bd7f05Smrg type, format, PropModeReplace, 2247a3bd7f05Smrg (unsigned char *) value, (int) length); 2248444c061aSmrg} 2249444c061aSmrg 2250444c061aSmrg/* Retrieves data passed in a parameter. Data for this is stored 2251444c061aSmrg on the originator's window */ 2252a3bd7f05Smrgvoid 2253a3bd7f05SmrgXtGetSelectionParameters(Widget owner, 2254a3bd7f05Smrg Atom selection, 2255a3bd7f05Smrg XtRequestId request_id, 2256a3bd7f05Smrg Atom *type_return, 2257a3bd7f05Smrg XtPointer *value_return, 2258a3bd7f05Smrg unsigned long *length_return, 2259a3bd7f05Smrg int *format_return) 2260444c061aSmrg{ 2261444c061aSmrg Request req; 2262444c061aSmrg Display *dpy = XtDisplay(owner); 2263a3bd7f05Smrg 2264444c061aSmrg WIDGET_TO_APPCON(owner); 2265444c061aSmrg 2266444c061aSmrg *value_return = NULL; 22670568f49bSmrg *length_return = (unsigned long) (*format_return = 0); 2268444c061aSmrg *type_return = None; 2269444c061aSmrg 2270444c061aSmrg LOCK_APP(app); 2271444c061aSmrg 2272444c061aSmrg req = GetRequestRecord(owner, selection, request_id); 2273444c061aSmrg 2274444c061aSmrg if (req && req->property) { 2275a3bd7f05Smrg unsigned long bytes_after; /* unused */ 2276a3bd7f05Smrg 2277a3bd7f05Smrg StartProtectedSection(dpy, req->requestor); 2278a3bd7f05Smrg XGetWindowProperty(dpy, req->requestor, req->property, 0L, 10000000, 2279a3bd7f05Smrg False, AnyPropertyType, type_return, format_return, 2280a3bd7f05Smrg length_return, &bytes_after, 2281a3bd7f05Smrg (unsigned char **) value_return); 2282a3bd7f05Smrg EndProtectedSection(dpy); 2283444c061aSmrg#ifdef XT_COPY_SELECTION 2284a3bd7f05Smrg if (*value_return) { 2285a3bd7f05Smrg int size = (int) BYTELENGTH(*length_return, *format_return) + 1; 2286a3bd7f05Smrg char *tmp = __XtMalloc((Cardinal) size); 2287a3bd7f05Smrg 2288a3bd7f05Smrg (void) memmove(tmp, *value_return, (size_t) size); 2289a3bd7f05Smrg XFree(*value_return); 2290a3bd7f05Smrg *value_return = tmp; 2291a3bd7f05Smrg } 2292444c061aSmrg#endif 2293444c061aSmrg } 2294444c061aSmrg UNLOCK_APP(app); 2295444c061aSmrg} 2296444c061aSmrg 2297444c061aSmrg/* Parameters are temporarily stashed in an XContext. A list is used because 2298444c061aSmrg * there may be more than one selection request in progress. The context 2299444c061aSmrg * data is deleted when the list is empty. In the future, the parameter 2300444c061aSmrg * context could be merged with other contexts used during selections. 2301444c061aSmrg */ 2302444c061aSmrg 2303a3bd7f05Smrgstatic void 2304a3bd7f05SmrgAddParamInfo(Widget w, Atom selection, Atom param_atom) 2305444c061aSmrg{ 2306444c061aSmrg Param p; 2307444c061aSmrg ParamInfo pinfo; 2308444c061aSmrg 2309444c061aSmrg LOCK_PROCESS; 2310444c061aSmrg if (paramPropertyContext == 0) 2311a3bd7f05Smrg paramPropertyContext = XUniqueContext(); 2312444c061aSmrg 2313444c061aSmrg if (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2314a3bd7f05Smrg (XPointer *) &pinfo)) { 2315a3bd7f05Smrg pinfo = (ParamInfo) __XtMalloc(sizeof(ParamInfoRec)); 2316a3bd7f05Smrg pinfo->count = 1; 2317a3bd7f05Smrg pinfo->paramlist = XtNew(ParamRec); 2318a3bd7f05Smrg p = pinfo->paramlist; 2319a3bd7f05Smrg (void) XSaveContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2320a3bd7f05Smrg (char *) pinfo); 2321444c061aSmrg } 2322444c061aSmrg else { 2323a3bd7f05Smrg int n; 2324a3bd7f05Smrg 2325a3bd7f05Smrg for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++) { 2326a3bd7f05Smrg if (p->selection == None || p->selection == selection) 2327a3bd7f05Smrg break; 2328a3bd7f05Smrg } 2329a3bd7f05Smrg if (n == 0) { 2330a3bd7f05Smrg pinfo->count++; 2331a3bd7f05Smrg pinfo->paramlist = (Param) 2332a3bd7f05Smrg XtRealloc((char *) pinfo->paramlist, 2333a3bd7f05Smrg (Cardinal) (pinfo->count * sizeof(ParamRec))); 2334a3bd7f05Smrg p = &pinfo->paramlist[pinfo->count - 1]; 2335a3bd7f05Smrg (void) XSaveContext(XtDisplay(w), XtWindow(w), 2336a3bd7f05Smrg paramPropertyContext, (char *) pinfo); 2337a3bd7f05Smrg } 2338444c061aSmrg } 2339444c061aSmrg p->selection = selection; 2340444c061aSmrg p->param = param_atom; 2341444c061aSmrg UNLOCK_PROCESS; 2342444c061aSmrg} 2343444c061aSmrg 2344a3bd7f05Smrgstatic void 2345a3bd7f05SmrgRemoveParamInfo(Widget w, Atom selection) 2346444c061aSmrg{ 2347444c061aSmrg ParamInfo pinfo; 2348444c061aSmrg Boolean retain = False; 2349444c061aSmrg 2350444c061aSmrg LOCK_PROCESS; 2351444c061aSmrg if (paramPropertyContext 2352a3bd7f05Smrg && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2353a3bd7f05Smrg (XPointer *) &pinfo) == 0)) { 2354a3bd7f05Smrg Param p; 2355a3bd7f05Smrg int n; 2356a3bd7f05Smrg 2357a3bd7f05Smrg /* Find and invalidate the parameter data. */ 2358a3bd7f05Smrg for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++) { 2359a3bd7f05Smrg if (p->selection != None) { 2360a3bd7f05Smrg if (p->selection == selection) 2361a3bd7f05Smrg p->selection = None; 2362a3bd7f05Smrg else 2363a3bd7f05Smrg retain = True; 2364a3bd7f05Smrg } 2365a3bd7f05Smrg } 2366a3bd7f05Smrg /* If there's no valid data remaining, release the context entry. */ 2367a3bd7f05Smrg if (!retain) { 2368a3bd7f05Smrg XtFree((char *) pinfo->paramlist); 2369a3bd7f05Smrg XtFree((char *) pinfo); 2370a3bd7f05Smrg XDeleteContext(XtDisplay(w), XtWindow(w), paramPropertyContext); 2371a3bd7f05Smrg } 2372444c061aSmrg } 2373444c061aSmrg UNLOCK_PROCESS; 2374444c061aSmrg} 2375444c061aSmrg 2376a3bd7f05Smrgstatic Atom 2377a3bd7f05SmrgGetParamInfo(Widget w, Atom selection) 2378444c061aSmrg{ 2379444c061aSmrg ParamInfo pinfo; 2380444c061aSmrg Atom atom = None; 2381444c061aSmrg 2382444c061aSmrg LOCK_PROCESS; 2383444c061aSmrg if (paramPropertyContext 2384a3bd7f05Smrg && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, 2385a3bd7f05Smrg (XPointer *) &pinfo) == 0)) { 2386a3bd7f05Smrg Param p; 2387a3bd7f05Smrg int n; 2388a3bd7f05Smrg 2389a3bd7f05Smrg for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++) 2390a3bd7f05Smrg if (p->selection == selection) { 2391a3bd7f05Smrg atom = p->param; 2392a3bd7f05Smrg break; 2393a3bd7f05Smrg } 2394444c061aSmrg } 2395444c061aSmrg UNLOCK_PROCESS; 2396444c061aSmrg return atom; 2397444c061aSmrg} 2398