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