1706f2543Smrg/*
2706f2543Smrg * Copyright (c) 1994-2003 by The XFree86 Project, Inc.
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Software"),
6706f2543Smrg * to deal in the Software without restriction, including without limitation
7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, subject to the following conditions:
10706f2543Smrg *
11706f2543Smrg * The above copyright notice and this permission notice shall be included in
12706f2543Smrg * all copies or substantial portions of the Software.
13706f2543Smrg *
14706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17706f2543Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20706f2543Smrg * OTHER DEALINGS IN THE SOFTWARE.
21706f2543Smrg *
22706f2543Smrg * Except as contained in this notice, the name of the copyright holder(s)
23706f2543Smrg * and author(s) shall not be used in advertising or otherwise to promote
24706f2543Smrg * the sale, use or other dealings in this Software without prior written
25706f2543Smrg * authorization from the copyright holder(s) and author(s).
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
29706f2543Smrg#include <xorg-config.h>
30706f2543Smrg#endif
31706f2543Smrg
32706f2543Smrg#include <X11/X.h>
33706f2543Smrg#include <X11/Xmd.h>
34706f2543Smrg#include "input.h"
35706f2543Smrg#include "cursor.h"
36706f2543Smrg#include "mipointer.h"
37706f2543Smrg#include "scrnintstr.h"
38706f2543Smrg#include "globals.h"
39706f2543Smrg
40706f2543Smrg#include "compiler.h"
41706f2543Smrg
42706f2543Smrg#include "xf86.h"
43706f2543Smrg#include "xf86Priv.h"
44706f2543Smrg#include "xf86_OSproc.h"
45706f2543Smrg
46706f2543Smrg#include <X11/extensions/XIproto.h>
47706f2543Smrg#include "xf86Xinput.h"
48706f2543Smrg
49706f2543Smrg#ifdef XFreeXDGA
50706f2543Smrg#include "dgaproc.h"
51706f2543Smrg#endif
52706f2543Smrg
53706f2543Smrgtypedef struct _xf86EdgeRec {
54706f2543Smrg   short screen;
55706f2543Smrg   short start;
56706f2543Smrg   short end;
57706f2543Smrg   DDXPointRec offset;
58706f2543Smrg   struct _xf86EdgeRec *next;
59706f2543Smrg} xf86EdgeRec, *xf86EdgePtr;
60706f2543Smrg
61706f2543Smrgtypedef struct {
62706f2543Smrg    xf86EdgePtr	left, right, up, down;
63706f2543Smrg} xf86ScreenLayoutRec, *xf86ScreenLayoutPtr;
64706f2543Smrg
65706f2543Smrgstatic Bool xf86CursorOffScreen(ScreenPtr *pScreen, int *x, int *y);
66706f2543Smrgstatic void xf86CrossScreen(ScreenPtr pScreen, Bool entering);
67706f2543Smrgstatic void xf86WarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y);
68706f2543Smrg
69706f2543Smrgstatic void xf86PointerMoved(int scrnIndex, int x, int y);
70706f2543Smrg
71706f2543Smrgstatic miPointerScreenFuncRec xf86PointerScreenFuncs = {
72706f2543Smrg  xf86CursorOffScreen,
73706f2543Smrg  xf86CrossScreen,
74706f2543Smrg  xf86WarpCursor,
75706f2543Smrg  /* let miPointerInitialize take care of these */
76706f2543Smrg  NULL,
77706f2543Smrg  NULL
78706f2543Smrg};
79706f2543Smrg
80706f2543Smrgstatic xf86ScreenLayoutRec xf86ScreenLayout[MAXSCREENS];
81706f2543Smrg
82706f2543Smrgstatic Bool HardEdges;
83706f2543Smrg
84706f2543Smrg/*
85706f2543Smrg * xf86InitViewport --
86706f2543Smrg *      Initialize paning & zooming parameters, so that a driver must only
87706f2543Smrg *      check what resolutions are possible and whether the virtual area
88706f2543Smrg *      is valid if specified.
89706f2543Smrg */
90706f2543Smrg
91706f2543Smrgvoid
92706f2543Smrgxf86InitViewport(ScrnInfoPtr pScr)
93706f2543Smrg{
94706f2543Smrg
95706f2543Smrg  pScr->PointerMoved = xf86PointerMoved;
96706f2543Smrg
97706f2543Smrg  /*
98706f2543Smrg   * Compute the initial Viewport if necessary
99706f2543Smrg   */
100706f2543Smrg  if (pScr->display) {
101706f2543Smrg    if (pScr->display->frameX0 < 0) {
102706f2543Smrg      pScr->frameX0 = (pScr->virtualX - pScr->modes->HDisplay) / 2;
103706f2543Smrg      pScr->frameY0 = (pScr->virtualY - pScr->modes->VDisplay) / 2;
104706f2543Smrg    } else {
105706f2543Smrg      pScr->frameX0 = pScr->display->frameX0;
106706f2543Smrg      pScr->frameY0 = pScr->display->frameY0;
107706f2543Smrg    }
108706f2543Smrg  }
109706f2543Smrg
110706f2543Smrg  pScr->frameX1 = pScr->frameX0 + pScr->modes->HDisplay - 1;
111706f2543Smrg  pScr->frameY1 = pScr->frameY0 + pScr->modes->VDisplay - 1;
112706f2543Smrg
113706f2543Smrg  /*
114706f2543Smrg   * Now adjust the initial Viewport, so it lies within the virtual area
115706f2543Smrg   */
116706f2543Smrg  if (pScr->frameX1 >= pScr->virtualX)
117706f2543Smrg    {
118706f2543Smrg	pScr->frameX0 = pScr->virtualX - pScr->modes->HDisplay;
119706f2543Smrg	pScr->frameX1 = pScr->frameX0 + pScr->modes->HDisplay - 1;
120706f2543Smrg    }
121706f2543Smrg
122706f2543Smrg  if (pScr->frameY1 >= pScr->virtualY)
123706f2543Smrg    {
124706f2543Smrg	pScr->frameY0 = pScr->virtualY - pScr->modes->VDisplay;
125706f2543Smrg	pScr->frameY1 = pScr->frameY0 + pScr->modes->VDisplay - 1;
126706f2543Smrg    }
127706f2543Smrg}
128706f2543Smrg
129706f2543Smrg
130706f2543Smrg/*
131706f2543Smrg * xf86SetViewport --
132706f2543Smrg *      Scroll the visual part of the screen so the pointer is visible.
133706f2543Smrg */
134706f2543Smrg
135706f2543Smrgvoid
136706f2543Smrgxf86SetViewport(ScreenPtr pScreen, int x, int y)
137706f2543Smrg{
138706f2543Smrg  ScrnInfoPtr   pScr = XF86SCRNINFO(pScreen);
139706f2543Smrg
140706f2543Smrg  (*pScr->PointerMoved)(pScreen->myNum, x, y);
141706f2543Smrg}
142706f2543Smrg
143706f2543Smrg
144706f2543Smrgstatic void
145706f2543Smrgxf86PointerMoved(int scrnIndex, int x, int y)
146706f2543Smrg{
147706f2543Smrg  Bool          frameChanged = FALSE;
148706f2543Smrg  ScrnInfoPtr   pScr = xf86Screens[scrnIndex];
149706f2543Smrg
150706f2543Smrg  /*
151706f2543Smrg   * check wether (x,y) belongs to the visual part of the screen
152706f2543Smrg   * if not, change the base of the displayed frame accoring
153706f2543Smrg   */
154706f2543Smrg  if ( pScr->frameX0 > x) {
155706f2543Smrg    pScr->frameX0 = x;
156706f2543Smrg    pScr->frameX1 = x + pScr->currentMode->HDisplay - 1;
157706f2543Smrg    frameChanged = TRUE ;
158706f2543Smrg  }
159706f2543Smrg
160706f2543Smrg  if ( pScr->frameX1 < x) {
161706f2543Smrg    pScr->frameX1 = x + 1;
162706f2543Smrg    pScr->frameX0 = x - pScr->currentMode->HDisplay + 1;
163706f2543Smrg    frameChanged = TRUE ;
164706f2543Smrg  }
165706f2543Smrg
166706f2543Smrg  if ( pScr->frameY0 > y) {
167706f2543Smrg    pScr->frameY0 = y;
168706f2543Smrg    pScr->frameY1 = y + pScr->currentMode->VDisplay - 1;
169706f2543Smrg    frameChanged = TRUE;
170706f2543Smrg  }
171706f2543Smrg
172706f2543Smrg  if ( pScr->frameY1 < y) {
173706f2543Smrg    pScr->frameY1 = y;
174706f2543Smrg    pScr->frameY0 = y - pScr->currentMode->VDisplay + 1;
175706f2543Smrg    frameChanged = TRUE;
176706f2543Smrg  }
177706f2543Smrg
178706f2543Smrg  if (frameChanged && pScr->AdjustFrame != NULL)
179706f2543Smrg    pScr->AdjustFrame(pScr->scrnIndex, pScr->frameX0, pScr->frameY0, 0);
180706f2543Smrg}
181706f2543Smrg
182706f2543Smrg/*
183706f2543Smrg * xf86LockZoom --
184706f2543Smrg *	Enable/disable ZoomViewport
185706f2543Smrg */
186706f2543Smrg
187706f2543Smrgvoid
188706f2543Smrgxf86LockZoom(ScreenPtr pScreen, Bool lock)
189706f2543Smrg{
190706f2543Smrg  XF86SCRNINFO(pScreen)->zoomLocked = lock;
191706f2543Smrg}
192706f2543Smrg
193706f2543Smrg/*
194706f2543Smrg * xf86SwitchMode --
195706f2543Smrg *	This is called by both keyboard processing and the VidMode extension to
196706f2543Smrg *	set a new mode.
197706f2543Smrg */
198706f2543Smrg
199706f2543SmrgBool
200706f2543Smrgxf86SwitchMode(ScreenPtr pScreen, DisplayModePtr mode)
201706f2543Smrg{
202706f2543Smrg  ScrnInfoPtr pScr = XF86SCRNINFO(pScreen);
203706f2543Smrg  ScreenPtr   pCursorScreen;
204706f2543Smrg  Bool        Switched;
205706f2543Smrg  int         px, py, was_blocked;
206706f2543Smrg  DeviceIntPtr dev, it;
207706f2543Smrg
208706f2543Smrg  if (!pScr->vtSema || !mode || !pScr->SwitchMode)
209706f2543Smrg    return FALSE;
210706f2543Smrg
211706f2543Smrg#ifdef XFreeXDGA
212706f2543Smrg  if (DGAActive(pScr->scrnIndex))
213706f2543Smrg    return FALSE;
214706f2543Smrg#endif
215706f2543Smrg
216706f2543Smrg  if (mode == pScr->currentMode)
217706f2543Smrg    return TRUE;
218706f2543Smrg
219706f2543Smrg  if (mode->HDisplay > pScr->virtualX || mode->VDisplay > pScr->virtualY)
220706f2543Smrg    return FALSE;
221706f2543Smrg
222706f2543Smrg  /* Let's take an educated guess for which pointer to take here. And about as
223706f2543Smrg     educated as it gets is to take the first pointer we find.
224706f2543Smrg   */
225706f2543Smrg  for (dev = inputInfo.devices; dev; dev = dev->next)
226706f2543Smrg  {
227706f2543Smrg      if (IsPointerDevice(dev) && dev->spriteInfo->spriteOwner)
228706f2543Smrg          break;
229706f2543Smrg  }
230706f2543Smrg
231706f2543Smrg  pCursorScreen = miPointerGetScreen(dev);
232706f2543Smrg  if (pScreen == pCursorScreen)
233706f2543Smrg    miPointerGetPosition(dev, &px, &py);
234706f2543Smrg
235706f2543Smrg  was_blocked = xf86BlockSIGIO();
236706f2543Smrg  Switched = (*pScr->SwitchMode)(pScr->scrnIndex, mode, 0);
237706f2543Smrg  if (Switched) {
238706f2543Smrg    pScr->currentMode = mode;
239706f2543Smrg
240706f2543Smrg    /*
241706f2543Smrg     * Adjust frame for new display size.
242706f2543Smrg     * Frame is centered around cursor position if cursor is on same screen.
243706f2543Smrg     */
244706f2543Smrg    if (pScreen == pCursorScreen)
245706f2543Smrg      pScr->frameX0 = px - (mode->HDisplay / 2) + 1;
246706f2543Smrg    else
247706f2543Smrg      pScr->frameX0 = (pScr->frameX0 + pScr->frameX1 + 1 - mode->HDisplay) / 2;
248706f2543Smrg
249706f2543Smrg    if (pScr->frameX0 < 0)
250706f2543Smrg      pScr->frameX0 = 0;
251706f2543Smrg
252706f2543Smrg    pScr->frameX1 = pScr->frameX0 + mode->HDisplay - 1;
253706f2543Smrg    if (pScr->frameX1 >= pScr->virtualX) {
254706f2543Smrg      pScr->frameX0 = pScr->virtualX - mode->HDisplay;
255706f2543Smrg      pScr->frameX1 = pScr->virtualX - 1;
256706f2543Smrg    }
257706f2543Smrg
258706f2543Smrg    if (pScreen == pCursorScreen)
259706f2543Smrg      pScr->frameY0 = py - (mode->VDisplay / 2) + 1;
260706f2543Smrg    else
261706f2543Smrg      pScr->frameY0 = (pScr->frameY0 + pScr->frameY1 + 1 - mode->VDisplay) / 2;
262706f2543Smrg
263706f2543Smrg    if (pScr->frameY0 < 0)
264706f2543Smrg      pScr->frameY0 = 0;
265706f2543Smrg
266706f2543Smrg    pScr->frameY1 = pScr->frameY0 + mode->VDisplay - 1;
267706f2543Smrg    if (pScr->frameY1 >= pScr->virtualY) {
268706f2543Smrg      pScr->frameY0 = pScr->virtualY - mode->VDisplay;
269706f2543Smrg      pScr->frameY1 = pScr->virtualY - 1;
270706f2543Smrg    }
271706f2543Smrg  }
272706f2543Smrg  xf86UnblockSIGIO(was_blocked);
273706f2543Smrg
274706f2543Smrg  if (pScr->AdjustFrame)
275706f2543Smrg    (*pScr->AdjustFrame)(pScr->scrnIndex, pScr->frameX0, pScr->frameY0, 0);
276706f2543Smrg
277706f2543Smrg  /* The original code centered the frame around the cursor if possible.
278706f2543Smrg   * Since this is hard to achieve with multiple cursors, we do the following:
279706f2543Smrg   *   - center around the first pointer
280706f2543Smrg   *   - move all other pointers to the nearest edge on the screen (or leave
281706f2543Smrg   *   them unmodified if they are within the boundaries).
282706f2543Smrg   */
283706f2543Smrg  if (pScreen == pCursorScreen)
284706f2543Smrg  {
285706f2543Smrg      xf86WarpCursor(dev, pScreen, px, py);
286706f2543Smrg  }
287706f2543Smrg
288706f2543Smrg  for (it = inputInfo.devices; it; it = it->next)
289706f2543Smrg  {
290706f2543Smrg      if (it == dev)
291706f2543Smrg          continue;
292706f2543Smrg
293706f2543Smrg      if (IsPointerDevice(it) && it->spriteInfo->spriteOwner)
294706f2543Smrg      {
295706f2543Smrg          pCursorScreen = miPointerGetScreen(it);
296706f2543Smrg          if (pScreen == pCursorScreen)
297706f2543Smrg          {
298706f2543Smrg              miPointerGetPosition(it, &px, &py);
299706f2543Smrg              if (px < pScr->frameX0)
300706f2543Smrg                  px = pScr->frameX0;
301706f2543Smrg              else if (px > pScr->frameX1)
302706f2543Smrg                  px = pScr->frameX1;
303706f2543Smrg
304706f2543Smrg              if(py < pScr->frameY0)
305706f2543Smrg                  py = pScr->frameY0;
306706f2543Smrg              else if(py > pScr->frameY1)
307706f2543Smrg                  py = pScr->frameY1;
308706f2543Smrg
309706f2543Smrg              xf86WarpCursor(it, pScreen, px, py);
310706f2543Smrg          }
311706f2543Smrg      }
312706f2543Smrg  }
313706f2543Smrg
314706f2543Smrg  return Switched;
315706f2543Smrg}
316706f2543Smrg
317706f2543Smrg/*
318706f2543Smrg * xf86ZoomViewport --
319706f2543Smrg *      Reinitialize the visual part of the screen for another mode.
320706f2543Smrg */
321706f2543Smrg
322706f2543Smrgvoid
323706f2543Smrgxf86ZoomViewport(ScreenPtr pScreen, int zoom)
324706f2543Smrg{
325706f2543Smrg  ScrnInfoPtr    pScr = XF86SCRNINFO(pScreen);
326706f2543Smrg  DisplayModePtr mode;
327706f2543Smrg
328706f2543Smrg  if (pScr->zoomLocked || !(mode = pScr->currentMode))
329706f2543Smrg    return;
330706f2543Smrg
331706f2543Smrg  do {
332706f2543Smrg    if (zoom > 0)
333706f2543Smrg      mode = mode->next;
334706f2543Smrg    else
335706f2543Smrg      mode = mode->prev;
336706f2543Smrg  } while (mode != pScr->currentMode && !(mode->type & M_T_USERDEF));
337706f2543Smrg
338706f2543Smrg  (void)xf86SwitchMode(pScreen, mode);
339706f2543Smrg}
340706f2543Smrg
341706f2543Smrg
342706f2543Smrgstatic xf86EdgePtr
343706f2543SmrgFindEdge(xf86EdgePtr edge, int val)
344706f2543Smrg{
345706f2543Smrg    while(edge && (edge->end <= val))
346706f2543Smrg	edge = edge->next;
347706f2543Smrg
348706f2543Smrg    if(edge && (edge->start <= val))
349706f2543Smrg	return edge;
350706f2543Smrg
351706f2543Smrg    return NULL;
352706f2543Smrg}
353706f2543Smrg
354706f2543Smrg/*
355706f2543Smrg * xf86CursorOffScreen --
356706f2543Smrg *      Check whether it is necessary to switch to another screen
357706f2543Smrg */
358706f2543Smrg
359706f2543Smrgstatic Bool
360706f2543Smrgxf86CursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
361706f2543Smrg{
362706f2543Smrg    xf86EdgePtr edge;
363706f2543Smrg    int tmp;
364706f2543Smrg
365706f2543Smrg    if(screenInfo.numScreens == 1)
366706f2543Smrg	return FALSE;
367706f2543Smrg
368706f2543Smrg    if(*x < 0) {
369706f2543Smrg        tmp = *y;
370706f2543Smrg	if(tmp < 0) tmp = 0;
371706f2543Smrg	if(tmp >= (*pScreen)->height) tmp = (*pScreen)->height - 1;
372706f2543Smrg
373706f2543Smrg	if((edge = xf86ScreenLayout[(*pScreen)->myNum].left))
374706f2543Smrg	   edge = FindEdge(edge, tmp);
375706f2543Smrg
376706f2543Smrg	if(!edge) *x = 0;
377706f2543Smrg	else {
378706f2543Smrg	    *x += edge->offset.x;
379706f2543Smrg	    *y += edge->offset.y;
380706f2543Smrg	    *pScreen = xf86Screens[edge->screen]->pScreen;
381706f2543Smrg	}
382706f2543Smrg    }
383706f2543Smrg
384706f2543Smrg    if(*x >= (*pScreen)->width) {
385706f2543Smrg        tmp = *y;
386706f2543Smrg	if(tmp < 0) tmp = 0;
387706f2543Smrg	if(tmp >= (*pScreen)->height) tmp = (*pScreen)->height - 1;
388706f2543Smrg
389706f2543Smrg	if((edge = xf86ScreenLayout[(*pScreen)->myNum].right))
390706f2543Smrg	   edge = FindEdge(edge, tmp);
391706f2543Smrg
392706f2543Smrg	if(!edge) *x = (*pScreen)->width - 1;
393706f2543Smrg	else {
394706f2543Smrg	    *x += edge->offset.x;
395706f2543Smrg	    *y += edge->offset.y;
396706f2543Smrg	    *pScreen = xf86Screens[edge->screen]->pScreen;
397706f2543Smrg	}
398706f2543Smrg    }
399706f2543Smrg
400706f2543Smrg    if(*y < 0) {
401706f2543Smrg        tmp = *x;
402706f2543Smrg	if(tmp < 0) tmp = 0;
403706f2543Smrg	if(tmp >= (*pScreen)->width) tmp = (*pScreen)->width - 1;
404706f2543Smrg
405706f2543Smrg	if((edge = xf86ScreenLayout[(*pScreen)->myNum].up))
406706f2543Smrg	   edge = FindEdge(edge, tmp);
407706f2543Smrg
408706f2543Smrg	if(!edge) *y = 0;
409706f2543Smrg	else {
410706f2543Smrg	    *x += edge->offset.x;
411706f2543Smrg	    *y += edge->offset.y;
412706f2543Smrg	    *pScreen = xf86Screens[edge->screen]->pScreen;
413706f2543Smrg	}
414706f2543Smrg    }
415706f2543Smrg
416706f2543Smrg    if(*y >= (*pScreen)->height) {
417706f2543Smrg        tmp = *x;
418706f2543Smrg	if(tmp < 0) tmp = 0;
419706f2543Smrg	if(tmp >= (*pScreen)->width) tmp = (*pScreen)->width - 1;
420706f2543Smrg
421706f2543Smrg	if((edge = xf86ScreenLayout[(*pScreen)->myNum].down))
422706f2543Smrg	   edge = FindEdge(edge, tmp);
423706f2543Smrg
424706f2543Smrg	if(!edge) *y = (*pScreen)->height - 1;
425706f2543Smrg	else {
426706f2543Smrg	    *x += edge->offset.x;
427706f2543Smrg	    *y += edge->offset.y;
428706f2543Smrg	    (*pScreen) = xf86Screens[edge->screen]->pScreen;
429706f2543Smrg	}
430706f2543Smrg    }
431706f2543Smrg
432706f2543Smrg
433706f2543Smrg#if 0
434706f2543Smrg    /* This presents problems for overlapping screens when
435706f2543Smrg 	HardEdges is used.  Have to think about the logic more */
436706f2543Smrg    if((*x < 0) || (*x >= (*pScreen)->width) ||
437706f2543Smrg       (*y < 0) || (*y >= (*pScreen)->height)) {
438706f2543Smrg	/* We may have crossed more than one screen */
439706f2543Smrg	xf86CursorOffScreen(pScreen, x, y);
440706f2543Smrg    }
441706f2543Smrg#endif
442706f2543Smrg
443706f2543Smrg    return TRUE;
444706f2543Smrg}
445706f2543Smrg
446706f2543Smrg
447706f2543Smrg
448706f2543Smrg/*
449706f2543Smrg * xf86CrossScreen --
450706f2543Smrg *      Switch to another screen
451706f2543Smrg *
452706f2543Smrg *	Currently nothing special happens, but mi assumes the CrossScreen
453706f2543Smrg *	method exists.
454706f2543Smrg */
455706f2543Smrg
456706f2543Smrgstatic void
457706f2543Smrgxf86CrossScreen (ScreenPtr pScreen, Bool entering)
458706f2543Smrg{
459706f2543Smrg}
460706f2543Smrg
461706f2543Smrg
462706f2543Smrg/*
463706f2543Smrg * xf86WarpCursor --
464706f2543Smrg *      Warp possible to another screen
465706f2543Smrg */
466706f2543Smrg
467706f2543Smrg/* ARGSUSED */
468706f2543Smrgstatic void
469706f2543Smrgxf86WarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
470706f2543Smrg{
471706f2543Smrg    int    sigstate;
472706f2543Smrg    sigstate = xf86BlockSIGIO ();
473706f2543Smrg    miPointerWarpCursor(pDev, pScreen, x, y);
474706f2543Smrg
475706f2543Smrg    xf86Info.currentScreen = pScreen;
476706f2543Smrg    xf86UnblockSIGIO (sigstate);
477706f2543Smrg}
478706f2543Smrg
479706f2543Smrg
480706f2543Smrgvoid *
481706f2543Smrgxf86GetPointerScreenFuncs(void)
482706f2543Smrg{
483706f2543Smrg    return (void *)&xf86PointerScreenFuncs;
484706f2543Smrg}
485706f2543Smrg
486706f2543Smrg
487706f2543Smrgstatic xf86EdgePtr
488706f2543SmrgAddEdge(
489706f2543Smrg   xf86EdgePtr edge,
490706f2543Smrg   short min,
491706f2543Smrg   short max,
492706f2543Smrg   short dx,
493706f2543Smrg   short dy,
494706f2543Smrg   short screen
495706f2543Smrg){
496706f2543Smrg   xf86EdgePtr pEdge = edge, pPrev = NULL, pNew;
497706f2543Smrg
498706f2543Smrg   while(1) {
499706f2543Smrg	while(pEdge && (min >= pEdge->end)) {
500706f2543Smrg	    pPrev = pEdge;
501706f2543Smrg	    pEdge = pEdge->next;
502706f2543Smrg	}
503706f2543Smrg
504706f2543Smrg	if(!pEdge) {
505706f2543Smrg	    if(!(pNew = malloc(sizeof(xf86EdgeRec))))
506706f2543Smrg		break;
507706f2543Smrg
508706f2543Smrg	    pNew->screen = screen;
509706f2543Smrg	    pNew->start = min;
510706f2543Smrg	    pNew->end = max;
511706f2543Smrg	    pNew->offset.x = dx;
512706f2543Smrg	    pNew->offset.y = dy;
513706f2543Smrg	    pNew->next = NULL;
514706f2543Smrg
515706f2543Smrg	    if(pPrev)
516706f2543Smrg		pPrev->next = pNew;
517706f2543Smrg	    else
518706f2543Smrg		edge = pNew;
519706f2543Smrg
520706f2543Smrg	    break;
521706f2543Smrg	} else if (min < pEdge->start) {
522706f2543Smrg	    if(!(pNew = malloc(sizeof(xf86EdgeRec))))
523706f2543Smrg		break;
524706f2543Smrg
525706f2543Smrg	    pNew->screen = screen;
526706f2543Smrg	    pNew->start = min;
527706f2543Smrg	    pNew->offset.x = dx;
528706f2543Smrg	    pNew->offset.y = dy;
529706f2543Smrg	    pNew->next = pEdge;
530706f2543Smrg
531706f2543Smrg	    if(pPrev) pPrev->next = pNew;
532706f2543Smrg	    else edge = pNew;
533706f2543Smrg
534706f2543Smrg	    if(max <= pEdge->start) {
535706f2543Smrg		pNew->end = max;
536706f2543Smrg		break;
537706f2543Smrg	    } else {
538706f2543Smrg		pNew->end = pEdge->start;
539706f2543Smrg		min = pEdge->end;
540706f2543Smrg	    }
541706f2543Smrg	} else
542706f2543Smrg	    min = pEdge->end;
543706f2543Smrg
544706f2543Smrg	pPrev = pEdge;
545706f2543Smrg	pEdge = pEdge->next;
546706f2543Smrg
547706f2543Smrg	if(max <= min) break;
548706f2543Smrg   }
549706f2543Smrg
550706f2543Smrg   return edge;
551706f2543Smrg}
552706f2543Smrg
553706f2543Smrgstatic void
554706f2543SmrgFillOutEdge(xf86EdgePtr pEdge, int limit)
555706f2543Smrg{
556706f2543Smrg    xf86EdgePtr pNext;
557706f2543Smrg    int diff;
558706f2543Smrg
559706f2543Smrg    if(pEdge->start > 0) pEdge->start = 0;
560706f2543Smrg
561706f2543Smrg    while((pNext = pEdge->next)) {
562706f2543Smrg	diff = pNext->start - pEdge->end;
563706f2543Smrg	if(diff > 0) {
564706f2543Smrg	    pEdge->end += diff >> 1;
565706f2543Smrg	    pNext->start -= diff - (diff >> 1);
566706f2543Smrg	}
567706f2543Smrg	pEdge = pNext;
568706f2543Smrg    }
569706f2543Smrg
570706f2543Smrg    if(pEdge->end < limit)
571706f2543Smrg	pEdge->end = limit;
572706f2543Smrg}
573706f2543Smrg
574706f2543Smrg/*
575706f2543Smrg * xf86InitOrigins() can deal with a maximum of 32 screens
576706f2543Smrg * on 32 bit architectures, 64 on 64 bit architectures.
577706f2543Smrg */
578706f2543Smrg
579706f2543Smrgvoid
580706f2543Smrgxf86InitOrigins(void)
581706f2543Smrg{
582706f2543Smrg    unsigned long screensLeft, prevScreensLeft, mask;
583706f2543Smrg    screenLayoutPtr screen;
584706f2543Smrg    ScreenPtr pScreen, refScreen;
585706f2543Smrg    int x1, x2, y1, y2, left, right, top, bottom;
586706f2543Smrg    int i, j, ref, minX, minY, min, max;
587706f2543Smrg    xf86ScreenLayoutPtr pLayout;
588706f2543Smrg    Bool OldStyleConfig = FALSE;
589706f2543Smrg
590706f2543Smrg    /* need to have this set up with a config file option */
591706f2543Smrg    HardEdges = FALSE;
592706f2543Smrg
593706f2543Smrg    memset(xf86ScreenLayout, 0, MAXSCREENS * sizeof(xf86ScreenLayoutRec));
594706f2543Smrg
595706f2543Smrg    screensLeft = prevScreensLeft = (1 << xf86NumScreens) - 1;
596706f2543Smrg
597706f2543Smrg    while(1) {
598706f2543Smrg	for(mask = screensLeft, i = 0; mask; mask >>= 1, i++) {
599706f2543Smrg	    if(!(mask & 1L)) continue;
600706f2543Smrg
601706f2543Smrg	    screen = &xf86ConfigLayout.screens[i];
602706f2543Smrg
603706f2543Smrg	    if (screen->refscreen != NULL &&
604706f2543Smrg		screen->refscreen->screennum >= xf86NumScreens) {
605706f2543Smrg		screensLeft &= ~(1 << i);
606706f2543Smrg	        xf86Msg(X_WARNING, "Not including screen \"%s\" in origins calculation.\n",
607706f2543Smrg			screen->screen->id);
608706f2543Smrg	        continue;
609706f2543Smrg	    }
610706f2543Smrg
611706f2543Smrg	    pScreen = xf86Screens[i]->pScreen;
612706f2543Smrg	    switch(screen->where) {
613706f2543Smrg	    case PosObsolete:
614706f2543Smrg		OldStyleConfig = TRUE;
615706f2543Smrg		pLayout = &xf86ScreenLayout[i];
616706f2543Smrg		/* force edge lists */
617706f2543Smrg		if(screen->left) {
618706f2543Smrg		    ref = screen->left->screennum;
619706f2543Smrg		    if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) {
620706f2543Smrg			ErrorF("Referenced uninitialized screen in Layout!\n");
621706f2543Smrg			break;
622706f2543Smrg		    }
623706f2543Smrg		    pLayout->left = AddEdge(pLayout->left,
624706f2543Smrg			0, pScreen->height,
625706f2543Smrg			xf86Screens[ref]->pScreen->width, 0, ref);
626706f2543Smrg		}
627706f2543Smrg		if(screen->right) {
628706f2543Smrg		    ref = screen->right->screennum;
629706f2543Smrg		    if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) {
630706f2543Smrg			ErrorF("Referenced uninitialized screen in Layout!\n");
631706f2543Smrg			break;
632706f2543Smrg		    }
633706f2543Smrg		    pLayout->right = AddEdge(pLayout->right,
634706f2543Smrg			0, pScreen->height, -pScreen->width, 0, ref);
635706f2543Smrg		}
636706f2543Smrg		if(screen->top) {
637706f2543Smrg		    ref = screen->top->screennum;
638706f2543Smrg		    if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) {
639706f2543Smrg			ErrorF("Referenced uninitialized screen in Layout!\n");
640706f2543Smrg			break;
641706f2543Smrg		    }
642706f2543Smrg		    pLayout->up = AddEdge(pLayout->up,
643706f2543Smrg			0, pScreen->width,
644706f2543Smrg			0, xf86Screens[ref]->pScreen->height, ref);
645706f2543Smrg		}
646706f2543Smrg		if(screen->bottom) {
647706f2543Smrg		    ref = screen->bottom->screennum;
648706f2543Smrg		    if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) {
649706f2543Smrg			ErrorF("Referenced uninitialized screen in Layout!\n");
650706f2543Smrg			break;
651706f2543Smrg		    }
652706f2543Smrg		    pLayout->down = AddEdge(pLayout->down,
653706f2543Smrg			0, pScreen->width, 0, -pScreen->height, ref);
654706f2543Smrg		}
655706f2543Smrg	        /* we could also try to place it based on those
656706f2543Smrg		   relative locations if we wanted to */
657706f2543Smrg		screen->x = screen->y = 0;
658706f2543Smrg		/* FALLTHROUGH */
659706f2543Smrg	    case PosAbsolute:
660706f2543Smrg		pScreen->x = screen->x;
661706f2543Smrg		pScreen->y = screen->y;
662706f2543Smrg		screensLeft &= ~(1 << i);
663706f2543Smrg		break;
664706f2543Smrg	    case PosRelative:
665706f2543Smrg		ref = screen->refscreen->screennum;
666706f2543Smrg		if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) {
667706f2543Smrg		    ErrorF("Referenced uninitialized screen in Layout!\n");
668706f2543Smrg		    break;
669706f2543Smrg		}
670706f2543Smrg		if(screensLeft & (1 << ref)) break;
671706f2543Smrg		refScreen = xf86Screens[ref]->pScreen;
672706f2543Smrg		pScreen->x = refScreen->x + screen->x;
673706f2543Smrg		pScreen->y = refScreen->y + screen->y;
674706f2543Smrg		screensLeft &= ~(1 << i);
675706f2543Smrg		break;
676706f2543Smrg	    case PosRightOf:
677706f2543Smrg		ref = screen->refscreen->screennum;
678706f2543Smrg		if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) {
679706f2543Smrg		    ErrorF("Referenced uninitialized screen in Layout!\n");
680706f2543Smrg		    break;
681706f2543Smrg		}
682706f2543Smrg		if(screensLeft & (1 << ref)) break;
683706f2543Smrg		refScreen = xf86Screens[ref]->pScreen;
684706f2543Smrg		pScreen->x = refScreen->x + refScreen->width;
685706f2543Smrg		pScreen->y = refScreen->y;
686706f2543Smrg		screensLeft &= ~(1 << i);
687706f2543Smrg		break;
688706f2543Smrg	    case PosLeftOf:
689706f2543Smrg		ref = screen->refscreen->screennum;
690706f2543Smrg		if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) {
691706f2543Smrg		    ErrorF("Referenced uninitialized screen in Layout!\n");
692706f2543Smrg		    break;
693706f2543Smrg		}
694706f2543Smrg		if(screensLeft & (1 << ref)) break;
695706f2543Smrg		refScreen = xf86Screens[ref]->pScreen;
696706f2543Smrg		pScreen->x = refScreen->x - pScreen->width;
697706f2543Smrg		pScreen->y = refScreen->y;
698706f2543Smrg		screensLeft &= ~(1 << i);
699706f2543Smrg		break;
700706f2543Smrg	    case PosBelow:
701706f2543Smrg		ref = screen->refscreen->screennum;
702706f2543Smrg		if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) {
703706f2543Smrg		    ErrorF("Referenced uninitialized screen in Layout!\n");
704706f2543Smrg		    break;
705706f2543Smrg		}
706706f2543Smrg		if(screensLeft & (1 << ref)) break;
707706f2543Smrg		refScreen = xf86Screens[ref]->pScreen;
708706f2543Smrg		pScreen->x = refScreen->x;
709706f2543Smrg		pScreen->y = refScreen->y + refScreen->height;
710706f2543Smrg		screensLeft &= ~(1 << i);
711706f2543Smrg		break;
712706f2543Smrg	    case PosAbove:
713706f2543Smrg		ref = screen->refscreen->screennum;
714706f2543Smrg		if (! xf86Screens[ref] || ! xf86Screens[ref]->pScreen) {
715706f2543Smrg		    ErrorF("Referenced uninitialized screen in Layout!\n");
716706f2543Smrg		    break;
717706f2543Smrg		}
718706f2543Smrg		if(screensLeft & (1 << ref)) break;
719706f2543Smrg		refScreen = xf86Screens[ref]->pScreen;
720706f2543Smrg		pScreen->x = refScreen->x;
721706f2543Smrg		pScreen->y = refScreen->y - pScreen->height;
722706f2543Smrg		screensLeft &= ~(1 << i);
723706f2543Smrg		break;
724706f2543Smrg	    default:
725706f2543Smrg		ErrorF("Illegal placement keyword in Layout!\n");
726706f2543Smrg		break;
727706f2543Smrg	    }
728706f2543Smrg
729706f2543Smrg	}
730706f2543Smrg
731706f2543Smrg	if(!screensLeft) break;
732706f2543Smrg
733706f2543Smrg	if(screensLeft == prevScreensLeft) {
734706f2543Smrg	/* All the remaining screens are referencing each other.
735706f2543Smrg	   Assign a value to one of them and go through again */
736706f2543Smrg	    i = 0;
737706f2543Smrg	    while(!((1 << i) & screensLeft)){ i++; }
738706f2543Smrg
739706f2543Smrg	    ref = xf86ConfigLayout.screens[i].refscreen->screennum;
740706f2543Smrg	    xf86Screens[ref]->pScreen->x = xf86Screens[ref]->pScreen->y = 0;
741706f2543Smrg	    screensLeft &= ~(1 << ref);
742706f2543Smrg	}
743706f2543Smrg
744706f2543Smrg	prevScreensLeft = screensLeft;
745706f2543Smrg    }
746706f2543Smrg
747706f2543Smrg    /* justify the topmost and leftmost to (0,0) */
748706f2543Smrg    minX = xf86Screens[0]->pScreen->x;
749706f2543Smrg    minY = xf86Screens[0]->pScreen->y;
750706f2543Smrg
751706f2543Smrg    for(i = 1; i < xf86NumScreens; i++) {
752706f2543Smrg	if(xf86Screens[i]->pScreen->x < minX)
753706f2543Smrg	  minX = xf86Screens[i]->pScreen->x;
754706f2543Smrg	if(xf86Screens[i]->pScreen->y < minY)
755706f2543Smrg	  minY = xf86Screens[i]->pScreen->y;
756706f2543Smrg    }
757706f2543Smrg
758706f2543Smrg    if (minX || minY) {
759706f2543Smrg	for(i = 0; i < xf86NumScreens; i++) {
760706f2543Smrg	   xf86Screens[i]->pScreen->x -= minX;
761706f2543Smrg	   xf86Screens[i]->pScreen->y -= minY;
762706f2543Smrg	}
763706f2543Smrg    }
764706f2543Smrg
765706f2543Smrg
766706f2543Smrg    /* Create the edge lists */
767706f2543Smrg
768706f2543Smrg    if(!OldStyleConfig) {
769706f2543Smrg      for(i = 0; i < xf86NumScreens; i++) {
770706f2543Smrg	pLayout = &xf86ScreenLayout[i];
771706f2543Smrg
772706f2543Smrg	pScreen = xf86Screens[i]->pScreen;
773706f2543Smrg
774706f2543Smrg	left = pScreen->x;
775706f2543Smrg	right = left + pScreen->width;
776706f2543Smrg	top = pScreen->y;
777706f2543Smrg	bottom = top + pScreen->height;
778706f2543Smrg
779706f2543Smrg	for(j = 0; j < xf86NumScreens; j++) {
780706f2543Smrg	    if(i == j) continue;
781706f2543Smrg
782706f2543Smrg	    refScreen = xf86Screens[j]->pScreen;
783706f2543Smrg
784706f2543Smrg	    x1 = refScreen->x;
785706f2543Smrg	    x2 = x1 + refScreen->width;
786706f2543Smrg	    y1 = refScreen->y;
787706f2543Smrg	    y2 = y1 + refScreen->height;
788706f2543Smrg
789706f2543Smrg	    if((bottom > y1) && (top < y2)) {
790706f2543Smrg		min = y1 - top;
791706f2543Smrg		if(min < 0) min = 0;
792706f2543Smrg		max = pScreen->height - (bottom - y2);
793706f2543Smrg		if(max > pScreen->height) max = pScreen->height;
794706f2543Smrg
795706f2543Smrg		if(((left - 1) >= x1) && ((left - 1) < x2))
796706f2543Smrg		    pLayout->left = AddEdge(pLayout->left, min, max,
797706f2543Smrg			pScreen->x - refScreen->x,
798706f2543Smrg			pScreen->y - refScreen->y, j);
799706f2543Smrg
800706f2543Smrg		if((right >= x1) && (right < x2))
801706f2543Smrg		    pLayout->right = AddEdge(pLayout->right, min, max,
802706f2543Smrg			pScreen->x - refScreen->x,
803706f2543Smrg			pScreen->y - refScreen->y, j);
804706f2543Smrg	    }
805706f2543Smrg
806706f2543Smrg
807706f2543Smrg	    if((left < x2) && (right > x1)) {
808706f2543Smrg		min = x1 - left;
809706f2543Smrg		if(min < 0) min = 0;
810706f2543Smrg		max = pScreen->width - (right - x2);
811706f2543Smrg		if(max > pScreen->width) max = pScreen->width;
812706f2543Smrg
813706f2543Smrg		if(((top - 1) >= y1) && ((top - 1) < y2))
814706f2543Smrg		    pLayout->up = AddEdge(pLayout->up, min, max,
815706f2543Smrg			pScreen->x - refScreen->x,
816706f2543Smrg			pScreen->y - refScreen->y, j);
817706f2543Smrg
818706f2543Smrg		if((bottom >= y1) && (bottom < y2))
819706f2543Smrg		    pLayout->down = AddEdge(pLayout->down, min, max,
820706f2543Smrg			pScreen->x - refScreen->x,
821706f2543Smrg			pScreen->y - refScreen->y, j);
822706f2543Smrg	    }
823706f2543Smrg	}
824706f2543Smrg      }
825706f2543Smrg    }
826706f2543Smrg
827706f2543Smrg    if(!HardEdges && !OldStyleConfig) {
828706f2543Smrg	for(i = 0; i < xf86NumScreens; i++) {
829706f2543Smrg	    pLayout = &xf86ScreenLayout[i];
830706f2543Smrg	    pScreen = xf86Screens[i]->pScreen;
831706f2543Smrg	    if(pLayout->left)
832706f2543Smrg		FillOutEdge(pLayout->left, pScreen->height);
833706f2543Smrg	    if(pLayout->right)
834706f2543Smrg		FillOutEdge(pLayout->right, pScreen->height);
835706f2543Smrg	    if(pLayout->up)
836706f2543Smrg		FillOutEdge(pLayout->up, pScreen->width);
837706f2543Smrg	    if(pLayout->down)
838706f2543Smrg		FillOutEdge(pLayout->down, pScreen->width);
839706f2543Smrg	}
840706f2543Smrg    }
841706f2543Smrg}
842706f2543Smrg
843706f2543Smrgvoid
844706f2543Smrgxf86ReconfigureLayout(void)
845706f2543Smrg{
846706f2543Smrg    int i;
847706f2543Smrg
848706f2543Smrg    for (i = 0; i < MAXSCREENS; i++) {
849706f2543Smrg	xf86ScreenLayoutPtr sl = &xf86ScreenLayout[i];
850706f2543Smrg	/* we don't have to zero these, xf86InitOrigins() takes care of that */
851706f2543Smrg	free(sl->left);
852706f2543Smrg	free(sl->right);
853706f2543Smrg	free(sl->up);
854706f2543Smrg	free(sl->down);
855706f2543Smrg    }
856706f2543Smrg
857706f2543Smrg    xf86InitOrigins();
858706f2543Smrg}
859706f2543Smrg
860706f2543Smrg
861