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