1#include <pthread.h>
2#include <signal.h>
3#include <unistd.h>
4
5#include "glitch.h"
6
7WindowManager wm = {0};
8
9void handle_signal(int signal) {
10 wm.running = 0;
11 wm.restart = 1;
12 printf("running: %d\n", wm.running);
13 log_message(stderr, LOG_DEBUG, "Signal received: %d", signal);
14}
15
16static void* expose_timer_thread(void* arg) {
17 (void)arg;
18
19 for(;;) {
20 sleep(1);
21
22 if (wm.dpy != NULL) {
23 XLockDisplay(wm.dpy);
24 XEvent event = {0};
25 event.type = Expose;
26 event.xexpose.window = wm.root;
27 event.xexpose.x = 0;
28 event.xexpose.y = 0;
29 event.xexpose.width = 1;
30 event.xexpose.height = 1;
31 event.xexpose.count = 0;
32
33 // This is thread-safe - XSendEvent is designed for this.
34 XSendEvent(wm.dpy, wm.root, False, ExposureMask, &event);
35 XFlush(wm.dpy);
36 XUnlockDisplay(wm.dpy);
37 }
38 }
39 return NULL;
40}
41
42int main(int argc, char *argv[]) {
43 (void)argc;
44 set_log_level(get_log_level_from_env());
45
46 // Initialize X11 threading support.
47 if (!XInitThreads()) {
48 log_message(stderr, LOG_ERROR, "XInitThreads failed");
49 return 1;
50 }
51
52 init_window_manager();
53
54 // Starts Expose ticker for updating widgets.
55 pthread_t timer_tid;
56 if (pthread_create(&timer_tid, NULL, expose_timer_thread, NULL) != 0) {
57 log_message(stderr, LOG_ERROR, "failed to create timer thread");
58 } else {
59 pthread_detach(timer_tid);
60 }
61
62 // SIGUSR1 is used for restarting the window manager.
63 // kill -s SIGUSR1 $(pidof glitch)
64 signal(SIGUSR1, handle_signal);
65
66 wm.running = 1;
67 while(wm.running) {
68 XNextEvent(wm.dpy, &wm.ev);
69
70 XLockDisplay(wm.dpy);
71 switch (wm.ev.type) {
72 case MapRequest:
73 handle_map_request();
74 break;
75 case MapNotify:
76 handle_map_notify();
77 break;
78 case UnmapNotify:
79 handle_unmap_notify();
80 break;
81 case DestroyNotify:
82 handle_destroy_notify();
83 break;
84 case PropertyNotify:
85 handle_property_notify();
86 break;
87 case MotionNotify:
88 // Compress MotionNotify events.
89 while (XCheckTypedEvent(wm.dpy, MotionNotify, &wm.ev));
90 handle_motion_notify();
91 break;
92 case ClientMessage:
93 handle_client_message();
94 break;
95 case ButtonPress:
96 handle_button_press();
97 break;
98 case ButtonRelease:
99 handle_button_release();
100 break;
101 case KeyPress:
102 handle_key_press();
103 break;
104 case KeyRelease:
105 handle_key_release();
106 break;
107 case FocusIn:
108 handle_focus_in();
109 break;
110 case FocusOut:
111 handle_focus_out();
112 break;
113 case EnterNotify:
114 handle_enter_notify();
115 break;
116 case Expose:
117 handle_expose();
118 break;
119 case ConfigureRequest:
120 handle_configure_request();
121 break;
122 case ConfigureNotify:
123 handle_configure_notify();
124 break;
125 }
126 XUnlockDisplay(wm.dpy);
127 }
128
129 deinit_window_manager();
130
131 if (wm.restart) {
132 execvp(argv[0], argv);
133 perror("execvp");
134 }
135
136 return 0;
137}