xf86RandR.c revision 6747b715
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 "globals.h" 31#include "xf86.h" 32#include "xf86str.h" 33#include "xf86Priv.h" 34#include "xf86DDC.h" 35#include "mipointer.h" 36#include <randrstr.h> 37#include "inputstr.h" 38 39typedef struct _xf86RandRInfo { 40 CreateScreenResourcesProcPtr CreateScreenResources; 41 CloseScreenProcPtr CloseScreen; 42 int virtualX; 43 int virtualY; 44 int mmWidth; 45 int mmHeight; 46 Rotation rotation; 47} XF86RandRInfoRec, *XF86RandRInfoPtr; 48 49static DevPrivateKeyRec xf86RandRKeyRec; 50static DevPrivateKey xf86RandRKey; 51 52#define XF86RANDRINFO(p) ((XF86RandRInfoPtr)dixLookupPrivate(&(p)->devPrivates, xf86RandRKey)) 53 54static int 55xf86RandRModeRefresh (DisplayModePtr mode) 56{ 57 if (mode->VRefresh) 58 return (int) (mode->VRefresh + 0.5); 59 else if (mode->Clock == 0) 60 return 0; 61 else 62 return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); 63} 64 65static Bool 66xf86RandRGetInfo (ScreenPtr pScreen, Rotation *rotations) 67{ 68 RRScreenSizePtr pSize; 69 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 70 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 71 DisplayModePtr mode; 72 int refresh0 = 60; 73 xorgRRModeMM RRModeMM; 74 75 *rotations = RR_Rotate_0; 76 77 for (mode = scrp->modes; mode != NULL ; mode = mode->next) 78 { 79 int refresh = xf86RandRModeRefresh (mode); 80 81 if (mode == scrp->modes) 82 refresh0 = refresh; 83 84 RRModeMM.mode = mode; 85 RRModeMM.virtX = randrp->virtualX; 86 RRModeMM.virtY = randrp->virtualY; 87 RRModeMM.mmWidth = randrp->mmWidth; 88 RRModeMM.mmHeight = randrp->mmHeight; 89 90 if(scrp->DriverFunc) { 91 (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); 92 } 93 94 pSize = RRRegisterSize (pScreen, 95 mode->HDisplay, mode->VDisplay, 96 RRModeMM.mmWidth, RRModeMM.mmHeight); 97 if (!pSize) 98 return FALSE; 99 RRRegisterRate (pScreen, pSize, refresh); 100 if (mode == scrp->currentMode && 101 mode->HDisplay == scrp->virtualX && mode->VDisplay == scrp->virtualY) 102 RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); 103 if (mode->next == scrp->modes) 104 break; 105 } 106 if (scrp->currentMode->HDisplay != randrp->virtualX || 107 scrp->currentMode->VDisplay != randrp->virtualY) 108 { 109 mode = scrp->modes; 110 111 RRModeMM.mode = NULL; 112 RRModeMM.virtX = randrp->virtualX; 113 RRModeMM.virtY = randrp->virtualY; 114 RRModeMM.mmWidth = randrp->mmWidth; 115 RRModeMM.mmHeight = randrp->mmHeight; 116 117 if(scrp->DriverFunc) { 118 (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); 119 } 120 121 pSize = RRRegisterSize (pScreen, 122 randrp->virtualX, randrp->virtualY, 123 RRModeMM.mmWidth, RRModeMM.mmHeight); 124 if (!pSize) 125 return FALSE; 126 RRRegisterRate (pScreen, pSize, refresh0); 127 if (scrp->virtualX == randrp->virtualX && 128 scrp->virtualY == randrp->virtualY) 129 { 130 RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize); 131 } 132 } 133 134 /* If there is driver support for randr, let it set our supported rotations */ 135 if(scrp->DriverFunc) { 136 xorgRRRotation RRRotation; 137 138 RRRotation.RRRotations = *rotations; 139 if (!(*scrp->DriverFunc)(scrp, RR_GET_INFO, &RRRotation)) 140 return TRUE; 141 *rotations = RRRotation.RRRotations; 142 } 143 144 return TRUE; 145} 146 147static Bool 148xf86RandRSetMode (ScreenPtr pScreen, 149 DisplayModePtr mode, 150 Bool useVirtual, 151 int mmWidth, 152 int mmHeight) 153{ 154 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 155 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 156 int oldWidth = pScreen->width; 157 int oldHeight = pScreen->height; 158 int oldmmWidth = pScreen->mmWidth; 159 int oldmmHeight = pScreen->mmHeight; 160 int oldVirtualX = scrp->virtualX; 161 int oldVirtualY = scrp->virtualY; 162 WindowPtr pRoot = pScreen->root; 163 Bool ret = TRUE; 164 165 if (pRoot && scrp->vtSema) 166 (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); 167 if (useVirtual) 168 { 169 scrp->virtualX = randrp->virtualX; 170 scrp->virtualY = randrp->virtualY; 171 } 172 else 173 { 174 scrp->virtualX = mode->HDisplay; 175 scrp->virtualY = mode->VDisplay; 176 } 177 178 /* 179 * The DIX forgets the physical dimensions we passed into RRRegisterSize, so 180 * reconstruct them if possible. 181 */ 182 if(scrp->DriverFunc) { 183 xorgRRModeMM RRModeMM; 184 185 RRModeMM.mode = mode; 186 RRModeMM.virtX = scrp->virtualX; 187 RRModeMM.virtY = scrp->virtualY; 188 RRModeMM.mmWidth = mmWidth; 189 RRModeMM.mmHeight = mmHeight; 190 191 (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); 192 193 mmWidth = RRModeMM.mmWidth; 194 mmHeight = RRModeMM.mmHeight; 195 } 196 if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) 197 { 198 /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ 199 pScreen->width = scrp->virtualY; 200 pScreen->height = scrp->virtualX; 201 pScreen->mmWidth = mmHeight; 202 pScreen->mmHeight = mmWidth; 203 } 204 else 205 { 206 pScreen->width = scrp->virtualX; 207 pScreen->height = scrp->virtualY; 208 pScreen->mmWidth = mmWidth; 209 pScreen->mmHeight = mmHeight; 210 } 211 if (!xf86SwitchMode (pScreen, mode)) 212 { 213 pScreen->width = oldWidth; 214 pScreen->height = oldHeight; 215 pScreen->mmWidth = oldmmWidth; 216 pScreen->mmHeight = oldmmHeight; 217 scrp->virtualX = oldVirtualX; 218 scrp->virtualY = oldVirtualY; 219 ret = FALSE; 220 } 221 /* 222 * Make sure the layout is correct 223 */ 224 xf86ReconfigureLayout(); 225 226 /* 227 * Make sure the whole screen is visible 228 */ 229 xf86SetViewport (pScreen, pScreen->width, pScreen->height); 230 xf86SetViewport (pScreen, 0, 0); 231 if (pRoot && scrp->vtSema) 232 (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); 233 return ret; 234} 235 236static Bool 237xf86RandRSetConfig (ScreenPtr pScreen, 238 Rotation rotation, 239 int rate, 240 RRScreenSizePtr pSize) 241{ 242 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 243 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 244 DisplayModePtr mode; 245 int px, py; 246 Bool useVirtual = FALSE; 247 Rotation oldRotation = randrp->rotation; 248 249 miPointerGetPosition(inputInfo.pointer, &px, &py); 250 for (mode = scrp->modes; ; mode = mode->next) 251 { 252 if (mode->HDisplay == pSize->width && 253 mode->VDisplay == pSize->height && 254 (rate == 0 || xf86RandRModeRefresh (mode) == rate)) 255 break; 256 if (mode->next == scrp->modes) 257 { 258 if (pSize->width == randrp->virtualX && 259 pSize->height == randrp->virtualY) 260 { 261 mode = scrp->modes; 262 useVirtual = TRUE; 263 break; 264 } 265 return FALSE; 266 } 267 } 268 269 if (randrp->rotation != rotation) { 270 271 /* Have the driver do its thing. */ 272 if (scrp->DriverFunc) { 273 xorgRRRotation RRRotation; 274 RRRotation.RRConfig.rotation = rotation; 275 RRRotation.RRConfig.rate = rate; 276 RRRotation.RRConfig.width = pSize->width; 277 RRRotation.RRConfig.height = pSize->height; 278 279 /* 280 * Currently we need to rely on HW support for rotation. 281 */ 282 if (!(*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation)) 283 return FALSE; 284 } else 285 return FALSE; 286 287 randrp->rotation = rotation; 288 } 289 290 if (!xf86RandRSetMode (pScreen, mode, useVirtual, pSize->mmWidth, pSize->mmHeight)) { 291 if(randrp->rotation != oldRotation) { 292 /* Have the driver undo its thing. */ 293 if (scrp->DriverFunc) { 294 xorgRRRotation RRRotation; 295 RRRotation.RRConfig.rotation = oldRotation; 296 RRRotation.RRConfig.rate = xf86RandRModeRefresh (scrp->currentMode); 297 RRRotation.RRConfig.width = scrp->virtualX; 298 RRRotation.RRConfig.height = scrp->virtualY; 299 (*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation); 300 } 301 302 randrp->rotation = oldRotation; 303 } 304 return FALSE; 305 } 306 /* 307 * Move the cursor back where it belongs; SwitchMode repositions it 308 */ 309 if (pScreen == miPointerCurrentScreen ()) 310 { 311 px = (px >= pScreen->width ? (pScreen->width - 1) : px); 312 py = (py >= pScreen->height ? (pScreen->height - 1) : py); 313 314 xf86SetViewport(pScreen, px, py); 315 316 (*pScreen->SetCursorPosition) (inputInfo.pointer, pScreen, px, py, FALSE); 317 } 318 319 return TRUE; 320} 321 322/* 323 * Wait until the screen is initialized before whacking the 324 * sizes around; otherwise the screen pixmap will be allocated 325 * at the current mode size rather than the maximum size 326 */ 327static Bool 328xf86RandRCreateScreenResources (ScreenPtr pScreen) 329{ 330 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 331#if 0 332 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 333 DisplayModePtr mode; 334#endif 335 336 pScreen->CreateScreenResources = randrp->CreateScreenResources; 337 if (!(*pScreen->CreateScreenResources) (pScreen)) 338 return FALSE; 339 340#if 0 341 mode = scrp->currentMode; 342 if (mode) 343 xf86RandRSetMode (pScreen, mode, TRUE); 344#endif 345 346 return TRUE; 347} 348 349/* 350 * Reset size back to original 351 */ 352static Bool 353xf86RandRCloseScreen (int index, ScreenPtr pScreen) 354{ 355 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 356 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 357 358 scrp->virtualX = pScreen->width = randrp->virtualX; 359 scrp->virtualY = pScreen->height = randrp->virtualY; 360 scrp->currentMode = scrp->modes; 361 pScreen->CloseScreen = randrp->CloseScreen; 362 free(randrp); 363 dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, NULL); 364 return (*pScreen->CloseScreen) (index, pScreen); 365} 366 367Rotation 368xf86GetRotation(ScreenPtr pScreen) 369{ 370 if (xf86RandRKey == NULL) 371 return RR_Rotate_0; 372 373 return XF86RANDRINFO(pScreen)->rotation; 374} 375 376/* Function to change RandR's idea of the virtual screen size */ 377Bool 378xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen, 379 int newvirtX, int newvirtY, int newmmWidth, int newmmHeight, 380 Bool resetMode) 381{ 382 XF86RandRInfoPtr randrp; 383 384 if (xf86RandRKey == NULL) 385 return FALSE; 386 387 randrp = XF86RANDRINFO(pScreen); 388 if (randrp == NULL) 389 return FALSE; 390 391 if (newvirtX > 0) 392 randrp->virtualX = newvirtX; 393 394 if (newvirtY > 0) 395 randrp->virtualY = newvirtY; 396 397 if (newmmWidth > 0) 398 randrp->mmWidth = newmmWidth; 399 400 if (newmmHeight > 0) 401 randrp->mmHeight = newmmHeight; 402 403 /* This is only for during server start */ 404 if (resetMode) { 405 return (xf86RandRSetMode(pScreen, 406 XF86SCRNINFO(pScreen)->currentMode, 407 TRUE, 408 pScreen->mmWidth, pScreen->mmHeight)); 409 } 410 411 return TRUE; 412} 413 414Bool 415xf86RandRInit (ScreenPtr pScreen) 416{ 417 rrScrPrivPtr rp; 418 XF86RandRInfoPtr randrp; 419 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 420 421#ifdef PANORAMIX 422 /* XXX disable RandR when using Xinerama */ 423 if (!noPanoramiXExtension) 424 return TRUE; 425#endif 426 427 xf86RandRKey = &xf86RandRKeyRec; 428 429 if (!dixRegisterPrivateKey(&xf86RandRKeyRec, PRIVATE_SCREEN, 0)) 430 return FALSE; 431 432 randrp = malloc(sizeof (XF86RandRInfoRec)); 433 if (!randrp) 434 return FALSE; 435 436 if (!RRScreenInit (pScreen)) 437 { 438 free(randrp); 439 return FALSE; 440 } 441 rp = rrGetScrPriv(pScreen); 442 rp->rrGetInfo = xf86RandRGetInfo; 443 rp->rrSetConfig = xf86RandRSetConfig; 444 445 randrp->virtualX = scrp->virtualX; 446 randrp->virtualY = scrp->virtualY; 447 randrp->mmWidth = pScreen->mmWidth; 448 randrp->mmHeight = pScreen->mmHeight; 449 450 randrp->CreateScreenResources = pScreen->CreateScreenResources; 451 pScreen->CreateScreenResources = xf86RandRCreateScreenResources; 452 453 randrp->CloseScreen = pScreen->CloseScreen; 454 pScreen->CloseScreen = xf86RandRCloseScreen; 455 456 randrp->rotation = RR_Rotate_0; 457 458 dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, randrp); 459 return TRUE; 460} 461 462 463