/xminuto.c
C | 232 lines | 199 code | 28 blank | 5 comment | 41 complexity | 6a9eb0d4f7d871b7a785686b4b0fc6d4 MD5 | raw file
- #include <X11/Xlib.h>
- #include <X11/Xatom.h>
- #include <X11/Xutil.h>
- #include <sys/select.h>
- #include <string.h>
- #include <time.h>
- #include <stdlib.h>
- #include <unistd.h>
- #ifdef DOMINO
- const int cols = 3;
- #else
- const int cols = 4;
- #endif
- struct options {
- int minimal;
- int background;
- int x;
- int y;
- int width;
- };
- void get_current_time(struct tm *local_time, struct timeval *wait_time) {
- struct timespec timestamp;
- int fails = 0;
- while (clock_gettime(CLOCK_REALTIME, ×tamp)) {
- if (fails++ > 10) exit(3);
- }
- long nsec_offset = timestamp.tv_nsec;
- time_t current_second = timestamp.tv_sec;
- localtime_r(¤t_second, local_time);
- wait_time->tv_usec = 1000000 - nsec_offset / 1000;
- wait_time->tv_sec = (local_time->tm_sec > 58)? 0: 59 - local_time->tm_sec;
- }
- void draw_clock(const struct tm *lt, Display *display, Window window) {
- XWindowAttributes attributes;
- int screen = DefaultScreen(display);
- unsigned long black = BlackPixel(display, screen);
- unsigned long white = WhitePixel(display, screen);
- GC gc = XCreateGC(display, window, 0, 0);
- XGetWindowAttributes(display, window, &attributes);
- int height = attributes.height - 2;
- int width = attributes.width - 2;
- int mask = cols == 3? 4: 1;
- int x_pos[] = {0, width / cols, width * 2 / cols, width * 3 / cols, width};
- int y_pos[] = {0, height / 2, height};
- int bits = ((lt->tm_hour << 6) | (lt->tm_min << 4) / 15);
- for (int col = cols; col--;) {
- for (int row = 2; row--;) {
- XSetForeground(display, gc, bits & mask? black: white);
- XFillRectangle(display, window, gc,
- 1 + x_pos[col], 1 + y_pos[row],
- x_pos[col + 1] - x_pos[col],
- y_pos[row + 1] - y_pos[row]);
- mask <<= 1;
- }
- }
- XSetForeground(display, gc, black);
- if (! (bits & (cols == 3? 0xa8: 0xaa))) {
- XDrawLine(display, window, gc, (1 + width) / 2, 1,
- (1 + width) / 2, height / 4);
- }
- if (! (bits & (cols == 3? 0x54: 0x55))) {
- XDrawLine(display, window, gc, (1 + width) / 2, 1 + 3 * height / 4,
- (1 + width) / 2, 1 + height);
- }
- if (! (bits & 0xc0)) {
- XDrawLine(display, window, gc, 1, 1 + height / 2,
- width / 8, 1 + height/2);
- }
- if (! (bits & (cols == 3? 0xc: 3))) {
- XDrawLine(display, window, gc, 1 + 7 * width / 8, 1 + height / 2,
- 1 + width, 1 + height/2);
- }
- XSetForeground(display, gc, white);
- XDrawLine(display, window, gc, 0, 0, width + 1, 0);
- XDrawLine(display, window, gc, 0, 0, 0, height + 1);
- XDrawLine(display, window, gc, width + 1, 0, width + 1, height + 1);
- XDrawLine(display, window, gc, 0, height + 1, width + 1, height + 1);
- XFreeGC(display, gc);
- XFlush(display);
- };
- Window initialize_window(Display *display, struct options *options) {
- int width = options->width * cols + 2;
- int height = options->width * 2 + 2;
- Window window = XCreateSimpleWindow(
- display, DefaultRootWindow(display),
- 0, 0, width, height, 0, 0, 0);
- XSetStandardProperties(display, window, "Minuto", "Minuto",
- None, NULL, 0, NULL);
- if (options->minimal || options->background) {
- // This should make the window undecorated and always on top
- Atom windowType = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
- long typeValue = XInternAtom(display,
- options->minimal?
- "_NET_WM_WINDOW_TYPE_DOCK": "_NET_WM_WINDOW_TYPE_DESKTOP",
- False);
- if (windowType != None) {
- XChangeProperty(display, window, windowType,
- XA_ATOM, 32, PropModeReplace,
- (unsigned char *) &typeValue, 1);
- }
- // Place on all desktops
- unsigned long desktop_value = 0xffffffff;
- Atom desktop = XInternAtom(display, "_NET_WM_DESKTOP", False);
- if (desktop != None) {
- XChangeProperty(display, window, desktop,
- XA_CARDINAL, 32, PropModeReplace,
- (unsigned char *) &desktop_value, 1);
- }
- // Don't request focus
- XWMHints *hints = XAllocWMHints();
- hints->flags = InputHint;
- hints->input = 0;
- XSetWMHints(display, window, hints);
- }
- // These are defaults for _NET_WM_WINDOW_TYPE_DOCK, at least with Openbox
- Atom windowState = XInternAtom(display, "_NET_WM_STATE", False);
- long stateValues[2];
- stateValues[0] = XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False);
- stateValues[1] = XInternAtom(display,
- options->minimal? "_NET_WM_STATE_ABOVE": "_NET_WM_STATE_BELOW",
- False);
- if (windowState != None) {
- XChangeProperty(display, window, windowState,
- XA_ATOM, 32, PropModeReplace,
- (unsigned char *) &stateValues,
- options->minimal || options->background? 2: 1);
- }
- XSelectInput(display, window, ExposureMask | VisibilityChangeMask);
- XMapWindow(display, window);
- // Looks like this only works after the map
- if (options->x || options->y) {
- XMoveWindow(display, window, options->x, options->y);
- }
- XFlush(display);
- return window;
- }
- void set_options(struct options *options, int argc, char *argv[]) {
- int opt;
- while ((opt = getopt(argc, argv, "mbx:y:w:")) != -1) {
- switch(opt) {
- case 'm':
- options->minimal = 1;
- options->x = options->x? options->x: 0x300;
- options->width = options->width? options->width: 4;
- break;
- case 'b':
- options->background = 1;
- break;
- case 'x':
- options->x = atoi(optarg);
- break;
- case 'y':
- options->y = atoi(optarg);
- break;
- case 'w':
- options->width = atoi(optarg);
- break;
- }
- }
- options->width = options->width? options->width: 0x10;
- }
- int main(int argc, char *argv[]) {
- Display *display;
- struct options options = {.minimal = 0, .background = 0,
- .x = 0, .y = 0, .width = 0};
- XEvent event;
- struct tm local_time;
- struct timeval wait_time = {.tv_sec = 1, .tv_usec = 0};
- fd_set in_fds;
- set_options(&options, argc, argv);
- display = XOpenDisplay(NULL);
- if (display == NULL) return 1;
- Window window = initialize_window(display, &options);
- int file_descriptor = ConnectionNumber(display);
- Atom deleteWindow = XInternAtom(display, "WM_DELETE_WINDOW", 0);
- if (deleteWindow != None) {
- XSetWMProtocols(display, window, &deleteWindow, 1);
- }
- int visible = 1;
- while (1) {
- FD_ZERO(&in_fds);
- FD_SET(file_descriptor, &in_fds);
- int num_fds = select(file_descriptor + 1, &in_fds, NULL, NULL,
- visible? &wait_time: NULL);
- if (num_fds < 0) return 2;
- while (XPending(display)) {
- XNextEvent(display, &event);
- if (event.type == ClientMessage
- && event.xclient.data.l[0] == deleteWindow) {
- XDestroyWindow(display, window);
- XCloseDisplay(display);
- return 0;
- }
- else if (event.type == VisibilityNotify) {
- visible = event.xvisibility.state
- != VisibilityFullyObscured;
- }
- }
- if (visible) {
- get_current_time(&local_time, &wait_time);
- draw_clock(&local_time, display, window);
- }
- }
- }