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
pkg-configin your makefile, you might as well use it for all your libraries. You’re both compiling with the headers (--cflags) and linking to the libraries (--libs). You also probably want to use XLib-XCB or just XCB. (Although this requires some changes to the source code.) So something like$(pkg-config --cflags --libs xlib-xcb xcb-util xcb-xkb xcb-atom xft)Alternatively, maybe--cflags --libs x11 xft. \$\endgroup\$