Imported Upstream version 1.15.1
[deb_xorg-server.git] / Xext / xvmain.c
CommitLineData
a09e091a
JB
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 "gc.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(pointer, XID);
138static int XvdiDestroyEncoding(pointer, XID);
139static int XvdiDestroyVideoNotify(pointer, XID);
140static int XvdiDestroyPortNotify(pointer, XID);
141static int XvdiDestroyVideoNotifyList(pointer, XID);
142static int XvdiDestroyPort(pointer, 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 (*pxvs->ddCloseScreen) (pScreen);
306
307 free(pxvs);
308
309 dixSetPrivate(&pScreen->devPrivates, XvScreenKey, NULL);
310
311 return (*pScreen->CloseScreen) (pScreen);
312}
313
314static void
315XvResetProc(ExtensionEntry * extEntry)
316{
317 XvResetProcVector();
318}
319
320DevPrivateKey
321XvGetScreenKey(void)
322{
323 return XvScreenKey;
324}
325
326unsigned long
327XvGetRTPort(void)
328{
329 return XvRTPort;
330}
331
332static Bool
333XvDestroyPixmap(PixmapPtr pPix)
334{
335 Bool status;
336 ScreenPtr pScreen;
337 XvScreenPtr pxvs;
338 XvAdaptorPtr pa;
339 int na;
340 XvPortPtr pp;
341 int np;
342
343 pScreen = pPix->drawable.pScreen;
344
345 SCREEN_PROLOGUE(pScreen, DestroyPixmap);
346
347 pxvs = (XvScreenPtr) dixLookupPrivate(&pScreen->devPrivates, XvScreenKey);
348
349 /* CHECK TO SEE IF THIS PORT IS IN USE */
350
351 pa = pxvs->pAdaptors;
352 na = pxvs->nAdaptors;
353 while (na--) {
354 np = pa->nPorts;
355 pp = pa->pPorts;
356
357 while (np--) {
358 if (pp->pDraw == (DrawablePtr) pPix) {
359 XvdiSendVideoNotify(pp, pp->pDraw, XvPreempted);
360
361 (void) (*pp->pAdaptor->ddStopVideo) (NULL, pp, pp->pDraw);
362
363 pp->pDraw = NULL;
364 pp->client = NULL;
365 pp->time = currentTime;
366 }
367 pp++;
368 }
369 pa++;
370 }
371
372 status = (*pScreen->DestroyPixmap) (pPix);
373
374 SCREEN_EPILOGUE(pScreen, DestroyPixmap, XvDestroyPixmap);
375
376 return status;
377
378}
379
380static Bool
381XvDestroyWindow(WindowPtr pWin)
382{
383 Bool status;
384 ScreenPtr pScreen;
385 XvScreenPtr pxvs;
386 XvAdaptorPtr pa;
387 int na;
388 XvPortPtr pp;
389 int np;
390
391 pScreen = pWin->drawable.pScreen;
392
393 SCREEN_PROLOGUE(pScreen, DestroyWindow);
394
395 pxvs = (XvScreenPtr) dixLookupPrivate(&pScreen->devPrivates, XvScreenKey);
396
397 /* CHECK TO SEE IF THIS PORT IS IN USE */
398
399 pa = pxvs->pAdaptors;
400 na = pxvs->nAdaptors;
401 while (na--) {
402 np = pa->nPorts;
403 pp = pa->pPorts;
404
405 while (np--) {
406 if (pp->pDraw == (DrawablePtr) pWin) {
407 XvdiSendVideoNotify(pp, pp->pDraw, XvPreempted);
408
409 (void) (*pp->pAdaptor->ddStopVideo) (NULL, pp, pp->pDraw);
410
411 pp->pDraw = NULL;
412 pp->client = NULL;
413 pp->time = currentTime;
414 }
415 pp++;
416 }
417 pa++;
418 }
419
420 status = (*pScreen->DestroyWindow) (pWin);
421
422 SCREEN_EPILOGUE(pScreen, DestroyWindow, XvDestroyWindow);
423
424 return status;
425
426}
427
428/* The XvdiVideoStopped procedure is a hook for the device dependent layer.
429 It provides a way for the dd layer to inform the di layer that video has
430 stopped in a port for reasons that the di layer had no control over; note
431 that it doesn't call back into the dd layer */
432
433int
434XvdiVideoStopped(XvPortPtr pPort, int reason)
435{
436
437 /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */
438
439 if (!pPort->pDraw)
440 return Success;
441
442 XvdiSendVideoNotify(pPort, pPort->pDraw, reason);
443
444 pPort->pDraw = NULL;
445 pPort->client = NULL;
446 pPort->time = currentTime;
447
448 return Success;
449
450}
451
452static int
453XvdiDestroyPort(pointer pPort, XID id)
454{
455 return (*((XvPortPtr) pPort)->pAdaptor->ddFreePort) (pPort);
456}
457
458static int
459XvdiDestroyGrab(pointer pGrab, XID id)
460{
461 ((XvGrabPtr) pGrab)->client = NULL;
462 return Success;
463}
464
465static int
466XvdiDestroyVideoNotify(pointer pn, XID id)
467{
468 /* JUST CLEAR OUT THE client POINTER FIELD */
469
470 ((XvVideoNotifyPtr) pn)->client = NULL;
471 return Success;
472}
473
474static int
475XvdiDestroyPortNotify(pointer pn, XID id)
476{
477 /* JUST CLEAR OUT THE client POINTER FIELD */
478
479 ((XvPortNotifyPtr) pn)->client = NULL;
480 return Success;
481}
482
483static int
484XvdiDestroyVideoNotifyList(pointer pn, XID id)
485{
486 XvVideoNotifyPtr npn, cpn;
487
488 /* ACTUALLY DESTROY THE NOTITY LIST */
489
490 cpn = (XvVideoNotifyPtr) pn;
491
492 while (cpn) {
493 npn = cpn->next;
494 if (cpn->client)
495 FreeResource(cpn->id, XvRTVideoNotify);
496 free(cpn);
497 cpn = npn;
498 }
499 return Success;
500}
501
502static int
503XvdiDestroyEncoding(pointer value, XID id)
504{
505 return Success;
506}
507
508static int
509XvdiSendVideoNotify(XvPortPtr pPort, DrawablePtr pDraw, int reason)
510{
511 XvVideoNotifyPtr pn;
512
513 dixLookupResourceByType((pointer *) &pn, pDraw->id, XvRTVideoNotifyList,
514 serverClient, DixReadAccess);
515
516 while (pn) {
517 xvEvent event = {
518 .u.videoNotify.reason = reason,
519 .u.videoNotify.time = currentTime.milliseconds,
520 .u.videoNotify.drawable = pDraw->id,
521 .u.videoNotify.port = pPort->id
522 };
523 event.u.u.type = XvEventBase + XvVideoNotify;
524 WriteEventsToClient(pn->client, 1, (xEventPtr) &event);
525 pn = pn->next;
526 }
527
528 return Success;
529
530}
531
532int
533XvdiSendPortNotify(XvPortPtr pPort, Atom attribute, INT32 value)
534{
535 XvPortNotifyPtr pn;
536
537 pn = pPort->pNotify;
538
539 while (pn) {
540 xvEvent event = {
541 .u.portNotify.time = currentTime.milliseconds,
542 .u.portNotify.port = pPort->id,
543 .u.portNotify.attribute = attribute,
544 .u.portNotify.value = value
545 };
546 event.u.u.type = XvEventBase + XvPortNotify;
547 WriteEventsToClient(pn->client, 1, (xEventPtr) &event);
548 pn = pn->next;
549 }
550
551 return Success;
552
553}
554
555#define CHECK_SIZE(dw, dh, sw, sh) { \
556 if(!dw || !dh || !sw || !sh) return Success; \
557 /* The region code will break these if they are too large */ \
558 if((dw > 32767) || (dh > 32767) || (sw > 32767) || (sh > 32767)) \
559 return BadValue; \
560}
561
562int
563XvdiPutVideo(ClientPtr client,
564 DrawablePtr pDraw,
565 XvPortPtr pPort,
566 GCPtr pGC,
567 INT16 vid_x, INT16 vid_y,
568 CARD16 vid_w, CARD16 vid_h,
569 INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
570{
571 DrawablePtr pOldDraw;
572
573 CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
574
575 /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
576
577 UpdateCurrentTime();
578
579 /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
580 INFORM CLIENT OF ITS FAILURE */
581
582 if (pPort->grab.client && (pPort->grab.client != client)) {
583 XvdiSendVideoNotify(pPort, pDraw, XvBusy);
584 return Success;
585 }
586
587 /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED
588 EVENTS TO ANY CLIENTS WHO WANT THEM */
589
590 pOldDraw = pPort->pDraw;
591 if ((pOldDraw) && (pOldDraw != pDraw)) {
592 XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
593 }
594
595 (void) (*pPort->pAdaptor->ddPutVideo) (client, pDraw, pPort, pGC,
596 vid_x, vid_y, vid_w, vid_h,
597 drw_x, drw_y, drw_w, drw_h);
598
599 if ((pPort->pDraw) && (pOldDraw != pDraw)) {
600 pPort->client = client;
601 XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted);
602 }
603
604 pPort->time = currentTime;
605
606 return Success;
607
608}
609
610int
611XvdiPutStill(ClientPtr client,
612 DrawablePtr pDraw,
613 XvPortPtr pPort,
614 GCPtr pGC,
615 INT16 vid_x, INT16 vid_y,
616 CARD16 vid_w, CARD16 vid_h,
617 INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
618{
619 int status;
620
621 CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
622
623 /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
624
625 UpdateCurrentTime();
626
627 /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
628 INFORM CLIENT OF ITS FAILURE */
629
630 if (pPort->grab.client && (pPort->grab.client != client)) {
631 XvdiSendVideoNotify(pPort, pDraw, XvBusy);
632 return Success;
633 }
634
635 pPort->time = currentTime;
636
637 status = (*pPort->pAdaptor->ddPutStill) (client, pDraw, pPort, pGC,
638 vid_x, vid_y, vid_w, vid_h,
639 drw_x, drw_y, drw_w, drw_h);
640
641 return status;
642
643}
644
645int
646XvdiPutImage(ClientPtr client,
647 DrawablePtr pDraw,
648 XvPortPtr pPort,
649 GCPtr pGC,
650 INT16 src_x, INT16 src_y,
651 CARD16 src_w, CARD16 src_h,
652 INT16 drw_x, INT16 drw_y,
653 CARD16 drw_w, CARD16 drw_h,
654 XvImagePtr image,
655 unsigned char *data, Bool sync, CARD16 width, CARD16 height)
656{
657 CHECK_SIZE(drw_w, drw_h, src_w, src_h);
658
659 /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
660
661 UpdateCurrentTime();
662
663 /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
664 INFORM CLIENT OF ITS FAILURE */
665
666 if (pPort->grab.client && (pPort->grab.client != client)) {
667 XvdiSendVideoNotify(pPort, pDraw, XvBusy);
668 return Success;
669 }
670
671 pPort->time = currentTime;
672
673 return (*pPort->pAdaptor->ddPutImage) (client, pDraw, pPort, pGC,
674 src_x, src_y, src_w, src_h,
675 drw_x, drw_y, drw_w, drw_h,
676 image, data, sync, width, height);
677}
678
679int
680XvdiGetVideo(ClientPtr client,
681 DrawablePtr pDraw,
682 XvPortPtr pPort,
683 GCPtr pGC,
684 INT16 vid_x, INT16 vid_y,
685 CARD16 vid_w, CARD16 vid_h,
686 INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
687{
688 DrawablePtr pOldDraw;
689
690 CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
691
692 /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
693
694 UpdateCurrentTime();
695
696 /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
697 INFORM CLIENT OF ITS FAILURE */
698
699 if (pPort->grab.client && (pPort->grab.client != client)) {
700 XvdiSendVideoNotify(pPort, pDraw, XvBusy);
701 return Success;
702 }
703
704 /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED
705 EVENTS TO ANY CLIENTS WHO WANT THEM */
706
707 pOldDraw = pPort->pDraw;
708 if ((pOldDraw) && (pOldDraw != pDraw)) {
709 XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
710 }
711
712 (void) (*pPort->pAdaptor->ddGetVideo) (client, pDraw, pPort, pGC,
713 vid_x, vid_y, vid_w, vid_h,
714 drw_x, drw_y, drw_w, drw_h);
715
716 if ((pPort->pDraw) && (pOldDraw != pDraw)) {
717 pPort->client = client;
718 XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted);
719 }
720
721 pPort->time = currentTime;
722
723 return Success;
724
725}
726
727int
728XvdiGetStill(ClientPtr client,
729 DrawablePtr pDraw,
730 XvPortPtr pPort,
731 GCPtr pGC,
732 INT16 vid_x, INT16 vid_y,
733 CARD16 vid_w, CARD16 vid_h,
734 INT16 drw_x, INT16 drw_y, CARD16 drw_w, CARD16 drw_h)
735{
736 int status;
737
738 CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
739
740 /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
741
742 UpdateCurrentTime();
743
744 /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
745 INFORM CLIENT OF ITS FAILURE */
746
747 if (pPort->grab.client && (pPort->grab.client != client)) {
748 XvdiSendVideoNotify(pPort, pDraw, XvBusy);
749 return Success;
750 }
751
752 status = (*pPort->pAdaptor->ddGetStill) (client, pDraw, pPort, pGC,
753 vid_x, vid_y, vid_w, vid_h,
754 drw_x, drw_y, drw_w, drw_h);
755
756 pPort->time = currentTime;
757
758 return status;
759
760}
761
762int
763XvdiGrabPort(ClientPtr client, XvPortPtr pPort, Time ctime, int *p_result)
764{
765 unsigned long id;
766 TimeStamp time;
767
768 UpdateCurrentTime();
769 time = ClientTimeToServerTime(ctime);
770
771 if (pPort->grab.client && (client != pPort->grab.client)) {
772 *p_result = XvAlreadyGrabbed;
773 return Success;
774 }
775
776 if ((CompareTimeStamps(time, currentTime) == LATER) ||
777 (CompareTimeStamps(time, pPort->time) == EARLIER)) {
778 *p_result = XvInvalidTime;
779 return Success;
780 }
781
782 if (client == pPort->grab.client) {
783 *p_result = Success;
784 return Success;
785 }
786
787 id = FakeClientID(client->index);
788
789 if (!AddResource(id, XvRTGrab, &pPort->grab)) {
790 return BadAlloc;
791 }
792
793 /* IF THERE IS ACTIVE VIDEO THEN STOP IT */
794
795 if ((pPort->pDraw) && (client != pPort->client)) {
796 XvdiStopVideo(NULL, pPort, pPort->pDraw);
797 }
798
799 pPort->grab.client = client;
800 pPort->grab.id = id;
801
802 pPort->time = currentTime;
803
804 *p_result = Success;
805
806 return Success;
807
808}
809
810int
811XvdiUngrabPort(ClientPtr client, XvPortPtr pPort, Time ctime)
812{
813 TimeStamp time;
814
815 UpdateCurrentTime();
816 time = ClientTimeToServerTime(ctime);
817
818 if ((!pPort->grab.client) || (client != pPort->grab.client)) {
819 return Success;
820 }
821
822 if ((CompareTimeStamps(time, currentTime) == LATER) ||
823 (CompareTimeStamps(time, pPort->time) == EARLIER)) {
824 return Success;
825 }
826
827 /* FREE THE GRAB RESOURCE; AND SET THE GRAB CLIENT TO NULL */
828
829 FreeResource(pPort->grab.id, XvRTGrab);
830 pPort->grab.client = NULL;
831
832 pPort->time = currentTime;
833
834 return Success;
835
836}
837
838int
839XvdiSelectVideoNotify(ClientPtr client, DrawablePtr pDraw, BOOL onoff)
840{
841 XvVideoNotifyPtr pn, tpn, fpn;
842 int rc;
843
844 /* FIND VideoNotify LIST */
845
846 rc = dixLookupResourceByType((pointer *) &pn, pDraw->id,
847 XvRTVideoNotifyList, client, DixWriteAccess);
848 if (rc != Success && rc != BadValue)
849 return rc;
850
851 /* IF ONE DONES'T EXIST AND NO MASK, THEN JUST RETURN */
852
853 if (!onoff && !pn)
854 return Success;
855
856 /* IF ONE DOESN'T EXIST CREATE IT AND ADD A RESOURCE SO THAT THE LIST
857 WILL BE DELETED WHEN THE DRAWABLE IS DESTROYED */
858
859 if (!pn) {
860 if (!(tpn = malloc(sizeof(XvVideoNotifyRec))))
861 return BadAlloc;
862 tpn->next = NULL;
863 if (!AddResource(pDraw->id, XvRTVideoNotifyList, tpn)) {
864 free(tpn);
865 return BadAlloc;
866 }
867 }
868 else {
869 /* LOOK TO SEE IF ENTRY ALREADY EXISTS */
870
871 fpn = NULL;
872 tpn = pn;
873 while (tpn) {
874 if (tpn->client == client) {
875 if (!onoff)
876 tpn->client = NULL;
877 return Success;
878 }
879 if (!tpn->client)
880 fpn = tpn; /* TAKE NOTE OF FREE ENTRY */
881 tpn = tpn->next;
882 }
883
884 /* IF TUNNING OFF, THEN JUST RETURN */
885
886 if (!onoff)
887 return Success;
888
889 /* IF ONE ISN'T FOUND THEN ALLOCATE ONE AND LINK IT INTO THE LIST */
890
891 if (fpn) {
892 tpn = fpn;
893 }
894 else {
895 if (!(tpn = malloc(sizeof(XvVideoNotifyRec))))
896 return BadAlloc;
897 tpn->next = pn->next;
898 pn->next = tpn;
899 }
900 }
901
902 /* INIT CLIENT PTR IN CASE WE CAN'T ADD RESOURCE */
903 /* ADD RESOURCE SO THAT IF CLIENT EXITS THE CLIENT PTR WILL BE CLEARED */
904
905 tpn->client = NULL;
906 tpn->id = FakeClientID(client->index);
907 AddResource(tpn->id, XvRTVideoNotify, tpn);
908
909 tpn->client = client;
910 return Success;
911
912}
913
914int
915XvdiSelectPortNotify(ClientPtr client, XvPortPtr pPort, BOOL onoff)
916{
917 XvPortNotifyPtr pn, tpn;
918
919 /* SEE IF CLIENT IS ALREADY IN LIST */
920
921 tpn = NULL;
922 pn = pPort->pNotify;
923 while (pn) {
924 if (!pn->client)
925 tpn = pn; /* TAKE NOTE OF FREE ENTRY */
926 if (pn->client == client)
927 break;
928 pn = pn->next;
929 }
930
931 /* IS THE CLIENT ALREADY ON THE LIST? */
932
933 if (pn) {
934 /* REMOVE IT? */
935
936 if (!onoff) {
937 pn->client = NULL;
938 FreeResource(pn->id, XvRTPortNotify);
939 }
940
941 return Success;
942 }
943
944 /* DIDN'T FIND IT; SO REUSE LIST ELEMENT IF ONE IS FREE OTHERWISE
945 CREATE A NEW ONE AND ADD IT TO THE BEGINNING OF THE LIST */
946
947 if (!tpn) {
948 if (!(tpn = malloc(sizeof(XvPortNotifyRec))))
949 return BadAlloc;
950 tpn->next = pPort->pNotify;
951 pPort->pNotify = tpn;
952 }
953
954 tpn->client = client;
955 tpn->id = FakeClientID(client->index);
956 AddResource(tpn->id, XvRTPortNotify, tpn);
957
958 return Success;
959
960}
961
962int
963XvdiStopVideo(ClientPtr client, XvPortPtr pPort, DrawablePtr pDraw)
964{
965 int status;
966
967 /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */
968
969 if (!pPort->pDraw || (pPort->pDraw != pDraw)) {
970 XvdiSendVideoNotify(pPort, pDraw, XvStopped);
971 return Success;
972 }
973
974 /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
975 INFORM CLIENT OF ITS FAILURE */
976
977 if ((client) && (pPort->grab.client) && (pPort->grab.client != client)) {
978 XvdiSendVideoNotify(pPort, pDraw, XvBusy);
979 return Success;
980 }
981
982 XvdiSendVideoNotify(pPort, pDraw, XvStopped);
983
984 status = (*pPort->pAdaptor->ddStopVideo) (client, pPort, pDraw);
985
986 pPort->pDraw = NULL;
987 pPort->client = (ClientPtr) client;
988 pPort->time = currentTime;
989
990 return status;
991
992}
993
994int
995XvdiPreemptVideo(ClientPtr client, XvPortPtr pPort, DrawablePtr pDraw)
996{
997 int status;
998
999 /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */
1000
1001 if (!pPort->pDraw || (pPort->pDraw != pDraw))
1002 return Success;
1003
1004 XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
1005
1006 status = (*pPort->pAdaptor->ddStopVideo) (client, pPort, pPort->pDraw);
1007
1008 pPort->pDraw = NULL;
1009 pPort->client = (ClientPtr) client;
1010 pPort->time = currentTime;
1011
1012 return status;
1013
1014}
1015
1016int
1017XvdiMatchPort(XvPortPtr pPort, DrawablePtr pDraw)
1018{
1019
1020 XvAdaptorPtr pa;
1021 XvFormatPtr pf;
1022 int nf;
1023
1024 pa = pPort->pAdaptor;
1025
1026 if (pa->pScreen != pDraw->pScreen)
1027 return BadMatch;
1028
1029 nf = pa->nFormats;
1030 pf = pa->pFormats;
1031
1032 while (nf--) {
1033 if (pf->depth == pDraw->depth)
1034 return Success;
1035 pf++;
1036 }
1037
1038 return BadMatch;
1039
1040}
1041
1042int
1043XvdiSetPortAttribute(ClientPtr client,
1044 XvPortPtr pPort, Atom attribute, INT32 value)
1045{
1046 int status;
1047
1048 status =
1049 (*pPort->pAdaptor->ddSetPortAttribute) (client, pPort, attribute,
1050 value);
1051 if (status == Success)
1052 XvdiSendPortNotify(pPort, attribute, value);
1053
1054 return status;
1055}
1056
1057int
1058XvdiGetPortAttribute(ClientPtr client,
1059 XvPortPtr pPort, Atom attribute, INT32 *p_value)
1060{
1061
1062 return
1063 (*pPort->pAdaptor->ddGetPortAttribute) (client, pPort, attribute,
1064 p_value);
1065
1066}
1067
1068static void
1069WriteSwappedVideoNotifyEvent(xvEvent * from, xvEvent * to)
1070{
1071
1072 to->u.u.type = from->u.u.type;
1073 to->u.u.detail = from->u.u.detail;
1074 cpswaps(from->u.videoNotify.sequenceNumber,
1075 to->u.videoNotify.sequenceNumber);
1076 cpswapl(from->u.videoNotify.time, to->u.videoNotify.time);
1077 cpswapl(from->u.videoNotify.drawable, to->u.videoNotify.drawable);
1078 cpswapl(from->u.videoNotify.port, to->u.videoNotify.port);
1079
1080}
1081
1082static void
1083WriteSwappedPortNotifyEvent(xvEvent * from, xvEvent * to)
1084{
1085
1086 to->u.u.type = from->u.u.type;
1087 to->u.u.detail = from->u.u.detail;
1088 cpswaps(from->u.portNotify.sequenceNumber, to->u.portNotify.sequenceNumber);
1089 cpswapl(from->u.portNotify.time, to->u.portNotify.time);
1090 cpswapl(from->u.portNotify.port, to->u.portNotify.port);
1091 cpswapl(from->u.portNotify.value, to->u.portNotify.value);
1092
1093}