172 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|    Copyright (C) 1999.  The XFree86 Project Inc.
 | |
|    Copyright 2014 Red Hat, Inc.
 | |
| 
 | |
|    Written by Mark Vojkovich (mvojkovi@ucsd.edu)
 | |
|    Pre-fb-write callbacks and RENDER support - Nolan Leake (nolan@vmware.com)
 | |
| */
 | |
| 
 | |
| #ifdef HAVE_XORG_CONFIG_H
 | |
| #include <xorg-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <X11/X.h>
 | |
| #include <X11/Xproto.h>
 | |
| #include "misc.h"
 | |
| #include "pixmapstr.h"
 | |
| #include "input.h"
 | |
| #include <X11/fonts/font.h>
 | |
| #include "mi.h"
 | |
| #include "scrnintstr.h"
 | |
| #include "windowstr.h"
 | |
| #include "gcstruct.h"
 | |
| #include "dixfontstr.h"
 | |
| #include <X11/fonts/fontstruct.h>
 | |
| #include "xf86.h"
 | |
| #include "xf86str.h"
 | |
| #include "shadowfb.h"
 | |
| 
 | |
| #include "picturestr.h"
 | |
| 
 | |
| static Bool ShadowCloseScreen(ScreenPtr pScreen);
 | |
| static Bool ShadowCreateRootWindow(WindowPtr pWin);
 | |
| 
 | |
| typedef struct {
 | |
|     ScrnInfoPtr pScrn;
 | |
|     RefreshAreaFuncPtr preRefresh;
 | |
|     RefreshAreaFuncPtr postRefresh;
 | |
|     CloseScreenProcPtr CloseScreen;
 | |
|     CreateWindowProcPtr CreateWindow;
 | |
| } ShadowScreenRec, *ShadowScreenPtr;
 | |
| 
 | |
| static DevPrivateKeyRec ShadowScreenKeyRec;
 | |
| 
 | |
| static ShadowScreenPtr
 | |
| shadowfbGetScreenPrivate(ScreenPtr pScreen)
 | |
| {
 | |
|     return dixLookupPrivate(&(pScreen)->devPrivates, &ShadowScreenKeyRec);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ShadowFBInit2(ScreenPtr pScreen,
 | |
|               RefreshAreaFuncPtr preRefreshArea,
 | |
|               RefreshAreaFuncPtr postRefreshArea)
 | |
| {
 | |
|     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
 | |
|     ShadowScreenPtr pPriv;
 | |
| 
 | |
|     if (!preRefreshArea && !postRefreshArea)
 | |
|         return FALSE;
 | |
| 
 | |
|     if (!dixRegisterPrivateKey(&ShadowScreenKeyRec, PRIVATE_SCREEN, 0))
 | |
|         return FALSE;
 | |
| 
 | |
|     if (!(pPriv = (ShadowScreenPtr) malloc(sizeof(ShadowScreenRec))))
 | |
|         return FALSE;
 | |
| 
 | |
|     dixSetPrivate(&pScreen->devPrivates, &ShadowScreenKeyRec, pPriv);
 | |
| 
 | |
|     pPriv->pScrn = pScrn;
 | |
|     pPriv->preRefresh = preRefreshArea;
 | |
|     pPriv->postRefresh = postRefreshArea;
 | |
| 
 | |
|     pPriv->CloseScreen = pScreen->CloseScreen;
 | |
|     pPriv->CreateWindow = pScreen->CreateWindow;
 | |
| 
 | |
|     pScreen->CloseScreen = ShadowCloseScreen;
 | |
|     pScreen->CreateWindow = ShadowCreateRootWindow;
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ShadowFBInit(ScreenPtr pScreen, RefreshAreaFuncPtr refreshArea)
 | |
| {
 | |
|     return ShadowFBInit2(pScreen, NULL, refreshArea);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Note that we don't do DamageEmpty, or indeed look at the region inside the
 | |
|  * DamagePtr at all.  This is an optimization, believe it or not.  The
 | |
|  * incoming RegionPtr is the new damage, and if we were to empty the region
 | |
|  * miext/damage would just have to waste time reallocating and re-unioning
 | |
|  * it every time, whereas if we leave it around the union gets fast-pathed
 | |
|  * away.
 | |
|  */
 | |
| 
 | |
| static void
 | |
| shadowfbReportPre(DamagePtr damage, RegionPtr reg, void *closure)
 | |
| {
 | |
|     ShadowScreenPtr pPriv = closure;
 | |
| 
 | |
|     if (!pPriv->pScrn->vtSema)
 | |
|         return;
 | |
| 
 | |
|     pPriv->preRefresh(pPriv->pScrn, RegionNumRects(reg), RegionRects(reg));
 | |
| }
 | |
| 
 | |
| static void
 | |
| shadowfbReportPost(DamagePtr damage, RegionPtr reg, void *closure)
 | |
| {
 | |
|     ShadowScreenPtr pPriv = closure;
 | |
| 
 | |
|     if (!pPriv->pScrn->vtSema)
 | |
|         return;
 | |
| 
 | |
|     pPriv->postRefresh(pPriv->pScrn, RegionNumRects(reg), RegionRects(reg));
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| ShadowCreateRootWindow(WindowPtr pWin)
 | |
| {
 | |
|     Bool ret;
 | |
|     ScreenPtr pScreen = pWin->drawable.pScreen;
 | |
|     ShadowScreenPtr pPriv = shadowfbGetScreenPrivate(pScreen);
 | |
| 
 | |
|     /* paranoia */
 | |
|     if (pWin != pScreen->root)
 | |
|         ErrorF("ShadowCreateRootWindow called unexpectedly\n");
 | |
| 
 | |
|     /* call down, but don't hook ourselves back in; we know the first time
 | |
|      * we're called it's for the root window.
 | |
|      */
 | |
|     pScreen->CreateWindow = pPriv->CreateWindow;
 | |
|     ret = pScreen->CreateWindow(pWin);
 | |
| 
 | |
|     /* this might look like it leaks, but the damage code reaps listeners
 | |
|      * when their drawable disappears.
 | |
|      */
 | |
|     if (ret) {
 | |
|         DamagePtr damage;
 | |
| 
 | |
|         if (pPriv->preRefresh) {
 | |
|             damage = DamageCreate(shadowfbReportPre, NULL,
 | |
|                                   DamageReportRawRegion,
 | |
|                                   TRUE, pScreen, pPriv);
 | |
|             DamageRegister(&pWin->drawable, damage);
 | |
|         }
 | |
| 
 | |
|         if (pPriv->postRefresh) {
 | |
|             damage = DamageCreate(shadowfbReportPost, NULL,
 | |
|                                   DamageReportRawRegion,
 | |
|                                   TRUE, pScreen, pPriv);
 | |
|             DamageSetReportAfterOp(damage, TRUE);
 | |
|             DamageRegister(&pWin->drawable, damage);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| ShadowCloseScreen(ScreenPtr pScreen)
 | |
| {
 | |
|     ShadowScreenPtr pPriv = shadowfbGetScreenPrivate(pScreen);
 | |
| 
 | |
|     pScreen->CloseScreen = pPriv->CloseScreen;
 | |
| 
 | |
|     free(pPriv);
 | |
| 
 | |
|     return (*pScreen->CloseScreen) (pScreen);
 | |
| }
 |