]> git.decadent.org.uk Git - ion3.git/blob - ioncore/event.c
Merge commit '20070318' into HEAD
[ion3.git] / ioncore / event.c
1 /*
2  * ion/ioncore/event.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <X11/Xmd.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <sys/time.h>
16 #include <sys/signal.h>
17
18 #include <libmainloop/select.h>
19 #include <libmainloop/signal.h>
20 #include <libmainloop/defer.h>
21
22 #include "common.h"
23 #include "global.h"
24 #include "event.h"
25 #include "eventh.h"
26 #include "focus.h"
27 #include "exec.h"
28 #include "ioncore.h"
29
30
31
32 /*{{{ Hooks */
33
34
35 WHook *ioncore_handle_event_alt=NULL;
36
37
38 /*}}}*/
39
40
41 /*{{{ Signal check */
42     
43
44 static void check_signals()
45 {
46     int kill_sig=mainloop_check_signals();
47     
48     if(kill_sig!=0){
49         if(kill_sig==SIGUSR1){
50             ioncore_restart();
51             assert(0);
52         } 
53         if(kill_sig==SIGTERM){
54             /* Save state if not running under a session manager. */
55             ioncore_emergency_snapshot();
56             ioncore_resign();
57             /* We may still return here if running under a session manager. */
58         }else{
59             ioncore_emergency_snapshot();
60             ioncore_deinit();
61             kill(getpid(), kill_sig);
62         }
63     }
64 }
65
66
67 /*}}}*/
68
69
70 /*{{{ Timestamp stuff */
71
72 #define CHKEV(E, T) case E: tm=((T*)ev)->time; break;
73 #define CLOCK_SKEW_MS 30000
74
75 static Time last_timestamp=CurrentTime;
76
77 void ioncore_update_timestamp(XEvent *ev)
78 {
79     Time tm;
80     
81     switch(ev->type){
82     CHKEV(ButtonPress, XButtonPressedEvent);
83     CHKEV(ButtonRelease, XButtonReleasedEvent);
84     CHKEV(EnterNotify, XEnterWindowEvent);
85     CHKEV(KeyPress, XKeyPressedEvent);
86     CHKEV(KeyRelease, XKeyReleasedEvent);
87     CHKEV(LeaveNotify, XLeaveWindowEvent);
88     CHKEV(MotionNotify, XPointerMovedEvent);
89     CHKEV(PropertyNotify, XPropertyEvent);
90     CHKEV(SelectionClear, XSelectionClearEvent);
91     CHKEV(SelectionNotify, XSelectionEvent);
92     CHKEV(SelectionRequest, XSelectionRequestEvent);
93     default:
94         return;
95     }
96
97     if(tm>last_timestamp || last_timestamp - tm > CLOCK_SKEW_MS)
98         last_timestamp=tm;
99 }
100
101
102 Time ioncore_get_timestamp()
103 {
104     if(last_timestamp==CurrentTime){
105         /* Idea blatantly copied from wmx */
106         XEvent ev;
107         Atom dummy;
108         
109         D(fprintf(stderr, "Attempting to get time from X server."));
110         
111         dummy=XInternAtom(ioncore_g.dpy, "_ION_TIMEREQUEST", False);
112         if(dummy==None){
113             warn(TR("Time request from X server failed."));
114             return 0;
115         }
116         /* TODO: use some other window that should also function as a
117          * NET_WM support check window.
118          */
119         XChangeProperty(ioncore_g.dpy, ioncore_g.rootwins->dummy_win,
120                         dummy, dummy, 8, PropModeAppend,
121                         (unsigned char*)"", 0);
122         ioncore_get_event(&ev, PropertyChangeMask);
123         XPutBackEvent(ioncore_g.dpy, &ev);
124     }
125     
126     return last_timestamp;
127 }
128
129
130 /*}}}*/
131
132
133 /*{{{ Event reading */
134
135
136 void ioncore_get_event(XEvent *ev, long mask)
137 {
138     fd_set rfds;
139     
140     while(1){
141         check_signals();
142         
143         if(XCheckMaskEvent(ioncore_g.dpy, mask, ev)){
144             ioncore_update_timestamp(ev);
145             return;
146         }
147         
148         FD_ZERO(&rfds);
149         FD_SET(ioncore_g.conn, &rfds);
150
151         /* Other FD:s are _not_ to be handled! */
152         select(ioncore_g.conn+1, &rfds, NULL, NULL, NULL);
153     }
154 }
155
156
157 /*}}}*/
158
159
160 /*{{{ Flush */
161
162
163 static void skip_enterwindow()
164 {
165     XEvent ev;
166     
167     XSync(ioncore_g.dpy, False);
168     
169     while(XCheckMaskEvent(ioncore_g.dpy, EnterWindowMask, &ev)){
170         ioncore_update_timestamp(&ev);
171     }
172 }
173
174
175 void ioncore_flushfocus()
176 {
177     WRegion *next;
178     bool warp;
179     
180     if(ioncore_g.input_mode!=IONCORE_INPUTMODE_NORMAL)
181         return;
182         
183     next=ioncore_g.focus_next;
184     warp=ioncore_g.warp_next;
185
186     if(next==NULL)
187         return;
188         
189     ioncore_g.focus_next=NULL;
190         
191     region_do_set_focus(next, warp);
192         
193     /* Just greedily eating it all away that X has to offer
194      * seems to be the best we can do with Xlib.
195      */
196     if(warp)
197         skip_enterwindow();
198 }
199
200
201 /*}}}*/
202
203
204 /*{{{ X connection FD handler */
205
206
207 void ioncore_x_connection_handler(int conn, void *unused)
208 {
209     XEvent ev;
210
211     XNextEvent(ioncore_g.dpy, &ev);
212     ioncore_update_timestamp(&ev);
213
214     hook_call_alt_p(ioncore_handle_event_alt, &ev, NULL);
215 }
216
217
218 /*}}}*/
219
220
221 /*{{{ Mainloop */
222
223
224 void ioncore_mainloop()
225 {
226     mainloop_trap_signals(NULL);
227     
228     ioncore_g.opmode=IONCORE_OPMODE_NORMAL;
229
230     while(1){
231         check_signals();
232         mainloop_execute_deferred();
233         
234         if(QLength(ioncore_g.dpy)==0){
235             XSync(ioncore_g.dpy, False);
236             
237             if(QLength(ioncore_g.dpy)==0){
238                 ioncore_flushfocus();
239                 XSync(ioncore_g.dpy, False);
240                 
241                 if(QLength(ioncore_g.dpy)==0){
242                     mainloop_select();
243                     continue;
244                 }
245             }
246         }
247         
248         ioncore_x_connection_handler(ioncore_g.conn, NULL);
249     }
250 }
251
252
253 /*}}}*/
254