tizen 2.4 release
[adaptation/xorg/driver/xserver-xorg-input-evdev.git] / src / proxyDev.c
1 /*
2  *
3  * xserver-xorg-input-evdev
4  *
5  * Contact: Sung-Jin Park <sj76.park@samsung.com>
6  *          Sangjin LEE <lsj119@samsung.com>
7  *          Jeonghyun Kang <jhyuni.kang@samsung.com>
8  *
9  * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
10  * Copyright © 2004-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 Red Hat
17  * not be used in advertising or publicity pertaining to distribution
18  * of the software without specific, written prior permission.  Red
19  * Hat makes no representations about the suitability of this software
20  * for any 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  * Authors:
32  *      Kristian Høgsberg (krh@redhat.com)
33  *      Adam Jackson (ajax@redhat.com)
34  *      Peter Hutterer (peter.hutterer@redhat.com)
35  *      Oliver McFadden (oliver.mcfadden@nokia.com)
36  */
37
38 #ifdef _F_PROXY_DEVICE_ENABLED_
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42
43 #include "evdev.h"
44 #include <evdev-properties.h>
45 #include <errno.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50
51 #include <exevents.h>
52 #include <xf86.h>
53 #include <xf86Xinput.h>
54 #include <X11/Xatom.h>
55 #include <xorg/optionstr.h>
56
57 #include <xorg/mi.h>
58
59 struct _DeviceEvent {
60     unsigned char header; /**< Always ET_Internal */
61     enum EventType type;  /**< One of EventType */
62     int length;           /**< Length in bytes */
63     Time time;            /**< Time in ms */
64     int deviceid;         /**< Device to post this event for */
65     int sourceid;         /**< The physical source device */
66     union {
67         uint32_t button;  /**< Button number (also used in pointer emulating
68                                touch events) */
69         uint32_t key;     /**< Key code */
70     } detail;
71     uint32_t touchid;     /**< Touch ID (client_id) */
72     int16_t root_x;       /**< Pos relative to root window in integral data */
73     float root_x_frac;    /**< Pos relative to root window in frac part */
74     int16_t root_y;       /**< Pos relative to root window in integral part */
75     float root_y_frac;    /**< Pos relative to root window in frac part */
76     uint8_t buttons[(MAX_BUTTONS + 7) / 8];  /**< Button mask */
77     struct {
78         uint8_t mask[(MAX_VALUATORS + 7) / 8];/**< Valuator mask */
79         uint8_t mode[(MAX_VALUATORS + 7) / 8];/**< Valuator mode (Abs or Rel)*/
80         double data[MAX_VALUATORS];           /**< Valuator data */
81     } valuators;
82     struct {
83         uint32_t base;    /**< XKB base modifiers */
84         uint32_t latched; /**< XKB latched modifiers */
85         uint32_t locked;  /**< XKB locked modifiers */
86         uint32_t effective;/**< XKB effective modifiers */
87     } mods;
88     struct {
89         uint8_t base;    /**< XKB base group */
90         uint8_t latched; /**< XKB latched group */
91         uint8_t locked;  /**< XKB locked group */
92         uint8_t effective;/**< XKB effective group */
93     } group;
94     Window root;      /**< Root window of the event */
95     int corestate;    /**< Core key/button state BEFORE the event */
96     int key_repeat;   /**< Internally-generated key repeat event */
97     uint32_t flags;   /**< Flags to be copied into the generated event */
98     uint32_t resource; /**< Touch event resource, only for TOUCH_REPLAYING */
99 };
100
101 typedef struct _barrierBoundary {
102     unsigned int x1;
103     unsigned int y1;
104     unsigned int x2;
105     unsigned int y2;
106 } barrierBoundary;
107
108 typedef enum _barrierState {
109     BARRIER_NONE,
110     BARRIER_INSIDE,
111     BARRIER_OUTSIDE
112 } barrierState;
113
114 #define prop_MLS_Barrier_Boundary "MLS_Barrier_Boundary"
115 #define prop_MLS_Barrier_Hit "MLS_Barrier_Hit"
116
117 static void EvdevProxyBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead);
118 void EvdevProxySetBarrierBoundary(int num, unsigned int val[4], barrierBoundary *boundary);
119 barrierState EvdevProxyLocationManager(int x, int y, barrierBoundary boundary);
120 void EvdevProxyProcessMotion(int screen_num, InternalEvent *ev, DeviceIntPtr device);
121 void EvdevProxyProcessRawMotion(int screen_num, InternalEvent *ev, DeviceIntPtr device);
122 static int EvdevProxySetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, BOOL checkonly);
123 static int EvdevProxyDeleteProperty(DeviceIntPtr dev, Atom atom);
124
125 DeviceIntPtr proxyDev;
126
127 /* MLS Barrier */
128 barrierBoundary BarrierBoundary;
129 barrierState BarrierState;
130 Atom atom_MLS_Barrier_Boundary;
131 Atom atom_MLS_Barrier_Hit;
132
133 /* Ungrab device */
134 static Atom prop_ungrab_device;
135
136 int last_id;
137 #define VCP_ID 2
138
139 static void
140 EvdevProxyBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead)
141 {
142     InputInfoPtr pInfo = (InputInfoPtr)data;
143     int rc = 0;
144
145     RemoveBlockAndWakeupHandlers(EvdevProxyBlockHandler,
146                                  (WakeupHandlerProcPtr)NoopDDA,
147                                  data);
148
149     if (BarrierState != BARRIER_NONE)
150         rc = XIChangeDeviceProperty(pInfo->dev, atom_MLS_Barrier_Hit, XA_INTEGER, 32,
151                                 PropModeReplace, 1, &BarrierState, TRUE);
152
153     if (rc != Success)
154     {
155         xf86IDrvMsg(pInfo, X_ERROR, "[%s:%d] Failed to change device property (id:%d, prop=%d)\n", __FUNCTION__, __LINE__, pInfo->dev->id, atom_MLS_Barrier_Hit);
156     }
157 }
158
159 void EvdevProxySetBarrierBoundary(int num, unsigned int val[4], barrierBoundary *boundary)
160 {
161     if (num == 0) {
162         if (BarrierState != BARRIER_NONE) ErrorF("[%s:%d] Unset MLS Barrier Boundary\n", __FUNCTION__, __LINE__);
163         boundary->x1 = 0;
164         boundary->x2 = 0;
165         boundary->y1 = 0;
166         boundary->y2 = 0;
167         BarrierState = BARRIER_NONE;
168     }
169     else {
170         ErrorF("[%s:%d] Set MLS Barrier Boundary (%d, %d) (%d, %d)\n", __FUNCTION__, __LINE__, val[0], val[1], val[2], val[3]);
171         boundary->x1 = val[0];
172         boundary->x2 = val[2];
173         boundary->y1 = val[1];
174         boundary->y2 = val[3];
175     }
176 }
177
178 barrierState EvdevProxyLocationManager(int x, int y, barrierBoundary boundary)
179 {
180     if ((boundary.x1+boundary.y1+boundary.x2+boundary.y2) <= 0 ) {
181         return BARRIER_NONE;
182     }
183     else if ( (boundary.x1 <= x && x <=boundary.x2)
184         && (boundary.y1 <= y && y <=boundary.y2) ) {
185         return BARRIER_INSIDE;
186     }
187     return BARRIER_OUTSIDE;
188 }
189
190 void EvdevProxyProcessRawMotion(int screen_num, InternalEvent * ev,DeviceIntPtr device)
191 {
192     if (device->id != VCP_ID)
193         last_id = device->id;
194     device->public.processInputProc(ev, device);
195 }
196
197 void EvdevProxyProcessMotion(int screen_num, InternalEvent * ev,DeviceIntPtr device)
198 {
199     DeviceEvent *dev = &(ev->changed_event);
200     barrierState prevBarrierState = BarrierState;
201     if (!dev) {
202         ErrorF("[%s:%d] It is not a device event\n", __FUNCTION__, __LINE__);
203         goto process_event;
204     }
205     if (last_id != device->id) {
206         last_id = 0;
207         goto process_event;
208     }
209
210     BarrierState = EvdevProxyLocationManager(dev->root_x, dev->root_y, BarrierBoundary);
211     if (BarrierState == BARRIER_NONE)
212         goto process_event;
213     else if (prevBarrierState == BarrierState)
214         goto process_event;
215     else if (prevBarrierState == BARRIER_INSIDE) {
216         ErrorF("[%s:%d] Pointer in to barrier from outside\n", __FUNCTION__, __LINE__);
217         OsBlockSIGIO();
218         RegisterBlockAndWakeupHandlers(EvdevProxyBlockHandler ,(WakeupHandlerProcPtr) NoopDDA, (InputInfoPtr)(proxyDev->public.devicePrivate));
219         OsReleaseSIGIO();
220     }
221     else if (prevBarrierState == BARRIER_OUTSIDE) {
222         ErrorF("[%s:%d] Pointer out to barrier from inside\n", __FUNCTION__, __LINE__);
223         OsBlockSIGIO();
224         RegisterBlockAndWakeupHandlers(EvdevProxyBlockHandler ,(WakeupHandlerProcPtr) NoopDDA, (InputInfoPtr)(proxyDev->public.devicePrivate));
225         OsReleaseSIGIO();
226     }
227     else if (prevBarrierState == BARRIER_NONE && BarrierState == BARRIER_INSIDE) {
228         ErrorF("[%s:%d] Pointer move start from inside\n", __FUNCTION__, __LINE__);
229         OsBlockSIGIO();
230         RegisterBlockAndWakeupHandlers(EvdevProxyBlockHandler ,(WakeupHandlerProcPtr) NoopDDA, (InputInfoPtr)(proxyDev->public.devicePrivate));
231         OsReleaseSIGIO();
232     }
233     last_id = 0;
234 process_event:
235     device->public.processInputProc(ev, device);
236 }
237
238 void EvdevProxyInit(DeviceIntPtr device)
239 {
240     InputInfoPtr pInfo = device->public.devicePrivate;;
241     EvdevPtr pEvdev = pInfo->private;
242
243     XIRegisterPropertyHandler(device, EvdevProxySetProperty, NULL, EvdevProxyDeleteProperty);
244     mieqSetHandler(ET_Motion, EvdevProxyProcessMotion);
245     mieqSetHandler(ET_RawMotion, EvdevProxyProcessRawMotion);
246
247     proxyDev = device;
248
249     BarrierBoundary.x1 = 0;
250     BarrierBoundary.y1 = 0;
251     BarrierBoundary.x2 = 0;
252     BarrierBoundary.y2 = 0;
253     BarrierState = BARRIER_NONE;
254
255     last_id = 0;
256
257     atom_MLS_Barrier_Boundary = MakeAtom(prop_MLS_Barrier_Boundary, strlen(prop_MLS_Barrier_Boundary), TRUE);
258     atom_MLS_Barrier_Hit = MakeAtom(prop_MLS_Barrier_Hit, strlen(prop_MLS_Barrier_Hit), TRUE);
259     prop_ungrab_device = MakeAtom(XI_PROP_UNGRAB_DEVICE, strlen(XI_PROP_UNGRAB_DEVICE), TRUE);
260 }
261
262 static int
263 EvdevProxySetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
264                  BOOL checkonly)
265 {
266     if (atom == atom_MLS_Barrier_Boundary) {
267         if (val->format != 32 || val->type != XA_INTEGER)
268             return BadMatch;
269         if (val->size != 4 && val->size != 0)
270             return BadMatch;
271
272         if (!checkonly) {
273             EvdevProxySetBarrierBoundary(val->size, val->data, &BarrierBoundary);
274         }
275     }
276
277     else if (atom == prop_ungrab_device )
278     {
279         int data;
280         DeviceIntPtr master = inputInfo.pointer;
281
282         if(!checkonly) {
283             data = *((CARD8*)val->data);
284             if (data == 1 && master->deviceGrab.grab) {
285                 ErrorF("[%s:%d] ungrab master pointer device(%d) in device (%d)\n", __FUNCTION__, __LINE__, master->id, dev->id);
286                 (*master->deviceGrab.DeactivateGrab) (master);
287             }
288         }
289     }
290
291     return Success;
292 }
293
294 static int
295 EvdevProxyDeleteProperty(DeviceIntPtr dev, Atom atom)
296 {
297     if (atom == atom_MLS_Barrier_Boundary) {
298         EvdevProxySetBarrierBoundary(0, NULL, &BarrierBoundary);
299     }
300
301     return Success;
302 }
303 #endif //_F_PROXY_DEVICE_ENABLED_