sunMouse.c revision 177290df
1/* $Xorg: sunMouse.c,v 1.3 2000/08/17 19:48:32 cpqbld Exp $ */
2/*-
3 * Copyright 1987 by the Regents of the University of California
4 *
5 * Permission to use, copy, modify, and distribute this
6 * software and its documentation for any purpose and without
7 * fee is hereby granted, provided that the above copyright
8 * notice appear in all copies.  The University of California
9 * makes no representations about the suitability of this
10 * software for any purpose.  It is provided "as is" without
11 * express or implied warranty.
12 */
13
14/************************************************************
15Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA.
16
17                    All Rights Reserved
18
19Permission  to  use,  copy,  modify,  and  distribute   this
20software  and  its documentation for any purpose and without
21fee is hereby granted, provided that the above copyright no-
22tice  appear  in all copies and that both that copyright no-
23tice and this permission notice appear in  supporting  docu-
24mentation,  and  that the names of Sun or The Open Group
25not be used in advertising or publicity pertaining to
26distribution  of  the software  without specific prior
27written permission. Sun and The Open Group make no
28representations about the suitability of this software for
29any purpose. It is provided "as is" without any express or
30implied warranty.
31
32SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
33INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
34NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
35ABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
36ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
37PROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
38OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
39THE USE OR PERFORMANCE OF THIS SOFTWARE.
40
41********************************************************/
42/*
43 * Copyright 1991, 1992, 1993 Kaleb S. Keithley
44 *
45 * Permission to use, copy, modify, and distribute this
46 * software and its documentation for any purpose and without
47 * fee is hereby granted, provided that the above copyright
48 * notice appear in all copies.  Kaleb S. Keithley makes no
49 * representations about the suitability of this software for
50 * any purpose.  It is provided "as is" without express or
51 * implied warranty.
52 */
53/* $XFree86: xc/programs/Xserver/hw/sun/sunMouse.c,v 1.4 2003/11/17 22:20:36 dawes Exp $ */
54
55#define NEED_EVENTS
56#include    "sun.h"
57#include    "mi.h"
58#include    "cursor.h"
59#include    "input.h"
60#include    "inpututils.h"
61#include    "exevents.h"
62#include    "xserver-properties.h"
63
64Bool sunActiveZaphod = TRUE;
65DeviceIntPtr sunPointerDevice = NULL;
66
67static void sunMouseEvents(int, int, void *);
68static Firm_event *sunMouseGetEvents(int, Bool, int *, Bool *);
69static void sunMouseEnqueueEvent(DeviceIntPtr, Firm_event *);
70static Bool sunCursorOffScreen(ScreenPtr *, int *, int *);
71static void sunCrossScreen(ScreenPtr, int);
72static void sunWarpCursor(DeviceIntPtr, ScreenPtr, int, int);
73
74miPointerScreenFuncRec sunPointerScreenFuncs = {
75    sunCursorOffScreen,
76    sunCrossScreen,
77    sunWarpCursor,
78};
79
80static void
81sunMouseEvents(int fd, int ready, void *data)
82{
83    int i, numEvents = 0;
84    Bool again = FALSE;
85    Firm_event *events;
86    DeviceIntPtr device = (DeviceIntPtr)data;
87
88    input_lock();
89
90    do {
91	events = sunMouseGetEvents(fd, device->public.on, &numEvents, &again);
92	for (i = 0; i < numEvents; i++) {
93	    sunMouseEnqueueEvent(device, &events[i]);
94	}
95    } while (again);
96
97    input_unlock();
98}
99
100/*-
101 *-----------------------------------------------------------------------
102 * sunMouseCtrl --
103 *	Alter the control parameters for the mouse. Since acceleration
104 *	etc. is done from the PtrCtrl record in the mouse's device record,
105 *	there's nothing to do here.
106 *
107 * Results:
108 *	None.
109 *
110 * Side Effects:
111 *	None.
112 *
113 *-----------------------------------------------------------------------
114 */
115/*ARGSUSED*/
116static void
117sunMouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl)
118{
119}
120
121/*-
122 *-----------------------------------------------------------------------
123 * sunMouseProc --
124 *	Handle the initialization, etc. of a mouse
125 *
126 * Results:
127 *	none.
128 *
129 * Side Effects:
130 *
131 * Note:
132 *	When using sunwindows, all input comes off a single fd, stored in the
133 *	global windowFd.  Therefore, only one device should be enabled and
134 *	disabled, even though the application still sees both mouse and
135 *	keyboard.  We have arbitrarily chosen to enable and disable windowFd
136 *	in the keyboard routine sunKbdProc rather than in sunMouseProc.
137 *
138 *-----------------------------------------------------------------------
139 */
140int
141sunMouseProc(DeviceIntPtr device, int what)
142{
143    DevicePtr	  pMouse = &device->public;
144    int	    	  format;
145    static int	  oformat;
146    BYTE    	  map[4];
147    Atom btn_labels[3] = {0};
148    Atom axes_labels[2] = { 0, 0 };
149
150    switch (what) {
151	case DEVICE_INIT:
152	    if (pMouse != &sunPointerDevice->public) {
153		ErrorF ("Cannot open non-system mouse\n");
154		return !Success;
155	    }
156	    if (sunPtrPriv.fd == -1)
157		return !Success;
158	    pMouse->devicePrivate = (void *) &sunPtrPriv;
159	    pMouse->on = FALSE;
160	    map[1] = 1;
161	    map[2] = 2;
162	    map[3] = 3;
163	    btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
164	    btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
165	    btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
166	    axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
167	    axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
168
169	    InitPointerDeviceStruct(pMouse, map, 3, btn_labels,
170		sunMouseCtrl, GetMotionHistorySize(),
171		2, axes_labels);
172
173	    /* X valuator */
174	    InitValuatorAxisStruct(device, 0, axes_labels[0],
175		NO_AXIS_LIMITS, NO_AXIS_LIMITS, 1, 0, 1, Relative);
176            device->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
177            device->last.valuators[0] = device->valuator->axisVal[0];
178
179	    /* Y valuator */
180	    InitValuatorAxisStruct(device, 1, axes_labels[1],
181		NO_AXIS_LIMITS, NO_AXIS_LIMITS, 1, 0, 1, Relative);
182            device->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
183            device->last.valuators[1] = device->valuator->axisVal[1];
184
185	    break;
186
187	case DEVICE_ON:
188	    if (ioctl (sunPtrPriv.fd, VUIDGFORMAT, &oformat) == -1) {
189		ErrorF("sunMouseProc ioctl VUIDGFORMAT\n");
190		return !Success;
191	    }
192	    format = VUID_FIRM_EVENT;
193	    if (ioctl (sunPtrPriv.fd, VUIDSFORMAT, &format) == -1) {
194		ErrorF("sunMouseProc ioctl VUIDSFORMAT\n");
195		return !Success;
196	    }
197
198	    if (fcntl(sunPtrPriv.fd, F_SETFL, O_NONBLOCK) == -1) {
199		ErrorF("Non-blocking mouse I/O failed");
200		return !Success;
201	    }
202	    SetNotifyFd(sunPtrPriv.fd, sunMouseEvents, X_NOTIFY_READ, device);
203
204	    pPriv->bmask = 0;
205	    pMouse->on = TRUE;
206	    break;
207
208	case DEVICE_CLOSE:
209	    pMouse->on = FALSE;
210	    if (ioctl (sunPtrPriv.fd, VUIDSFORMAT, &oformat) == -1)
211		ErrorF("sunMouseProc ioctl VUIDSFORMAT\n");
212	    break;
213
214	case DEVICE_OFF:
215	    pMouse->on = FALSE;
216	    RemoveNotifyFd(sunPtrPriv.fd);
217	    break;
218
219	case DEVICE_ABORT:
220	    break;
221    }
222    return Success;
223}
224
225/*-
226 *-----------------------------------------------------------------------
227 * sunMouseGetEvents --
228 *	Return the events waiting in the wings for the given mouse.
229 *
230 * Results:
231 *	A pointer to an array of Firm_events or (Firm_event *)0 if no events
232 *	The number of events contained in the array.
233 *	A boolean as to whether more events might be available.
234 *
235 * Side Effects:
236 *	None.
237 *-----------------------------------------------------------------------
238 */
239
240static Firm_event *
241sunMouseGetEvents(int fd, Bool on, int *pNumEvents, Bool *pAgain)
242{
243    int	    	  nBytes;	    /* number of bytes of events available. */
244    static Firm_event	evBuf[SUN_MAXEVENTS];   /* Buffer for Firm_events */
245
246    if ((nBytes = read (fd, (char *)evBuf, sizeof(evBuf))) == -1) {
247	if (errno == EWOULDBLOCK) {
248	    *pNumEvents = 0;
249	    *pAgain = FALSE;
250	} else {
251	    ErrorF("sunMouseGetEvents read\n");
252	    FatalError ("Could not read from mouse");
253	}
254    } else {
255	if (on) {
256	    *pNumEvents = nBytes / sizeof (Firm_event);
257	    *pAgain = (nBytes == sizeof (evBuf));
258	} else {
259	    *pNumEvents = 0;
260	    *pAgain = FALSE;
261	}
262    }
263    return evBuf;
264}
265
266
267/*-
268 *-----------------------------------------------------------------------
269 * sunMouseEnqueueEvent --
270 *	Given a Firm_event for a mouse, pass it off the the dix layer
271 *	properly converted...
272 *
273 * Results:
274 *	None.
275 *
276 * Side Effects:
277 *	The cursor may be redrawn...? devPrivate/x/y will be altered.
278 *
279 *-----------------------------------------------------------------------
280 */
281
282static void
283sunMouseEnqueueEvent(DeviceIntPtr device, Firm_event *fe)
284{
285    sunPtrPrivPtr	pPriv;	/* Private data for pointer */
286    int			bmask;	/* Temporary button mask */
287    int			x, y;
288    double		tmpx, tmpy;
289    int			type, buttons, flag;
290    int			valuators[2];
291    ValuatorMask	mask;
292
293    pPriv = (sunPtrPrivPtr)device->public.devicePrivate;
294
295    switch (fe->id) {
296    case MS_LEFT:
297    case MS_MIDDLE:
298    case MS_RIGHT:
299	/*
300	 * A button changed state. Sometimes we will get two events
301	 * for a single state change. Should we get a button event which
302	 * reflects the current state of affairs, that event is discarded.
303	 *
304	 * Mouse buttons start at 1.
305	 */
306	buttons = (fe->id - MS_LEFT) + 1;
307	bmask = 1 << buttons;
308	if (fe->value == VKEY_UP) {
309	    if (pPriv->bmask & bmask) {
310		type = ButtonRelease;
311		pPriv->bmask &= ~bmask;
312	    } else {
313		return;
314	    }
315	} else {
316	    if ((pPriv->bmask & bmask) == 0) {
317		type = ButtonPress;
318		pPriv->bmask |= bmask;
319	    } else {
320		return;
321	    }
322	}
323	flag = POINTER_RELATIVE;
324	valuator_mask_zero(&mask);
325	QueuePointerEvents(device, type, buttons, flag, &mask);
326	break;
327    case LOC_X_DELTA:
328	valuators[0] = fe->value;
329	valuators[1] = 0;
330	valuator_mask_set_range(&mask, 0, 2, valuators);
331	flag = POINTER_RELATIVE | POINTER_ACCELERATE;
332	QueuePointerEvents(device, MotionNotify, 0, flag, &mask);
333	break;
334    case LOC_Y_DELTA:
335	/*
336	 * For some reason, motion up generates a positive y delta
337	 * and motion down a negative delta, so we must subtract
338	 * here instead of add...
339	 */
340	valuators[0] = 0;
341	valuators[1] = -fe->value;
342	valuator_mask_set_range(&mask, 0, 2, valuators);
343	flag = POINTER_RELATIVE | POINTER_ACCELERATE;
344	QueuePointerEvents(device, MotionNotify, 0, flag, &mask);
345	break;
346    case LOC_X_ABSOLUTE:
347	miPointerGetPosition(device, &x, &y);
348	tmpx = fe->value;
349	tmpy = y;
350	miPointerSetPosition(device, Absolute, &tmpx, &tmpy, NULL, NULL);
351	break;
352    case LOC_Y_ABSOLUTE:
353	miPointerGetPosition(device, &x, &y);
354	tmpx = x;
355	tmpy = fe->value;
356	miPointerSetPosition(device, Absolute, &tmpx, &tmpy, NULL, NULL);
357	break;
358    default:
359	FatalError ("sunMouseEnqueueEvent: unrecognized id\n");
360	break;
361    }
362}
363
364/*ARGSUSED*/
365static Bool
366sunCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
367{
368    int	    index, ret = FALSE;
369    DeviceIntPtr device = sunPointerDevice;	/* XXX */
370
371    if (device && PointerConfinedToScreen(device))
372	return TRUE;
373    /*
374     * Active Zaphod implementation:
375     *    increment or decrement the current screen
376     *    if the x is to the right or the left of
377     *    the current screen.
378     */
379    if (sunActiveZaphod &&
380	screenInfo.numScreens > 1 && (*x >= (*pScreen)->width || *x < 0)) {
381	index = (*pScreen)->myNum;
382	if (*x < 0) {
383	    index = (index ? index : screenInfo.numScreens) - 1;
384	    *pScreen = screenInfo.screens[index];
385	    *x += (*pScreen)->width;
386	} else {
387	    *x -= (*pScreen)->width;
388	    index = (index + 1) % screenInfo.numScreens;
389	    *pScreen = screenInfo.screens[index];
390	}
391	ret = TRUE;
392    }
393    return ret;
394}
395
396static void
397sunCrossScreen(ScreenPtr pScreen, int entering)
398{
399    if (sunFbs[pScreen->myNum].EnterLeave)
400	(*sunFbs[pScreen->myNum].EnterLeave) (pScreen, entering ? 0 : 1);
401}
402
403static void
404sunWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
405{
406    input_lock();
407    miPointerWarpCursor (pDev, pScreen, x, y);
408    input_unlock();
409}
410