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