xrectdraw

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

commit: 21f56a5908b3c7e4f69f6d990d8ceb94e8b4f05c
parent: 4e25a8e3f4e462612627db4a7115d5dacc61d734
author: Chris Noxz <chris@noxz.tech>
date:   Fri, 1 Nov 2019 20:29:00 +0100
Large commit with Makefile, license, config and more
M.gitignore2+
ALICENSE21++++
AMakefile51++++++++
AREADME.md38++++++
Aconfig.def.h8++
Aconfig.mk21++++
Mxrectdraw.c125+++++++++++---------
7 files changed, 210 insertions(+), 56 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1 +1,3 @@
 xrectdraw
+config.h
+*.o
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+© 2019 Chris Noxz <chris@noxz.tech>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,51 @@
+.POSIX:
+
+include config.mk
+
+SRC = xrectdraw.c
+OBJ = $(SRC:.c=.o)
+
+all: options xrectdraw
+
+options:
+	@echo xrectdraw build options:
+	@echo "VERSION = $(VERSION)"
+	@echo "CFLAGS  = $(STCFLAGS)"
+	@echo "LDFLAGS = $(STLDFLAGS)"
+	@echo "CC      = $(CC)"
+
+.c.o:
+	@echo CC $<
+	@$(CC) $(STCFLAGS) -c $<
+
+${OBJ}: config.h config.mk
+
+config.h:
+	@echo creating $@ from config.def.h
+	@cp config.def.h $@
+
+xrectdraw: $(OBJ)
+	@echo CC -o $@
+	@$(CC) -o $@ $(OBJ) $(STLDFLAGS)
+
+clean:
+	@echo cleaning
+	@rm -f xrectdraw $(OBJ)
+
+install: xrectdraw
+	@echo installing executables to ${PREFIX}/bin
+	@mkdir -p ${PREFIX}/bin
+	@cp -f xrectdraw ${PREFIX}/bin
+	@chmod 755 ${PREFIX}/bin/xrectdraw
+#	@echo installing manual page to ${MANPREFIX}/man1
+#	@mkdir -p ${MANPREFIX}/man1
+#	@cp -f xrectdraw.1 ${MANPREFIX}/man1
+#	@chmod 644 ${MANPREFIX}/man1/xrectdraw.1
+
+uninstall:
+	@echo removing executable files from ${PREFIX}/bin
+	@rm -f ${PREFIX}/bin/xrectdraw
+#	@echo removing manual page from ${MANPREFIX}/man1
+#	@rm -f ${MANPREFIX}/man1/xrectdraw.1
+
+.PHONY: all options clean install uninstall
diff --git a/README.md b/README.md
@@ -0,0 +1,38 @@
+xrectdraw
+=========
+A small program used to draw rectangles on X11. The idea came when I needed
+something to indicate screen recordings for a small script using ffmpeg. I used
+xrectsel for selecting the region for ffmpeg to capture, so I kinda got the
+inspiration from there.
+
+xrectdraw actually draws four windows making up the borders of the rectangle.
+This means no compositor is needed, the root window isn't hogged and the region
+is not overlaied.
+
+Installation
+------------
+Edit config.mk to match your local setup (xrectdraw is installed into the
+/usr/local namespace by default), then simply enter the following command to
+install (if necessary as root):
+
+    make clean install
+
+Customization
+-------------
+xrectdraw can be customized by creating a custom config.h and (re)compiling the
+source code.
+
+Usage
+-----
+Together with the source code is a script called *screenrec.sh* which is a fine
+example of how xrectdraw can be used. The program is used like this:
+
+    xrectdraw 10 20 100 200 \#ff0000 3:2:3:2
+
+The example above draws a rectangle, 100px wide, 200px heigh at the position
+(x:10px, y:20px). The borders are red, the top and bottom are 3px wide and the
+right and left are 2pc wide.
+
+License
+-------
+The project is licensed under the MIT license.
diff --git a/config.def.h b/config.def.h
@@ -0,0 +1,8 @@
+ /* See LICENSE file for copyright and license details. */
+#define BORDER_TOP      1
+#define BORDER_RIGHT    1
+#define BORDER_BOTTOM   1
+#define BORDER_LEFT     1
+
+static int exit_key = 0x09;
+static float dim_percentage = 0.4;
diff --git a/config.mk b/config.mk
@@ -0,0 +1,21 @@
+# xrectdraw version
+VERSION = 0.0.1
+
+# paths
+PREFIX = /usr/local
+MANPREFIX = $(PREFIX)/share/man
+X11INC = /usr/X11R6/include
+X11LIB = /usr/X11R6/lib
+
+# includes and libs
+INCS = -I$(X11INC)
+LIBS = -L$(X11LIB) -lX11
+
+# flags
+CFLAGS = -Wall -pedantic -std=c99
+CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600
+STCFLAGS = $(INCS) $(CPPFLAGS) $(CFLAGS)
+STLDFLAGS = $(LIBS) $(LDFLAGS)
+
+# compiler and linker
+CC = gcc
diff --git a/xrectdraw.c b/xrectdraw.c
@@ -1,3 +1,26 @@
+/*
+ * MIT License
+ *
+ * © 2019 Chris Noxz <chris@noxz.tech>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -6,6 +29,8 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 
+#include "config.def.h"
+
 struct Border {
     int top;
     int right;
@@ -13,14 +38,11 @@ struct Border {
     int left;
 };
 
-Display *dpy;
-int screen, gfocus;
-Window root;
-Window win[4];
-Drawable drw;
-XColor color;
-XColor color_dim;
-struct Border border;
+static int screen, gfocus;
+static Display *dpy;
+static Window root, win[4];
+static XColor color[2];
+static struct Border border;
 
 void
 die(char *format, ...)
@@ -37,21 +59,13 @@ die(char *format, ...)
 void
 draw(int x, int y, int width, int height)
 {
-    int i;
+    int i, ix, iy, iw, ih;
     XWindowAttributes wa;
     XSetWindowAttributes swa;
     XClassHint ch = {"xrectdraw", "xrectdraw"};
-    XIM xim;
-    XIC xic;
-
-    // setup for left border
-    int ix = x - border.left,
-        iy = y - border.top,
-        iw = border.left,
-        ih = height + border.bottom;
 
     swa.border_pixel = 0;
-    swa.background_pixel = color.pixel;
+    swa.background_pixel = color[0].pixel;
     swa.override_redirect = 1;
     swa.event_mask = ExposureMask
         | KeyPressMask
@@ -61,38 +75,35 @@ draw(int x, int y, int width, int height)
     XGetWindowAttributes(dpy, root, &wa);
 
     for (i = 0; i < 4; i++) {
-        win[i] = XCreateWindow(dpy, root, ix, iy, iw, ih, 0,
-            CopyFromParent, CopyFromParent, CopyFromParent,
-            CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
-
-        XSetClassHint(dpy, win[i], &ch);
-
-        xim = XOpenIM(dpy, NULL, NULL, NULL);
-        xic = XCreateIC(xim, XNInputStyle,
-            XIMPreeditNothing | XIMStatusNothing,
-            XNClientWindow, win[i], XNFocusWindow, win[i], NULL);
-
-        XMapRaised(dpy, win[i]);
-        XSetInputFocus(dpy, win[i], RevertToParent, CurrentTime);
-
         switch (i) {
-        // setup for right border
-        case 0:
+        case 0: // setup for left border
+            ix = x - border.left;
+            iy = y - border.top;
+            iw = border.left;
+            ih = height + border.bottom;
+            break;
+        case 1: // setup for right border
             ix += (width + border.left);
             iw = border.right;
             break;
-        // setup for top border
-        case 1:
+        case 2: // setup for top border
             ix -= (width + border.left);
             iw = (width + border.left + border.right);
             ih = border.top;
             break;
-        // setup for bottom border
-        case 2:
+        case 3: // setup for bottom border
             ih = border.bottom;
             iy += (height + border.top);
             break;
         }
+
+        win[i] = XCreateWindow(dpy, root, ix, iy, iw, ih, 0,
+            CopyFromParent, CopyFromParent, CopyFromParent,
+            CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
+
+        XSetClassHint(dpy, win[i], &ch);
+        XMapRaised(dpy, win[i]);
+        XSetInputFocus(dpy, win[i], RevertToParent, CurrentTime);
     }
 }
 
@@ -107,6 +118,7 @@ hex(const char c)
         return c - 0x61 + 10;
     else
         puts("error: cannot set color");
+    return 0;
 }
 
 void
@@ -115,29 +127,31 @@ setcolor(const char *clr)
     int i, r;
     const char *ptr;
 
-    color.flags = DoRed | DoGreen | DoBlue;
-    color_dim.flags = DoRed | DoGreen | DoBlue;
+    color[0].flags = DoRed | DoGreen | DoBlue;
+    color[1].flags = DoRed | DoGreen | DoBlue;
+
     for (i = 0; i < 3; i++) {
         ptr = clr + (1 + i * 2);
         r = (hex(ptr[0]) * 16 + hex(ptr[1])) * 256;
 
         switch (i) {
         case 0:
-            color.red = r;
-            color_dim.red = r * 0.4;
+            color[0].red = r;
+            color[1].red = r * dim_percentage;
             break;
         case 1:
-            color.green = r;
-            color_dim.green = r * 0.4;
+            color[0].green = r;
+            color[1].green = r * dim_percentage;
             break;
         case 2:
-            color.blue = r;
-            color_dim.blue = r * 0.4;
+            color[0].blue = r;
+            color[1].blue = r * dim_percentage;
             break;
         }
     }
-    XAllocColor(dpy, DefaultColormap(dpy, screen), &color);
-    XAllocColor(dpy, DefaultColormap(dpy, screen), &color_dim);
+
+    XAllocColor(dpy, DefaultColormap(dpy, screen), &color[0]);
+    XAllocColor(dpy, DefaultColormap(dpy, screen), &color[1]);
 }
 
 void
@@ -152,7 +166,7 @@ toggle()
 void
 highlight(int focus)
 {
-    unsigned long pixel = (gfocus = focus) ? color.pixel : color_dim.pixel;
+    unsigned long pixel = color[!(gfocus = focus)].pixel;
 
     for (int i = 0; i < 4; i++) {
         XSetWindowBackground(dpy, win[i], pixel);
@@ -174,13 +188,12 @@ setborders(const char *str)
 int
 main(int argc, const char *argv[])
 {
-    int width, height,
-        x, y;
+    int x, y, width, height;
 
-    border.top = 1;
-    border.right = 1;
-    border.bottom = 1;
-    border.left = 1;
+    border.top = BORDER_TOP;
+    border.right = BORDER_RIGHT;
+    border.bottom = BORDER_BOTTOM;
+    border.left = BORDER_LEFT;
 
     if (argc == 7 && argc--)
         setborders(argv[6]);
@@ -220,7 +233,7 @@ main(int argc, const char *argv[])
         XNextEvent(dpy, &ev);
         if (ev.type == Expose)
             continue;
-        else if (ev.type == KeyPress && ev.xkey.keycode == 0x09)
+        else if (ev.type == KeyPress && ev.xkey.keycode == exit_key)
             break;
         else if (ev.type == ButtonPress)
             toggle();