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