4 * This event handling stuff was based on Tk.
9 #include "../src/config.h"
11 #include <sys/types.h>
19 #ifdef HAVE_SYS_SELECT_H
20 # include <sys/select.h>
23 #ifdef HAVE_GETTIMEOFDAY
24 # include <sys/time.h>
25 # ifdef TIME_WITH_SYS_TIME
28 #else /* ! HAVE_GETTIMEOFDAY */
30 #endif /* ! HAVE_GETTIMEOFDAY */
33 extern _WINGsConfiguration WINGsConfiguration
;
37 typedef struct TimerHandler
{
38 WMCallback
*callback
; /* procedure to call */
39 struct timeval when
; /* when to call the callback */
41 struct TimerHandler
*next
;
45 typedef struct IdleHandler
{
48 struct IdleHandler
*next
;
52 typedef struct InputHandler
{
53 WMInputProc
*callback
;
57 struct InputHandler
*next
;
61 /* table to map event types to event masks */
62 static unsigned long eventMasks
[] = {
65 KeyPressMask
, /* KeyPress */
66 KeyReleaseMask
, /* KeyRelease */
67 ButtonPressMask
, /* ButtonPress */
68 ButtonReleaseMask
, /* ButtonRelease */
69 PointerMotionMask
|PointerMotionHintMask
|ButtonMotionMask
70 |Button1MotionMask
|Button2MotionMask
|Button3MotionMask
71 |Button4MotionMask
|Button5MotionMask
,
73 EnterWindowMask
, /* EnterNotify */
74 LeaveWindowMask
, /* LeaveNotify */
75 FocusChangeMask
, /* FocusIn */
76 FocusChangeMask
, /* FocusOut */
77 KeymapStateMask
, /* KeymapNotify */
78 ExposureMask
, /* Expose */
79 ExposureMask
, /* GraphicsExpose */
80 ExposureMask
, /* NoExpose */
81 VisibilityChangeMask
, /* VisibilityNotify */
82 SubstructureNotifyMask
, /* CreateNotify */
83 StructureNotifyMask
, /* DestroyNotify */
84 StructureNotifyMask
, /* UnmapNotify */
85 StructureNotifyMask
, /* MapNotify */
86 SubstructureRedirectMask
, /* MapRequest */
87 StructureNotifyMask
, /* ReparentNotify */
88 StructureNotifyMask
, /* ConfigureNotify */
89 SubstructureRedirectMask
, /* ConfigureRequest */
90 StructureNotifyMask
, /* GravityNotify */
91 ResizeRedirectMask
, /* ResizeRequest */
92 StructureNotifyMask
, /* CirculateNotify */
93 SubstructureRedirectMask
, /* CirculateRequest */
94 PropertyChangeMask
, /* PropertyNotify */
95 0, /* SelectionClear */
96 0, /* SelectionRequest */
97 0, /* SelectionNotify */
98 ColormapChangeMask
, /* ColormapNotify */
99 ClientMessageMask
, /* ClientMessage */
100 0, /* Mapping Notify */
105 /* queue of timer event handlers */
106 static TimerHandler
*timerHandler
=NULL
;
108 static IdleHandler
*idleHandler
=NULL
;
110 static InputHandler
*inputHandler
=NULL
;
112 /* hook for other toolkits or wmaker process their events */
113 static WMEventHook
*extraEventHandler
=NULL
;
117 #define timerPending() (timerHandler)
119 #define idlePending() (idleHandler)
122 #ifdef HAVE_GETTIMEOFDAY
124 rightNow(struct timeval
*tv
) {
125 gettimeofday(tv
, NULL
);
127 #else /* !HAVE_GETTIMEOFDAY */
128 # define rightNow(tv) (tv)->tv_sec==time(NULL),(tv)->tv_usec=0
129 #endif /* !HAVE_GETTIMEOFDAY */
132 /* is t1 after t2 ? */
133 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
134 (((t1).tv_sec == (t2).tv_sec) \
135 && ((t1).tv_usec > (t2).tv_usec)))
139 addmillisecs(struct timeval
*tv
, int milliseconds
)
141 tv
->tv_usec
+= milliseconds
*1000;
143 tv
->tv_sec
+= tv
->tv_usec
/1000000;
144 tv
->tv_usec
= tv
->tv_usec
%1000000;
149 WMAddTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
151 TimerHandler
*handler
, *tmp
;
153 handler
= malloc(sizeof(TimerHandler
));
157 rightNow(&handler
->when
);
158 addmillisecs(&handler
->when
, milliseconds
);
159 handler
->callback
= callback
;
160 handler
->clientData
= cdata
;
161 /* insert callback in queue, sorted by time left */
162 if (!timerHandler
|| !IS_AFTER(handler
->when
, timerHandler
->when
)) {
163 /* first in the queue */
164 handler
->next
= timerHandler
;
165 timerHandler
= handler
;
168 while (tmp
->next
&& IS_AFTER(handler
->when
, tmp
->next
->when
)) {
171 handler
->next
= tmp
->next
;
180 WMDeleteTimerWithClientData(void *cdata
)
182 TimerHandler
*handler
, *tmp
;
184 if (!cdata
|| !timerHandler
)
188 if (tmp
->clientData
==cdata
) {
189 timerHandler
= tmp
->next
;
193 if (tmp
->next
->clientData
==cdata
) {
195 tmp
->next
= handler
->next
;
207 WMDeleteTimerHandler(WMHandlerID handlerID
)
209 TimerHandler
*tmp
, *handler
=(TimerHandler
*)handlerID
;
211 if (!handler
|| !timerHandler
)
216 timerHandler
= handler
->next
;
220 if (tmp
->next
==handler
) {
221 tmp
->next
=handler
->next
;
233 WMAddIdleHandler(WMCallback
*callback
, void *cdata
)
235 IdleHandler
*handler
, *tmp
;
237 handler
= malloc(sizeof(IdleHandler
));
241 handler
->callback
= callback
;
242 handler
->clientData
= cdata
;
243 handler
->next
= NULL
;
244 /* add callback at end of queue */
246 idleHandler
= handler
;
261 WMDeleteIdleHandler(WMHandlerID handlerID
)
263 IdleHandler
*tmp
, *handler
= (IdleHandler
*)handlerID
;
265 if (!handler
|| !idleHandler
)
269 if (tmp
== handler
) {
270 idleHandler
= handler
->next
;
274 if (tmp
->next
== handler
) {
275 tmp
->next
= handler
->next
;
287 WMAddInputHandler(int fd
, int condition
, WMInputProc
*proc
, void *clientData
)
289 InputHandler
*handler
;
291 handler
= wmalloc(sizeof(InputHandler
));
294 handler
->mask
= condition
;
295 handler
->callback
= proc
;
296 handler
->clientData
= clientData
;
298 handler
->next
= inputHandler
;
300 inputHandler
= handler
;
307 WMDeleteInputHandler(WMHandlerID handlerID
)
309 InputHandler
*tmp
, *handler
= (InputHandler
*)handlerID
;
311 if (!handler
|| !inputHandler
)
315 if (tmp
== handler
) {
316 inputHandler
= handler
->next
;
320 if (tmp
->next
== handler
) {
321 tmp
->next
= handler
->next
;
334 IdleHandler
*handler
, *tmp
;
339 handler
= idleHandler
;
341 /* we will process all idleHandlers so, empty the handler list */
346 (*handler
->callback
)(handler
->clientData
);
347 /* remove the handler */
359 TimerHandler
*handler
;
364 while (timerHandler
&& IS_AFTER(now
, timerHandler
->when
)) {
365 handler
= timerHandler
;
366 timerHandler
= timerHandler
->next
;
367 handler
->next
= NULL
;
368 (*handler
->callback
)(handler
->clientData
);
376 delayUntilNextTimerEvent(struct timeval
*delay
)
381 /* The return value of this function is only valid if there _are_
389 if (IS_AFTER(now
, timerHandler
->when
)) {
393 delay
->tv_sec
= timerHandler
->when
.tv_sec
- now
.tv_sec
;
394 delay
->tv_usec
= timerHandler
->when
.tv_usec
- now
.tv_usec
;
395 if (delay
->tv_usec
< 0) {
396 delay
->tv_usec
+= 1000000;
406 * WMCreateEventHandler--
407 * Create an event handler and put it in the event handler list for the
408 * view. If the same callback and clientdata are already used in another
409 * handler, the masks are swapped.
413 WMCreateEventHandler(WMView
*view
, unsigned long mask
, WMEventProc
*eventProc
,
416 W_EventHandler
*handler
;
417 W_EventHandler
*ptr
= view
->handlerList
;
418 unsigned long eventMask
;
421 handler
= wmalloc(sizeof(W_EventHandler
));
423 handler
->nextHandler
= NULL
;
425 view
->handlerList
= handler
;
431 while (ptr
!= NULL
) {
432 if (ptr
->clientData
== clientData
&& ptr
->proc
== eventProc
) {
435 eventMask
|= ptr
->eventMask
;
437 ptr
= ptr
->nextHandler
;
440 handler
= wmalloc(sizeof(W_EventHandler
));
441 handler
->nextHandler
= view
->handlerList
;
442 view
->handlerList
= handler
;
446 /* select events for window */
447 handler
->eventMask
= mask
;
448 handler
->proc
= eventProc
;
449 handler
->clientData
= clientData
;
454 * WMDeleteEventHandler--
455 * Delete event handler matching arguments from windows
456 * event handler list.
460 WMDeleteEventHandler(WMView
*view
, unsigned long mask
, WMEventProc
*eventProc
,
463 W_EventHandler
*handler
, *ptr
, *pptr
;
465 ptr
= view
->handlerList
;
471 if (ptr
->eventMask
== mask
&& ptr
->proc
== eventProc
472 && ptr
->clientData
== clientData
) {
477 ptr
= ptr
->nextHandler
;
484 view
->handlerList
= handler
->nextHandler
;
486 pptr
->nextHandler
= handler
->nextHandler
;
494 W_CleanUpEvents(WMView
*view
)
496 W_EventHandler
*ptr
, *nptr
;
498 ptr
= view
->handlerList
;
501 nptr
= ptr
->nextHandler
;
510 getEventTime(WMScreen
*screen
, XEvent
*event
)
512 switch (event
->type
) {
515 return event
->xbutton
.time
;
518 return event
->xkey
.time
;
520 return event
->xmotion
.time
;
523 return event
->xcrossing
.time
;
525 return event
->xproperty
.time
;
527 return event
->xselectionclear
.time
;
528 case SelectionRequest
:
529 return event
->xselectionrequest
.time
;
530 case SelectionNotify
:
531 return event
->xselection
.time
;
533 return screen
->lastEventTime
;
539 W_CallDestroyHandlers(W_View
*view
)
542 W_EventHandler
*hPtr
;
544 event
.type
= DestroyNotify
;
545 event
.xdestroywindow
.window
= view
->window
;
546 event
.xdestroywindow
.event
= view
->window
;
547 hPtr
= view
->handlerList
;
549 if (hPtr
->eventMask
& StructureNotifyMask
) {
550 (*hPtr
->proc
)(&event
, hPtr
->clientData
);
553 hPtr
= hPtr
->nextHandler
;
559 WMHandleEvent(XEvent
*event
)
561 W_EventHandler
*hPtr
;
562 W_View
*view
, *vPtr
, *toplevel
;
566 if (event
->type
== MappingNotify
) {
567 XRefreshKeyboardMapping(&event
->xmapping
);
571 mask
= eventMasks
[event
->xany
.type
];
573 window
= event
->xany
.window
;
575 /* diferentiate SubstructureNotify with StructureNotify */
576 if (mask
== StructureNotifyMask
) {
577 if (event
->xmap
.event
!= event
->xmap
.window
) {
578 mask
= SubstructureNotifyMask
;
579 window
= event
->xmap
.event
;
582 view
= W_GetViewForXWindow(event
->xany
.display
, window
);
584 if (extraEventHandler
)
585 (extraEventHandler
)(event
);
590 view
->screen
->lastEventTime
= getEventTime(view
->screen
, event
);
592 toplevel
= W_TopLevelOfView(view
);
594 /* if it's a key event, redispatch it to the focused control */
595 if (mask
& (KeyPressMask
|KeyReleaseMask
)) {
596 W_View
*focused
= W_FocusedViewOfToplevel(toplevel
);
603 /* compress Motion events */
604 if (event
->type
== MotionNotify
&& !view
->flags
.dontCompressMotion
) {
605 while (XPending(event
->xmotion
.display
)) {
607 XPeekEvent(event
->xmotion
.display
, &ev
);
608 if (ev
.type
== MotionNotify
609 && event
->xmotion
.window
== ev
.xmotion
.window
610 && event
->xmotion
.subwindow
== ev
.xmotion
.subwindow
) {
612 XNextEvent(event
->xmotion
.display
, event
);
617 /* compress expose events */
618 if (event
->type
== Expose
&& !view
->flags
.dontCompressExpose
) {
619 while (XCheckTypedWindowEvent(event
->xexpose
.display
, view
->window
,
624 if (view
->screen
->modal
&& toplevel
!=view
->screen
->modalView
625 && !toplevel
->flags
.worksWhenModal
) {
626 if (event
->type
== KeyPress
|| event
->type
== KeyRelease
627 || event
->type
== MotionNotify
|| event
->type
== ButtonPress
628 || event
->type
== ButtonRelease
629 || event
->type
== FocusIn
|| event
->type
== FocusOut
) {
634 /* This is a hack. It will make the panel be secure while
635 * the event handlers are handled, as some event handler
636 * might destroy the widget. */
637 W_RetainView(toplevel
);
639 hPtr
= view
->handlerList
;
644 tmp
= hPtr
->nextHandler
;
646 if ((hPtr
->eventMask
& mask
)) {
647 (*hPtr
->proc
)(event
, hPtr
->clientData
);
653 /* pass the event to the top level window of the widget */
654 if (view
->parent
!=NULL
) {
656 while (vPtr
->parent
!=NULL
)
659 hPtr
= vPtr
->handlerList
;
663 if (hPtr
->eventMask
& mask
) {
664 (*hPtr
->proc
)(event
, hPtr
->clientData
);
666 hPtr
= hPtr
->nextHandler
;
670 /* save button click info to track double-clicks */
671 if (view
->screen
->ignoreNextDoubleClick
) {
672 view
->screen
->ignoreNextDoubleClick
= 0;
674 if (event
->type
== ButtonPress
) {
675 view
->screen
->lastClickWindow
= event
->xbutton
.window
;
676 view
->screen
->lastClickTime
= event
->xbutton
.time
;
680 W_ReleaseView(toplevel
);
687 WMIsDoubleClick(XEvent
*event
)
691 if (event
->type
!= ButtonPress
)
694 view
= W_GetViewForXWindow(event
->xany
.display
, event
->xbutton
.window
);
699 if (view
->screen
->lastClickWindow
!= event
->xbutton
.window
)
702 if (event
->xbutton
.time
- view
->screen
->lastClickTime
703 < WINGsConfiguration
.doubleClickDelay
) {
704 view
->screen
->lastClickTime
= 0;
705 view
->screen
->lastClickWindow
= None
;
706 view
->screen
->ignoreNextDoubleClick
= 1;
714 W_WaitForEvent(Display
*dpy
, unsigned long xeventmask
)
716 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
718 InputHandler
*handler
;
719 int count
, timeout
, nfds
, k
, retval
;
721 for (nfds
= 1, handler
= inputHandler
;
722 handler
!= 0; handler
= handler
->next
) nfds
++;
724 fds
= wmalloc(nfds
* sizeof(struct pollfd
));
725 fds
[0].fd
= ConnectionNumber(dpy
);
726 fds
[0].events
= POLLIN
;
728 for (k
= 1, handler
= inputHandler
;
730 handler
= handler
->next
, k
++) {
731 fds
[k
].fd
= handler
->fd
;
733 if (handler
->mask
& WIReadMask
)
734 fds
[k
].events
|= POLLIN
;
736 if (handler
->mask
& WIWriteMask
)
737 fds
[k
].events
|= POLLOUT
;
740 if (handler
->mask
& WIExceptMask
)
741 FD_SET(handler
->fd
, &eset
);
746 * Setup the select() timeout to the estimated time until the
747 * next timer expires.
749 if (timerPending()) {
751 delayUntilNextTimerEvent(&tv
);
752 timeout
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
762 if (XCheckMaskEvent(dpy
, xeventmask
, &ev
)) {
763 XPutBackEvent(dpy
, &ev
);
768 count
= poll(fds
, nfds
, timeout
);
771 handler
= inputHandler
;
778 if (fds
[k
].revents
& (POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
))
781 if (fds
[k
].revents
& (POLLOUT
| POLLWRBAND
))
784 if (fds
[k
].revents
& (POLLHUP
| POLLNVAL
| POLLERR
))
785 mask
|= WIExceptMask
;
787 if (mask
!=0 && handler
->callback
) {
788 (*handler
->callback
)(handler
->fd
, mask
,
789 handler
->clientData
);
792 handler
= handler
->next
;
797 retval
= fds
[0].revents
& (POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
);
801 #else /* not HAVE_POLL */
803 struct timeval timeout
;
804 struct timeval
*timeoutPtr
;
805 fd_set rset
, wset
, eset
;
808 InputHandler
*handler
= inputHandler
;
814 FD_SET(ConnectionNumber(dpy
), &rset
);
815 maxfd
= ConnectionNumber(dpy
);
818 if (handler
->mask
& WIReadMask
)
819 FD_SET(handler
->fd
, &rset
);
821 if (handler
->mask
& WIWriteMask
)
822 FD_SET(handler
->fd
, &wset
);
824 if (handler
->mask
& WIExceptMask
)
825 FD_SET(handler
->fd
, &eset
);
827 if (maxfd
< handler
->fd
)
830 handler
= handler
->next
;
835 * Setup the select() timeout to the estimated time until the
836 * next timer expires.
838 if (timerPending()) {
839 delayUntilNextTimerEvent(&timeout
);
840 timeoutPtr
= &timeout
;
842 timeoutPtr
= (struct timeval
*)0;
851 if (XCheckMaskEvent(dpy
, xeventmask
, &ev
)) {
852 XPutBackEvent(dpy
, &ev
);
857 count
= select(1 + maxfd
, &rset
, &wset
, &eset
, timeoutPtr
);
860 handler
= inputHandler
;
867 if (FD_ISSET(handler
->fd
, &rset
))
870 if (FD_ISSET(handler
->fd
, &wset
))
873 if (FD_ISSET(handler
->fd
, &eset
))
874 mask
|= WIExceptMask
;
876 if (mask
!=0 && handler
->callback
) {
877 (*handler
->callback
)(handler
->fd
, mask
,
878 handler
->clientData
);
881 handler
= handler
->next
;
885 return FD_ISSET(ConnectionNumber(dpy
), &rset
);
886 #else /* not HAVE_SELECT, not HAVE_POLL */
887 Neither select nor poll
. You lose
.
888 #endif /* HAVE_SELECT */
889 #endif /* HAVE_POLL */
893 WMNextEvent(Display
*dpy
, XEvent
*event
)
895 /* Check any expired timers */
896 if (timerPending()) {
897 checkTimerHandlers();
900 while (XPending(dpy
) == 0) {
902 /* Do idle and timer stuff while there are no timer or X events */
903 while (!XPending(dpy
) && idlePending()) {
906 /* dispatch timer events */
908 checkTimerHandlers();
912 * Make sure that new events did not arrive while we were doing
913 * timer/idle stuff. Or we might block forever waiting for
914 * an event that already arrived.
916 /* wait to something happen */
917 W_WaitForEvent(dpy
, 0);
919 /* Check any expired timers */
920 if (timerPending()) {
921 checkTimerHandlers();
925 XNextEvent(dpy
, event
);
930 WMMaskEvent(Display
*dpy
, long mask
, XEvent
*event
)
932 unsigned long milliseconds
;
933 struct timeval timeout
;
934 struct timeval
*timeoutOrInfty
;
937 while (!XCheckMaskEvent(dpy
, mask
, event
)) {
938 /* Do idle stuff while there are no timer or X events */
939 while (idlePending()) {
941 if (XCheckMaskEvent(dpy
, mask
, event
))
946 * Setup the select() timeout to the estimated time until the
947 * next timer expires.
949 if (timerPending()) {
950 delayUntilNextTimerEvent(&timeout
);
951 timeoutOrInfty
= &timeout
;
953 timeoutOrInfty
= (struct timeval
*)0;
956 if (XCheckMaskEvent(dpy
, mask
, event
))
959 /* Wait for input on the X connection socket */
961 FD_SET(ConnectionNumber(dpy
), &readset
);
962 select(1 + ConnectionNumber(dpy
), &readset
, (fd_set
*)0, (fd_set
*)0,
965 /* Check any expired timers */
966 if (timerPending()) {
967 checkTimerHandlers();
974 * Cant use this because XPending() will make W_WaitForEvent
975 * return even if the event in the queue is not what we want,
976 * and if we block until some new event arrives from the
977 * server, other events already in the queue (like Expose)
981 WMMaskEvent(Display
*dpy
, long mask
, XEvent
*event
)
983 while (!XCheckMaskEvent(dpy
, mask
, event
)) {
984 /* Do idle stuff while there are no timer or X events */
985 while (idlePending()) {
987 if (XCheckMaskEvent(dpy
, mask
, event
))
991 /* Wait for input on the X connection socket */
992 W_WaitForEvent(dpy
, mask
);
994 /* Check any expired timers */
995 if (timerPending()) {
996 checkTimerHandlers();
1003 WMScreenPending(WMScreen
*scr
)
1005 if (XPending(scr
->display
))
1013 WMHookEventHandler(WMEventHook
*handler
)
1015 WMEventHook
*oldHandler
= extraEventHandler
;
1017 extraEventHandler
= handler
;