16747b715Smrg/** 26747b715Smrg * Copyright © 2009 Red Hat, Inc. 36747b715Smrg * 46747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a 56747b715Smrg * copy of this software and associated documentation files (the "Software"), 66747b715Smrg * to deal in the Software without restriction, including without limitation 76747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 86747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the 96747b715Smrg * Software is furnished to do so, subject to the following conditions: 106747b715Smrg * 116747b715Smrg * The above copyright notice and this permission notice (including the next 126747b715Smrg * paragraph) shall be included in all copies or substantial portions of the 136747b715Smrg * Software. 146747b715Smrg * 156747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 166747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 176747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 186747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 196747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 206747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 216747b715Smrg * DEALINGS IN THE SOFTWARE. 226747b715Smrg */ 236747b715Smrg 24ed6184dfSmrg/* Test relies on assert() */ 25ed6184dfSmrg#undef NDEBUG 26ed6184dfSmrg 276747b715Smrg#ifdef HAVE_DIX_CONFIG_H 286747b715Smrg#include <dix-config.h> 296747b715Smrg#endif 306747b715Smrg 3135c4bbdfSmrg#include <errno.h> 326747b715Smrg#include <stdint.h> 3335c4bbdfSmrg#include "extinit.h" /* for XInputExtensionInit */ 346747b715Smrg#include "exglobals.h" 3535c4bbdfSmrg#include "xkbsrv.h" /* for XkbInitPrivates */ 3635c4bbdfSmrg#include "xserver-properties.h" 3735c4bbdfSmrg#include "syncsrv.h" 3835c4bbdfSmrg#include <X11/extensions/XI2.h> 396747b715Smrg 401b5d61b8Smrg#define INSIDE_PROTOCOL_COMMON 416747b715Smrg#include "protocol-common.h" 426747b715Smrg 436747b715Smrgstruct devices devices; 446747b715SmrgScreenRec screen; 456747b715SmrgWindowRec root; 466747b715SmrgWindowRec window; 4735c4bbdfSmrgstatic ClientRec server_client; 486747b715Smrg 4935c4bbdfSmrgvoid *global_userdata; 506747b715Smrg 515a7dfde8Smrgvoid (*reply_handler) (ClientPtr client, int len, char *data, void *userdata); 525a7dfde8Smrg 531b5d61b8Smrgint enable_GrabButton_wrap = 1; 541b5d61b8Smrgint enable_XISetEventMask_wrap = 1; 551b5d61b8Smrg 5635c4bbdfSmrgstatic void 5735c4bbdfSmrgfake_init_sprite(DeviceIntPtr dev) 586747b715Smrg{ 596747b715Smrg SpritePtr sprite; 6035c4bbdfSmrg 616747b715Smrg sprite = dev->spriteInfo->sprite; 626747b715Smrg 636747b715Smrg sprite->spriteTraceSize = 10; 646747b715Smrg sprite->spriteTrace = calloc(sprite->spriteTraceSize, sizeof(WindowPtr)); 656747b715Smrg sprite->spriteTraceGood = 1; 666747b715Smrg sprite->spriteTrace[0] = &root; 676747b715Smrg sprite->hot.x = SPRITE_X; 686747b715Smrg sprite->hot.y = SPRITE_Y; 696747b715Smrg sprite->hotPhys.x = sprite->hot.x; 706747b715Smrg sprite->hotPhys.y = sprite->hot.y; 716747b715Smrg sprite->win = &window; 726747b715Smrg sprite->hotPhys.pScreen = &screen; 736747b715Smrg sprite->physLimits.x1 = 0; 746747b715Smrg sprite->physLimits.y1 = 0; 756747b715Smrg sprite->physLimits.x2 = screen.width; 766747b715Smrg sprite->physLimits.y2 = screen.height; 776747b715Smrg} 786747b715Smrg 7935c4bbdfSmrg/* This is essentially CorePointerProc with ScrollAxes added */ 8035c4bbdfSmrgstatic int 8135c4bbdfSmrgTestPointerProc(DeviceIntPtr pDev, int what) 8235c4bbdfSmrg{ 8335c4bbdfSmrg#define NBUTTONS 10 8435c4bbdfSmrg#define NAXES 4 8535c4bbdfSmrg BYTE map[NBUTTONS + 1]; 8635c4bbdfSmrg int i = 0; 8735c4bbdfSmrg Atom btn_labels[NBUTTONS] = { 0 }; 8835c4bbdfSmrg Atom axes_labels[NAXES] = { 0 }; 8935c4bbdfSmrg 9035c4bbdfSmrg switch (what) { 9135c4bbdfSmrg case DEVICE_INIT: 9235c4bbdfSmrg for (i = 1; i <= NBUTTONS; i++) 9335c4bbdfSmrg map[i] = i; 9435c4bbdfSmrg 9535c4bbdfSmrg btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); 9635c4bbdfSmrg btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); 9735c4bbdfSmrg btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); 9835c4bbdfSmrg btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); 9935c4bbdfSmrg btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); 10035c4bbdfSmrg btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); 10135c4bbdfSmrg btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); 10235c4bbdfSmrg /* don't know about the rest */ 10335c4bbdfSmrg 10435c4bbdfSmrg axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); 10535c4bbdfSmrg axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); 10635c4bbdfSmrg axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL); 10735c4bbdfSmrg axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL); 10835c4bbdfSmrg 10935c4bbdfSmrg if (!InitPointerDeviceStruct 11035c4bbdfSmrg ((DevicePtr) pDev, map, NBUTTONS, btn_labels, 11135c4bbdfSmrg (PtrCtrlProcPtr) NoopDDA, GetMotionHistorySize(), NAXES, 11235c4bbdfSmrg axes_labels)) { 11335c4bbdfSmrg ErrorF("Could not initialize device '%s'. Out of memory.\n", 11435c4bbdfSmrg pDev->name); 11535c4bbdfSmrg return BadAlloc; 11635c4bbdfSmrg } 11735c4bbdfSmrg pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; 11835c4bbdfSmrg pDev->last.valuators[0] = pDev->valuator->axisVal[0]; 11935c4bbdfSmrg pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; 12035c4bbdfSmrg pDev->last.valuators[1] = pDev->valuator->axisVal[1]; 12135c4bbdfSmrg 12235c4bbdfSmrg /* protocol-xiquerydevice.c relies on these increment */ 12335c4bbdfSmrg SetScrollValuator(pDev, 2, SCROLL_TYPE_VERTICAL, 2.4, SCROLL_FLAG_NONE); 12435c4bbdfSmrg SetScrollValuator(pDev, 3, SCROLL_TYPE_HORIZONTAL, 3.5, 12535c4bbdfSmrg SCROLL_FLAG_PREFERRED); 12635c4bbdfSmrg break; 12735c4bbdfSmrg 12835c4bbdfSmrg case DEVICE_CLOSE: 12935c4bbdfSmrg break; 13035c4bbdfSmrg 13135c4bbdfSmrg default: 13235c4bbdfSmrg break; 13335c4bbdfSmrg } 13435c4bbdfSmrg 13535c4bbdfSmrg return Success; 13635c4bbdfSmrg 13735c4bbdfSmrg#undef NBUTTONS 13835c4bbdfSmrg#undef NAXES 13935c4bbdfSmrg} 14035c4bbdfSmrg 1416747b715Smrg/** 1426747b715Smrg * Create and init 2 master devices (VCP + VCK) and two slave devices, one 1436747b715Smrg * default mouse, one default keyboard. 1446747b715Smrg */ 14535c4bbdfSmrgstruct devices 14635c4bbdfSmrginit_devices(void) 1476747b715Smrg{ 1486747b715Smrg ClientRec client; 14935c4bbdfSmrg struct devices local_devices; 15035c4bbdfSmrg int ret; 15135c4bbdfSmrg 15235c4bbdfSmrg /* 15335c4bbdfSmrg * Put a unique name in display pointer so that when tests are run in 15435c4bbdfSmrg * parallel, their xkbcomp outputs to /tmp/server-<display>.xkm don't 15535c4bbdfSmrg * stomp on each other. 15635c4bbdfSmrg */ 15735c4bbdfSmrg#ifdef HAVE_GETPROGNAME 15835c4bbdfSmrg display = getprogname(); 15935c4bbdfSmrg#elif HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME 16035c4bbdfSmrg display = program_invocation_short_name; 16135c4bbdfSmrg#endif 1626747b715Smrg 1636747b715Smrg client = init_client(0, NULL); 1646747b715Smrg 16535c4bbdfSmrg AllocDevicePair(&client, "Virtual core", &local_devices.vcp, &local_devices.vck, 1666747b715Smrg CorePointerProc, CoreKeyboardProc, TRUE); 16735c4bbdfSmrg inputInfo.pointer = local_devices.vcp; 1686747b715Smrg 16935c4bbdfSmrg inputInfo.keyboard = local_devices.vck; 17035c4bbdfSmrg ret = ActivateDevice(local_devices.vcp, FALSE); 17135c4bbdfSmrg assert(ret == Success); 17235c4bbdfSmrg /* This may fail if xkbcomp fails or xkb-config is not found. */ 17335c4bbdfSmrg ret = ActivateDevice(local_devices.vck, FALSE); 17435c4bbdfSmrg assert(ret == Success); 17535c4bbdfSmrg EnableDevice(local_devices.vcp, FALSE); 17635c4bbdfSmrg EnableDevice(local_devices.vck, FALSE); 17735c4bbdfSmrg 17835c4bbdfSmrg AllocDevicePair(&client, "", &local_devices.mouse, &local_devices.kbd, 17935c4bbdfSmrg TestPointerProc, CoreKeyboardProc, FALSE); 18035c4bbdfSmrg ret = ActivateDevice(local_devices.mouse, FALSE); 18135c4bbdfSmrg assert(ret == Success); 18235c4bbdfSmrg ret = ActivateDevice(local_devices.kbd, FALSE); 18335c4bbdfSmrg assert(ret == Success); 18435c4bbdfSmrg EnableDevice(local_devices.mouse, FALSE); 18535c4bbdfSmrg EnableDevice(local_devices.kbd, FALSE); 18635c4bbdfSmrg 18735c4bbdfSmrg local_devices.num_devices = 4; 18835c4bbdfSmrg local_devices.num_master_devices = 2; 18935c4bbdfSmrg 19035c4bbdfSmrg fake_init_sprite(local_devices.mouse); 19135c4bbdfSmrg fake_init_sprite(local_devices.vcp); 19235c4bbdfSmrg 19335c4bbdfSmrg return local_devices; 19435c4bbdfSmrg} 1956747b715Smrg 1966747b715Smrg/* Create minimal client, with the given buffer and len as request buffer */ 19735c4bbdfSmrgClientRec 19835c4bbdfSmrginit_client(int len, void *data) 1996747b715Smrg{ 2006747b715Smrg ClientRec client = { 0 }; 2016747b715Smrg 2026747b715Smrg /* we store the privates now and reassign it after the memset. this way 2036747b715Smrg * we can share them across multiple test runs and don't have to worry 2046747b715Smrg * about freeing them after each test run. */ 2056747b715Smrg 2066747b715Smrg client.index = CLIENT_INDEX; 2076747b715Smrg client.clientAsMask = CLIENT_MASK; 2086747b715Smrg client.sequence = CLIENT_SEQUENCE; 2096747b715Smrg client.req_len = len; 2106747b715Smrg 2116747b715Smrg client.requestBuffer = data; 2126747b715Smrg dixAllocatePrivates(&client.devPrivates, PRIVATE_CLIENT); 2136747b715Smrg return client; 2146747b715Smrg} 2156747b715Smrg 21635c4bbdfSmrgvoid 21735c4bbdfSmrginit_window(WindowPtr local_window, WindowPtr parent, int id) 2186747b715Smrg{ 21935c4bbdfSmrg memset(local_window, 0, sizeof(*local_window)); 22035c4bbdfSmrg 22135c4bbdfSmrg local_window->drawable.id = id; 22235c4bbdfSmrg if (parent) { 22335c4bbdfSmrg local_window->drawable.x = 30; 22435c4bbdfSmrg local_window->drawable.y = 50; 22535c4bbdfSmrg local_window->drawable.width = 100; 22635c4bbdfSmrg local_window->drawable.height = 200; 2276747b715Smrg } 22835c4bbdfSmrg local_window->parent = parent; 22935c4bbdfSmrg local_window->optional = calloc(1, sizeof(WindowOptRec)); 23035c4bbdfSmrg assert(local_window->optional); 2316747b715Smrg} 2326747b715Smrg 2336747b715Smrgextern DevPrivateKeyRec miPointerScreenKeyRec; 2346747b715Smrgextern DevPrivateKeyRec miPointerPrivKeyRec; 2356747b715Smrg 2366747b715Smrg/* Needed for the screen setup, otherwise we crash during sprite initialization */ 23735c4bbdfSmrgstatic Bool 23835c4bbdfSmrgdevice_cursor_init(DeviceIntPtr dev, ScreenPtr local_screen) 23935c4bbdfSmrg{ 24035c4bbdfSmrg return TRUE; 24135c4bbdfSmrg} 24235c4bbdfSmrg 24335c4bbdfSmrgstatic void 24435c4bbdfSmrgdevice_cursor_cleanup(DeviceIntPtr dev, ScreenPtr local_screen) 24535c4bbdfSmrg{ 24635c4bbdfSmrg} 24735c4bbdfSmrg 24835c4bbdfSmrgstatic Bool 24935c4bbdfSmrgset_cursor_pos(DeviceIntPtr dev, ScreenPtr local_screen, int x, int y, Bool event) 25035c4bbdfSmrg{ 25135c4bbdfSmrg return TRUE; 25235c4bbdfSmrg} 25335c4bbdfSmrg 25435c4bbdfSmrgvoid 25535c4bbdfSmrginit_simple(void) 2566747b715Smrg{ 2576747b715Smrg screenInfo.numScreens = 1; 2586747b715Smrg screenInfo.screens[0] = &screen; 2596747b715Smrg 2606747b715Smrg screen.myNum = 0; 2616747b715Smrg screen.id = 100; 2626747b715Smrg screen.width = 640; 2636747b715Smrg screen.height = 480; 2646747b715Smrg screen.DeviceCursorInitialize = device_cursor_init; 26535c4bbdfSmrg screen.DeviceCursorCleanup = device_cursor_cleanup; 2666747b715Smrg screen.SetCursorPosition = set_cursor_pos; 267e23ec014Smrg screen.root = &root; 2686747b715Smrg 2696747b715Smrg dixResetPrivates(); 2706747b715Smrg InitAtoms(); 2716747b715Smrg XkbInitPrivates(); 27235c4bbdfSmrg dixRegisterPrivateKey(&XIClientPrivateKeyRec, PRIVATE_CLIENT, 27335c4bbdfSmrg sizeof(XIClientRec)); 2746747b715Smrg dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0); 2756747b715Smrg dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0); 2766747b715Smrg XInputExtensionInit(); 2776747b715Smrg 2786747b715Smrg init_window(&root, NULL, ROOT_WINDOW_ID); 2796747b715Smrg init_window(&window, &root, CLIENT_WINDOW_ID); 2806747b715Smrg 28135c4bbdfSmrg serverClient = &server_client; 28235c4bbdfSmrg InitClient(serverClient, 0, (void *) NULL); 28335c4bbdfSmrg if (!InitClientResources(serverClient)) /* for root resources */ 28435c4bbdfSmrg FatalError("couldn't init server resources"); 28535c4bbdfSmrg SyncExtensionInit(); 28635c4bbdfSmrg 2876747b715Smrg devices = init_devices(); 2886747b715Smrg} 2896747b715Smrg 29035c4bbdfSmrgvoid 29135c4bbdfSmrg__wrap_WriteToClient(ClientPtr client, int len, void *data) 2926747b715Smrg{ 29335c4bbdfSmrg assert(reply_handler != NULL); 2946747b715Smrg 29535c4bbdfSmrg (*reply_handler) (client, len, data, global_userdata); 2966747b715Smrg} 2971b5d61b8Smrg 2981b5d61b8Smrg/* dixLookupWindow requires a lot of setup not necessary for this test. 2991b5d61b8Smrg * Simple wrapper that returns either one of the fake root window or the 3001b5d61b8Smrg * fake client window. If the requested ID is neither of those wanted, 3011b5d61b8Smrg * return whatever the real dixLookupWindow does. 3021b5d61b8Smrg */ 3031b5d61b8Smrgint 3041b5d61b8Smrg__wrap_dixLookupWindow(WindowPtr *win, XID id, ClientPtr client, Mask access) 3051b5d61b8Smrg{ 3061b5d61b8Smrg if (id == root.drawable.id) { 3071b5d61b8Smrg *win = &root; 3081b5d61b8Smrg return Success; 3091b5d61b8Smrg } 3101b5d61b8Smrg else if (id == window.drawable.id) { 3111b5d61b8Smrg *win = &window; 3121b5d61b8Smrg return Success; 3131b5d61b8Smrg } 3141b5d61b8Smrg 3151b5d61b8Smrg return __real_dixLookupWindow(win, id, client, access); 3161b5d61b8Smrg} 3171b5d61b8Smrg 3181b5d61b8Smrgextern ClientRec client_window; 3191b5d61b8Smrg 3201b5d61b8Smrgint 3211b5d61b8Smrg__wrap_dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, 3221b5d61b8Smrg Mask access) 3231b5d61b8Smrg{ 3241b5d61b8Smrg if (rid == ROOT_WINDOW_ID) 3251b5d61b8Smrg return BadWindow; 3261b5d61b8Smrg 3271b5d61b8Smrg if (rid == CLIENT_WINDOW_ID) { 3281b5d61b8Smrg *pClient = &client_window; 3291b5d61b8Smrg return Success; 3301b5d61b8Smrg } 3311b5d61b8Smrg 3321b5d61b8Smrg return __real_dixLookupClient(pClient, rid, client, access); 3331b5d61b8Smrg} 334