xrectdraw

Draw geometry of a rectangular screen region
git clone git://git.noxz.tech/xrectdraw
Log | Files | Refs | README | LICENSE

xrectdraw.c (6585B)


      1 /*
      2  * MIT License
      3  *
      4  * © 2019 Chris Noxz <chris@noxz.tech>
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  */
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <stdarg.h>
     27 #include <string.h>
     28 
     29 #include <X11/Xlib.h>
     30 #include <X11/Xutil.h>
     31 
     32 #include "config.def.h"
     33 
     34 struct Border {
     35     int top;
     36     int right;
     37     int bottom;
     38     int left;
     39 };
     40 
     41 static int screen, gfocus;
     42 static Display *dpy;
     43 static Window root, win[4];
     44 static XColor color[2];
     45 static struct Border border;
     46 
     47 void
     48 die(char *format, ...)
     49 {
     50     va_list args;
     51 
     52     va_start(args, format);
     53     vprintf(format, args);
     54     va_end(args);
     55 
     56     exit(1);
     57 }
     58 
     59 void
     60 draw(int x, int y, int width, int height)
     61 {
     62     int i, ix, iy, iw, ih;
     63     XWindowAttributes wa;
     64     XSetWindowAttributes swa;
     65     XClassHint ch = {"xrectdraw", "xrectdraw"};
     66 
     67     swa.border_pixel = 0;
     68     swa.background_pixel = color[0].pixel;
     69     swa.override_redirect = 1;
     70     swa.event_mask = ExposureMask
     71         | KeyPressMask
     72         | ButtonPressMask
     73         | FocusChangeMask;
     74 
     75     XGetWindowAttributes(dpy, root, &wa);
     76 
     77     for (i = 0; i < 4; i++) {
     78         switch (i) {
     79         case 0: // setup for left border
     80             ix = x - border.left;
     81             iy = y - border.top;
     82             iw = border.left;
     83             ih = height + border.bottom;
     84             break;
     85         case 1: // setup for right border
     86             ix += (width + border.left);
     87             iw = border.right;
     88             break;
     89         case 2: // setup for top border
     90             ix -= (width + border.left);
     91             iw = (width + border.left + border.right);
     92             ih = border.top;
     93             break;
     94         case 3: // setup for bottom border
     95             ih = border.bottom;
     96             iy += (height + border.top);
     97             break;
     98         }
     99 
    100         win[i] = XCreateWindow(dpy, root, ix, iy, iw, ih, 0,
    101             CopyFromParent, CopyFromParent, CopyFromParent,
    102             CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
    103 
    104         XSetClassHint(dpy, win[i], &ch);
    105         XMapRaised(dpy, win[i]);
    106         XSetInputFocus(dpy, win[i], RevertToParent, CurrentTime);
    107     }
    108 }
    109 
    110 int
    111 hex(const char c)
    112 {
    113     if (c >= 0x30 && c <= 0x39)
    114         return c - 0x30;
    115     else if (c >= 0x41 && c <= 0x46)
    116         return c - 0x41 + 10;
    117     else if (c >= 0x61 && c <= 0x66)
    118         return c - 0x61 + 10;
    119     else
    120         puts("error: cannot set color");
    121     return 0;
    122 }
    123 
    124 void
    125 setcolor(const char *clr)
    126 {
    127     int i, r;
    128     const char *ptr;
    129 
    130     color[0].flags = DoRed | DoGreen | DoBlue;
    131     color[1].flags = DoRed | DoGreen | DoBlue;
    132 
    133     for (i = 0; i < 3; i++) {
    134         ptr = clr + (1 + i * 2);
    135         r = (hex(ptr[0]) * 16 + hex(ptr[1])) * 256;
    136 
    137         switch (i) {
    138         case 0:
    139             color[0].red = r;
    140             color[1].red = r * dim_percentage;
    141             break;
    142         case 1:
    143             color[0].green = r;
    144             color[1].green = r * dim_percentage;
    145             break;
    146         case 2:
    147             color[0].blue = r;
    148             color[1].blue = r * dim_percentage;
    149             break;
    150         }
    151     }
    152 
    153     XAllocColor(dpy, DefaultColormap(dpy, screen), &color[0]);
    154     XAllocColor(dpy, DefaultColormap(dpy, screen), &color[1]);
    155 }
    156 
    157 void
    158 toggle()
    159 {
    160     if (!gfocus)
    161         XSetInputFocus(dpy, win[0], RevertToParent, CurrentTime);
    162     else
    163         XSetInputFocus(dpy, None, RevertToParent, CurrentTime);
    164 }
    165 
    166 void
    167 highlight(int focus)
    168 {
    169     unsigned long pixel = color[!(gfocus = focus)].pixel;
    170 
    171     for (int i = 0; i < 4; i++) {
    172         XSetWindowBackground(dpy, win[i], pixel);
    173         XClearArea(dpy, win[i], 0, 0, 0, 0, True);
    174     }
    175 }
    176 
    177 void
    178 setborders(const char *str)
    179 {
    180     if (sscanf(str, "%d:%d:%d:%d",
    181         &border.top,
    182         &border.right,
    183         &border.bottom,
    184         &border.left) != 4)
    185         die("error: borders should be entered in the format 't:r:b:l'");
    186 }
    187 
    188 int
    189 main(int argc, const char *argv[])
    190 {
    191     int x, y, width, height;
    192 
    193     border.top = BORDER_TOP;
    194     border.right = BORDER_RIGHT;
    195     border.bottom = BORDER_BOTTOM;
    196     border.left = BORDER_LEFT;
    197 
    198     if (argc == 7 && argc--)
    199         setborders(argv[6]);
    200 
    201     if (argc != 6
    202         || strcmp(argv[1], "-h") == 0
    203         || strcmp(argv[1], "--help") == 0)
    204         die(
    205             "usage: %s x y width height #RRGGBB [t:r:b:l]\n"
    206             "  x        x coordinage on screen\n"
    207             "  y        y coordinage on screen\n"
    208             "  width    width of the rectangle\n"
    209             "  height   height of the rectangle (downwards)\n"
    210             "  #RRGGBB  hex border colors of the rectangle\n"
    211             "  t:r:b:l  (optional) border widths: top, right, bottom & left\n"
    212             "           e.g. 2:2:5:2. Default is 1:1:1:1\n\n"
    213             "Use ESC key to kill the program when focused. Clicking on the\n"
    214             "borders toggles the focus.\n"
    215         , argv[0]);
    216 
    217     if (!(dpy = XOpenDisplay(NULL)))
    218         die("error: cannot open display");
    219 
    220     screen = DefaultScreen(dpy);
    221     root = RootWindow(dpy, screen);
    222 
    223     x = atoi(argv[1]);
    224     y = atoi(argv[2]);
    225     width = atoi(argv[3]);
    226     height = atoi(argv[4]);
    227     setcolor(argv[5]);
    228 
    229     draw(x, y, width, height);
    230 
    231     XEvent ev;
    232     for (;;) {
    233         XNextEvent(dpy, &ev);
    234         if (ev.type == Expose)
    235             continue;
    236         else if (ev.type == KeyPress && ev.xkey.keycode == exit_key)
    237             break;
    238         else if (ev.type == ButtonPress)
    239             toggle();
    240         else if (ev.type == FocusIn)
    241             highlight(True);
    242         else if (ev.type == FocusOut)
    243             highlight(False);
    244     }
    245 
    246     XCloseDisplay(dpy);
    247     return 0;
    248 }