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