sunMouse.c revision 8931864a
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	if (pMouse->on) {
276	    NumEvents = nBytes / sizeof(pPriv->evbuf[0]);
277	}
278    }
279    return NumEvents;
280}
281
282
283/*-
284 *-----------------------------------------------------------------------
285 * sunMouseEnqueueEvent --
286 *	Given a Firm_event for a mouse, pass it off the the dix layer
287 *	properly converted...
288 *
289 * Results:
290 *	None.
291 *
292 * Side Effects:
293 *	The cursor may be redrawn...? devPrivate/x/y will be altered.
294 *
295 *-----------------------------------------------------------------------
296 */
297
298static void
299sunMouseEnqueueEvent(DeviceIntPtr device, Firm_event *fe)
300{
301    sunPtrPrivPtr	pPriv;	/* Private data for pointer */
302    int			bmask;	/* Temporary button mask */
303    int			x, y;
304    double		tmpx, tmpy;
305    int			type, buttons, flag;
306    int			valuators[2];
307    ValuatorMask	mask;
308
309    pPriv = (sunPtrPrivPtr)device->public.devicePrivate;
310
311    switch (fe->id) {
312    case MS_LEFT:
313    case MS_MIDDLE:
314    case MS_RIGHT:
315	/*
316	 * A button changed state. Sometimes we will get two events
317	 * for a single state change. Should we get a button event which
318	 * reflects the current state of affairs, that event is discarded.
319	 *
320	 * Mouse buttons start at 1.
321	 */
322	buttons = (fe->id - MS_LEFT) + 1;
323	bmask = 1 << buttons;
324	if (fe->value == VKEY_UP) {
325	    if (pPriv->bmask & bmask) {
326		type = ButtonRelease;
327		pPriv->bmask &= ~bmask;
328	    } else {
329		return;
330	    }
331	} else {
332	    if ((pPriv->bmask & bmask) == 0) {
333		type = ButtonPress;
334		pPriv->bmask |= bmask;
335	    } else {
336		return;
337	    }
338	}
339	flag = POINTER_RELATIVE;
340	valuator_mask_zero(&mask);
341	QueuePointerEvents(device, type, buttons, flag, &mask);
342	break;
343    case LOC_X_DELTA:
344	valuators[0] = fe->value;
345	valuators[1] = 0;
346	valuator_mask_set_range(&mask, 0, 2, valuators);
347	flag = POINTER_RELATIVE | POINTER_ACCELERATE;
348	QueuePointerEvents(device, MotionNotify, 0, flag, &mask);
349	break;
350    case LOC_Y_DELTA:
351	/*
352	 * For some reason, motion up generates a positive y delta
353	 * and motion down a negative delta, so we must subtract
354	 * here instead of add...
355	 */
356	valuators[0] = 0;
357	valuators[1] = -fe->value;
358	valuator_mask_set_range(&mask, 0, 2, valuators);
359	flag = POINTER_RELATIVE | POINTER_ACCELERATE;
360	QueuePointerEvents(device, MotionNotify, 0, flag, &mask);
361	break;
362    case LOC_X_ABSOLUTE:
363	miPointerGetPosition(device, &x, &y);
364	tmpx = fe->value;
365	tmpy = y;
366	miPointerSetPosition(device, Absolute, &tmpx, &tmpy, NULL, NULL);
367	break;
368    case LOC_Y_ABSOLUTE:
369	miPointerGetPosition(device, &x, &y);
370	tmpx = x;
371	tmpy = fe->value;
372	miPointerSetPosition(device, Absolute, &tmpx, &tmpy, NULL, NULL);
373	break;
374    default:
375	FatalError ("sunMouseEnqueueEvent: unrecognized id\n");
376	break;
377    }
378}
379
380/*ARGSUSED*/
381static Bool
382sunCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
383{
384    int	    index, ret = FALSE;
385    DeviceIntPtr device = sunPointerDevice;	/* XXX */
386
387    if (device && PointerConfinedToScreen(device))
388	return TRUE;
389    /*
390     * Active Zaphod implementation:
391     *    increment or decrement the current screen
392     *    if the x is to the right or the left of
393     *    the current screen.
394     */
395    if (sunActiveZaphod &&
396	screenInfo.numScreens > 1 && (*x >= (*pScreen)->width || *x < 0)) {
397	index = (*pScreen)->myNum;
398	if (*x < 0) {
399	    index = (index ? index : screenInfo.numScreens) - 1;
400	    *pScreen = screenInfo.screens[index];
401	    *x += (*pScreen)->width;
402	} else {
403	    *x -= (*pScreen)->width;
404	    index = (index + 1) % screenInfo.numScreens;
405	    *pScreen = screenInfo.screens[index];
406	}
407	ret = TRUE;
408    }
409    return ret;
410}
411
412static void
413sunCrossScreen(ScreenPtr pScreen, int entering)
414{
415    if (sunFbs[pScreen->myNum].EnterLeave)
416	(*sunFbs[pScreen->myNum].EnterLeave) (pScreen, entering ? 0 : 1);
417}
418
419static void
420sunWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
421{
422    input_lock();
423    miPointerWarpCursor (pDev, pScreen, x, y);
424    input_unlock();
425}
426