1 /**
2 * Copyright © 2009 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
26 #endif
27
28 #include <errno.h>
29 #include <stdint.h>
30 #include "extinit.h" /* for XInputExtensionInit */
31 #include "exglobals.h"
32 #include "xkbsrv.h" /* for XkbInitPrivates */
33 #include "xserver-properties.h"
34 #include "syncsrv.h"
35 #include <X11/extensions/XI2.h>
36
37 #define INSIDE_PROTOCOL_COMMON
38 #include "protocol-common.h"
39
40 struct devices devices;
41 ScreenRec screen;
42 WindowRec root;
43 WindowRec window;
44 static ClientRec server_client;
45
46 void *global_userdata;
47
48 void (*reply_handler) (ClientPtr client, int len, char *data, void *userdata);
49
50 int enable_GrabButton_wrap = 1;
51 int enable_XISetEventMask_wrap = 1;
52
53 static void
fake_init_sprite(DeviceIntPtr dev)54 fake_init_sprite(DeviceIntPtr dev)
55 {
56 SpritePtr sprite;
57
58 sprite = dev->spriteInfo->sprite;
59
60 sprite->spriteTraceSize = 10;
61 sprite->spriteTrace = calloc(sprite->spriteTraceSize, sizeof(WindowPtr));
62 sprite->spriteTraceGood = 1;
63 sprite->spriteTrace[0] = &root;
64 sprite->hot.x = SPRITE_X;
65 sprite->hot.y = SPRITE_Y;
66 sprite->hotPhys.x = sprite->hot.x;
67 sprite->hotPhys.y = sprite->hot.y;
68 sprite->win = &window;
69 sprite->hotPhys.pScreen = &screen;
70 sprite->physLimits.x1 = 0;
71 sprite->physLimits.y1 = 0;
72 sprite->physLimits.x2 = screen.width;
73 sprite->physLimits.y2 = screen.height;
74 }
75
76 /* This is essentially CorePointerProc with ScrollAxes added */
77 static int
TestPointerProc(DeviceIntPtr pDev,int what)78 TestPointerProc(DeviceIntPtr pDev, int what)
79 {
80 #define NBUTTONS 10
81 #define NAXES 4
82 BYTE map[NBUTTONS + 1];
83 int i = 0;
84 Atom btn_labels[NBUTTONS] = { 0 };
85 Atom axes_labels[NAXES] = { 0 };
86
87 switch (what) {
88 case DEVICE_INIT:
89 for (i = 1; i <= NBUTTONS; i++)
90 map[i] = i;
91
92 btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
93 btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
94 btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
95 btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
96 btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
97 btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
98 btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
99 /* don't know about the rest */
100
101 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
102 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
103 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
104 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
105
106 if (!InitPointerDeviceStruct
107 ((DevicePtr) pDev, map, NBUTTONS, btn_labels,
108 (PtrCtrlProcPtr) NoopDDA, GetMotionHistorySize(), NAXES,
109 axes_labels)) {
110 ErrorF("Could not initialize device '%s'. Out of memory.\n",
111 pDev->name);
112 return BadAlloc;
113 }
114 pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
115 pDev->last.valuators[0] = pDev->valuator->axisVal[0];
116 pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
117 pDev->last.valuators[1] = pDev->valuator->axisVal[1];
118
119 /* protocol-xiquerydevice.c relies on these increment */
120 SetScrollValuator(pDev, 2, SCROLL_TYPE_VERTICAL, 2.4, SCROLL_FLAG_NONE);
121 SetScrollValuator(pDev, 3, SCROLL_TYPE_HORIZONTAL, 3.5,
122 SCROLL_FLAG_PREFERRED);
123 break;
124
125 case DEVICE_CLOSE:
126 break;
127
128 default:
129 break;
130 }
131
132 return Success;
133
134 #undef NBUTTONS
135 #undef NAXES
136 }
137
138 /**
139 * Create and init 2 master devices (VCP + VCK) and two slave devices, one
140 * default mouse, one default keyboard.
141 */
142 struct devices
init_devices(void)143 init_devices(void)
144 {
145 ClientRec client;
146 struct devices local_devices;
147 int ret;
148
149 /*
150 * Put a unique name in display pointer so that when tests are run in
151 * parallel, their xkbcomp outputs to /tmp/server-<display>.xkm don't
152 * stomp on each other.
153 */
154 #ifdef HAVE_GETPROGNAME
155 display = getprogname();
156 #elif HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
157 display = program_invocation_short_name;
158 #endif
159
160 client = init_client(0, NULL);
161
162 AllocDevicePair(&client, "Virtual core", &local_devices.vcp, &local_devices.vck,
163 CorePointerProc, CoreKeyboardProc, TRUE);
164 inputInfo.pointer = local_devices.vcp;
165
166 inputInfo.keyboard = local_devices.vck;
167 ret = ActivateDevice(local_devices.vcp, FALSE);
168 assert(ret == Success);
169 /* This may fail if xkbcomp fails or xkb-config is not found. */
170 ret = ActivateDevice(local_devices.vck, FALSE);
171 assert(ret == Success);
172 EnableDevice(local_devices.vcp, FALSE);
173 EnableDevice(local_devices.vck, FALSE);
174
175 AllocDevicePair(&client, "", &local_devices.mouse, &local_devices.kbd,
176 TestPointerProc, CoreKeyboardProc, FALSE);
177 ret = ActivateDevice(local_devices.mouse, FALSE);
178 assert(ret == Success);
179 ret = ActivateDevice(local_devices.kbd, FALSE);
180 assert(ret == Success);
181 EnableDevice(local_devices.mouse, FALSE);
182 EnableDevice(local_devices.kbd, FALSE);
183
184 local_devices.num_devices = 4;
185 local_devices.num_master_devices = 2;
186
187 fake_init_sprite(local_devices.mouse);
188 fake_init_sprite(local_devices.vcp);
189
190 return local_devices;
191 }
192
193 /* Create minimal client, with the given buffer and len as request buffer */
194 ClientRec
init_client(int len,void * data)195 init_client(int len, void *data)
196 {
197 ClientRec client = { 0 };
198
199 /* we store the privates now and reassign it after the memset. this way
200 * we can share them across multiple test runs and don't have to worry
201 * about freeing them after each test run. */
202
203 client.index = CLIENT_INDEX;
204 client.clientAsMask = CLIENT_MASK;
205 client.sequence = CLIENT_SEQUENCE;
206 client.req_len = len;
207
208 client.requestBuffer = data;
209 dixAllocatePrivates(&client.devPrivates, PRIVATE_CLIENT);
210 return client;
211 }
212
213 void
init_window(WindowPtr local_window,WindowPtr parent,int id)214 init_window(WindowPtr local_window, WindowPtr parent, int id)
215 {
216 memset(local_window, 0, sizeof(*local_window));
217
218 local_window->drawable.id = id;
219 if (parent) {
220 local_window->drawable.x = 30;
221 local_window->drawable.y = 50;
222 local_window->drawable.width = 100;
223 local_window->drawable.height = 200;
224 }
225 local_window->parent = parent;
226 local_window->optional = calloc(1, sizeof(WindowOptRec));
227 assert(local_window->optional);
228 }
229
230 extern DevPrivateKeyRec miPointerScreenKeyRec;
231 extern DevPrivateKeyRec miPointerPrivKeyRec;
232
233 /* Needed for the screen setup, otherwise we crash during sprite initialization */
234 static Bool
device_cursor_init(DeviceIntPtr dev,ScreenPtr local_screen)235 device_cursor_init(DeviceIntPtr dev, ScreenPtr local_screen)
236 {
237 return TRUE;
238 }
239
240 static void
device_cursor_cleanup(DeviceIntPtr dev,ScreenPtr local_screen)241 device_cursor_cleanup(DeviceIntPtr dev, ScreenPtr local_screen)
242 {
243 }
244
245 static Bool
set_cursor_pos(DeviceIntPtr dev,ScreenPtr local_screen,int x,int y,Bool event)246 set_cursor_pos(DeviceIntPtr dev, ScreenPtr local_screen, int x, int y, Bool event)
247 {
248 return TRUE;
249 }
250
251 void
init_simple(void)252 init_simple(void)
253 {
254 screenInfo.numScreens = 1;
255 screenInfo.screens[0] = &screen;
256
257 screen.myNum = 0;
258 screen.id = 100;
259 screen.width = 640;
260 screen.height = 480;
261 screen.DeviceCursorInitialize = device_cursor_init;
262 screen.DeviceCursorCleanup = device_cursor_cleanup;
263 screen.SetCursorPosition = set_cursor_pos;
264 screen.root = &root;
265
266 dixResetPrivates();
267 InitAtoms();
268 XkbInitPrivates();
269 dixRegisterPrivateKey(&XIClientPrivateKeyRec, PRIVATE_CLIENT,
270 sizeof(XIClientRec));
271 dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0);
272 dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0);
273 XInputExtensionInit();
274
275 init_window(&root, NULL, ROOT_WINDOW_ID);
276 init_window(&window, &root, CLIENT_WINDOW_ID);
277
278 serverClient = &server_client;
279 InitClient(serverClient, 0, (void *) NULL);
280 if (!InitClientResources(serverClient)) /* for root resources */
281 FatalError("couldn't init server resources");
282 SyncExtensionInit();
283
284 devices = init_devices();
285 }
286
287 void
__wrap_WriteToClient(ClientPtr client,int len,void * data)288 __wrap_WriteToClient(ClientPtr client, int len, void *data)
289 {
290 assert(reply_handler != NULL);
291
292 (*reply_handler) (client, len, data, global_userdata);
293 }
294
295 /* dixLookupWindow requires a lot of setup not necessary for this test.
296 * Simple wrapper that returns either one of the fake root window or the
297 * fake client window. If the requested ID is neither of those wanted,
298 * return whatever the real dixLookupWindow does.
299 */
300 int
__wrap_dixLookupWindow(WindowPtr * win,XID id,ClientPtr client,Mask access)301 __wrap_dixLookupWindow(WindowPtr *win, XID id, ClientPtr client, Mask access)
302 {
303 if (id == root.drawable.id) {
304 *win = &root;
305 return Success;
306 }
307 else if (id == window.drawable.id) {
308 *win = &window;
309 return Success;
310 }
311
312 return __real_dixLookupWindow(win, id, client, access);
313 }
314
315 extern ClientRec client_window;
316
317 int
__wrap_dixLookupClient(ClientPtr * pClient,XID rid,ClientPtr client,Mask access)318 __wrap_dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client,
319 Mask access)
320 {
321 if (rid == ROOT_WINDOW_ID)
322 return BadWindow;
323
324 if (rid == CLIENT_WINDOW_ID) {
325 *pClient = &client_window;
326 return Success;
327 }
328
329 return __real_dixLookupClient(pClient, rid, client, access);
330 }
331