| 1 | /* |
| 2 | * Copyright (c) 1994-2003 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 | |
| 28 | #ifdef HAVE_XORG_CONFIG_H |
| 29 | #include <xorg-config.h> |
| 30 | #endif |
| 31 | |
| 32 | #include <X11/X.h> |
| 33 | #include <X11/Xmd.h> |
| 34 | #include "input.h" |
| 35 | #include "cursor.h" |
| 36 | #include "mipointer.h" |
| 37 | #include "scrnintstr.h" |
| 38 | #include "globals.h" |
| 39 | |
| 40 | #include "compiler.h" |
| 41 | |
| 42 | #include "xf86.h" |
| 43 | #include "xf86Priv.h" |
| 44 | #include "xf86_OSproc.h" |
| 45 | |
| 46 | #include <X11/extensions/XIproto.h> |
| 47 | #include "xf86Xinput.h" |
| 48 | |
| 49 | #ifdef XFreeXDGA |
| 50 | #include "dgaproc.h" |
| 51 | #endif |
| 52 | |
| 53 | typedef struct _xf86EdgeRec { |
| 54 | short screen; |
| 55 | short start; |
| 56 | short end; |
| 57 | DDXPointRec offset; |
| 58 | struct _xf86EdgeRec *next; |
| 59 | } xf86EdgeRec, *xf86EdgePtr; |
| 60 | |
| 61 | typedef struct { |
| 62 | xf86EdgePtr left, right, up, down; |
| 63 | } xf86ScreenLayoutRec, *xf86ScreenLayoutPtr; |
| 64 | |
| 65 | static Bool xf86CursorOffScreen(ScreenPtr *pScreen, int *x, int *y); |
| 66 | static void xf86CrossScreen(ScreenPtr pScreen, Bool entering); |
| 67 | static void xf86WarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); |
| 68 | |
| 69 | static void xf86PointerMoved(ScrnInfoPtr pScrn, int x, int y); |
| 70 | |
| 71 | static miPointerScreenFuncRec xf86PointerScreenFuncs = { |
| 72 | xf86CursorOffScreen, |
| 73 | xf86CrossScreen, |
| 74 | xf86WarpCursor, |
| 75 | }; |
| 76 | |
| 77 | static xf86ScreenLayoutRec xf86ScreenLayout[MAXSCREENS]; |
| 78 | |
| 79 | static Bool HardEdges; |
| 80 | |
| 81 | /* |
| 82 | * xf86InitViewport -- |
| 83 | * Initialize paning & zooming parameters, so that a driver must only |
| 84 | * check what resolutions are possible and whether the virtual area |
| 85 | * is valid if specified. |
| 86 | */ |
| 87 | |
| 88 | void |
| 89 | xf86InitViewport(ScrnInfoPtr pScr) |
| 90 | { |
| 91 | |
| 92 | pScr->PointerMoved = xf86PointerMoved; |
| 93 | |
| 94 | /* |
| 95 | * Compute the initial Viewport if necessary |
| 96 | */ |
| 97 | if (pScr->display) { |
| 98 | if (pScr->display->frameX0 < 0) { |
| 99 | pScr->frameX0 = (pScr->virtualX - pScr->modes->HDisplay) / 2; |
| 100 | pScr->frameY0 = (pScr->virtualY - pScr->modes->VDisplay) / 2; |
| 101 | } |
| 102 | else { |
| 103 | pScr->frameX0 = pScr->display->frameX0; |
| 104 | pScr->frameY0 = pScr->display->frameY0; |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | pScr->frameX1 = pScr->frameX0 + pScr->modes->HDisplay - 1; |
| 109 | pScr->frameY1 = pScr->frameY0 + pScr->modes->VDisplay - 1; |
| 110 | |
| 111 | /* |
| 112 | * Now adjust the initial Viewport, so it lies within the virtual area |
| 113 | */ |
| 114 | if (pScr->frameX1 >= pScr->virtualX) { |
| 115 | pScr->frameX0 = pScr->virtualX - pScr->modes->HDisplay; |
| 116 | pScr->frameX1 = pScr->frameX0 + pScr->modes->HDisplay - 1; |
| 117 | } |
| 118 | |
| 119 | if (pScr->frameY1 >= pScr->virtualY) { |
| 120 | pScr->frameY0 = pScr->virtualY - pScr->modes->VDisplay; |
| 121 | pScr->frameY1 = pScr->frameY0 + pScr->modes->VDisplay - 1; |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | /* |
| 126 | * xf86SetViewport -- |
| 127 | * Scroll the visual part of the screen so the pointer is visible. |
| 128 | */ |
| 129 | |
| 130 | void |
| 131 | xf86SetViewport(ScreenPtr pScreen, int x, int y) |
| 132 | { |
| 133 | ScrnInfoPtr pScr = xf86ScreenToScrn(pScreen); |
| 134 | |
| 135 | (*pScr->PointerMoved) (pScr, x, y); |
| 136 | } |
| 137 | |
| 138 | static void |
| 139 | xf86PointerMoved(ScrnInfoPtr pScr, int x, int y) |
| 140 | { |
| 141 | Bool frameChanged = FALSE; |
| 142 | |
| 143 | /* |
| 144 | * check wether (x,y) belongs to the visual part of the screen |
| 145 | * if not, change the base of the displayed frame accoring |
| 146 | */ |
| 147 | if (pScr->frameX0 > x) { |
| 148 | pScr->frameX0 = x; |
| 149 | pScr->frameX1 = x + pScr->currentMode->HDisplay - 1; |
| 150 | frameChanged = TRUE; |
| 151 | } |
| 152 | |
| 153 | if (pScr->frameX1 < x) { |
| 154 | pScr->frameX1 = x + 1; |
| 155 | pScr->frameX0 = x - pScr->currentMode->HDisplay + 1; |
| 156 | frameChanged = TRUE; |
| 157 | } |
| 158 | |
| 159 | if (pScr->frameY0 > y) { |
| 160 | pScr->frameY0 = y; |
| 161 | pScr->frameY1 = y + pScr->currentMode->VDisplay - 1; |
| 162 | frameChanged = TRUE; |
| 163 | } |
| 164 | |
| 165 | if (pScr->frameY1 < y) { |
| 166 | pScr->frameY1 = y; |
| 167 | pScr->frameY0 = y - pScr->currentMode->VDisplay + 1; |
| 168 | frameChanged = TRUE; |
| 169 | } |
| 170 | |
| 171 | if (frameChanged && pScr->AdjustFrame != NULL) |
| 172 | pScr->AdjustFrame(pScr, pScr->frameX0, pScr->frameY0); |
| 173 | } |
| 174 | |
| 175 | /* |
| 176 | * xf86LockZoom -- |
| 177 | * Enable/disable ZoomViewport |
| 178 | */ |
| 179 | |
| 180 | void |
| 181 | xf86LockZoom(ScreenPtr pScreen, Bool lock) |
| 182 | { |
| 183 | ScrnInfoPtr pScr = xf86ScreenToScrn(pScreen); |
| 184 | pScr->zoomLocked = lock; |
| 185 | } |
| 186 | |
| 187 | /* |
| 188 | * xf86SwitchMode -- |
| 189 | * This is called by both keyboard processing and the VidMode extension to |
| 190 | * set a new mode. |
| 191 | */ |
| 192 | |
| 193 | Bool |
| 194 | xf86SwitchMode(ScreenPtr pScreen, DisplayModePtr mode) |
| 195 | { |
| 196 | ScrnInfoPtr pScr = xf86ScreenToScrn(pScreen); |
| 197 | ScreenPtr pCursorScreen; |
| 198 | Bool Switched; |
| 199 | int px, py; |
| 200 | DeviceIntPtr dev, it; |
| 201 | |
| 202 | if (!pScr->vtSema || !mode || !pScr->SwitchMode) |
| 203 | return FALSE; |
| 204 | |
| 205 | #ifdef XFreeXDGA |
| 206 | if (DGAActive(pScr->scrnIndex)) |
| 207 | return FALSE; |
| 208 | #endif |
| 209 | |
| 210 | if (mode == pScr->currentMode) |
| 211 | return TRUE; |
| 212 | |
| 213 | if (mode->HDisplay > pScr->virtualX || mode->VDisplay > pScr->virtualY) |
| 214 | return FALSE; |
| 215 | |
| 216 | /* Let's take an educated guess for which pointer to take here. And about as |
| 217 | educated as it gets is to take the first pointer we find. |
| 218 | */ |
| 219 | for (dev = inputInfo.devices; dev; dev = dev->next) { |
| 220 | if (IsPointerDevice(dev) && dev->spriteInfo->spriteOwner) |
| 221 | break; |
| 222 | } |
| 223 | |
| 224 | pCursorScreen = miPointerGetScreen(dev); |
| 225 | if (pScreen == pCursorScreen) |
| 226 | miPointerGetPosition(dev, &px, &py); |
| 227 | |
| 228 | OsBlockSIGIO(); |
| 229 | Switched = (*pScr->SwitchMode) (pScr, mode); |
| 230 | if (Switched) { |
| 231 | pScr->currentMode = mode; |
| 232 | |
| 233 | /* |
| 234 | * Adjust frame for new display size. |
| 235 | * Frame is centered around cursor position if cursor is on same screen. |
| 236 | */ |
| 237 | if (pScreen == pCursorScreen) |
| 238 | pScr->frameX0 = px - (mode->HDisplay / 2) + 1; |
| 239 | else |
| 240 | pScr->frameX0 = |
| 241 | (pScr->frameX0 + pScr->frameX1 + 1 - mode->HDisplay) / 2; |
| 242 | |
| 243 | if (pScr->frameX0 < 0) |
| 244 | pScr->frameX0 = 0; |
| 245 | |
| 246 | pScr->frameX1 = pScr->frameX0 + mode->HDisplay - 1; |
| 247 | if (pScr->frameX1 >= pScr->virtualX) { |
| 248 | pScr->frameX0 = pScr->virtualX - mode->HDisplay; |
| 249 | pScr->frameX1 = pScr->virtualX - 1; |
| 250 | } |
| 251 | |
| 252 | if (pScreen == pCursorScreen) |
| 253 | pScr->frameY0 = py - (mode->VDisplay / 2) + 1; |
| 254 | else |
| 255 | pScr->frameY0 = |
| 256 | (pScr->frameY0 + pScr->frameY1 + 1 - mode->VDisplay) / 2; |
| 257 | |
| 258 | if (pScr->frameY0 < 0) |
| 259 | pScr->frameY0 = 0; |
| 260 | |
| 261 | pScr->frameY1 = pScr->frameY0 + mode->VDisplay - 1; |
| 262 | if (pScr->frameY1 >= pScr->virtualY) { |
| 263 | pScr->frameY0 = pScr->virtualY - mode->VDisplay; |
| 264 | pScr->frameY1 = pScr->virtualY - 1; |
| 265 | } |
| 266 | } |
| 267 | OsReleaseSIGIO(); |
| 268 | |
| 269 | if (pScr->AdjustFrame) |
| 270 | (*pScr->AdjustFrame) (pScr, pScr->frameX0, pScr->frameY0); |
| 271 | |
| 272 | /* The original code centered the frame around the cursor if possible. |
| 273 | * Since this is hard to achieve with multiple cursors, we do the following: |
| 274 | * - center around the first pointer |
| 275 | * - move all other pointers to the nearest edge on the screen (or leave |
| 276 | * them unmodified if they are within the boundaries). |
| 277 | */ |
| 278 | if (pScreen == pCursorScreen) { |
| 279 | xf86WarpCursor(dev, pScreen, px, py); |
| 280 | } |
| 281 | |
| 282 | for (it = inputInfo.devices; it; it = it->next) { |
| 283 | if (it == dev) |
| 284 | continue; |
| 285 | |
| 286 | if (IsPointerDevice(it) && it->spriteInfo->spriteOwner) { |
| 287 | pCursorScreen = miPointerGetScreen(it); |
| 288 | if (pScreen == pCursorScreen) { |
| 289 | miPointerGetPosition(it, &px, &py); |
| 290 | if (px < pScr->frameX0) |
| 291 | px = pScr->frameX0; |
| 292 | else if (px > pScr->frameX1) |
| 293 | px = pScr->frameX1; |
| 294 | |
| 295 | if (py < pScr->frameY0) |
| 296 | py = pScr->frameY0; |
| 297 | else if (py > pScr->frameY1) |
| 298 | py = pScr->frameY1; |
| 299 | |
| 300 | xf86WarpCursor(it, pScreen, px, py); |
| 301 | } |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | return Switched; |
| 306 | } |
| 307 | |
| 308 | /* |
| 309 | * xf86ZoomViewport -- |
| 310 | * Reinitialize the visual part of the screen for another mode. |
| 311 | */ |
| 312 | |
| 313 | void |
| 314 | xf86ZoomViewport(ScreenPtr pScreen, int zoom) |
| 315 | { |
| 316 | ScrnInfoPtr pScr = xf86ScreenToScrn(pScreen); |
| 317 | DisplayModePtr mode; |
| 318 | |
| 319 | if (pScr->zoomLocked || !(mode = pScr->currentMode)) |
| 320 | return; |
| 321 | |
| 322 | do { |
| 323 | if (zoom > 0) |
| 324 | mode = mode->next; |
| 325 | else |
| 326 | mode = mode->prev; |
| 327 | } while (mode != pScr->currentMode && !(mode->type & M_T_USERDEF)); |
| 328 | |
| 329 | (void) xf86SwitchMode(pScreen, mode); |
| 330 | } |
| 331 | |
| 332 | static xf86EdgePtr |
| 333 | FindEdge(xf86EdgePtr edge, int val) |
| 334 | { |
| 335 | while (edge && (edge->end <= val)) |
| 336 | edge = edge->next; |
| 337 | |
| 338 | if (edge && (edge->start <= val)) |
| 339 | return edge; |
| 340 | |
| 341 | return NULL; |
| 342 | } |
| 343 | |
| 344 | /* |
| 345 | * xf86CursorOffScreen -- |
| 346 | * Check whether it is necessary to switch to another screen |
| 347 | */ |
| 348 | |
| 349 | static Bool |
| 350 | xf86CursorOffScreen(ScreenPtr *pScreen, int *x, int *y) |
| 351 | { |
| 352 | xf86EdgePtr edge; |
| 353 | int tmp; |
| 354 | |
| 355 | if (screenInfo.numScreens == 1) |
| 356 | return FALSE; |
| 357 | |
| 358 | if (*x < 0) { |
| 359 | tmp = *y; |
| 360 | if (tmp < 0) |
| 361 | tmp = 0; |
| 362 | if (tmp >= (*pScreen)->height) |
| 363 | tmp = (*pScreen)->height - 1; |
| 364 | |
| 365 | if ((edge = xf86ScreenLayout[(*pScreen)->myNum].left)) |
| 366 | edge = FindEdge(edge, tmp); |
| 367 | |
| 368 | if (!edge) |
| 369 | *x = 0; |
| 370 | else { |
| 371 | *x += edge->offset.x; |
| 372 | *y += edge->offset.y; |
| 373 | *pScreen = xf86Screens[edge->screen]->pScreen; |
| 374 | } |
| 375 | } |
| 376 | |
| 377 | if (*x >= (*pScreen)->width) { |
| 378 | tmp = *y; |
| 379 | if (tmp < 0) |
| 380 | tmp = 0; |
| 381 | if (tmp >= (*pScreen)->height) |
| 382 | tmp = (*pScreen)->height - 1; |
| 383 | |
| 384 | if ((edge = xf86ScreenLayout[(*pScreen)->myNum].right)) |
| 385 | edge = FindEdge(edge, tmp); |
| 386 | |
| 387 | if (!edge) |
| 388 | *x = (*pScreen)->width - 1; |
| 389 | else { |
| 390 | *x += edge->offset.x; |
| 391 | *y += edge->offset.y; |
| 392 | *pScreen = xf86Screens[edge->screen]->pScreen; |
| 393 | } |
| 394 | } |
| 395 | |
| 396 | if (*y < 0) { |
| 397 | tmp = *x; |
| 398 | if (tmp < 0) |
| 399 | tmp = 0; |
| 400 | if (tmp >= (*pScreen)->width) |
| 401 | tmp = (*pScreen)->width - 1; |
| 402 | |
| 403 | if ((edge = xf86ScreenLayout[(*pScreen)->myNum].up)) |
| 404 | edge = FindEdge(edge, tmp); |
| 405 | |
| 406 | if (!edge) |
| 407 | *y = 0; |
| 408 | else { |
| 409 | *x += edge->offset.x; |
| 410 | *y += edge->offset.y; |
| 411 | *pScreen = xf86Screens[edge->screen]->pScreen; |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | if (*y >= (*pScreen)->height) { |
| 416 | tmp = *x; |
| 417 | if (tmp < 0) |
| 418 | tmp = 0; |
| 419 | if (tmp >= (*pScreen)->width) |
| 420 | tmp = (*pScreen)->width - 1; |
| 421 | |
| 422 | if ((edge = xf86ScreenLayout[(*pScreen)->myNum].down)) |
| 423 | edge = FindEdge(edge, tmp); |
| 424 | |
| 425 | if (!edge) |
| 426 | *y = (*pScreen)->height - 1; |
| 427 | else { |
| 428 | *x += edge->offset.x; |
| 429 | *y += edge->offset.y; |
| 430 | (*pScreen) = xf86Screens[edge->screen]->pScreen; |
| 431 | } |
| 432 | } |
| 433 | |
| 434 | #if 0 |
| 435 | /* This presents problems for overlapping screens when |
| 436 | HardEdges is used. Have to think about the logic more */ |
| 437 | if ((*x < 0) || (*x >= (*pScreen)->width) || |
| 438 | (*y < 0) || (*y >= (*pScreen)->height)) { |
| 439 | /* We may have crossed more than one screen */ |
| 440 | xf86CursorOffScreen(pScreen, x, y); |
| 441 | } |
| 442 | #endif |
| 443 | |
| 444 | return TRUE; |
| 445 | } |
| 446 | |
| 447 | /* |
| 448 | * xf86CrossScreen -- |
| 449 | * Switch to another screen |
| 450 | * |
| 451 | * Currently nothing special happens, but mi assumes the CrossScreen |
| 452 | * method exists. |
| 453 | */ |
| 454 | |
| 455 | static void |
| 456 | xf86CrossScreen(ScreenPtr pScreen, Bool entering) |
| 457 | { |
| 458 | } |
| 459 | |
| 460 | /* |
| 461 | * xf86WarpCursor -- |
| 462 | * Warp possible to another screen |
| 463 | */ |
| 464 | |
| 465 | /* ARGSUSED */ |
| 466 | static void |
| 467 | xf86WarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) |
| 468 | { |
| 469 | OsBlockSIGIO(); |
| 470 | miPointerWarpCursor(pDev, pScreen, x, y); |
| 471 | |
| 472 | xf86Info.currentScreen = pScreen; |
| 473 | OsReleaseSIGIO(); |
| 474 | } |
| 475 | |
| 476 | void * |
| 477 | xf86GetPointerScreenFuncs(void) |
| 478 | { |
| 479 | return (void *) &xf86PointerScreenFuncs; |
| 480 | } |
| 481 | |
| 482 | static xf86EdgePtr |
| 483 | AddEdge(xf86EdgePtr edge, |
| 484 | short min, short max, short dx, short dy, short screen) |
| 485 | { |
| 486 | xf86EdgePtr pEdge = edge, pPrev = NULL, pNew; |
| 487 | |
| 488 | while (1) { |
| 489 | while (pEdge && (min >= pEdge->end)) { |
| 490 | pPrev = pEdge; |
| 491 | pEdge = pEdge->next; |
| 492 | } |
| 493 | |
| 494 | if (!pEdge) { |
| 495 | if (!(pNew = malloc(sizeof(xf86EdgeRec)))) |
| 496 | break; |
| 497 | |
| 498 | pNew->screen = screen; |
| 499 | pNew->start = min; |
| 500 | pNew->end = max; |
| 501 | pNew->offset.x = dx; |
| 502 | pNew->offset.y = dy; |
| 503 | pNew->next = NULL; |
| 504 | |
| 505 | if (pPrev) |
| 506 | pPrev->next = pNew; |
| 507 | else |
| 508 | edge = pNew; |
| 509 | |
| 510 | break; |
| 511 | } |
| 512 | else if (min < pEdge->start) { |
| 513 | if (!(pNew = malloc(sizeof(xf86EdgeRec)))) |
| 514 | break; |
| 515 | |
| 516 | pNew->screen = screen; |
| 517 | pNew->start = min; |
| 518 | pNew->offset.x = dx; |
| 519 | pNew->offset.y = dy; |
| 520 | pNew->next = pEdge; |
| 521 | |
| 522 | if (pPrev) |
| 523 | pPrev->next = pNew; |
| 524 | else |
| 525 | edge = pNew; |
| 526 | |
| 527 | if (max <= pEdge->start) { |
| 528 | pNew->end = max; |
| 529 | break; |
| 530 | } |
| 531 | else { |
| 532 | pNew->end = pEdge->start; |
| 533 | min = pEdge->end; |
| 534 | } |
| 535 | } |
| 536 | else |
| 537 | min = pEdge->end; |
| 538 | |
| 539 | pPrev = pEdge; |
| 540 | pEdge = pEdge->next; |
| 541 | |
| 542 | if (max <= min) |
| 543 | break; |
| 544 | } |
| 545 | |
| 546 | return edge; |
| 547 | } |
| 548 | |
| 549 | static void |
| 550 | FillOutEdge(xf86EdgePtr pEdge, int limit) |
| 551 | { |
| 552 | xf86EdgePtr pNext; |
| 553 | int diff; |
| 554 | |
| 555 | if (pEdge->start > 0) |
| 556 | pEdge->start = 0; |
| 557 | |
| 558 | while ((pNext = pEdge->next)) { |
| 559 | diff = pNext->start - pEdge->end; |
| 560 | if (diff > 0) { |
| 561 | pEdge->end += diff >> 1; |
| 562 | pNext->start -= diff - (diff >> 1); |
| 563 | } |
| 564 | pEdge = pNext; |
| 565 | } |
| 566 | |
| 567 | if (pEdge->end < limit) |
| 568 | pEdge->end = limit; |
| 569 | } |
| 570 | |
| 571 | /* |
| 572 | * xf86InitOrigins() can deal with a maximum of 32 screens |
| 573 | * on 32 bit architectures, 64 on 64 bit architectures. |
| 574 | */ |
| 575 | |
| 576 | void |
| 577 | xf86InitOrigins(void) |
| 578 | { |
| 579 | unsigned long screensLeft, prevScreensLeft, mask; |
| 580 | screenLayoutPtr screen; |
| 581 | ScreenPtr pScreen, refScreen; |
| 582 | int x1, x2, y1, y2, left, right, top, bottom; |
| 583 | int i, j, ref, minX, minY, min, max; |
| 584 | xf86ScreenLayoutPtr pLayout; |
| 585 | Bool OldStyleConfig = FALSE; |
| 586 | |
| 587 | /* need to have this set up with a config file option */ |
| 588 | HardEdges = FALSE; |
| 589 | |
| 590 | memset(xf86ScreenLayout, 0, MAXSCREENS * sizeof(xf86ScreenLayoutRec)); |
| 591 | |
| 592 | screensLeft = prevScreensLeft = (1 << xf86NumScreens) - 1; |
| 593 | |
| 594 | while (1) { |
| 595 | for (mask = screensLeft, i = 0; mask; mask >>= 1, i++) { |
| 596 | if (!(mask & 1L)) |
| 597 | continue; |
| 598 | |
| 599 | screen = &xf86ConfigLayout.screens[i]; |
| 600 | |
| 601 | if (screen->refscreen != NULL && |
| 602 | screen->refscreen->screennum >= xf86NumScreens) { |
| 603 | screensLeft &= ~(1 << i); |
| 604 | xf86Msg(X_WARNING, |
| 605 | "Not including screen \"%s\" in origins calculation.\n", |
| 606 | screen->screen->id); |
| 607 | continue; |
| 608 | } |
| 609 | |
| 610 | pScreen = xf86Screens[i]->pScreen; |
| 611 | switch (screen->where) { |
| 612 | case PosObsolete: |
| 613 | OldStyleConfig = TRUE; |
| 614 | pLayout = &xf86ScreenLayout[i]; |
| 615 | /* force edge lists */ |
| 616 | if (screen->left) { |
| 617 | ref = screen->left->screennum; |
| 618 | if (!xf86Screens[ref] || !xf86Screens[ref]->pScreen) { |
| 619 | ErrorF("Referenced uninitialized screen in Layout!\n"); |
| 620 | break; |
| 621 | } |
| 622 | pLayout->left = AddEdge(pLayout->left, |
| 623 | 0, pScreen->height, |
| 624 | xf86Screens[ref]->pScreen->width, 0, |
| 625 | ref); |
| 626 | } |
| 627 | if (screen->right) { |
| 628 | ref = screen->right->screennum; |
| 629 | if (!xf86Screens[ref] || !xf86Screens[ref]->pScreen) { |
| 630 | ErrorF("Referenced uninitialized screen in Layout!\n"); |
| 631 | break; |
| 632 | } |
| 633 | pLayout->right = AddEdge(pLayout->right, |
| 634 | 0, pScreen->height, |
| 635 | -pScreen->width, 0, ref); |
| 636 | } |
| 637 | if (screen->top) { |
| 638 | ref = screen->top->screennum; |
| 639 | if (!xf86Screens[ref] || !xf86Screens[ref]->pScreen) { |
| 640 | ErrorF("Referenced uninitialized screen in Layout!\n"); |
| 641 | break; |
| 642 | } |
| 643 | pLayout->up = AddEdge(pLayout->up, |
| 644 | 0, pScreen->width, |
| 645 | 0, xf86Screens[ref]->pScreen->height, |
| 646 | ref); |
| 647 | } |
| 648 | if (screen->bottom) { |
| 649 | ref = screen->bottom->screennum; |
| 650 | if (!xf86Screens[ref] || !xf86Screens[ref]->pScreen) { |
| 651 | ErrorF("Referenced uninitialized screen in Layout!\n"); |
| 652 | break; |
| 653 | } |
| 654 | pLayout->down = AddEdge(pLayout->down, |
| 655 | 0, pScreen->width, 0, |
| 656 | -pScreen->height, ref); |
| 657 | } |
| 658 | /* we could also try to place it based on those |
| 659 | relative locations if we wanted to */ |
| 660 | screen->x = screen->y = 0; |
| 661 | /* FALLTHROUGH */ |
| 662 | case PosAbsolute: |
| 663 | pScreen->x = screen->x; |
| 664 | pScreen->y = screen->y; |
| 665 | screensLeft &= ~(1 << i); |
| 666 | break; |
| 667 | case PosRelative: |
| 668 | ref = screen->refscreen->screennum; |
| 669 | if (!xf86Screens[ref] || !xf86Screens[ref]->pScreen) { |
| 670 | ErrorF("Referenced uninitialized screen in Layout!\n"); |
| 671 | break; |
| 672 | } |
| 673 | if (screensLeft & (1 << ref)) |
| 674 | break; |
| 675 | refScreen = xf86Screens[ref]->pScreen; |
| 676 | pScreen->x = refScreen->x + screen->x; |
| 677 | pScreen->y = refScreen->y + screen->y; |
| 678 | screensLeft &= ~(1 << i); |
| 679 | break; |
| 680 | case PosRightOf: |
| 681 | ref = screen->refscreen->screennum; |
| 682 | if (!xf86Screens[ref] || !xf86Screens[ref]->pScreen) { |
| 683 | ErrorF("Referenced uninitialized screen in Layout!\n"); |
| 684 | break; |
| 685 | } |
| 686 | if (screensLeft & (1 << ref)) |
| 687 | break; |
| 688 | refScreen = xf86Screens[ref]->pScreen; |
| 689 | pScreen->x = refScreen->x + refScreen->width; |
| 690 | pScreen->y = refScreen->y; |
| 691 | screensLeft &= ~(1 << i); |
| 692 | break; |
| 693 | case PosLeftOf: |
| 694 | ref = screen->refscreen->screennum; |
| 695 | if (!xf86Screens[ref] || !xf86Screens[ref]->pScreen) { |
| 696 | ErrorF("Referenced uninitialized screen in Layout!\n"); |
| 697 | break; |
| 698 | } |
| 699 | if (screensLeft & (1 << ref)) |
| 700 | break; |
| 701 | refScreen = xf86Screens[ref]->pScreen; |
| 702 | pScreen->x = refScreen->x - pScreen->width; |
| 703 | pScreen->y = refScreen->y; |
| 704 | screensLeft &= ~(1 << i); |
| 705 | break; |
| 706 | case PosBelow: |
| 707 | ref = screen->refscreen->screennum; |
| 708 | if (!xf86Screens[ref] || !xf86Screens[ref]->pScreen) { |
| 709 | ErrorF("Referenced uninitialized screen in Layout!\n"); |
| 710 | break; |
| 711 | } |
| 712 | if (screensLeft & (1 << ref)) |
| 713 | break; |
| 714 | refScreen = xf86Screens[ref]->pScreen; |
| 715 | pScreen->x = refScreen->x; |
| 716 | pScreen->y = refScreen->y + refScreen->height; |
| 717 | screensLeft &= ~(1 << i); |
| 718 | break; |
| 719 | case PosAbove: |
| 720 | ref = screen->refscreen->screennum; |
| 721 | if (!xf86Screens[ref] || !xf86Screens[ref]->pScreen) { |
| 722 | ErrorF("Referenced uninitialized screen in Layout!\n"); |
| 723 | break; |
| 724 | } |
| 725 | if (screensLeft & (1 << ref)) |
| 726 | break; |
| 727 | refScreen = xf86Screens[ref]->pScreen; |
| 728 | pScreen->x = refScreen->x; |
| 729 | pScreen->y = refScreen->y - pScreen->height; |
| 730 | screensLeft &= ~(1 << i); |
| 731 | break; |
| 732 | default: |
| 733 | ErrorF("Illegal placement keyword in Layout!\n"); |
| 734 | break; |
| 735 | } |
| 736 | |
| 737 | } |
| 738 | |
| 739 | if (!screensLeft) |
| 740 | break; |
| 741 | |
| 742 | if (screensLeft == prevScreensLeft) { |
| 743 | /* All the remaining screens are referencing each other. |
| 744 | Assign a value to one of them and go through again */ |
| 745 | i = 0; |
| 746 | while (!((1 << i) & screensLeft)) { |
| 747 | i++; |
| 748 | } |
| 749 | |
| 750 | ref = xf86ConfigLayout.screens[i].refscreen->screennum; |
| 751 | xf86Screens[ref]->pScreen->x = xf86Screens[ref]->pScreen->y = 0; |
| 752 | screensLeft &= ~(1 << ref); |
| 753 | } |
| 754 | |
| 755 | prevScreensLeft = screensLeft; |
| 756 | } |
| 757 | |
| 758 | /* justify the topmost and leftmost to (0,0) */ |
| 759 | minX = xf86Screens[0]->pScreen->x; |
| 760 | minY = xf86Screens[0]->pScreen->y; |
| 761 | |
| 762 | for (i = 1; i < xf86NumScreens; i++) { |
| 763 | if (xf86Screens[i]->pScreen->x < minX) |
| 764 | minX = xf86Screens[i]->pScreen->x; |
| 765 | if (xf86Screens[i]->pScreen->y < minY) |
| 766 | minY = xf86Screens[i]->pScreen->y; |
| 767 | } |
| 768 | |
| 769 | if (minX || minY) { |
| 770 | for (i = 0; i < xf86NumScreens; i++) { |
| 771 | xf86Screens[i]->pScreen->x -= minX; |
| 772 | xf86Screens[i]->pScreen->y -= minY; |
| 773 | } |
| 774 | } |
| 775 | |
| 776 | /* Create the edge lists */ |
| 777 | |
| 778 | if (!OldStyleConfig) { |
| 779 | for (i = 0; i < xf86NumScreens; i++) { |
| 780 | pLayout = &xf86ScreenLayout[i]; |
| 781 | |
| 782 | pScreen = xf86Screens[i]->pScreen; |
| 783 | |
| 784 | left = pScreen->x; |
| 785 | right = left + pScreen->width; |
| 786 | top = pScreen->y; |
| 787 | bottom = top + pScreen->height; |
| 788 | |
| 789 | for (j = 0; j < xf86NumScreens; j++) { |
| 790 | if (i == j) |
| 791 | continue; |
| 792 | |
| 793 | refScreen = xf86Screens[j]->pScreen; |
| 794 | |
| 795 | x1 = refScreen->x; |
| 796 | x2 = x1 + refScreen->width; |
| 797 | y1 = refScreen->y; |
| 798 | y2 = y1 + refScreen->height; |
| 799 | |
| 800 | if ((bottom > y1) && (top < y2)) { |
| 801 | min = y1 - top; |
| 802 | if (min < 0) |
| 803 | min = 0; |
| 804 | max = pScreen->height - (bottom - y2); |
| 805 | if (max > pScreen->height) |
| 806 | max = pScreen->height; |
| 807 | |
| 808 | if (((left - 1) >= x1) && ((left - 1) < x2)) |
| 809 | pLayout->left = AddEdge(pLayout->left, min, max, |
| 810 | pScreen->x - refScreen->x, |
| 811 | pScreen->y - refScreen->y, j); |
| 812 | |
| 813 | if ((right >= x1) && (right < x2)) |
| 814 | pLayout->right = AddEdge(pLayout->right, min, max, |
| 815 | pScreen->x - refScreen->x, |
| 816 | pScreen->y - refScreen->y, j); |
| 817 | } |
| 818 | |
| 819 | if ((left < x2) && (right > x1)) { |
| 820 | min = x1 - left; |
| 821 | if (min < 0) |
| 822 | min = 0; |
| 823 | max = pScreen->width - (right - x2); |
| 824 | if (max > pScreen->width) |
| 825 | max = pScreen->width; |
| 826 | |
| 827 | if (((top - 1) >= y1) && ((top - 1) < y2)) |
| 828 | pLayout->up = AddEdge(pLayout->up, min, max, |
| 829 | pScreen->x - refScreen->x, |
| 830 | pScreen->y - refScreen->y, j); |
| 831 | |
| 832 | if ((bottom >= y1) && (bottom < y2)) |
| 833 | pLayout->down = AddEdge(pLayout->down, min, max, |
| 834 | pScreen->x - refScreen->x, |
| 835 | pScreen->y - refScreen->y, j); |
| 836 | } |
| 837 | } |
| 838 | } |
| 839 | } |
| 840 | |
| 841 | if (!HardEdges && !OldStyleConfig) { |
| 842 | for (i = 0; i < xf86NumScreens; i++) { |
| 843 | pLayout = &xf86ScreenLayout[i]; |
| 844 | pScreen = xf86Screens[i]->pScreen; |
| 845 | if (pLayout->left) |
| 846 | FillOutEdge(pLayout->left, pScreen->height); |
| 847 | if (pLayout->right) |
| 848 | FillOutEdge(pLayout->right, pScreen->height); |
| 849 | if (pLayout->up) |
| 850 | FillOutEdge(pLayout->up, pScreen->width); |
| 851 | if (pLayout->down) |
| 852 | FillOutEdge(pLayout->down, pScreen->width); |
| 853 | } |
| 854 | } |
| 855 | |
| 856 | update_desktop_dimensions(); |
| 857 | } |
| 858 | |
| 859 | void |
| 860 | xf86ReconfigureLayout(void) |
| 861 | { |
| 862 | int i; |
| 863 | |
| 864 | for (i = 0; i < MAXSCREENS; i++) { |
| 865 | xf86ScreenLayoutPtr sl = &xf86ScreenLayout[i]; |
| 866 | |
| 867 | /* we don't have to zero these, xf86InitOrigins() takes care of that */ |
| 868 | free(sl->left); |
| 869 | free(sl->right); |
| 870 | free(sl->up); |
| 871 | free(sl->down); |
| 872 | } |
| 873 | |
| 874 | xf86InitOrigins(); |
| 875 | } |