#include #include #include #include #include #include #include #include #include #include #include #include "config.h" static Display *dpy; static Visual *visual; static Window root; static Colormap colormap; static int depth; static int screen; static int xfd; static unsigned long alloc_color(const char *s) { XColor color; if (!XAllocNamedColor(dpy, colormap, s, &color, &color)) errx(1, "cannot allocate color"); return color.pixel; } static Window create_win(int x, int y, int w, int h) { XSetWindowAttributes swa; Window win; swa.background_pixel = alloc_color(bg); swa.override_redirect = 1; swa.event_mask = ExposureMask; win = XCreateWindow(dpy, root, x, y, w, h, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWBackPixel | CWOverrideRedirect | CWEventMask, &swa); return win; } static void init_atoms(Window win) { /* set up atoms in the worst possibly way */ Atom dock = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", 0); Atom win_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", 0); XChangeProperty(dpy, win, win_type, XA_ATOM, 32, PropModeReplace, (unsigned char *)&dock, 1); Atom win_state = XInternAtom(dpy, "_NET_WM_STATE", 0); Atom sticky = XInternAtom(dpy, "_NET_WM_STATE_STICKY", 0); XChangeProperty(dpy, win, win_state, XA_ATOM, 32, PropModeReplace, (unsigned char *)&sticky, 1); Atom above = XInternAtom(dpy, "_NET_WM_STATE_ABOVE", 0); XChangeProperty(dpy, win, win_state, XA_ATOM, 32, PropModeReplace, (unsigned char *)&above, 1); Atom wm_name = XInternAtom(dpy, "_NET_WM_NAME", 0); Atom utf8string = XInternAtom(dpy, "UTF8_STRING", 0); char *name = "barito"; XChangeProperty(dpy, win, wm_name, utf8string, 8, PropModeReplace, (unsigned char *)name, strlen(name)); unsigned long prop = 0xFFFFFFFF; Atom desktop = XInternAtom(dpy, "_NET_WM_DESKTOP", 0); XChangeProperty(dpy, win, desktop, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&prop, 1); } static Pixmap create_pixmap(GC gc, int w, int h) { Pixmap pix; pix = XCreatePixmap(dpy, root, w, h, depth); XSetForeground(dpy, gc, alloc_color(bg)); XFillRectangle(dpy, pix, gc, 0, 0, w, h); XSetForeground(dpy, gc, alloc_color(bg)); return pix; } /* allocate color for Xft */ static void xft_alloc_color(const char *colorname, XftColor *color) { if (!XftColorAllocName(dpy, visual, colormap, colorname, color)) errx(1, "cannot allocate color"); } /* draw text on pixmap */ static void draw_text(Drawable pix, XftFont *font, XftColor *color, const char *text) { XGlyphInfo ext; XftDraw *draw; int x, y; size_t len; draw = XftDrawCreate(dpy, pix, visual, colormap); len = strlen(text); XftTextExtentsUtf8(dpy, font, text, len, &ext); x = (WIDTH - ext.width) / 2; y = (HEIGHT + ext.height) / 2 - 4; XftDrawStringUtf8(draw, color, font, x, y, text, len); XftDrawDestroy(draw); } int main(int argc, char *argv[]) { XftColor color; XftFont *font; Pixmap pix; Window win; GC gc; XExposeEvent xexpose; /* read line from stdin */ char buffer[BUFSIZ]; int reading = 1; int flags; /* stdin flags */ /* make stdin non-blocking */ if ((flags = fcntl(STDIN_FILENO, F_GETFL)) == -1) errx(1, "cannot get status flags"); if (fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) == -1) errx(1, "cannot set flags on stdin"); if ((dpy = XOpenDisplay(NULL)) == NULL) errx(1, "could not open display"); screen = DefaultScreen(dpy); colormap = DefaultColormap(dpy, screen); visual = DefaultVisual(dpy, screen); depth = DefaultDepth(dpy, screen); root = RootWindow(dpy, screen); win = create_win(0, 0, WIDTH, HEIGHT); gc = XCreateGC(dpy, root, 0, NULL); pix = create_pixmap(gc, WIDTH, HEIGHT); font = XftFontOpenName(dpy, screen, fontname); xft_alloc_color(fg, &color); xfd = XConnectionNumber(dpy); init_atoms(win); struct pollfd pfd[2]; pfd[0].fd = STDIN_FILENO; pfd[1].fd = xfd; pfd[0].events = pfd[1].events = POLLIN; int redraw = 0; XMapWindow(dpy, win); while (reading) { if (pfd[0].revents & POLLHUP) { pfd[0].fd = -1; reading = 0; } if (poll(pfd, 2, -1)) { if (pfd[0].revents & POLLIN) { if (fgets(buffer, sizeof buffer, stdin) == NULL) break; if (redraw) { XFreePixmap(dpy, pix); pix = create_pixmap(gc, WIDTH, HEIGHT); } draw_text(pix, font, &color, buffer); XClearArea(dpy, win, 0, 0, WIDTH, HEIGHT, 1); XFlush(dpy); } if (pfd[1].revents & POLLIN) { XEvent ev; while (XPending(dpy) && !XNextEvent(dpy, &ev)) { if (ev.type == Expose) { xexpose = ev.xexpose; XCopyArea(dpy, pix, win, gc, xexpose.x, xexpose.y, xexpose.width, xexpose.height, xexpose.x, xexpose.y); redraw = 1; break; } } } } XFlush(dpy); } /* housekeeping */ XUnmapWindow(dpy, win); XDestroyWindow(dpy, win); XFreePixmap(dpy, pix); XFreeGC(dpy, gc); XftColorFree(dpy, visual, colormap, &color); XftFontClose(dpy, font); XCloseDisplay(dpy); return 0; }