Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | } |