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