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