4 * This event handling stuff was inspired on Tk.
9 #include "../src/config.h"
11 #include <sys/types.h>
21 #ifdef HAVE_SYS_SELECT_H
22 # include <sys/select.h>
27 #ifndef X_GETTIMEOFDAY
28 #define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
36 typedef struct TimerHandler
{
37 WMCallback
*callback
; /* procedure to call */
38 struct timeval when
; /* when to call the callback */
40 struct TimerHandler
*next
;
41 int nextDelay
; /* 0 if it's one-shot */
45 typedef struct IdleHandler
{
51 typedef struct InputHandler
{
52 WMInputProc
*callback
;
59 /* table to map event types to event masks */
60 static unsigned long eventMasks
[] = {
63 KeyPressMask
, /* KeyPress */
64 KeyReleaseMask
, /* KeyRelease */
65 ButtonPressMask
, /* ButtonPress */
66 ButtonReleaseMask
, /* ButtonRelease */
67 PointerMotionMask
|PointerMotionHintMask
|ButtonMotionMask
68 |Button1MotionMask
|Button2MotionMask
|Button3MotionMask
69 |Button4MotionMask
|Button5MotionMask
,
71 EnterWindowMask
, /* EnterNotify */
72 LeaveWindowMask
, /* LeaveNotify */
73 FocusChangeMask
, /* FocusIn */
74 FocusChangeMask
, /* FocusOut */
75 KeymapStateMask
, /* KeymapNotify */
76 ExposureMask
, /* Expose */
77 ExposureMask
, /* GraphicsExpose */
78 ExposureMask
, /* NoExpose */
79 VisibilityChangeMask
, /* VisibilityNotify */
80 SubstructureNotifyMask
, /* CreateNotify */
81 StructureNotifyMask
, /* DestroyNotify */
82 StructureNotifyMask
, /* UnmapNotify */
83 StructureNotifyMask
, /* MapNotify */
84 SubstructureRedirectMask
, /* MapRequest */
85 StructureNotifyMask
, /* ReparentNotify */
86 StructureNotifyMask
, /* ConfigureNotify */
87 SubstructureRedirectMask
, /* ConfigureRequest */
88 StructureNotifyMask
, /* GravityNotify */
89 ResizeRedirectMask
, /* ResizeRequest */
90 StructureNotifyMask
, /* CirculateNotify */
91 SubstructureRedirectMask
, /* CirculateRequest */
92 PropertyChangeMask
, /* PropertyNotify */
93 0, /* SelectionClear */
94 0, /* SelectionRequest */
95 0, /* SelectionNotify */
96 ColormapChangeMask
, /* ColormapNotify */
97 ClientMessageMask
, /* ClientMessage */
98 0, /* Mapping Notify */
103 /* queue of timer event handlers */
104 static TimerHandler
*timerHandler
=NULL
;
106 static WMBag
*idleHandler
=NULL
;
108 static WMBag
*inputHandler
=NULL
;
110 /* hook for other toolkits or wmaker process their events */
111 static WMEventHook
*extraEventHandler
=NULL
;
115 #define timerPending() (timerHandler)
120 rightNow(struct timeval
*tv
) {
124 /* is t1 after t2 ? */
125 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
126 (((t1).tv_sec == (t2).tv_sec) \
127 && ((t1).tv_usec > (t2).tv_usec)))
129 #define IS_ZERO(tv) (tv.tv_sec == 0 && tv.tv_usec == 0)
131 #define SET_ZERO(tv) tv.tv_sec = 0, tv.tv_usec = 0
134 addmillisecs(struct timeval
*tv
, int milliseconds
)
136 tv
->tv_usec
+= milliseconds
*1000;
138 tv
->tv_sec
+= tv
->tv_usec
/1000000;
139 tv
->tv_usec
= tv
->tv_usec
%1000000;
144 enqueueTimerHandler(TimerHandler
*handler
)
148 /* insert callback in queue, sorted by time left */
149 if (!timerHandler
|| !IS_AFTER(handler
->when
, timerHandler
->when
)) {
150 /* first in the queue */
151 handler
->next
= timerHandler
;
152 timerHandler
= handler
;
155 while (tmp
->next
&& IS_AFTER(handler
->when
, tmp
->next
->when
)) {
158 handler
->next
= tmp
->next
;
165 WMAddTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
167 TimerHandler
*handler
;
169 handler
= malloc(sizeof(TimerHandler
));
173 rightNow(&handler
->when
);
174 addmillisecs(&handler
->when
, milliseconds
);
175 handler
->callback
= callback
;
176 handler
->clientData
= cdata
;
177 handler
->nextDelay
= 0;
179 enqueueTimerHandler(handler
);
186 WMAddEternalTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
188 TimerHandler
*handler
= WMAddTimerHandler(milliseconds
, callback
, cdata
);
191 handler
->nextDelay
= milliseconds
;
199 WMDeleteTimerWithClientData(void *cdata
)
201 TimerHandler
*handler
, *tmp
;
203 if (!cdata
|| !timerHandler
)
207 if (tmp
->clientData
==cdata
) {
209 if (!IS_ZERO(tmp
->when
)) {
210 timerHandler
= tmp
->next
;
215 if (tmp
->next
->clientData
==cdata
) {
217 handler
->nextDelay
= 0;
218 if (IS_ZERO(handler
->when
))
220 tmp
->next
= handler
->next
;
232 WMDeleteTimerHandler(WMHandlerID handlerID
)
234 TimerHandler
*tmp
, *handler
=(TimerHandler
*)handlerID
;
236 if (!handler
|| !timerHandler
)
241 handler
->nextDelay
= 0;
243 if (IS_ZERO(handler
->when
))
247 timerHandler
= handler
->next
;
251 if (tmp
->next
==handler
) {
252 tmp
->next
=handler
->next
;
264 WMAddIdleHandler(WMCallback
*callback
, void *cdata
)
266 IdleHandler
*handler
;
268 handler
= malloc(sizeof(IdleHandler
));
272 handler
->callback
= callback
;
273 handler
->clientData
= cdata
;
274 /* add handler at end of queue */
276 idleHandler
= WMCreateBag(16);
278 WMPutInBag(idleHandler
, handler
);
285 WMDeleteIdleHandler(WMHandlerID handlerID
)
287 IdleHandler
*handler
= (IdleHandler
*)handlerID
;
290 if (!handler
|| !idleHandler
)
293 pos
= WMGetFirstInBag(idleHandler
, handler
);
294 if (pos
!= WBNotFound
) {
296 WMDeleteFromBag(idleHandler
, pos
);
303 WMAddInputHandler(int fd
, int condition
, WMInputProc
*proc
, void *clientData
)
305 InputHandler
*handler
;
307 handler
= wmalloc(sizeof(InputHandler
));
310 handler
->mask
= condition
;
311 handler
->callback
= proc
;
312 handler
->clientData
= clientData
;
315 inputHandler
= WMCreateBag(16);
316 WMPutInBag(inputHandler
, handler
);
324 WMDeleteInputHandler(WMHandlerID handlerID
)
326 InputHandler
*handler
= (InputHandler
*)handlerID
;
329 if (!handler
|| !inputHandler
)
332 pos
= WMGetFirstInBag(inputHandler
, handler
);
333 if (pos
!= WBNotFound
) {
335 WMDeleteFromBag(inputHandler
, pos
);
344 IdleHandler
*handler
;
348 if (!idleHandler
|| WMGetBagItemCount(idleHandler
)==0) {
349 W_FlushIdleNotificationQueue();
350 /* make sure an observer in queue didn't added an idle handler */
351 return (idleHandler
!=NULL
&& WMGetBagItemCount(idleHandler
)>0);
354 handlerCopy
= WMCreateBag(WMGetBagItemCount(idleHandler
));
355 WMAppendBag(handlerCopy
, idleHandler
);
357 for (handler
= WMBagFirst(handlerCopy
, &iter
);
359 handler
= WMBagNext(handlerCopy
, &iter
)) {
360 /* check if the handler still exist or was removed by a callback */
361 if (WMGetFirstInBag(idleHandler
, handler
) == WBNotFound
)
364 (*handler
->callback
)(handler
->clientData
);
365 WMDeleteIdleHandler(handler
);
368 WMFreeBag(handlerCopy
);
370 W_FlushIdleNotificationQueue();
372 /* this is not necesarrily False, because one handler can re-add itself */
373 return (WMGetBagItemCount(idleHandler
)>0);
381 TimerHandler
*handler
;
385 W_FlushASAPNotificationQueue();
391 handler
= timerHandler
;
392 while (handler
&& IS_AFTER(now
, handler
->when
)) {
393 if (!IS_ZERO(handler
->when
)) {
394 SET_ZERO(handler
->when
);
395 (*handler
->callback
)(handler
->clientData
);
397 handler
= handler
->next
;
400 while (timerHandler
&& IS_ZERO(handler
->when
)) {
401 handler
= timerHandler
;
402 timerHandler
= timerHandler
->next
;
404 if (handler
->nextDelay
> 0) {
406 addmillisecs(&handler
->when
, handler
->nextDelay
);
407 enqueueTimerHandler(handler
);
413 W_FlushASAPNotificationQueue();
419 delayUntilNextTimerEvent(struct timeval
*delay
)
422 TimerHandler
*handler
;
424 handler
= timerHandler
;
425 while (handler
&& IS_ZERO(handler
->when
)) handler
= handler
->next
;
428 /* The return value of this function is only valid if there _are_
436 if (IS_AFTER(now
, handler
->when
)) {
440 delay
->tv_sec
= handler
->when
.tv_sec
- now
.tv_sec
;
441 delay
->tv_usec
= handler
->when
.tv_usec
- now
.tv_usec
;
442 if (delay
->tv_usec
< 0) {
443 delay
->tv_usec
+= 1000000;
453 * WMCreateEventHandler--
454 * Create an event handler and put it in the event handler list for the
455 * view. If the same callback and clientdata are already used in another
456 * handler, the masks are swapped.
460 WMCreateEventHandler(WMView
*view
, unsigned long mask
, WMEventProc
*eventProc
,
463 W_EventHandler
*handler
, *ptr
;
464 unsigned long eventMask
;
471 WM_ITERATE_BAG(view
->eventHandlers
, ptr
, iter
) {
472 if (ptr
->clientData
== clientData
&& ptr
->proc
== eventProc
) {
474 eventMask
|= ptr
->eventMask
;
478 handler
= wmalloc(sizeof(W_EventHandler
));
480 WMPutInBag(view
->eventHandlers
, handler
);
482 /* select events for window */
483 handler
->eventMask
= eventMask
;
484 handler
->proc
= eventProc
;
485 handler
->clientData
= clientData
;
490 * WMDeleteEventHandler--
491 * Delete event handler matching arguments from windows
492 * event handler list.
496 WMDeleteEventHandler(WMView
*view
, unsigned long mask
, WMEventProc
*eventProc
,
499 W_EventHandler
*handler
, *ptr
;
504 WM_ITERATE_BAG(view
->eventHandlers
, ptr
, iter
) {
505 if (ptr
->eventMask
== mask
&& ptr
->proc
== eventProc
506 && ptr
->clientData
== clientData
) {
515 WMRemoveFromBag(view
->eventHandlers
, handler
);
523 W_CleanUpEvents(WMView
*view
)
528 WM_ITERATE_BAG(view
->eventHandlers
, ptr
, iter
) {
536 getEventTime(WMScreen
*screen
, XEvent
*event
)
538 switch (event
->type
) {
541 return event
->xbutton
.time
;
544 return event
->xkey
.time
;
546 return event
->xmotion
.time
;
549 return event
->xcrossing
.time
;
551 return event
->xproperty
.time
;
553 return event
->xselectionclear
.time
;
554 case SelectionRequest
:
555 return event
->xselectionrequest
.time
;
556 case SelectionNotify
:
557 return event
->xselection
.time
;
559 return screen
->lastEventTime
;
565 W_CallDestroyHandlers(W_View
*view
)
569 W_EventHandler
*hPtr
;
571 event
.type
= DestroyNotify
;
572 event
.xdestroywindow
.window
= view
->window
;
573 event
.xdestroywindow
.event
= view
->window
;
575 WM_ITERATE_BAG(view
->eventHandlers
, hPtr
, iter
) {
576 if (hPtr
->eventMask
& StructureNotifyMask
) {
577 (*hPtr
->proc
)(&event
, hPtr
->clientData
);
585 WMSetViewNextResponder(WMView
*view
, WMView
*responder
)
587 /* set the widget to receive keyboard events that aren't handled
590 view
->nextResponder
= responder
;
595 WMRelayToNextResponder(WMView
*view
, XEvent
*event
)
597 unsigned long mask
= eventMasks
[event
->xany
.type
];
599 if (view
->nextResponder
) {
600 WMView
*next
= view
->nextResponder
;
601 W_EventHandler
*hPtr
;
604 WM_ITERATE_BAG(next
->eventHandlers
, hPtr
, iter
) {
605 if ((hPtr
->eventMask
& mask
)) {
606 (*hPtr
->proc
)(event
, hPtr
->clientData
);
614 WMHandleEvent(XEvent
*event
)
616 W_EventHandler
*hPtr
;
617 W_View
*view
, *vPtr
, *toplevel
;
622 if (event
->type
== MappingNotify
) {
623 XRefreshKeyboardMapping(&event
->xmapping
);
627 mask
= eventMasks
[event
->xany
.type
];
629 window
= event
->xany
.window
;
631 /* diferentiate SubstructureNotify with StructureNotify */
632 if (mask
== StructureNotifyMask
) {
633 if (event
->xmap
.event
!= event
->xmap
.window
) {
634 mask
= SubstructureNotifyMask
;
635 window
= event
->xmap
.event
;
638 view
= W_GetViewForXWindow(event
->xany
.display
, window
);
641 if (extraEventHandler
)
642 (extraEventHandler
)(event
);
647 view
->screen
->lastEventTime
= getEventTime(view
->screen
, event
);
649 toplevel
= W_TopLevelOfView(view
);
651 if (event
->type
== SelectionNotify
|| event
->type
== SelectionClear
652 || event
->type
== SelectionRequest
) {
653 /* handle selection related events */
654 W_HandleSelectionEvent(event
);
656 } else if (event
->type
== ClientMessage
) {
658 W_HandleDNDClientMessage(toplevel
, &event
->xclient
);
661 /* if it's a key event, redispatch it to the focused control */
662 if (mask
& (KeyPressMask
|KeyReleaseMask
)) {
663 W_View
*focused
= W_FocusedViewOfToplevel(toplevel
);
670 /* compress Motion events */
671 if (event
->type
== MotionNotify
&& !view
->flags
.dontCompressMotion
) {
672 while (XPending(event
->xmotion
.display
)) {
674 XPeekEvent(event
->xmotion
.display
, &ev
);
675 if (ev
.type
== MotionNotify
676 && event
->xmotion
.window
== ev
.xmotion
.window
677 && event
->xmotion
.subwindow
== ev
.xmotion
.subwindow
) {
679 XNextEvent(event
->xmotion
.display
, event
);
684 /* compress expose events */
685 if (event
->type
== Expose
&& !view
->flags
.dontCompressExpose
) {
686 while (XCheckTypedWindowEvent(event
->xexpose
.display
, view
->window
,
691 if (view
->screen
->modalLoop
&& toplevel
!=view
->screen
->modalView
692 && !toplevel
->flags
.worksWhenModal
) {
693 if (event
->type
== KeyPress
|| event
->type
== KeyRelease
694 || event
->type
== MotionNotify
|| event
->type
== ButtonPress
695 || event
->type
== ButtonRelease
696 || event
->type
== FocusIn
|| event
->type
== FocusOut
) {
701 /* do balloon stuffs */
702 if (event
->type
== EnterNotify
)
703 W_BalloonHandleEnterView(view
);
704 else if (event
->type
== LeaveNotify
)
705 W_BalloonHandleLeaveView(view
);
707 /* This is a hack. It will make the panel be secure while
708 * the event handlers are handled, as some event handler
709 * might destroy the widget. */
710 W_RetainView(toplevel
);
712 WM_ITERATE_BAG(view
->eventHandlers
, hPtr
, iter
) {
713 if ((hPtr
->eventMask
& mask
)) {
714 (*hPtr
->proc
)(event
, hPtr
->clientData
);
718 /* pass the event to the top level window of the widget */
719 /* TODO: change this to a responder chain */
720 if (view
->parent
!= NULL
) {
722 while (vPtr
->parent
!= NULL
)
725 WM_ITERATE_BAG(vPtr
->eventHandlers
, hPtr
, iter
) {
726 if (hPtr
->eventMask
& mask
) {
727 (*hPtr
->proc
)(event
, hPtr
->clientData
);
732 /* save button click info to track double-clicks */
733 if (view
->screen
->ignoreNextDoubleClick
) {
734 view
->screen
->ignoreNextDoubleClick
= 0;
736 if (event
->type
== ButtonPress
) {
737 view
->screen
->lastClickWindow
= event
->xbutton
.window
;
738 view
->screen
->lastClickTime
= event
->xbutton
.time
;
742 W_ReleaseView(toplevel
);
749 WMIsDoubleClick(XEvent
*event
)
753 if (event
->type
!= ButtonPress
)
756 view
= W_GetViewForXWindow(event
->xany
.display
, event
->xbutton
.window
);
761 if (view
->screen
->lastClickWindow
!= event
->xbutton
.window
)
764 if (event
->xbutton
.time
- view
->screen
->lastClickTime
765 < WINGsConfiguration
.doubleClickDelay
) {
766 view
->screen
->lastClickTime
= 0;
767 view
->screen
->lastClickWindow
= None
;
768 view
->screen
->ignoreNextDoubleClick
= 1;
776 W_WaitForEvent(Display
*dpy
, unsigned long xeventmask
)
778 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
780 InputHandler
*handler
;
781 int count
, timeout
, nfds
, i
, retval
;
784 nfds
= WMGetBagItemCount(inputHandler
);
788 fds
= wmalloc(nfds
+1 * sizeof(struct pollfd
));
789 /* put this to the end of array to avoid using ranges from 1 to nfds+1 */
790 fds
[nfds
].fd
= ConnectionNumber(dpy
);
791 fds
[nfds
].events
= POLLIN
;
793 for (i
= 0; i
<nfds
; i
++) {
794 handler
= WMGetFromBag(inputHandler
, i
);
795 fds
[i
].fd
= handler
->fd
;
797 if (handler
->mask
& WIReadMask
)
798 fds
[i
].events
|= POLLIN
;
800 if (handler
->mask
& WIWriteMask
)
801 fds
[i
].events
|= POLLOUT
;
804 if (handler
->mask
& WIExceptMask
)
805 FD_SET(handler
->fd
, &eset
);
810 * Setup the select() timeout to the estimated time until the
811 * next timer expires.
813 if (timerPending()) {
815 delayUntilNextTimerEvent(&tv
);
816 timeout
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
826 if (XCheckMaskEvent(dpy
, xeventmask
, &ev
)) {
827 XPutBackEvent(dpy
, &ev
);
832 count
= poll(fds
, nfds
, timeout
);
834 if (count
>0 && nfds
>0) {
835 WMBag
*handlerCopy
= WMCreateBag(nfds
);
837 for (i
=0; i
<nfds
; i
++)
838 WMPutInBag(handlerCopy
, WMGetFromBag(inputHandler
, i
));
840 for (i
=0; i
<nfds
; i
++) {
843 handler
= WMGetFromBag(handlerCopy
, i
);
844 /* check if the handler still exist or was removed by a callback */
845 if (WMGetFirstInBag(inputHandler
, handler
) == WBNotFound
)
850 if ((handler
->mask
& WIReadMask
) &&
851 (fds
[i
].revents
& (POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
)))
854 if ((handler
->mask
& WIWriteMask
) &&
855 (fds
[i
].revents
& (POLLOUT
| POLLWRBAND
)))
858 if ((handler
->mask
& WIExceptMask
) &&
859 (fds
[i
].revents
& (POLLHUP
| POLLNVAL
| POLLERR
)))
860 mask
|= WIExceptMask
;
862 if (mask
!=0 && handler
->callback
) {
863 (*handler
->callback
)(handler
->fd
, mask
,
864 handler
->clientData
);
868 WMFreeBag(handlerCopy
);
871 retval
= fds
[nfds
].revents
& (POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
);
874 W_FlushASAPNotificationQueue();
877 #else /* not HAVE_POLL */
879 struct timeval timeout
;
880 struct timeval
*timeoutPtr
;
881 fd_set rset
, wset
, eset
;
884 InputHandler
*handler
;
890 FD_SET(ConnectionNumber(dpy
), &rset
);
891 maxfd
= ConnectionNumber(dpy
);
894 nfds
= WMGetBagItemCount(inputHandler
);
898 for (i
=0; i
<nfds
; i
++) {
899 handler
= WMGetFromBag(inputHandler
, i
);
900 if (handler
->mask
& WIReadMask
)
901 FD_SET(handler
->fd
, &rset
);
903 if (handler
->mask
& WIWriteMask
)
904 FD_SET(handler
->fd
, &wset
);
906 if (handler
->mask
& WIExceptMask
)
907 FD_SET(handler
->fd
, &eset
);
909 if (maxfd
< handler
->fd
)
915 * Setup the select() timeout to the estimated time until the
916 * next timer expires.
918 if (timerPending()) {
919 delayUntilNextTimerEvent(&timeout
);
920 timeoutPtr
= &timeout
;
922 timeoutPtr
= (struct timeval
*)0;
931 if (XCheckMaskEvent(dpy
, xeventmask
, &ev
)) {
932 XPutBackEvent(dpy
, &ev
);
937 count
= select(1 + maxfd
, &rset
, &wset
, &eset
, timeoutPtr
);
939 if (count
>0 && nfds
>0) {
940 WMBag
*handlerCopy
= WMCreateBag(nfds
);
942 for (i
=0; i
<nfds
; i
++)
943 WMPutInBag(handlerCopy
, WMGetFromBag(inputHandler
, i
));
945 for (i
=0; i
<nfds
; i
++) {
948 handler
= WMGetFromBag(handlerCopy
, i
);
949 /* check if the handler still exist or was removed by a callback */
950 if (WMGetFirstInBag(inputHandler
, handler
) == WBNotFound
)
955 if ((handler
->mask
& WIReadMask
) && FD_ISSET(handler
->fd
, &rset
))
958 if ((handler
->mask
& WIWriteMask
) && FD_ISSET(handler
->fd
, &wset
))
961 if ((handler
->mask
& WIExceptMask
) && FD_ISSET(handler
->fd
, &eset
))
962 mask
|= WIExceptMask
;
964 if (mask
!=0 && handler
->callback
) {
965 (*handler
->callback
)(handler
->fd
, mask
,
966 handler
->clientData
);
970 WMFreeBag(handlerCopy
);
973 W_FlushASAPNotificationQueue();
975 return FD_ISSET(ConnectionNumber(dpy
), &rset
);
976 #else /* not HAVE_SELECT, not HAVE_POLL */
977 Neither select nor poll
. You lose
.
978 #endif /* HAVE_SELECT */
979 #endif /* HAVE_POLL */
984 WMNextEvent(Display
*dpy
, XEvent
*event
)
986 /* Check any expired timers */
987 checkTimerHandlers();
989 while (XPending(dpy
) == 0) {
991 /* Do idle and timer stuff while there are no timer or X events */
992 while (XPending(dpy
) == 0 && checkIdleHandlers()) {
993 /* dispatch timer events */
994 checkTimerHandlers();
998 * Make sure that new events did not arrive while we were doing
999 * timer/idle stuff. Or we might block forever waiting for
1000 * an event that already arrived.
1002 /* wait for something to happen or a timer to expire */
1003 W_WaitForEvent(dpy
, 0);
1005 /* Check any expired timers */
1006 checkTimerHandlers();
1009 XNextEvent(dpy
, event
);
1014 WMMaskEvent(Display
*dpy
, long mask
, XEvent
*event
)
1016 unsigned long milliseconds
;
1017 struct timeval timeout
;
1018 struct timeval
*timeoutOrInfty
;
1021 while (!XCheckMaskEvent(dpy
, mask
, event
)) {
1022 /* Do idle stuff while there are no timer or X events */
1023 while (checkIdleHandlers()) {
1024 if (XCheckMaskEvent(dpy
, mask
, event
))
1029 * Setup the select() timeout to the estimated time until the
1030 * next timer expires.
1032 if (timerPending()) {
1033 delayUntilNextTimerEvent(&timeout
);
1034 timeoutOrInfty
= &timeout
;
1036 timeoutOrInfty
= (struct timeval
*)0;
1039 if (XCheckMaskEvent(dpy
, mask
, event
))
1042 /* Wait for input on the X connection socket */
1044 FD_SET(ConnectionNumber(dpy
), &readset
);
1045 select(1 + ConnectionNumber(dpy
), &readset
, (fd_set
*)0, (fd_set
*)0,
1048 /* Check any expired timers */
1049 checkTimerHandlers();
1055 * Cant use this because XPending() will make W_WaitForEvent
1056 * return even if the event in the queue is not what we want,
1057 * and if we block until some new event arrives from the
1058 * server, other events already in the queue (like Expose)
1062 WMMaskEvent(Display
*dpy
, long mask
, XEvent
*event
)
1064 while (!XCheckMaskEvent(dpy
, mask
, event
)) {
1065 /* Do idle stuff while there are no timer or X events */
1066 while (checkIdleHandlers()) {
1067 if (XCheckMaskEvent(dpy
, mask
, event
))
1071 /* Wait for input on the X connection socket */
1072 W_WaitForEvent(dpy
, mask
);
1074 /* Check any expired timers */
1075 checkTimerHandlers();
1081 WMScreenPending(WMScreen
*scr
)
1083 if (XPending(scr
->display
))
1091 WMHookEventHandler(WMEventHook
*handler
)
1093 WMEventHook
*oldHandler
= extraEventHandler
;
1095 extraEventHandler
= handler
;