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
130
131
132
133
134
135
136
137
|
#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);
XLockDisplay(wm.dpy);
switch (wm.ev.type) {
case MapRequest:
handle_map_request();
break;
case MapNotify:
handle_map_notify();
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;
case ConfigureNotify:
handle_configure_notify();
break;
}
XUnlockDisplay(wm.dpy);
}
deinit_window_manager();
if (wm.restart) {
execvp(argv[0], argv);
perror("execvp");
}
return 0;
}
|