1 /***********************************************************
2 Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts,
3 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4 
5                         All Rights Reserved
6 
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Digital or MIT not be
12 used in advertising or publicity pertaining to distribution of the
13 software without specific, written prior permission.
14 
15 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21 SOFTWARE.
22 
23 ******************************************************************/
24 
25 /*
26 ** File:
27 **
28 **   xvmain.c --- Xv server extension main device independent module.
29 **
30 ** Author:
31 **
32 **   David Carver (Digital Workstation Engineering/Project Athena)
33 **
34 ** Revisions:
35 **
36 **   04.09.91 Carver
37 **     - change: stop video always generates an event even when video
38 **       wasn't active
39 **
40 **   29.08.91 Carver
41 **     - change: unrealizing windows no longer preempts video
42 **
43 **   11.06.91 Carver
44 **     - changed SetPortControl to SetPortAttribute
45 **     - changed GetPortControl to GetPortAttribute
46 **     - changed QueryBestSize
47 **
48 **   28.05.91 Carver
49 **     - fixed Put and Get requests to not preempt operations to same drawable
50 **
51 **   15.05.91 Carver
52 **     - version 2.0 upgrade
53 **
54 **   19.03.91 Carver
55 **     - fixed Put and Get requests to honor grabbed ports.
56 **     - fixed Video requests to update di structure with new drawable, and
57 **       client after calling ddx.
58 **
59 **   24.01.91 Carver
60 **     - version 1.4 upgrade
61 **
62 ** Notes:
63 **
64 **   Port structures reference client structures in a two different
65 **   ways: when grabs, or video is active.  Each reference is encoded
66 **   as fake client resources and thus when the client is goes away so
67 **   does the reference (it is zeroed).  No other action is taken, so
68 **   video doesn't necessarily stop.  It probably will as a result of
69 **   other resources going away, but if a client starts video using
70 **   none of its own resources, then the video will continue to play
71 **   after the client disappears.
72 **
73 **
74 */
75 
76 #ifdef HAVE_DIX_CONFIG_H
77 #include <dix-config.h>
78 #endif
79 
80 #include <string.h>
81 
82 #include <X11/X.h>
83 #include <X11/Xproto.h>
84 #include "misc.h"
85 #include "os.h"
86 #include "scrnintstr.h"
87 #include "windowstr.h"
88 #include "pixmapstr.h"
89 #include "gcstruct.h"
90 #include "extnsionst.h"
91 #include "extinit.h"
92 #include "dixstruct.h"
93 #include "resource.h"
94 #include "opaque.h"
95 #include "input.h"
96 
97 #define GLOBAL
98 
99 #include <X11/extensions/Xv.h>
100 #include <X11/extensions/Xvproto.h>
101 #include "xvdix.h"
102 
103 #ifdef PANORAMIX
104 #include "panoramiX.h"
105 #include "panoramiXsrv.h"
106 #endif
107 #include "xvdisp.h"
108 
109 static DevPrivateKeyRec XvScreenKeyRec;
110 
111 #define XvScreenKey (&XvScreenKeyRec)
112 unsigned long XvExtensionGeneration = 0;
113 unsigned long XvScreenGeneration = 0;
114 unsigned long XvResourceGeneration = 0;
115 
116 int XvReqCode;
117 int XvEventBase;
118 int XvErrorBase;
119 
120 RESTYPE XvRTPort;
121 RESTYPE XvRTEncoding;
122 RESTYPE XvRTGrab;
123 RESTYPE XvRTVideoNotify;
124 RESTYPE XvRTVideoNotifyList;
125 RESTYPE XvRTPortNotify;
126 
127 /* EXTERNAL */
128 
129 static void WriteSwappedVideoNotifyEvent(xvEvent *, xvEvent *);
130 static void WriteSwappedPortNotifyEvent(xvEvent *, xvEvent *);
131 static Bool CreateResourceTypes(void);
132 
133 static Bool XvCloseScreen(ScreenPtr);
134 static Bool XvDestroyPixmap(PixmapPtr);
135 static Bool XvDestroyWindow(WindowPtr);
136 static void XvResetProc(ExtensionEntry *);
137 static int XvdiDestroyGrab(void *, XID);
138 static int XvdiDestroyEncoding(void *, XID);
139 static int XvdiDestroyVideoNotify(void *, XID);
140 static int XvdiDestroyPortNotify(void *, XID);
141 static int XvdiDestroyVideoNotifyList(void *, XID);
142 static int XvdiDestroyPort(void *, XID);
143 static int XvdiSendVideoNotify(XvPortPtr, DrawablePtr, int);
144 
145 /*
146 ** XvExtensionInit
147 **
148 **
149 */
150 
151 void
XvExtensionInit(void)152 XvExtensionInit(void)
153 {
154     ExtensionEntry *extEntry;
155 
156     if (!dixRegisterPrivateKey(&XvScreenKeyRec, PRIVATE_SCREEN, 0))
157         return;
158 
159     /* Look to see if any screens were initialized; if not then
160        init global variables so the extension can function */
161     if (XvScreenGeneration != serverGeneration) {
162         if (!CreateResourceTypes()) {
163             ErrorF("XvExtensionInit: Unable to allocate resource types\n");
164             return;
165         }
166 #ifdef PANORAMIX
167         XineramaRegisterConnectionBlockCallback(XineramifyXv);
168 #endif
169         XvScreenGeneration = serverGeneration;
170     }
171 
172     if (XvExtensionGeneration != serverGeneration) {
173         XvExtensionGeneration = serverGeneration;
174 
175         extEntry = AddExtension(XvName, XvNumEvents, XvNumErrors,
176                                 ProcXvDispatch, SProcXvDispatch,
177                                 XvResetProc, StandardMinorOpcode);
178         if (!extEntry) {
179             FatalError("XvExtensionInit: AddExtensions failed\n");
180         }
181 
182         XvReqCode = extEntry->base;
183         XvEventBase = extEntry->eventBase;
184         XvErrorBase = extEntry->errorBase;
185 
186         EventSwapVector[XvEventBase + XvVideoNotify] =
187             (EventSwapPtr) WriteSwappedVideoNotifyEvent;
188         EventSwapVector[XvEventBase + XvPortNotify] =
189             (EventSwapPtr) WriteSwappedPortNotifyEvent;
190 
191         SetResourceTypeErrorValue(XvRTPort, _XvBadPort);
192         (void) MakeAtom(XvName, strlen(XvName), xTrue);
193 
194     }
195 }
196 
197 static Bool
CreateResourceTypes(void)198 CreateResourceTypes(void)
199 {
200 
201     if (XvResourceGeneration == serverGeneration)
202         return TRUE;
203 
204     XvResourceGeneration = serverGeneration;
205 
206     if (!(XvRTPort = CreateNewResourceType(XvdiDestroyPort, "XvRTPort"))) {
207         ErrorF("CreateResourceTypes: failed to allocate port resource.\n");
208         return FALSE;
209     }
210 
211     if (!(XvRTGrab = CreateNewResourceType(XvdiDestroyGrab, "XvRTGrab"))) {
212         ErrorF("CreateResourceTypes: failed to allocate grab resource.\n");
213         return FALSE;
214     }
215 
216     if (!(XvRTEncoding = CreateNewResourceType(XvdiDestroyEncoding,
217                                                "XvRTEncoding"))) {
218         ErrorF("CreateResourceTypes: failed to allocate encoding resource.\n");
219         return FALSE;
220     }
221 
222     if (!(XvRTVideoNotify = CreateNewResourceType(XvdiDestroyVideoNotify,
223                                                   "XvRTVideoNotify"))) {
224         ErrorF
225             ("CreateResourceTypes: failed to allocate video notify resource.\n");
226         return FALSE;
227     }
228 
229     if (!
230         (XvRTVideoNotifyList =
231          CreateNewResourceType(XvdiDestroyVideoNotifyList,
232                                "XvRTVideoNotifyList"))) {
233         ErrorF
234             ("CreateResourceTypes: failed to allocate video notify list resource.\n");
235         return FALSE;
236     }
237 
238     if (!(XvRTPortNotify = CreateNewResourceType(XvdiDestroyPortNotify,
239                                                  "XvRTPortNotify"))) {
240         ErrorF
241             ("CreateResourceTypes: failed to allocate port notify resource.\n");
242         return FALSE;
243     }
244 
245     return TRUE;
246 
247 }
248 
249 int
XvScreenInit(ScreenPtr pScreen)250 XvScreenInit(ScreenPtr pScreen)
251 {
252     XvScreenPtr pxvs;
253 
254     if (XvScreenGeneration != serverGeneration) {
255         if (!CreateResourceTypes()) {
256             ErrorF("XvScreenInit: Unable to allocate resource types\n");
257             return BadAlloc;
258         }
259 #ifdef PANORAMIX
260         XineramaRegisterConnectionBlockCallback(XineramifyXv);
261 #endif
262         XvScreenGeneration = serverGeneration;
263     }
264 
265     if (!dixRegisterPrivateKey(&XvScreenKeyRec, PRIVATE_SCREEN, 0))
266         return BadAlloc;
267 
268     if (dixLookupPrivate(&pScreen->devPrivates, XvScreenKey)) {
269         ErrorF("XvScreenInit: screen devPrivates ptr non-NULL before init\n");
270     }
271 
272     /* ALLOCATE SCREEN PRIVATE RECORD */
273 
274     pxvs = malloc(sizeof(XvScreenRec));
275     if (!pxvs) {
276         ErrorF("XvScreenInit: Unable to allocate screen private structure\n");
277         return BadAlloc;
278     }
279 
280     dixSetPrivate(&pScreen->devPrivates, XvScreenKey, pxvs);
281 
282     pxvs->DestroyPixmap = pScreen->DestroyPixmap;
283     pxvs->DestroyWindow = pScreen->DestroyWindow;
284     pxvs->CloseScreen = pScreen->CloseScreen;
285 
286     pScreen->DestroyPixmap = XvDestroyPixmap;
287     pScreen->DestroyWindow = XvDestroyWindow;
288     pScreen->CloseScreen = XvCloseScreen;
289 
290     return Success;
291 }
292 
293 static Bool
XvCloseScreen(ScreenPtr pScreen)294 XvCloseScreen(ScreenPtr pScreen)
295 {
296 
297     XvScreenPtr pxvs;
298 
299     pxvs = (XvScreenPtr) dixLookupPrivate(&pScreen->devPrivates, XvScreenKey);
300 
301     pScreen->DestroyPixmap = pxvs->DestroyPixmap;
302     pScreen->DestroyWindow = pxvs->DestroyWindow;
303     pScreen->CloseScreen = pxvs->CloseScreen;
304 
305     free(pxvs);
306 
307     dixSetPrivate(&pScreen->devPrivates, XvScreenKey, NULL);
308 
309     return (*pScreen->CloseScreen) (pScreen);
310 }
311 
312 static void
XvResetProc(ExtensionEntry * extEntry)313 XvResetProc(ExtensionEntry * extEntry)
314 {
315     XvResetProcVector();
316 }
317 
318 DevPrivateKey
XvGetScreenKey(void)319 XvGetScreenKey(void)
320 {
321     return XvScreenKey;
322 }
323 
324 unsigned long
XvGetRTPort(void)325 XvGetRTPort(void)
326 {
327     return XvRTPort;
328 }
329 
330 static void
XvStopAdaptors(DrawablePtr pDrawable)331 XvStopAdaptors(DrawablePtr pDrawable)
332 {
333     ScreenPtr pScreen = pDrawable->pScreen;
334     XvScreenPtr pxvs = dixLookupPrivate(&pScreen->devPrivates, XvScreenKey);
335     XvAdaptorPtr pa = pxvs->pAdaptors;
336     int na = pxvs->nAdaptors;
337 
338     /* CHECK TO SEE IF THIS PORT IS IN USE */
339     while (na--) {
340         XvPortPtr pp = pa->pPorts;
341         int np = pa->nPorts;
342 
343         while (np--) {
344             if (pp->pDraw == pDrawable) {
345                 XvdiSendVideoNotify(pp, pDrawable, XvPreempted);
346 
347                 (void) (*pp->pAdaptor->ddStopVideo) (pp, pDrawable);
348 
349                 pp->pDraw = NULL;
350                 pp->client = NULL;
351                 pp->time = currentTime;
352             }
353             pp++;
354         }
355         pa++;
356     }
357 }
358 
359 static Bool
XvDestroyPixmap(PixmapPtr pPix)360 XvDestroyPixmap(PixmapPtr pPix)
361 {
362     ScreenPtr pScreen = pPix->drawable.pScreen;
363     Bool status;
364 
365     if (pPix->refcnt == 1)
366         XvStopAdaptors(&pPix->drawable);
367 
368     SCREEN_PROLOGUE(pScreen, DestroyPixmap);
369     status = (*pScreen->DestroyPixmap) (pPix);
370     SCREEN_EPILOGUE(pScreen, DestroyPixmap, XvDestroyPixmap);
371 
372     return status;
373 
374 }
375 
376 static Bool
XvDestroyWindow(WindowPtr pWin)377 XvDestroyWindow(WindowPtr pWin)
378 {
379     ScreenPtr pScreen = pWin->drawable.pScreen;
380     Bool status;
381 
382     XvStopAdaptors(&pWin->drawable);
383 
384     SCREEN_PROLOGUE(pScreen, DestroyWindow);
385     status = (*pScreen->DestroyWindow) (pWin);
386     SCREEN_EPILOGUE(pScreen, DestroyWindow, XvDestroyWindow);
387 
388     return status;
389 
390 }
391 
392 static int
XvdiDestroyPort(void * pPort,XID id)393 XvdiDestroyPort(void *pPort, XID id)
394 {
395     return Success;
396 }
397 
398 static int
XvdiDestroyGrab(void * pGrab,XID id)399 XvdiDestroyGrab(void *pGrab, XID id)
400 {
401     ((XvGrabPtr) pGrab)->client = NULL;
402     return Success;
403 }
404 
405 static int
XvdiDestroyVideoNotify(void * pn,XID id)406 XvdiDestroyVideoNotify(void *pn, XID id)
407 {
408     /* JUST CLEAR OUT THE client POINTER FIELD */
409 
410     ((XvVideoNotifyPtr) pn)->client = NULL;
411     return Success;
412 }
413 
414 static int
XvdiDestroyPortNotify(void * pn,XID id)415 XvdiDestroyPortNotify(void *pn, XID id)
416 {
417     /* JUST CLEAR OUT THE client POINTER FIELD */
418 
419     ((XvPortNotifyPtr) pn)->client = NULL;
420     return Success;
421 }
422 
423 static int
XvdiDestroyVideoNotifyList(void * pn,XID id)424 XvdiDestroyVideoNotifyList(void *pn, XID id)
425 {
426     XvVideoNotifyPtr npn, cpn;
427 
428     /* ACTUALLY DESTROY THE NOTITY LIST */
429 
430     cpn = (XvVideoNotifyPtr) pn;
431 
432     while (cpn) {
433         npn = cpn->next;
434         if (cpn->client)
435             FreeResource(cpn->id, XvRTVideoNotify);
436         free(cpn);
437         cpn = npn;
438     }
439     return Success;
440 }
441 
442 static int
XvdiDestroyEncoding(void * value,XID id)443 XvdiDestroyEncoding(void *value, XID id)
444 {
445     return Success;
446 }
447 
448 static int
XvdiSendVideoNotify(XvPortPtr pPort,DrawablePtr pDraw,int reason)449 XvdiSendVideoNotify(XvPortPtr pPort, DrawablePtr pDraw, int reason)
450 {
451     XvVideoNotifyPtr pn;
452 
453     dixLookupResourceByType((void **) &pn, pDraw->id, XvRTVideoNotifyList,
454                             serverClient, DixReadAccess);
455 
456     while (pn) {
457         xvEvent event = {
458             .u.videoNotify.reason = reason,
459             .u.videoNotify.time = currentTime.milliseconds,
460             .u.videoNotify.drawable = pDraw->id,
461             .u.videoNotify.port = pPort->id
462         };
463         event.u.u.type = XvEventBase + XvVideoNotify;
464         WriteEventsToClient(pn->client, 1, (xEventPtr) &event);
465         pn = pn->next;
466     }
467 
468     return Success;
469 
470 }
471 
472 int
XvdiSendPortNotify(XvPortPtr pPort,Atom attribute,INT32 value)473 XvdiSendPortNotify(XvPortPtr pPort, Atom attribute, INT32 value)
474 {
475     XvPortNotifyPtr pn;
476 
477     pn = pPort->pNotify;
478 
479     while (pn) {
480         xvEvent event = {
481             .u.portNotify.time = currentTime.milliseconds,
482             .u.portNotify.port = pPort->id,
483             .u.portNotify.attribute = attribute,
484             .u.portNotify.value = value
485         };
486         event.u.u.type = XvEventBase + XvPortNotify;
487         WriteEventsToClient(pn->client, 1, (xEventPtr) &event);
488         pn = pn->next;
489     }
490 
491     return Success;
492 
493 }
494 
495 #define CHECK_SIZE(dw, dh, sw, sh) {                                  \
496   if(!dw || !dh || !sw || !sh)  return Success;                       \
497   /* The region code will break these if they are too large */        \
498   if((dw > 32767) || (dh > 32767) || (sw > 32767) || (sh > 32767))    \
499         return BadValue;                                              \
500 }
501 
502 int
XvdiPutVideo(ClientPtr client,DrawablePtr pDraw,XvPortPtr pPort,GCPtr pGC,INT16 vid_x,INT16 vid_y,CARD16 vid_w,CARD16 vid_h,INT16 drw_x,INT16 drw_y,CARD16 drw_w,CARD16 drw_h)503 XvdiPutVideo(ClientPtr client,
504              DrawablePtr pDraw,
505              XvPortPtr pPort,
506              GCPtr pGC,
507              INT16 vid_x, INT16 vid_y,
508              CARD16 vid_w, CARD16 vid_h,
509              INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
510 {
511     DrawablePtr pOldDraw;
512 
513     CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
514 
515     /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
516 
517     UpdateCurrentTime();
518 
519     /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
520        INFORM CLIENT OF ITS FAILURE */
521 
522     if (pPort->grab.client && (pPort->grab.client != client)) {
523         XvdiSendVideoNotify(pPort, pDraw, XvBusy);
524         return Success;
525     }
526 
527     /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED
528        EVENTS TO ANY CLIENTS WHO WANT THEM */
529 
530     pOldDraw = pPort->pDraw;
531     if ((pOldDraw) && (pOldDraw != pDraw)) {
532         XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
533     }
534 
535     (void) (*pPort->pAdaptor->ddPutVideo) (pDraw, pPort, pGC,
536                                            vid_x, vid_y, vid_w, vid_h,
537                                            drw_x, drw_y, drw_w, drw_h);
538 
539     if ((pPort->pDraw) && (pOldDraw != pDraw)) {
540         pPort->client = client;
541         XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted);
542     }
543 
544     pPort->time = currentTime;
545 
546     return Success;
547 
548 }
549 
550 int
XvdiPutStill(ClientPtr client,DrawablePtr pDraw,XvPortPtr pPort,GCPtr pGC,INT16 vid_x,INT16 vid_y,CARD16 vid_w,CARD16 vid_h,INT16 drw_x,INT16 drw_y,CARD16 drw_w,CARD16 drw_h)551 XvdiPutStill(ClientPtr client,
552              DrawablePtr pDraw,
553              XvPortPtr pPort,
554              GCPtr pGC,
555              INT16 vid_x, INT16 vid_y,
556              CARD16 vid_w, CARD16 vid_h,
557              INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
558 {
559     int status;
560 
561     CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
562 
563     /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
564 
565     UpdateCurrentTime();
566 
567     /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
568        INFORM CLIENT OF ITS FAILURE */
569 
570     if (pPort->grab.client && (pPort->grab.client != client)) {
571         XvdiSendVideoNotify(pPort, pDraw, XvBusy);
572         return Success;
573     }
574 
575     pPort->time = currentTime;
576 
577     status = (*pPort->pAdaptor->ddPutStill) (pDraw, pPort, pGC,
578                                              vid_x, vid_y, vid_w, vid_h,
579                                              drw_x, drw_y, drw_w, drw_h);
580 
581     return status;
582 
583 }
584 
585 int
XvdiPutImage(ClientPtr client,DrawablePtr pDraw,XvPortPtr pPort,GCPtr pGC,INT16 src_x,INT16 src_y,CARD16 src_w,CARD16 src_h,INT16 drw_x,INT16 drw_y,CARD16 drw_w,CARD16 drw_h,XvImagePtr image,unsigned char * data,Bool sync,CARD16 width,CARD16 height)586 XvdiPutImage(ClientPtr client,
587              DrawablePtr pDraw,
588              XvPortPtr pPort,
589              GCPtr pGC,
590              INT16 src_x, INT16 src_y,
591              CARD16 src_w, CARD16 src_h,
592              INT16 drw_x, INT16 drw_y,
593              CARD16 drw_w, CARD16 drw_h,
594              XvImagePtr image,
595              unsigned char *data, Bool sync, CARD16 width, CARD16 height)
596 {
597     CHECK_SIZE(drw_w, drw_h, src_w, src_h);
598 
599     /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
600 
601     UpdateCurrentTime();
602 
603     /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
604        INFORM CLIENT OF ITS FAILURE */
605 
606     if (pPort->grab.client && (pPort->grab.client != client)) {
607         XvdiSendVideoNotify(pPort, pDraw, XvBusy);
608         return Success;
609     }
610 
611     pPort->time = currentTime;
612 
613     return (*pPort->pAdaptor->ddPutImage) (pDraw, pPort, pGC,
614                                            src_x, src_y, src_w, src_h,
615                                            drw_x, drw_y, drw_w, drw_h,
616                                            image, data, sync, width, height);
617 }
618 
619 int
XvdiGetVideo(ClientPtr client,DrawablePtr pDraw,XvPortPtr pPort,GCPtr pGC,INT16 vid_x,INT16 vid_y,CARD16 vid_w,CARD16 vid_h,INT16 drw_x,INT16 drw_y,CARD16 drw_w,CARD16 drw_h)620 XvdiGetVideo(ClientPtr client,
621              DrawablePtr pDraw,
622              XvPortPtr pPort,
623              GCPtr pGC,
624              INT16 vid_x, INT16 vid_y,
625              CARD16 vid_w, CARD16 vid_h,
626              INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
627 {
628     DrawablePtr pOldDraw;
629 
630     CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
631 
632     /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
633 
634     UpdateCurrentTime();
635 
636     /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
637        INFORM CLIENT OF ITS FAILURE */
638 
639     if (pPort->grab.client && (pPort->grab.client != client)) {
640         XvdiSendVideoNotify(pPort, pDraw, XvBusy);
641         return Success;
642     }
643 
644     /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED
645        EVENTS TO ANY CLIENTS WHO WANT THEM */
646 
647     pOldDraw = pPort->pDraw;
648     if ((pOldDraw) && (pOldDraw != pDraw)) {
649         XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
650     }
651 
652     (void) (*pPort->pAdaptor->ddGetVideo) (pDraw, pPort, pGC,
653                                            vid_x, vid_y, vid_w, vid_h,
654                                            drw_x, drw_y, drw_w, drw_h);
655 
656     if ((pPort->pDraw) && (pOldDraw != pDraw)) {
657         pPort->client = client;
658         XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted);
659     }
660 
661     pPort->time = currentTime;
662 
663     return Success;
664 
665 }
666 
667 int
XvdiGetStill(ClientPtr client,DrawablePtr pDraw,XvPortPtr pPort,GCPtr pGC,INT16 vid_x,INT16 vid_y,CARD16 vid_w,CARD16 vid_h,INT16 drw_x,INT16 drw_y,CARD16 drw_w,CARD16 drw_h)668 XvdiGetStill(ClientPtr client,
669              DrawablePtr pDraw,
670              XvPortPtr pPort,
671              GCPtr pGC,
672              INT16 vid_x, INT16 vid_y,
673              CARD16 vid_w, CARD16 vid_h,
674              INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
675 {
676     int status;
677 
678     CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
679 
680     /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
681 
682     UpdateCurrentTime();
683 
684     /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
685        INFORM CLIENT OF ITS FAILURE */
686 
687     if (pPort->grab.client && (pPort->grab.client != client)) {
688         XvdiSendVideoNotify(pPort, pDraw, XvBusy);
689         return Success;
690     }
691 
692     status = (*pPort->pAdaptor->ddGetStill) (pDraw, pPort, pGC,
693                                              vid_x, vid_y, vid_w, vid_h,
694                                              drw_x, drw_y, drw_w, drw_h);
695 
696     pPort->time = currentTime;
697 
698     return status;
699 
700 }
701 
702 int
XvdiGrabPort(ClientPtr client,XvPortPtr pPort,Time ctime,int * p_result)703 XvdiGrabPort(ClientPtr client, XvPortPtr pPort, Time ctime, int *p_result)
704 {
705     unsigned long id;
706     TimeStamp time;
707 
708     UpdateCurrentTime();
709     time = ClientTimeToServerTime(ctime);
710 
711     if (pPort->grab.client && (client != pPort->grab.client)) {
712         *p_result = XvAlreadyGrabbed;
713         return Success;
714     }
715 
716     if ((CompareTimeStamps(time, currentTime) == LATER) ||
717         (CompareTimeStamps(time, pPort->time) == EARLIER)) {
718         *p_result = XvInvalidTime;
719         return Success;
720     }
721 
722     if (client == pPort->grab.client) {
723         *p_result = Success;
724         return Success;
725     }
726 
727     id = FakeClientID(client->index);
728 
729     if (!AddResource(id, XvRTGrab, &pPort->grab)) {
730         return BadAlloc;
731     }
732 
733     /* IF THERE IS ACTIVE VIDEO THEN STOP IT */
734 
735     if ((pPort->pDraw) && (client != pPort->client)) {
736         XvdiStopVideo(NULL, pPort, pPort->pDraw);
737     }
738 
739     pPort->grab.client = client;
740     pPort->grab.id = id;
741 
742     pPort->time = currentTime;
743 
744     *p_result = Success;
745 
746     return Success;
747 
748 }
749 
750 int
XvdiUngrabPort(ClientPtr client,XvPortPtr pPort,Time ctime)751 XvdiUngrabPort(ClientPtr client, XvPortPtr pPort, Time ctime)
752 {
753     TimeStamp time;
754 
755     UpdateCurrentTime();
756     time = ClientTimeToServerTime(ctime);
757 
758     if ((!pPort->grab.client) || (client != pPort->grab.client)) {
759         return Success;
760     }
761 
762     if ((CompareTimeStamps(time, currentTime) == LATER) ||
763         (CompareTimeStamps(time, pPort->time) == EARLIER)) {
764         return Success;
765     }
766 
767     /* FREE THE GRAB RESOURCE; AND SET THE GRAB CLIENT TO NULL */
768 
769     FreeResource(pPort->grab.id, XvRTGrab);
770     pPort->grab.client = NULL;
771 
772     pPort->time = currentTime;
773 
774     return Success;
775 
776 }
777 
778 int
XvdiSelectVideoNotify(ClientPtr client,DrawablePtr pDraw,BOOL onoff)779 XvdiSelectVideoNotify(ClientPtr client, DrawablePtr pDraw, BOOL onoff)
780 {
781     XvVideoNotifyPtr pn, tpn, fpn;
782     int rc;
783 
784     /* FIND VideoNotify LIST */
785 
786     rc = dixLookupResourceByType((void **) &pn, pDraw->id,
787                                  XvRTVideoNotifyList, client, DixWriteAccess);
788     if (rc != Success && rc != BadValue)
789         return rc;
790 
791     /* IF ONE DONES'T EXIST AND NO MASK, THEN JUST RETURN */
792 
793     if (!onoff && !pn)
794         return Success;
795 
796     /* IF ONE DOESN'T EXIST CREATE IT AND ADD A RESOURCE SO THAT THE LIST
797        WILL BE DELETED WHEN THE DRAWABLE IS DESTROYED */
798 
799     if (!pn) {
800         if (!(tpn = malloc(sizeof(XvVideoNotifyRec))))
801             return BadAlloc;
802         tpn->next = NULL;
803         tpn->client = NULL;
804         if (!AddResource(pDraw->id, XvRTVideoNotifyList, tpn))
805             return BadAlloc;
806     }
807     else {
808         /* LOOK TO SEE IF ENTRY ALREADY EXISTS */
809 
810         fpn = NULL;
811         tpn = pn;
812         while (tpn) {
813             if (tpn->client == client) {
814                 if (!onoff)
815                     tpn->client = NULL;
816                 return Success;
817             }
818             if (!tpn->client)
819                 fpn = tpn;      /* TAKE NOTE OF FREE ENTRY */
820             tpn = tpn->next;
821         }
822 
823         /* IF TUNNING OFF, THEN JUST RETURN */
824 
825         if (!onoff)
826             return Success;
827 
828         /* IF ONE ISN'T FOUND THEN ALLOCATE ONE AND LINK IT INTO THE LIST */
829 
830         if (fpn) {
831             tpn = fpn;
832         }
833         else {
834             if (!(tpn = malloc(sizeof(XvVideoNotifyRec))))
835                 return BadAlloc;
836             tpn->next = pn->next;
837             pn->next = tpn;
838         }
839     }
840 
841     /* INIT CLIENT PTR IN CASE WE CAN'T ADD RESOURCE */
842     /* ADD RESOURCE SO THAT IF CLIENT EXITS THE CLIENT PTR WILL BE CLEARED */
843 
844     tpn->client = NULL;
845     tpn->id = FakeClientID(client->index);
846     if (!AddResource(tpn->id, XvRTVideoNotify, tpn))
847         return BadAlloc;
848 
849     tpn->client = client;
850     return Success;
851 
852 }
853 
854 int
XvdiSelectPortNotify(ClientPtr client,XvPortPtr pPort,BOOL onoff)855 XvdiSelectPortNotify(ClientPtr client, XvPortPtr pPort, BOOL onoff)
856 {
857     XvPortNotifyPtr pn, tpn;
858 
859     /* SEE IF CLIENT IS ALREADY IN LIST */
860 
861     tpn = NULL;
862     pn = pPort->pNotify;
863     while (pn) {
864         if (!pn->client)
865             tpn = pn;           /* TAKE NOTE OF FREE ENTRY */
866         if (pn->client == client)
867             break;
868         pn = pn->next;
869     }
870 
871     /* IS THE CLIENT ALREADY ON THE LIST? */
872 
873     if (pn) {
874         /* REMOVE IT? */
875 
876         if (!onoff) {
877             pn->client = NULL;
878             FreeResource(pn->id, XvRTPortNotify);
879         }
880 
881         return Success;
882     }
883 
884     /* DIDN'T FIND IT; SO REUSE LIST ELEMENT IF ONE IS FREE OTHERWISE
885        CREATE A NEW ONE AND ADD IT TO THE BEGINNING OF THE LIST */
886 
887     if (!tpn) {
888         if (!(tpn = malloc(sizeof(XvPortNotifyRec))))
889             return BadAlloc;
890         tpn->next = pPort->pNotify;
891         pPort->pNotify = tpn;
892     }
893 
894     tpn->client = client;
895     tpn->id = FakeClientID(client->index);
896     if (!AddResource(tpn->id, XvRTPortNotify, tpn))
897         return BadAlloc;
898 
899     return Success;
900 
901 }
902 
903 int
XvdiStopVideo(ClientPtr client,XvPortPtr pPort,DrawablePtr pDraw)904 XvdiStopVideo(ClientPtr client, XvPortPtr pPort, DrawablePtr pDraw)
905 {
906     int status;
907 
908     /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */
909 
910     if (!pPort->pDraw || (pPort->pDraw != pDraw)) {
911         XvdiSendVideoNotify(pPort, pDraw, XvStopped);
912         return Success;
913     }
914 
915     /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
916        INFORM CLIENT OF ITS FAILURE */
917 
918     if ((client) && (pPort->grab.client) && (pPort->grab.client != client)) {
919         XvdiSendVideoNotify(pPort, pDraw, XvBusy);
920         return Success;
921     }
922 
923     XvdiSendVideoNotify(pPort, pDraw, XvStopped);
924 
925     status = (*pPort->pAdaptor->ddStopVideo) (pPort, pDraw);
926 
927     pPort->pDraw = NULL;
928     pPort->client = (ClientPtr) client;
929     pPort->time = currentTime;
930 
931     return status;
932 
933 }
934 
935 int
XvdiMatchPort(XvPortPtr pPort,DrawablePtr pDraw)936 XvdiMatchPort(XvPortPtr pPort, DrawablePtr pDraw)
937 {
938 
939     XvAdaptorPtr pa;
940     XvFormatPtr pf;
941     int nf;
942 
943     pa = pPort->pAdaptor;
944 
945     if (pa->pScreen != pDraw->pScreen)
946         return BadMatch;
947 
948     nf = pa->nFormats;
949     pf = pa->pFormats;
950 
951     while (nf--) {
952         if (pf->depth == pDraw->depth)
953             return Success;
954         pf++;
955     }
956 
957     return BadMatch;
958 
959 }
960 
961 int
XvdiSetPortAttribute(ClientPtr client,XvPortPtr pPort,Atom attribute,INT32 value)962 XvdiSetPortAttribute(ClientPtr client,
963                      XvPortPtr pPort, Atom attribute, INT32 value)
964 {
965     int status;
966 
967     status =
968         (*pPort->pAdaptor->ddSetPortAttribute) (pPort, attribute,
969                                                 value);
970     if (status == Success)
971         XvdiSendPortNotify(pPort, attribute, value);
972 
973     return status;
974 }
975 
976 int
XvdiGetPortAttribute(ClientPtr client,XvPortPtr pPort,Atom attribute,INT32 * p_value)977 XvdiGetPortAttribute(ClientPtr client,
978                      XvPortPtr pPort, Atom attribute, INT32 *p_value)
979 {
980 
981     return
982         (*pPort->pAdaptor->ddGetPortAttribute) (pPort, attribute,
983                                                 p_value);
984 
985 }
986 
987 static void _X_COLD
WriteSwappedVideoNotifyEvent(xvEvent * from,xvEvent * to)988 WriteSwappedVideoNotifyEvent(xvEvent * from, xvEvent * to)
989 {
990 
991     to->u.u.type = from->u.u.type;
992     to->u.u.detail = from->u.u.detail;
993     cpswaps(from->u.videoNotify.sequenceNumber,
994             to->u.videoNotify.sequenceNumber);
995     cpswapl(from->u.videoNotify.time, to->u.videoNotify.time);
996     cpswapl(from->u.videoNotify.drawable, to->u.videoNotify.drawable);
997     cpswapl(from->u.videoNotify.port, to->u.videoNotify.port);
998 
999 }
1000 
1001 static void _X_COLD
WriteSwappedPortNotifyEvent(xvEvent * from,xvEvent * to)1002 WriteSwappedPortNotifyEvent(xvEvent * from, xvEvent * to)
1003 {
1004 
1005     to->u.u.type = from->u.u.type;
1006     to->u.u.detail = from->u.u.detail;
1007     cpswaps(from->u.portNotify.sequenceNumber, to->u.portNotify.sequenceNumber);
1008     cpswapl(from->u.portNotify.time, to->u.portNotify.time);
1009     cpswapl(from->u.portNotify.port, to->u.portNotify.port);
1010     cpswapl(from->u.portNotify.value, to->u.portNotify.value);
1011 
1012 }
1013 
1014 void
XvFreeAdaptor(XvAdaptorPtr pAdaptor)1015 XvFreeAdaptor(XvAdaptorPtr pAdaptor)
1016 {
1017     int i;
1018 
1019     free(pAdaptor->name);
1020     pAdaptor->name = NULL;
1021 
1022     if (pAdaptor->pEncodings) {
1023         XvEncodingPtr pEncode = pAdaptor->pEncodings;
1024 
1025         for (i = 0; i < pAdaptor->nEncodings; i++, pEncode++)
1026             free(pEncode->name);
1027         free(pAdaptor->pEncodings);
1028         pAdaptor->pEncodings = NULL;
1029     }
1030 
1031     free(pAdaptor->pFormats);
1032     pAdaptor->pFormats = NULL;
1033 
1034     free(pAdaptor->pPorts);
1035     pAdaptor->pPorts = NULL;
1036 
1037     if (pAdaptor->pAttributes) {
1038         XvAttributePtr pAttribute = pAdaptor->pAttributes;
1039 
1040         for (i = 0; i < pAdaptor->nAttributes; i++, pAttribute++)
1041             free(pAttribute->name);
1042         free(pAdaptor->pAttributes);
1043         pAdaptor->pAttributes = NULL;
1044     }
1045 
1046     free(pAdaptor->pImages);
1047     pAdaptor->pImages = NULL;
1048 
1049     free(pAdaptor->devPriv.ptr);
1050     pAdaptor->devPriv.ptr = NULL;
1051 }
1052 
1053 void
XvFillColorKey(DrawablePtr pDraw,CARD32 key,RegionPtr region)1054 XvFillColorKey(DrawablePtr pDraw, CARD32 key, RegionPtr region)
1055 {
1056     ScreenPtr pScreen = pDraw->pScreen;
1057     ChangeGCVal pval[2];
1058     BoxPtr pbox = RegionRects(region);
1059     int i, nbox = RegionNumRects(region);
1060     xRectangle *rects;
1061     GCPtr gc;
1062 
1063     gc = GetScratchGC(pDraw->depth, pScreen);
1064     if (!gc)
1065         return;
1066 
1067     pval[0].val = key;
1068     pval[1].val = IncludeInferiors;
1069     (void) ChangeGC(NullClient, gc, GCForeground | GCSubwindowMode, pval);
1070     ValidateGC(pDraw, gc);
1071 
1072     rects = xallocarray(nbox, sizeof(xRectangle));
1073     if (rects) {
1074         for (i = 0; i < nbox; i++, pbox++) {
1075             rects[i].x = pbox->x1 - pDraw->x;
1076             rects[i].y = pbox->y1 - pDraw->y;
1077             rects[i].width = pbox->x2 - pbox->x1;
1078             rects[i].height = pbox->y2 - pbox->y1;
1079         }
1080 
1081         (*gc->ops->PolyFillRect) (pDraw, gc, nbox, rects);
1082 
1083         free(rects);
1084     }
1085     FreeScratchGC(gc);
1086 }
1087