xvmain.c revision 05b261ec
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 "dixstruct.h"
92#include "resource.h"
93#include "opaque.h"
94#include "input.h"
95
96#define GLOBAL
97
98#include <X11/extensions/Xv.h>
99#include <X11/extensions/Xvproto.h>
100#include "xvdix.h"
101
102#ifdef PANORAMIX
103#include "panoramiX.h"
104#include "panoramiXsrv.h"
105#include "xvdisp.h"
106#endif
107
108int  XvScreenIndex = -1;
109unsigned long XvExtensionGeneration = 0;
110unsigned long XvScreenGeneration = 0;
111unsigned long XvResourceGeneration = 0;
112
113int XvReqCode;
114int XvEventBase;
115int XvErrorBase;
116
117unsigned long XvRTPort;
118unsigned long XvRTEncoding;
119unsigned long XvRTGrab;
120unsigned long XvRTVideoNotify;
121unsigned long XvRTVideoNotifyList;
122unsigned long XvRTPortNotify;
123
124
125
126/* EXTERNAL */
127
128extern XID clientErrorValue;
129
130static void WriteSwappedVideoNotifyEvent(xvEvent *, xvEvent *);
131static void WriteSwappedPortNotifyEvent(xvEvent *, xvEvent *);
132static Bool CreateResourceTypes(void);
133
134static Bool XvCloseScreen(int, ScreenPtr);
135static Bool XvDestroyPixmap(PixmapPtr);
136static Bool XvDestroyWindow(WindowPtr);
137static void XvResetProc(ExtensionEntry*);
138static int XvdiDestroyGrab(pointer, XID);
139static int XvdiDestroyEncoding(pointer, XID);
140static int XvdiDestroyVideoNotify(pointer, XID);
141static int XvdiDestroyPortNotify(pointer, XID);
142static int XvdiDestroyVideoNotifyList(pointer, XID);
143static int XvdiDestroyPort(pointer, XID);
144static int XvdiSendVideoNotify(XvPortPtr, DrawablePtr, int);
145
146
147
148
149/*
150** XvExtensionInit
151**
152**
153*/
154
155void
156XvExtensionInit(void)
157{
158  ExtensionEntry *extEntry;
159
160  /* LOOK TO SEE IF ANY SCREENS WERE INITIALIZED; IF NOT THEN
161     INIT GLOBAL VARIABLES SO THE EXTENSION CAN FUNCTION */
162  if (XvScreenGeneration != serverGeneration)
163    {
164      if (!CreateResourceTypes())
165	{
166	  ErrorF("XvExtensionInit: Unable to allocate resource types\n");
167	  return;
168	}
169      XvScreenIndex = AllocateScreenPrivateIndex ();
170      if (XvScreenIndex < 0)
171	{
172	  ErrorF("XvExtensionInit: Unable to allocate screen private index\n");
173	  return;
174	}
175#ifdef PANORAMIX
176        XineramaRegisterConnectionBlockCallback(XineramifyXv);
177#endif
178      XvScreenGeneration = serverGeneration;
179    }
180
181  if (XvExtensionGeneration != serverGeneration)
182    {
183      XvExtensionGeneration = serverGeneration;
184
185      extEntry = AddExtension(XvName, XvNumEvents, XvNumErrors,
186			      ProcXvDispatch, SProcXvDispatch,
187			      XvResetProc, StandardMinorOpcode);
188      if (!extEntry)
189	{
190	  FatalError("XvExtensionInit: AddExtensions failed\n");
191	}
192
193      XvReqCode = extEntry->base;
194      XvEventBase = extEntry->eventBase;
195      XvErrorBase = extEntry->errorBase;
196
197      EventSwapVector[XvEventBase+XvVideoNotify] =
198	(EventSwapPtr)WriteSwappedVideoNotifyEvent;
199      EventSwapVector[XvEventBase+XvPortNotify] =
200	(EventSwapPtr)WriteSwappedPortNotifyEvent;
201
202      (void)MakeAtom(XvName, strlen(XvName), xTrue);
203
204    }
205}
206
207static Bool
208CreateResourceTypes(void)
209
210{
211
212  if (XvResourceGeneration == serverGeneration) return TRUE;
213
214  XvResourceGeneration = serverGeneration;
215
216  if (!(XvRTPort = CreateNewResourceType(XvdiDestroyPort)))
217    {
218      ErrorF("CreateResourceTypes: failed to allocate port resource.\n");
219      return FALSE;
220    }
221
222  if (!(XvRTGrab = CreateNewResourceType(XvdiDestroyGrab)))
223    {
224      ErrorF("CreateResourceTypes: failed to allocate grab resource.\n");
225      return FALSE;
226    }
227
228  if (!(XvRTEncoding = CreateNewResourceType(XvdiDestroyEncoding)))
229    {
230      ErrorF("CreateResourceTypes: failed to allocate encoding resource.\n");
231      return FALSE;
232    }
233
234  if (!(XvRTVideoNotify = CreateNewResourceType(XvdiDestroyVideoNotify)))
235    {
236      ErrorF("CreateResourceTypes: failed to allocate video notify resource.\n");
237      return FALSE;
238    }
239
240  if (!(XvRTVideoNotifyList = CreateNewResourceType(XvdiDestroyVideoNotifyList)))
241    {
242      ErrorF("CreateResourceTypes: failed to allocate video notify list resource.\n");
243      return FALSE;
244    }
245
246  if (!(XvRTPortNotify = CreateNewResourceType(XvdiDestroyPortNotify)))
247    {
248      ErrorF("CreateResourceTypes: failed to allocate port notify resource.\n");
249      return FALSE;
250    }
251
252  return TRUE;
253
254}
255
256_X_EXPORT int
257XvScreenInit(ScreenPtr pScreen)
258{
259  XvScreenPtr pxvs;
260
261  if (XvScreenGeneration != serverGeneration)
262    {
263      if (!CreateResourceTypes())
264	{
265	  ErrorF("XvScreenInit: Unable to allocate resource types\n");
266	  return BadAlloc;
267	}
268      XvScreenIndex = AllocateScreenPrivateIndex ();
269      if (XvScreenIndex < 0)
270	{
271	  ErrorF("XvScreenInit: Unable to allocate screen private index\n");
272	  return BadAlloc;
273	}
274#ifdef PANORAMIX
275        XineramaRegisterConnectionBlockCallback(XineramifyXv);
276#endif
277      XvScreenGeneration = serverGeneration;
278    }
279
280  if (pScreen->devPrivates[XvScreenIndex].ptr)
281    {
282      ErrorF("XvScreenInit: screen devPrivates ptr non-NULL before init\n");
283    }
284
285  /* ALLOCATE SCREEN PRIVATE RECORD */
286
287  pxvs = (XvScreenPtr) xalloc (sizeof (XvScreenRec));
288  if (!pxvs)
289    {
290      ErrorF("XvScreenInit: Unable to allocate screen private structure\n");
291      return BadAlloc;
292    }
293
294  pScreen->devPrivates[XvScreenIndex].ptr = (pointer)pxvs;
295
296
297  pxvs->DestroyPixmap = pScreen->DestroyPixmap;
298  pxvs->DestroyWindow = pScreen->DestroyWindow;
299  pxvs->CloseScreen = pScreen->CloseScreen;
300
301  pScreen->DestroyPixmap = XvDestroyPixmap;
302  pScreen->DestroyWindow = XvDestroyWindow;
303  pScreen->CloseScreen = XvCloseScreen;
304
305  return Success;
306}
307
308static Bool
309XvCloseScreen(
310  int ii,
311  ScreenPtr pScreen
312){
313
314  XvScreenPtr pxvs;
315
316  pxvs = (XvScreenPtr) pScreen->devPrivates[XvScreenIndex].ptr;
317
318  pScreen->DestroyPixmap = pxvs->DestroyPixmap;
319  pScreen->DestroyWindow = pxvs->DestroyWindow;
320  pScreen->CloseScreen = pxvs->CloseScreen;
321
322  (* pxvs->ddCloseScreen)(ii, pScreen);
323
324  xfree(pxvs);
325
326  pScreen->devPrivates[XvScreenIndex].ptr = (pointer)NULL;
327
328  return (*pScreen->CloseScreen)(ii, pScreen);
329
330}
331
332static void
333XvResetProc(ExtensionEntry* extEntry)
334{
335}
336
337_X_EXPORT int
338XvGetScreenIndex(void)
339{
340  return XvScreenIndex;
341}
342
343_X_EXPORT unsigned long
344XvGetRTPort(void)
345{
346  return XvRTPort;
347}
348
349static Bool
350XvDestroyPixmap(PixmapPtr pPix)
351{
352  Bool status;
353  ScreenPtr pScreen;
354  XvScreenPtr pxvs;
355  XvAdaptorPtr pa;
356  int na;
357  XvPortPtr pp;
358  int np;
359
360  pScreen = pPix->drawable.pScreen;
361
362  SCREEN_PROLOGUE(pScreen, DestroyPixmap);
363
364  pxvs = (XvScreenPtr)pScreen->devPrivates[XvScreenIndex].ptr;
365
366  /* CHECK TO SEE IF THIS PORT IS IN USE */
367
368  pa = pxvs->pAdaptors;
369  na = pxvs->nAdaptors;
370  while (na--)
371    {
372      np = pa->nPorts;
373      pp = pa->pPorts;
374
375      while (np--)
376	{
377	  if (pp->pDraw == (DrawablePtr)pPix)
378	    {
379	      XvdiSendVideoNotify(pp, pp->pDraw, XvPreempted);
380
381	      (void)(* pp->pAdaptor->ddStopVideo)((ClientPtr)NULL, pp,
382						  pp->pDraw);
383
384	      pp->pDraw = (DrawablePtr)NULL;
385	      pp->client = (ClientPtr)NULL;
386	      pp->time = currentTime;
387	    }
388	  pp++;
389	}
390      pa++;
391    }
392
393  status = (* pScreen->DestroyPixmap)(pPix);
394
395  SCREEN_EPILOGUE(pScreen, DestroyPixmap, XvDestroyPixmap);
396
397  return status;
398
399}
400
401static Bool
402XvDestroyWindow(WindowPtr pWin)
403{
404  Bool status;
405  ScreenPtr pScreen;
406  XvScreenPtr pxvs;
407  XvAdaptorPtr pa;
408  int na;
409  XvPortPtr pp;
410  int np;
411
412  pScreen = pWin->drawable.pScreen;
413
414  SCREEN_PROLOGUE(pScreen, DestroyWindow);
415
416  pxvs = (XvScreenPtr)pScreen->devPrivates[XvScreenIndex].ptr;
417
418  /* CHECK TO SEE IF THIS PORT IS IN USE */
419
420  pa = pxvs->pAdaptors;
421  na = pxvs->nAdaptors;
422  while (na--)
423    {
424      np = pa->nPorts;
425      pp = pa->pPorts;
426
427      while (np--)
428	{
429	  if (pp->pDraw == (DrawablePtr)pWin)
430	    {
431	      XvdiSendVideoNotify(pp, pp->pDraw, XvPreempted);
432
433	      (void)(* pp->pAdaptor->ddStopVideo)((ClientPtr)NULL, pp,
434						  pp->pDraw);
435
436	      pp->pDraw = (DrawablePtr)NULL;
437	      pp->client = (ClientPtr)NULL;
438	      pp->time = currentTime;
439	    }
440	  pp++;
441	}
442      pa++;
443    }
444
445
446  status = (* pScreen->DestroyWindow)(pWin);
447
448  SCREEN_EPILOGUE(pScreen, DestroyWindow, XvDestroyWindow);
449
450  return status;
451
452}
453
454/* The XvdiVideoStopped procedure is a hook for the device dependent layer.
455   It provides a way for the dd layer to inform the di layer that video has
456   stopped in a port for reasons that the di layer had no control over; note
457   that it doesn't call back into the dd layer */
458
459int
460XvdiVideoStopped(XvPortPtr pPort, int reason)
461{
462
463  /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */
464
465  if (!pPort->pDraw) return Success;
466
467  XvdiSendVideoNotify(pPort, pPort->pDraw, reason);
468
469  pPort->pDraw = (DrawablePtr)NULL;
470  pPort->client = (ClientPtr)NULL;
471  pPort->time = currentTime;
472
473  return Success;
474
475}
476
477static int
478XvdiDestroyPort(pointer pPort, XID id)
479{
480  return (* ((XvPortPtr)pPort)->pAdaptor->ddFreePort)(pPort);
481}
482
483static int
484XvdiDestroyGrab(pointer pGrab, XID id)
485{
486  ((XvGrabPtr)pGrab)->client = (ClientPtr)NULL;
487  return Success;
488}
489
490static int
491XvdiDestroyVideoNotify(pointer pn, XID id)
492{
493  /* JUST CLEAR OUT THE client POINTER FIELD */
494
495  ((XvVideoNotifyPtr)pn)->client = (ClientPtr)NULL;
496  return Success;
497}
498
499static int
500XvdiDestroyPortNotify(pointer pn, XID id)
501{
502  /* JUST CLEAR OUT THE client POINTER FIELD */
503
504  ((XvPortNotifyPtr)pn)->client = (ClientPtr)NULL;
505  return Success;
506}
507
508static int
509XvdiDestroyVideoNotifyList(pointer pn, XID id)
510{
511  XvVideoNotifyPtr npn,cpn;
512
513  /* ACTUALLY DESTROY THE NOTITY LIST */
514
515  cpn = (XvVideoNotifyPtr)pn;
516
517  while (cpn)
518    {
519      npn = cpn->next;
520      if (cpn->client) FreeResource(cpn->id, XvRTVideoNotify);
521      xfree(cpn);
522      cpn = npn;
523    }
524  return Success;
525}
526
527static int
528XvdiDestroyEncoding(pointer value, XID id)
529{
530  return Success;
531}
532
533static int
534XvdiSendVideoNotify(pPort, pDraw, reason)
535
536XvPortPtr pPort;
537DrawablePtr pDraw;
538int reason;
539
540{
541  xvEvent event;
542  XvVideoNotifyPtr pn;
543
544  pn = (XvVideoNotifyPtr)LookupIDByType(pDraw->id, XvRTVideoNotifyList);
545
546  while (pn)
547    {
548      if (pn->client)
549	{
550	  event.u.u.type = XvEventBase + XvVideoNotify;
551	  event.u.u.sequenceNumber = pn->client->sequence;
552	  event.u.videoNotify.time = currentTime.milliseconds;
553	  event.u.videoNotify.drawable = pDraw->id;
554	  event.u.videoNotify.port = pPort->id;
555	  event.u.videoNotify.reason = reason;
556	  (void) TryClientEvents(pn->client, (xEventPtr)&event, 1, NoEventMask,
557				 NoEventMask, NullGrab);
558	}
559      pn = pn->next;
560    }
561
562  return Success;
563
564}
565
566
567int
568XvdiSendPortNotify(
569  XvPortPtr pPort,
570  Atom attribute,
571  INT32 value
572){
573  xvEvent event;
574  XvPortNotifyPtr pn;
575
576  pn = pPort->pNotify;
577
578  while (pn)
579    {
580      if (pn->client)
581	{
582	  event.u.u.type = XvEventBase + XvPortNotify;
583	  event.u.u.sequenceNumber = pn->client->sequence;
584	  event.u.portNotify.time = currentTime.milliseconds;
585	  event.u.portNotify.port = pPort->id;
586	  event.u.portNotify.attribute = attribute;
587	  event.u.portNotify.value = value;
588	  (void) TryClientEvents(pn->client, (xEventPtr)&event, 1, NoEventMask,
589				 NoEventMask, NullGrab);
590	}
591      pn = pn->next;
592    }
593
594  return Success;
595
596}
597
598
599#define CHECK_SIZE(dw, dh, sw, sh) {                                  \
600  if(!dw || !dh || !sw || !sh)  return Success;                       \
601  /* The region code will break these if they are too large */        \
602  if((dw > 32767) || (dh > 32767) || (sw > 32767) || (sh > 32767))    \
603        return BadValue;                                              \
604}
605
606
607int
608XvdiPutVideo(
609   ClientPtr client,
610   DrawablePtr pDraw,
611   XvPortPtr pPort,
612   GCPtr pGC,
613   INT16 vid_x, INT16 vid_y,
614   CARD16 vid_w, CARD16 vid_h,
615   INT16 drw_x, INT16 drw_y,
616   CARD16 drw_w, CARD16 drw_h
617){
618  DrawablePtr pOldDraw;
619
620  CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
621
622  /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
623
624  UpdateCurrentTime();
625
626  /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
627     INFORM CLIENT OF ITS FAILURE */
628
629  if (pPort->grab.client && (pPort->grab.client != client))
630    {
631      XvdiSendVideoNotify(pPort, pDraw, XvBusy);
632      return Success;
633    }
634
635  /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED
636     EVENTS TO ANY CLIENTS WHO WANT THEM */
637
638  pOldDraw = pPort->pDraw;
639  if ((pOldDraw) && (pOldDraw != pDraw))
640    {
641      XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
642    }
643
644  (void) (* pPort->pAdaptor->ddPutVideo)(client, pDraw, pPort, pGC,
645					   vid_x, vid_y, vid_w, vid_h,
646					   drw_x, drw_y, drw_w, drw_h);
647
648  if ((pPort->pDraw) && (pOldDraw != pDraw))
649    {
650      pPort->client = client;
651      XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted);
652    }
653
654  pPort->time = currentTime;
655
656  return (Success);
657
658}
659
660int
661XvdiPutStill(
662   ClientPtr client,
663   DrawablePtr pDraw,
664   XvPortPtr pPort,
665   GCPtr pGC,
666   INT16 vid_x, INT16 vid_y,
667   CARD16 vid_w, CARD16 vid_h,
668   INT16 drw_x, INT16 drw_y,
669   CARD16 drw_w, CARD16 drw_h
670){
671  int status;
672
673  CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
674
675  /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
676
677  UpdateCurrentTime();
678
679  /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
680     INFORM CLIENT OF ITS FAILURE */
681
682  if (pPort->grab.client && (pPort->grab.client != client))
683    {
684      XvdiSendVideoNotify(pPort, pDraw, XvBusy);
685      return Success;
686    }
687
688  pPort->time = currentTime;
689
690  status = (* pPort->pAdaptor->ddPutStill)(client, pDraw, pPort, pGC,
691					   vid_x, vid_y, vid_w, vid_h,
692					   drw_x, drw_y, drw_w, drw_h);
693
694  return status;
695
696}
697
698int
699XvdiPutImage(
700   ClientPtr client,
701   DrawablePtr pDraw,
702   XvPortPtr pPort,
703   GCPtr pGC,
704   INT16 src_x, INT16 src_y,
705   CARD16 src_w, CARD16 src_h,
706   INT16 drw_x, INT16 drw_y,
707   CARD16 drw_w, CARD16 drw_h,
708   XvImagePtr image,
709   unsigned char* data,
710   Bool sync,
711   CARD16 width, CARD16 height
712){
713  CHECK_SIZE(drw_w, drw_h, src_w, src_h);
714
715  /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
716
717  UpdateCurrentTime();
718
719  /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
720     INFORM CLIENT OF ITS FAILURE */
721
722  if (pPort->grab.client && (pPort->grab.client != client))
723    {
724      XvdiSendVideoNotify(pPort, pDraw, XvBusy);
725      return Success;
726    }
727
728  pPort->time = currentTime;
729
730  return (* pPort->pAdaptor->ddPutImage)(client, pDraw, pPort, pGC,
731					   src_x, src_y, src_w, src_h,
732					   drw_x, drw_y, drw_w, drw_h,
733					   image, data, sync, width, height);
734}
735
736
737int
738XvdiGetVideo(
739   ClientPtr client,
740   DrawablePtr pDraw,
741   XvPortPtr pPort,
742   GCPtr pGC,
743   INT16 vid_x, INT16 vid_y,
744   CARD16 vid_w, CARD16 vid_h,
745   INT16 drw_x, INT16 drw_y,
746   CARD16 drw_w, CARD16 drw_h
747){
748  DrawablePtr pOldDraw;
749
750  CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
751
752  /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
753
754  UpdateCurrentTime();
755
756  /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
757     INFORM CLIENT OF ITS FAILURE */
758
759  if (pPort->grab.client && (pPort->grab.client != client))
760    {
761      XvdiSendVideoNotify(pPort, pDraw, XvBusy);
762      return Success;
763    }
764
765  /* CHECK TO SEE IF PORT IS IN USE; IF SO THEN WE MUST DELIVER INTERRUPTED
766     EVENTS TO ANY CLIENTS WHO WANT THEM */
767
768  pOldDraw = pPort->pDraw;
769  if ((pOldDraw) && (pOldDraw != pDraw))
770    {
771      XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
772    }
773
774  (void) (* pPort->pAdaptor->ddGetVideo)(client, pDraw, pPort, pGC,
775					   vid_x, vid_y, vid_w, vid_h,
776					   drw_x, drw_y, drw_w, drw_h);
777
778  if ((pPort->pDraw) && (pOldDraw != pDraw))
779    {
780      pPort->client = client;
781      XvdiSendVideoNotify(pPort, pPort->pDraw, XvStarted);
782    }
783
784  pPort->time = currentTime;
785
786  return (Success);
787
788}
789
790int
791XvdiGetStill(
792   ClientPtr client,
793   DrawablePtr pDraw,
794   XvPortPtr pPort,
795   GCPtr pGC,
796   INT16 vid_x, INT16 vid_y,
797   CARD16 vid_w, CARD16 vid_h,
798   INT16 drw_x, INT16 drw_y,
799   CARD16 drw_w, CARD16 drw_h
800){
801  int status;
802
803  CHECK_SIZE(drw_w, drw_h, vid_w, vid_h);
804
805  /* UPDATE TIME VARIABLES FOR USE IN EVENTS */
806
807  UpdateCurrentTime();
808
809  /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
810     INFORM CLIENT OF ITS FAILURE */
811
812  if (pPort->grab.client && (pPort->grab.client != client))
813    {
814      XvdiSendVideoNotify(pPort, pDraw, XvBusy);
815      return Success;
816    }
817
818  status = (* pPort->pAdaptor->ddGetStill)(client, pDraw, pPort, pGC,
819					   vid_x, vid_y, vid_w, vid_h,
820					   drw_x, drw_y, drw_w, drw_h);
821
822  pPort->time = currentTime;
823
824  return status;
825
826}
827
828int
829XvdiGrabPort(
830   ClientPtr client,
831   XvPortPtr pPort,
832   Time ctime,
833   int *p_result
834){
835  unsigned long id;
836  TimeStamp time;
837
838  UpdateCurrentTime();
839  time = ClientTimeToServerTime(ctime);
840
841  if (pPort->grab.client && (client != pPort->grab.client))
842    {
843      *p_result = XvAlreadyGrabbed;
844      return Success;
845    }
846
847  if ((CompareTimeStamps(time, currentTime) == LATER) ||
848      (CompareTimeStamps(time, pPort->time) == EARLIER))
849    {
850      *p_result = XvInvalidTime;
851      return Success;
852    }
853
854  if (client == pPort->grab.client)
855    {
856      *p_result = Success;
857      return Success;
858    }
859
860  id = FakeClientID(client->index);
861
862  if (!AddResource(id, XvRTGrab, &pPort->grab))
863    {
864      return BadAlloc;
865    }
866
867  /* IF THERE IS ACTIVE VIDEO THEN STOP IT */
868
869  if ((pPort->pDraw) && (client != pPort->client))
870    {
871      XVCALL(diStopVideo)((ClientPtr)NULL, pPort, pPort->pDraw);
872    }
873
874  pPort->grab.client = client;
875  pPort->grab.id = id;
876
877  pPort->time = currentTime;
878
879  *p_result = Success;
880
881  return Success;
882
883}
884
885int
886XvdiUngrabPort(
887  ClientPtr client,
888  XvPortPtr pPort,
889  Time ctime
890){
891  TimeStamp time;
892
893  UpdateCurrentTime();
894  time = ClientTimeToServerTime(ctime);
895
896  if ((!pPort->grab.client) || (client != pPort->grab.client))
897    {
898      return Success;
899    }
900
901  if ((CompareTimeStamps(time, currentTime) == LATER) ||
902      (CompareTimeStamps(time, pPort->time) == EARLIER))
903    {
904      return Success;
905    }
906
907  /* FREE THE GRAB RESOURCE; AND SET THE GRAB CLIENT TO NULL */
908
909  FreeResource(pPort->grab.id, XvRTGrab);
910  pPort->grab.client = (ClientPtr)NULL;
911
912  pPort->time = currentTime;
913
914  return Success;
915
916}
917
918
919int
920XvdiSelectVideoNotify(
921  ClientPtr client,
922  DrawablePtr pDraw,
923  BOOL onoff
924){
925  XvVideoNotifyPtr pn,tpn,fpn;
926
927  /* FIND VideoNotify LIST */
928
929  pn = (XvVideoNotifyPtr)LookupIDByType(pDraw->id, XvRTVideoNotifyList);
930
931  /* IF ONE DONES'T EXIST AND NO MASK, THEN JUST RETURN */
932
933  if (!onoff && !pn) return Success;
934
935  /* IF ONE DOESN'T EXIST CREATE IT AND ADD A RESOURCE SO THAT THE LIST
936     WILL BE DELETED WHEN THE DRAWABLE IS DESTROYED */
937
938  if (!pn)
939    {
940      if (!(tpn = (XvVideoNotifyPtr)xalloc(sizeof(XvVideoNotifyRec))))
941	return BadAlloc;
942      tpn->next = (XvVideoNotifyPtr)NULL;
943      if (!AddResource(pDraw->id, XvRTVideoNotifyList, tpn))
944	{
945	  xfree(tpn);
946	  return BadAlloc;
947	}
948    }
949  else
950    {
951      /* LOOK TO SEE IF ENTRY ALREADY EXISTS */
952
953      fpn = (XvVideoNotifyPtr)NULL;
954      tpn = pn;
955      while (tpn)
956	{
957	  if (tpn->client == client)
958	    {
959	      if (!onoff) tpn->client = (ClientPtr)NULL;
960	      return Success;
961	    }
962	  if (!tpn->client) fpn = tpn; /* TAKE NOTE OF FREE ENTRY */
963	  tpn = tpn->next;
964	}
965
966      /* IF TUNNING OFF, THEN JUST RETURN */
967
968      if (!onoff) return Success;
969
970      /* IF ONE ISN'T FOUND THEN ALLOCATE ONE AND LINK IT INTO THE LIST */
971
972      if (fpn)
973	{
974	  tpn = fpn;
975	}
976      else
977	{
978	  if (!(tpn = (XvVideoNotifyPtr)xalloc(sizeof(XvVideoNotifyRec))))
979	    return BadAlloc;
980	  tpn->next = pn->next;
981	  pn->next = tpn;
982	}
983    }
984
985  /* INIT CLIENT PTR IN CASE WE CAN'T ADD RESOURCE */
986  /* ADD RESOURCE SO THAT IF CLIENT EXITS THE CLIENT PTR WILL BE CLEARED */
987
988  tpn->client = (ClientPtr)NULL;
989  tpn->id = FakeClientID(client->index);
990  AddResource(tpn->id, XvRTVideoNotify, tpn);
991
992  tpn->client = client;
993  return Success;
994
995}
996
997int
998XvdiSelectPortNotify(
999   ClientPtr client,
1000   XvPortPtr pPort,
1001   BOOL onoff
1002){
1003  XvPortNotifyPtr pn,tpn;
1004
1005  /* SEE IF CLIENT IS ALREADY IN LIST */
1006
1007  tpn = (XvPortNotifyPtr)NULL;
1008  pn = pPort->pNotify;
1009  while (pn)
1010    {
1011      if (!pn->client) tpn = pn; /* TAKE NOTE OF FREE ENTRY */
1012      if (pn->client == client) break;
1013      pn = pn->next;
1014    }
1015
1016  /* IS THE CLIENT ALREADY ON THE LIST? */
1017
1018  if (pn)
1019    {
1020      /* REMOVE IT? */
1021
1022      if (!onoff)
1023	{
1024	  pn->client = (ClientPtr)NULL;
1025	  FreeResource(pn->id, XvRTPortNotify);
1026	}
1027
1028      return Success;
1029    }
1030
1031  /* DIDN'T FIND IT; SO REUSE LIST ELEMENT IF ONE IS FREE OTHERWISE
1032     CREATE A NEW ONE AND ADD IT TO THE BEGINNING OF THE LIST */
1033
1034  if (!tpn)
1035    {
1036      if (!(tpn = (XvPortNotifyPtr)xalloc(sizeof(XvPortNotifyRec))))
1037	return BadAlloc;
1038      tpn->next = pPort->pNotify;
1039      pPort->pNotify = tpn;
1040    }
1041
1042  tpn->client = client;
1043  tpn->id = FakeClientID(client->index);
1044  AddResource(tpn->id, XvRTPortNotify, tpn);
1045
1046  return Success;
1047
1048}
1049
1050int
1051XvdiStopVideo(
1052  ClientPtr client,
1053  XvPortPtr pPort,
1054  DrawablePtr pDraw
1055){
1056  int status;
1057
1058  /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */
1059
1060  if (!pPort->pDraw || (pPort->pDraw != pDraw))
1061    {
1062      XvdiSendVideoNotify(pPort, pDraw, XvStopped);
1063      return Success;
1064    }
1065
1066  /* CHECK FOR GRAB; IF THIS CLIENT DOESN'T HAVE THE PORT GRABBED THEN
1067     INFORM CLIENT OF ITS FAILURE */
1068
1069  if ((client) && (pPort->grab.client) && (pPort->grab.client != client))
1070    {
1071      XvdiSendVideoNotify(pPort, pDraw, XvBusy);
1072      return Success;
1073    }
1074
1075  XvdiSendVideoNotify(pPort, pDraw, XvStopped);
1076
1077  status = (* pPort->pAdaptor->ddStopVideo)(client, pPort, pDraw);
1078
1079  pPort->pDraw = (DrawablePtr)NULL;
1080  pPort->client = (ClientPtr)client;
1081  pPort->time = currentTime;
1082
1083  return status;
1084
1085}
1086
1087int
1088XvdiPreemptVideo(
1089  ClientPtr client,
1090  XvPortPtr pPort,
1091  DrawablePtr pDraw
1092){
1093  int status;
1094
1095  /* IF PORT ISN'T ACTIVE THEN WE'RE DONE */
1096
1097  if (!pPort->pDraw || (pPort->pDraw != pDraw)) return Success;
1098
1099  XvdiSendVideoNotify(pPort, pPort->pDraw, XvPreempted);
1100
1101  status = (* pPort->pAdaptor->ddStopVideo)(client, pPort, pPort->pDraw);
1102
1103  pPort->pDraw = (DrawablePtr)NULL;
1104  pPort->client = (ClientPtr)client;
1105  pPort->time = currentTime;
1106
1107  return status;
1108
1109}
1110
1111int
1112XvdiMatchPort(
1113  XvPortPtr pPort,
1114  DrawablePtr pDraw
1115){
1116
1117  XvAdaptorPtr pa;
1118  XvFormatPtr pf;
1119  int nf;
1120
1121  pa = pPort->pAdaptor;
1122
1123  if (pa->pScreen != pDraw->pScreen) return BadMatch;
1124
1125  nf = pa->nFormats;
1126  pf = pa->pFormats;
1127
1128  while (nf--)
1129    {
1130      if ((pf->depth == pDraw->depth)
1131#if 0
1132         && ((pDraw->type == DRAWABLE_PIXMAP) ||
1133	   (wVisual(((WindowPtr)pDraw)) == pf->visual))
1134#endif
1135	)
1136	return Success;
1137      pf++;
1138    }
1139
1140  return BadMatch;
1141
1142}
1143
1144int
1145XvdiSetPortAttribute(
1146  ClientPtr client,
1147  XvPortPtr pPort,
1148  Atom attribute,
1149  INT32 value
1150){
1151
1152    XvdiSendPortNotify(pPort, attribute, value);
1153
1154  return
1155    (* pPort->pAdaptor->ddSetPortAttribute)(client, pPort, attribute, value);
1156
1157}
1158
1159int
1160XvdiGetPortAttribute(
1161  ClientPtr client,
1162  XvPortPtr pPort,
1163  Atom attribute,
1164  INT32 *p_value
1165){
1166
1167  return
1168    (* pPort->pAdaptor->ddGetPortAttribute)(client, pPort, attribute, p_value);
1169
1170}
1171
1172static void
1173WriteSwappedVideoNotifyEvent(xvEvent *from, xvEvent *to)
1174
1175{
1176
1177  to->u.u.type = from->u.u.type;
1178  to->u.u.detail = from->u.u.detail;
1179  cpswaps(from->u.videoNotify.sequenceNumber,
1180	  to->u.videoNotify.sequenceNumber);
1181  cpswapl(from->u.videoNotify.time, to->u.videoNotify.time);
1182  cpswapl(from->u.videoNotify.drawable, to->u.videoNotify.drawable);
1183  cpswapl(from->u.videoNotify.port, to->u.videoNotify.port);
1184
1185}
1186
1187static void
1188WriteSwappedPortNotifyEvent(xvEvent *from, xvEvent *to)
1189
1190{
1191
1192  to->u.u.type = from->u.u.type;
1193  to->u.u.detail = from->u.u.detail;
1194  cpswaps(from->u.portNotify.sequenceNumber, to->u.portNotify.sequenceNumber);
1195  cpswapl(from->u.portNotify.time, to->u.portNotify.time);
1196  cpswapl(from->u.portNotify.port, to->u.portNotify.port);
1197  cpswapl(from->u.portNotify.value, to->u.portNotify.value);
1198
1199}
1200