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