xf86DGA.c revision b1d344b3
1/*
2 * Copyright (c) 1998-2002 by The XFree86 Project, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Except as contained in this notice, the name of the copyright holder(s)
23 * and author(s) shall not be used in advertising or otherwise to promote
24 * the sale, use or other dealings in this Software without prior written
25 * authorization from the copyright holder(s) and author(s).
26 *
27 * Written by Mark Vojkovich
28 */
29
30#ifdef HAVE_XORG_CONFIG_H
31#include <xorg-config.h>
32#endif
33
34#include "xf86.h"
35#include "xf86str.h"
36#include "xf86Priv.h"
37#include "dgaproc.h"
38#include <X11/extensions/xf86dgastr.h>
39#include "colormapst.h"
40#include "pixmapstr.h"
41#include "inputstr.h"
42#include "globals.h"
43#include "servermd.h"
44#include "micmap.h"
45#ifdef XKB
46#include <xkbsrv.h>
47#endif
48#include "xf86Xinput.h"
49#include "exglobals.h"
50#include "exevents.h"
51
52#include "mi.h"
53
54static int DGAScreenKeyIndex;
55static DevPrivateKey DGAScreenKey;
56static int mieq_installed = 0;
57
58static Bool DGACloseScreen(int i, ScreenPtr pScreen);
59static void DGADestroyColormap(ColormapPtr pmap);
60static void DGAInstallColormap(ColormapPtr pmap);
61static void DGAUninstallColormap(ColormapPtr pmap);
62static void DGAHandleEvent(int screen_num, xEvent *event,
63                           DeviceIntPtr device, int nevents);
64
65static void
66DGACopyModeInfo(
67   DGAModePtr mode,
68   XDGAModePtr xmode
69);
70
71_X_EXPORT int *XDGAEventBase = NULL;
72
73#define DGA_GET_SCREEN_PRIV(pScreen) ((DGAScreenPtr) \
74    dixLookupPrivate(&(pScreen)->devPrivates, DGAScreenKey))
75
76
77typedef struct _FakedVisualList{
78   Bool free;
79   VisualPtr pVisual;
80   struct _FakedVisualList *next;
81} FakedVisualList;
82
83
84typedef struct {
85   ScrnInfoPtr 		pScrn;
86   int			numModes;
87   DGAModePtr		modes;
88   CloseScreenProcPtr	CloseScreen;
89   DestroyColormapProcPtr DestroyColormap;
90   InstallColormapProcPtr InstallColormap;
91   UninstallColormapProcPtr UninstallColormap;
92   DGADevicePtr		current;
93   DGAFunctionPtr	funcs;
94   int			input;
95   ClientPtr		client;
96   int			pixmapMode;
97   FakedVisualList	*fakedVisuals;
98   ColormapPtr 		dgaColormap;
99   ColormapPtr		savedColormap;
100   Bool			grabMouse;
101   Bool			grabKeyboard;
102} DGAScreenRec, *DGAScreenPtr;
103
104_X_EXPORT Bool
105DGAInit(
106   ScreenPtr pScreen,
107   DGAFunctionPtr funcs,
108   DGAModePtr modes,
109   int num
110){
111    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
112    DGAScreenPtr pScreenPriv;
113    int i;
114
115    if(!funcs || !funcs->SetMode || !funcs->OpenFramebuffer)
116	return FALSE;
117
118    if(!modes || num <= 0)
119	return FALSE;
120
121    DGAScreenKey = &DGAScreenKeyIndex;
122
123    pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
124
125    if (!pScreenPriv)
126    {
127	if(!(pScreenPriv = (DGAScreenPtr)xalloc(sizeof(DGAScreenRec))))
128	    return FALSE;
129	dixSetPrivate(&pScreen->devPrivates, DGAScreenKey, pScreenPriv);
130	pScreenPriv->CloseScreen = pScreen->CloseScreen;
131	pScreen->CloseScreen = DGACloseScreen;
132	pScreenPriv->DestroyColormap = pScreen->DestroyColormap;
133	pScreen->DestroyColormap = DGADestroyColormap;
134	pScreenPriv->InstallColormap = pScreen->InstallColormap;
135	pScreen->InstallColormap = DGAInstallColormap;
136	pScreenPriv->UninstallColormap = pScreen->UninstallColormap;
137	pScreen->UninstallColormap = DGAUninstallColormap;
138    }
139
140    pScreenPriv->pScrn = pScrn;
141    pScreenPriv->numModes = num;
142    pScreenPriv->modes = modes;
143    pScreenPriv->current = NULL;
144
145    pScreenPriv->funcs = funcs;
146    pScreenPriv->input = 0;
147    pScreenPriv->client = NULL;
148    pScreenPriv->fakedVisuals = NULL;
149    pScreenPriv->dgaColormap = NULL;
150    pScreenPriv->savedColormap = NULL;
151    pScreenPriv->grabMouse = FALSE;
152    pScreenPriv->grabKeyboard = FALSE;
153
154    for(i = 0; i < num; i++)
155	modes[i].num = i + 1;
156
157#ifdef PANORAMIX
158     if(!noPanoramiXExtension)
159	for(i = 0; i < num; i++)
160	    modes[i].flags &= ~DGA_PIXMAP_AVAILABLE;
161#endif
162
163    return TRUE;
164}
165
166/* DGAReInitModes allows the driver to re-initialize
167 * the DGA mode list.
168 */
169
170_X_EXPORT Bool
171DGAReInitModes(
172   ScreenPtr pScreen,
173   DGAModePtr modes,
174   int num
175){
176    DGAScreenPtr pScreenPriv;
177    int i;
178
179    /* No DGA? Ignore call (but don't make it look like it failed) */
180    if(DGAScreenKey == NULL)
181	return TRUE;
182
183    pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
184
185    /* Same as above */
186    if(!pScreenPriv)
187	return TRUE;
188
189    /* Can't do this while DGA is active */
190    if(pScreenPriv->current)
191	return FALSE;
192
193    /* Quick sanity check */
194    if(!num)
195	modes = NULL;
196    else if(!modes)
197	num = 0;
198
199    pScreenPriv->numModes = num;
200    pScreenPriv->modes = modes;
201
202    /* This practically disables DGA. So be it. */
203    if(!num)
204	return TRUE;
205
206    for(i = 0; i < num; i++)
207	modes[i].num = i + 1;
208
209#ifdef PANORAMIX
210     if(!noPanoramiXExtension)
211	for(i = 0; i < num; i++)
212	    modes[i].flags &= ~DGA_PIXMAP_AVAILABLE;
213#endif
214
215     return TRUE;
216}
217
218static void
219FreeMarkedVisuals(ScreenPtr pScreen)
220{
221    DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
222    FakedVisualList *prev, *curr, *tmp;
223
224    if(!pScreenPriv->fakedVisuals)
225	return;
226
227    prev = NULL;
228    curr = pScreenPriv->fakedVisuals;
229
230    while(curr) {
231	if(curr->free) {
232	    tmp = curr;
233	    curr = curr->next;
234	    if(prev)
235		prev->next = curr;
236	    else
237		pScreenPriv->fakedVisuals = curr;
238	    xfree(tmp->pVisual);
239	    xfree(tmp);
240	} else {
241	    prev = curr;
242	    curr = curr->next;
243	}
244    }
245}
246
247static Bool
248DGACloseScreen(int i, ScreenPtr pScreen)
249{
250   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
251
252   if (XDGAEventBase) {
253       mieqSetHandler(*XDGAEventBase + MotionNotify, NULL);
254       mieqSetHandler(*XDGAEventBase + ButtonPress, NULL);
255       mieqSetHandler(*XDGAEventBase + ButtonRelease, NULL);
256       mieqSetHandler(*XDGAEventBase + KeyPress, NULL);
257       mieqSetHandler(*XDGAEventBase + KeyRelease, NULL);
258    }
259
260   FreeMarkedVisuals(pScreen);
261
262   pScreen->CloseScreen = pScreenPriv->CloseScreen;
263   pScreen->DestroyColormap = pScreenPriv->DestroyColormap;
264   pScreen->InstallColormap = pScreenPriv->InstallColormap;
265   pScreen->UninstallColormap = pScreenPriv->UninstallColormap;
266
267   /* DGAShutdown() should have ensured that no DGA
268	screen were active by here */
269
270   xfree(pScreenPriv);
271
272   return((*pScreen->CloseScreen)(i, pScreen));
273}
274
275
276static void
277DGADestroyColormap(ColormapPtr pmap)
278{
279   ScreenPtr pScreen = pmap->pScreen;
280   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
281   VisualPtr pVisual = pmap->pVisual;
282
283   if(pScreenPriv->fakedVisuals) {
284	FakedVisualList *curr = pScreenPriv->fakedVisuals;
285
286	while(curr) {
287	    if(curr->pVisual == pVisual) {
288		/* We can't get rid of them yet since FreeColormap
289		   still needs the pVisual during the cleanup */
290		curr->free = TRUE;
291		break;
292	    }
293	    curr = curr->next;
294	}
295   }
296
297   if(pScreenPriv->DestroyColormap) {
298        pScreen->DestroyColormap = pScreenPriv->DestroyColormap;
299        (*pScreen->DestroyColormap)(pmap);
300        pScreen->DestroyColormap = DGADestroyColormap;
301   }
302}
303
304
305static void
306DGAInstallColormap(ColormapPtr pmap)
307{
308    ScreenPtr pScreen = pmap->pScreen;
309    DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
310
311    if(pScreenPriv->current && pScreenPriv->dgaColormap) {
312	if (pmap != pScreenPriv->dgaColormap) {
313	    pScreenPriv->savedColormap = pmap;
314	    pmap = pScreenPriv->dgaColormap;
315	}
316    }
317
318    pScreen->InstallColormap = pScreenPriv->InstallColormap;
319    (*pScreen->InstallColormap)(pmap);
320    pScreen->InstallColormap = DGAInstallColormap;
321}
322
323static void
324DGAUninstallColormap(ColormapPtr pmap)
325{
326    ScreenPtr pScreen = pmap->pScreen;
327    DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
328
329    if(pScreenPriv->current && pScreenPriv->dgaColormap) {
330	if (pmap == pScreenPriv->dgaColormap) {
331	    pScreenPriv->dgaColormap = NULL;
332	}
333    }
334
335    pScreen->UninstallColormap = pScreenPriv->UninstallColormap;
336    (*pScreen->UninstallColormap)(pmap);
337    pScreen->UninstallColormap = DGAUninstallColormap;
338}
339
340int
341xf86SetDGAMode(
342   int index,
343   int num,
344   DGADevicePtr devRet
345){
346   ScreenPtr pScreen = screenInfo.screens[index];
347   DGAScreenPtr pScreenPriv;
348   ScrnInfoPtr pScrn;
349   DGADevicePtr device;
350   PixmapPtr pPix = NULL;
351   DGAModePtr pMode = NULL;
352
353   /* First check if DGAInit was successful on this screen */
354   if (DGAScreenKey == NULL)
355	return BadValue;
356   pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
357   if (!pScreenPriv)
358	return BadValue;
359   pScrn = pScreenPriv->pScrn;
360
361   if(!num) {
362	if(pScreenPriv->current) {
363	    PixmapPtr oldPix = pScreenPriv->current->pPix;
364	    if(oldPix) {
365		if(oldPix->drawable.id)
366		    FreeResource(oldPix->drawable.id, RT_NONE);
367		else
368		    (*pScreen->DestroyPixmap)(oldPix);
369	    }
370	    xfree(pScreenPriv->current);
371	    pScreenPriv->current = NULL;
372	    pScrn->vtSema = TRUE;
373	    (*pScreenPriv->funcs->SetMode)(pScrn, NULL);
374	    if(pScreenPriv->savedColormap) {
375	        (*pScreen->InstallColormap)(pScreenPriv->savedColormap);
376		pScreenPriv->savedColormap = NULL;
377	    }
378	    pScreenPriv->dgaColormap = NULL;
379	    (*pScrn->EnableDisableFBAccess)(index, TRUE);
380
381	    FreeMarkedVisuals(pScreen);
382	}
383
384        pScreenPriv->grabMouse = FALSE;
385        pScreenPriv->grabKeyboard = FALSE;
386
387	return Success;
388   }
389
390   if(!pScrn->vtSema && !pScreenPriv->current) /* Really switched away */
391	return BadAlloc;
392
393   if((num > 0) && (num <= pScreenPriv->numModes))
394	pMode = &(pScreenPriv->modes[num - 1]);
395   else
396	return BadValue;
397
398   if(!(device = (DGADevicePtr)xalloc(sizeof(DGADeviceRec))))
399	return BadAlloc;
400
401   if(!pScreenPriv->current) {
402	Bool oldVTSema = pScrn->vtSema;
403
404	pScrn->vtSema = FALSE;  /* kludge until we rewrite VT switching */
405	(*pScrn->EnableDisableFBAccess)(index, FALSE);
406	pScrn->vtSema = oldVTSema;
407   }
408
409   if(!(*pScreenPriv->funcs->SetMode)(pScrn, pMode)) {
410	xfree(device);
411	return BadAlloc;
412   }
413
414   pScrn->currentMode = pMode->mode;
415
416   if(!pScreenPriv->current && !pScreenPriv->input) {
417	/* if it's multihead we need to warp the cursor off of
418	   our screen so it doesn't get trapped  */
419   }
420
421   pScrn->vtSema = FALSE;
422
423   if(pScreenPriv->current) {
424	PixmapPtr oldPix = pScreenPriv->current->pPix;
425	if(oldPix) {
426	    if(oldPix->drawable.id)
427		FreeResource(oldPix->drawable.id, RT_NONE);
428	    else
429		(*pScreen->DestroyPixmap)(oldPix);
430	}
431	xfree(pScreenPriv->current);
432	pScreenPriv->current = NULL;
433   }
434
435   if(pMode->flags & DGA_PIXMAP_AVAILABLE) {
436	if((pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pMode->depth, 0))) {
437	    (*pScreen->ModifyPixmapHeader)(pPix,
438			pMode->pixmapWidth, pMode->pixmapHeight,
439			pMode->depth, pMode->bitsPerPixel,
440			pMode->bytesPerScanline,
441 			(pointer)(pMode->address));
442        }
443   }
444
445   devRet->mode = device->mode = pMode;
446   devRet->pPix = device->pPix = pPix;
447   pScreenPriv->current = device;
448   pScreenPriv->pixmapMode = FALSE;
449   pScreenPriv->grabMouse = TRUE;
450   pScreenPriv->grabKeyboard = TRUE;
451
452   return Success;
453}
454
455
456
457/*********** exported ones ***************/
458
459_X_EXPORT void
460DGASetInputMode(int index, Bool keyboard, Bool mouse)
461{
462   ScreenPtr pScreen = screenInfo.screens[index];
463   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
464
465   if (pScreenPriv)
466   {
467      pScreenPriv->grabMouse = mouse;
468      pScreenPriv->grabKeyboard = keyboard;
469
470      if (!mieq_installed) {
471          mieqSetHandler(*XDGAEventBase + MotionNotify, DGAHandleEvent);
472          mieqSetHandler(*XDGAEventBase + ButtonPress, DGAHandleEvent);
473          mieqSetHandler(*XDGAEventBase + ButtonRelease, DGAHandleEvent);
474          mieqSetHandler(*XDGAEventBase + KeyPress, DGAHandleEvent);
475          mieqSetHandler(*XDGAEventBase + KeyRelease, DGAHandleEvent);
476          mieq_installed = 1;
477      }
478   }
479}
480
481_X_EXPORT Bool
482DGAChangePixmapMode(int index, int *x, int *y, int mode)
483{
484   DGAScreenPtr pScreenPriv;
485   DGADevicePtr pDev;
486   DGAModePtr   pMode;
487   PixmapPtr    pPix;
488
489   if(DGAScreenKey == NULL)
490	return FALSE;
491
492   pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
493
494   if(!pScreenPriv || !pScreenPriv->current || !pScreenPriv->current->pPix)
495	return FALSE;
496
497   pDev = pScreenPriv->current;
498   pPix = pDev->pPix;
499   pMode = pDev->mode;
500
501   if(mode) {
502	int shift = 2;
503
504	if(*x > (pMode->pixmapWidth - pMode->viewportWidth))
505	    *x = pMode->pixmapWidth - pMode->viewportWidth;
506	if(*y > (pMode->pixmapHeight - pMode->viewportHeight))
507	    *y = pMode->pixmapHeight - pMode->viewportHeight;
508
509	switch(xf86Screens[index]->bitsPerPixel) {
510	case 16: shift = 1;  break;
511	case 32: shift = 0;  break;
512	default: break;
513	}
514
515	if(BITMAP_SCANLINE_PAD == 64)
516	    shift++;
517
518	*x = (*x >> shift) << shift;
519
520	pPix->drawable.x = *x;
521	pPix->drawable.y = *y;
522	pPix->drawable.width = pMode->viewportWidth;
523	pPix->drawable.height = pMode->viewportHeight;
524   } else {
525	pPix->drawable.x = 0;
526	pPix->drawable.y = 0;
527	pPix->drawable.width = pMode->pixmapWidth;
528	pPix->drawable.height = pMode->pixmapHeight;
529   }
530   pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER;
531   pScreenPriv->pixmapMode = mode;
532
533   return TRUE;
534}
535
536_X_EXPORT Bool
537DGAAvailable(int index)
538{
539   if(DGAScreenKey == NULL)
540	return FALSE;
541
542   if (!xf86NoSharedResources(((ScrnInfoPtr)dixLookupPrivate(
543				   &screenInfo.screens[index]->devPrivates,
544				   xf86ScreenKey))->scrnIndex, MEM))
545       return FALSE;
546
547   if(DGA_GET_SCREEN_PRIV(screenInfo.screens[index]))
548	return TRUE;
549
550   return FALSE;
551}
552
553_X_EXPORT Bool
554DGAActive(int index)
555{
556   DGAScreenPtr pScreenPriv;
557
558   if(DGAScreenKey == NULL)
559	return FALSE;
560
561   pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
562
563   if(pScreenPriv && pScreenPriv->current)
564	return TRUE;
565
566   return FALSE;
567}
568
569
570
571/* Called by the event code in case the server is abruptly terminated */
572
573void
574DGAShutdown()
575{
576    ScrnInfoPtr pScrn;
577    int i;
578
579    if(DGAScreenKey == NULL)
580	return;
581
582    for(i = 0; i < screenInfo.numScreens; i++) {
583	pScrn = xf86Screens[i];
584
585	(void)(*pScrn->SetDGAMode)(pScrn->scrnIndex, 0, NULL);
586    }
587}
588
589/* Called by the extension to initialize a mode */
590
591_X_EXPORT int
592DGASetMode(
593   int index,
594   int num,
595   XDGAModePtr mode,
596   PixmapPtr *pPix
597){
598    ScrnInfoPtr pScrn = xf86Screens[index];
599    DGADeviceRec device;
600    int ret;
601
602    /* We rely on the extension to check that DGA is available */
603
604    ret = (*pScrn->SetDGAMode)(index, num, &device);
605    if((ret == Success) && num) {
606	DGACopyModeInfo(device.mode, mode);
607	*pPix = device.pPix;
608    }
609
610    return ret;
611}
612
613/* Called from the extension to let the DDX know which events are requested */
614
615_X_EXPORT void
616DGASelectInput(
617   int index,
618   ClientPtr client,
619   long mask
620){
621   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
622
623   /* We rely on the extension to check that DGA is available */
624   pScreenPriv->client = client;
625   pScreenPriv->input = mask;
626}
627
628_X_EXPORT int
629DGAGetViewportStatus(int index)
630{
631   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
632
633   /* We rely on the extension to check that DGA is active */
634
635   if (!pScreenPriv->funcs->GetViewport)
636      return 0;
637
638   return (*pScreenPriv->funcs->GetViewport)(pScreenPriv->pScrn);
639}
640
641_X_EXPORT int
642DGASetViewport(
643   int index,
644   int x, int y,
645   int mode
646){
647   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
648
649   if (pScreenPriv->funcs->SetViewport)
650      (*pScreenPriv->funcs->SetViewport)(pScreenPriv->pScrn, x, y, mode);
651   return Success;
652}
653
654
655static int
656BitsClear(CARD32 data)
657{
658   int bits = 0;
659   CARD32 mask;
660
661   for(mask = 1; mask; mask <<= 1) {
662	if(!(data & mask)) bits++;
663	else break;
664   }
665
666   return bits;
667}
668
669_X_EXPORT int
670DGACreateColormap(int index, ClientPtr client, int id, int mode, int alloc)
671{
672   ScreenPtr pScreen = screenInfo.screens[index];
673   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
674   FakedVisualList *fvlp;
675   VisualPtr pVisual;
676   DGAModePtr pMode;
677   ColormapPtr pmap;
678
679   if(!mode || (mode > pScreenPriv->numModes))
680	return BadValue;
681
682   if((alloc != AllocNone) && (alloc != AllocAll))
683	return BadValue;
684
685   pMode = &(pScreenPriv->modes[mode - 1]);
686
687   if(!(pVisual = xalloc(sizeof(VisualRec))))
688	return BadAlloc;
689
690   pVisual->vid = FakeClientID(0);
691   pVisual->class = pMode->visualClass;
692   pVisual->nplanes = pMode->depth;
693   pVisual->ColormapEntries = 1 << pMode->depth;
694   pVisual->bitsPerRGBValue = (pMode->depth + 2) / 3;
695
696   switch (pVisual->class) {
697   case PseudoColor:
698   case GrayScale:
699   case StaticGray:
700	pVisual->bitsPerRGBValue = 8; /* not quite */
701	pVisual->redMask     = 0;
702	pVisual->greenMask   = 0;
703	pVisual->blueMask    = 0;
704	pVisual->offsetRed   = 0;
705	pVisual->offsetGreen = 0;
706	pVisual->offsetBlue  = 0;
707	break;
708   case DirectColor:
709   case TrueColor:
710	pVisual->ColormapEntries = 1 << pVisual->bitsPerRGBValue;
711                /* fall through */
712   case StaticColor:
713	pVisual->redMask = pMode->red_mask;
714	pVisual->greenMask = pMode->green_mask;
715	pVisual->blueMask = pMode->blue_mask;
716	pVisual->offsetRed   = BitsClear(pVisual->redMask);
717	pVisual->offsetGreen = BitsClear(pVisual->greenMask);
718	pVisual->offsetBlue  = BitsClear(pVisual->blueMask);
719   }
720
721   if(!(fvlp = xalloc(sizeof(FakedVisualList)))) {
722	xfree(pVisual);
723	return BadAlloc;
724   }
725
726   fvlp->free = FALSE;
727   fvlp->pVisual = pVisual;
728   fvlp->next = pScreenPriv->fakedVisuals;
729   pScreenPriv->fakedVisuals = fvlp;
730
731   LEGAL_NEW_RESOURCE(id, client);
732
733   return CreateColormap(id, pScreen, pVisual, &pmap, alloc, client->index);
734}
735
736/*  Called by the extension to install a colormap on DGA active screens */
737
738_X_EXPORT void
739DGAInstallCmap(ColormapPtr cmap)
740{
741    ScreenPtr pScreen = cmap->pScreen;
742    DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
743
744    /* We rely on the extension to check that DGA is active */
745
746    if(!pScreenPriv->dgaColormap)
747	pScreenPriv->savedColormap = miInstalledMaps[pScreen->myNum];
748
749    pScreenPriv->dgaColormap = cmap;
750
751    (*pScreen->InstallColormap)(cmap);
752}
753
754_X_EXPORT int
755DGASync(int index)
756{
757   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
758
759   /* We rely on the extension to check that DGA is active */
760
761   if (pScreenPriv->funcs->Sync)
762      (*pScreenPriv->funcs->Sync)(pScreenPriv->pScrn);
763
764   return Success;
765}
766
767_X_EXPORT int
768DGAFillRect(
769   int index,
770   int x, int y, int w, int h,
771   unsigned long color
772){
773   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
774
775   /* We rely on the extension to check that DGA is active */
776
777   if(pScreenPriv->funcs->FillRect &&
778	(pScreenPriv->current->mode->flags & DGA_FILL_RECT)) {
779
780	(*pScreenPriv->funcs->FillRect)(pScreenPriv->pScrn, x, y, w, h, color);
781	return Success;
782   }
783   return BadMatch;
784}
785
786_X_EXPORT int
787DGABlitRect(
788   int index,
789   int srcx, int srcy,
790   int w, int h,
791   int dstx, int dsty
792){
793   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
794
795   /* We rely on the extension to check that DGA is active */
796
797   if(pScreenPriv->funcs->BlitRect &&
798	(pScreenPriv->current->mode->flags & DGA_BLIT_RECT)) {
799
800	(*pScreenPriv->funcs->BlitRect)(pScreenPriv->pScrn,
801		srcx, srcy, w, h, dstx, dsty);
802	return Success;
803   }
804   return BadMatch;
805}
806
807_X_EXPORT int
808DGABlitTransRect(
809   int index,
810   int srcx, int srcy,
811   int w, int h,
812   int dstx, int dsty,
813   unsigned long color
814){
815   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
816
817   /* We rely on the extension to check that DGA is active */
818
819   if(pScreenPriv->funcs->BlitTransRect &&
820	(pScreenPriv->current->mode->flags & DGA_BLIT_RECT_TRANS)) {
821
822	(*pScreenPriv->funcs->BlitTransRect)(pScreenPriv->pScrn,
823		srcx, srcy, w, h, dstx, dsty, color);
824	return Success;
825   }
826   return BadMatch;
827}
828
829
830_X_EXPORT int
831DGAGetModes(int index)
832{
833   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
834   /* We rely on the extension to check that DGA is available */
835
836   return pScreenPriv->numModes;
837}
838
839
840_X_EXPORT int
841DGAGetModeInfo(
842  int index,
843  XDGAModePtr mode,
844  int num
845){
846   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
847   /* We rely on the extension to check that DGA is available */
848
849   if((num <= 0) || (num > pScreenPriv->numModes))
850	return BadValue;
851
852   DGACopyModeInfo(&(pScreenPriv->modes[num - 1]), mode);
853
854   return Success;
855}
856
857
858static void
859DGACopyModeInfo(
860   DGAModePtr mode,
861   XDGAModePtr xmode
862){
863   DisplayModePtr dmode = mode->mode;
864
865   xmode->num = mode->num;
866   xmode->name = dmode->name;
867   xmode->VSync_num = (int)(dmode->VRefresh * 1000.0);
868   xmode->VSync_den = 1000;
869   xmode->flags = mode->flags;
870   xmode->imageWidth = mode->imageWidth;
871   xmode->imageHeight = mode->imageHeight;
872   xmode->pixmapWidth = mode->pixmapWidth;
873   xmode->pixmapHeight = mode->pixmapHeight;
874   xmode->bytesPerScanline = mode->bytesPerScanline;
875   xmode->byteOrder = mode->byteOrder;
876   xmode->depth = mode->depth;
877   xmode->bitsPerPixel = mode->bitsPerPixel;
878   xmode->red_mask = mode->red_mask;
879   xmode->green_mask = mode->green_mask;
880   xmode->blue_mask = mode->blue_mask;
881   xmode->visualClass = mode->visualClass;
882   xmode->viewportWidth = mode->viewportWidth;
883   xmode->viewportHeight = mode->viewportHeight;
884   xmode->xViewportStep = mode->xViewportStep;
885   xmode->yViewportStep = mode->yViewportStep;
886   xmode->maxViewportX = mode->maxViewportX;
887   xmode->maxViewportY = mode->maxViewportY;
888   xmode->viewportFlags = mode->viewportFlags;
889   xmode->reserved1 = mode->reserved1;
890   xmode->reserved2 = mode->reserved2;
891   xmode->offset = mode->offset;
892
893   if(dmode->Flags & V_INTERLACE) xmode->flags |= DGA_INTERLACED;
894   if(dmode->Flags & V_DBLSCAN) xmode->flags |= DGA_DOUBLESCAN;
895}
896
897
898Bool
899DGAVTSwitch(void)
900{
901    ScreenPtr pScreen;
902    int i;
903
904    for(i = 0; i < screenInfo.numScreens; i++) {
905       pScreen = screenInfo.screens[i];
906
907       /* Alternatively, this could send events to DGA clients */
908
909       if(DGAScreenKey) {
910	   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
911
912	   if(pScreenPriv && pScreenPriv->current)
913		return FALSE;
914       }
915    }
916
917   return TRUE;
918}
919
920Bool
921DGAStealKeyEvent(DeviceIntPtr dev, int index, int key_code, int is_down)
922{
923   DGAScreenPtr pScreenPriv;
924   dgaEvent    de;
925
926   if(DGAScreenKey == NULL) /* no DGA */
927        return FALSE;
928
929   if (key_code < 8 || key_code > 255)
930       return FALSE;
931
932   pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
933
934   if(!pScreenPriv || !pScreenPriv->grabKeyboard) /* no direct mode */
935        return FALSE;
936
937    de.u.u.type = *XDGAEventBase + (is_down ? KeyPress : KeyRelease);
938    de.u.u.detail = key_code;
939    de.u.event.time = GetTimeInMillis();
940    mieqEnqueue (dev, (xEvent *) &de);
941
942   return TRUE;
943}
944
945static int  DGAMouseX, DGAMouseY;
946
947Bool
948DGAStealMotionEvent(DeviceIntPtr dev, int index, int dx, int dy)
949{
950   DGAScreenPtr pScreenPriv;
951    dgaEvent    de;
952
953   if(DGAScreenKey == NULL) /* no DGA */
954        return FALSE;
955
956   pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
957
958   if(!pScreenPriv || !pScreenPriv->grabMouse) /* no direct mode */
959        return FALSE;
960
961    DGAMouseX += dx;
962    if (DGAMouseX < 0)
963        DGAMouseX = 0;
964    else if (DGAMouseX > screenInfo.screens[index]->width)
965        DGAMouseX = screenInfo.screens[index]->width;
966    DGAMouseY += dy;
967    if (DGAMouseY < 0)
968        DGAMouseY = 0;
969    else if (DGAMouseY > screenInfo.screens[index]->height)
970        DGAMouseY = screenInfo.screens[index]->height;
971    de.u.u.type = *XDGAEventBase + MotionNotify;
972    de.u.u.detail = 0;
973    de.u.event.time = GetTimeInMillis();
974    de.u.event.dx = dx;
975    de.u.event.dy = dy;
976    de.u.event.pad1 = DGAMouseX;
977    de.u.event.pad2 = DGAMouseY;
978    mieqEnqueue (dev, (xEvent *) &de);
979    return TRUE;
980}
981
982Bool
983DGAStealButtonEvent(DeviceIntPtr dev, int index, int button, int is_down)
984{
985    DGAScreenPtr pScreenPriv;
986    dgaEvent de;
987
988    if (DGAScreenKey == NULL)
989        return FALSE;
990
991    pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
992
993    if (!pScreenPriv || !pScreenPriv->grabMouse)
994        return FALSE;
995
996    de.u.u.type = *XDGAEventBase + (is_down ? ButtonPress : ButtonRelease);
997    de.u.u.detail = button;
998    de.u.event.time = GetTimeInMillis();
999    de.u.event.dx = 0;
1000    de.u.event.dy = 0;
1001    de.u.event.pad1 = DGAMouseX;
1002    de.u.event.pad2 = DGAMouseY;
1003    mieqEnqueue (dev, (xEvent *) &de);
1004
1005    return TRUE;
1006}
1007
1008/* We have the power to steal or modify events that are about to get queued */
1009
1010Bool
1011DGAIsDgaEvent (xEvent *e)
1012{
1013    int	    coreEquiv;
1014    if (DGAScreenKey == NULL || XDGAEventBase == 0)
1015	return FALSE;
1016    coreEquiv = e->u.u.type - *XDGAEventBase;
1017    if (KeyPress <= coreEquiv && coreEquiv <= MotionNotify)
1018	return TRUE;
1019    return FALSE;
1020}
1021
1022#define NoSuchEvent 0x80000000	/* so doesn't match NoEventMask */
1023static Mask filters[] =
1024{
1025	NoSuchEvent,		       /* 0 */
1026	NoSuchEvent,		       /* 1 */
1027	KeyPressMask,		       /* KeyPress */
1028	KeyReleaseMask,		       /* KeyRelease */
1029	ButtonPressMask,	       /* ButtonPress */
1030	ButtonReleaseMask,	       /* ButtonRelease */
1031	PointerMotionMask,	       /* MotionNotify (initial state) */
1032};
1033
1034static void
1035DGAProcessKeyboardEvent (ScreenPtr pScreen, dgaEvent *de, DeviceIntPtr keybd)
1036{
1037    int		    coreEquiv;
1038    xEvent	    xi;
1039    KeyClassPtr	    keyc = keybd->key;
1040    DGAScreenPtr    pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
1041    DeviceIntPtr    pointer = GetPairedDevice(keybd);
1042
1043    coreEquiv = de->u.u.type - *XDGAEventBase;
1044
1045    /*
1046     * Fill in remaining event state
1047     */
1048    de->u.event.dx = 0;
1049    de->u.event.dy = 0;
1050    de->u.event.screen = pScreen->myNum;
1051    de->u.event.state = keyc->state | pointer->button->state;
1052
1053    de->u.u.type = (IEventBase - 1) + coreEquiv; /* change to XI event */
1054    UpdateDeviceState(keybd, (xEvent*)de, 1);
1055    de->u.u.type = *XDGAEventBase + coreEquiv; /* change back */
1056
1057    /*
1058     * Deliver the DGA event
1059     */
1060    if (pScreenPriv->client)
1061    {
1062	/* If the DGA client has selected input, then deliver based on the usual filter */
1063	TryClientEvents (pScreenPriv->client, keybd, (xEvent *) de, 1,
1064			 filters[coreEquiv], pScreenPriv->input, 0);
1065    }
1066    else
1067    {
1068	/* If the keyboard is actively grabbed, deliver a grabbed core event */
1069	if (keybd->deviceGrab.grab && !keybd->deviceGrab.fromPassiveGrab)
1070	{
1071	    xi.u.u.type                  = (IEventBase - 1) + coreEquiv;
1072	    xi.u.u.detail                = de->u.u.detail;
1073	    xi.u.keyButtonPointer.time   = de->u.event.time;
1074	    xi.u.keyButtonPointer.eventX = de->u.event.dx;
1075	    xi.u.keyButtonPointer.eventY = de->u.event.dy;
1076	    xi.u.keyButtonPointer.rootX  = de->u.event.dx;
1077	    xi.u.keyButtonPointer.rootY  = de->u.event.dy;
1078	    xi.u.keyButtonPointer.state  = de->u.event.state;
1079	    ((deviceKeyButtonPointer*)&xi)->deviceid = keybd->id;
1080	    DeliverGrabbedEvent (&xi, keybd, FALSE, 1);
1081	}
1082    }
1083}
1084
1085static void
1086DGAProcessPointerEvent (ScreenPtr pScreen, dgaEvent *de, DeviceIntPtr mouse)
1087{
1088    ButtonClassPtr  butc = mouse->button;
1089    int		    coreEquiv;
1090    DGAScreenPtr    pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
1091    xEvent	    xi;
1092
1093    coreEquiv = de->u.u.type - *XDGAEventBase;
1094    /*
1095     * Fill in remaining event state
1096     */
1097    de->u.event.screen = pScreen->myNum;
1098    de->u.event.state = butc->state | GetPairedDevice(mouse)->key->state;
1099
1100    de->u.u.type = (IEventBase - 1) + coreEquiv; /* change to XI event */
1101    UpdateDeviceState(mouse, (xEvent*)de, 1);
1102    de->u.u.type = *XDGAEventBase + coreEquiv; /* change back */
1103
1104    /*
1105     * Deliver the DGA event
1106     */
1107    if (pScreenPriv->client)
1108    {
1109	/* If the DGA client has selected input, then deliver based on the usual filter */
1110	TryClientEvents (pScreenPriv->client, mouse, (xEvent *) de, 1,
1111			 filters[coreEquiv], pScreenPriv->input, 0);
1112    }
1113    else
1114    {
1115	/* If the pointer is actively grabbed, deliver a grabbed core event */
1116	if (mouse->deviceGrab.grab && !mouse->deviceGrab.fromPassiveGrab)
1117	{
1118	    xi.u.u.type                   = (IEventBase - 1 ) + coreEquiv;
1119	    xi.u.u.detail                 = de->u.u.detail;
1120	    xi.u.keyButtonPointer.time    = de->u.event.time;
1121	    xi.u.keyButtonPointer.eventX  = de->u.event.dx;
1122	    xi.u.keyButtonPointer.eventY  = de->u.event.dy;
1123	    xi.u.keyButtonPointer.rootX   = de->u.event.dx;
1124	    xi.u.keyButtonPointer.rootY   = de->u.event.dy;
1125	    xi.u.keyButtonPointer.state   = de->u.event.state;
1126	    DeliverGrabbedEvent (&xi, mouse, FALSE, 1);
1127	}
1128    }
1129}
1130
1131_X_EXPORT Bool
1132DGAOpenFramebuffer(
1133   int index,
1134   char **name,
1135   unsigned char **mem,
1136   int *size,
1137   int *offset,
1138   int *flags
1139){
1140   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
1141
1142   /* We rely on the extension to check that DGA is available */
1143
1144   return (*pScreenPriv->funcs->OpenFramebuffer)(pScreenPriv->pScrn,
1145				name, mem, size, offset, flags);
1146}
1147
1148_X_EXPORT void
1149DGACloseFramebuffer(int index)
1150{
1151   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
1152
1153   /* We rely on the extension to check that DGA is available */
1154   if(pScreenPriv->funcs->CloseFramebuffer)
1155	(*pScreenPriv->funcs->CloseFramebuffer)(pScreenPriv->pScrn);
1156}
1157
1158/*  For DGA 1.0 backwards compatibility only */
1159
1160_X_EXPORT int
1161DGAGetOldDGAMode(int index)
1162{
1163   DGAScreenPtr pScreenPriv = DGA_GET_SCREEN_PRIV(screenInfo.screens[index]);
1164   ScrnInfoPtr pScrn = pScreenPriv->pScrn;
1165   DGAModePtr mode;
1166   int i, w, h, p;
1167
1168   /* We rely on the extension to check that DGA is available */
1169
1170   w = pScrn->currentMode->HDisplay;
1171   h = pScrn->currentMode->VDisplay;
1172   p = ((pScrn->displayWidth * (pScrn->bitsPerPixel >> 3)) + 3) & ~3L;
1173
1174   for(i = 0; i < pScreenPriv->numModes; i++) {
1175	mode = &(pScreenPriv->modes[i]);
1176
1177	if((mode->viewportWidth == w) && (mode->viewportHeight == h) &&
1178		(mode->bytesPerScanline == p) &&
1179		(mode->bitsPerPixel == pScrn->bitsPerPixel) &&
1180		(mode->depth == pScrn->depth)) {
1181
1182		return mode->num;
1183	}
1184   }
1185
1186   return 0;
1187}
1188
1189static void
1190DGAHandleEvent(int screen_num, xEvent *event, DeviceIntPtr device, int nevents)
1191{
1192    dgaEvent	    *de = (dgaEvent *) event;
1193    ScreenPtr       pScreen = screenInfo.screens[screen_num];
1194    DGAScreenPtr    pScreenPriv;
1195    int		    coreEquiv;
1196
1197    /* no DGA */
1198    if (DGAScreenKey == NULL || XDGAEventBase == 0)
1199	return;
1200    pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
1201
1202    /* DGA not initialized on this screen */
1203    if (!pScreenPriv)
1204	return;
1205
1206    coreEquiv = de->u.u.type - *XDGAEventBase;
1207    /* Not a DGA event; shouldn't happen, but you never know. */
1208    if (coreEquiv < KeyPress || coreEquiv > MotionNotify)
1209	return;
1210
1211    switch (coreEquiv) {
1212    case KeyPress:
1213    case KeyRelease:
1214	DGAProcessKeyboardEvent (pScreen, de, device);
1215	break;
1216    default:
1217	DGAProcessPointerEvent (pScreen, de, device);
1218	break;
1219    }
1220}
1221