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}