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