463 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			463 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  *
 | |
|  * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that
 | |
|  * copyright notice and this permission notice appear in supporting
 | |
|  * documentation, and that the name of Keith Packard not be used in
 | |
|  * advertising or publicity pertaining to distribution of the software without
 | |
|  * specific, written prior permission.  Keith Packard makes no
 | |
|  * representations about the suitability of this software for any purpose.  It
 | |
|  * is provided "as is" without express or implied warranty.
 | |
|  *
 | |
|  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | |
|  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 | |
|  * PERFORMANCE OF THIS SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_XORG_CONFIG_H
 | |
| #include <xorg-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <X11/X.h>
 | |
| #include "os.h"
 | |
| #include "globals.h"
 | |
| #include "xf86.h"
 | |
| #include "xf86str.h"
 | |
| #include "xf86Priv.h"
 | |
| #include "xf86DDC.h"
 | |
| #include "mipointer.h"
 | |
| #include <randrstr.h>
 | |
| #include "inputstr.h"
 | |
| 
 | |
| typedef struct _xf86RandRInfo {
 | |
|     CreateScreenResourcesProcPtr    CreateScreenResources;
 | |
|     CloseScreenProcPtr		    CloseScreen;
 | |
|     int				    virtualX;
 | |
|     int				    virtualY;
 | |
|     int				    mmWidth;
 | |
|     int				    mmHeight;
 | |
|     Rotation			    rotation;
 | |
| } XF86RandRInfoRec, *XF86RandRInfoPtr;
 | |
| 
 | |
| static DevPrivateKeyRec xf86RandRKeyRec;
 | |
| static DevPrivateKey xf86RandRKey;
 | |
| 
 | |
| #define XF86RANDRINFO(p) ((XF86RandRInfoPtr)dixLookupPrivate(&(p)->devPrivates, xf86RandRKey))
 | |
| 
 | |
| static int
 | |
| xf86RandRModeRefresh (DisplayModePtr mode)
 | |
| {
 | |
|     if (mode->VRefresh)
 | |
| 	return (int) (mode->VRefresh + 0.5);
 | |
|     else if (mode->Clock == 0)
 | |
| 	return 0;
 | |
|     else
 | |
| 	return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5);
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| xf86RandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
 | |
| {
 | |
|     RRScreenSizePtr	    pSize;
 | |
|     ScrnInfoPtr		    scrp = XF86SCRNINFO(pScreen);
 | |
|     XF86RandRInfoPtr	    randrp = XF86RANDRINFO(pScreen);
 | |
|     DisplayModePtr	    mode;
 | |
|     int			    refresh0 = 60;
 | |
|     xorgRRModeMM	    RRModeMM;
 | |
| 
 | |
|     *rotations = RR_Rotate_0;
 | |
| 
 | |
|     for (mode = scrp->modes; mode != NULL ; mode = mode->next)
 | |
|     {
 | |
| 	int refresh = xf86RandRModeRefresh (mode);
 | |
| 
 | |
| 	if (mode == scrp->modes)
 | |
| 	    refresh0 = refresh;
 | |
| 
 | |
| 	RRModeMM.mode = mode;
 | |
| 	RRModeMM.virtX = randrp->virtualX;
 | |
| 	RRModeMM.virtY = randrp->virtualY;
 | |
| 	RRModeMM.mmWidth = randrp->mmWidth;
 | |
| 	RRModeMM.mmHeight = randrp->mmHeight;
 | |
| 
 | |
| 	if(scrp->DriverFunc) {
 | |
| 	   (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM);
 | |
| 	}
 | |
| 
 | |
| 	pSize = RRRegisterSize (pScreen,
 | |
| 				mode->HDisplay, mode->VDisplay,
 | |
| 				RRModeMM.mmWidth, RRModeMM.mmHeight);
 | |
| 	if (!pSize)
 | |
| 	    return FALSE;
 | |
| 	RRRegisterRate (pScreen, pSize, refresh);
 | |
| 	if (mode == scrp->currentMode &&
 | |
| 	    mode->HDisplay == scrp->virtualX && mode->VDisplay == scrp->virtualY)
 | |
| 	    RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize);
 | |
| 	if (mode->next == scrp->modes)
 | |
| 	    break;
 | |
|     }
 | |
