monsterwm

Personal build of monsterwm
git clone git://git.gormless.xyz/monsterwm.git
Log | Files | Refs | README | LICENSE

mopag.c (7148B)


      1 /**
      2  * Matus Telgarsky <chisel@gmail.com>
      3  * gcc -o mopag -std=c99 -pedantic -Wall -Wextra -Os mopag.c -lX11
      4  */
      5 
      6 #include <stdio.h>
      7 #include <string.h>
      8 #include <stdlib.h>
      9 #include <unistd.h>
     10 #include <assert.h>
     11 #include <sys/select.h>
     12 #include <X11/Xlib.h>
     13 
     14 #define HEIGHT      4
     15 #define FATTICK_W   4
     16 #define TOP         True        /* show on top or bottom of the screen */
     17 #define GAP         (14)        /* space above when on top. space below when on bottom */
     18 #define BG          "#3b4252"
     19 #define FG          "#d8dee9"
     20 #define URFG        "#eceff4"
     21 #define URBG        "#2e3440"
     22 #define WINFG       "#3b4252"
     23 #define WINBG       "#5e81ac"
     24 
     25 typedef struct {
     26     unsigned int nwins;
     27     unsigned int mode;
     28     unsigned int urgent;
     29 } DeskInfo;
     30 
     31 enum { BORED, ERROR, RERENDER };
     32 
     33 static void cleanup();
     34 static int parse();
     35 static void render();
     36 static void setup();
     37 
     38 static long fg, bg, urfg, urbg, winfg, winbg;
     39 static unsigned int currdesk, ndesks = 0;
     40 static int screen, scrwidth;
     41 static Display *dis;
     42 static Window root, w;
     43 static Pixmap pm;
     44 static GC gc;
     45 static DeskInfo *di = NULL;
     46 
     47 void setup()
     48 {
     49     assert((dis = XOpenDisplay(NULL)));
     50     screen = DefaultScreen(dis);
     51     root = RootWindow(dis, screen);
     52     scrwidth  = DisplayWidth(dis, screen);
     53 
     54     long *col_vars[] = { &fg, &bg, &urfg, &urbg, &winfg, &winbg, NULL };
     55     const char *col_strs[] = { FG, BG, URFG, URBG, WINFG, WINBG, NULL };
     56     XColor c;
     57     for (unsigned int i = 0; col_vars[i]; ++i) {
     58         assert(XAllocNamedColor(dis, DefaultColormap(dis, screen), col_strs[i], &c, &c));
     59         *col_vars[i] = c.pixel;
     60     }
     61 
     62     XSetWindowAttributes wa = { .background_pixel = bg, .override_redirect = 1, .event_mask = ExposureMask, };
     63     w = XCreateWindow(dis, root, 0,
     64             (TOP) ? GAP : DisplayHeight(dis, screen) - HEIGHT - GAP,
     65             scrwidth, HEIGHT, 1, CopyFromParent, InputOutput, CopyFromParent,
     66             CWBackPixel | CWOverrideRedirect | CWEventMask, &wa);
     67     XMapWindow(dis, w);
     68     XSetWindowBorderWidth(dis, w, 0);
     69 
     70     XGCValues gcv = { .graphics_exposures = 0, }; /* otherwise get NoExpose on XCopyArea */
     71     gc = XCreateGC(dis, root, GCGraphicsExposures, &gcv);
     72     pm = XCreatePixmap(dis, w, scrwidth, HEIGHT, DefaultDepth(dis,screen));
     73 }
     74 
     75 int parse()
     76 {
     77     static DeskInfo *di_temp;
     78     static unsigned int cur_desk_temp;
     79 
     80     char buf2[2048];
     81     ssize_t ret = read(STDIN_FILENO, buf2, sizeof(buf2));
     82     assert(buf2[ret - 1] == '\n');
     83     assert(ret > 2); /* XXX I had this fail once! (after 1 week of use?) */
     84     unsigned int pos2 = ret - 2;
     85     while (pos2 > 0 && buf2[pos2] != '\n') pos2 -= 1;
     86     printf("pos2 %u\n", pos2);
     87     char *buf = buf2 + pos2;
     88 
     89     int rerender = 0;
     90 
     91     if (!di) {
     92         char *s;
     93         assert(s = strrchr(buf, ' '));
     94         ndesks = atoi(s) + 1;
     95         assert((di = malloc(ndesks * sizeof(DeskInfo))));
     96         assert((di_temp = malloc(ndesks * sizeof(DeskInfo))));
     97         rerender = 1;
     98     }
     99 
    100     char *pos = buf;
    101     for (unsigned int i = 0; i < ndesks; ++i)
    102     {
    103         unsigned int is_cur, d;
    104         int offset;
    105         int res = sscanf(pos, "%u:%u:%u:%u:%u%n", &d, &di_temp[i].nwins,
    106                 &di_temp[i].mode, &is_cur, &di_temp[i].urgent, &offset);
    107         printf("[%u, %u:%u:%u:%u:%u] ", res, d, di_temp[i].nwins,
    108                 di_temp[i].mode, is_cur, di_temp[i].urgent);
    109         if (res < 5 || d != i) { /* %n doesn't count */
    110             fprintf(stderr, "Ignoring malformed input.\n");
    111             return ERROR;
    112         }
    113 
    114         if (is_cur)
    115             cur_desk_temp = i;
    116 
    117         if (!rerender &&
    118                 (di_temp[i].nwins != di[i].nwins
    119                  || di_temp[i].mode != di[i].mode
    120                  || di_temp[i].urgent != di[i].urgent
    121                  || (is_cur != (currdesk == i)) ) )
    122             rerender = 1;
    123         printf("(re %u) ", rerender);
    124 
    125         pos += offset; /* okay if goes off end */
    126     }
    127 
    128     if (rerender) {
    129         currdesk = cur_desk_temp;
    130         DeskInfo *t = di;
    131         di = di_temp;
    132         di_temp = t;
    133         return RERENDER;
    134     } else return BORED;
    135 }
    136 
    137 void render()
    138 {
    139     XSetForeground(dis, gc, bg);
    140     XFillRectangle(dis, pm, gc, 0, 0, scrwidth, HEIGHT);
    141 
    142     for (unsigned int i = 0; i < ndesks; ++i)
    143     {
    144         unsigned int start = i * scrwidth/ ndesks;
    145         unsigned int end = (i + 1) * scrwidth / ndesks;
    146         unsigned int width = end - start;
    147 
    148         if (i == currdesk || di[i].urgent) {
    149             XSetForeground(dis, gc, di[i].urgent ? ((i == currdesk) ? urfg : urbg) : fg);
    150             XFillRectangle(dis, pm, gc, start, 0, width, HEIGHT);
    151         }
    152 
    153 
    154         printf("[%u, %u] ", i, di[i].nwins);
    155         if (di[i].nwins) {
    156             //XSetForeground(dis, gc, (i == currdesk) ? bg : fg);
    157 
    158             unsigned int tick_width = width / di[i].nwins / 4;
    159             tick_width = (tick_width > FATTICK_W) ? FATTICK_W : tick_width;
    160             unsigned int nticks = di[i].nwins;
    161             if (!tick_width) {
    162                 tick_width = 1;
    163                 nticks = width / 4;
    164             }
    165 
    166             for (unsigned int j = 0; j < nticks; ++j) {
    167                 XSetForeground(dis, gc, winbg);
    168                 XFillRectangle(dis, pm, gc, start + tick_width * (2 * j + 1), 0,
    169                         tick_width,HEIGHT);
    170                 if (tick_width > 2 && HEIGHT > 2) {
    171                     XSetForeground(dis, gc, winfg);
    172                     XFillRectangle(dis, pm, gc, start + tick_width * (2 * j + 1) +1, 1,
    173                             tick_width - 2, HEIGHT - 2);
    174                 }
    175             }
    176         } else {
    177             /* XXX this debugging check shows the status indicator bug is in monster, not with me */
    178             //XSetForeground(dis, gc, winbg);
    179             //XFillRectangle(dis, pm, gc, start+FATTICK_W*5, 0, FATTICK_W * 5, HEIGHT);
    180         }
    181     }
    182     printf("\n");
    183 }
    184 
    185 void cleanup()
    186 {
    187     //di not free()'d for solidarity with di_temp
    188     XFreeGC(dis, gc);
    189     XFreePixmap(dis, pm);
    190     XDestroyWindow(dis, w);
    191     XCloseDisplay(dis);
    192 }
    193 
    194 int main()
    195 {
    196     setup();
    197 
    198     int xfd = ConnectionNumber(dis);
    199     int nfds = 1 + ((xfd > STDIN_FILENO) ? xfd : STDIN_FILENO);
    200     while (1) {
    201         int redraw = 0;
    202         fd_set fds;
    203         FD_ZERO(&fds);
    204         FD_SET(xfd, &fds);
    205         FD_SET(STDIN_FILENO, &fds);
    206         select(nfds, &fds, NULL, NULL, NULL);
    207 
    208         if (FD_ISSET(STDIN_FILENO, &fds)) {
    209             if (parse() == RERENDER) {
    210                 render();
    211                 redraw = 1;
    212             }
    213         }
    214 
    215         if (FD_ISSET(xfd, &fds)) {
    216             /* XXX I still (2012-02-28) can drop some exposes
    217              * test: start xscreensaver, leave it, BAM, mopag not redrawn
    218              */
    219             XEvent xev;
    220             while (XPending(dis)) {
    221                 XNextEvent(dis, &xev);
    222                 printf("EXPOSE\n");
    223                 if (xev.type == Expose)
    224                     redraw = 1;
    225                 else
    226                     fprintf(stderr, "weird event of type %u\n", xev.type);
    227             }
    228         }
    229 
    230         if (redraw)
    231             XCopyArea(dis, pm, w, gc, 0, 0, scrwidth, HEIGHT, 0, 0);
    232 
    233         XSync(dis, False);
    234     }
    235 
    236     cleanup();
    237 }