4 * This event handling stuff was based on Tk.
9 #include "../src/config.h"
11 #include <sys/types.h>
14 #ifdef HAVE_SYS_SELECT_H
15 # include <sys/select.h>
18 #ifdef HAVE_GETTIMEOFDAY
19 # include <sys/time.h>
20 # ifdef TIME_WITH_SYS_TIME
23 #else /* ! HAVE_GETTIMEOFDAY */
25 #endif /* ! HAVE_GETTIMEOFDAY */
28 extern _WINGsConfiguration WINGsConfiguration
;
32 typedef struct TimerHandler
{
33 WMCallback
*callback
; /* procedure to call */
34 struct timeval when
; /* when to call the callback */
36 struct TimerHandler
*next
;
40 typedef struct IdleHandler
{
43 struct IdleHandler
*next
;
47 typedef struct InputHandler
{
48 WMInputProc
*callback
;
52 struct InputHandler
*next
;
56 /* table to map event types to event masks */
57 static unsigned long eventMasks
[] = {
60 KeyPressMask
, /* KeyPress */
61 KeyReleaseMask
, /* KeyRelease */
62 ButtonPressMask
, /* ButtonPress */
63 ButtonReleaseMask
, /* ButtonRelease */
64 PointerMotionMask
|PointerMotionHintMask
|ButtonMotionMask
65 |Button1MotionMask
|Button2MotionMask
|Button3MotionMask
66 |Button4MotionMask
|Button5MotionMask
,
68 EnterWindowMask
, /* EnterNotify */
69 LeaveWindowMask
, /* LeaveNotify */
70 FocusChangeMask
, /* FocusIn */
71 FocusChangeMask
, /* FocusOut */
72 KeymapStateMask
, /* KeymapNotify */
73 ExposureMask
, /* Expose */
74 ExposureMask
, /* GraphicsExpose */
75 ExposureMask
, /* NoExpose */
76 VisibilityChangeMask
, /* VisibilityNotify */
77 SubstructureNotifyMask
, /* CreateNotify */
78 StructureNotifyMask
, /* DestroyNotify */
79 StructureNotifyMask
, /* UnmapNotify */
80 StructureNotifyMask
, /* MapNotify */
81 SubstructureRedirectMask
, /* MapRequest */
82 StructureNotifyMask
, /* ReparentNotify */
83 StructureNotifyMask
, /* ConfigureNotify */
84 SubstructureRedirectMask
, /* ConfigureRequest */
85 StructureNotifyMask
, /* GravityNotify */
86 ResizeRedirectMask
, /* ResizeRequest */
87 StructureNotifyMask
, /* CirculateNotify */
88 SubstructureRedirectMask
, /* CirculateRequest */
89 PropertyChangeMask
, /* PropertyNotify */
90 0, /* SelectionClear */
91 0, /* SelectionRequest */
92 0, /* SelectionNotify */
93 ColormapChangeMask
, /* ColormapNotify */
94 ClientMessageMask
, /* ClientMessage */
95 0, /* Mapping Notify */
100 /* queue of timer event handlers */
101 static TimerHandler
*timerHandler
=NULL
;
103 static IdleHandler
*idleHandler
=NULL
;
105 static InputHandler
*inputHandler
=NULL
;
107 /* hook for other toolkits or wmaker process their events */
108 static WMEventHook
*extraEventHandler
=NULL
;
112 #define timerPending() (timerHandler)
114 #define idlePending() (idleHandler)
117 #ifdef HAVE_GETTIMEOFDAY
119 rightNow(struct timeval
*tv
) {
120 gettimeofday(tv
, NULL
);
122 #else /* !HAVE_GETTIMEOFDAY */
123 # define rightNow(tv) (tv)->tv_sec==time(NULL),(tv)->tv_usec=0
124 #endif /* !HAVE_GETTIMEOFDAY */
127 /* is t1 after t2 ? */
128 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
129 (((t1).tv_sec == (t2).tv_sec) \
130 && ((t1).tv_usec > (t2).tv_usec)))
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 WMAddTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
146 TimerHandler
*handler
, *tmp
;
148 handler
= malloc(sizeof(TimerHandler
));
152 rightNow(&handler
->when
);
153 addmillisecs(&handler
->when
, milliseconds
);
154 handler
->callback
= callback
;
155 handler
->clientData
= cdata
;
156 /* insert callback in queue, sorted by time left */
157 if (!timerHandler
|| !IS_AFTER(handler
->when
, timerHandler
->when
)) {
158 /* first in the queue */
159 handler
->next
= timerHandler
;
160 timerHandler
= handler
;
163 while (tmp
->next
&& IS_AFTER(handler
->when
, tmp
->next
->when
)) {
166 handler
->next
= tmp
->next
;
175 WMDeleteTimerWithClientData(void *cdata
)
177 TimerHandler
*handler
, *tmp
;
179 if (!cdata
|| !timerHandler
)
183 if (tmp
->clientData
==cdata
) {
184 timerHandler
= tmp
->next
;
188 if (tmp
->next
->clientData
==cdata
) {
190 tmp
->next
= handler
->next
;
202 WMDeleteTimerHandler(WMHandlerID handlerID
)
204 TimerHandler
*tmp
, *handler
=(TimerHandler
*)handlerID
;
206 if (!handler
|| !timerHandler
)
211 timerHandler
= handler
->next
;
215 if (tmp
->next
==handler
) {
216 tmp
->next
=handler
->next
;
228 WMAddIdleHandler(WMCallback
*callback
, void *cdata
)
230 IdleHandler
*handler
, *tmp
;
232 handler
= malloc(sizeof(IdleHandler
));
236 handler
->callback
= callback
;
237 handler
->clientData
= cdata
;
238 handler
->next
= NULL
;
239 /* add callback at end of queue */
241 idleHandler
= handler
;
256 WMDeleteIdleHandler(WMHandlerID handlerID
)
258 IdleHandler
*tmp
, *handler
= (IdleHandler
*)handlerID
;
260 if (!handler
|| !idleHandler
)
264 if (tmp
== handler
) {
265 idleHandler
= handler
->next
;
269 if (tmp
->next
== handler
) {
270 tmp
->next
= handler
->next
;
282 WMAddInputHandler(int fd
, int condition
, WMInputProc
*proc
, void *clientData
)
284 InputHandler
*handler
;
286 handler
= wmalloc(sizeof(InputHandler
));
289 handler
->mask
= condition
;
290 handler
->callback
= proc
;
291 handler
->clientData
= clientData
;
293 handler
->next
= inputHandler
;
295 inputHandler
= handler
;
302 WMDeleteInputHandler(WMHandlerID handlerID
)
304 InputHandler
*tmp
, *handler
= (InputHandler
*)handlerID
;
306 if (!handler
|| !inputHandler
)
310 if (tmp
== handler
) {
311 inputHandler
= handler
->next
;
315 if (tmp
->next
== handler
) {
316 tmp
->next
= handler
->next
;
329 IdleHandler
*handler
, *tmp
;
334 handler
= idleHandler
;
336 /* we will process all idleHandlers so, empty the handler list */
341 (*handler
->callback
)(handler
->clientData
);
342 /* remove the handler */
354 TimerHandler
*handler
;
359 while (timerHandler
&& IS_AFTER(now
, timerHandler
->when
)) {
360 handler
= timerHandler
;
361 timerHandler
= timerHandler
->next
;
362 handler
->next
= NULL
;
363 (*handler
->callback
)(handler
->clientData
);
371 delayUntilNextTimerEvent(struct timeval
*delay
)
376 /* The return value of this function is only valid if there _are_
384 if (IS_AFTER(now
, timerHandler
->when
)) {
388 delay
->tv_sec
= timerHandler
->when
.tv_sec
- now
.tv_sec
;
389 delay
->tv_usec
= timerHandler
->when
.tv_usec
- now
.tv_usec
;
397 * WMCreateEventHandler--
398 * Create an event handler and put it in the event handler list for the
399 * view. If the same callback and clientdata are already used in another
400 * handler, the masks are swapped.
404 WMCreateEventHandler(WMView
*view
, unsigned long mask
, WMEventProc
*eventProc
,
407 W_EventHandler
*handler
;
408 W_EventHandler
*ptr
= view
->handlerList
;
409 unsigned long eventMask
;
412 handler
= wmalloc(sizeof(W_EventHandler
));
414 handler
->nextHandler
= NULL
;
416 view
->handlerList
= handler
;
422 while (ptr
!= NULL
) {
423 if (ptr
->clientData
== clientData
&& ptr
->proc
== eventProc
) {
426 eventMask
|= ptr
->eventMask
;
428 ptr
= ptr
->nextHandler
;
431 handler
= wmalloc(sizeof(W_EventHandler
));
432 handler
->nextHandler
= view
->handlerList
;
433 view
->handlerList
= handler
;
437 /* select events for window */
438 handler
->eventMask
= mask
;
439 handler
->proc
= eventProc
;
440 handler
->clientData
= clientData
;
445 * WMDeleteEventHandler--
446 * Delete event handler matching arguments from windows
447 * event handler list.
451 WMDeleteEventHandler(WMView
*view
, unsigned long mask
, WMEventProc
*eventProc
,
454 W_EventHandler
*handler
, *ptr
, *pptr
;
456 ptr
= view
->handlerList
;
462 if (ptr
->eventMask
== mask
&& ptr
->proc
== eventProc
463 && ptr
->clientData
== clientData
) {
468 ptr
= ptr
->nextHandler
;
475 view
->handlerList
= handler
->nextHandler
;
477 pptr
->nextHandler
= handler
->nextHandler
;
485 W_CleanUpEvents(WMView
*view
)
487 W_EventHandler
*ptr
, *nptr
;
489 ptr
= view
->handlerList
;
492 nptr
= ptr
->nextHandler
;
501 getEventTime(WMScreen
*screen
, XEvent
*event
)
503 switch (event
->type
) {
506 return event
->xbutton
.time
;
509 return event
->xkey
.time
;
511 return event
->xmotion
.time
;
514 return event
->xcrossing
.time
;
516 return event
->xproperty
.time
;
518 return event
->xselectionclear
.time
;
519 case SelectionRequest
:
520 return event
->xselectionrequest
.time
;
521 case SelectionNotify
:
522 return event
->xselection
.time
;
524 return screen
->lastEventTime
;
530 W_CallDestroyHandlers(W_View
*view
)
533 W_EventHandler
*hPtr
;
535 event
.type
= DestroyNotify
;
536 event
.xdestroywindow
.window
= view
->window
;
537 event
.xdestroywindow
.event
= view
->window
;
538 hPtr
= view
->handlerList
;
540 if (hPtr
->eventMask
& StructureNotifyMask
) {
541 (*hPtr
->proc
)(&event
, hPtr
->clientData
);
544 hPtr
= hPtr
->nextHandler
;
550 WMHandleEvent(XEvent
*event
)
552 W_EventHandler
*hPtr
;
553 W_View
*view
, *vPtr
, *toplevel
;
557 if (event
->type
== MappingNotify
) {
558 XRefreshKeyboardMapping(&event
->xmapping
);
562 mask
= eventMasks
[event
->xany
.type
];
564 window
= event
->xany
.window
;
566 /* diferentiate SubstructureNotify with StructureNotify */
567 if (mask
== StructureNotifyMask
) {
568 if (event
->xmap
.event
!= event
->xmap
.window
) {
569 mask
= SubstructureNotifyMask
;
570 window
= event
->xmap
.event
;
573 view
= W_GetViewForXWindow(event
->xany
.display
, window
);
575 if (extraEventHandler
)
576 (extraEventHandler
)(event
);
581 view
->screen
->lastEventTime
= getEventTime(view
->screen
, event
);
583 toplevel
= W_TopLevelOfView(view
);
585 /* if it's a key event, redispatch it to the focused control */
586 if (mask
& (KeyPressMask
|KeyReleaseMask
)) {
587 W_View
*focused
= W_FocusedViewOfToplevel(toplevel
);
594 /* compress Motion events */
595 if (event
->type
== MotionNotify
&& !view
->flags
.dontCompressMotion
) {
596 while (XPending(event
->xmotion
.display
)) {
598 XPeekEvent(event
->xmotion
.display
, &ev
);
599 if (ev
.type
== MotionNotify
600 && event
->xmotion
.window
== ev
.xmotion
.window
601 && event
->xmotion
.subwindow
== ev
.xmotion
.subwindow
) {
603 XNextEvent(event
->xmotion
.display
, event
);
608 /* compress expose events */
609 if (event
->type
== Expose
&& !view
->flags
.dontCompressExpose
) {
610 while (XCheckTypedWindowEvent(event
->xexpose
.display
, view
->window
,
615 if (view
->screen
->modal
&& toplevel
!=view
->screen
->modalView
616 && !toplevel
->flags
.worksWhenModal
) {
617 if (event
->type
== KeyPress
|| event
->type
== KeyRelease
618 || event
->type
== MotionNotify
|| event
->type
== ButtonPress
619 || event
->type
== ButtonRelease
620 || event
->type
== FocusIn
|| event
->type
== FocusOut
) {
625 /* This is a hack. It will make the panel be secure while
626 * the event handlers are handled, as some event handler
627 * might destroy the widget. */
628 W_RetainView(toplevel
);
630 hPtr
= view
->handlerList
;
635 tmp
= hPtr
->nextHandler
;
637 if ((hPtr
->eventMask
& mask
)) {
638 (*hPtr
->proc
)(event
, hPtr
->clientData
);
644 /* pass the event to the top level window of the widget */
645 if (view
->parent
!=NULL
) {
647 while (vPtr
->parent
!=NULL
)
650 hPtr
= vPtr
->handlerList
;
654 if (hPtr
->eventMask
& mask
) {
655 (*hPtr
->proc
)(event
, hPtr
->clientData
);
657 hPtr
= hPtr
->nextHandler
;
661 /* save button click info to track double-clicks */
662 if (view
->screen
->ignoreNextDoubleClick
) {
663 view
->screen
->ignoreNextDoubleClick
= 0;
665 if (event
->type
== ButtonPress
) {
666 view
->screen
->lastClickWindow
= event
->xbutton
.window
;
667 view
->screen
->lastClickTime
= event
->xbutton
.time
;
671 W_ReleaseView(toplevel
);
678 WMIsDoubleClick(XEvent
*event
)
682 if (event
->type
!= ButtonPress
)
685 view
= W_GetViewForXWindow(event
->xany
.display
, event
->xbutton
.window
);
690 if (view
->screen
->lastClickWindow
!= event
->xbutton
.window
)
693 if (event
->xbutton
.time
- view
->screen
->lastClickTime
694 < WINGsConfiguration
.doubleClickDelay
) {
695 view
->screen
->lastClickTime
= 0;
696 view
->screen
->lastClickWindow
= None
;
697 view
->screen
->ignoreNextDoubleClick
= 1;
705 W_WaitForEvent(Display
*dpy
, unsigned long xeventmask
)
708 #error This_system_does_not_have_select(2)_and_is_not_supported
710 struct timeval timeout
;
711 struct timeval
*timeoutPtr
;
712 fd_set rset
, wset
, eset
;
715 InputHandler
*handler
= inputHandler
;
721 FD_SET(ConnectionNumber(dpy
), &rset
);
722 maxfd
= ConnectionNumber(dpy
);
725 if (handler
->mask
& WIReadMask
)
726 FD_SET(handler
->fd
, &rset
);
728 if (handler
->mask
& WIWriteMask
)
729 FD_SET(handler
->fd
, &wset
);
731 if (handler
->mask
& WIExceptMask
)
732 FD_SET(handler
->fd
, &eset
);
734 if (maxfd
< handler
->fd
)
737 handler
= handler
->next
;
742 * Setup the select() timeout to the estimated time until the
743 * next timer expires.
745 if (timerPending()) {
746 delayUntilNextTimerEvent(&timeout
);
747 timeoutPtr
= &timeout
;
749 timeoutPtr
= (struct timeval
*)0;
758 if (XCheckMaskEvent(dpy
, xeventmask
, &ev
)) {
759 XPutBackEvent(dpy
, &ev
);
763 /* TODO: port to poll() */
764 count
= select(1 + maxfd
, &rset
, &wset
, &eset
, timeoutPtr
);
767 handler
= inputHandler
;
774 if (FD_ISSET(handler
->fd
, &rset
))
777 if (FD_ISSET(handler
->fd
, &wset
))
780 if (FD_ISSET(handler
->fd
, &eset
))
781 mask
|= WIExceptMask
;
783 if (mask
!=0 && handler
->callback
) {
784 (*handler
->callback
)(handler
->fd
, mask
,
785 handler
->clientData
);
788 handler
= handler
->next
;
792 return FD_ISSET(ConnectionNumber(dpy
), &rset
);
798 WMNextEvent(Display
*dpy
, XEvent
*event
)
800 /* Check any expired timers */
801 if (timerPending()) {
802 checkTimerHandlers();
805 while (XPending(dpy
) == 0) {
807 /* Do idle and timer stuff while there are no timer or X events */
808 while (!XPending(dpy
) && idlePending()) {
811 /* dispatch timer events */
813 checkTimerHandlers();
817 * Make sure that new events did not arrive while we were doing
818 * timer/idle stuff. Or we might block forever waiting for
819 * an event that already arrived.
821 /* wait to something happen */
822 W_WaitForEvent(dpy
, 0);
824 /* Check any expired timers */
825 if (timerPending()) {
826 checkTimerHandlers();
830 XNextEvent(dpy
, event
);
835 WMMaskEvent(Display
*dpy
, long mask
, XEvent
*event
)
837 unsigned long milliseconds
;
838 struct timeval timeout
;
839 struct timeval
*timeoutOrInfty
;
842 while (!XCheckMaskEvent(dpy
, mask
, event
)) {
843 /* Do idle stuff while there are no timer or X events */
844 while (idlePending()) {
846 if (XCheckMaskEvent(dpy
, mask
, event
))
851 * Setup the select() timeout to the estimated time until the
852 * next timer expires.
854 if (timerPending()) {
855 delayUntilNextTimerEvent(&timeout
);
856 timeoutOrInfty
= &timeout
;
858 timeoutOrInfty
= (struct timeval
*)0;
861 if (XCheckMaskEvent(dpy
, mask
, event
))
864 /* Wait for input on the X connection socket */
866 FD_SET(ConnectionNumber(dpy
), &readset
);
867 select(1 + ConnectionNumber(dpy
), &readset
, (fd_set
*)0, (fd_set
*)0,
870 /* Check any expired timers */
871 if (timerPending()) {
872 checkTimerHandlers();
879 * Cant use this because XPending() will make W_WaitForEvent
880 * return even if the event in the queue is not what we want,
881 * and if we block until some new event arrives from the
882 * server, other events already in the queue (like Expose)
886 WMMaskEvent(Display
*dpy
, long mask
, XEvent
*event
)
888 while (!XCheckMaskEvent(dpy
, mask
, event
)) {
889 /* Do idle stuff while there are no timer or X events */
890 while (idlePending()) {
892 if (XCheckMaskEvent(dpy
, mask
, event
))
896 /* Wait for input on the X connection socket */
897 W_WaitForEvent(dpy
, mask
);
899 /* Check any expired timers */
900 if (timerPending()) {
901 checkTimerHandlers();
908 WMScreenPending(WMScreen
*scr
)
910 if (XPending(scr
->display
))
918 WMHookEventHandler(WMEventHook
*handler
)
920 WMEventHook
*oldHandler
= extraEventHandler
;
922 extraEventHandler
= handler
;