sunMouse.c revision 2da8aa69
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
64/*
65 * Data private to any sun pointer device.
66 */
67typedef struct {
68    int		fd;
69    int		bmask;		/* last known button state */
70    int		oformat;	/* saved value of VUIDGFORMAT */
71} sunPtrPrivRec, *sunPtrPrivPtr;
72
73Bool sunActiveZaphod = TRUE;
74DeviceIntPtr sunPointerDevice = NULL;
75
76static void sunMouseEvents(int, int, void *);
77static Firm_event *sunMouseGetEvents(int, Bool, int *, Bool *);
78static void sunMouseEnqueueEvent(DeviceIntPtr, Firm_event *);
79static Bool sunCursorOffScreen(ScreenPtr *, int *, int *);
80static void sunCrossScreen(ScreenPtr, int);
81static void sunWarpCursor(DeviceIntPtr, ScreenPtr, int, int);
82
83miPointerScreenFuncRec sunPointerScreenFuncs = {
84    sunCursorOffScreen,
85    sunCrossScreen,
86    sunWarpCursor,
87};
88
89static void
90sunMouseEvents(int fd, int ready, void *data)
91{
92    int i, numEvents = 0;
93    Bool again = FALSE;
94    Firm_event *events;
95    DeviceIntPtr device = (DeviceIntPtr)data;
96
97    input_lock();
98
99    do {
100	events = sunMouseGetEvents(fd, device->public.on, &numEvents, &again);
101	for (i = 0; i < numEvents; i++) {
102	    sunMouseEnqueueEvent(device, &events[i]);
103	}
104    } while (again);
105
106    input_unlock();
107}
108
109/*-
110 *-----------------------------------------------------------------------
111 * sunMouseCtrl --
112 *	Alter the control parameters for the mouse. Since acceleration
113 *	etc. is done from the PtrCtrl record in the mouse's device record,
114 *	there's nothing to do here.
115 *
116 * Results:
117 *	None.
118 *
119 * Side Effects:
120 *	None.
121 *
122 *-----------------------------------------------------------------------
123 */
124/*ARGSUSED*/
125static void
126sunMouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl)
127{
128}
129
130/*-
131 *-----------------------------------------------------------------------
132 * sunMouseProc --
133 *	Handle the initialization, etc. of a mouse
134 *
135 * Results:
136 *	none.
137 *
138 * Side Effects:
139 *
140 * Note:
141 *	When using sunwindows, all input comes off a single fd, stored in the
142 *	global windowFd.  Therefore, only one device should be enabled and
143 *	disabled, even though the application still sees both mouse and
144 *	keyboard.  We have arbitrarily chosen to enable and disable windowFd
145 *	in the keyboard routine sunKbdProc rather than in sunMouseProc.
146 *
147 *-----------------------------------------------------------------------
148 */
149int
150sunMouseProc(DeviceIntPtr device, int what)
151{
152    DevicePtr	  pMouse = &device->public;
153    sunPtrPrivPtr pPriv;
154    int	    	  format;
155    BYTE    	  map[4];
156    Atom btn_labels[3] = {0};
157    Atom axes_labels[2] = { 0, 0 };
158
159    switch (what) {
160	case DEVICE_INIT:
161	    pPriv = malloc(sizeof(*pPriv));
162	    if (pPriv == NULL) {
163		LogMessage(X_ERROR, "Cannot allocate private data for mouse\n");
164		return !Success;
165	    }
166	    pPriv->fd = open("/dev/mouse", O_RDWR | O_NONBLOCK, 0);
167	    if (pPriv->fd < 0) {
168		LogMessage(X_ERROR, "Cannot open /dev/mouse, error %d\n",
169		    errno);
170		free(pPriv);
171		return !Success;
172	    }
173	    pPriv->bmask = 0;
174	    pPriv->oformat = 0;
175	    pMouse->devicePrivate = pPriv;
176	    pMouse->on = FALSE;
177
178	    map[1] = 1;
179	    map[2] = 2;
180	    map[3] = 3;
181	    btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
182	    btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
183	    btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
184	    axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
185	    axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
186
187	    InitPointerDeviceStruct(pMouse, map, 3, btn_labels,
188		sunMouseCtrl, GetMotionHistorySize(),
189		2, axes_labels);
190
191	    /* X valuator */
192	    InitValuatorAxisStruct(device, 0, axes_labels[0],
193		NO_AXIS_LIMITS, NO_AXIS_LIMITS, 1, 0, 1, Relative);
194            device->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
195            device->last.valuators[0] = device->valuator->axisVal[0];
196
197	    /* Y valuator */
198	    InitValuatorAxisStruct(device, 1, axes_labels[1],
199		NO_AXIS_LIMITS, NO_AXIS_LIMITS, 1, 0, 1, Relative);
200            device->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
201            device->last.valuators[1] = device->valuator->axisVal[1];
202
203	    break;
204
205	case DEVICE_ON:
206	    pPriv = (sunPtrPrivPtr)pMouse->devicePrivate;
207	    if (ioctl(pPriv->fd, VUIDGFORMAT, &pPriv->oformat) == -1) {
208		LogMessage(X_ERROR, "sunMouseProc ioctl VUIDGFORMAT\n");
209		return !Success;
210	    }
211	    format = VUID_FIRM_EVENT;
212	    if (ioctl(pPriv->fd, VUIDSFORMAT, &format) == -1) {
213		LogMessage(X_ERROR, "sunMouseProc ioctl VUIDSFORMAT\n");
214		return !Success;
215	    }
216
217	    SetNotifyFd(pPriv->fd, sunMouseEvents, X_NOTIFY_READ, device);
218
219	    pPriv->bmask = 0;
220	    pMouse->on = TRUE;
221	    break;
222
223	case DEVICE_OFF:
224	    pPriv = (sunPtrPrivPtr)pMouse->devicePrivate;
225	    RemoveNotifyFd(pPriv->fd);
226	    if (ioctl(pPriv->fd, VUIDSFORMAT, &pPriv->oformat) == -1)
227		LogMessage(X_ERROR, "sunMouseProc ioctl VUIDSFORMAT\n");
228	    pMouse->on = FALSE;
229	    break;
230
231	case DEVICE_CLOSE:
232	    pPriv = (sunPtrPrivPtr)pMouse->devicePrivate;
233	    close(pPriv->fd);
234	    free(pPriv);
235	    pMouse->devicePrivate = NULL;
236	    break;
237
238	case DEVICE_ABORT:
239	    break;
240    }
241    return Success;
242}
243
244/*-
245 *-----------------------------------------------------------------------
246 * sunMouseGetEvents --
247 *	Return the events waiting in the wings for the given mouse.
248 *
249 * Results:
250 *	A pointer to an array of Firm_events or (Firm_event *)0 if no events
251 *	The number of events contained in the array.
252 *	A boolean as to whether more events might be available.
253 *
254 * Side Effects:
255 *	None.
256 *-----------------------------------------------------------------------
257 */
258
259static Firm_event *
260sunMouseGetEvents(int fd, Bool on, int *pNumEvents, Bool *pAgain)
261{
262    int	    	  nBytes;	    /* number of bytes of events available. */
263    static Firm_event	evBuf[SUN_MAXEVENTS];   /* Buffer for Firm_events */
264
265    if ((nBytes = read (fd, (char *)evBuf, sizeof(evBuf))) == -1) {
266	if (errno == EWOULDBLOCK) {
267	    *pNumEvents = 0;
268	    *pAgain = FALSE;
269	} else {
270	    ErrorF("sunMouseGetEvents read\n");
271	    FatalError ("Could not read from mouse");
272	}
273    } else {
274	if (on) {
275	    *pNumEvents = nBytes / sizeof (Firm_event);
276	    *pAgain = (nBytes == sizeof (evBuf));
277	} else {
278	    *pNumEvents = 0;
279	    *pAgain = FALSE;
280	}
281    }
282    return evBuf;
283}
284
285
286/*-
287 *-----------------------------------------------------------------------
288 * sunMouseEnqueueEvent --
289 *	Given a Firm_event for a mouse, pass it off the the dix layer
290 *	properly converted...
291 *
292 * Results:
293 *	None.
294 *
295 * Side Effects:
296 *	The cursor may be redrawn...? devPrivate/x/y will be altered.
297 *
298 *-----------------------------------------------------------------------
299 */
300
301static void
302sunMouseEnqueueEvent(DeviceIntPtr device, Firm_event *fe)
303{
304    sunPtrPrivPtr	pPriv;	/* Private data for pointer */
305    int			bmask;	/* Temporary button mask */
306    int			x, y;
307    double		tmpx, tmpy;
308    int			type, buttons, flag;
309    int			valuators[2];
310    ValuatorMask	mask;
311
312    pPriv = (sunPtrPrivPtr)device->public.devicePrivate;
313
314    switch (fe->id) {
315    case MS_LEFT:
316    case MS_MIDDLE:
317    case MS_RIGHT:
318	/*
319	 * A button changed state. Sometimes we will get two events
320	 * for a single state change. Should we get a button event which
321	 * reflects the current state of affairs, that event is discarded.
322	 *
323	 * Mouse buttons start at 1.
324	 */
325	buttons = (fe->id - MS_LEFT) + 1;
326	bmask = 1 << buttons;
327	if (fe->value == VKEY_UP) {
328	    if (pPriv->bmask & bmask) {
329		type = ButtonRelease;
330		pPriv->bmask &= ~bmask;
331	    } else {
332		return;
333	    }
334	} else {
335	    if ((pPriv->bmask & bmask) == 0) {
336		type = ButtonPress;
337		pPriv->bmask |= bmask;
338	    } else {
339		return;
340	    }
341	}
342	flag = POINTER_RELATIVE;
343	valuator_mask_zero(&mask);
344	QueuePointerEvents(device, type, buttons, flag, &mask);
345	break;
346    case LOC_X_DELTA:
347	valuators[0] = fe->value;
348	valuators[1] = 0;
349	valuator_mask_set_range(&mask, 0, 2, valuators);
350	flag = POINTER_RELATIVE | POINTER_ACCELERATE;
351	QueuePointerEvents(device, MotionNotify, 0, flag, &mask);
352	break;
353    case LOC_Y_DELTA:
354	/*
355	 * For some reason, motion up generates a positive y delta
356	 * and motion down a negative delta, so we must subtract
357	 * here instead of add...
358	 */
359	valuators[0] = 0;
360	valuators[1] = -fe->value;
361	valuator_mask_set_range(&mask, 0, 2, valuators);
362	flag = POINTER_RELATIVE | POINTER_ACCELERATE;
363	QueuePointerEvents(device, MotionNotify, 0, flag, &mask);
364	break;
365    case LOC_X_ABSOLUTE:
366	miPointerGetPosition(device, &x, &y);
367	tmpx = fe->value;
368	tmpy = y;
369	miPointerSetPosition(device, Absolute, &tmpx, &tmpy, NULL, NULL);
370	break;
371    case LOC_Y_ABSOLUTE:
372	miPointerGetPosition(device, &x, &y);
373	tmpx = x;
374	tmpy = fe->value;
375	miPointerSetPosition(device, Absolute, &tmpx, &tmpy, NULL, NULL);
376	break;
377    default:
378	FatalError ("sunMouseEnqueueEvent: unrecognized id\n");
379	break;
380    }
381}
382
383/*ARGSUSED*/
384static Bool
385sunCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
386{
387    int	    index, ret = FALSE;
388    DeviceIntPtr device = sunPointerDevice;	/* XXX */
389
390    if (device && PointerConfinedToScreen(device))
391	return TRUE;
392    /*
393     * Active Zaphod implementation:
394     *    increment or decrement the current screen
395     *    if the x is to the right or the left of
396     *    the current screen.
397     */
398    if (sunActiveZaphod &&
399	screenInfo.numScreens > 1 && (*x >= (*pScreen)->width || *x < 0)) {
400	index = (*pScreen)->myNum;
401	if (*x < 0) {
402	    index = (index ? index : screenInfo.numScreens) - 1;
403	    *pScreen = screenInfo.screens[index];
404	    *x += (*pScreen)->width;
405	} else {
406	    *x -= (*pScreen)->width;
407	    index = (index + 1) % screenInfo.numScreens;
408	    *pScreen = screenInfo.screens[index];
409	}
410	ret = TRUE;
411    }
412    return ret;
413}
414
415static void
416sunCrossScreen(ScreenPtr pScreen, int entering)
417{
418    if (sunFbs[pScreen->myNum].EnterLeave)
419	(*sunFbs[pScreen->myNum].EnterLeave) (pScreen, entering ? 0 : 1);
420}
421
422static void
423sunWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
424{
425    input_lock();
426    miPointerWarpCursor (pDev, pScreen, x, y);
427    input_unlock();
428}
429