commit 3ede808ab86004aac28b768a9374331e1acea523
parent cae73b002271e0bf90f4e88c396e06c0dafab1b4
Author: Louis Burda <quent.burda@gmail.com>
Date: Thu, 20 Oct 2022 23:57:06 +0200
Add option for transparency and un-/regrabbing
Diffstat:
M | overdraw.c | | | 228 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
1 file changed, 161 insertions(+), 67 deletions(-)
diff --git a/overdraw.c b/overdraw.c
@@ -1,3 +1,4 @@
+#include <X11/X.h>
#include <cairo/cairo.h>
#include <cairo/cairo-xlib.h>
#include <X11/Xlib.h>
@@ -7,6 +8,7 @@
#include <X11/cursorfont.h>
#include <err.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -24,21 +26,16 @@ struct line {
struct rgb color;
};
-static void add_line(cairo_path_t *path, struct rgb *color);
-static void clear_background(void);
-static void draw_color_mark(void);
-static void draw_lines(void);
-
static struct rgb colors[3];
static int color_index;
-static XImage *image;
-
XWindowAttributes scr;
static Display *display;
static Screen *screen;
static Window root, win;
-static GC gc;
+static bool grabbed;
+static bool done;
+static bool draw;
static cairo_surface_t *cs;
static cairo_t *cr;
@@ -46,6 +43,8 @@ static cairo_t *cr;
static struct line *lines;
static int lines_cnt, lines_cap;
+static bool transparent;
+
void
add_line(cairo_path_t *path, struct rgb *color)
{
@@ -62,12 +61,6 @@ add_line(cairo_path_t *path, struct rgb *color)
}
void
-clear_background(void)
-{
- XClearWindow(display, win);
-}
-
-void
draw_color_mark(void)
{
struct rgb *c;
@@ -82,6 +75,20 @@ draw_color_mark(void)
}
void
+update_pixmap(void)
+{
+ Pixmap pix;
+ GC gc;
+
+ pix = XCreatePixmap(display, win,
+ scr.width, scr.height, scr.depth);
+ gc = XCreateGC(display, win, 0, 0);
+ XCopyArea(display, win, pix, gc, 0, 0,
+ scr.width, scr.height, 0, 0);
+ XSetWindowBackgroundPixmap(display, win, pix);
+}
+
+void
draw_lines(void)
{
int i;
@@ -98,42 +105,120 @@ draw_lines(void)
}
void
-init(void)
+grab(void)
{
Cursor cursor;
+
+ cursor = XCreateFontCursor(display, XC_pencil);
+ XGrabPointer(display, root, False,
+ ButtonMotionMask | ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync, root, cursor, CurrentTime);
+ XGrabKeyboard(display, root, False, GrabModeAsync,
+ GrabModeAsync, CurrentTime);
+ grabbed = true;
+}
+
+void
+ungrab(void)
+{
+ XUngrabKeyboard(display, CurrentTime);
+ XUngrabPointer(display, CurrentTime);
+ XGrabKey(display, XKeysymToKeycode(display, XK_Escape), Mod1Mask,
+ root, False, GrabModeAsync, GrabModeAsync);
+ grabbed = false;
+}
+
+void
+redraw(void)
+{
+ if (transparent) {
+ cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
+ cairo_rectangle(cr, 0, 0, scr.width, scr.height);
+ cairo_fill(cr);
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ } else {
+ XClearWindow(display, win);
+ }
+
+ draw_color_mark();
+ draw_lines();
+ XFlush(display);
+}
+
+void
+keypress(XEvent ev)
+{
+ int keysym;
+
+ keysym = XkbKeycodeToKeysym(display, ev.xkey.keycode, 0,
+ ev.xkey.state & ShiftMask ? 1 : 0);
+ switch (keysym) {
+ case XK_Escape:
+ if (!ev.xkey.state) {
+ done = true;
+ } else if ((ev.xkey.state & Mod1Mask)) {
+ if (grabbed) {
+ ungrab();
+ if (!transparent) {
+ XUnmapWindow(display, win);
+ }
+ } else {
+ if (!transparent) {
+ XMapWindow(display, win);
+ update_pixmap();
+ redraw();
+ }
+ grab();
+ }
+ }
+ break;
+ case ' ':
+ color_index = (color_index + 1) % ARRLEN(colors);
+ draw_color_mark();
+ break;
+ }
+}
+
+void
+init(void)
+{
XSetWindowAttributes swa;
XGCValues gcvals;
+ XVisualInfo vinfo;
Visual *visual;
+ int depth;
display = XOpenDisplay(NULL);
root = DefaultRootWindow(display);
+ screen = XDefaultScreenOfDisplay(display);
XGetWindowAttributes(display, root, &scr);
+ if (transparent) {
+ XMatchVisualInfo(display, DefaultScreen(display),
+ 32, TrueColor, &vinfo);
+ visual = vinfo.visual;
+ depth = vinfo.depth;
+ } else {
+ visual = XDefaultVisualOfScreen(screen);
+ depth = CopyFromParent;
+ }
+
+ swa.border_pixel = 0;
swa.override_redirect = 1;
+ swa.event_mask = ExposureMask;
+ swa.colormap = XCreateColormap(display, root, visual, AllocNone);
win = XCreateWindow(display, root, scr.x, scr.y, scr.width, scr.height,
- 0, CopyFromParent, InputOutput, CopyFromParent,
- CWOverrideRedirect, &swa);
+ 0, depth, InputOutput, visual, CWOverrideRedirect
+ | CWBorderPixel | CWColormap | CWEventMask, &swa);
if (!win) err(1, "XCreateWindow");
XMapWindow(display, win);
- image = XGetImage(display, win, scr.x, scr.y, scr.width, scr.height,
- AllPlanes, ZPixmap);
- if (!image) err(1, "XGetImage");
-
- gcvals = (XGCValues) { 0 };
- gcvals.subwindow_mode = IncludeInferiors;
- gcvals.line_width = 2;
- gc = XCreateGC(display, win, GCSubwindowMode | GCLineWidth, &gcvals);
-
- screen = XDefaultScreenOfDisplay(display);
- visual = XDefaultVisualOfScreen(screen);
-
- Pixmap pix = XCreatePixmap(display, win, scr.width, scr.height, scr.depth);
- XCopyArea(display, win, pix, gc, 0, 0, scr.width, scr.height, 0, 0);
- XSetWindowBackgroundPixmap(display, win, pix);
+ if (!transparent)
+ update_pixmap();
- cs = cairo_xlib_surface_create(display, win, visual, scr.width, scr.height);
+ cs = cairo_xlib_surface_create(display,
+ win, visual, scr.width, scr.height);
cr = cairo_create(cs);
cairo_surface_flush(cs);
@@ -146,53 +231,28 @@ init(void)
colors[2] = (struct rgb) { 0.0, 0.0, 0.0 };
color_index = 0;
- cursor = XCreateFontCursor(display, XC_pencil);
-
- XGrabPointer(display, root, False,
- ButtonMotionMask | ButtonPressMask | ButtonReleaseMask,
- GrabModeAsync, GrabModeAsync, root, cursor, CurrentTime);
-
- XGrabKeyboard(display, root, False, GrabModeAsync,
- GrabModeAsync, CurrentTime);
-
lines_cap = 10;
lines = calloc(lines_cap, sizeof(struct line));
if (!lines) exit(1);
lines_cnt = 0;
- draw_color_mark();
- XFlush(display);
+ grab();
}
-int
-main(int argc, char *argv[])
+void
+update(void)
{
int px, py, x, y;
struct rgb color;
cairo_path_t *path;
- int done, draw;
- int keysym;
XEvent ev;
- init();
-
done = 0;
while (!done) {
- if (!XPending(display)) continue;
XNextEvent(display, &ev);
switch (ev.type) {
case KeyPress:
- keysym = XkbKeycodeToKeysym(display, ev.xkey.keycode, 0,
- ev.xkey.state & ShiftMask ? 1 : 0);
- switch (keysym) {
- case XK_Escape:
- done = 1;
- break;
- case ' ':
- color_index = (color_index + 1) % ARRLEN(colors);
- draw_color_mark();
- break;
- }
+ keypress(ev);
break;
case MotionNotify:
if (!draw) break;
@@ -201,6 +261,14 @@ main(int argc, char *argv[])
cairo_move_to(cr, ev.xmotion.x, ev.xmotion.y);
cairo_stroke_preserve(cr);
cairo_surface_flush(cs);
+ path = cairo_copy_path(cr);
+ if (path->num_data > 500) {
+ add_line(path, &color);
+ cairo_new_path(cr);
+ cairo_line_to(cr, ev.xmotion.x, ev.xmotion.y);
+ } else {
+ cairo_path_destroy(path);
+ }
XFlush(display);
break;
case ButtonPress:
@@ -214,17 +282,43 @@ main(int argc, char *argv[])
path = cairo_copy_path(cr);
add_line(path, &color);
- clear_background();
- draw_color_mark();
- draw_lines();
-
- XFlush(display);
+ redraw();
+ break;
+ case Expose:
+ redraw();
break;
}
}
+}
+void
+deinit(void)
+{
cairo_surface_destroy(cs);
XDestroyWindow(display, win);
XCloseDisplay(display);
+
+ free(lines);
+}
+
+int
+main(int argc, const char **argv)
+{
+ const char **arg;
+
+ transparent = false;
+ for (arg = &argv[1]; *arg; arg++) {
+ if (!strcmp(*arg, "-t")) {
+ transparent = true;
+ } else {
+ errx(1, "Unknown arg: %s", *arg);
+ }
+ }
+
+ init();
+
+ update();
+
+ deinit();
}