1 #ifndef lint
2 #ifdef SCCS
3 static char sccsid[] = "@(#)sel_util.c 1.29 93/06/28";
4 #endif
5 #endif
6
7 /*
8 * (c) Copyright 1990 Sun Microsystems, Inc. Sun design patents
9 * pending in the U.S. and foreign countries. See LEGAL NOTICE
10 * file for terms of the license.
11 */
12
13 #include <xview_private/sel_impl.h>
14 #include <xview_private/svr_impl.h>
15 #include <xview/notify.h>
16 #include <xview/window.h>
17 #include <xview/server.h>
18 #ifdef SVR4
19 #include <stdlib.h>
20 #endif SVR4
21
22 static void tvdiff();
23 static void FreeMultiProp();
24 static int SelMatchReply();
25 static Sel_req_tbl *SelMatchReqTbl();
26
27 Pkg_private struct timeval *
xv_sel_cvt_xtime_to_timeval(XTime)28 xv_sel_cvt_xtime_to_timeval( XTime )
29 Time XTime;
30 {
31 struct timeval *time;
32
33 time = xv_alloc( struct timeval );
34 time->tv_sec = ((unsigned long) XTime )/1000;
35 time->tv_usec = (((unsigned long) XTime ) % 1000) * 1000;
36 return time;
37 }
38
39
40 Pkg_private Time
xv_sel_cvt_timeval_to_xtime(timeV)41 xv_sel_cvt_timeval_to_xtime( timeV )
42 struct timeval *timeV;
43 {
44 return ( ( timeV->tv_sec * 1000 ) + ( timeV->tv_usec / 1000 ) );
45 }
46
47
48 Pkg_private Sel_owner_info *
xv_sel_find_selection_data(dpy,selection,xid)49 xv_sel_find_selection_data( dpy, selection, xid )
50 Display *dpy;
51 Atom selection;
52 Window xid;
53 {
54 Sel_owner_info *sel;
55
56 if ( selCtx == 0 )
57 selCtx = XUniqueContext();
58 if ( XFindContext( dpy, (Window) selection, selCtx, (caddr_t *)&sel ) ) {
59
60 sel = xv_alloc( Sel_owner_info );
61
62 if ( sel == NULL ) {
63 return ( (Sel_owner_info *) NULL );
64 }
65 /* Attach the atom type informations to the display */
66 sel->atomList = xv_sel_find_atom_list( dpy, xid );
67 sel->dpy = dpy;
68 sel->selection = selection;
69 sel->xid = NULL;
70 sel->status = 0;
71 (void)XSaveContext( dpy, (Window)selection, selCtx, (caddr_t)sel );
72 }
73 return sel;
74 }
75
76
77
78 Pkg_private Sel_owner_info *
xv_sel_set_selection_data(dpy,selection,sel_owner)79 xv_sel_set_selection_data( dpy, selection, sel_owner )
80 Display *dpy;
81 Atom selection;
82 Sel_owner_info *sel_owner;
83 {
84 if ( selCtx == 0 )
85 selCtx = XUniqueContext();
86
87 /* Attach the atom type informations to the display */
88 sel_owner->atomList = xv_sel_find_atom_list( dpy, sel_owner->xid );
89 sel_owner->dpy = dpy;
90 sel_owner->selection = selection;
91 sel_owner->status = 0;
92 (void)XSaveContext( dpy,(Window)selection, selCtx,(caddr_t)sel_owner);
93 return sel_owner;
94 }
95
96 /*
97 * REMINDER: This needs to be changed to a more efficient way of getting
98 * last event time.
99 */
100 Xv_private Time
xv_sel_get_last_event_time(dpy,win)101 xv_sel_get_last_event_time( dpy, win )
102 Display *dpy;
103 Window win;
104 {
105 XEvent event;
106 XPropertyEvent *ev;
107 Atom prop = xv_sel_get_property( dpy );
108 XWindowAttributes winAttr;
109 int arg;
110 int status = xv_sel_add_prop_notify_mask( dpy, win, &winAttr );
111
112 XChangeProperty( dpy, win, prop, XA_STRING, 8, PropModeReplace,
113 (unsigned char *) NULL, 0 );
114
115 /* Wait for the PropertyNotify */
116 arg = PropertyNotify;
117 if ( !xv_sel_block_for_event( dpy, &event, 3 , xv_sel_predicate, (char *) &arg ) ) {
118 xv_error(NULL,
119 ERROR_STRING,XV_MSG("xv_sel_get_last_event_time: Unable to get the last event time"),
120 ERROR_PKG,SELECTION,
121 0);
122 return ( (Time) NULL );
123 }
124
125 xv_sel_free_property( dpy, prop );
126
127 /*
128 * If we have added PropertyChangeMask to the win, reset the mask to
129 * it's original state.
130 */
131 if ( status )
132 XSelectInput( dpy, win, winAttr.your_event_mask );
133
134 ev = (XPropertyEvent *) &event;
135 return( ev->time );
136 }
137
138
139 int
xv_sel_add_prop_notify_mask(dpy,win,winAttr)140 xv_sel_add_prop_notify_mask( dpy, win, winAttr )
141 Display *dpy;
142 Window win;
143 XWindowAttributes *winAttr;
144 {
145 XGetWindowAttributes( dpy, win, winAttr );
146
147 /*
148 * If PropertyChangeMask has already been set on the window, don't set
149 * it again.
150 */
151 if ( winAttr->your_event_mask & PropertyChangeMask )
152 return FALSE;
153
154 XSelectInput( dpy, win, winAttr->your_event_mask | PropertyChangeMask );
155 return TRUE;
156 }
157
158
159
160 /* REMEMBER TO FREE THE ALLOCATED MEM */
161 Pkg_private Sel_atom_list *
xv_sel_find_atom_list(dpy,xid)162 xv_sel_find_atom_list( dpy, xid )
163 Display *dpy;
164 Window xid;
165 {
166 Sel_atom_list *list;
167 Xv_window xvWin;
168 Xv_Server server;
169
170 if ( targetCtx == 0 )
171 targetCtx = XUniqueContext();
172 if ( XFindContext( dpy, DefaultRootWindow(dpy), targetCtx,
173 (caddr_t *)&list ) ) {
174 list = xv_alloc( Sel_atom_list );
175 if ( list == NULL ) {
176 return( (Sel_atom_list *) NULL );
177 }
178 /* Get XView object */
179 xvWin = win_data( dpy, xid );
180 server = XV_SERVER_FROM_WINDOW( xvWin );
181
182 list->multiple = (Atom) xv_get( server, SERVER_ATOM, "MULTIPLE" );
183 list->targets = (Atom) xv_get( server, SERVER_ATOM, "TARGETS" );
184 list->timestamp = (Atom) xv_get( server, SERVER_ATOM, "TIMESTAMP" );
185 list->file_name = (Atom) xv_get( server, SERVER_ATOM, "FILE_NAME" );
186 list->string = (Atom) xv_get( server, SERVER_ATOM, "STRING" );
187 list->incr = (Atom) xv_get( server, SERVER_ATOM, "INCR" );
188 list->integer = (Atom) xv_get( server, SERVER_ATOM, "INTEGER" );
189 #ifdef OW_I18N
190 list->ctext = (Atom) xv_get( server, SERVER_ATOM, "COMPOUND_TEXT" );
191 #endif OW_I18N
192 (void)XSaveContext( dpy, DefaultRootWindow(dpy), targetCtx,
193 (caddr_t)list );
194 }
195 return ( list );
196 }
197
198
199 Pkg_private Sel_prop_list *
xv_sel_get_prop_list(dpy)200 xv_sel_get_prop_list( dpy )
201 Display *dpy;
202 {
203 Sel_prop_list *list;
204
205 if ( propCtx == 0 )
206 propCtx = XUniqueContext();
207 if ( XFindContext( dpy, DefaultRootWindow(dpy), propCtx,
208 (caddr_t *)&list ) ) {
209
210 list = xv_alloc( Sel_prop_list );
211 if ( list == NULL ) {
212 return ( (Sel_prop_list *) NULL );
213 }
214
215 list->prop = XInternAtom(dpy, "XV_SELECTION_0", FALSE);
216 list->avail = TRUE;
217 list->next = NULL;
218
219 (void)XSaveContext( dpy, DefaultRootWindow(dpy), propCtx,
220 (caddr_t)list );
221 }
222 return ( list );
223 }
224
225
226 /* NOTE: the avail field should be reset to TRUE after a complete transaction. */
227 Pkg_private Atom
xv_sel_get_property(dpy)228 xv_sel_get_property( dpy )
229 Display *dpy;
230 {
231 Sel_prop_list *cPtr;
232 char str[100];
233 int i=0;
234
235 cPtr = xv_sel_get_prop_list( dpy );
236
237 do {
238 if ( cPtr->avail ) {
239 cPtr->avail = FALSE;
240 return ( cPtr->prop );
241 }
242 i++;
243 if ( cPtr->next == NULL )
244 break;
245 cPtr = cPtr->next;
246 } while ( 1 );
247
248
249 /* Create a new property and add it to the list */
250 cPtr->next = xv_alloc( Sel_prop_list );
251 if ( cPtr->next == NULL ) {
252 return ( (Atom) NULL );
253 }
254 cPtr = cPtr->next;
255 sprintf( str,"XV_SELECTION_%d", i );
256 cPtr->prop = XInternAtom(dpy, str, FALSE);
257 cPtr->avail = FALSE;
258 cPtr->next = NULL;
259 return ( cPtr->prop );
260 }
261
262
263 Pkg_private void
xv_sel_free_property(dpy,prop)264 xv_sel_free_property( dpy, prop )
265 Display *dpy;
266 Atom prop;
267 {
268 Sel_prop_list *plPtr;
269
270 plPtr = xv_sel_get_prop_list( dpy );
271
272 do {
273 if ( plPtr->prop == prop ) {
274 plPtr->avail = TRUE;
275 break;
276 }
277 if ( plPtr->next == NULL )
278 break;
279 plPtr = plPtr->next;
280 } while ( 1 );
281 }
282
283
284
285 /*
286 * Predicate function for XCheckIfEvent
287 *
288 */
289 /*ARGSUSED*/
290 Pkg_private int
xv_sel_predicate(display,xevent,args)291 xv_sel_predicate( display, xevent, args )
292 Display *display;
293 register XEvent *xevent;
294 char *args;
295 {
296 int eventType;
297
298 XV_BCOPY( (char *) args, (char *) &eventType, sizeof(int) );
299
300 if ( (xevent->type & 0177) == eventType )
301 return ( TRUE );
302
303 /*
304 * If we receive a SelectionRequest while waiting, handle selection request
305 * to avoid a dead lock.
306 */
307 if ( (xevent->type & 0177) == SelectionRequest ) {
308 XSelectionRequestEvent *reqEvent = (XSelectionRequestEvent *) xevent;
309
310 if (!xv_sel_handle_selection_request(reqEvent)) {
311 Xv_window xvWin;
312 Xv_Server server;
313
314 xvWin = win_data( display, reqEvent->requestor );
315
316 if ( xvWin == 0 )
317 server = xv_default_server;
318 else
319 server = XV_SERVER_FROM_WINDOW( xvWin );
320
321 /*
322 * Send this request to the old selection package.
323 */
324 selection_agent_selectionrequest( server, reqEvent);
325 }
326
327 }
328
329 return ( FALSE );
330 }
331
332 /*
333 * Predicate function for XCheckIfEvent
334 *
335 */
336 /*ARGSUSED*/
337 Pkg_private int
xv_sel_check_selnotify(display,xevent,args)338 xv_sel_check_selnotify( display, xevent, args )
339 Display *display;
340 register XEvent *xevent;
341 char *args;
342 {
343 Sel_reply_info reply;
344
345 XV_BCOPY( (char *) args, (char *) &reply, sizeof(Sel_reply_info) );
346
347 if ( (xevent->type & 0177) == SelectionNotify ) {
348 XSelectionEvent *ev = (XSelectionEvent *) xevent;
349
350 #ifdef SEL_DEBUG1
351 printf("REcieved SelectionNotify win = %d selection = %s property = %s target = %s\n", ev->requestor,XGetAtomName(ev->display,ev->selection),XGetAtomName(ev->display,ev->property),XGetAtomName(ev->display,ev->target));
352 #endif
353
354 if ((ev->target == *reply.target))
355 return ( TRUE );
356 /*
357 * else
358 * fprintf(stderr, "Possible BUG case - xv_sel_check_selnotify \n");
359 */
360 }
361
362 /*
363 * If we receive a SelectionRequest while waiting, handle selection request
364 * to avoid a dead lock.
365 */
366 if ( (xevent->type & 0177) == SelectionRequest ) {
367 XSelectionRequestEvent *reqEvent = (XSelectionRequestEvent *) xevent;
368
369 if (!xv_sel_handle_selection_request(reqEvent)) {
370 Xv_window xvWin;
371 Xv_Server server;
372
373 xvWin = win_data( display, reqEvent->requestor );
374
375 if ( xvWin == 0 )
376 server = xv_default_server;
377 else
378 server = XV_SERVER_FROM_WINDOW( xvWin );
379
380 /*
381 * Send this request to the old selection package.
382 */
383 selection_agent_selectionrequest( server, reqEvent);
384 }
385
386 }
387
388 return ( FALSE );
389 }
390
391
392
393
394 Pkg_private char *
xv_sel_atom_to_str(dpy,atom,xid)395 xv_sel_atom_to_str( dpy, atom, xid )
396 Display *dpy;
397 Atom atom;
398 XID xid;
399 {
400 Xv_window xvWin;
401 Xv_opaque server;
402
403 if ( xid == 0 )
404 server = xv_default_server;
405 else {
406 xvWin = win_data( dpy, xid );
407 server = XV_SERVER_FROM_WINDOW( xvWin );
408 }
409
410 return ( (char *) xv_get( server, SERVER_ATOM_NAME, atom ));
411 }
412
413 Pkg_private Atom
xv_sel_str_to_atom(dpy,str,xid)414 xv_sel_str_to_atom( dpy, str, xid )
415 Display *dpy;
416 char *str;
417 XID xid;
418 {
419 Xv_window xvWin;
420 Xv_opaque server;
421
422 if ( xid == 0 )
423 server = xv_default_server;
424 else {
425 xvWin = win_data( dpy, xid );
426 server = XV_SERVER_FROM_WINDOW( xvWin );
427 }
428
429 return ( (Atom) xv_get( server, SERVER_ATOM, str ));
430 }
431
432 /*
433 * REMINDER: Go over the erro codes make sure they match the spec!!
434 */
435 /*ARGSUSED*/
436 Pkg_private int
xv_sel_handle_error(errCode,sel,replyInfo,target)437 xv_sel_handle_error( errCode, sel, replyInfo, target )
438 int errCode;
439 Sel_req_info *sel;
440 Sel_reply_info *replyInfo;
441 Atom target;
442 {
443 Selection_requestor sel_req;
444
445 if ( sel != NULL )
446 sel_req = SEL_REQUESTOR_PUBLIC( sel );
447
448 /* REMINDER: Need to remove all the printf!! */
449
450 switch ( errCode ) {
451 case SEL_BAD_PROPERTY :
452 #ifdef SEL_DEBUG
453 printf("xv_sel_handle_error: Bad property!\n");
454 #endif
455 break;
456 case SEL_BAD_CONVERSION :
457 #ifdef SEL_DEBUG
458 printf("xv_sel_handle_error: Bad conversion!\n");
459 #endif
460 break;
461 case SEL_BAD_TIME:
462 #ifdef SEL_DEBUG
463 printf("xv_sel_handle_error: Bad time!\n");
464 #endif
465 break;
466 case SEL_BAD_WIN_ID:
467 #ifdef SEL_DEBUG
468 printf("xv_sel_handle_error: Bad window id!\n");
469 #endif
470 break;
471 case SEL_TIMEDOUT:
472 #ifdef SEL_DEBUG
473 printf("xv_sel_handle_error: Timed out!\n");
474 #endif
475 break;
476 case SEL_PROPERTY_DELETED:
477 #ifdef SEL_DEBUG
478 printf("xv_sel_handle_error: Expected a PropertyNotify event stat==NewValue!\n");
479 #endif
480 break;
481 case SEL_BAD_PROPERTY_EVENT:
482 #ifdef SEL_DEBUG
483 printf("xv_sel_handle_error: Owner received a bad PropertyNotify event !\n");
484 #endif
485 break;
486 }
487
488 if ( (sel != NULL) && (sel->reply_proc != NULL) )
489 (*sel->reply_proc)( sel_req, target, NULL, &errCode, SEL_ERROR, 0 );
490 }
491
492
493 /*
494 * xv_sel_block_for_event
495 *
496 * Scan the input queue for the specified event.
497 * If there aren't any events in the queue, select() for them until a
498 * certain timeout period has elapsed. Return value indicates whether the
499 * specified event was seen.
500 */
501 Pkg_private int
xv_sel_block_for_event(display,xevent,seconds,predicate,arg)502 xv_sel_block_for_event( display, xevent, seconds, predicate, arg )
503 Display *display;
504 XEvent *xevent;
505 int seconds;
506 int (*predicate)();
507 char *arg;
508 {
509 fd_set rfds;
510 int result;
511 struct timeval timeout;
512 struct timeval starttime, curtime, diff1, diff2;
513 extern int errno;
514
515 timeout.tv_sec = seconds;
516 timeout.tv_usec = 0;
517
518 (void) gettimeofday(&starttime, NULL);
519 XSync( display, False );
520 while (1) {
521 /*
522 * Check for data on the connection. Read it and scan it.
523 */
524 if (XCheckIfEvent(display, xevent, predicate, (char *) arg ))
525 return( TRUE );
526
527 /*
528 * We've drained the queue, so we must select for more.
529 */
530 FD_ZERO( &rfds );
531 FD_SET( ConnectionNumber( display ), &rfds );
532
533 result = select( ConnectionNumber( display ) + 1, &rfds, NULL,
534 NULL, &timeout);
535
536 if ( result == 0 ) {
537 ((XSelectionEvent *) xevent)->property = None;
538 /* REMINDER: Do we need this ^^^ here? */
539 #ifdef SEL_DEBUG
540 printf("Selection Timed out!\n");
541 #endif
542 /* we timed out without getting anything */
543 return FALSE;
544 }
545
546 /*
547 * Report errors. If we were interrupted (errno == EINTR), we simply
548 * continue around the loop. We scan the input queue again.
549 */
550 if (result == -1 && errno != EINTR)
551 perror("Select");
552
553 /*
554 * Either we got interrupted or the descriptor became ready.
555 * Compute the remaining time on the timeout.
556 */
557 (void) gettimeofday(&curtime, NULL);
558 tvdiff(&starttime, &curtime, &diff1);
559 tvdiff(&diff1, &timeout, &diff2);
560 timeout = diff2;
561 starttime = curtime;
562 if (timeout.tv_sec < 0)
563 return False;
564 }
565 }
566
567
568
569
570 /* compute t2 - t1 and return the time value in diff */
571 static void
tvdiff(t1,t2,diff)572 tvdiff(t1, t2, diff)
573 struct timeval *t1, *t2, *diff;
574 {
575 diff->tv_sec = t2->tv_sec - t1->tv_sec;
576 diff->tv_usec = t2->tv_usec - t1->tv_usec;
577 if (diff->tv_usec < 0) {
578 diff->tv_sec -= 1;
579 diff->tv_usec += 1000000;
580 }
581 }
582
583
584
585 Pkg_private Sel_req_tbl *
xv_sel_set_reply(reply)586 xv_sel_set_reply( reply )
587 Sel_reply_info *reply;
588 {
589 Sel_req_tbl *reqTbl;
590 Display *dpy;
591
592 if ( replyCtx == 0 )
593 replyCtx = XUniqueContext();
594
595 dpy = reply->seln->dpy;
596
597 if ( XFindContext( dpy, DefaultRootWindow(dpy), replyCtx,
598 (caddr_t *)&reqTbl )) {
599 reqTbl = xv_alloc( Sel_req_tbl );
600 reqTbl->done = FALSE;
601 reqTbl->reply = reply;
602 reqTbl->next = NULL;
603 (void)XSaveContext( dpy, DefaultRootWindow(dpy),replyCtx,
604 (caddr_t *)reqTbl);
605 return reqTbl;
606 }
607 return (Sel_req_tbl *) xv_sel_add_new_req( reqTbl, reply );
608 }
609
610
611
612 Pkg_private Sel_req_tbl *
xv_sel_add_new_req(reqTbl,reply)613 xv_sel_add_new_req( reqTbl, reply )
614 Sel_req_tbl *reqTbl;
615 Sel_reply_info *reply;
616 {
617 Sel_req_tbl *rPtr;
618
619 rPtr = reqTbl;
620
621 /*
622 * If there is an slot open use it.
623 */
624 do {
625 if ( rPtr->done ) {
626 if ( rPtr->reply != NULL )
627 XFree( (char *)rPtr->reply );
628 rPtr->reply = reply;
629 rPtr->done = FALSE;
630 return reqTbl;
631 }
632 if ( rPtr->next == NULL )
633 break;
634 rPtr = rPtr->next;
635 } while ( 1 );
636
637 /*
638 * Create a new reply and add it to the list.
639 */
640 rPtr->next = xv_alloc( Sel_req_tbl );
641 if ( rPtr->next == NULL ) {
642 return( (Sel_req_tbl * ) NULL );
643 }
644 rPtr = rPtr->next;
645 rPtr->reply = reply;
646 rPtr->done = FALSE;
647 rPtr->next = NULL;
648
649 return reqTbl;
650 }
651
652
653
654 Pkg_private Sel_reply_info *
xv_sel_get_reply(event)655 xv_sel_get_reply( event )
656 XEvent *event;
657 {
658 Sel_req_tbl *reqTbl, *rPtr;
659 Display *dpy;
660
661 if ( replyCtx == 0 )
662 replyCtx = XUniqueContext();
663
664 if ( event->type == SelectionNotify )
665 dpy = event->xselection.display;
666 else
667 dpy = event->xproperty.display;
668
669 if ( XFindContext( dpy, DefaultRootWindow(dpy), replyCtx,
670 (caddr_t *)&reqTbl ))
671 return (Sel_reply_info *) NULL;
672
673 rPtr = reqTbl;
674
675 /*
676 * Find this window's reply struct.
677 */
678 do {
679 if ( !rPtr->done && SelMatchReply( event, rPtr->reply ) )
680 return rPtr->reply;
681
682 if ( rPtr->next == NULL )
683 break;
684 rPtr = rPtr->next;
685 } while ( 1 );
686
687 return (Sel_reply_info *) NULL;
688 }
689
690
691 static int
SelMatchReply(event,reply)692 SelMatchReply( event, reply )
693 XEvent *event;
694 Sel_reply_info *reply;
695 {
696 if ( event->type == SelectionNotify ) {
697 XSelectionEvent *ev = (XSelectionEvent *) event;
698
699 if (ev->requestor != reply->requestor)
700 return FALSE;
701
702 if ( ev->selection != reply->seln->selection )
703 return FALSE;
704
705 if ( ( ev->target != *reply->target) &&
706 (ev->target != reply->seln->atomList->incr ) )
707 return FALSE;
708 }
709 else {
710 XPropertyEvent *ev = (XPropertyEvent *) event;
711
712 if ( ev->window != reply->requestor )
713 return FALSE;
714
715 if ( ev->state != PropertyNewValue )
716 return FALSE;
717 }
718
719 return TRUE;
720 }
721
722
723
724 /*ARGSUSED*/
725 Pkg_private Notify_value
xv_sel_handle_sel_timeout(client,which)726 xv_sel_handle_sel_timeout( client, which )
727 Notify_client client;
728 int which;
729 {
730 Sel_reply_info *reply = (Sel_reply_info *) client;
731 Sel_req_tbl *reqTbl;
732
733
734 reqTbl = (Sel_req_tbl *) SelMatchReqTbl( reply );
735
736 if ( reqTbl != NULL ) {
737
738 if ( !reqTbl->done ) {
739 xv_sel_handle_error( SEL_TIMEDOUT, reply->req_info, reply,
740 *reply->target );
741 xv_sel_end_request( reply );
742 }
743 }
744
745 return NOTIFY_DONE;
746 }
747
748
749
750 static Sel_req_tbl *
SelMatchReqTbl(reply)751 SelMatchReqTbl( reply )
752 Sel_reply_info *reply;
753 {
754 Sel_req_tbl *reqTbl, *rPtr;
755 Display *dpy = reply->seln->dpy;
756
757 if ( replyCtx == 0 )
758 replyCtx = XUniqueContext();
759
760 if ( XFindContext( dpy, DefaultRootWindow(dpy), replyCtx,
761 (caddr_t *)&reqTbl ))
762 return FALSE;
763
764 rPtr = reqTbl;
765
766 /*
767 * Find this window's request table.
768 */
769 do {
770 if ( !rPtr->done && SelFindReply( reply, rPtr->reply ) )
771 return rPtr;
772
773 if ( rPtr->next == NULL )
774 break;
775 rPtr = rPtr->next;
776 } while ( 1 );
777
778 return (Sel_req_tbl *) NULL;
779 }
780
781
782 int
xv_sel_end_request(reply)783 xv_sel_end_request( reply )
784 Sel_reply_info *reply;
785 {
786 XWindowAttributes winAttr;
787 Sel_req_tbl *reqTbl;
788
789 reqTbl = SelMatchReqTbl( reply );
790
791 if ( reqTbl != NULL ) {
792
793 notify_set_itimer_func( (Notify_client) reply, NOTIFY_FUNC_NULL, ITIMER_REAL,
794 NULL, NULL);
795
796 /*
797 * Free all the properties that were created for the multiple
798 * request.
799 */
800 FreeMultiProp( reply );
801
802 reqTbl->done = TRUE;
803 /*
804 * If we have added PropertyChangeMask to the win, reset the mask to
805 * it's original state.
806 */
807 if ( reply->status == TRUE ) {
808 XGetWindowAttributes( reply->seln->dpy, reply->requestor, &winAttr );
809
810 XSelectInput(reply->seln->dpy, reply->requestor,
811 (winAttr.your_event_mask & ~(PropertyChangeMask)));
812 }
813
814 XDeleteContext( reply->seln->dpy, (Window) reply->seln->selection,
815 selCtx );
816
817 xv_sel_free_property( reply->seln->dpy, reqTbl->reply->property );
818
819 XFree( (char *)reqTbl->reply );
820 reqTbl->reply = NULL;
821 return TRUE;
822 }
823 return FALSE;
824 }
825
826
827
828
829 static int
SelFindReply(r1,r2)830 SelFindReply( r1, r2 )
831 Sel_reply_info *r1;
832 Sel_reply_info *r2;
833 {
834 /*
835 * Make sure it is really it!!
836 */
837 if ( (r1->requestor == r2->requestor) && (*r1->target == *r2->target) &&
838 (r1->property == r2->property) && (r1->format == r2->format) &&
839 (r1->time == r2->time) && (r2->length == r1->length) &&
840 (r1->seln->selection == r2->seln->selection) )
841 return TRUE;
842 return FALSE;
843 }
844
845
846 /*
847 * Free all the properties that were created for the multiple
848 * request.
849 */
850 static void
FreeMultiProp(reply)851 FreeMultiProp( reply )
852 Sel_reply_info *reply;
853 {
854 int i;
855
856 if ( reply->multiple ) {
857 for ( i=0; i < reply->multiple; i++ )
858 xv_sel_free_property( reply->seln->dpy, reply->atomPair[i].property );
859 }
860 }
861
862
863
864
865
866 /*ARGSUSED*/
867 Pkg_private int
xv_sel_check_property_event(display,xevent,args)868 xv_sel_check_property_event( display, xevent, args )
869 Display *display;
870 XEvent *xevent;
871 char *args;
872 {
873 Sel_reply_info reply;
874
875 XV_BCOPY( (char *) args, (char *) &reply, sizeof(Sel_reply_info) );
876
877 /*
878 * If some other process wants to become the selection owner, let
879 * it do so but continue handling the current transaction.
880 */
881 if ( ( xevent->type & 0177) == SelectionClear ) {
882 xv_sel_handle_selection_clear( (XSelectionClearEvent * ) xevent );
883 return FALSE;
884 }
885
886 if ( ( xevent->type & 0177) == PropertyNotify ) {
887 XPropertyEvent *ev = (XPropertyEvent *) xevent;
888 if ( ev->state == PropertyNewValue && ev->atom == reply.property &&
889 ev->time > reply.time )
890 return ( TRUE );
891 }
892 return ( FALSE );
893 }
894
895
896
897
898
899 Xv_private void
xv_sel_set_compat_data(dpy,selection,xid,clientType)900 xv_sel_set_compat_data( dpy, selection, xid, clientType )
901 Display *dpy;
902 Atom selection;
903 Window xid;
904 int clientType;
905 {
906 Sel_cmpat_info *cmptInfo, *infoPtr;
907
908 if ( cmpatCtx == 0 )
909 cmpatCtx = XUniqueContext();
910
911 if (XFindContext(dpy, DefaultRootWindow(dpy), cmpatCtx, (caddr_t *)&cmptInfo)) {
912 cmptInfo = xv_alloc( Sel_cmpat_info );
913 if ( cmptInfo == NULL ) {
914 return;
915 }
916 cmptInfo->selection = selection;
917 cmptInfo->owner = xid;
918 cmptInfo->clientType = clientType;
919 cmptInfo->next = NULL;
920 (void)XSaveContext(dpy, DefaultRootWindow(dpy), cmpatCtx, (caddr_t)cmptInfo);
921 return;
922 }
923 infoPtr = cmptInfo;
924
925 do {
926 if ( (infoPtr->selection == selection) || (infoPtr->selection == NULL) ) {
927 infoPtr->selection = selection;
928 infoPtr->clientType = clientType;
929 infoPtr->owner = xid;
930 return;
931 }
932
933 if ( infoPtr->next == NULL )
934 break;
935 infoPtr = infoPtr->next;
936 } while ( 1 );
937
938 infoPtr->next = xv_alloc( Sel_cmpat_info );
939 if ( infoPtr->next == NULL )
940 return;
941
942 infoPtr = infoPtr->next;
943 infoPtr->selection = selection;
944 infoPtr->clientType = clientType;
945 infoPtr->owner = xid;
946 infoPtr->next = NULL;
947 return;
948 }
949
950
951
952 Pkg_private void
xv_sel_free_compat_data(dpy,selection)953 xv_sel_free_compat_data( dpy, selection )
954 Display *dpy;
955 Atom selection;
956 {
957 Sel_cmpat_info *cmptInfo, *infoPtr;
958
959 if ( cmpatCtx == 0 )
960 cmpatCtx = XUniqueContext();
961 if ( XFindContext(dpy, DefaultRootWindow(dpy), cmpatCtx,(caddr_t *)&cmptInfo))
962 return;
963
964 infoPtr = cmptInfo;
965
966 do {
967 if ( infoPtr->selection == selection ) {
968 infoPtr->selection = NULL;
969 infoPtr->owner = NULL;
970 infoPtr->clientType = NULL;
971 return;
972 }
973 if ( infoPtr->next == NULL )
974 break;
975 infoPtr = infoPtr->next;
976 } while ( 1 );
977 }
978
979
980 Pkg_private void
xv_sel_send_old_pkg_sel_clear(dpy,selection,xid,time)981 xv_sel_send_old_pkg_sel_clear( dpy, selection, xid, time )
982 Display *dpy;
983 Atom selection;
984 Window xid;
985 Time time;
986 {
987 Sel_cmpat_info *cmpatInfo, *infoPtr;
988
989 if ( cmpatCtx == 0 )
990 cmpatCtx = XUniqueContext();
991 if ( XFindContext(dpy, DefaultRootWindow(dpy), cmpatCtx,(caddr_t *)&cmpatInfo))
992 return;
993
994 infoPtr = cmpatInfo;
995 do {
996 if ( (infoPtr->selection == selection) &&
997 (infoPtr->clientType == OLD_SEL_CLIENT) ) {
998 Xv_window xvWin;
999 Xv_Server server;
1000 Seln_agent_info *agent;
1001 XSelectionClearEvent clrEvent;
1002 Seln_holder holder;
1003 Seln_request *response;
1004
1005 clrEvent.display = dpy;
1006 clrEvent.window = infoPtr->owner;
1007 clrEvent.selection = selection;
1008 clrEvent.time = time;
1009
1010 xvWin = win_data( dpy, xid );
1011 server = XV_SERVER_FROM_WINDOW( xvWin );
1012
1013 holder = selection_inquire( server, SELN_PRIMARY );
1014 response = selection_ask( server, &holder, SELN_REQ_YIELD, NULL, 0 );
1015
1016 agent = (Seln_agent_info *) xv_get(server, (Attr_attribute)XV_KEY_DATA,
1017 SELN_AGENT_INFO);
1018 seln_give_up_selection( server,
1019 selection_to_rank( selection, agent));
1020
1021 selection_agent_clear( server, &clrEvent );
1022
1023 break;
1024 }
1025 if ( infoPtr->next == NULL )
1026 break;
1027
1028 infoPtr = infoPtr->next;
1029 }while (1);
1030 }
1031
1032
1033
1034 Xv_private int
xv_seln_handle_req(cmpatInfo,dpy,sel,target,prop,req,time)1035 xv_seln_handle_req( cmpatInfo, dpy, sel, target, prop, req, time)
1036 Sel_cmpat_info *cmpatInfo;
1037 Display *dpy;
1038 Atom sel;
1039 Atom target;
1040 Atom prop;
1041 Window req;
1042 Time time;
1043 {
1044 XSelectionRequestEvent reqEvent;
1045 Sel_cmpat_info *infoPtr;
1046
1047 if ( cmpatInfo == (Sel_cmpat_info *) NULL )
1048 return FALSE;
1049
1050 infoPtr = cmpatInfo;
1051 do {
1052 if ( infoPtr->selection != sel ) {
1053 if ( infoPtr->next == NULL )
1054 return FALSE;
1055 infoPtr = infoPtr->next;
1056 } else {
1057 /*
1058 * We found the local selection owner data!!
1059 */
1060 reqEvent.display = dpy;
1061 reqEvent.owner = infoPtr->owner;
1062 reqEvent.requestor = req;
1063 reqEvent.selection = infoPtr->selection;
1064 reqEvent.target = target;
1065 reqEvent.property = prop;
1066 reqEvent.time = time;
1067 break;
1068 }
1069 } while( 1 );
1070
1071 /*
1072 * Note that selection data transfer will fail if the request is:
1073 * MULTIPLE or INCR.
1074 * This routine is compatibility proc to solve the communication
1075 * problem between the old selection package and the new one.
1076 * This routine and all the refrences to it can be deleted after
1077 * textsw starts using the new selection package.
1078 */
1079 xv_sel_handle_selection_request( &reqEvent );
1080 return TRUE;
1081 }
1082
1083
1084
1085 Pkg_private Sel_cmpat_info *
xv_sel_get_compat_data(dpy)1086 xv_sel_get_compat_data( dpy )
1087 Display *dpy;
1088 {
1089 Sel_cmpat_info *cmpatInfo;
1090
1091 if ( XFindContext( dpy, DefaultRootWindow(dpy), cmpatCtx,
1092 (caddr_t *)&cmpatInfo ))
1093 return( (Sel_cmpat_info *) NULL );
1094 return( (Sel_cmpat_info *) cmpatInfo );
1095
1096 }
1097
1098
1099
1100 Xv_private void
xv_sel_send_old_owner_sel_clear(dpy,selection,xid,time)1101 xv_sel_send_old_owner_sel_clear( dpy, selection, xid, time )
1102 Display *dpy;
1103 Atom selection;
1104 Window xid;
1105 Time time;
1106 {
1107 Sel_cmpat_info *cmpatInfo, *infoPtr;
1108
1109 if ( cmpatCtx == 0 )
1110 cmpatCtx = XUniqueContext();
1111 if ( XFindContext(dpy, DefaultRootWindow(dpy), cmpatCtx,(caddr_t *)&cmpatInfo))
1112 return;
1113
1114 infoPtr = cmpatInfo;
1115 do {
1116 if ( (infoPtr->selection == selection) && (infoPtr->owner != xid) ) {
1117 XSelectionClearEvent clrEvent;
1118
1119 clrEvent.display = dpy;
1120 clrEvent.window = infoPtr->owner;
1121 clrEvent.selection = selection;
1122 clrEvent.time = time;
1123
1124 xv_sel_handle_selection_clear( &clrEvent );
1125 }
1126 if ( infoPtr->next == NULL )
1127 break;
1128 infoPtr = infoPtr->next;
1129 }while (1);
1130 }
1131
1132
1133