|     if (scrp->currentMode->HDisplay != randrp->virtualX ||
 | |
| 	scrp->currentMode->VDisplay != randrp->virtualY)
 | |
|     {
 | |
| 	mode = scrp->modes;
 | |
| 
 | |
| 	RRModeMM.mode = NULL;
 | |
| 	RRModeMM.virtX = randrp->virtualX;
 | |
| 	RRModeMM.virtY = randrp->virtualY;
 | |
| 	RRModeMM.mmWidth = randrp->mmWidth;
 | |
| 	RRModeMM.mmHeight = randrp->mmHeight;
 | |
| 
 | |
| 	if(scrp->DriverFunc) {
 | |
| 	   (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM);
 | |
| 	}
 | |
| 
 | |
| 	pSize = RRRegisterSize (pScreen,
 | |
| 				randrp->virtualX, randrp->virtualY,
 | |
| 				RRModeMM.mmWidth, RRModeMM.mmHeight);
 | |
| 	if (!pSize)
 | |
| 	    return FALSE;
 | |
| 	RRRegisterRate (pScreen, pSize, refresh0);
 | |
| 	if (scrp->virtualX == randrp->virtualX &&
 | |
| 	    scrp->virtualY == randrp->virtualY)
 | |
| 	{
 | |
| 	    RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     /* If there is driver support for randr, let it set our supported rotations */
 | |
|     if(scrp->DriverFunc) {
 | |
| 	xorgRRRotation RRRotation;
 | |
| 
 | |
| 	RRRotation.RRRotations = *rotations;
 | |
| 	if (!(*scrp->DriverFunc)(scrp, RR_GET_INFO, &RRRotation))
 | |
| 	    return TRUE;
 | |
| 	*rotations = RRRotation.RRRotations;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| xf86RandRSetMode (ScreenPtr	    pScreen,
 | |
| 		  DisplayModePtr    mode,
 | |
| 		  Bool		    useVirtual,
 | |
| 		  int		    mmWidth,
 | |
| 		  int		    mmHeight)
 | |
| {
 | |
|     ScrnInfoPtr		scrp = XF86SCRNINFO(pScreen);
 | |
|     XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
 | |
|     int			oldWidth = pScreen->width;
 | |
|     int			oldHeight = pScreen->height;
 | |
|     int			oldmmWidth = pScreen->mmWidth;
 | |
|     int			oldmmHeight = pScreen->mmHeight;
 | |
|     int			oldVirtualX = scrp->virtualX;
 | |
|     int			oldVirtualY = scrp->virtualY;
 | |
|     WindowPtr		pRoot = pScreen->root;
 | |
|     Bool		ret = TRUE;
 | |
| 
 | |
|     if (pRoot && scrp->vtSema)
 | |
| 	(*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE);
 | |
|     if (useVirtual)
 | |
|     {
 | |
| 	scrp->virtualX = randrp->virtualX;
 | |
| 	scrp->virtualY = randrp->virtualY;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	scrp->virtualX = mode->HDisplay;
 | |
| 	scrp->virtualY = mode->VDisplay;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * The DIX forgets the physical dimensions we passed into RRRegisterSize, so
 | |
|      * reconstruct them if possible.
 | |
|      */
 | |
|     if(scrp->DriverFunc) {
 | |
| 	xorgRRModeMM RRModeMM;
 | |
| 
 | |
| 	RRModeMM.mode = mode;
 | |
| 	RRModeMM.virtX = scrp->virtualX;
 | |
| 	RRModeMM.virtY = scrp->virtualY;
 | |
| 	RRModeMM.mmWidth = mmWidth;
 | |
| 	RRModeMM.mmHeight = mmHeight;
 | |
| 
 | |
| 	(*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM);
 | |
| 
 | |
| 	mmWidth = RRModeMM.mmWidth;
 | |
| 	mmHeight = RRModeMM.mmHeight;
 | |
|     }
 | |
|     if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270))
 | |
|     {
 | |
| 	/* If the screen is rotated 90 or 270 degrees, swap the sizes. */
 | |
| 	pScreen->width = scrp->virtualY;
 | |
| 	pScreen->height = scrp->virtualX;
 | |
| 	pScreen->mmWidth = mmHeight;
 | |
| 	pScreen->mmHeight = mmWidth;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	pScreen->width = scrp->virtualX;
 | |
| 	pScreen->height = scrp->virtualY;
 | |
| 	pScreen->mmWidth = mmWidth;
 | |
| 	pScreen->mmHeight = mmHeight;
 | |
|     }
 | |
|     if (!xf86SwitchMode (pScreen, mode))
 | |
|     {
 | |
| 	pScreen->width = oldWidth;
 | |
| 	pScreen->height = oldHeight;
 | |
| 	pScreen->mmWidth = oldmmWidth;
 | |
| 	pScreen->mmHeight = oldmmHeight;
 | |
| 	scrp->virtualX = oldVirtualX;
 | |
| 	scrp->virtualY = oldVirtualY;
 | |
| 	ret = FALSE;
 | |
|     }
 | |
|     /*
 | |
|      * Make sure the layout is correct
 | |
|      */
 | |
|     xf86ReconfigureLayout();
 | |
| 
 | |
|     /*
 | |
|      * Make sure the whole screen is visible
 | |
|      */
 | |
|     xf86SetViewport (pScreen, pScreen->width, pScreen->height);
 | |
|     xf86SetViewport (pScreen, 0, 0);
 | |
|     if (pRoot && scrp->vtSema)
 | |
| 	(*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| xf86RandRSetConfig (ScreenPtr		pScreen,
 | |
| 		    Rotation		rotation,
 | |
| 		    int			rate,
 | |
| 		    RRScreenSizePtr	pSize)
 | |
| {
 | |
|     ScrnInfoPtr		    scrp = XF86SCRNINFO(pScreen);
 | |
|     XF86RandRInfoPtr	    randrp = XF86RANDRINFO(pScreen);
 | |
|     DisplayModePtr	    mode;
 | |
|     int			    px, py;
 | |
|     Bool		    useVirtual = FALSE;
 | |
|     Rotation		    oldRotation = randrp->rotation;
 | |
| 
 | |
|     miPointerGetPosition(inputInfo.pointer, &px, &py);
 | |
|     for (mode = scrp->modes; ; mode = mode->next)
 | |
|     {
 | |
| 	if (mode->HDisplay == pSize->width &&
 | |
| 	    mode->VDisplay == pSize->height &&
 | |
| 	    (rate == 0 || xf86RandRModeRefresh (mode) == rate))
 | |
| 	    break;
 | |
| 	if (mode->next == scrp->modes)
 | |
| 	{
 | |
| 	    if (pSize->width == randrp->virtualX &&
 | |
| 		pSize->height == randrp->virtualY)
 | |
| 	    {
 | |
| 		mode = scrp->modes;
 | |
| 		useVirtual = TRUE;
 | |
| 		break;
 | |
| 	    }
 | |
| 	    return FALSE;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if (randrp->rotation != rotation) {
 | |
| 
 | |
|         /* Have the driver do its thing. */
 | |
| 	if (scrp->DriverFunc) {
 | |
| 	    xorgRRRotation RRRotation;
 | |
| 	    RRRotation.RRConfig.rotation = rotation;
 | |
| 	    RRRotation.RRConfig.rate = rate;
 | |
| 	    RRRotation.RRConfig.width = pSize->width;
 | |
| 	    RRRotation.RRConfig.height = pSize->height;
 | |
| 
 | |
| 	    /*
 | |
| 	     * Currently we need to rely on HW support for rotation.
 | |
| 	     */
 | |
| 	    if (!(*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation))
 | |
| 		return FALSE;
 | |
| 	} else
 | |
| 	    return FALSE;
 | |
| 
 | |
| 	randrp->rotation = rotation;
 | |
|     }
 | |
| 
 | |
|     if (!xf86RandRSetMode (pScreen, mode, useVirtual, pSize->mmWidth, pSize->mmHeight)) {
 | |
| 	if(randrp->rotation != oldRotation) {
 | |
| 	   /* Have the driver undo its thing. */
 | |
| 	   if (scrp->DriverFunc) {
 | |
| 	       xorgRRRotation RRRotation;
 | |
| 	       RRRotation.RRConfig.rotation = oldRotation;
 | |
| 	       RRRotation.RRConfig.rate = xf86RandRModeRefresh (scrp->currentMode);
 | |
| 	       RRRotation.RRConfig.width = scrp->virtualX;
 | |
| 	       RRRotation.RRConfig.height = scrp->virtualY;
 | |
| 	       (*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation);
 | |
| 	   }
 | |
| 
 | |
| 	   randrp->rotation = oldRotation;
 | |
| 	}
 | |
| 	return FALSE;
 | |
|     }
 | |
|     /*
 | |
|      * Move the cursor back where it belongs; SwitchMode repositions it
 | |
|      */
 | |
|     if (pScreen == miPointerCurrentScreen ())
 | |
|     {
 | |
| 	px = (px >= pScreen->width ? (pScreen->width - 1) : px);
 | |
| 	py = (py >= pScreen->height ? (pScreen->height - 1) : py);
 | |
| 
 | |
|         xf86SetViewport(pScreen, px, py);
 | |
| 
 | |
|         (*pScreen->SetCursorPosition) (inputInfo.pointer, pScreen, px, py, FALSE);
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Wait until the screen is initialized before whacking the
 | |
|  * sizes around; otherwise the screen pixmap will be allocated
 | |
|  * at the current mode size rather than the maximum size
 | |
|  */
 | |
| static Bool
 | |
| xf86RandRCreateScreenResources (ScreenPtr pScreen)
 | |
| {
 | |
|     XF86RandRInfoPtr	    randrp = XF86RANDRINFO(pScreen);
 | |
| #if 0
 | |
|     ScrnInfoPtr		    scrp = XF86SCRNINFO(pScreen);
 | |
|     DisplayModePtr	    mode;
 | |
| #endif
 | |
| 
 | |
|     pScreen->CreateScreenResources = randrp->CreateScreenResources;
 | |
|     if (!(*pScreen->CreateScreenResources) (pScreen))
 | |
| 	return FALSE;
 | |
| 
 | |
| #if 0
 | |
|     mode = scrp->currentMode;
 | |
|     if (mode)
 | |
| 	xf86RandRSetMode (pScreen, mode, TRUE);
 | |
| #endif
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Reset size back to original
 | |
|  */
 | |
| static Bool
 | |
| xf86RandRCloseScreen (int index, ScreenPtr pScreen)
 | |
| {
 | |
|     ScrnInfoPtr		    scrp = XF86SCRNINFO(pScreen);
 | |
|     XF86RandRInfoPtr	    randrp = XF86RANDRINFO(pScreen);
 | |
| 
 | |
|     scrp->virtualX = pScreen->width = randrp->virtualX;
 | |
|     scrp->virtualY = pScreen->height = randrp->virtualY;
 | |
|     scrp->currentMode = scrp->modes;
 | |
|     pScreen->CloseScreen = randrp->CloseScreen;
 | |
|     free(randrp);
 | |
|     dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, NULL);
 | |
|     return (*pScreen->CloseScreen) (index, pScreen);
 | |
| }
 | |
| 
 | |
| Rotation
 | |
| xf86GetRotation(ScreenPtr pScreen)
 | |
| {
 | |
|     if (xf86RandRKey == NULL)
 | |
|        return RR_Rotate_0;
 | |
| 
 | |
|     return XF86RANDRINFO(pScreen)->rotation;
 | |
| }
 | |
| 
 | |
| /* Function to change RandR's idea of the virtual screen size */
 | |
| Bool
 | |
| xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen,
 | |
| 	int newvirtX, int newvirtY, int newmmWidth, int newmmHeight,
 | |
| 	Bool resetMode)
 | |
| {
 | |
|     XF86RandRInfoPtr randrp;
 | |
| 
 | |
|     if (xf86RandRKey == NULL)
 | |
| 	return FALSE;
 | |
| 
 | |
|     randrp = XF86RANDRINFO(pScreen);
 | |
|     if (randrp == NULL)
 | |
| 	return FALSE;
 | |
| 
 | |
|     if (newvirtX > 0)
 | |
| 	randrp->virtualX = newvirtX;
 | |
| 
 | |
|     if (newvirtY > 0)
 | |
| 	randrp->virtualY = newvirtY;
 | |
| 
 | |
|     if (newmmWidth > 0)
 | |
| 	randrp->mmWidth = newmmWidth;
 | |
| 
 | |
|     if (newmmHeight > 0)
 | |
| 	randrp->mmHeight = newmmHeight;
 | |
| 
 | |
|     /* This is only for during server start */
 | |
|     if (resetMode) {
 | |
| 	return (xf86RandRSetMode(pScreen,
 | |
| 		  XF86SCRNINFO(pScreen)->currentMode,
 | |
| 		  TRUE,
 | |
| 		  pScreen->mmWidth, pScreen->mmHeight));
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| xf86RandRInit (ScreenPtr    pScreen)
 | |
| {
 | |
|     rrScrPrivPtr	rp;
 | |
|     XF86RandRInfoPtr	randrp;
 | |
|     ScrnInfoPtr		scrp = XF86SCRNINFO(pScreen);
 | |
| 
 | |
| #ifdef PANORAMIX
 | |
|     /* XXX disable RandR when using Xinerama */
 | |
|     if (!noPanoramiXExtension)
 | |
| 	return TRUE;
 | |
| #endif
 | |
| 
 | |
|     xf86RandRKey = &xf86RandRKeyRec;
 | |
| 
 | |
|     if (!dixRegisterPrivateKey(&xf86RandRKeyRec, PRIVATE_SCREEN, 0))
 | |
| 	return FALSE;
 | |
| 
 | |
|     randrp = malloc(sizeof (XF86RandRInfoRec));
 | |
|     if (!randrp)
 | |
| 	return FALSE;
 | |
| 
 | |
|     if (!RRScreenInit (pScreen))
 | |
|     {
 | |
| 	free(randrp);
 | |
| 	return FALSE;
 | |
|     }
 | |
|     rp = rrGetScrPriv(pScreen);
 | |
|     rp->rrGetInfo = xf86RandRGetInfo;
 | |
|     rp->rrSetConfig = xf86RandRSetConfig;
 | |
| 
 | |
|     randrp->virtualX = scrp->virtualX;
 | |
|     randrp->virtualY = scrp->virtualY;
 | |
|     randrp->mmWidth = pScreen->mmWidth;
 | |
|     randrp->mmHeight = pScreen->mmHeight;
 | |
| 
 | |
|     randrp->CreateScreenResources = pScreen->CreateScreenResources;
 | |
|     pScreen->CreateScreenResources = xf86RandRCreateScreenResources;
 | |
| 
 | |
|     randrp->CloseScreen = pScreen->CloseScreen;
 | |
|     pScreen->CloseScreen = xf86RandRCloseScreen;
 | |
| 
 | |
|     randrp->rotation = RR_Rotate_0;
 | |
| 
 | |
|     dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, randrp);
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 |