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 unsigned long msec
; /* 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)
118 /* return current time in milliseconds */
119 #ifdef HAVE_GETTIMEOFDAY
124 gettimeofday(&tv
, NULL
);
126 return 1000L*(unsigned long)tv
.tv_sec
+ (unsigned long)tv
.tv_usec
/1000L;
128 #else /* !HAVE_GETTIMEOFDAY */
129 # define rightNow() (1000*(unsigned long)time(NULL))
130 #endif /* !HAVE_GETTIMEOFDAY */
134 WMAddTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
136 TimerHandler
*handler
, *tmp
;
138 handler
= malloc(sizeof(TimerHandler
));
142 handler
->msec
= rightNow()+milliseconds
;
143 handler
->callback
= callback
;
144 handler
->clientData
= cdata
;
145 /* insert callback in queue, sorted by time left */
146 if (!timerHandler
|| timerHandler
->msec
>= handler
->msec
) {
147 /* first in the queue */
148 handler
->next
= timerHandler
;
149 timerHandler
= handler
;
152 while (tmp
->next
&& tmp
->next
->msec
< handler
->msec
) {
155 handler
->next
= tmp
->next
;
164 WMDeleteTimerWithClientData(void *cdata
)
166 TimerHandler
*handler
, *tmp
;
168 if (!cdata
|| !timerHandler
)
172 if (tmp
->clientData
==cdata
) {
173 timerHandler
= tmp
->next
;
177 if (tmp
->next
->clientData
==cdata
) {
179 tmp
->next
= handler
->next
;
191 WMDeleteTimerHandler(WMHandlerID handlerID
)
193 TimerHandler
*tmp
, *handler
=(TimerHandler
*)handlerID
;
195 if (!handler
|| !timerHandler
)
200 timerHandler
= handler
->next
;
204 if (tmp
->next
==handler
) {
205 tmp
->next
=handler
->next
;
217 WMAddIdleHandler(WMCallback
*callback
, void *cdata
)
219 IdleHandler
*handler
, *tmp
;
221 handler
= malloc(sizeof(IdleHandler
));
225 handler
->callback
= callback
;
226 handler
->clientData
= cdata
;
227 handler
->next
= NULL
;
228 /* add callback at end of queue */
230 idleHandler
= handler
;
245 WMDeleteIdleHandler(WMHandlerID handlerID
)
247 IdleHandler
*tmp
, *handler
= (IdleHandler
*)handlerID
;
249 if (!handler
|| !idleHandler
)
253 if (tmp
== handler
) {
254 idleHandler
= handler
->next
;
258 if (tmp
->next
== handler
) {
259 tmp
->next
= handler
->next
;
271 WMAddInputHandler(int fd
, int condition
, WMInputProc
*proc
, void *clientData
)
273 InputHandler
*handler
;
275 handler
= wmalloc(sizeof(InputHandler
));
278 handler
->mask
= condition
;
279 handler
->callback
= proc
;
280 handler
->clientData
= clientData
;
282 handler
->next
= inputHandler
;
284 inputHandler
= handler
;
291 WMDeleteInputHandler(WMHandlerID handlerID
)
293 InputHandler
*tmp
, *handler
= (InputHandler
*)handlerID
;
295 if (!handler
|| !inputHandler
)
299 if (tmp
== handler
) {
300 inputHandler
= handler
->next
;
304 if (tmp
->next
== handler
) {
305 tmp
->next
= handler
->next
;
318 IdleHandler
*handler
, *tmp
;
323 handler
= idleHandler
;
325 /* we will process all idleHandlers so, empty the handler list */
330 (*handler
->callback
)(handler
->clientData
);
331 /* remove the handler */
343 TimerHandler
*handler
;
344 unsigned long now
= rightNow();
346 if (!timerHandler
|| (timerHandler
->msec
> now
))
349 while (timerHandler
&& timerHandler
->msec
<= now
) {
350 handler
= timerHandler
;
351 timerHandler
= timerHandler
->next
;
352 handler
->next
= NULL
;
353 (*handler
->callback
)(handler
->clientData
);
366 /* The return value of this function is only valid if there _are_
372 if (timerHandler
->msec
< now
) {
375 return timerHandler
->msec
- now
;
383 * WMCreateEventHandler--
384 * Create an event handler and put it in the event handler list for the
385 * view. If the same callback and clientdata are already used in another
386 * handler, the masks are swapped.
390 WMCreateEventHandler(WMView
*view
, unsigned long mask
, WMEventProc
*eventProc
,
393 W_EventHandler
*handler
;
394 W_EventHandler
*ptr
= view
->handlerList
;
395 unsigned long eventMask
;
398 handler
= wmalloc(sizeof(W_EventHandler
));
400 handler
->nextHandler
= NULL
;
402 view
->handlerList
= handler
;
408 while (ptr
!= NULL
) {
409 if (ptr
->clientData
== clientData
&& ptr
->proc
== eventProc
) {
412 eventMask
|= ptr
->eventMask
;
414 ptr
= ptr
->nextHandler
;
417 handler
= wmalloc(sizeof(W_EventHandler
));
418 handler
->nextHandler
= view
->handlerList
;
419 view
->handlerList
= handler
;
423 /* select events for window */
424 handler
->eventMask
= mask
;
425 handler
->proc
= eventProc
;
426 handler
->clientData
= clientData
;
431 * WMDeleteEventHandler--
432 * Delete event handler matching arguments from windows
433 * event handler list.
437 WMDeleteEventHandler(WMView
*view
, unsigned long mask
, WMEventProc
*eventProc
,
440 W_EventHandler
*handler
, *ptr
, *pptr
;
442 ptr
= view
->handlerList
;
448 if (ptr
->eventMask
== mask
&& ptr
->proc
== eventProc
449 && ptr
->clientData
== clientData
) {
454 ptr
= ptr
->nextHandler
;
461 view
->handlerList
= handler
->nextHandler
;
463 pptr
->nextHandler
= handler
->nextHandler
;
471 W_CleanUpEvents(WMView
*view
)
473 W_EventHandler
*ptr
, *nptr
;
475 ptr
= view
->handlerList
;
478 nptr
= ptr
->nextHandler
;
487 getEventTime(WMScreen
*screen
, XEvent
*event
)
489 switch (event
->type
) {
492 return event
->xbutton
.time
;
495 return event
->xkey
.time
;
497 return event
->xmotion
.time
;
500 return event
->xcrossing
.time
;
502 return event
->xproperty
.time
;
504 return event
->xselectionclear
.time
;
505 case SelectionRequest
:
506 return event
->xselectionrequest
.time
;
507 case SelectionNotify
:
508 return event
->xselection
.time
;
510 return screen
->lastEventTime
;
516 W_CallDestroyHandlers(W_View
*view
)
519 W_EventHandler
*hPtr
;
521 event
.type
= DestroyNotify
;
522 event
.xdestroywindow
.window
= view
->window
;
523 event
.xdestroywindow
.event
= view
->window
;
524 hPtr
= view
->handlerList
;
526 if (hPtr
->eventMask
& StructureNotifyMask
) {
527 (*hPtr
->proc
)(&event
, hPtr
->clientData
);
530 hPtr
= hPtr
->nextHandler
;
536 WMHandleEvent(XEvent
*event
)
538 W_EventHandler
*hPtr
;
539 W_View
*view
, *vPtr
, *toplevel
;
543 if (event
->type
== MappingNotify
) {
544 XRefreshKeyboardMapping(&event
->xmapping
);
548 mask
= eventMasks
[event
->xany
.type
];
550 window
= event
->xany
.window
;
552 /* diferentiate SubstructureNotify with StructureNotify */
553 if (mask
== StructureNotifyMask
) {
554 if (event
->xmap
.event
!= event
->xmap
.window
) {
555 mask
= SubstructureNotifyMask
;
556 window
= event
->xmap
.event
;
559 view
= W_GetViewForXWindow(event
->xany
.display
, window
);
561 if (extraEventHandler
)
562 (extraEventHandler
)(event
);
567 view
->screen
->lastEventTime
= getEventTime(view
->screen
, event
);
569 toplevel
= W_TopLevelOfView(view
);
571 /* if it's a key event, redispatch it to the focused control */
572 if (mask
& (KeyPressMask
|KeyReleaseMask
)) {
573 W_View
*focused
= W_FocusedViewOfToplevel(toplevel
);
580 /* compress Motion events */
581 if (event
->type
== MotionNotify
&& !view
->flags
.dontCompressMotion
) {
582 while (XPending(event
->xmotion
.display
)) {
584 XPeekEvent(event
->xmotion
.display
, &ev
);
585 if (ev
.type
== MotionNotify
586 && event
->xmotion
.window
== ev
.xmotion
.window
587 && event
->xmotion
.subwindow
== ev
.xmotion
.subwindow
) {
589 XNextEvent(event
->xmotion
.display
, event
);
594 /* compress expose events */
595 if (event
->type
== Expose
&& !view
->flags
.dontCompressExpose
) {
596 while (XCheckTypedWindowEvent(event
->xexpose
.display
, view
->window
,
601 if (view
->screen
->modal
&& toplevel
!=view
->screen
->modalView
602 && !toplevel
->flags
.worksWhenModal
) {
603 if (event
->type
== KeyPress
|| event
->type
== KeyRelease
604 || event
->type
== MotionNotify
|| event
->type
== ButtonPress
605 || event
->type
== ButtonRelease
606 || event
->type
== FocusIn
|| event
->type
== FocusOut
) {
611 /* This is a hack. It will make the panel be secure while
612 * the event handlers are handled, as some event handler
613 * might destroy the widget. */
614 W_RetainView(toplevel
);
616 hPtr
= view
->handlerList
;
621 tmp
= hPtr
->nextHandler
;
623 if ((hPtr
->eventMask
& mask
)) {
624 (*hPtr
->proc
)(event
, hPtr
->clientData
);
630 /* pass the event to the top level window of the widget */
631 if (view
->parent
!=NULL
) {
633 while (vPtr
->parent
!=NULL
)
636 hPtr
= vPtr
->handlerList
;
640 if (hPtr
->eventMask
& mask
) {
641 (*hPtr
->proc
)(event
, hPtr
->clientData
);
643 hPtr
= hPtr
->nextHandler
;
647 /* save button click info to track double-clicks */
648 if (view
->screen
->ignoreNextDoubleClick
) {
649 view
->screen
->ignoreNextDoubleClick
= 0;
651 if (event
->type
== ButtonPress
) {
652 view
->screen
->lastClickWindow
= event
->xbutton
.window
;
653 view
->screen
->lastClickTime
= event
->xbutton
.time
;
657 W_ReleaseView(toplevel
);
664 WMIsDoubleClick(XEvent
*event
)
668 if (event
->type
!= ButtonPress
)
671 view
= W_GetViewForXWindow(event
->xany
.display
, event
->xbutton
.window
);
676 if (view
->screen
->lastClickWindow
!= event
->xbutton
.window
)
679 if (event
->xbutton
.time
- view
->screen
->lastClickTime
680 < WINGsConfiguration
.doubleClickDelay
) {
681 view
->screen
->lastClickTime
= 0;
682 view
->screen
->lastClickWindow
= None
;
683 view
->screen
->ignoreNextDoubleClick
= 1;
691 W_WaitForEvent(Display
*dpy
, unsigned long xeventmask
)
694 #error This_system_does_not_have_select(2)_and_is_not_supported
696 unsigned long milliseconds
;
697 struct timeval timeout
;
698 struct timeval
*timeoutPtr
;
699 fd_set rset
, wset
, eset
;
702 InputHandler
*handler
= inputHandler
;
708 FD_SET(ConnectionNumber(dpy
), &rset
);
709 maxfd
= ConnectionNumber(dpy
);
712 if (handler
->mask
& WIReadMask
)
713 FD_SET(handler
->fd
, &rset
);
715 if (handler
->mask
& WIWriteMask
)
716 FD_SET(handler
->fd
, &wset
);
718 if (handler
->mask
& WIExceptMask
)
719 FD_SET(handler
->fd
, &eset
);
721 if (maxfd
< handler
->fd
)
724 handler
= handler
->next
;
729 * Setup the select() timeout to the estimated time until the
730 * next timer expires.
732 if (timerPending()) {
733 milliseconds
= msToNextTimerEvent();
734 timeout
.tv_sec
= milliseconds
/ 1000;
735 timeout
.tv_usec
= (milliseconds
% 1000) * 1000;
736 timeoutPtr
= &timeout
;
738 timeoutPtr
= (struct timeval
*)0;
747 if (XCheckMaskEvent(dpy
, xeventmask
, &ev
)) {
748 XPutBackEvent(dpy
, &ev
);
752 /* TODO: port to poll() */
753 count
= select(1 + maxfd
, &rset
, &wset
, &eset
, timeoutPtr
);
756 handler
= inputHandler
;
763 if (FD_ISSET(handler
->fd
, &rset
))
766 if (FD_ISSET(handler
->fd
, &wset
))
769 if (FD_ISSET(handler
->fd
, &eset
))
770 mask
|= WIExceptMask
;
772 if (mask
!=0 && handler
->callback
) {
773 (*handler
->callback
)(handler
->fd
, mask
,
774 handler
->clientData
);
777 handler
= handler
->next
;
781 return FD_ISSET(ConnectionNumber(dpy
), &rset
);
787 WMNextEvent(Display
*dpy
, XEvent
*event
)
789 /* Check any expired timers */
790 if (timerPending()) {
791 checkTimerHandlers();
794 while (XPending(dpy
) == 0) {
796 /* Do idle and timer stuff while there are no timer or X events */
797 while (!XPending(dpy
) && idlePending()) {
800 /* dispatch timer events */
802 checkTimerHandlers();
806 * Make sure that new events did not arrive while we were doing
807 * timer/idle stuff. Or we might block forever waiting for
808 * an event that already arrived.
810 /* wait to something happen */
811 W_WaitForEvent(dpy
, 0);
813 /* Check any expired timers */
814 if (timerPending()) {
815 checkTimerHandlers();
819 XNextEvent(dpy
, event
);
824 WMMaskEvent(Display
*dpy
, long mask
, XEvent
*event
)
826 unsigned long milliseconds
;
827 struct timeval timeout
;
828 struct timeval
*timeoutOrInfty
;
831 while (!XCheckMaskEvent(dpy
, mask
, event
)) {
832 /* Do idle stuff while there are no timer or X events */
833 while (idlePending()) {
835 if (XCheckMaskEvent(dpy
, mask
, event
))
840 * Setup the select() timeout to the estimated time until the
841 * next timer expires.
843 if (timerPending()) {
844 milliseconds
= msToNextTimerEvent();
845 timeout
.tv_sec
= milliseconds
/ 1000;
846 timeout
.tv_usec
= (milliseconds
% 1000) * 1000;
847 timeoutOrInfty
= &timeout
;
849 timeoutOrInfty
= (struct timeval
*)0;
852 if (XCheckMaskEvent(dpy
, mask
, event
))
855 /* Wait for input on the X connection socket */
857 FD_SET(ConnectionNumber(dpy
), &readset
);
858 select(1 + ConnectionNumber(dpy
), &readset
, (fd_set
*)0, (fd_set
*)0,
861 /* Check any expired timers */
862 if (timerPending()) {
863 checkTimerHandlers();
870 * Cant use this because XPending() will make W_WaitForEvent
871 * return even if the event in the queue is not what we want,
872 * and if we block until some new event arrives from the
873 * server, other events already in the queue (like Expose)
877 WMMaskEvent(Display
*dpy
, long mask
, XEvent
*event
)
879 while (!XCheckMaskEvent(dpy
, mask
, event
)) {
880 /* Do idle stuff while there are no timer or X events */
881 while (idlePending()) {
883 if (XCheckMaskEvent(dpy
, mask
, event
))
887 /* Wait for input on the X connection socket */
888 W_WaitForEvent(dpy
, mask
);
890 /* Check any expired timers */
891 if (timerPending()) {
892 checkTimerHandlers();
899 WMScreenPending(WMScreen
*scr
)
901 if (XPending(scr
->display
))
909 WMHookEventHandler(WMEventHook
*handler
)
911 WMEventHook
*oldHandler
= extraEventHandler
;
913 extraEventHandler
= handler
;