update copyright step 1
[dana/openbox.git] / openbox / mainloop.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    mainloop.c for the Openbox window manager
4    Copyright (c) 2006        Mikael Magnusson
5    Copyright (c) 2003        Ben Jansens
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "mainloop.h"
21 #include "action.h"
22 #include "client.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/select.h>
27 #include <signal.h>
28
29 typedef struct _ObMainLoopTimer             ObMainLoopTimer;
30 typedef struct _ObMainLoopSignal            ObMainLoopSignal;
31 typedef struct _ObMainLoopSignalHandlerType ObMainLoopSignalHandlerType;
32 typedef struct _ObMainLoopXHandlerType      ObMainLoopXHandlerType;
33 typedef struct _ObMainLoopFdHandlerType     ObMainLoopFdHandlerType;
34
35 /* this should be more than the number of possible signals on any
36    architecture... */
37 #define NUM_SIGNALS 99
38
39 /* all created ObMainLoops. Used by the signal handler to pass along signals */
40 static GSList *all_loops;
41
42 /* signals are global to all loops */
43 struct {
44     guint installed; /* a ref count */
45     struct sigaction oldact;
46 } all_signals[NUM_SIGNALS];
47
48 /* a set of all possible signals */
49 sigset_t all_signals_set;
50
51 /* signals which cause a core dump, these can't be used for callbacks */
52 static gint core_signals[] =
53 {
54     SIGABRT,
55     SIGSEGV,
56     SIGFPE,
57     SIGILL,
58     SIGQUIT,
59     SIGTRAP,
60     SIGSYS,
61     SIGBUS,
62     SIGXCPU,
63     SIGXFSZ
64 };
65 #define NUM_CORE_SIGNALS (sizeof(core_signals) / sizeof(core_signals[0]))
66
67 static void sighandler(gint sig);
68 static void timer_dispatch(ObMainLoop *loop, GTimeVal **wait);
69 static void fd_handler_destroy(gpointer data);
70
71 struct _ObMainLoop
72 {
73     Display *display;
74
75     gboolean run;     /* do keep running */
76     gboolean running; /* is still running */
77
78     GSList *x_handlers;
79
80     gint fd_x; /* The X fd is a special case! */
81     gint fd_max;
82     GHashTable *fd_handlers;
83     fd_set fd_set;
84
85     GSList *timers;
86     GTimeVal now;
87     GTimeVal ret_wait;
88
89     gboolean signal_fired;
90     guint signals_fired[NUM_SIGNALS];
91     GSList *signal_handlers[NUM_SIGNALS];
92
93     GSList *action_queue;
94 };
95
96 struct _ObMainLoopTimer
97 {
98     gulong delay;
99     GSourceFunc func;
100     gpointer data;
101     GDestroyNotify destroy;
102
103     /* The timer needs to be freed */
104     gboolean del_me;
105     /* The time the last fire should've been at */
106     GTimeVal last;
107     /* When this timer will next trigger */
108     GTimeVal timeout;
109 };
110
111 struct _ObMainLoopSignalHandlerType
112 {
113     ObMainLoop *loop;
114     gint signal;
115     gpointer data;
116     ObMainLoopSignalHandler func;
117     GDestroyNotify destroy;
118 };
119
120 struct _ObMainLoopXHandlerType
121 {
122     ObMainLoop *loop;
123     gpointer data;
124     ObMainLoopXHandler func;
125     GDestroyNotify destroy;
126 };
127
128 struct _ObMainLoopFdHandlerType
129 {
130     ObMainLoop *loop;
131     gint fd;
132     gpointer data;
133     ObMainLoopFdHandler func;
134     GDestroyNotify destroy;
135 };
136
137 ObMainLoop *ob_main_loop_new(Display *display)
138 {
139     ObMainLoop *loop;
140
141     loop = g_new0(ObMainLoop, 1);
142     loop->display = display;
143     loop->fd_x = ConnectionNumber(display);
144     FD_ZERO(&loop->fd_set);
145     FD_SET(loop->fd_x, &loop->fd_set);
146     loop->fd_max = loop->fd_x;
147
148     loop->fd_handlers = g_hash_table_new_full(g_int_hash, g_int_equal,
149                                               NULL, fd_handler_destroy);
150
151     g_get_current_time(&loop->now);
152
153     /* only do this if we're the first loop created */
154     if (!all_loops) {
155         guint i;
156         struct sigaction action;
157         sigset_t sigset;
158
159         /* initialize the all_signals_set */
160         sigfillset(&all_signals_set);
161
162         sigemptyset(&sigset);
163         action.sa_handler = sighandler;
164         action.sa_mask = sigset;
165         action.sa_flags = SA_NOCLDSTOP;
166
167         /* grab all the signals that cause core dumps */
168         for (i = 0; i < NUM_CORE_SIGNALS; ++i) {
169             /* SIGABRT is curiously not grabbed here!! that's because when we
170                get one of the core_signals, we use abort() to dump the core.
171                And having the abort() only go back to our signal handler again
172                is less than optimal */
173             if (core_signals[i] != SIGABRT) {
174                 sigaction(core_signals[i], &action,
175                           &all_signals[core_signals[i]].oldact);
176                 all_signals[core_signals[i]].installed++;
177             }
178         }
179     }
180
181     all_loops = g_slist_prepend(all_loops, loop);
182
183     loop->action_queue = NULL;
184
185     return loop;
186 }
187
188 void ob_main_loop_destroy(ObMainLoop *loop)
189 {
190     guint i;
191     GSList *it, *next;
192
193     if (loop) {
194         g_assert(loop->running == FALSE);
195
196         for (it = loop->x_handlers; it; it = next) {
197             ObMainLoopXHandlerType *h = it->data;
198             next = g_slist_next(it);
199             ob_main_loop_x_remove(loop, h->func);
200         }
201
202         g_hash_table_destroy(loop->fd_handlers);
203
204         for (it = loop->timers; it; it = g_slist_next(it)) {
205             ObMainLoopTimer *t = it->data;
206             if (t->destroy) t->destroy(t->data);
207             g_free(t);
208         }
209         g_slist_free(loop->timers);
210         loop->timers = NULL;
211
212         for (i = 0; i < NUM_SIGNALS; ++i)
213             for (it = loop->signal_handlers[i]; it; it = next) {
214                 ObMainLoopSignalHandlerType *h = it->data;
215                 next = g_slist_next(it);
216                 ob_main_loop_signal_remove(loop, h->func);
217             }
218
219         all_loops = g_slist_remove(all_loops, loop);
220
221         /* only do this if we're the last loop destroyed */
222         if (!all_loops) {
223             guint i;
224
225             /* grab all the signals that cause core dumps */
226             for (i = 0; i < NUM_CORE_SIGNALS; ++i) {
227                 if (all_signals[core_signals[i]].installed) {
228                     sigaction(core_signals[i],
229                               &all_signals[core_signals[i]].oldact, NULL);
230                     all_signals[core_signals[i]].installed--;
231                 }
232             }
233         }
234
235         for (it = loop->action_queue; it; it = g_slist_next(it))
236             action_unref(it->data);
237         g_slist_free(loop->action_queue);
238
239         g_free(loop);
240     }
241 }
242
243 static void fd_handle_foreach(gpointer key,
244                               gpointer value,
245                               gpointer data)
246 {
247     ObMainLoopFdHandlerType *h = value;
248     fd_set *set = data;
249
250     if (FD_ISSET(h->fd, set))
251         h->func(h->fd, h->data);
252 }
253
254 void ob_main_loop_queue_action(ObMainLoop *loop, ObAction *act)
255 {
256     loop->action_queue = g_slist_append(loop->action_queue, action_copy(act));
257 }
258
259 static void ob_main_loop_client_destroy(ObClient *client, gpointer data)
260 {
261     ObMainLoop *loop = data;
262     GSList *it;
263
264     for (it = loop->action_queue; it; it = g_slist_next(it)) {
265         ObAction *act = it->data;
266
267         if (act->data.any.c == client)
268             act->data.any.c = NULL;
269     }
270 }
271
272 void ob_main_loop_run(ObMainLoop *loop)
273 {
274     XEvent e;
275     struct timeval *wait;
276     fd_set selset;
277     GSList *it;
278     ObAction *act;
279
280     loop->run = TRUE;
281     loop->running = TRUE;
282
283     client_add_destructor(ob_main_loop_client_destroy, loop);
284
285     while (loop->run) {
286         if (loop->signal_fired) {
287             guint i;
288             sigset_t oldset;
289
290             /* block signals so that we can do this without the data changing
291                on us */
292             sigprocmask(SIG_SETMASK, &all_signals_set, &oldset);
293
294             for (i = 0; i < NUM_SIGNALS; ++i) {
295                 while (loop->signals_fired[i]) {
296                     for (it = loop->signal_handlers[i];
297                             it; it = g_slist_next(it)) {
298                         ObMainLoopSignalHandlerType *h = it->data;
299                         h->func(i, h->data);
300                     }
301                     loop->signals_fired[i]--;
302                 }
303             }
304             loop->signal_fired = FALSE;
305
306             sigprocmask(SIG_SETMASK, &oldset, NULL);
307         } else if (XPending(loop->display)) {
308             do {
309                 XNextEvent(loop->display, &e);
310
311                 for (it = loop->x_handlers; it; it = g_slist_next(it)) {
312                     ObMainLoopXHandlerType *h = it->data;
313                     h->func(&e, h->data);
314                 }
315             } while (XPending(loop->display));
316         } else if (loop->action_queue) {
317             /* only fire off one action at a time, then go back for more
318                X events, since the action might cause some X events (like
319                FocusIn :) */
320
321             do {
322                 act = loop->action_queue->data;
323                 if (act->data.any.client_action == OB_CLIENT_ACTION_ALWAYS &&
324                     !act->data.any.c)
325                 {
326                     loop->action_queue =
327                         g_slist_delete_link(loop->action_queue,
328                                 loop->action_queue);
329                     action_unref(act);
330                     act = NULL;
331                 }
332             } while (!act && loop->action_queue);
333
334             if  (act) {
335                 act->func(&act->data);
336                 loop->action_queue =
337                     g_slist_delete_link(loop->action_queue,
338                                         loop->action_queue);
339                 action_unref(act);
340             }
341         } else {
342             /* this only runs if there were no x events received */
343
344             timer_dispatch(loop, (GTimeVal**)&wait);
345
346             selset = loop->fd_set;
347             /* there is a small race condition here. if a signal occurs
348                between this if() and the select() then we will not process
349                the signal until 'wait' expires. possible solutions include
350                using GStaticMutex, and having the signal handler set 'wait'
351                to 0 */
352             if (!loop->signal_fired)
353                 select(loop->fd_max + 1, &selset, NULL, NULL, wait);
354
355             /* handle the X events with highest prioirity */
356             if (FD_ISSET(loop->fd_x, &selset))
357                 continue;
358
359             g_hash_table_foreach(loop->fd_handlers,
360                                  fd_handle_foreach, &selset);
361         }
362     }
363
364     client_remove_destructor(ob_main_loop_client_destroy);
365
366     loop->running = FALSE;
367 }
368
369 void ob_main_loop_exit(ObMainLoop *loop)
370 {
371     loop->run = FALSE;
372 }
373
374 /*** XEVENT WATCHERS ***/
375
376 void ob_main_loop_x_add(ObMainLoop *loop,
377                         ObMainLoopXHandler handler,
378                         gpointer data,
379                         GDestroyNotify notify)
380 {
381     ObMainLoopXHandlerType *h;
382
383     h = g_new(ObMainLoopXHandlerType, 1);
384     h->loop = loop;
385     h->func = handler;
386     h->data = data;
387     h->destroy = notify;
388     loop->x_handlers = g_slist_prepend(loop->x_handlers, h);
389 }
390
391 void ob_main_loop_x_remove(ObMainLoop *loop,
392                            ObMainLoopXHandler handler)
393 {
394     GSList *it, *next;
395
396     for (it = loop->x_handlers; it; it = next) {
397         ObMainLoopXHandlerType *h = it->data;
398         next = g_slist_next(it);
399         if (h->func == handler) {
400             loop->x_handlers = g_slist_delete_link(loop->x_handlers, it);
401             if (h->destroy) h->destroy(h->data);
402             g_free(h);
403         }
404     }
405 }
406
407 /*** SIGNAL WATCHERS ***/
408
409 static void sighandler(gint sig)
410 {
411     GSList *it;
412     guint i;
413
414     g_return_if_fail(sig < NUM_SIGNALS);
415
416     for (i = 0; i < NUM_CORE_SIGNALS; ++i)
417         if (sig == core_signals[i]) {
418             /* XXX special case for signals that default to core dump.
419                but throw some helpful output here... */
420
421             fprintf(stderr, "Fuck yah. Core dump. (Signal=%d)\n", sig);
422
423             /* die with a core dump */
424             abort();
425         }
426
427     for (it = all_loops; it; it = g_slist_next(it)) {
428         ObMainLoop *loop = it->data;
429         loop->signal_fired = TRUE;
430         loop->signals_fired[sig]++;
431     }
432 }
433
434 void ob_main_loop_signal_add(ObMainLoop *loop,
435                              gint signal,
436                              ObMainLoopSignalHandler handler,
437                              gpointer data,
438                              GDestroyNotify notify)
439 {
440     ObMainLoopSignalHandlerType *h;
441
442     g_return_if_fail(signal < NUM_SIGNALS);
443
444     h = g_new(ObMainLoopSignalHandlerType, 1);
445     h->loop = loop;
446     h->signal = signal;
447     h->func = handler;
448     h->data = data;
449     h->destroy = notify;
450     loop->signal_handlers[h->signal] =
451         g_slist_prepend(loop->signal_handlers[h->signal], h);
452
453     if (!all_signals[signal].installed) {
454         struct sigaction action;
455         sigset_t sigset;
456
457         sigemptyset(&sigset);
458         action.sa_handler = sighandler;
459         action.sa_mask = sigset;
460         action.sa_flags = SA_NOCLDSTOP;
461
462         sigaction(signal, &action, &all_signals[signal].oldact);
463     }
464
465     all_signals[signal].installed++;
466 }
467
468 void ob_main_loop_signal_remove(ObMainLoop *loop,
469                                 ObMainLoopSignalHandler handler)
470 {
471     guint i;
472     GSList *it, *next;
473
474     for (i = 0; i < NUM_SIGNALS; ++i) {
475         for (it = loop->signal_handlers[i]; it; it = next) {
476             ObMainLoopSignalHandlerType *h = it->data;
477
478             next = g_slist_next(it);
479
480             if (h->func == handler) {
481                 g_assert(all_signals[h->signal].installed > 0);
482
483                 all_signals[h->signal].installed--;
484                 if (!all_signals[h->signal].installed) {
485                     sigaction(h->signal, &all_signals[h->signal].oldact, NULL);
486                 }
487
488                 loop->signal_handlers[i] =
489                     g_slist_delete_link(loop->signal_handlers[i], it);
490                 if (h->destroy) h->destroy(h->data);
491
492                 g_free(h);
493             }
494         }
495     }
496
497 }
498
499 /*** FILE DESCRIPTOR WATCHERS ***/
500
501 static void max_fd_func(gpointer key, gpointer value, gpointer data)
502 {
503     ObMainLoop *loop = data;
504
505     /* key is the fd */
506     loop->fd_max = MAX(loop->fd_max, *(gint*)key);
507 }
508
509 static void calc_max_fd(ObMainLoop *loop)
510 {
511     loop->fd_max = loop->fd_x;
512
513     g_hash_table_foreach(loop->fd_handlers, max_fd_func, loop);
514 }
515
516 void ob_main_loop_fd_add(ObMainLoop *loop,
517                          gint fd,
518                          ObMainLoopFdHandler handler,
519                          gpointer data,
520                          GDestroyNotify notify)
521 {
522     ObMainLoopFdHandlerType *h;
523
524     h = g_new(ObMainLoopFdHandlerType, 1);
525     h->loop = loop;
526     h->fd = fd;
527     h->func = handler;
528     h->data = data;
529     h->destroy = notify;
530
531     g_hash_table_replace(loop->fd_handlers, &h->fd, h);
532     FD_SET(h->fd, &loop->fd_set);
533     calc_max_fd(loop);
534 }
535
536 static void fd_handler_destroy(gpointer data)
537 {
538     ObMainLoopFdHandlerType *h = data;
539
540     FD_CLR(h->fd, &h->loop->fd_set);
541
542     if (h->destroy)
543         h->destroy(h->data);
544 }
545
546 void ob_main_loop_fd_remove(ObMainLoop *loop,
547                             gint fd)
548 {
549     g_hash_table_remove(loop->fd_handlers, &fd);
550 }
551
552 /*** TIMEOUTS ***/
553
554 #define NEAREST_TIMEOUT(loop) \
555     (((ObMainLoopTimer*)(loop)->timers->data)->timeout)
556
557 static glong timecompare(GTimeVal *a, GTimeVal *b)
558 {
559     glong r;
560
561     if ((r = b->tv_sec - a->tv_sec)) return r;
562     return b->tv_usec - a->tv_usec;
563     
564 }
565
566 static void insert_timer(ObMainLoop *loop, ObMainLoopTimer *ins)
567 {
568     GSList *it;
569     for (it = loop->timers; it; it = g_slist_next(it)) {
570         ObMainLoopTimer *t = it->data;
571         if (timecompare(&ins->timeout, &t->timeout) >= 0) {
572             loop->timers = g_slist_insert_before(loop->timers, it, ins);
573             break;
574         }
575     }
576     if (it == NULL) /* didnt fit anywhere in the list */
577         loop->timers = g_slist_append(loop->timers, ins);
578 }
579
580 void ob_main_loop_timeout_add(ObMainLoop *loop,
581                               gulong microseconds,
582                               GSourceFunc handler,
583                               gpointer data,
584                               GDestroyNotify notify)
585 {
586     ObMainLoopTimer *t = g_new(ObMainLoopTimer, 1);
587     t->delay = microseconds;
588     t->func = handler;
589     t->data = data;
590     t->destroy = notify;
591     t->del_me = FALSE;
592     g_get_current_time(&loop->now);
593     t->last = t->timeout = loop->now;
594     g_time_val_add(&t->timeout, t->delay);
595
596     insert_timer(loop, t);
597 }
598
599 void ob_main_loop_timeout_remove(ObMainLoop *loop,
600                                  GSourceFunc handler)
601 {
602     GSList *it;
603
604     for (it = loop->timers; it; it = g_slist_next(it)) {
605         ObMainLoopTimer *t = it->data;
606         if (t->func == handler)
607             t->del_me = TRUE;
608     }
609 }
610
611 void ob_main_loop_timeout_remove_data(ObMainLoop *loop, GSourceFunc handler,
612                                       gpointer data, gboolean cancel_dest)
613 {
614     GSList *it;
615
616     for (it = loop->timers; it; it = g_slist_next(it)) {
617         ObMainLoopTimer *t = it->data;
618         if (t->func == handler && t->data == data) {
619             t->del_me = TRUE;
620             if (cancel_dest)
621                 t->destroy = NULL;
622         }
623     }
624 }
625
626 /* find the time to wait for the nearest timeout */
627 static gboolean nearest_timeout_wait(ObMainLoop *loop, GTimeVal *tm)
628 {
629   if (loop->timers == NULL)
630     return FALSE;
631
632   tm->tv_sec = NEAREST_TIMEOUT(loop).tv_sec - loop->now.tv_sec;
633   tm->tv_usec = NEAREST_TIMEOUT(loop).tv_usec - loop->now.tv_usec;
634
635   while (tm->tv_usec < 0) {
636     tm->tv_usec += G_USEC_PER_SEC;
637     tm->tv_sec--;
638   }
639   tm->tv_sec += tm->tv_usec / G_USEC_PER_SEC;
640   tm->tv_usec %= G_USEC_PER_SEC;
641   if (tm->tv_sec < 0)
642     tm->tv_sec = 0;
643
644   return TRUE;
645 }
646
647 static void timer_dispatch(ObMainLoop *loop, GTimeVal **wait)
648 {
649     GSList *it, *next;
650
651     gboolean fired = FALSE;
652
653     g_get_current_time(&loop->now);
654
655     for (it = loop->timers; it; it = next) {
656         ObMainLoopTimer *curr;
657         
658         next = g_slist_next(it);
659
660         curr = it->data;
661
662         /* since timer_stop doesn't actually free the timer, we have to do our
663            real freeing in here.
664         */
665         if (curr->del_me) {
666             /* delete the top */
667             loop->timers = g_slist_delete_link(loop->timers, it); 
668             if (curr->destroy)
669                 curr->destroy(curr->data);
670             g_free(curr);
671             continue;
672         }
673
674         /* the queue is sorted, so if this timer shouldn't fire, none are 
675            ready */
676         if (timecompare(&NEAREST_TIMEOUT(loop), &loop->now) < 0)
677             break;
678
679         /* we set the last fired time to delay msec after the previous firing,
680            then re-insert.  timers maintain their order and may trigger more
681            than once if they've waited more than one delay's worth of time.
682         */
683         loop->timers = g_slist_delete_link(loop->timers, it);
684         g_time_val_add(&curr->last, curr->delay);
685         if (curr->func(curr->data)) {
686             g_time_val_add(&curr->timeout, curr->delay);
687             insert_timer(loop, curr);
688         } else {
689             if (curr->destroy)
690                 curr->destroy(curr->data);
691             g_free(curr);
692         }
693
694         fired = TRUE;
695     }
696
697     if (fired) {
698         /* if at least one timer fires, then don't wait on X events, as there
699            may already be some in the queue from the timer callbacks.
700         */
701         loop->ret_wait.tv_sec = loop->ret_wait.tv_usec = 0;
702         *wait = &loop->ret_wait;
703     } else if (nearest_timeout_wait(loop, &loop->ret_wait))
704         *wait = &loop->ret_wait;
705     else
706         *wait = NULL;
707 }