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