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