xvmain.c revision 35c4bbdf
1/***********************************************************
2Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts,
3and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4
5                        All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Digital or MIT not be
12used in advertising or publicity pertaining to distribution of the
13software without specific, written prior permission.
14
15DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21SOFTWARE.
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
109static DevPrivateKeyRec XvScreenKeyRec;
110
111#define XvScreenKey (&XvScreenKeyRec)
112unsigned long XvExtensionGeneration = 0;
113unsigned long XvScreenGeneration = 0;
114unsigned long XvResourceGeneration = 0;
115
116int XvReqCode;
117int XvEventBase;
118int XvErrorBase;
119
120RESTYPE XvRTPort;
121RESTYPE XvRTEncoding;
122RESTYPE XvRTGrab;
123RESTYPE XvRTVideoNotify;
124RESTYPE XvRTVideoNotifyList;
125RESTYPE XvRTPortNotify;
126
127/* EXTERNAL */
128
129static void WriteSwappedVideoNotifyEvent(xvEvent *, xvEvent *);
130static void WriteSwappedPortNotifyEvent(xvEvent *, xvEvent *);
131static Bool CreateResourceTypes(void);
132
133static Bool XvCloseScreen(ScreenPtr);
134static Bool XvDestroyPixmap(PixmapPtr);
135static Bool XvDestroyWindow(WindowPtr);
136static void XvResetProc(ExtensionEntry *);
137static int XvdiDestroyGrab(void *, XID);
138static int XvdiDestroyEncoding(void *, XID);
139static int XvdiDestroyVideoNotify(void *, XID);
140static int XvdiDestroyPortNotify(void *, XID);
141static int XvdiDestroyVideoNotifyList(void *, XID);
142static int XvdiDestroyPort(void *, XID);
143static int XvdiSendVideoNotify(XvPortPtr, DrawablePtr, int);
144
145/*
146** XvExtensionInit
147**
148**
149*/
150
151void
152XvExtensionInit(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
197static Bool
198CreateResourceTypes(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
249int
250XvScreenInit(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
293static Bool
294XvCloseScreen(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
312static void
313XvResetProc(ExtensionEntry * extEntry)
314{
315    XvResetProcVector();
316}
317
318DevPrivateKey
319XvGetScreenKey(void)
320{
321    return XvScreenKey;
322}
323
324unsigned long
325XvGetRTPort(void)
326{
327    return XvRTPort;
328}
329
330static void
331XvStopAdaptors(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
359static Bool
360XvDestroyPixmap(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
376static Bool
377XvDestroyWindow(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
392static int
393XvdiDestroyPort(void *pPort, XID id)
394{
395    return Success;
396}
397
398static int
399XvdiDestroyGrab(void *pGrab, XID id)
400{
401    ((XvGrabPtr) pGrab)->client = NULL;
402    return Success;
403}
404
405static int
406XvdiDestroyVideoNotify(void *pn, XID id)
407{
408    /* JUST CLEAR OUT THE client POINTER FIELD */
409
410    ((XvVideoNotifyPtr) pn)->client = NULL;
411    return Success;
412}
413
414static int
415XvdiDestroyPortNotify(void *pn, XID id)
416{
417    /* JUST CLEAR OUT THE client POINTER FIELD */
418
419    ((XvPortNotifyPtr) pn)->client = NULL;
420    return Success;
421}
422
423static int
424XvdiDestroyVideoNotifyList(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
442static int
443XvdiDestroyEncoding(void *value, XID id)
444{
445    return Success;
446}
447
448static int
449XvdiSendVideoNotify(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
472int
473XvdiSendPortNotify(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
502int
503XvdiPutVideo(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
550int
551XvdiPutStill(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
585int
586XvdiPutImage(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
619int
620XvdiGetVideo(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
667int
668XvdiGetStill(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
702int
703XvdiGrabPort(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
750int
751XvdiUngrabPort(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
778int
779XvdiSelectVideoNotify(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
854int
855XvdiSelectPortNotify(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
903int
904XvdiStopVideo(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
935int
936XvdiMatchPort(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
961int
962XvdiSetPortAttribute(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
976int
977XvdiGetPortAttribute(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
987static void
988WriteSwappedVideoNotifyEvent(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
1001static void
1002WriteSwappedPortNotifyEvent(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
1014void
1015XvFreeAdaptor(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
1053void
1054XvFillColorKey(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