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