diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2012-12-12 15:41:32 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2012-12-18 08:28:02 +1000 |
commit | f71c2f895c9e2f9d0d42feaac2a3e1d2deb71f67 (patch) | |
tree | 11697b10e13eb7d86eb99ff2e14dddb8c65af7a0 /Xi | |
parent | cc10ac8f0e07854647e1fd7cc70b7e9f8d919fd1 (diff) |
Xi: fix per-device barrier handling
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Jasper St. Pierre <jstpierre@mecheye.net>
Diffstat (limited to 'Xi')
-rw-r--r-- | Xi/xibarriers.c | 235 | ||||
-rw-r--r-- | Xi/xibarriers.h | 3 | ||||
-rw-r--r-- | Xi/xichangehierarchy.c | 6 |
3 files changed, 195 insertions, 49 deletions
diff --git a/Xi/xibarriers.c b/Xi/xibarriers.c index 048af62a2..7e8b2e6cd 100644 --- a/Xi/xibarriers.c +++ b/Xi/xibarriers.c @@ -67,19 +67,28 @@ static DevPrivateKeyRec BarrierScreenPrivateKeyRec; typedef struct PointerBarrierClient *PointerBarrierClientPtr; +struct PointerBarrierDevice { + struct xorg_list entry; + int deviceid; + Time last_timestamp; + int barrier_event_id; + int release_event_id; + Bool hit; + Bool seen; +}; + struct PointerBarrierClient { XID id; ScreenPtr screen; WindowPtr window; struct PointerBarrier barrier; struct xorg_list entry; + /* num_devices/device_ids are devices the barrier applies to */ int num_devices; int *device_ids; /* num_devices */ - Time last_timestamp; - int barrier_event_id; - int release_event_id; - Bool hit; - Bool seen; + + /* per_device keeps track of devices actually blocked by barriers */ + struct xorg_list per_device; }; typedef struct _BarrierScreen { @@ -90,6 +99,47 @@ typedef struct _BarrierScreen { #define GetBarrierScreenIfSet(s) GetBarrierScreen(s) #define SetBarrierScreen(s,p) dixSetPrivate(&(s)->devPrivates, BarrierScreenPrivateKey, p) +static struct PointerBarrierDevice *AllocBarrierDevice(void) +{ + struct PointerBarrierDevice *pbd = NULL; + + pbd = malloc(sizeof(struct PointerBarrierDevice)); + if (!pbd) + return NULL; + + pbd->deviceid = -1; /* must be set by caller */ + pbd->barrier_event_id = 1; + pbd->release_event_id = 0; + pbd->hit = FALSE; + pbd->seen = FALSE; + xorg_list_init(&pbd->entry); + + return pbd; +} + +static void FreePointerBarrierClient(struct PointerBarrierClient *c) +{ + struct PointerBarrierDevice *pbd = NULL, *tmp = NULL; + + xorg_list_for_each_entry_safe(pbd, tmp, &c->per_device, entry) { + free(pbd); + } + free(c); +} + +static struct PointerBarrierDevice *GetBarrierDevice(struct PointerBarrierClient *c, int deviceid) +{ + struct PointerBarrierDevice *pbd = NULL; + + xorg_list_for_each_entry(pbd, &c->per_device, entry) { + if (pbd->deviceid == deviceid) + break; + } + + BUG_WARN(!pbd); + return pbd; +} + static BOOL barrier_is_horizontal(const struct PointerBarrier *barrier) { @@ -283,9 +333,11 @@ barrier_find_nearest(BarrierScreenPtr cs, DeviceIntPtr dev, xorg_list_for_each_entry(c, &cs->barriers, entry) { struct PointerBarrier *b = &c->barrier; + struct PointerBarrierDevice *pbd; double distance; - if (c->seen) + pbd = GetBarrierDevice(c, dev->id); + if (pbd->seen) continue; if (!barrier_is_blocking_direction(b, dir)) @@ -358,6 +410,7 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen, .root = screen->root->drawable.id, }; InternalEvent *barrier_events = events; + DeviceIntPtr master; if (nevents) *nevents = 0; @@ -365,6 +418,13 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen, if (xorg_list_is_empty(&cs->barriers) || IsFloating(dev)) goto out; + /** + * This function is only called for slave devices, but pointer-barriers + * are for master-devices only. Flip the device to the master here, + * continue with that. + */ + master = GetMaster(dev, MASTER_POINTER); + /* How this works: * Given the origin and the movement vector, get the nearest barrier * to the origin that is blocking the movement. @@ -375,16 +435,19 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen, dir = barrier_get_direction(current_x, current_y, x, y); while (dir != 0) { - c = barrier_find_nearest(cs, dev, dir, current_x, current_y, x, y); + struct PointerBarrierDevice *pbd; + + c = barrier_find_nearest(cs, master, dir, current_x, current_y, x, y); if (!c) break; nearest = &c->barrier; - c->seen = TRUE; - c->hit = TRUE; + pbd = GetBarrierDevice(c, master->id); + pbd->seen = TRUE; + pbd->hit = TRUE; - if (c->barrier_event_id == c->release_event_id) + if (pbd->barrier_event_id == pbd->release_event_id) continue; ev.type = ET_BarrierHit; @@ -400,12 +463,12 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen, } ev.flags = 0; - ev.event_id = c->barrier_event_id; + ev.event_id = pbd->barrier_event_id; ev.barrierid = c->id; - ev.dt = ms - c->last_timestamp; + ev.dt = ms - pbd->last_timestamp; ev.window = c->window->drawable.id; - c->last_timestamp = ms; + pbd->last_timestamp = ms; /* root x/y is filled in later */ @@ -415,28 +478,31 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen, } xorg_list_for_each_entry(c, &cs->barriers, entry) { + struct PointerBarrierDevice *pbd; int flags = 0; - c->seen = FALSE; - if (!c->hit) + + pbd = GetBarrierDevice(c, master->id); + pbd->seen = FALSE; + if (!pbd->hit) continue; if (barrier_inside_hit_box(&c->barrier, x, y)) continue; - c->hit = FALSE; + pbd->hit = FALSE; ev.type = ET_BarrierLeave; - if (c->barrier_event_id == c->release_event_id) + if (pbd->barrier_event_id == pbd->release_event_id) flags |= XIBarrierPointerReleased; ev.flags = flags; - ev.event_id = c->barrier_event_id; + ev.event_id = pbd->barrier_event_id; ev.barrierid = c->id; - ev.dt = ms - c->last_timestamp; + ev.dt = ms - pbd->last_timestamp; ev.window = c->window->drawable.id; - c->last_timestamp = ms; + pbd->last_timestamp = ms; /* root x/y is filled in later */ @@ -446,7 +512,7 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen, /* If we've left the hit box, this is the * start of a new event ID. */ - c->barrier_event_id++; + pbd->barrier_event_id++; } out: @@ -479,6 +545,7 @@ CreatePointerBarrierClient(ClientPtr client, int i; struct PointerBarrierClient *ret; CARD16 *in_devices; + DeviceIntPtr dev; size = sizeof(*ret) + sizeof(DeviceIntPtr) * stuff->num_devices; ret = malloc(size); @@ -487,6 +554,8 @@ CreatePointerBarrierClient(ClientPtr client, return BadAlloc; } + xorg_list_init(&ret->per_device); + err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); if (err != Success) { client->errorValue = stuff->window; @@ -524,11 +593,25 @@ CreatePointerBarrierClient(ClientPtr client, ret->device_ids[i] = device_id; } + /* Alloc one per master pointer, they're the ones that can be blocked */ + xorg_list_init(&ret->per_device); + nt_list_for_each_entry(dev, inputInfo.devices, next) { + struct PointerBarrierDevice *pbd; + + if (dev->type != MASTER_POINTER) + continue; + + pbd = AllocBarrierDevice(); + if (!pbd) { + err = BadAlloc; + goto error; + } + pbd->deviceid = dev->id; + + xorg_list_add(&pbd->entry, &ret->per_device); + } + ret->id = stuff->barrier; - ret->barrier_event_id = 1; - ret->release_event_id = 0; - ret->hit = FALSE; - ret->seen = FALSE; ret->barrier.x1 = stuff->x1; ret->barrier.x2 = stuff->x2; ret->barrier.y1 = stuff->y1; @@ -547,7 +630,7 @@ CreatePointerBarrierClient(ClientPtr client, error: *client_out = NULL; - free(ret); + FreePointerBarrierClient(ret); return err; } @@ -556,13 +639,15 @@ BarrierFreeBarrier(void *data, XID id) { struct PointerBarrierClient *c; Time ms = GetTimeInMillis(); + DeviceIntPtr dev = NULL; + ScreenPtr screen; c = container_of(data, struct PointerBarrierClient, barrier); + screen = c->screen; - /* FIXME: this is really broken for multidevice */ - if (c->hit) { - DeviceIntPtr dev = NULL; - ScreenPtr screen = c->screen; + for (dev = inputInfo.devices; dev; dev = dev->next) { + struct PointerBarrierDevice *pbd; + int root_x, root_y; BarrierEvent ev = { .header = ET_Internal, .type = ET_BarrierLeave, @@ -577,36 +662,79 @@ BarrierFreeBarrier(void *data, XID id) .dy = 0, /* .root_x */ /* .root_y */ - .dt = ms - c->last_timestamp, - .event_id = c->barrier_event_id, + /* .dt */ + /* .event_id */ .flags = XIBarrierPointerReleased, }; - for (dev = inputInfo.devices; dev; dev = dev->next) { - int root_x, root_y; - if (dev->type != MASTER_POINTER) - continue; + if (dev->type != MASTER_POINTER) + continue; - if (!barrier_blocks_device(c, dev)) - continue; + pbd = GetBarrierDevice(c, dev->id); + if (!pbd->hit) + continue; - ev.deviceid = dev->id; + ev.deviceid = dev->id; + ev.event_id = pbd->barrier_event_id, + ev.dt = ms - pbd->last_timestamp, - GetSpritePosition(dev, &root_x, &root_y); - ev.root_x = root_x; - ev.root_y = root_y; + GetSpritePosition(dev, &root_x, &root_y); + ev.root_x = root_x; + ev.root_y = root_y; - mieqEnqueue(dev, (InternalEvent *) &ev); - } + mieqEnqueue(dev, (InternalEvent *) &ev); } xorg_list_del(&c->entry); - free(c); + FreePointerBarrierClient(c); return Success; } +static void add_master_func(pointer res, XID id, pointer devid) +{ + struct PointerBarrier *b; + struct PointerBarrierClient *barrier; + struct PointerBarrierDevice *pbd; + int *deviceid = devid; + + b = res; + barrier = container_of(b, struct PointerBarrierClient, barrier); + + + pbd = AllocBarrierDevice(); + pbd->deviceid = *deviceid; + + xorg_list_add(&pbd->entry, &barrier->per_device); +} + +static void remove_master_func(pointer res, XID id, pointer devid) +{ + struct PointerBarrierDevice *pbd; + struct PointerBarrierClient *barrier; + struct PointerBarrier *b; + int *deviceid = devid; + + b = res; + barrier = container_of(b, struct PointerBarrierClient, barrier); + + pbd = GetBarrierDevice(barrier, *deviceid); + xorg_list_del(&pbd->entry); + free(pbd); +} + +void XIBarrierNewMasterDevice(ClientPtr client, int deviceid) +{ + FindClientResourcesByType(client, PointerBarrierType, add_master_func, &deviceid); +} + +void XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid) +{ + /* FIXME: send LeaveNotify */ + FindClientResourcesByType(client, PointerBarrierType, remove_master_func, &deviceid); +} + int XICreatePointerBarrier(ClientPtr client, xXFixesCreatePointerBarrierReq * stuff) @@ -698,14 +826,19 @@ ProcXIBarrierReleasePointer(ClientPtr client) info = (xXIBarrierReleasePointerInfo*) &stuff[1]; for (i = 0; i < stuff->num_barriers; i++, info++) { + struct PointerBarrierDevice *pbd; + DeviceIntPtr dev; CARD32 barrier_id, event_id; _X_UNUSED CARD32 device_id; barrier_id = info->barrier; event_id = info->eventid; - /* FIXME: per-device releases */ - device_id = info->deviceid; + err = dixLookupDevice(&dev, info->deviceid, client, DixReadAccess); + if (err != Success) { + client->errorValue = BadDevice; + return err; + } err = dixLookupResourceByType((void **) &b, barrier_id, PointerBarrierType, client, DixReadAccess); @@ -717,9 +850,13 @@ ProcXIBarrierReleasePointer(ClientPtr client) if (CLIENT_ID(barrier_id) != client->index) return BadAccess; + barrier = container_of(b, struct PointerBarrierClient, barrier); - if (barrier->barrier_event_id == event_id) - barrier->release_event_id = event_id; + + pbd = GetBarrierDevice(barrier, dev->id); + + if (pbd->barrier_event_id == event_id) + pbd->release_event_id = event_id; } return Success; diff --git a/Xi/xibarriers.h b/Xi/xibarriers.h index bdcb0b289..11e84ec9f 100644 --- a/Xi/xibarriers.h +++ b/Xi/xibarriers.h @@ -42,4 +42,7 @@ XIBarrierInit(void); int SProcXIBarrierReleasePointer(ClientPtr client); int ProcXIBarrierReleasePointer(ClientPtr client); +void XIBarrierNewMasterDevice(ClientPtr client, int deviceid); +void XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid); + #endif /* _XIBARRIERS_H_ */ diff --git a/Xi/xichangehierarchy.c b/Xi/xichangehierarchy.c index 89f16d8be..a2cb832c4 100644 --- a/Xi/xichangehierarchy.c +++ b/Xi/xichangehierarchy.c @@ -52,6 +52,7 @@ #include "xkbsrv.h" #include "xichangehierarchy.h" +#include "xibarriers.h" /** * Send the current state of the device hierarchy to all clients. @@ -189,6 +190,8 @@ add_master(ClientPtr client, xXIAddMasterInfo * c, int flags[MAXDEVICES]) flags[XTestptr->id] |= XISlaveAttached; flags[XTestkeybd->id] |= XISlaveAttached; + XIBarrierNewMasterDevice(client, ptr->id); + unwind: free(name); return rc; @@ -293,6 +296,8 @@ remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES]) } } + XIBarrierRemoveMasterDevice(client, ptr->id); + /* disable the remove the devices, XTest devices must be done first else the sprites they rely on will be destroyed */ DisableDevice(XTestptr, FALSE); @@ -313,6 +318,7 @@ remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES]) flags[keybd->id] |= XIMasterRemoved; flags[ptr->id] |= XIMasterRemoved; + unwind: return rc; } |