Released version 3-2014010505
[notion.git] / ioncore / event.c
blob3723af02175e7952a160ef5fcbb274e8204f2412
1 /*
2 * ion/ioncore/event.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <X11/Xmd.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <sys/time.h>
13 #include <sys/signal.h>
15 #include <libmainloop/select.h>
16 #include <libmainloop/signal.h>
17 #include <libmainloop/defer.h>
19 #include "common.h"
20 #include "global.h"
21 #include "event.h"
22 #include "eventh.h"
23 #include "focus.h"
24 #include "exec.h"
25 #include "ioncore.h"
29 /*{{{ Hooks */
32 WHook *ioncore_handle_event_alt=NULL;
35 /*}}}*/
38 /*{{{ Signal check */
41 static void check_signals()
43 int kill_sig=mainloop_check_signals();
45 if(kill_sig!=0){
46 if(kill_sig==SIGUSR1){
47 ioncore_restart();
48 assert(0);
50 if(kill_sig==SIGTERM){
51 /* Save state if not running under a session manager. */
52 ioncore_emergency_snapshot();
53 ioncore_resign();
54 /* We may still return here if running under a session manager. */
55 }else{
56 ioncore_emergency_snapshot();
57 ioncore_deinit();
58 kill(getpid(), kill_sig);
64 /*}}}*/
67 /*{{{ Timestamp stuff */
69 #define CHKEV(E, T) case E: tm=((T*)ev)->time; break;
71 static Time last_timestamp=CurrentTime;
73 void ioncore_update_timestamp(XEvent *ev)
75 Time tm;
77 switch(ev->type){
78 CHKEV(ButtonPress, XButtonPressedEvent);
79 CHKEV(ButtonRelease, XButtonReleasedEvent);
80 CHKEV(EnterNotify, XEnterWindowEvent);
81 CHKEV(KeyPress, XKeyPressedEvent);
82 CHKEV(KeyRelease, XKeyReleasedEvent);
83 CHKEV(LeaveNotify, XLeaveWindowEvent);
84 CHKEV(MotionNotify, XPointerMovedEvent);
85 CHKEV(PropertyNotify, XPropertyEvent);
86 CHKEV(SelectionClear, XSelectionClearEvent);
87 CHKEV(SelectionNotify, XSelectionEvent);
88 CHKEV(SelectionRequest, XSelectionRequestEvent);
89 default:
90 return;
93 if(tm>last_timestamp || last_timestamp - tm > IONCORE_CLOCK_SKEW_MS)
94 last_timestamp=tm;
98 Time ioncore_get_timestamp()
100 if(last_timestamp==CurrentTime){
101 /* Idea blatantly copied from wmx */
102 XEvent ev;
103 Atom dummy;
105 D(fprintf(stderr, "Attempting to get time from X server."));
107 dummy=XInternAtom(ioncore_g.dpy, "_ION_TIMEREQUEST", False);
108 if(dummy==None){
109 warn(TR("Time request from X server failed."));
110 return 0;
112 /* TODO: use some other window that should also function as a
113 * NET_WM support check window.
115 XChangeProperty(ioncore_g.dpy, ioncore_g.rootwins->dummy_win,
116 dummy, dummy, 8, PropModeAppend,
117 (unsigned char*)"", 0);
118 ioncore_get_event(&ev, PropertyChangeMask);
119 XPutBackEvent(ioncore_g.dpy, &ev);
122 return last_timestamp;
126 /*}}}*/
129 /*{{{ Event reading */
132 void ioncore_get_event(XEvent *ev, long mask)
134 fd_set rfds;
136 while(1){
137 check_signals();
139 if(XCheckMaskEvent(ioncore_g.dpy, mask, ev)){
140 ioncore_update_timestamp(ev);
141 return;
144 FD_ZERO(&rfds);
145 FD_SET(ioncore_g.conn, &rfds);
147 /* Other FD:s are _not_ to be handled! */
148 select(ioncore_g.conn+1, &rfds, NULL, NULL, NULL);
153 /*}}}*/
156 /*{{{ Flush */
159 static void skip_enterwindow()
161 XEvent ev;
163 XSync(ioncore_g.dpy, False);
165 while(XCheckMaskEvent(ioncore_g.dpy, EnterWindowMask, &ev)){
166 ioncore_update_timestamp(&ev);
171 void ioncore_flushfocus()
173 WRegion *next;
174 bool warp;
176 if(ioncore_g.input_mode!=IONCORE_INPUTMODE_NORMAL)
177 return;
179 next=ioncore_g.focus_next;
180 warp=ioncore_g.warp_next;
182 if(next==NULL)
183 return;
185 ioncore_g.focus_next=NULL;
187 region_do_set_focus(next, warp);
189 /* Just greedily eating it all away that X has to offer
190 * seems to be the best we can do with Xlib.
192 if(warp)
193 skip_enterwindow();
197 /*}}}*/
200 /*{{{ X connection FD handler */
203 void ioncore_x_connection_handler(int conn, void *unused)
205 XEvent ev;
207 XNextEvent(ioncore_g.dpy, &ev);
208 ioncore_update_timestamp(&ev);
210 hook_call_alt_p(ioncore_handle_event_alt, &ev, NULL);
214 /*}}}*/
217 /*{{{ Mainloop */
220 void ioncore_mainloop()
222 mainloop_trap_signals(NULL);
224 ioncore_g.opmode=IONCORE_OPMODE_NORMAL;
226 while(1){
227 check_signals();
228 mainloop_execute_deferred();
230 if(QLength(ioncore_g.dpy)==0){
231 XSync(ioncore_g.dpy, False);
233 if(QLength(ioncore_g.dpy)==0){
234 ioncore_flushfocus();
235 XSync(ioncore_g.dpy, False);
237 if(QLength(ioncore_g.dpy)==0){
238 mainloop_select();
239 continue;
244 ioncore_x_connection_handler(ioncore_g.conn, NULL);
249 /*}}}*/