Clean up spec file for packaging.
[profile/ivi/xorg-drv-evdev.git] / src / draglock.c
1 /*
2  * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
3  * Copyright 1993 by David Dawes <dawes@xfree86.org>
4  * Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
5  * Copyright 1994-2002 by The XFree86 Project, Inc.
6  * Copyright 2002 by Paul Elliott
7  * (Ported from xf86-input-mouse, above copyrights taken from there)
8  * Copyright © 2008 University of South Australia
9  * Copyright 2008 by Chris Salch
10  * Copyright 2008 Red Hat, Inc.
11  *
12  * Permission to use, copy, modify, distribute, and sell this software
13  * and its documentation for any purpose is hereby granted without
14  * fee, provided that the above copyright notice appear in all copies
15  * and that both that copyright notice and this permission notice
16  * appear in supporting documentation, and that the name of the authors
17  * not be used in advertising or publicity pertaining to distribution of the
18  * software without specific, written prior permission.  The authors make no
19  * representations about the suitability of this software for any
20  * purpose.  It is provided "as is" without express or implied
21  * warranty.
22  *
23  * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
24  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
25  * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
26  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
27  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
28  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
29  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30  *
31  */
32
33 /* Draglock code */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include <xf86.h>
40 #include <xf86Xinput.h>
41 #include <X11/Xatom.h>
42 #include <exevents.h>
43
44 #include <evdev-properties.h>
45 #include "evdev.h"
46
47 #ifdef HAVE_PROPERTIES
48 static Atom prop_dlock     = 0; /* Drag lock buttons. */
49 #endif
50
51 void EvdevDragLockLockButton(InputInfoPtr pInfo, unsigned int button);
52
53
54 /* Setup and configuration code */
55 void
56 EvdevDragLockPreInit(InputInfoPtr pInfo)
57 {
58     EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
59     char *option_string = NULL;
60     int meta_button = 0;
61     int lock_button = 0;
62     char *next_num = NULL;
63     char *end_str = NULL;
64     BOOL pairs = FALSE;
65
66     option_string = xf86CheckStrOption(pInfo->options, "DragLockButtons",NULL);
67
68     if (!option_string)
69         return;
70
71     next_num = option_string;
72
73     /* Loop until we hit the end of our option string */
74     while (next_num != NULL) {
75         lock_button = 0;
76         meta_button = strtol(next_num, &end_str, 10);
77
78         /* check to see if we found anything */
79         if (next_num != end_str) {
80             /* setup for the next number */
81             next_num = end_str;
82         } else {
83             /* we have nothing more to parse, drop out of the loop */
84             next_num = NULL;
85         }
86
87         /* Check for a button to lock if we have a meta button */
88         if (meta_button != 0 && next_num != NULL ) {
89             lock_button = strtol(next_num, &end_str, 10);
90
91             /* check to see if we found anything */
92             if (next_num != end_str) {
93                 /* setup for the next number */
94                 next_num = end_str;
95             } else {
96                 /* we have nothing more to parse, drop out of the loop */
97                 next_num = NULL;
98             }
99         }
100
101         /* Ok, let the user know what we found on this look */
102         if (meta_button != 0) {
103             if (lock_button == 0) {
104                 if (!pairs) {
105                     /* We only have a meta button */
106                     pEvdev->dragLock.meta = meta_button;
107
108                     xf86Msg(X_CONFIG, "%s: DragLockButtons : "
109                             "%i as meta\n",
110                             pInfo->name, meta_button);
111                 } else {
112                     xf86Msg(X_ERROR, "%s: DragLockButtons : "
113                             "Incomplete pair specifying button pairs %s\n",
114                             pInfo->name, option_string);
115                 }
116             } else {
117
118                 /* Do bounds checking to make sure we don't crash */
119                 if ((meta_button <= EVDEV_MAXBUTTONS) && (meta_button >= 0 ) &&
120                     (lock_button <= EVDEV_MAXBUTTONS) && (lock_button >= 0)) {
121
122                     xf86Msg(X_CONFIG, "%s: DragLockButtons : %i -> %i\n",
123                             pInfo->name, meta_button, lock_button);
124
125                     pEvdev->dragLock.lock_pair[meta_button - 1] = lock_button;
126                     pairs=TRUE;
127                 } else {
128                     /* Let the user know something was wrong
129                        with this pair of buttons */
130                     xf86Msg(X_CONFIG, "%s: DragLockButtons : "
131                             "Invalid button pair %i -> %i\n",
132                             pInfo->name, meta_button, lock_button);
133                 }
134             }
135         } else {
136             xf86Msg(X_ERROR, "%s: Found DragLockButtons "
137                     "with  invalid lock button string : '%s'\n",
138                     pInfo->name, option_string);
139
140             /* This should be the case anyhow, just make sure */
141             next_num = NULL;
142         }
143
144         /* Check for end of string, to avoid annoying error */
145         if (next_num != NULL && *next_num == '\0')
146             next_num = NULL;
147     }
148 }
149
150 /* Updates DragLock button state and fires button event messges */
151 void
152 EvdevDragLockLockButton(InputInfoPtr pInfo, unsigned int button)
153 {
154     EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
155     BOOL state = 0;
156
157     /* update button state */
158     state = pEvdev->dragLock.lock_state[button - 1] ? FALSE : TRUE;
159     pEvdev->dragLock.lock_state[button - 1] = state;
160
161     EvdevQueueButtonEvent(pInfo, button, state);
162 }
163
164 /* Filter button presses looking for either a meta button or the
165  * control of a button pair.
166  *
167  * @param button button number (1 for left, 3 for right)
168  * @param value TRUE if button press, FALSE if release
169  *
170  * @return TRUE if the event was swallowed here, FALSE otherwise.
171  */
172 BOOL
173 EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value)
174 {
175     EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
176
177     if (button == 0)
178         return FALSE;
179
180     /* Do we have a single meta key or
181        several button pairings? */
182     if (pEvdev->dragLock.meta != 0) {
183
184         if (pEvdev->dragLock.meta == button) {
185
186             /* setup up for button lock */
187             if (value)
188                 pEvdev->dragLock.meta_state = TRUE;
189
190             return TRUE;
191         } else if (pEvdev->dragLock.meta_state) { /* waiting to lock */
192
193             pEvdev->dragLock.meta_state = FALSE;
194
195             EvdevDragLockLockButton(pInfo, button);
196
197             return TRUE;
198         }
199     } else if (pEvdev->dragLock.lock_pair[button - 1] && value) {
200         /* A meta button in a meta/lock pair was pressed */
201         EvdevDragLockLockButton(pInfo, pEvdev->dragLock.lock_pair[button - 1]);
202         return TRUE;
203     }
204
205     /* Eat events for buttons that are locked */
206     if (pEvdev->dragLock.lock_state[button - 1])
207         return TRUE;
208
209     return FALSE;
210 }
211
212 #ifdef HAVE_PROPERTIES
213 /**
214  * Set the drag lock property.
215  * If only one value is supplied, then this is used as the meta button.
216  * If more than one value is supplied, then each value is the drag lock button
217  * for the pair. 0 disables a pair.
218  * i.e. to set bt 3 to draglock button 1, supply 0,0,1
219  */
220 static int
221 EvdevDragLockSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
222                          BOOL checkonly)
223 {
224     InputInfoPtr pInfo  = dev->public.devicePrivate;
225     EvdevPtr     pEvdev = pInfo->private;
226
227     if (atom == prop_dlock)
228     {
229         int i;
230
231         if (val->format != 8 || val->type != XA_INTEGER)
232             return BadMatch;
233
234         /* Don't allow changes while a lock is active */
235         if (pEvdev->dragLock.meta)
236         {
237             if (pEvdev->dragLock.meta_state)
238                 return BadAccess;
239         } else
240         {
241             for (i = 0; i < EVDEV_MAXBUTTONS; i++)
242                 if (pEvdev->dragLock.lock_state[i])
243                     return BadValue;
244         }
245
246         if (val->size == 0)
247             return BadMatch;
248         else if (val->size == 1)
249         {
250             int meta = *((CARD8*)val->data);
251             if (meta > EVDEV_MAXBUTTONS)
252                 return BadValue;
253
254             if (!checkonly)
255             {
256                 pEvdev->dragLock.meta = meta;
257                 memset(pEvdev->dragLock.lock_pair, 0, sizeof(pEvdev->dragLock.lock_pair));
258             }
259         } else if ((val->size % 2) == 0)
260         {
261             CARD8* vals = (CARD8*)val->data;
262
263             for (i = 0; i < val->size && i < EVDEV_MAXBUTTONS; i++)
264                 if (vals[i] > EVDEV_MAXBUTTONS)
265                     return BadValue;
266
267             if (!checkonly)
268             {
269                 pEvdev->dragLock.meta = 0;
270                 memset(pEvdev->dragLock.lock_pair, 0, sizeof(pEvdev->dragLock.lock_pair));
271
272                 for (i = 0; i < val->size && i < EVDEV_MAXBUTTONS; i += 2)
273                     pEvdev->dragLock.lock_pair[vals[i] - 1] = vals[i + 1];
274             }
275         } else
276             return BadMatch;
277     }
278
279     return Success;
280 }
281
282 /**
283  * Initialise property for drag lock buttons setting.
284  */
285 void
286 EvdevDragLockInitProperty(DeviceIntPtr dev)
287 {
288     InputInfoPtr pInfo  = dev->public.devicePrivate;
289     EvdevPtr     pEvdev = pInfo->private;
290
291     if (!dev->button) /* don't init prop for keyboards */
292         return;
293
294     prop_dlock = MakeAtom(EVDEV_PROP_DRAGLOCK, strlen(EVDEV_PROP_DRAGLOCK), TRUE);
295     if (pEvdev->dragLock.meta)
296     {
297         XIChangeDeviceProperty(dev, prop_dlock, XA_INTEGER, 8,
298                                PropModeReplace, 1, &pEvdev->dragLock.meta,
299                                FALSE);
300     } else {
301         int highest = 0;
302         int i;
303         CARD8 pair[EVDEV_MAXBUTTONS] = {0};
304
305         for (i = 0; i < EVDEV_MAXBUTTONS; i++)
306         {
307             if (pEvdev->dragLock.lock_pair[i])
308                 highest = i;
309             pair[i] = pEvdev->dragLock.lock_pair[i];
310         }
311
312         XIChangeDeviceProperty(dev, prop_dlock, XA_INTEGER, 8, PropModeReplace,
313                                highest + 1, pair, FALSE);
314     }
315
316     XISetDevicePropertyDeletable(dev, prop_dlock, FALSE);
317
318     XIRegisterPropertyHandler(dev, EvdevDragLockSetProperty, NULL, NULL);
319 }
320
321 #endif