setxbg

X11 background image
git clone https://git.porkepik.fr/setxbg
Log | Files | Refs | README | LICENSE

setxbg.c (5582B)


      1 #include <err.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 
      6 #include <X11/Xatom.h>
      7 #include <X11/Xlib.h>
      8 #include <X11/Xutil.h>
      9 
     10 #define STB_IMAGE_IMPLEMENTATION
     11 #include "stb_image.h"
     12 
     13 #define STB_IMAGE_RESIZE_IMPLEMENTATION
     14 #include "stb_image_resize.h"
     15 
     16 
     17 #define RGBA 4
     18 
     19 
     20 enum modes {
     21 	BG_CENTER,
     22 	BG_FILL,
     23 	BG_MAX
     24 };
     25 
     26 struct image {
     27 	int width;
     28 	int height;
     29 	int src_x;
     30 	int src_y;
     31 	int dest_x;
     32 	int dest_y;
     33 	unsigned char *data;
     34 	enum modes bg_mode;
     35 	char *bg_color;
     36 };
     37 
     38 
     39 static void
     40 usage(void)
     41 {
     42 	printf("Usage: setxbg [--bg-center | --bg-fill | --bg-max] "
     43 	    "[--bg-color \"#ffffff\"] [FILE]\n");
     44 	exit(0);
     45 }
     46 
     47 static void
     48 check_args(int argc, char **argv, struct image *img)
     49 {
     50 	for (int i = 1; i <= argc - 1; i++) {
     51 		if (strcmp(argv[i], "--bg-fill") == 0)
     52 			img->bg_mode = BG_FILL;
     53 		else if (strcmp(argv[i], "--bg-max") == 0)
     54 			img->bg_mode = BG_MAX;
     55 		else if (strcmp(argv[i], "--bg-center") == 0)
     56 			img->bg_mode = BG_CENTER;
     57 		else if (strcmp(argv[i], "--bg-color") == 0 && i+1 != argc)
     58 			img->bg_color = argv[i+1];
     59 		else if (strcmp(argv[i], "-h") == 0)
     60 			usage();
     61 	}
     62 }
     63 
     64 static void
     65 rgb_to_bgr(struct image img)
     66 {
     67 	unsigned char red, blue;
     68 
     69 	for (long i = 0; i < img.width * img.height * RGBA; i += RGBA) {
     70 		red = img.data[i+2];
     71 		blue = img.data[i];
     72 		img.data[i] = red;
     73 		img.data[i+2] = blue;
     74 	}
     75 }
     76 
     77 static unsigned char *
     78 resize(struct image img, int new_w, int new_h)
     79 {
     80 	unsigned char *new_data;
     81 
     82 	if (new_w != img.width || new_h != img.height) {
     83 		new_data = malloc(new_h * new_w * RGBA);
     84 		stbir_resize_uint8(img.data, img.width, img.height, 0,
     85 		    new_data, new_w, new_h, 0, RGBA);
     86 		free(img.data);
     87 	} else {
     88 		new_data = img.data;
     89 	}
     90 
     91 	return new_data;
     92 }
     93 
     94 static void
     95 set_dimensions(struct image *img, int screen_w, int screen_h)
     96 {
     97 	int scaled_w, scaled_h, new_w, new_h;
     98 
     99 	scaled_w = (float)screen_h * ((float)img->width / (float)img->height);
    100 	scaled_h = (float)screen_w / ((float)img->width / (float)img->height);
    101 
    102 	if ((img->bg_mode == BG_FILL && scaled_w < screen_w) ||
    103 	    (img->bg_mode == BG_MAX && scaled_h <= screen_h)) {
    104 		new_w = screen_w;
    105 		new_h = scaled_h;
    106 	} else {
    107 		new_w = scaled_w;
    108 		new_h = screen_h;
    109 	}
    110 
    111 	if (img->bg_mode != BG_CENTER) {
    112 		img->data = resize(*img, new_w, new_h);
    113 		img->width = new_w;
    114 		img->height = new_h;
    115 	}
    116 
    117 	if (img->bg_mode == BG_FILL) {
    118 		img->src_x = (img->width - screen_w)/2;
    119 		img->src_y = (img->height - screen_h)/2;
    120 	} else if (img->bg_mode == BG_MAX || img->bg_mode == BG_CENTER) {
    121 		img->dest_x = (screen_w - img->width)/2;
    122 		img->dest_y = (screen_h - img->height)/2;
    123 	}
    124 }
    125 
    126 static void
    127 forget_old_background(Display *disp, Window root)
    128 {
    129 	Atom prop, prop_esetroot, type;
    130 	int format;
    131 	unsigned long length, after;
    132 	unsigned char *data_root = NULL, *data_esetroot = NULL;
    133 
    134 	prop = XInternAtom(disp, "_XROOTPMAP_ID", True);
    135 	prop_esetroot = XInternAtom(disp, "ESETROOT_PMAP_ID", True);
    136 	if (prop == None || prop_esetroot == None)
    137 		return;
    138 
    139 	XGetWindowProperty(disp, root, prop, 0L, 1L, False, AnyPropertyType,
    140 	    &type, &format, &length, &after, &data_root);
    141 
    142 	if (type == XA_PIXMAP) {
    143 		XGetWindowProperty(disp, root, prop_esetroot, 0L, 1L, False,
    144 		    AnyPropertyType, &type, &format, &length, &after,
    145 		    &data_esetroot);
    146 		if (type == XA_PIXMAP && data_root == data_esetroot)
    147 			XKillClient(disp, *data_root);
    148 	}
    149 
    150 	if (data_root)
    151 		XFree(data_root);
    152 	if (data_esetroot)
    153 		XFree(data_esetroot);
    154 }
    155 
    156 static void
    157 apply_background(Display *disp, struct image img, int screen_w, int screen_h)
    158 {
    159 	XImage *ximg;
    160 	Window root;
    161 	int depth;
    162 	Pixmap pixmap;
    163 	Colormap cmap;
    164 	XColor color;
    165 	XGCValues gcval;
    166 	GC gc;
    167 	Atom prop_root;
    168 
    169 	root = DefaultRootWindow(disp);
    170 	forget_old_background(disp, root);
    171 
    172 	depth = DefaultDepth(disp, 0);
    173 	pixmap = XCreatePixmap(disp, root, screen_w, screen_h, depth);
    174 
    175 	prop_root = XInternAtom(disp, "_XROOTPMAP_ID", False);
    176 	if (prop_root == None)
    177 		errx(1, "Creation of _XSETROOT_ID atom failed.");
    178 	XChangeProperty(disp, root, prop_root, XA_PIXMAP, 32, PropModeReplace,
    179 	    (unsigned char *)&pixmap, 1);
    180 	XSetCloseDownMode(disp, RetainPermanent);
    181 
    182 	cmap = DefaultColormap(disp, DefaultScreen(disp));
    183 	if (img.bg_color == NULL)
    184 		XAllocNamedColor(disp, cmap, "black", &color, &color);
    185 	else
    186 		XAllocNamedColor(disp, cmap, img.bg_color, &color, &color);
    187 	gcval.foreground = color.pixel;
    188 	gc = XCreateGC(disp, root, GCForeground, &gcval);
    189 	XFillRectangle(disp, pixmap, gc, 0, 0, screen_w, screen_h);
    190 
    191 	ximg = XCreateImage(disp, DefaultVisual(disp, 0), 24, ZPixmap, 0,
    192 	    (char *)img.data, img.width, img.height, 8, 0);
    193 	XPutImage(disp, pixmap, DefaultGC(disp, 0), ximg, img.src_x, img.src_y,
    194 	    img.dest_x, img.dest_y, img.width, img.height);
    195 	XSetWindowBackgroundPixmap(disp, root, pixmap);
    196 	XClearWindow(disp, root);
    197 
    198 	XFreePixmap(disp, pixmap);
    199 	XFreeGC(disp, gc);
    200 	XDestroyImage(ximg);
    201 }
    202 
    203 int
    204 main(int argc, char **argv)
    205 {
    206 	Display *disp;
    207 	int screen_w, screen_h;
    208 	struct image img;
    209 
    210 	img.src_x = 0;
    211 	img.src_y = 0;
    212 	img.dest_x = 0;
    213 	img.dest_y = 0;
    214 	img.bg_mode = BG_MAX;
    215 	img.bg_color = NULL;
    216 
    217 	disp = XOpenDisplay(NULL);
    218 	if (disp == NULL)
    219 		errx(1, "Failed opening DISPLAY.");
    220 
    221 	if (argc < 2)
    222 		usage();
    223 	check_args(argc, argv, &img);
    224 
    225 	img.data = stbi_load(argv[argc-1], &img.width, &img.height, NULL, RGBA);
    226 	if (img.data == NULL)
    227 		errx(1, "Error during image loading.");
    228 	rgb_to_bgr(img);
    229 
    230 	screen_w = WidthOfScreen(DefaultScreenOfDisplay(disp));
    231 	screen_h = HeightOfScreen(DefaultScreenOfDisplay(disp));
    232 	set_dimensions(&img, screen_w, screen_h);
    233 	apply_background(disp, img, screen_w, screen_h);
    234 
    235 	XCloseDisplay(disp);
    236 
    237 	return 0;
    238 }