This is the beginning of a simple X11/Xlib paint program. I got most of this code from an online source and started to modify it. But since I'm new to X11, I thought I'd ask before I add on to bad code.
#include <X11/X.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/XKBlib.h> #include <X11/Xatom.h> #include <X11/Xft/Xft.h> #include <stdio.h> #include <stdlib.h> #include <err.h> #define POSX 500 #define POSY 500 #define WIDTH 750 #define HEIGHT 500 #define BORDER 5 #define LINE 4 #define HX_BLUE "#0000ff" #define HX_GREEN "#00ff00" #define HX_RED "#ff0000" #define HX_YELLOW "#ffff00" #define HX_PINK "#ff00ff" #define HX_CYAN "#00ffff" #define HX_WHITE "#ffffff" #define HX_BLACK "#000000" #define HX_ORANGE "#ff8040" #define HX_GRAY "#c0c0c0" #define HX_DARKGRAY "#808080" #define HX_BROWN "#804000" #define CHILD_W 25 #define CHILD_H 25 #define CHILD_B 0 typedef XftColor Clr; typedef struct { Window win; Clr *color; } ColorButtons; static Display *dpy; static int scr; static Window root; static Visual *vis; static const char *colors[] = {HX_BLUE, HX_GREEN, HX_RED, HX_YELLOW, HX_PINK, HX_CYAN, HX_WHITE, HX_BLACK, HX_ORANGE, HX_GRAY, HX_DARKGRAY, HX_BROWN}; #define NUM_COLORS (int)(sizeof(colors) / sizeof(colors[0])) static ColorButtons color_buttons[NUM_COLORS]; static Window create_win(int x, int y, int w, int h, int b, Window* parent, int idx) { Window win; XSetWindowAttributes xwa = { .background_pixel = WhitePixel(dpy, scr), .border_pixel = BlackPixel(dpy, scr), }; if (parent == NULL) { xwa.event_mask = Button1MotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask; win = XCreateWindow(dpy, root, x, y, w, h, b, DefaultDepth(dpy, scr), InputOutput, vis, CWBackPixel | CWBorderPixel | CWEventMask, &xwa); } else { xwa.event_mask = ButtonPress; xwa.background_pixel = color_buttons[idx].color->pixel; xwa.border_pixel = WhitePixel(dpy, scr); win = XCreateWindow(dpy, *parent, x, y, w, h, b, DefaultDepth(dpy, scr), InputOutput, vis, CWBackPixel | CWBorderPixel | CWEventMask, &xwa); } return win; } static GC create_gc(int line_width) { GC gc; XGCValues xgcv; unsigned long valuemask; xgcv.line_style = LineSolid; xgcv.line_width = line_width; xgcv.cap_style = CapButt; xgcv.join_style = JoinMiter; xgcv.fill_style = FillSolid; xgcv.foreground = BlackPixel(dpy, scr); xgcv.background = WhitePixel(dpy, scr); valuemask = GCForeground | GCBackground | GCFillStyle | GCLineStyle | GCLineWidth | GCCapStyle | GCJoinStyle; gc = XCreateGC(dpy, root, valuemask, &xgcv); return gc; } static void run(GC gc) { XEvent ev; Window cur_win; int init = 0; int prev_x = 0, prev_y = 0; while (!(XNextEvent(dpy, &ev))) { switch (ev.type) { case ButtonPress: if (ev.xbutton.button == Button1) { cur_win = ev.xbutton.window; int flag = 0; for (int i = 0; i < NUM_COLORS; i++) { if (cur_win == color_buttons[i].win) { XSetForeground(dpy, gc, color_buttons[i].color->pixel); flag = 1; break; } } if (!flag) XDrawPoint(dpy, ev.xbutton.window, gc, ev.xbutton.x, ev.xbutton.y); } else if (ev.xbutton.button == Button3) XSetForeground(dpy, gc, BlackPixel(dpy, scr)); break; case MotionNotify: if (init) { XDrawLine(dpy, ev.xbutton.window, gc, prev_x, prev_y, ev.xbutton.x, ev.xbutton.y); } else { XDrawPoint(dpy, ev.xbutton.window, gc, ev.xbutton.x, ev.xbutton.y); init = 1; } prev_x = ev.xbutton.x, prev_y = ev.xbutton.y; break; case ButtonRelease: init = 0; break; case KeyPress: if (XkbKeycodeToKeysym(dpy, ev.xkey.keycode, 0, 0) == XK_q) return; } } } int main() { Window main_win; GC gc; int x = 200; int y = HEIGHT - (2 * (CHILD_H + CHILD_B)); if (!(dpy = XOpenDisplay(NULL))) errx(1, "Can't open display"); scr = DefaultScreen(dpy); root = RootWindow(dpy, scr); vis = DefaultVisual(dpy, scr); main_win = create_win(POSX, POSY, WIDTH, HEIGHT, BORDER, NULL, 0); for (int i = 0; i < NUM_COLORS; i++) { color_buttons[i].color = malloc(sizeof(Clr)); if (!color_buttons[i].color) errx(1, "Can't allocate memory for color"); if (!XftColorAllocName(dpy, vis, DefaultColormap(dpy, scr), colors[i], color_buttons[i].color)) errx(1, "Can't allocate xft color"); color_buttons[i].color->pixel |= 0xff << 24; color_buttons[i].win = create_win(x, y, CHILD_W, CHILD_H, CHILD_B, &main_win, i); if (i == (NUM_COLORS/2)-1) { y += CHILD_H + CHILD_B; x = 200; } else { x += CHILD_W + CHILD_B; } } gc = create_gc(LINE); XSizeHints xsh = {.min_width = WIDTH, .min_height = HEIGHT, .max_width = WIDTH, .max_height = HEIGHT}; xsh.flags = PMinSize | PMaxSize; XSetSizeHints(dpy, main_win, &xsh, XA_WM_NORMAL_HINTS); XStoreName(dpy, main_win, "Simple Paint"); XMapWindow(dpy, main_win); XMapSubwindows(dpy, main_win); run(gc); /* cleanup */ XUnmapWindow(dpy, main_win); XUnmapSubwindows(dpy, main_win); XDestroySubwindows(dpy, main_win); XDestroyWindow(dpy, main_win); XFreeGC(dpy, gc); for (int i = 0; i < NUM_COLORS; i++) XftColorFree(dpy, vis, DefaultColormap(dpy, scr), color_buttons[i].color); XCloseDisplay(dpy); return 0; } And here is the Makefile:
PROG = paint SRC = ${PROG}.c OBJ = ${SRC:.c=.o} CC = cc INCS = -I/usr/include/X11 `pkg-config --cflags xft` LIBS = -lX11 -lXft LDFLAGS = ${LIBS} CFLAGS = -Wall -Wextra -O0 ${INCS} all: ${PROG} ${PROG}: ${OBJ} ${CC} -o $@ ${OBJ} ${LDFLAGS} %.o: %.c ${CC} -c $< ${CFLAGS} clean: -rm ${OBJ} ${PROG} .PHONY: all clean