TMgrab.c revision fdf6a26f
1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates.
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#ifdef HAVE_CONFIG_H
72#include <config.h>
73#endif
74#include "IntrinsicI.h"
75
76typedef struct _GrabActionRec {
77    struct _GrabActionRec *next;
78    XtActionProc action_proc;
79    Boolean owner_events;
80    unsigned int event_mask;
81    int pointer_mode, keyboard_mode;
82} GrabActionRec;
83
84static GrabActionRec *grabActionList = NULL;
85
86static void
87GrabAllCorrectKeys(Widget widget,
88                   TMTypeMatch typeMatch,
89                   TMModifierMatch modMatch, GrabActionRec * grabP)
90{
91    Display *dpy = XtDisplay(widget);
92    KeyCode *keycodes, *keycodeP;
93    Cardinal keycount;
94    Modifiers careOn = 0;
95    Modifiers careMask = 0;
96
97    if (modMatch->lateModifiers) {
98        Boolean resolved;
99
100        resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
101                                          &careOn, &careMask);
102        if (!resolved)
103            return;
104    }
105    careOn = (careOn | (Modifiers) modMatch->modifiers);
106    careMask = (careMask | (Modifiers) modMatch->modifierMask);
107
108    keycodes = NULL;
109    XtKeysymToKeycodeList(dpy,
110                          (KeySym) typeMatch->eventCode, &keycodes, &keycount);
111    if (keycount == 0) {
112        XtFree((char *) keycodes);
113        return;
114    }
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
122            XtTranslateKeycode(dpy, *keycodeP, (Modifiers) 0,
123                               &modifiers_return, &keysym);
124            if (careOn & modifiers_return) {
125                XtFree((char *) keycodes);
126                return;
127            }
128            if (keysym == typeMatch->eventCode) {
129                XtGrabKey(widget, *keycodeP, careOn,
130                          grabP->owner_events,
131                          grabP->pointer_mode, grabP->keyboard_mode);
132                /* continue; *//* grab all modifier combinations */
133            }
134            least_mod = (int) (modifiers_return & (~modifiers_return + 1));
135            for (std_mods = (int) modifiers_return;
136                 std_mods >= least_mod; std_mods--) {
137                Modifiers dummy;
138
139                /* check all useful combinations of modifier bits */
140                if ((modifiers_return & (Modifiers) std_mods) &&
141                    !(~modifiers_return & (Modifiers) std_mods)) {
142                    XtTranslateKeycode(dpy, *keycodeP,
143                                       (Modifiers) std_mods, &dummy, &keysym);
144                    if (keysym == typeMatch->eventCode) {
145                        XtGrabKey(widget, *keycodeP,
146                                  careOn | (Modifiers) std_mods,
147                                  grabP->owner_events,
148                                  grabP->pointer_mode, grabP->keyboard_mode);
149                        /* break; *//* grab all modifier combinations */
150                    }
151                }
152            }
153        }
154        else {                  /* !event->standard */
155
156            XtGrabKey(widget, *keycodeP, careOn,
157                      grabP->owner_events,
158                      grabP->pointer_mode, grabP->keyboard_mode);
159        }
160    }
161    XtFree((char *) keycodes);
162}
163
164typedef struct {
165    TMShortCard count;
166    Widget widget;
167    GrabActionRec *grabP;
168} DoGrabRec;
169
170static Boolean
171DoGrab(StatePtr state, XtPointer data)
172{
173    /* *INDENT-EQLS* */
174    DoGrabRec *doGrabP     = (DoGrabRec *) data;
175    GrabActionRec *grabP   = doGrabP->grabP;
176    Widget widget          = doGrabP->widget;
177    TMShortCard count      = doGrabP->count;
178    TMShortCard typeIndex  = state->typeIndex;
179    TMShortCard modIndex   = state->modIndex;
180    ActionRec *action;
181    TMTypeMatch typeMatch;
182    TMModifierMatch modMatch;
183    Modifiers careOn = 0;
184    Modifiers careMask = 0;
185
186    LOCK_PROCESS;
187    typeMatch = TMGetTypeMatch(typeIndex);
188    modMatch = TMGetModifierMatch(modIndex);
189
190    for (action = state->actions; action; action = action->next)
191        if (count == action->idx)
192            break;
193    if (!action) {
194        UNLOCK_PROCESS;
195        return False;
196    }
197
198    switch (typeMatch->eventType) {
199    case ButtonPress:
200    case ButtonRelease:
201        if (modMatch->lateModifiers) {
202            Boolean resolved = _XtComputeLateBindings(XtDisplay(widget),
203                                                      modMatch->lateModifiers,
204                                                      &careOn, &careMask);
205
206            if (!resolved)
207                break;
208        }
209        careOn = (careOn | (Modifiers) modMatch->modifiers);
210        XtGrabButton(widget,
211                     (int) 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        break;
220
221    case KeyPress:
222    case KeyRelease:
223        GrabAllCorrectKeys(widget, typeMatch, modMatch, grabP);
224        break;
225
226    case EnterNotify:
227        break;
228
229    default:
230        XtAppWarningMsg(XtWidgetToApplicationContext(widget),
231                        "invalidPopup", "unsupportedOperation",
232                        XtCXtToolkitError,
233                        "Pop-up menu creation is only supported on Button, Key or EnterNotify events.",
234                        NULL, NULL);
235        break;
236    }
237    UNLOCK_PROCESS;
238    return False;
239}
240
241void
242_XtRegisterGrabs(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)
259        return;
260    stateTreePtr = (TMComplexStateTree *) xlations->stateTreeTbl;
261    if (*stateTreePtr == NULL)
262        return;
263    for (i = 0; i < xlations->numStateTrees; i++, stateTreePtr++) {
264        if (bindData->simple.isComplex)
265            procs = TMGetComplexBindEntry(bindData, i)->procs;
266        else
267            procs = TMGetSimpleBindEntry(bindData, i)->procs;
268        for (count = 0; count < (*stateTreePtr)->numQuarks; count++) {
269            GrabActionRec *grabP;
270            DoGrabRec doGrab;
271
272            LOCK_PROCESS;
273            for (grabP = grabActionList; grabP != NULL; grabP = grabP->next) {
274                if (grabP->action_proc == procs[count]) {
275                    /* we've found a "grabber" in the action table. Find the
276                     * states that call this action.  Note that if there is
277                     * more than one "grabber" in the action table, we end
278                     * up searching all of the states multiple times.
279                     */
280                    doGrab.widget = widget;
281                    doGrab.grabP = grabP;
282                    doGrab.count = (TMShortCard) count;
283                    _XtTraverseStateTree((TMStateTree) *stateTreePtr,
284                                         DoGrab, (XtPointer) &doGrab);
285                }
286            }
287            UNLOCK_PROCESS;
288        }
289    }
290}
291
292void
293XtRegisterGrabAction(XtActionProc action_proc,
294                     _XtBoolean owner_events,
295                     unsigned int event_mask,
296                     int pointer_mode,
297                     int keyboard_mode)
298{
299    GrabActionRec *actionP;
300
301    LOCK_PROCESS;
302    for (actionP = grabActionList; actionP != NULL; actionP = actionP->next) {
303        if (actionP->action_proc == action_proc)
304            break;
305    }
306    if (actionP == NULL) {
307        actionP = XtNew(GrabActionRec);
308        actionP->action_proc = action_proc;
309        actionP->next = grabActionList;
310        grabActionList = actionP;
311    }
312#ifdef DEBUG
313    else if (actionP->owner_events != owner_events
314             || actionP->event_mask != event_mask
315             || actionP->pointer_mode != pointer_mode
316             || actionP->keyboard_mode != keyboard_mode) {
317        Cardinal n = 0;
318
319        XtWarningMsg("argsReplaced", "xtRegisterGrabAction", XtCXtToolkitError,
320                     "XtRegisterGrabAction called on same proc with different args",
321                     NULL, &n);
322    }
323#endif /*DEBUG*/
324        actionP->owner_events = (Boolean) 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
331void
332_XtGrabInitialize(XtAppContext app _X_UNUSED)
333{
334    LOCK_PROCESS;
335    if (grabActionList == NULL)
336        XtRegisterGrabAction(XtMenuPopupAction, True,
337                             (unsigned) (ButtonPressMask | ButtonReleaseMask),
338                             GrabModeAsync, GrabModeAsync);
339    UNLOCK_PROCESS;
340
341}
342