Bug Summary

File:Selection.c
Location:line 97, column 2
Description:Access to field 'selectionTimeout' results in a dereference of a null pointer (loaded from variable 'app')

Annotated Source Code

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