Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /************************************************************ |
2 | Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. | |
3 | ||
4 | Permission to use, copy, modify, and distribute this | |
5 | software and its documentation for any purpose and without | |
6 | fee is hereby granted, provided that the above copyright | |
7 | notice appear in all copies and that both that copyright | |
8 | notice and this permission notice appear in supporting | |
9 | documentation, and that the name of Silicon Graphics not be | |
10 | used in advertising or publicity pertaining to distribution | |
11 | of the software without specific prior written permission. | |
12 | Silicon Graphics makes no representation about the suitability | |
13 | of this software for any purpose. It is provided "as is" | |
14 | without any express or implied warranty. | |
15 | ||
16 | SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS | |
17 | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |
18 | AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON | |
19 | GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL | |
20 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |
21 | DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | |
22 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH | |
23 | THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
24 | ||
25 | ********************************************************/ | |
26 | ||
27 | #ifdef HAVE_DIX_CONFIG_H | |
28 | #include <dix-config.h> | |
29 | #endif | |
30 | ||
31 | #include <stdio.h> | |
32 | #include <X11/X.h> | |
33 | #include <X11/Xproto.h> | |
34 | #include <X11/keysym.h> | |
35 | #include <X11/extensions/XI.h> | |
36 | #include <X11/extensions/XIproto.h> | |
37 | #include "inputstr.h" | |
38 | #include "exevents.h" | |
39 | #include "exglobals.h" | |
40 | #include "windowstr.h" | |
41 | #include <xkbsrv.h> | |
42 | #include "xkb.h" | |
43 | ||
44 | /***====================================================================***/ | |
45 | ||
46 | /* | |
47 | * This function sends out two kinds of notification: | |
48 | * - Core mapping notify events sent to clients for whom kbd is the | |
49 | * current core ('picked') keyboard _and_ have not explicitly | |
50 | * selected for XKB mapping notify events; | |
51 | * - Xi mapping events, sent unconditionally to all clients who have | |
52 | * explicitly selected for them (including those who have explicitly | |
53 | * selected for XKB mapping notify events!). | |
54 | */ | |
55 | static void | |
56 | XkbSendLegacyMapNotify(DeviceIntPtr kbd, CARD16 xkb_event, CARD16 changed, | |
57 | int first_key, int num_keys) | |
58 | { | |
59 | int i; | |
60 | int keymap_changed = 0; | |
61 | int modmap_changed = 0; | |
62 | CARD32 time = GetTimeInMillis(); | |
63 | ||
64 | if (xkb_event == XkbNewKeyboardNotify) { | |
65 | if (changed & XkbNKN_KeycodesMask) { | |
66 | keymap_changed = 1; | |
67 | modmap_changed = 1; | |
68 | } | |
69 | } | |
70 | else if (xkb_event == XkbMapNotify) { | |
71 | if (changed & XkbKeySymsMask) | |
72 | keymap_changed = 1; | |
73 | if (changed & XkbModifierMapMask) | |
74 | modmap_changed = 1; | |
75 | } | |
76 | if (!keymap_changed && !modmap_changed) | |
77 | return; | |
78 | ||
79 | /* 0 is serverClient. */ | |
80 | for (i = 1; i < currentMaxClients; i++) { | |
81 | if (!clients[i] || clients[i]->clientState != ClientStateRunning) | |
82 | continue; | |
83 | ||
84 | /* XKB allows clients to restrict the MappingNotify events sent to | |
85 | * them. This was broken for three years. Sorry. */ | |
86 | if (xkb_event == XkbMapNotify && | |
87 | (clients[i]->xkbClientFlags & _XkbClientInitialized) && | |
88 | !(clients[i]->mapNotifyMask & changed)) | |
89 | continue; | |
90 | /* Emulate previous server behaviour: any client which has activated | |
91 | * XKB will not receive core events emulated from a NewKeyboardNotify | |
92 | * at all. */ | |
93 | if (xkb_event == XkbNewKeyboardNotify && | |
94 | (clients[i]->xkbClientFlags & _XkbClientInitialized)) | |
95 | continue; | |
96 | ||
97 | /* Don't send core events to clients who don't know about us. */ | |
98 | if (!XIShouldNotify(clients[i], kbd)) | |
99 | continue; | |
100 | ||
101 | if (keymap_changed) { | |
102 | xEvent core_mn = { .u.u.type = MappingNotify }; | |
103 | core_mn.u.mappingNotify.request = MappingKeyboard; | |
104 | ||
105 | /* Clip the keycode range to what the client knows about, so it | |
106 | * doesn't freak out. */ | |
107 | if (first_key >= clients[i]->minKC) | |
108 | core_mn.u.mappingNotify.firstKeyCode = first_key; | |
109 | else | |
110 | core_mn.u.mappingNotify.firstKeyCode = clients[i]->minKC; | |
111 | if (first_key + num_keys - 1 <= clients[i]->maxKC) | |
112 | core_mn.u.mappingNotify.count = num_keys; | |
113 | else | |
114 | core_mn.u.mappingNotify.count = clients[i]->maxKC - | |
115 | clients[i]->minKC + 1; | |
116 | ||
117 | WriteEventsToClient(clients[i], 1, &core_mn); | |
118 | } | |
119 | if (modmap_changed) { | |
120 | xEvent core_mn = { | |
121 | .u.mappingNotify.request = MappingModifier, | |
122 | .u.mappingNotify.firstKeyCode = 0, | |
123 | .u.mappingNotify.count = 0 | |
124 | }; | |
125 | core_mn.u.u.type = MappingNotify; | |
126 | WriteEventsToClient(clients[i], 1, &core_mn); | |
127 | } | |
128 | } | |
129 | ||
130 | /* Hmm, maybe we can accidentally generate Xi events for core devices | |
131 | * here? Clients might be upset, but that seems better than the | |
132 | * alternative of stale keymaps. -ds */ | |
133 | if (keymap_changed) { | |
134 | deviceMappingNotify xi_mn = { | |
135 | .type = DeviceMappingNotify, | |
136 | .deviceid = kbd->id, | |
137 | .request = MappingKeyboard, | |
138 | .firstKeyCode = first_key, | |
139 | .count = num_keys, | |
140 | .time = time | |
141 | }; | |
142 | SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn, | |
143 | 1); | |
144 | } | |
145 | if (modmap_changed) { | |
146 | deviceMappingNotify xi_mn = { | |
147 | .type = DeviceMappingNotify, | |
148 | .deviceid = kbd->id, | |
149 | .request = MappingModifier, | |
150 | .firstKeyCode = 0, | |
151 | .count = 0, | |
152 | .time = time | |
153 | }; | |
154 | SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn, | |
155 | 1); | |
156 | } | |
157 | } | |
158 | ||
159 | /***====================================================================***/ | |
160 | ||
161 | void | |
162 | XkbSendNewKeyboardNotify(DeviceIntPtr kbd, xkbNewKeyboardNotify * pNKN) | |
163 | { | |
164 | int i; | |
165 | Time time = GetTimeInMillis(); | |
166 | CARD16 changed = pNKN->changed; | |
167 | ||
168 | pNKN->type = XkbEventCode + XkbEventBase; | |
169 | pNKN->xkbType = XkbNewKeyboardNotify; | |
170 | ||
171 | for (i = 1; i < currentMaxClients; i++) { | |
172 | if (!clients[i] || clients[i]->clientState != ClientStateRunning) | |
173 | continue; | |
174 | ||
175 | if (!(clients[i]->newKeyboardNotifyMask & changed)) | |
176 | continue; | |
177 | ||
178 | pNKN->sequenceNumber = clients[i]->sequence; | |
179 | pNKN->time = time; | |
180 | pNKN->changed = changed; | |
181 | if (clients[i]->swapped) { | |
182 | swaps(&pNKN->sequenceNumber); | |
183 | swapl(&pNKN->time); | |
184 | swaps(&pNKN->changed); | |
185 | } | |
186 | WriteToClient(clients[i], sizeof(xEvent), pNKN); | |
187 | ||
188 | if (changed & XkbNKN_KeycodesMask) { | |
189 | clients[i]->minKC = pNKN->minKeyCode; | |
190 | clients[i]->maxKC = pNKN->maxKeyCode; | |
191 | } | |
192 | } | |
193 | ||
194 | XkbSendLegacyMapNotify(kbd, XkbNewKeyboardNotify, changed, pNKN->minKeyCode, | |
195 | pNKN->maxKeyCode - pNKN->minKeyCode + 1); | |
196 | ||
197 | return; | |
198 | } | |
199 | ||
200 | /***====================================================================***/ | |
201 | ||
202 | void | |
203 | XkbSendStateNotify(DeviceIntPtr kbd, xkbStateNotify * pSN) | |
204 | { | |
205 | XkbSrvInfoPtr xkbi; | |
206 | XkbStatePtr state; | |
207 | XkbInterestPtr interest; | |
208 | Time time; | |
209 | register CARD16 changed, bState; | |
210 | ||
211 | interest = kbd->xkb_interest; | |
212 | if (!interest || !kbd->key || !kbd->key->xkbInfo) | |
213 | return; | |
214 | xkbi = kbd->key->xkbInfo; | |
215 | state = &xkbi->state; | |
216 | ||
217 | pSN->type = XkbEventCode + XkbEventBase; | |
218 | pSN->xkbType = XkbStateNotify; | |
219 | pSN->deviceID = kbd->id; | |
220 | pSN->time = time = GetTimeInMillis(); | |
221 | pSN->mods = state->mods; | |
222 | pSN->baseMods = state->base_mods; | |
223 | pSN->latchedMods = state->latched_mods; | |
224 | pSN->lockedMods = state->locked_mods; | |
225 | pSN->group = state->group; | |
226 | pSN->baseGroup = state->base_group; | |
227 | pSN->latchedGroup = state->latched_group; | |
228 | pSN->lockedGroup = state->locked_group; | |
229 | pSN->compatState = state->compat_state; | |
230 | pSN->grabMods = state->grab_mods; | |
231 | pSN->compatGrabMods = state->compat_grab_mods; | |
232 | pSN->lookupMods = state->lookup_mods; | |
233 | pSN->compatLookupMods = state->compat_lookup_mods; | |
234 | pSN->ptrBtnState = state->ptr_buttons; | |
235 | changed = pSN->changed; | |
236 | bState = pSN->ptrBtnState; | |
237 | ||
238 | while (interest) { | |
239 | if ((!interest->client->clientGone) && | |
240 | (interest->client->requestVector != InitialVector) && | |
241 | (interest->client->xkbClientFlags & _XkbClientInitialized) && | |
242 | (interest->stateNotifyMask & changed)) { | |
243 | pSN->sequenceNumber = interest->client->sequence; | |
244 | pSN->time = time; | |
245 | pSN->changed = changed; | |
246 | pSN->ptrBtnState = bState; | |
247 | if (interest->client->swapped) { | |
248 | swaps(&pSN->sequenceNumber); | |
249 | swapl(&pSN->time); | |
250 | swaps(&pSN->changed); | |
251 | swaps(&pSN->ptrBtnState); | |
252 | } | |
253 | WriteToClient(interest->client, sizeof(xEvent), pSN); | |
254 | } | |
255 | interest = interest->next; | |
256 | } | |
257 | return; | |
258 | } | |
259 | ||
260 | /***====================================================================***/ | |
261 | ||
262 | /* | |
263 | * This function sends out XKB mapping notify events to clients which | |
264 | * have explicitly selected for them. Core and Xi events are handled by | |
265 | * XkbSendLegacyMapNotify. */ | |
266 | void | |
267 | XkbSendMapNotify(DeviceIntPtr kbd, xkbMapNotify * pMN) | |
268 | { | |
269 | int i; | |
270 | CARD32 time = GetTimeInMillis(); | |
271 | CARD16 changed = pMN->changed; | |
272 | XkbSrvInfoPtr xkbi = kbd->key->xkbInfo; | |
273 | ||
274 | pMN->minKeyCode = xkbi->desc->min_key_code; | |
275 | pMN->maxKeyCode = xkbi->desc->max_key_code; | |
276 | pMN->type = XkbEventCode + XkbEventBase; | |
277 | pMN->xkbType = XkbMapNotify; | |
278 | pMN->deviceID = kbd->id; | |
279 | ||
280 | /* 0 is serverClient. */ | |
281 | for (i = 1; i < currentMaxClients; i++) { | |
282 | if (!clients[i] || clients[i]->clientState != ClientStateRunning) | |
283 | continue; | |
284 | ||
285 | if (!(clients[i]->mapNotifyMask & changed)) | |
286 | continue; | |
287 | ||
288 | pMN->time = time; | |
289 | pMN->sequenceNumber = clients[i]->sequence; | |
290 | pMN->changed = changed; | |
291 | ||
292 | if (clients[i]->swapped) { | |
293 | swaps(&pMN->sequenceNumber); | |
294 | swapl(&pMN->time); | |
295 | swaps(&pMN->changed); | |
296 | } | |
297 | WriteToClient(clients[i], sizeof(xEvent), pMN); | |
298 | } | |
299 | ||
300 | XkbSendLegacyMapNotify(kbd, XkbMapNotify, changed, pMN->firstKeySym, | |
301 | pMN->nKeySyms); | |
302 | } | |
303 | ||
304 | int | |
305 | XkbComputeControlsNotify(DeviceIntPtr kbd, | |
306 | XkbControlsPtr old, | |
307 | XkbControlsPtr new, | |
308 | xkbControlsNotify * pCN, Bool forceCtrlProc) | |
309 | { | |
310 | int i; | |
311 | CARD32 changedControls; | |
312 | ||
313 | changedControls = 0; | |
314 | ||
315 | if (!kbd || !kbd->kbdfeed) | |
316 | return 0; | |
317 | ||
318 | if (old->enabled_ctrls != new->enabled_ctrls) | |
319 | changedControls |= XkbControlsEnabledMask; | |
320 | if ((old->repeat_delay != new->repeat_delay) || | |
321 | (old->repeat_interval != new->repeat_interval)) | |
322 | changedControls |= XkbRepeatKeysMask; | |
323 | for (i = 0; i < XkbPerKeyBitArraySize; i++) | |
324 | if (old->per_key_repeat[i] != new->per_key_repeat[i]) | |
325 | changedControls |= XkbPerKeyRepeatMask; | |
326 | if (old->slow_keys_delay != new->slow_keys_delay) | |
327 | changedControls |= XkbSlowKeysMask; | |
328 | if (old->debounce_delay != new->debounce_delay) | |
329 | changedControls |= XkbBounceKeysMask; | |
330 | if ((old->mk_delay != new->mk_delay) || | |
331 | (old->mk_interval != new->mk_interval) || | |
332 | (old->mk_dflt_btn != new->mk_dflt_btn)) | |
333 | changedControls |= XkbMouseKeysMask; | |
334 | if ((old->mk_time_to_max != new->mk_time_to_max) || | |
335 | (old->mk_curve != new->mk_curve) || | |
336 | (old->mk_max_speed != new->mk_max_speed)) | |
337 | changedControls |= XkbMouseKeysAccelMask; | |
338 | if (old->ax_options != new->ax_options) | |
339 | changedControls |= XkbAccessXKeysMask; | |
340 | if ((old->ax_options ^ new->ax_options) & XkbAX_SKOptionsMask) | |
341 | changedControls |= XkbStickyKeysMask; | |
342 | if ((old->ax_options ^ new->ax_options) & XkbAX_FBOptionsMask) | |
343 | changedControls |= XkbAccessXFeedbackMask; | |
344 | if ((old->ax_timeout != new->ax_timeout) || | |
345 | (old->axt_ctrls_mask != new->axt_ctrls_mask) || | |
346 | (old->axt_ctrls_values != new->axt_ctrls_values) || | |
347 | (old->axt_opts_mask != new->axt_opts_mask) || | |
348 | (old->axt_opts_values != new->axt_opts_values)) { | |
349 | changedControls |= XkbAccessXTimeoutMask; | |
350 | } | |
351 | if ((old->internal.mask != new->internal.mask) || | |
352 | (old->internal.real_mods != new->internal.real_mods) || | |
353 | (old->internal.vmods != new->internal.vmods)) | |
354 | changedControls |= XkbInternalModsMask; | |
355 | if ((old->ignore_lock.mask != new->ignore_lock.mask) || | |
356 | (old->ignore_lock.real_mods != new->ignore_lock.real_mods) || | |
357 | (old->ignore_lock.vmods != new->ignore_lock.vmods)) | |
358 | changedControls |= XkbIgnoreLockModsMask; | |
359 | ||
360 | if (new->enabled_ctrls & XkbRepeatKeysMask) | |
361 | kbd->kbdfeed->ctrl.autoRepeat = TRUE; | |
362 | else | |
363 | kbd->kbdfeed->ctrl.autoRepeat = FALSE; | |
364 | ||
365 | if (kbd->kbdfeed && kbd->kbdfeed->CtrlProc && | |
366 | (changedControls || forceCtrlProc)) | |
367 | (*kbd->kbdfeed->CtrlProc) (kbd, &kbd->kbdfeed->ctrl); | |
368 | ||
369 | if ((!changedControls) && (old->num_groups == new->num_groups)) | |
370 | return 0; | |
371 | ||
372 | if (!kbd->xkb_interest) | |
373 | return 0; | |
374 | ||
375 | pCN->changedControls = changedControls; | |
376 | pCN->enabledControls = new->enabled_ctrls; | |
377 | pCN->enabledControlChanges = (new->enabled_ctrls ^ old->enabled_ctrls); | |
378 | pCN->numGroups = new->num_groups; | |
379 | ||
380 | return 1; | |
381 | } | |
382 | ||
383 | void | |
384 | XkbSendControlsNotify(DeviceIntPtr kbd, xkbControlsNotify * pCN) | |
385 | { | |
386 | int initialized; | |
387 | CARD32 changedControls, enabledControls, enabledChanges = 0; | |
388 | XkbSrvInfoPtr xkbi; | |
389 | XkbInterestPtr interest; | |
390 | Time time = 0; | |
391 | ||
392 | interest = kbd->xkb_interest; | |
393 | if (!interest || !kbd->key || !kbd->key->xkbInfo) | |
394 | return; | |
395 | xkbi = kbd->key->xkbInfo; | |
396 | ||
397 | initialized = 0; | |
398 | enabledControls = xkbi->desc->ctrls->enabled_ctrls; | |
399 | changedControls = pCN->changedControls; | |
400 | pCN->numGroups = xkbi->desc->ctrls->num_groups; | |
401 | while (interest) { | |
402 | if ((!interest->client->clientGone) && | |
403 | (interest->client->requestVector != InitialVector) && | |
404 | (interest->client->xkbClientFlags & _XkbClientInitialized) && | |
405 | (interest->ctrlsNotifyMask & changedControls)) { | |
406 | if (!initialized) { | |
407 | pCN->type = XkbEventCode + XkbEventBase; | |
408 | pCN->xkbType = XkbControlsNotify; | |
409 | pCN->deviceID = kbd->id; | |
410 | pCN->time = time = GetTimeInMillis(); | |
411 | enabledChanges = pCN->enabledControlChanges; | |
412 | initialized = 1; | |
413 | } | |
414 | pCN->changedControls = changedControls; | |
415 | pCN->enabledControls = enabledControls; | |
416 | pCN->enabledControlChanges = enabledChanges; | |
417 | pCN->sequenceNumber = interest->client->sequence; | |
418 | pCN->time = time; | |
419 | if (interest->client->swapped) { | |
420 | swaps(&pCN->sequenceNumber); | |
421 | swapl(&pCN->changedControls); | |
422 | swapl(&pCN->enabledControls); | |
423 | swapl(&pCN->enabledControlChanges); | |
424 | swapl(&pCN->time); | |
425 | } | |
426 | WriteToClient(interest->client, sizeof(xEvent), pCN); | |
427 | } | |
428 | interest = interest->next; | |
429 | } | |
430 | return; | |
431 | } | |
432 | ||
433 | static void | |
434 | XkbSendIndicatorNotify(DeviceIntPtr kbd, int xkbType, xkbIndicatorNotify * pEv) | |
435 | { | |
436 | int initialized; | |
437 | XkbInterestPtr interest; | |
438 | Time time = 0; | |
439 | CARD32 state, changed; | |
440 | ||
441 | interest = kbd->xkb_interest; | |
442 | if (!interest) | |
443 | return; | |
444 | ||
445 | initialized = 0; | |
446 | state = pEv->state; | |
447 | changed = pEv->changed; | |
448 | while (interest) { | |
449 | if ((!interest->client->clientGone) && | |
450 | (interest->client->requestVector != InitialVector) && | |
451 | (interest->client->xkbClientFlags & _XkbClientInitialized) && | |
452 | (((xkbType == XkbIndicatorStateNotify) && | |
453 | (interest->iStateNotifyMask & changed)) || | |
454 | ((xkbType == XkbIndicatorMapNotify) && | |
455 | (interest->iMapNotifyMask & changed)))) { | |
456 | if (!initialized) { | |
457 | pEv->type = XkbEventCode + XkbEventBase; | |
458 | pEv->xkbType = xkbType; | |
459 | pEv->deviceID = kbd->id; | |
460 | pEv->time = time = GetTimeInMillis(); | |
461 | initialized = 1; | |
462 | } | |
463 | pEv->sequenceNumber = interest->client->sequence; | |
464 | pEv->time = time; | |
465 | pEv->changed = changed; | |
466 | pEv->state = state; | |
467 | if (interest->client->swapped) { | |
468 | swaps(&pEv->sequenceNumber); | |
469 | swapl(&pEv->time); | |
470 | swapl(&pEv->changed); | |
471 | swapl(&pEv->state); | |
472 | } | |
473 | WriteToClient(interest->client, sizeof(xEvent), pEv); | |
474 | } | |
475 | interest = interest->next; | |
476 | } | |
477 | return; | |
478 | } | |
479 | ||
480 | void | |
481 | XkbHandleBell(BOOL force, | |
482 | BOOL eventOnly, | |
483 | DeviceIntPtr kbd, | |
484 | CARD8 percent, | |
485 | pointer pCtrl, | |
486 | CARD8 class, Atom name, WindowPtr pWin, ClientPtr pClient) | |
487 | { | |
488 | xkbBellNotify bn; | |
489 | int initialized; | |
490 | XkbSrvInfoPtr xkbi; | |
491 | XkbInterestPtr interest; | |
492 | CARD8 id; | |
493 | CARD16 pitch, duration; | |
494 | Time time = 0; | |
495 | XID winID = 0; | |
496 | ||
497 | if (!kbd->key || !kbd->key->xkbInfo) | |
498 | return; | |
499 | ||
500 | xkbi = kbd->key->xkbInfo; | |
501 | ||
502 | if ((force || (xkbi->desc->ctrls->enabled_ctrls & XkbAudibleBellMask)) && | |
503 | (!eventOnly)) { | |
504 | if (kbd->kbdfeed->BellProc) | |
505 | (*kbd->kbdfeed->BellProc) (percent, kbd, (pointer) pCtrl, class); | |
506 | } | |
507 | interest = kbd->xkb_interest; | |
508 | if ((!interest) || (force)) | |
509 | return; | |
510 | ||
511 | if ((class == 0) || (class == KbdFeedbackClass)) { | |
512 | KeybdCtrl *pKeyCtrl = (KeybdCtrl *) pCtrl; | |
513 | ||
514 | id = pKeyCtrl->id; | |
515 | pitch = pKeyCtrl->bell_pitch; | |
516 | duration = pKeyCtrl->bell_duration; | |
517 | } | |
518 | else if (class == BellFeedbackClass) { | |
519 | BellCtrl *pBellCtrl = (BellCtrl *) pCtrl; | |
520 | ||
521 | id = pBellCtrl->id; | |
522 | pitch = pBellCtrl->pitch; | |
523 | duration = pBellCtrl->duration; | |
524 | } | |
525 | else | |
526 | return; | |
527 | ||
528 | initialized = 0; | |
529 | while (interest) { | |
530 | if ((!interest->client->clientGone) && | |
531 | (interest->client->requestVector != InitialVector) && | |
532 | (interest->client->xkbClientFlags & _XkbClientInitialized) && | |
533 | (interest->bellNotifyMask)) { | |
534 | if (!initialized) { | |
535 | time = GetTimeInMillis(); | |
536 | bn.type = XkbEventCode + XkbEventBase; | |
537 | bn.xkbType = XkbBellNotify; | |
538 | bn.deviceID = kbd->id; | |
539 | bn.bellClass = class; | |
540 | bn.bellID = id; | |
541 | bn.percent = percent; | |
542 | bn.eventOnly = (eventOnly != 0); | |
543 | winID = (pWin ? pWin->drawable.id : None); | |
544 | initialized = 1; | |
545 | } | |
546 | bn.sequenceNumber = interest->client->sequence; | |
547 | bn.time = time; | |
548 | bn.pitch = pitch; | |
549 | bn.duration = duration; | |
550 | bn.name = name; | |
551 | bn.window = winID; | |
552 | if (interest->client->swapped) { | |
553 | swaps(&bn.sequenceNumber); | |
554 | swapl(&bn.time); | |
555 | swaps(&bn.pitch); | |
556 | swaps(&bn.duration); | |
557 | swapl(&bn.name); | |
558 | swapl(&bn.window); | |
559 | } | |
560 | WriteToClient(interest->client, sizeof(xEvent), &bn); | |
561 | } | |
562 | interest = interest->next; | |
563 | } | |
564 | return; | |
565 | } | |
566 | ||
567 | void | |
568 | XkbSendAccessXNotify(DeviceIntPtr kbd, xkbAccessXNotify * pEv) | |
569 | { | |
570 | int initialized; | |
571 | XkbInterestPtr interest; | |
572 | Time time = 0; | |
573 | CARD16 sk_delay, db_delay; | |
574 | ||
575 | interest = kbd->xkb_interest; | |
576 | if (!interest) | |
577 | return; | |
578 | ||
579 | initialized = 0; | |
580 | sk_delay = pEv->slowKeysDelay; | |
581 | db_delay = pEv->debounceDelay; | |
582 | while (interest) { | |
583 | if ((!interest->client->clientGone) && | |
584 | (interest->client->requestVector != InitialVector) && | |
585 | (interest->client->xkbClientFlags & _XkbClientInitialized) && | |
586 | (interest->accessXNotifyMask & (1 << pEv->detail))) { | |
587 | if (!initialized) { | |
588 | pEv->type = XkbEventCode + XkbEventBase; | |
589 | pEv->xkbType = XkbAccessXNotify; | |
590 | pEv->deviceID = kbd->id; | |
591 | pEv->time = time = GetTimeInMillis(); | |
592 | initialized = 1; | |
593 | } | |
594 | pEv->sequenceNumber = interest->client->sequence; | |
595 | pEv->time = time; | |
596 | pEv->slowKeysDelay = sk_delay; | |
597 | pEv->debounceDelay = db_delay; | |
598 | if (interest->client->swapped) { | |
599 | swaps(&pEv->sequenceNumber); | |
600 | swapl(&pEv->time); | |
601 | swaps(&pEv->slowKeysDelay); | |
602 | swaps(&pEv->debounceDelay); | |
603 | } | |
604 | WriteToClient(interest->client, sizeof(xEvent), pEv); | |
605 | } | |
606 | interest = interest->next; | |
607 | } | |
608 | return; | |
609 | } | |
610 | ||
611 | void | |
612 | XkbSendNamesNotify(DeviceIntPtr kbd, xkbNamesNotify * pEv) | |
613 | { | |
614 | int initialized; | |
615 | XkbInterestPtr interest; | |
616 | Time time = 0; | |
617 | CARD16 changed, changedVirtualMods; | |
618 | CARD32 changedIndicators; | |
619 | ||
620 | interest = kbd->xkb_interest; | |
621 | if (!interest) | |
622 | return; | |
623 | ||
624 | initialized = 0; | |
625 | changed = pEv->changed; | |
626 | changedIndicators = pEv->changedIndicators; | |
627 | changedVirtualMods = pEv->changedVirtualMods; | |
628 | while (interest) { | |
629 | if ((!interest->client->clientGone) && | |
630 | (interest->client->requestVector != InitialVector) && | |
631 | (interest->client->xkbClientFlags & _XkbClientInitialized) && | |
632 | (interest->namesNotifyMask & pEv->changed)) { | |
633 | if (!initialized) { | |
634 | pEv->type = XkbEventCode + XkbEventBase; | |
635 | pEv->xkbType = XkbNamesNotify; | |
636 | pEv->deviceID = kbd->id; | |
637 | pEv->time = time = GetTimeInMillis(); | |
638 | initialized = 1; | |
639 | } | |
640 | pEv->sequenceNumber = interest->client->sequence; | |
641 | pEv->time = time; | |
642 | pEv->changed = changed; | |
643 | pEv->changedIndicators = changedIndicators; | |
644 | pEv->changedVirtualMods = changedVirtualMods; | |
645 | if (interest->client->swapped) { | |
646 | swaps(&pEv->sequenceNumber); | |
647 | swapl(&pEv->time); | |
648 | swaps(&pEv->changed); | |
649 | swapl(&pEv->changedIndicators); | |
650 | swaps(&pEv->changedVirtualMods); | |
651 | } | |
652 | WriteToClient(interest->client, sizeof(xEvent), pEv); | |
653 | } | |
654 | interest = interest->next; | |
655 | } | |
656 | return; | |
657 | } | |
658 | ||
659 | void | |
660 | XkbSendCompatMapNotify(DeviceIntPtr kbd, xkbCompatMapNotify * pEv) | |
661 | { | |
662 | int initialized; | |
663 | XkbInterestPtr interest; | |
664 | Time time = 0; | |
665 | CARD16 firstSI = 0, nSI = 0, nTotalSI = 0; | |
666 | ||
667 | interest = kbd->xkb_interest; | |
668 | if (!interest) | |
669 | return; | |
670 | ||
671 | initialized = 0; | |
672 | while (interest) { | |
673 | if ((!interest->client->clientGone) && | |
674 | (interest->client->requestVector != InitialVector) && | |
675 | (interest->client->xkbClientFlags & _XkbClientInitialized) && | |
676 | (interest->compatNotifyMask)) { | |
677 | if (!initialized) { | |
678 | pEv->type = XkbEventCode + XkbEventBase; | |
679 | pEv->xkbType = XkbCompatMapNotify; | |
680 | pEv->deviceID = kbd->id; | |
681 | pEv->time = time = GetTimeInMillis(); | |
682 | firstSI = pEv->firstSI; | |
683 | nSI = pEv->nSI; | |
684 | nTotalSI = pEv->nTotalSI; | |
685 | initialized = 1; | |
686 | } | |
687 | pEv->sequenceNumber = interest->client->sequence; | |
688 | pEv->time = time; | |
689 | pEv->firstSI = firstSI; | |
690 | pEv->nSI = nSI; | |
691 | pEv->nTotalSI = nTotalSI; | |
692 | if (interest->client->swapped) { | |
693 | swaps(&pEv->sequenceNumber); | |
694 | swapl(&pEv->time); | |
695 | swaps(&pEv->firstSI); | |
696 | swaps(&pEv->nSI); | |
697 | swaps(&pEv->nTotalSI); | |
698 | } | |
699 | WriteToClient(interest->client, sizeof(xEvent), pEv); | |
700 | } | |
701 | interest = interest->next; | |
702 | } | |
703 | return; | |
704 | } | |
705 | ||
706 | void | |
707 | XkbSendActionMessage(DeviceIntPtr kbd, xkbActionMessage * pEv) | |
708 | { | |
709 | int initialized; | |
710 | XkbSrvInfoPtr xkbi; | |
711 | XkbInterestPtr interest; | |
712 | Time time = 0; | |
713 | ||
714 | interest = kbd->xkb_interest; | |
715 | if (!interest || !kbd->key || !kbd->key->xkbInfo) | |
716 | return; | |
717 | ||
718 | xkbi = kbd->key->xkbInfo; | |
719 | ||
720 | initialized = 0; | |
721 | pEv->mods = xkbi->state.mods; | |
722 | pEv->group = xkbi->state.group; | |
723 | while (interest) { | |
724 | if ((!interest->client->clientGone) && | |
725 | (interest->client->requestVector != InitialVector) && | |
726 | (interest->client->xkbClientFlags & _XkbClientInitialized) && | |
727 | (interest->actionMessageMask)) { | |
728 | if (!initialized) { | |
729 | pEv->type = XkbEventCode + XkbEventBase; | |
730 | pEv->xkbType = XkbActionMessage; | |
731 | pEv->deviceID = kbd->id; | |
732 | pEv->sequenceNumber = interest->client->sequence; | |
733 | pEv->time = time = GetTimeInMillis(); | |
734 | initialized = 1; | |
735 | } | |
736 | pEv->sequenceNumber = interest->client->sequence; | |
737 | pEv->time = time; | |
738 | if (interest->client->swapped) { | |
739 | swaps(&pEv->sequenceNumber); | |
740 | swapl(&pEv->time); | |
741 | } | |
742 | WriteToClient(interest->client, sizeof(xEvent), pEv); | |
743 | } | |
744 | interest = interest->next; | |
745 | } | |
746 | return; | |
747 | } | |
748 | ||
749 | void | |
750 | XkbSendExtensionDeviceNotify(DeviceIntPtr dev, | |
751 | ClientPtr client, xkbExtensionDeviceNotify * pEv) | |
752 | { | |
753 | int initialized; | |
754 | XkbInterestPtr interest; | |
755 | Time time = 0; | |
756 | CARD32 defined, state; | |
757 | CARD16 reason; | |
758 | ||
759 | interest = dev->xkb_interest; | |
760 | if (!interest) | |
761 | return; | |
762 | ||
763 | initialized = 0; | |
764 | reason = pEv->reason; | |
765 | defined = pEv->ledsDefined; | |
766 | state = pEv->ledState; | |
767 | while (interest) { | |
768 | if ((!interest->client->clientGone) && | |
769 | (interest->client->requestVector != InitialVector) && | |
770 | (interest->client->xkbClientFlags & _XkbClientInitialized) && | |
771 | (interest->extDevNotifyMask & reason)) { | |
772 | if (!initialized) { | |
773 | pEv->type = XkbEventCode + XkbEventBase; | |
774 | pEv->xkbType = XkbExtensionDeviceNotify; | |
775 | pEv->deviceID = dev->id; | |
776 | pEv->sequenceNumber = interest->client->sequence; | |
777 | pEv->time = time = GetTimeInMillis(); | |
778 | initialized = 1; | |
779 | } | |
780 | else { | |
781 | pEv->sequenceNumber = interest->client->sequence; | |
782 | pEv->time = time; | |
783 | pEv->ledsDefined = defined; | |
784 | pEv->ledState = state; | |
785 | pEv->reason = reason; | |
786 | pEv->supported = XkbXI_AllFeaturesMask; | |
787 | } | |
788 | if (interest->client->swapped) { | |
789 | swaps(&pEv->sequenceNumber); | |
790 | swapl(&pEv->time); | |
791 | swapl(&pEv->ledsDefined); | |
792 | swapl(&pEv->ledState); | |
793 | swaps(&pEv->reason); | |
794 | swaps(&pEv->supported); | |
795 | } | |
796 | WriteToClient(interest->client, sizeof(xEvent), pEv); | |
797 | } | |
798 | interest = interest->next; | |
799 | } | |
800 | return; | |
801 | } | |
802 | ||
803 | void | |
804 | XkbSendNotification(DeviceIntPtr kbd, | |
805 | XkbChangesPtr pChanges, XkbEventCausePtr cause) | |
806 | { | |
807 | XkbSrvLedInfoPtr sli; | |
808 | ||
809 | sli = NULL; | |
810 | if (pChanges->state_changes) { | |
811 | xkbStateNotify sn; | |
812 | ||
813 | sn.changed = pChanges->state_changes; | |
814 | sn.keycode = cause->kc; | |
815 | sn.eventType = cause->event; | |
816 | sn.requestMajor = cause->mjr; | |
817 | sn.requestMinor = cause->mnr; | |
818 | XkbSendStateNotify(kbd, &sn); | |
819 | } | |
820 | if (pChanges->map.changed) { | |
821 | xkbMapNotify mn; | |
822 | ||
823 | memset(&mn, 0, sizeof(xkbMapNotify)); | |
824 | mn.changed = pChanges->map.changed; | |
825 | mn.firstType = pChanges->map.first_type; | |
826 | mn.nTypes = pChanges->map.num_types; | |
827 | mn.firstKeySym = pChanges->map.first_key_sym; | |
828 | mn.nKeySyms = pChanges->map.num_key_syms; | |
829 | mn.firstKeyAct = pChanges->map.first_key_act; | |
830 | mn.nKeyActs = pChanges->map.num_key_acts; | |
831 | mn.firstKeyBehavior = pChanges->map.first_key_behavior; | |
832 | mn.nKeyBehaviors = pChanges->map.num_key_behaviors; | |
833 | mn.virtualMods = pChanges->map.vmods; | |
834 | mn.firstKeyExplicit = pChanges->map.first_key_explicit; | |
835 | mn.nKeyExplicit = pChanges->map.num_key_explicit; | |
836 | mn.firstModMapKey = pChanges->map.first_modmap_key; | |
837 | mn.nModMapKeys = pChanges->map.num_modmap_keys; | |
838 | mn.firstVModMapKey = pChanges->map.first_vmodmap_key; | |
839 | mn.nVModMapKeys = pChanges->map.num_vmodmap_keys; | |
840 | XkbSendMapNotify(kbd, &mn); | |
841 | } | |
842 | if ((pChanges->ctrls.changed_ctrls) || | |
843 | (pChanges->ctrls.enabled_ctrls_changes)) { | |
844 | xkbControlsNotify cn; | |
845 | ||
846 | memset(&cn, 0, sizeof(xkbControlsNotify)); | |
847 | cn.changedControls = pChanges->ctrls.changed_ctrls; | |
848 | cn.enabledControlChanges = pChanges->ctrls.enabled_ctrls_changes; | |
849 | cn.keycode = cause->kc; | |
850 | cn.eventType = cause->event; | |
851 | cn.requestMajor = cause->mjr; | |
852 | cn.requestMinor = cause->mnr; | |
853 | XkbSendControlsNotify(kbd, &cn); | |
854 | } | |
855 | if (pChanges->indicators.map_changes) { | |
856 | xkbIndicatorNotify in; | |
857 | ||
858 | if (sli == NULL) | |
859 | sli = XkbFindSrvLedInfo(kbd, XkbDfltXIClass, XkbDfltXIId, 0); | |
860 | memset(&in, 0, sizeof(xkbIndicatorNotify)); | |
861 | in.state = sli->effectiveState; | |
862 | in.changed = pChanges->indicators.map_changes; | |
863 | XkbSendIndicatorNotify(kbd, XkbIndicatorMapNotify, &in); | |
864 | } | |
865 | if (pChanges->indicators.state_changes) { | |
866 | xkbIndicatorNotify in; | |
867 | ||
868 | if (sli == NULL) | |
869 | sli = XkbFindSrvLedInfo(kbd, XkbDfltXIClass, XkbDfltXIId, 0); | |
870 | memset(&in, 0, sizeof(xkbIndicatorNotify)); | |
871 | in.state = sli->effectiveState; | |
872 | in.changed = pChanges->indicators.state_changes; | |
873 | XkbSendIndicatorNotify(kbd, XkbIndicatorStateNotify, &in); | |
874 | } | |
875 | if (pChanges->names.changed) { | |
876 | xkbNamesNotify nn; | |
877 | ||
878 | memset(&nn, 0, sizeof(xkbNamesNotify)); | |
879 | nn.changed = pChanges->names.changed; | |
880 | nn.firstType = pChanges->names.first_type; | |
881 | nn.nTypes = pChanges->names.num_types; | |
882 | nn.firstLevelName = pChanges->names.first_lvl; | |
883 | nn.nLevelNames = pChanges->names.num_lvls; | |
884 | nn.nRadioGroups = pChanges->names.num_rg; | |
885 | nn.changedVirtualMods = pChanges->names.changed_vmods; | |
886 | nn.changedIndicators = pChanges->names.changed_indicators; | |
887 | XkbSendNamesNotify(kbd, &nn); | |
888 | } | |
889 | if ((pChanges->compat.changed_groups) || (pChanges->compat.num_si > 0)) { | |
890 | xkbCompatMapNotify cmn; | |
891 | ||
892 | memset(&cmn, 0, sizeof(xkbCompatMapNotify)); | |
893 | cmn.changedGroups = pChanges->compat.changed_groups; | |
894 | cmn.firstSI = pChanges->compat.first_si; | |
895 | cmn.nSI = pChanges->compat.num_si; | |
896 | cmn.nTotalSI = kbd->key->xkbInfo->desc->compat->num_si; | |
897 | XkbSendCompatMapNotify(kbd, &cmn); | |
898 | } | |
899 | return; | |
900 | } | |
901 | ||
902 | /***====================================================================***/ | |
903 | ||
904 | void | |
905 | XkbFilterEvents(ClientPtr client, int nEvents, xEvent *xE) | |
906 | { | |
907 | DeviceIntPtr dev = NULL; | |
908 | XkbSrvInfoPtr xkbi; | |
909 | CARD8 type = xE[0].u.u.type; | |
910 | ||
911 | if (xE->u.u.type & EXTENSION_EVENT_BASE) | |
912 | dev = XIGetDevice(xE); | |
913 | ||
914 | if (!dev) | |
915 | dev = PickKeyboard(client); | |
916 | ||
917 | if (!dev->key) | |
918 | return; | |
919 | ||
920 | xkbi = dev->key->xkbInfo; | |
921 | ||
922 | if (client->xkbClientFlags & _XkbClientInitialized) { | |
923 | if ((xkbDebugFlags & 0x10) && | |
924 | (type == KeyPress || type == KeyRelease || | |
925 | type == DeviceKeyPress || type == DeviceKeyRelease)) | |
926 | DebugF("[xkb] XkbFilterWriteEvents (XKB client): state 0x%04x\n", | |
927 | xE[0].u.keyButtonPointer.state); | |
928 | ||
929 | if (dev->deviceGrab.grab != NullGrab && dev->deviceGrab.fromPassiveGrab | |
930 | && (type == KeyPress || type == KeyRelease || type == DeviceKeyPress | |
931 | || type == DeviceKeyRelease)) { | |
932 | unsigned int state, flags; | |
933 | ||
934 | flags = client->xkbClientFlags; | |
935 | state = xkbi->state.compat_grab_mods; | |
936 | if (flags & XkbPCF_GrabsUseXKBStateMask) { | |
937 | int group; | |
938 | ||
939 | if (flags & XkbPCF_LookupStateWhenGrabbed) { | |
940 | group = xkbi->state.group; | |
941 | state = xkbi->state.lookup_mods; | |
942 | } | |
943 | else { | |
944 | state = xkbi->state.grab_mods; | |
945 | group = xkbi->state.base_group + xkbi->state.latched_group; | |
946 | if (group < 0 || group >= xkbi->desc->ctrls->num_groups) | |
947 | group = XkbAdjustGroup(group, xkbi->desc->ctrls); | |
948 | } | |
949 | state = XkbBuildCoreState(state, group); | |
950 | } | |
951 | else if (flags & XkbPCF_LookupStateWhenGrabbed) { | |
952 | state = xkbi->state.compat_lookup_mods; | |
953 | } | |
954 | xE[0].u.keyButtonPointer.state = state; | |
955 | } | |
956 | } | |
957 | else { | |
958 | if ((xkbDebugFlags & 0x4) && | |
959 | (xE[0].u.u.type == KeyPress || xE[0].u.u.type == KeyRelease || | |
960 | xE[0].u.u.type == DeviceKeyPress || | |
961 | xE[0].u.u.type == DeviceKeyRelease)) { | |
962 | DebugF("[xkb] XKbFilterWriteEvents (non-XKB):\n"); | |
963 | DebugF("[xkb] event= 0x%04x\n", xE[0].u.keyButtonPointer.state); | |
964 | DebugF("[xkb] lookup= 0x%02x, grab= 0x%02x\n", | |
965 | xkbi->state.lookup_mods, xkbi->state.grab_mods); | |
966 | DebugF("[xkb] compat lookup= 0x%02x, grab= 0x%02x\n", | |
967 | xkbi->state.compat_lookup_mods, | |
968 | xkbi->state.compat_grab_mods); | |
969 | } | |
970 | if (type >= KeyPress && type <= MotionNotify) { | |
971 | CARD16 old, new; | |
972 | ||
973 | old = xE[0].u.keyButtonPointer.state & ~0x1f00; | |
974 | new = xE[0].u.keyButtonPointer.state & 0x1F00; | |
975 | ||
976 | if (old == XkbStateFieldFromRec(&xkbi->state)) | |
977 | new |= xkbi->state.compat_lookup_mods; | |
978 | else | |
979 | new |= xkbi->state.compat_grab_mods; | |
980 | xE[0].u.keyButtonPointer.state = new; | |
981 | } | |
982 | else if (type == EnterNotify || type == LeaveNotify) { | |
983 | xE[0].u.enterLeave.state &= 0x1F00; | |
984 | xE[0].u.enterLeave.state |= xkbi->state.compat_grab_mods; | |
985 | } | |
986 | else if (type >= DeviceKeyPress && type <= DeviceMotionNotify) { | |
987 | CARD16 old, new; | |
988 | deviceKeyButtonPointer *kbp = (deviceKeyButtonPointer *) &xE[0]; | |
989 | ||
990 | old = kbp->state & ~0x1F00; | |
991 | new = kbp->state & 0x1F00; | |
992 | if (old == XkbStateFieldFromRec(&xkbi->state)) | |
993 | new |= xkbi->state.compat_lookup_mods; | |
994 | else | |
995 | new |= xkbi->state.compat_grab_mods; | |
996 | kbp->state = new; | |
997 | } | |
998 | } | |
999 | } | |
1000 | ||
1001 | /***====================================================================***/ | |
1002 | ||
1003 | XkbInterestPtr | |
1004 | XkbFindClientResource(DevicePtr inDev, ClientPtr client) | |
1005 | { | |
1006 | DeviceIntPtr dev = (DeviceIntPtr) inDev; | |
1007 | XkbInterestPtr interest; | |
1008 | ||
1009 | if (dev->xkb_interest) { | |
1010 | interest = dev->xkb_interest; | |
1011 | while (interest) { | |
1012 | if (interest->client == client) { | |
1013 | return interest; | |
1014 | } | |
1015 | interest = interest->next; | |
1016 | } | |
1017 | } | |
1018 | return NULL; | |
1019 | } | |
1020 | ||
1021 | XkbInterestPtr | |
1022 | XkbAddClientResource(DevicePtr inDev, ClientPtr client, XID id) | |
1023 | { | |
1024 | DeviceIntPtr dev = (DeviceIntPtr) inDev; | |
1025 | XkbInterestPtr interest; | |
1026 | ||
1027 | interest = dev->xkb_interest; | |
1028 | while (interest) { | |
1029 | if (interest->client == client) | |
1030 | return ((interest->resource == id) ? interest : NULL); | |
1031 | interest = interest->next; | |
1032 | } | |
1033 | interest = calloc(1, sizeof(XkbInterestRec)); | |
1034 | if (interest) { | |
1035 | interest->dev = dev; | |
1036 | interest->client = client; | |
1037 | interest->resource = id; | |
1038 | interest->next = dev->xkb_interest; | |
1039 | dev->xkb_interest = interest; | |
1040 | return interest; | |
1041 | } | |
1042 | return NULL; | |
1043 | } | |
1044 | ||
1045 | int | |
1046 | XkbRemoveResourceClient(DevicePtr inDev, XID id) | |
1047 | { | |
1048 | XkbSrvInfoPtr xkbi; | |
1049 | DeviceIntPtr dev = (DeviceIntPtr) inDev; | |
1050 | XkbInterestPtr interest; | |
1051 | Bool found; | |
1052 | unsigned long autoCtrls, autoValues; | |
1053 | ClientPtr client = NULL; | |
1054 | ||
1055 | found = FALSE; | |
1056 | ||
1057 | if (!dev->key || !dev->key->xkbInfo) | |
1058 | return found; | |
1059 | ||
1060 | autoCtrls = autoValues = 0; | |
1061 | if (dev->xkb_interest) { | |
1062 | interest = dev->xkb_interest; | |
1063 | if (interest && (interest->resource == id)) { | |
1064 | dev->xkb_interest = interest->next; | |
1065 | autoCtrls = interest->autoCtrls; | |
1066 | autoValues = interest->autoCtrlValues; | |
1067 | client = interest->client; | |
1068 | free(interest); | |
1069 | found = TRUE; | |
1070 | } | |
1071 | while ((!found) && (interest->next)) { | |
1072 | if (interest->next->resource == id) { | |
1073 | XkbInterestPtr victim = interest->next; | |
1074 | ||
1075 | interest->next = victim->next; | |
1076 | autoCtrls = victim->autoCtrls; | |
1077 | autoValues = victim->autoCtrlValues; | |
1078 | client = victim->client; | |
1079 | free(victim); | |
1080 | found = TRUE; | |
1081 | } | |
1082 | interest = interest->next; | |
1083 | } | |
1084 | } | |
1085 | if (found && autoCtrls && dev->key && dev->key->xkbInfo) { | |
1086 | XkbEventCauseRec cause; | |
1087 | ||
1088 | xkbi = dev->key->xkbInfo; | |
1089 | XkbSetCauseXkbReq(&cause, X_kbPerClientFlags, client); | |
1090 | XkbEnableDisableControls(xkbi, autoCtrls, autoValues, NULL, &cause); | |
1091 | } | |
1092 | return found; | |
1093 | } |