/[dtapublic]/projs/trunk/shared_source/tk_base/tkpointer.c
ViewVC logotype

Annotation of /projs/trunk/shared_source/tk_base/tkpointer.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 25 - (hide annotations) (download)
Sat Oct 8 06:43:03 2016 UTC (7 years, 9 months ago) by dashley
Original Path: sf_code/esrgpcpj/shared/tk_base/tkpointer.c
File MIME type: text/plain
File size: 18075 byte(s)
Initial commit.
1 dashley 25 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkpointer.c,v 1.1.1.1 2001/06/13 05:07:19 dtashley Exp $ */
2    
3     /*
4     * tkPointer.c --
5     *
6     * This file contains functions for emulating the X server
7     * pointer and grab state machine. This file is used by the
8     * Mac and Windows platforms to generate appropriate enter/leave
9     * events, and to update the global grab window information.
10     *
11     * Copyright (c) 1996 by Sun Microsystems, Inc.
12     *
13     * See the file "license.terms" for information on usage and redistribution
14     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15     *
16     * RCS: @(#) $Id: tkpointer.c,v 1.1.1.1 2001/06/13 05:07:19 dtashley Exp $
17     */
18    
19     #include "tkInt.h"
20    
21     #ifdef __WIN32__
22     #include "tkWinInt.h"
23     #endif
24    
25     #ifdef MAC_TCL
26     #define Cursor XCursor
27     #endif
28    
29     /*
30     * Mask that selects any of the state bits corresponding to buttons,
31     * plus masks that select individual buttons' bits:
32     */
33    
34     #define ALL_BUTTONS \
35     (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
36     static unsigned int buttonMasks[] = {
37     Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask
38     };
39     #define ButtonMask(b) (buttonMasks[(b)-Button1])
40    
41     typedef struct ThreadSpecificData {
42     TkWindow *grabWinPtr; /* Window that defines the top of the
43     * grab tree in a global grab. */
44     int lastState; /* Last known state flags. */
45     XPoint lastPos; /* Last reported mouse position. */
46     TkWindow *lastWinPtr; /* Last reported mouse window. */
47     TkWindow *restrictWinPtr; /* Window to which all mouse events
48     * will be reported. */
49     TkWindow *cursorWinPtr; /* Window that is currently
50     * controlling the global cursor. */
51     } ThreadSpecificData;
52     static Tcl_ThreadDataKey dataKey;
53    
54     /*
55     * Forward declarations of procedures used in this file.
56     */
57    
58     static int GenerateEnterLeave _ANSI_ARGS_((TkWindow *winPtr,
59     int x, int y, int state));
60     static void InitializeEvent _ANSI_ARGS_((XEvent* eventPtr,
61     TkWindow *winPtr, int type, int x, int y,
62     int state, int detail));
63     static void UpdateCursor _ANSI_ARGS_((TkWindow *winPtr));
64    
65     /*
66     *----------------------------------------------------------------------
67     *
68     * InitializeEvent --
69     *
70     * Initializes the common fields for several X events.
71     *
72     * Results:
73     * None.
74     *
75     * Side effects:
76     * Fills in the specified event structure.
77     *
78     *----------------------------------------------------------------------
79     */
80    
81     static void
82     InitializeEvent(eventPtr, winPtr, type, x, y, state, detail)
83     XEvent* eventPtr; /* Event structure to initialize. */
84     TkWindow *winPtr; /* Window to make event relative to. */
85     int type; /* Message type. */
86     int x, y; /* Root coords of event. */
87     int state; /* State flags. */
88     int detail; /* Detail value. */
89     {
90     eventPtr->type = type;
91     eventPtr->xany.serial = LastKnownRequestProcessed(winPtr->display);
92     eventPtr->xany.send_event = False;
93     eventPtr->xany.display = winPtr->display;
94    
95     eventPtr->xcrossing.root = RootWindow(winPtr->display, winPtr->screenNum);
96     eventPtr->xcrossing.time = TkpGetMS();
97     eventPtr->xcrossing.x_root = x;
98     eventPtr->xcrossing.y_root = y;
99    
100     switch (type) {
101     case EnterNotify:
102     case LeaveNotify:
103     eventPtr->xcrossing.mode = NotifyNormal;
104     eventPtr->xcrossing.state = state;
105     eventPtr->xcrossing.detail = detail;
106     eventPtr->xcrossing.focus = False;
107     break;
108     case MotionNotify:
109     eventPtr->xmotion.state = state;
110     eventPtr->xmotion.is_hint = detail;
111     break;
112     case ButtonPress:
113     case ButtonRelease:
114     eventPtr->xbutton.state = state;
115     eventPtr->xbutton.button = detail;
116     break;
117     }
118     TkChangeEventWindow(eventPtr, winPtr);
119     }
120    
121     /*
122     *----------------------------------------------------------------------
123     *
124     * GenerateEnterLeave --
125     *
126     * Update the current mouse window and position, and generate
127     * any enter/leave events that are needed.
128     *
129     * Results:
130     * Returns 1 if enter/leave events were generated.
131     *
132     * Side effects:
133     * May insert events into the Tk event queue.
134     *
135     *----------------------------------------------------------------------
136     */
137    
138     static int
139     GenerateEnterLeave(winPtr, x, y, state)
140     TkWindow *winPtr; /* Current Tk window (or NULL). */
141     int x,y; /* Current mouse position in root coords. */
142     int state; /* State flags. */
143     {
144     int crossed = 0; /* 1 if mouse crossed a window boundary */
145     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
146     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
147     TkWindow *restrictWinPtr = tsdPtr->restrictWinPtr;
148     TkWindow *lastWinPtr = tsdPtr->lastWinPtr;
149    
150     if (winPtr != tsdPtr->lastWinPtr) {
151     if (restrictWinPtr) {
152     int newPos, oldPos;
153    
154     newPos = TkPositionInTree(winPtr, restrictWinPtr);
155     oldPos = TkPositionInTree(lastWinPtr, restrictWinPtr);
156    
157     /*
158     * Check if the mouse crossed into or out of the restrict
159     * window. If so, we need to generate an Enter or Leave event.
160     */
161    
162     if ((newPos != oldPos) && ((newPos == TK_GRAB_IN_TREE)
163     || (oldPos == TK_GRAB_IN_TREE))) {
164     XEvent event;
165     int type, detail;
166    
167     if (newPos == TK_GRAB_IN_TREE) {
168     type = EnterNotify;
169     } else {
170     type = LeaveNotify;
171     }
172     if ((oldPos == TK_GRAB_ANCESTOR)
173     || (newPos == TK_GRAB_ANCESTOR)) {
174     detail = NotifyAncestor;
175     } else {
176     detail = NotifyVirtual;
177     }
178     InitializeEvent(&event, restrictWinPtr, type, x, y,
179     state, detail);
180     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
181     }
182    
183     } else {
184     TkWindow *targetPtr;
185    
186     if ((lastWinPtr == NULL)
187     || (lastWinPtr->window == None)) {
188     targetPtr = winPtr;
189     } else {
190     targetPtr = lastWinPtr;
191     }
192    
193     if (targetPtr && (targetPtr->window != None)) {
194     XEvent event;
195    
196     /*
197     * Generate appropriate Enter/Leave events.
198     */
199    
200     InitializeEvent(&event, targetPtr, LeaveNotify, x, y, state,
201     NotifyNormal);
202    
203     TkInOutEvents(&event, lastWinPtr, winPtr, LeaveNotify,
204     EnterNotify, TCL_QUEUE_TAIL);
205     crossed = 1;
206     }
207     }
208     tsdPtr->lastWinPtr = winPtr;
209     }
210    
211     return crossed;
212     }
213    
214     /*
215     *----------------------------------------------------------------------
216     *
217     * Tk_UpdatePointer --
218     *
219     * This function updates the pointer state machine given an
220     * the current window, position and modifier state.
221     *
222     * Results:
223     * None.
224     *
225     * Side effects:
226     * May queue new events and update the grab state.
227     *
228     *----------------------------------------------------------------------
229     */
230    
231     void
232     Tk_UpdatePointer(tkwin, x, y, state)
233     Tk_Window tkwin; /* Window to which pointer event
234     * is reported. May be NULL. */
235     int x, y; /* Pointer location in root coords. */
236     int state; /* Modifier state mask. */
237     {
238     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
239     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
240     TkWindow *winPtr = (TkWindow *)tkwin;
241     TkWindow *targetWinPtr;
242     XPoint pos;
243     XEvent event;
244     int changes = (state ^ tsdPtr->lastState) & ALL_BUTTONS;
245     int type, b, mask;
246    
247     pos.x = x;
248     pos.y = y;
249    
250     /*
251     * Use the current keyboard state, but the old mouse button
252     * state since we haven't generated the button events yet.
253     */
254    
255     tsdPtr->lastState = (state & ~ALL_BUTTONS) | (tsdPtr->lastState
256     & ALL_BUTTONS);
257    
258     /*
259     * Generate Enter/Leave events. If the pointer has crossed window
260     * boundaries, update the current mouse position so we don't generate
261     * redundant motion events.
262     */
263    
264     if (GenerateEnterLeave(winPtr, x, y, tsdPtr->lastState)) {
265     tsdPtr->lastPos = pos;
266     }
267    
268     /*
269     * Generate ButtonPress/ButtonRelease events based on the differences
270     * between the current button state and the last known button state.
271     */
272    
273     for (b = Button1; b <= Button3; b++) {
274     mask = ButtonMask(b);
275     if (changes & mask) {
276     if (state & mask) {
277     type = ButtonPress;
278    
279     /*
280     * ButtonPress - Set restrict window if we aren't grabbed, or
281     * if this is the first button down.
282     */
283    
284     if (!tsdPtr->restrictWinPtr) {
285     if (!tsdPtr->grabWinPtr) {
286    
287     /*
288     * Mouse is not grabbed, so set a button grab.
289     */
290    
291     tsdPtr->restrictWinPtr = winPtr;
292     TkpSetCapture(tsdPtr->restrictWinPtr);
293    
294     } else if ((tsdPtr->lastState & ALL_BUTTONS) == 0) {
295    
296     /*
297     * Mouse is in a non-button grab, so ensure
298     * the button grab is inside the grab tree.
299     */
300    
301     if (TkPositionInTree(winPtr, tsdPtr->grabWinPtr)
302     == TK_GRAB_IN_TREE) {
303     tsdPtr->restrictWinPtr = winPtr;
304     } else {
305     tsdPtr->restrictWinPtr = tsdPtr->grabWinPtr;
306     }
307     TkpSetCapture(tsdPtr->restrictWinPtr);
308     }
309     }
310    
311     } else {
312     type = ButtonRelease;
313    
314     /*
315     * ButtonRelease - Release the mouse capture and clear the
316     * restrict window when the last button is released and we
317     * aren't in a global grab.
318     */
319    
320     if ((tsdPtr->lastState & ALL_BUTTONS) == mask) {
321     if (!tsdPtr->grabWinPtr) {
322     TkpSetCapture(NULL);
323     }
324     }
325    
326     /*
327     * If we are releasing a restrict window, then we need
328     * to send the button event followed by mouse motion from
329     * the restrict window to the current mouse position.
330     */
331    
332     if (tsdPtr->restrictWinPtr) {
333     InitializeEvent(&event, tsdPtr->restrictWinPtr, type, x, y,
334     tsdPtr->lastState, b);
335     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
336     tsdPtr->lastState &= ~mask;
337     tsdPtr->lastWinPtr = tsdPtr->restrictWinPtr;
338     tsdPtr->restrictWinPtr = NULL;
339    
340     GenerateEnterLeave(winPtr, x, y, tsdPtr->lastState);
341     tsdPtr->lastPos = pos;
342     continue;
343     }
344     }
345    
346     /*
347     * If a restrict window is set, make sure the pointer event
348     * is reported relative to that window. Otherwise, if a
349     * global grab is in effect then events outside of windows
350     * managed by Tk should be reported to the grab window.
351     */
352    
353     if (tsdPtr->restrictWinPtr) {
354     targetWinPtr = tsdPtr->restrictWinPtr;
355     } else if (tsdPtr->grabWinPtr && !winPtr) {
356     targetWinPtr = tsdPtr->grabWinPtr;
357     } else {
358     targetWinPtr = winPtr;
359     }
360    
361     /*
362     * If we still have a target window, send the event.
363     */
364    
365     if (winPtr != NULL) {
366     InitializeEvent(&event, targetWinPtr, type, x, y,
367     tsdPtr->lastState, b);
368     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
369     }
370    
371     /*
372     * Update the state for the next iteration.
373     */
374    
375     tsdPtr->lastState = (type == ButtonPress)
376     ? (tsdPtr->lastState | mask) : (tsdPtr->lastState & ~mask);
377     tsdPtr->lastPos = pos;
378     }
379     }
380    
381     /*
382     * Make sure the cursor window is up to date.
383     */
384    
385     if (tsdPtr->restrictWinPtr) {
386     targetWinPtr = tsdPtr->restrictWinPtr;
387     } else if (tsdPtr->grabWinPtr) {
388     targetWinPtr = (TkPositionInTree(winPtr, tsdPtr->grabWinPtr)
389     == TK_GRAB_IN_TREE) ? winPtr : tsdPtr->grabWinPtr;
390     } else {
391     targetWinPtr = winPtr;
392     }
393     UpdateCursor(targetWinPtr);
394    
395     /*
396     * If no other events caused the position to be updated,
397     * generate a motion event.
398     */
399    
400     if (tsdPtr->lastPos.x != pos.x || tsdPtr->lastPos.y != pos.y) {
401     if (tsdPtr->restrictWinPtr) {
402     targetWinPtr = tsdPtr->restrictWinPtr;
403     } else if (tsdPtr->grabWinPtr && !winPtr) {
404     targetWinPtr = tsdPtr->grabWinPtr;
405     }
406    
407     if (targetWinPtr != NULL) {
408     InitializeEvent(&event, targetWinPtr, MotionNotify, x, y,
409     tsdPtr->lastState, NotifyNormal);
410     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
411     }
412     tsdPtr->lastPos = pos;
413     }
414     }
415    
416     /*
417     *----------------------------------------------------------------------
418     *
419     * XGrabPointer --
420     *
421     * Capture the mouse so event are reported outside of toplevels.
422     * Note that this is a very limited implementation that only
423     * supports GrabModeAsync and owner_events True.
424     *
425     * Results:
426     * Always returns GrabSuccess.
427     *
428     * Side effects:
429     * Turns on mouse capture, sets the global grab pointer, and
430     * clears any window restrictions.
431     *
432     *----------------------------------------------------------------------
433     */
434    
435     int
436     XGrabPointer(display, grab_window, owner_events, event_mask, pointer_mode,
437     keyboard_mode, confine_to, cursor, time)
438     Display* display;
439     Window grab_window;
440     Bool owner_events;
441     unsigned int event_mask;
442     int pointer_mode;
443     int keyboard_mode;
444     Window confine_to;
445     Cursor cursor;
446     Time time;
447     {
448     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
449     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
450    
451     display->request++;
452     tsdPtr->grabWinPtr = (TkWindow *) Tk_IdToWindow(display, grab_window);
453     tsdPtr->restrictWinPtr = NULL;
454     TkpSetCapture(tsdPtr->grabWinPtr);
455     if (TkPositionInTree(tsdPtr->lastWinPtr, tsdPtr->grabWinPtr)
456     != TK_GRAB_IN_TREE) {
457     UpdateCursor(tsdPtr->grabWinPtr);
458     }
459     return GrabSuccess;
460     }
461    
462     /*
463     *----------------------------------------------------------------------
464     *
465     * XUngrabPointer --
466     *
467     * Release the current grab.
468     *
469     * Results:
470     * None.
471     *
472     * Side effects:
473     * Releases the mouse capture.
474     *
475     *----------------------------------------------------------------------
476     */
477    
478     void
479     XUngrabPointer(display, time)
480     Display* display;
481     Time time;
482     {
483     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
484     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
485    
486     display->request++;
487     tsdPtr->grabWinPtr = NULL;
488     tsdPtr->restrictWinPtr = NULL;
489     TkpSetCapture(NULL);
490     UpdateCursor(tsdPtr->lastWinPtr);
491     }
492    
493     /*
494     *----------------------------------------------------------------------
495     *
496     * TkPointerDeadWindow --
497     *
498     * Clean up pointer module state when a window is destroyed.
499     *
500     * Results:
501     * None.
502     *
503     * Side effects:
504     * May release the current capture window.
505     *
506     *----------------------------------------------------------------------
507     */
508    
509     void
510     TkPointerDeadWindow(winPtr)
511     TkWindow *winPtr;
512     {
513     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
514     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
515    
516     if (winPtr == tsdPtr->lastWinPtr) {
517     tsdPtr->lastWinPtr = NULL;
518     }
519     if (winPtr == tsdPtr->grabWinPtr) {
520     tsdPtr->grabWinPtr = NULL;
521     }
522     if (winPtr == tsdPtr->restrictWinPtr) {
523     tsdPtr->restrictWinPtr = NULL;
524     }
525     if (!(tsdPtr->restrictWinPtr || tsdPtr->grabWinPtr)) {
526     TkpSetCapture(NULL);
527     }
528     }
529    
530     /*
531     *----------------------------------------------------------------------
532     *
533     * UpdateCursor --
534     *
535     * Set the windows global cursor to the cursor associated with
536     * the given Tk window.
537     *
538     * Results:
539     * None.
540     *
541     * Side effects:
542     * Changes the mouse cursor.
543     *
544     *----------------------------------------------------------------------
545     */
546    
547     static void
548     UpdateCursor(winPtr)
549     TkWindow *winPtr;
550     {
551     Cursor cursor = None;
552     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
553     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
554    
555     /*
556     * A window inherits its cursor from its parent if it doesn't
557     * have one of its own. Top level windows inherit the default
558     * cursor.
559     */
560    
561     tsdPtr->cursorWinPtr = winPtr;
562     while (winPtr != NULL) {
563     if (winPtr->atts.cursor != None) {
564     cursor = winPtr->atts.cursor;
565     break;
566     } else if (winPtr->flags & TK_TOP_LEVEL) {
567     break;
568     }
569     winPtr = winPtr->parentPtr;
570     }
571     TkpSetCursor((TkpCursor) cursor);
572     }
573    
574     /*
575     *----------------------------------------------------------------------
576     *
577     * XDefineCursor --
578     *
579     * This function is called to update the cursor on a window.
580     * Since the mouse might be in the specified window, we need to
581     * check the specified window against the current mouse position
582     * and grab state.
583     *
584     * Results:
585     * None.
586     *
587     * Side effects:
588     * May update the cursor.
589     *
590     *----------------------------------------------------------------------
591     */
592    
593     void
594     XDefineCursor(display, w, cursor)
595     Display* display;
596     Window w;
597     Cursor cursor;
598     {
599     TkWindow *winPtr = (TkWindow *)Tk_IdToWindow(display, w);
600     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
601     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
602    
603     if (tsdPtr->cursorWinPtr == winPtr) {
604     UpdateCursor(winPtr);
605     }
606     display->request++;
607     }
608    
609     /*
610     *----------------------------------------------------------------------
611     *
612     * TkGenerateActivateEvents --
613     *
614     * This function is called by the Mac and Windows window manager
615     * routines when a toplevel window is activated or deactivated.
616     * Activate/Deactivate events will be sent to every subwindow of
617     * the toplevel followed by a FocusIn/FocusOut message.
618     *
619     * Results:
620     * None.
621     *
622     * Side effects:
623     * Generates X events.
624     *
625     *----------------------------------------------------------------------
626     */
627    
628     void
629     TkGenerateActivateEvents(winPtr, active)
630     TkWindow *winPtr; /* Toplevel to activate. */
631     int active; /* Non-zero if the window is being
632     * activated, else 0.*/
633     {
634     XEvent event;
635    
636     /*
637     * Generate Activate and Deactivate events. This event
638     * is sent to every subwindow in a toplevel window.
639     */
640    
641     event.xany.serial = winPtr->display->request++;
642     event.xany.send_event = False;
643     event.xany.display = winPtr->display;
644     event.xany.window = winPtr->window;
645    
646     event.xany.type = active ? ActivateNotify : DeactivateNotify;
647     TkQueueEventForAllChildren(winPtr, &event);
648    
649     }
650    
651    
652     /* $History: tkPointer.c $
653     *
654     * ***************** Version 1 *****************
655     * User: Dtashley Date: 1/02/01 Time: 3:04a
656     * Created in $/IjuScripter, IjuConsole/Source/Tk Base
657     * Initial check-in.
658     */
659    
660     /* End of TKPOINTER.C */

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25