xf86RandR.c revision 05b261ec
1/* 2 * 3 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that 8 * copyright notice and this permission notice appear in supporting 9 * documentation, and that the name of Keith Packard not be used in 10 * advertising or publicity pertaining to distribution of the software without 11 * specific, written prior permission. Keith Packard makes no 12 * representations about the suitability of this software for any purpose. It 13 * is provided "as is" without express or implied warranty. 14 * 15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21 * PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24#ifdef HAVE_XORG_CONFIG_H 25#include <xorg-config.h> 26#endif 27 28#include <X11/X.h> 29#include "os.h" 30#include "mibank.h" 31#include "globals.h" 32#include "xf86.h" 33#include "xf86Priv.h" 34#include "xf86DDC.h" 35#include "mipointer.h" 36#include <randrstr.h> 37 38typedef struct _xf86RandRInfo { 39 CreateScreenResourcesProcPtr CreateScreenResources; 40 CloseScreenProcPtr CloseScreen; 41 int virtualX; 42 int virtualY; 43 int mmWidth; 44 int mmHeight; 45 Rotation rotation; 46} XF86RandRInfoRec, *XF86RandRInfoPtr; 47 48static int xf86RandRIndex = -1; 49static int xf86RandRGeneration; 50 51#define XF86RANDRINFO(p) ((XF86RandRInfoPtr) (p)->devPrivates[xf86RandRIndex].ptr) 52 53static int 54xf86RandRModeRefresh (DisplayModePtr mode) 55{ 56 if (mode->VRefresh) 57 return (int) (mode->VRefresh + 0.5); 58 else 59 return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); 60} 61 62static Bool 63xf86RandRGetInfo (ScreenPtr pScreen, Rotation *rotations) 64{ 65 RRScreenSizePtr pSize; 66 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 67 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 68 DisplayModePtr mode; 69 int refresh0 = 60; 70 xorgRRModeMM RRModeMM; 71 72 *rotations = RR_Rotate_0; 73 74 for (mode = scrp->modes; ; mode = mode->next) 75 { 76 int refresh = xf86RandRModeRefresh (mode); 77 78 if (mode == scrp->modes) 79 refresh0 = refresh; 80 81 RRModeMM.mode = mode; 82 RRModeMM.virtX = randrp->virtualX; 83 RRModeMM.virtY = randrp->virtualY; 84 RRModeMM.mmWidth = randrp->mmWidth; 85 RRModeMM.mmHeight = randrp->mmHeight; 86 87 if(scrp->DriverFunc) { 88 (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); 89 } 90 91 pSize = RRRegisterSize (pScreen, 92 mode->HDisplay, mode->VDisplay, 93 RRModeMM.mmWidth, RRModeMM.mmHeight); 94 if (!pSize) 95 return FALSE; 96 RRRegisterRate (pScreen, pSize, refresh); 97 if (mode == scrp->currentMode && 98 mode->HDisplay == scrp->virtualX && mode->VDisplay == scrp->virtualY) 99 RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); 100 if (mode->next == scrp->modes) 101 break; 102 } 103 if (scrp->currentMode->HDisplay != randrp->virtualX || 104 scrp->currentMode->VDisplay != randrp->virtualY) 105 { 106 mode = scrp->modes; 107 108 RRModeMM.mode = NULL; 109 RRModeMM.virtX = randrp->virtualX; 110 RRModeMM.virtY = randrp->virtualY; 111 RRModeMM.mmWidth = randrp->mmWidth; 112 RRModeMM.mmHeight = randrp->mmHeight; 113 114 if(scrp->DriverFunc) { 115 (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); 116 } 117 118 pSize = RRRegisterSize (pScreen, 119 randrp->virtualX, randrp->virtualY, 120 RRModeMM.mmWidth, RRModeMM.mmHeight); 121 if (!pSize) 122 return FALSE; 123 RRRegisterRate (pScreen, pSize, refresh0); 124 if (scrp->virtualX == randrp->virtualX && 125 scrp->virtualY == randrp->virtualY) 126 { 127 RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize); 128 } 129 } 130 131 /* If there is driver support for randr, let it set our supported rotations */ 132 if(scrp->DriverFunc) { 133 xorgRRRotation RRRotation; 134 135 RRRotation.RRRotations = *rotations; 136 if (!(*scrp->DriverFunc)(scrp, RR_GET_INFO, &RRRotation)) 137 return TRUE; 138 *rotations = RRRotation.RRRotations; 139 } 140 141 return TRUE; 142} 143 144static Bool 145xf86RandRSetMode (ScreenPtr pScreen, 146 DisplayModePtr mode, 147 Bool useVirtual, 148 int mmWidth, 149 int mmHeight) 150{ 151 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 152 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 153 int oldWidth = pScreen->width; 154 int oldHeight = pScreen->height; 155 int oldmmWidth = pScreen->mmWidth; 156 int oldmmHeight = pScreen->mmHeight; 157 int oldVirtualX = scrp->virtualX; 158 int oldVirtualY = scrp->virtualY; 159 WindowPtr pRoot = WindowTable[pScreen->myNum]; 160 Bool ret = TRUE; 161 162 if (pRoot) 163 (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); 164 if (useVirtual) 165 { 166 scrp->virtualX = randrp->virtualX; 167 scrp->virtualY = randrp->virtualY; 168 } 169 else 170 { 171 scrp->virtualX = mode->HDisplay; 172 scrp->virtualY = mode->VDisplay; 173 } 174 if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) 175 { 176 /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ 177 pScreen->width = scrp->virtualY; 178 pScreen->height = scrp->virtualX; 179 pScreen->mmWidth = mmHeight; 180 pScreen->mmHeight = mmWidth; 181 } 182 else 183 { 184 pScreen->width = scrp->virtualX; 185 pScreen->height = scrp->virtualY; 186 pScreen->mmWidth = mmWidth; 187 pScreen->mmHeight = mmHeight; 188 } 189 if (!xf86SwitchMode (pScreen, mode)) 190 { 191 pScreen->width = oldWidth; 192 pScreen->height = oldHeight; 193 pScreen->mmWidth = oldmmWidth; 194 pScreen->mmHeight = oldmmHeight; 195 scrp->virtualX = oldVirtualX; 196 scrp->virtualY = oldVirtualY; 197 ret = FALSE; 198 } 199 /* 200 * Make sure the layout is correct 201 */ 202 xf86ReconfigureLayout(); 203 204 /* 205 * Make sure the whole screen is visible 206 */ 207 xf86SetViewport (pScreen, pScreen->width, pScreen->height); 208 xf86SetViewport (pScreen, 0, 0); 209 if (pRoot) 210 (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); 211 return ret; 212} 213 214static Bool 215xf86RandRSetConfig (ScreenPtr pScreen, 216 Rotation rotation, 217 int rate, 218 RRScreenSizePtr pSize) 219{ 220 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 221 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 222 DisplayModePtr mode; 223 int px, py; 224 Bool useVirtual = FALSE; 225 Rotation oldRotation = randrp->rotation; 226 227 miPointerPosition (&px, &py); 228 for (mode = scrp->modes; ; mode = mode->next) 229 { 230 if (mode->HDisplay == pSize->width && 231 mode->VDisplay == pSize->height && 232 (rate == 0 || xf86RandRModeRefresh (mode) == rate)) 233 break; 234 if (mode->next == scrp->modes) 235 { 236 if (pSize->width == randrp->virtualX && 237 pSize->height == randrp->virtualY) 238 { 239 mode = scrp->modes; 240 useVirtual = TRUE; 241 break; 242 } 243 return FALSE; 244 } 245 } 246 247 if (randrp->rotation != rotation) { 248 249 /* Have the driver do its thing. */ 250 if (scrp->DriverFunc) { 251 xorgRRRotation RRRotation; 252 RRRotation.RRConfig.rotation = rotation; 253 RRRotation.RRConfig.rate = rate; 254 RRRotation.RRConfig.width = pSize->width; 255 RRRotation.RRConfig.height = pSize->height; 256 257 /* 258 * Currently we need to rely on HW support for rotation. 259 */ 260 if (!(*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation)) 261 return FALSE; 262 } else 263 return FALSE; 264 265 randrp->rotation = rotation; 266 } 267 268 if (!xf86RandRSetMode (pScreen, mode, useVirtual, pSize->mmWidth, pSize->mmHeight)) { 269 if(randrp->rotation != oldRotation) { 270 /* Have the driver undo its thing. */ 271 if (scrp->DriverFunc) { 272 xorgRRRotation RRRotation; 273 RRRotation.RRConfig.rotation = oldRotation; 274 RRRotation.RRConfig.rate = xf86RandRModeRefresh (scrp->currentMode); 275 RRRotation.RRConfig.width = scrp->virtualX; 276 RRRotation.RRConfig.height = scrp->virtualY; 277 (*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation); 278 } 279 280 randrp->rotation = oldRotation; 281 } 282 return FALSE; 283 } 284 /* 285 * Move the cursor back where it belongs; SwitchMode repositions it 286 */ 287 if (pScreen == miPointerCurrentScreen ()) 288 { 289 px = (px >= pScreen->width ? (pScreen->width - 1) : px); 290 py = (py >= pScreen->height ? (pScreen->height - 1) : py); 291 292 xf86SetViewport(pScreen, px, py); 293 294 (*pScreen->SetCursorPosition) (pScreen, px, py, FALSE); 295 } 296 297 return TRUE; 298} 299 300/* 301 * Wait until the screen is initialized before whacking the 302 * sizes around; otherwise the screen pixmap will be allocated 303 * at the current mode size rather than the maximum size 304 */ 305static Bool 306xf86RandRCreateScreenResources (ScreenPtr pScreen) 307{ 308 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 309#if 0 310 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 311 DisplayModePtr mode; 312#endif 313 314 pScreen->CreateScreenResources = randrp->CreateScreenResources; 315 if (!(*pScreen->CreateScreenResources) (pScreen)) 316 return FALSE; 317 318#if 0 319 mode = scrp->currentMode; 320 if (mode) 321 xf86RandRSetMode (pScreen, mode, TRUE); 322#endif 323 324 return TRUE; 325} 326 327/* 328 * Reset size back to original 329 */ 330static Bool 331xf86RandRCloseScreen (int index, ScreenPtr pScreen) 332{ 333 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 334 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 335 336 scrp->virtualX = pScreen->width = randrp->virtualX; 337 scrp->virtualY = pScreen->height = randrp->virtualY; 338 scrp->currentMode = scrp->modes; 339 pScreen->CloseScreen = randrp->CloseScreen; 340 xfree (randrp); 341 pScreen->devPrivates[xf86RandRIndex].ptr = 0; 342 return (*pScreen->CloseScreen) (index, pScreen); 343} 344 345_X_EXPORT Rotation 346xf86GetRotation(ScreenPtr pScreen) 347{ 348 if (xf86RandRIndex == -1) 349 return RR_Rotate_0; 350 351 return XF86RANDRINFO(pScreen)->rotation; 352} 353 354/* Function to change RandR's idea of the virtual screen size */ 355_X_EXPORT Bool 356xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen, 357 int newvirtX, int newvirtY, int newmmWidth, int newmmHeight, 358 Bool resetMode) 359{ 360 XF86RandRInfoPtr randrp; 361 362 if (xf86RandRIndex == -1) 363 return FALSE; 364 365 randrp = XF86RANDRINFO(pScreen); 366 if (randrp == NULL) 367 return FALSE; 368 369 if (newvirtX > 0) 370 randrp->virtualX = newvirtX; 371 372 if (newvirtY > 0) 373 randrp->virtualY = newvirtY; 374 375 if (newmmWidth > 0) 376 randrp->mmWidth = newmmWidth; 377 378 if (newmmHeight > 0) 379 randrp->mmHeight = newmmHeight; 380 381 /* This is only for during server start */ 382 if (resetMode) { 383 return (xf86RandRSetMode(pScreen, 384 XF86SCRNINFO(pScreen)->currentMode, 385 TRUE, 386 pScreen->mmWidth, pScreen->mmHeight)); 387 } 388 389 return TRUE; 390} 391 392Bool 393xf86RandRInit (ScreenPtr pScreen) 394{ 395 rrScrPrivPtr rp; 396 XF86RandRInfoPtr randrp; 397 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 398 399#ifdef PANORAMIX 400 /* XXX disable RandR when using Xinerama */ 401 if (!noPanoramiXExtension) 402 return TRUE; 403#endif 404 if (xf86RandRGeneration != serverGeneration) 405 { 406 xf86RandRIndex = AllocateScreenPrivateIndex(); 407 xf86RandRGeneration = serverGeneration; 408 } 409 410 randrp = xalloc (sizeof (XF86RandRInfoRec)); 411 if (!randrp) 412 return FALSE; 413 414 if (!RRScreenInit (pScreen)) 415 { 416 xfree (randrp); 417 return FALSE; 418 } 419 rp = rrGetScrPriv(pScreen); 420 rp->rrGetInfo = xf86RandRGetInfo; 421 rp->rrSetConfig = xf86RandRSetConfig; 422 423 randrp->virtualX = scrp->virtualX; 424 randrp->virtualY = scrp->virtualY; 425 randrp->mmWidth = pScreen->mmWidth; 426 randrp->mmHeight = pScreen->mmHeight; 427 428 randrp->CreateScreenResources = pScreen->CreateScreenResources; 429 pScreen->CreateScreenResources = xf86RandRCreateScreenResources; 430 431 randrp->CloseScreen = pScreen->CloseScreen; 432 pScreen->CloseScreen = xf86RandRCloseScreen; 433 434 randrp->rotation = RR_Rotate_0; 435 436 pScreen->devPrivates[xf86RandRIndex].ptr = randrp; 437 return TRUE; 438} 439 440 441