TMgrab.c revision 1477040f
1/* $Xorg: TMgrab.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */
2
3/***********************************************************
4Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
5
6Permission is hereby granted, free of charge, to any person obtaining a
7copy of this software and associated documentation files (the "Software"),
8to deal in the Software without restriction, including without limitation
9the rights to use, copy, modify, merge, publish, distribute, sublicense,
10and/or sell copies of the Software, and to permit persons to whom the
11Software is furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice (including the next
14paragraph) shall be included in all copies or substantial portions of the
15Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23DEALINGS IN THE SOFTWARE.
24
25Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27                        All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45******************************************************************/
46
47/*
48
49Copyright 1987, 1988, 1998  The Open Group
50
51Permission to use, copy, modify, distribute, and sell this software and its
52documentation for any purpose is hereby granted without fee, provided that
53the above copyright notice appear in all copies and that both that
54copyright notice and this permission notice appear in supporting
55documentation.
56
57The above copyright notice and this permission notice shall be included in
58all copies or substantial portions of the Software.
59
60THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
63OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
64AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
65CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
66
67Except as contained in this notice, the name of The Open Group shall not be
68used in advertising or otherwise to promote the sale, use or other dealings
69in this Software without prior written authorization from The Open Group.
70
71*/
72/* $XFree86: xc/lib/Xt/TMgrab.c,v 1.3 2001/12/14 19:56:30 dawes Exp $ */
73
74/*LINTLIBRARY*/
75#ifdef HAVE_CONFIG_H
76#include <config.h>
77#endif
78#include "IntrinsicI.h"
79
80typedef struct _GrabActionRec {
81    struct _GrabActionRec* next;
82    XtActionProc action_proc;
83    Boolean owner_events;
84    unsigned int event_mask;
85    int pointer_mode, keyboard_mode;
86} GrabActionRec;
87
88static GrabActionRec *grabActionList = NULL;
89
90static void GrabAllCorrectKeys(
91    Widget widget,
92    TMTypeMatch typeMatch,
93    TMModifierMatch modMatch,
94    GrabActionRec* grabP)
95{
96    Display *dpy = XtDisplay(widget);
97    KeyCode *keycodes, *keycodeP;
98    Cardinal keycount;
99    Modifiers careOn = 0;
100    Modifiers careMask = 0;
101
102    if (modMatch->lateModifiers) {
103	Boolean resolved;
104	resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
105					  &careOn, &careMask);
106	if (!resolved) return;
107    }
108    careOn |= modMatch->modifiers;
109    careMask |= modMatch->modifierMask;
110
111    XtKeysymToKeycodeList(
112	    dpy,
113	    (KeySym)typeMatch->eventCode,
114	    &keycodes,
115	    &keycount
116			 );
117    if (keycount == 0) return;
118    for (keycodeP = keycodes; keycount--; keycodeP++) {
119	if (modMatch->standard) {
120	    /* find standard modifiers that produce this keysym */
121	    KeySym keysym;
122	    int std_mods, least_mod;
123	    Modifiers modifiers_return;
124	    XtTranslateKeycode( dpy, *keycodeP, (Modifiers)0,
125			        &modifiers_return, &keysym );
126	    if (careOn & modifiers_return)
127		return;
128	    if (keysym == typeMatch->eventCode) {
129		XtGrabKey(widget, *keycodeP, careOn,
130			  grabP->owner_events,
131			  grabP->pointer_mode,
132			  grabP->keyboard_mode
133			);
134		/* continue; */		/* grab all modifier combinations */
135	    }
136	    least_mod = modifiers_return & (~modifiers_return + 1);
137	    for (std_mods = modifiers_return;
138		 std_mods >= least_mod; std_mods--) {
139		Modifiers dummy;
140		 /* check all useful combinations of modifier bits */
141		if (modifiers_return & std_mods &&
142		    !(~modifiers_return & std_mods)) {
143		    XtTranslateKeycode( dpy, *keycodeP,
144					(Modifiers)std_mods,
145					&dummy, &keysym );
146		    if (keysym == typeMatch->eventCode) {
147			XtGrabKey(widget, *keycodeP,
148				  careOn | (Modifiers) std_mods,
149				  grabP->owner_events,
150				  grabP->pointer_mode,
151				  grabP->keyboard_mode
152				);
153			/* break; */	/* grab all modifier combinations */
154		    }
155		}
156	    }
157	} else /* !event->standard */ {
158	    XtGrabKey(widget, *keycodeP, careOn,
159		      grabP->owner_events,
160		      grabP->pointer_mode,
161		      grabP->keyboard_mode
162		    );
163	}
164    }
165    XtFree((char *)keycodes);
166}
167
168typedef struct {
169    TMShortCard count;
170    Widget	widget;
171    GrabActionRec *grabP;
172}DoGrabRec;
173
174static Boolean DoGrab(
175    StatePtr		state,
176    XtPointer		data)
177{
178    DoGrabRec		*doGrabP = (DoGrabRec *)data;
179    GrabActionRec* 	grabP = doGrabP->grabP;
180    Widget		widget = doGrabP->widget;
181    TMShortCard		count = doGrabP->count;
182    TMShortCard		typeIndex = state->typeIndex;
183    TMShortCard		modIndex = state->modIndex;
184    ActionRec		*action;
185    TMTypeMatch		typeMatch;
186    TMModifierMatch	modMatch;
187    Modifiers		careOn = 0;
188    Modifiers		careMask = 0;
189    Boolean		resolved;
190
191    LOCK_PROCESS;
192    typeMatch = TMGetTypeMatch(typeIndex);
193    modMatch = TMGetModifierMatch(modIndex);
194
195    for (action = state->actions; action; action = action->next)
196      if (count == action->idx) break;
197    if (!action) {
198	UNLOCK_PROCESS;
199	return False;
200    }
201
202    switch (typeMatch->eventType) {
203      case ButtonPress:
204      case ButtonRelease:
205	if (modMatch->lateModifiers) {
206	    resolved = _XtComputeLateBindings(XtDisplay(widget),
207					      modMatch->lateModifiers,
208					      &careOn, &careMask);
209	    if (!resolved) break;
210	}
211	careOn |= modMatch->modifiers;
212	XtGrabButton(
213		     widget,
214		     (unsigned) typeMatch->eventCode,
215		     careOn,
216		     grabP->owner_events,
217		     grabP->event_mask,
218		     grabP->pointer_mode,
219		     grabP->keyboard_mode,
220		     None,
221		     None
222		     );
223	break;
224
225      case KeyPress:
226      case KeyRelease:
227	GrabAllCorrectKeys(widget, typeMatch, modMatch, grabP);
228	break;
229
230      case EnterNotify:
231	break;
232
233      default:
234	XtAppWarningMsg(XtWidgetToApplicationContext(widget),
235			"invalidPopup","unsupportedOperation",XtCXtToolkitError,
236			"Pop-up menu creation is only supported on Button, Key or EnterNotify events.",
237			(String *)NULL, (Cardinal *)NULL);
238	break;
239    }
240    UNLOCK_PROCESS;
241    return False;
242}
243
244void _XtRegisterGrabs(
245    Widget widget)
246{
247    XtTranslations 	xlations = widget->core.tm.translations;
248    TMComplexStateTree 	*stateTreePtr;
249    unsigned int 	count;
250    TMShortCard		i;
251    TMBindData   	bindData = (TMBindData) widget->core.tm.proc_table;
252    XtActionProc	*procs;
253
254    if (! XtIsRealized(widget) || widget->core.being_destroyed)
255	return;
256
257    /* walk the widget instance action bindings table looking for */
258    /* actions registered as grab actions. */
259    /* when you find one, do a grab on the triggering event */
260
261    if (xlations == NULL) return;
262    stateTreePtr = (TMComplexStateTree *) xlations->stateTreeTbl;
263    if (*stateTreePtr == NULL) return;
264    for (i = 0; i < xlations->numStateTrees; i++, stateTreePtr++) {
265	if (bindData->simple.isComplex)
266	  procs = TMGetComplexBindEntry(bindData, i)->procs;
267	else
268	  procs = TMGetSimpleBindEntry(bindData, i)->procs;
269	for (count=0; count < (*stateTreePtr)->numQuarks; count++) {
270	    GrabActionRec* grabP;
271	    DoGrabRec      doGrab;
272
273	    LOCK_PROCESS;
274	    for (grabP = grabActionList; grabP != NULL; grabP = grabP->next) {
275		if (grabP->action_proc == procs[count]) {
276		    /* we've found a "grabber" in the action table. Find the
277		     * states that call this action.  Note that if there is
278		     * more than one "grabber" in the action table, we end
279		     * up searching all of the states multiple times.
280		     */
281		    doGrab.widget = widget;
282		    doGrab.grabP = grabP;
283		    doGrab.count = count;
284		    _XtTraverseStateTree((TMStateTree)*stateTreePtr,
285					 DoGrab,
286					 (XtPointer)&doGrab);
287		}
288	    }
289	    UNLOCK_PROCESS;
290	}
291    }
292}
293
294void XtRegisterGrabAction(
295    XtActionProc action_proc,
296    _XtBoolean owner_events,
297    unsigned int event_mask,
298    int pointer_mode,
299    int keyboard_mode)
300{
301    GrabActionRec* actionP;
302
303    LOCK_PROCESS;
304    for (actionP = grabActionList; actionP != NULL; actionP = actionP->next) {
305	if (actionP->action_proc == action_proc) break;
306    }
307    if (actionP == NULL) {
308	actionP = XtNew(GrabActionRec);
309	actionP->action_proc = action_proc;
310	actionP->next = grabActionList;
311	grabActionList = actionP;
312    }
313#ifdef DEBUG
314    else
315	if (   actionP->owner_events != owner_events
316	    || actionP->event_mask != event_mask
317	    || actionP->pointer_mode != pointer_mode
318	    || actionP->keyboard_mode != keyboard_mode) {
319	    Cardinal n = 0;
320	    XtWarningMsg(
321		"argsReplaced", "xtRegisterGrabAction", XtCXtToolkitError,
322		"XtRegisterGrabAction called on same proc with different args",
323			 NULL, &n);
324	}
325#endif /*DEBUG*/
326
327    actionP->owner_events = owner_events;
328    actionP->event_mask = event_mask;
329    actionP->pointer_mode = pointer_mode;
330    actionP->keyboard_mode = keyboard_mode;
331    UNLOCK_PROCESS;
332}
333
334/*ARGSUSED*/
335void _XtGrabInitialize(
336    XtAppContext	app)
337{
338    LOCK_PROCESS;
339    if (grabActionList == NULL)
340	XtRegisterGrabAction( XtMenuPopupAction, True,
341			      (unsigned)(ButtonPressMask | ButtonReleaseMask),
342			      GrabModeAsync,
343			      GrabModeAsync
344			    );
345    UNLOCK_PROCESS;
346
347}
348