xgetshape
changeset 0:2f02f100b20f
getting the window shape of another window
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 03 Nov 2015 00:42:08 +0200 |
parents | |
children | 9b560415bad4 |
files | .hgignore Makefile src/image.c src/image.h src/main.c src/texture.c src/texture.h |
diffstat | 7 files changed, 527 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Tue Nov 03 00:42:08 2015 +0200 1.3 @@ -0,0 +1,5 @@ 1.4 +\.o$ 1.5 +\.swp$ 1.6 +\.d$ 1.7 +\.ppm$ 1.8 +^xgetshape$
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/Makefile Tue Nov 03 00:42:08 2015 +0200 2.3 @@ -0,0 +1,13 @@ 2.4 +src = $(wildcard src/*.c) 2.5 +obj = $(src:.c=.o) 2.6 +bin = xgetshape 2.7 + 2.8 +CFLAGS = -pedantic -Wall -g 2.9 +LDFLAGS = -lGL -lX11 -lXext 2.10 + 2.11 +$(bin): $(obj) 2.12 + $(CC) -o $@ $(obj) $(LDFLAGS) 2.13 + 2.14 +.PHONY: clean 2.15 +clean: 2.16 + rm -f $(obj) $(bin)
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/image.c Tue Nov 03 00:42:08 2015 +0200 3.3 @@ -0,0 +1,122 @@ 3.4 +#include <stdio.h> 3.5 +#include <stdlib.h> 3.6 +#include <string.h> 3.7 +#include <errno.h> 3.8 +#include "image.h" 3.9 + 3.10 +int image_create(struct image *img, int w, int h) 3.11 +{ 3.12 + img->width = w; 3.13 + img->height = h; 3.14 + if(!(img->pixels = malloc(w * h * 4))) { 3.15 + return -1; 3.16 + } 3.17 + return 0; 3.18 +} 3.19 + 3.20 +void image_destroy(struct image *img) 3.21 +{ 3.22 + free(img->pixels); 3.23 + img->pixels = 0; 3.24 +} 3.25 + 3.26 +int image_save(struct image *img, const char *rgbname, const char *aname) 3.27 +{ 3.28 + int i; 3.29 + FILE *fp; 3.30 + unsigned char *pptr; 3.31 + 3.32 + if(rgbname) { 3.33 + if(!(fp = fopen(rgbname, "wb"))) { 3.34 + fprintf(stderr, "failed to open %s for writing: %s\n", rgbname, strerror(errno)); 3.35 + return -1; 3.36 + } 3.37 + 3.38 + fprintf(fp, "P6\n%d %d\n255\n", img->width, img->height); 3.39 + pptr = img->pixels; 3.40 + for(i=0; i<img->width * img->height; i++) { 3.41 + fputc(*pptr++, fp); 3.42 + fputc(*pptr++, fp); 3.43 + fputc(*pptr++, fp); 3.44 + ++pptr; 3.45 + } 3.46 + fclose(fp); 3.47 + } 3.48 + if(aname) { 3.49 + if(!(fp = fopen(aname, "wb"))) { 3.50 + fprintf(stderr, "failed to open %s for writing: %s\n", rgbname, strerror(errno)); 3.51 + return -1; 3.52 + } 3.53 + 3.54 + fprintf(fp, "P6\n%d %d\n255\n", img->width, img->height); 3.55 + pptr = img->pixels; 3.56 + for(i=0; i<img->width * img->height; i++) { 3.57 + int c = pptr[3]; 3.58 + pptr += 4; 3.59 + fputc(c, fp); 3.60 + fputc(c, fp); 3.61 + fputc(c, fp); 3.62 + } 3.63 + fclose(fp); 3.64 + } 3.65 + return 0; 3.66 +} 3.67 + 3.68 +int image_clear(struct image *img, int r, int g, int b, int a) 3.69 +{ 3.70 + return image_fillrect(img, 0, 0, img->width, img->height, r, g, b, a); 3.71 +} 3.72 + 3.73 +int image_fillrect(struct image *img, int x, int y, int w, int h, int r, int g, int b, int a) 3.74 +{ 3.75 + int i, j; 3.76 + unsigned char *pptr; 3.77 + 3.78 + if(x < 0) { 3.79 + w += x; 3.80 + x = 0; 3.81 + } 3.82 + if(y < 0) { 3.83 + h += y; 3.84 + y = 0; 3.85 + } 3.86 + if(x + w >= img->width) { 3.87 + w = img->width - x; 3.88 + } 3.89 + if(y + h >= img->height) { 3.90 + h = img->height - y; 3.91 + } 3.92 + if(w <= 0 || h <= 0) { 3.93 + return -1; 3.94 + } 3.95 + 3.96 + pptr = img->pixels + (y * img->width + x) * 4; 3.97 + for(i=0; i<h; i++) { 3.98 + for(j=0; j<w; j++) { 3.99 + pptr[0] = r; 3.100 + pptr[1] = g; 3.101 + pptr[2] = b; 3.102 + pptr[3] = a; 3.103 + pptr += 4; 3.104 + } 3.105 + pptr += (img->width - w) * 4; 3.106 + } 3.107 + return 0; 3.108 +} 3.109 + 3.110 +int image_chess(struct image *img, int sz, int r0, int g0, int b0, int r1, int g1, int b1) 3.111 +{ 3.112 + int i, j; 3.113 + unsigned char *pptr = img->pixels; 3.114 + 3.115 + for(i=0; i<img->height; i++) { 3.116 + for(j=0; j<img->width; j++) { 3.117 + int chess = ((i / sz) & 1) == ((j / sz) & 1); 3.118 + *pptr++ = chess ? r0 : r1; 3.119 + *pptr++ = chess ? g0 : g1; 3.120 + *pptr++ = chess ? b0 : b1; 3.121 + *pptr++ = 255; 3.122 + } 3.123 + } 3.124 + return 0; 3.125 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/image.h Tue Nov 03 00:42:08 2015 +0200 4.3 @@ -0,0 +1,18 @@ 4.4 +#ifndef IMAGE_H_ 4.5 +#define IMAGE_H_ 4.6 + 4.7 +struct image { 4.8 + int width, height; 4.9 + unsigned char *pixels; 4.10 +}; 4.11 + 4.12 +int image_create(struct image *img, int w, int h); 4.13 +void image_destroy(struct image *img); 4.14 + 4.15 +int image_save(struct image *img, const char *rgbname, const char *aname); 4.16 + 4.17 +int image_clear(struct image *img, int r, int g, int b, int a); 4.18 +int image_fillrect(struct image *img, int x, int y, int w, int h, int r, int g, int b, int a); 4.19 +int image_chess(struct image *img, int sz, int r0, int g0, int b0, int r1, int g1, int b1); 4.20 + 4.21 +#endif /* IMAGE_H_ */
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/main.c Tue Nov 03 00:42:08 2015 +0200 5.3 @@ -0,0 +1,323 @@ 5.4 +#include <stdio.h> 5.5 +#include <stdlib.h> 5.6 +#include <X11/Xlib.h> 5.7 +#include <X11/extensions/shape.h> 5.8 +#include <GL/glx.h> 5.9 +#include "image.h" 5.10 +#include "texture.h" 5.11 + 5.12 +void redraw(void); 5.13 +void reshape(int x, int y); 5.14 +int handle_event(XEvent *ev); 5.15 + 5.16 +/* X helper functions */ 5.17 +Window create_window(int xsz, int ysz); 5.18 +void set_window_title(Window win, const char *title); 5.19 +int get_window_shape(Window win, struct image *img); 5.20 + 5.21 +Display *dpy; 5.22 +Window win; 5.23 +GLXContext ctx; 5.24 +int width, height; 5.25 +int mapped; 5.26 +int redisp_pending; 5.27 +Atom xa_wm_prot, xa_wm_del_win; 5.28 +struct image img; 5.29 +struct texture tex; 5.30 +struct texture chess_tex; 5.31 +float aspect; 5.32 + 5.33 +unsigned int target_xid = 0; 5.34 + 5.35 +int main(int argc, char **argv) 5.36 +{ 5.37 + int event_base, error_base; 5.38 + char *endp; 5.39 + struct image chess_img; 5.40 + 5.41 + if(!argv[1]) { 5.42 + fprintf(stderr, "pass the window id to use\n"); 5.43 + return 1; 5.44 + } 5.45 + if(!(target_xid = strtol(argv[1], &endp, 0))) { 5.46 + fprintf(stderr, "invalid argument: %s\n", argv[1]); 5.47 + return 1; 5.48 + } 5.49 + 5.50 + if(!(dpy = XOpenDisplay(0))) { 5.51 + fprintf(stderr, "failed to open display\n"); 5.52 + return 1; 5.53 + } 5.54 + xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False); 5.55 + xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 5.56 + 5.57 + if(!XShapeQueryExtension(dpy, &event_base, &error_base)) { 5.58 + fprintf(stderr, "shape extension unsupported by this X server\n"); 5.59 + XCloseDisplay(dpy); 5.60 + return 1; 5.61 + } 5.62 + if(get_window_shape(target_xid, &img) == -1) { 5.63 + XCloseDisplay(dpy); 5.64 + return 1; 5.65 + } 5.66 + 5.67 + if(!(win = create_window(1280, 800))) { 5.68 + return 1; 5.69 + } 5.70 + 5.71 + image_texture(&tex, &img); 5.72 + 5.73 + image_create(&chess_img, 256, 256); 5.74 + image_chess(&chess_img, 8, 255, 128, 64, 64, 128, 255); 5.75 + image_texture(&chess_tex, &chess_img); 5.76 + image_destroy(&chess_img); 5.77 + 5.78 + for(;;) { 5.79 + XEvent ev; 5.80 + XNextEvent(dpy, &ev); 5.81 + 5.82 + if(handle_event(&ev) == -1) { 5.83 + break; 5.84 + } 5.85 + } 5.86 + 5.87 + XDestroyWindow(dpy, win); 5.88 + XCloseDisplay(dpy); 5.89 + return 0; 5.90 +} 5.91 + 5.92 +void redraw(void) 5.93 +{ 5.94 + glClearColor(0.4, 0.4, 0.4, 1); 5.95 + glClear(GL_COLOR_BUFFER_BIT); 5.96 + 5.97 + glMatrixMode(GL_MODELVIEW); 5.98 + glLoadIdentity(); 5.99 + 5.100 + glEnable(GL_TEXTURE_2D); 5.101 + glBindTexture(GL_TEXTURE_2D, chess_tex.id); 5.102 + 5.103 + 5.104 + /* background */ 5.105 + glBegin(GL_QUADS); 5.106 + glTexCoord2f(0, 0); glVertex2f(-aspect, -1); 5.107 + glTexCoord2f(1, 0); glVertex2f(aspect, -1); 5.108 + glTexCoord2f(1, 1); glVertex2f(aspect, 1); 5.109 + glTexCoord2f(0, 1); glVertex2f(-aspect, 1); 5.110 + glEnd(); 5.111 + 5.112 + /* draw the window shape */ 5.113 + glEnable(GL_BLEND); 5.114 + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 5.115 + 5.116 + glBindTexture(GL_TEXTURE_2D, tex.id); 5.117 + glMatrixMode(GL_TEXTURE); 5.118 + glLoadIdentity(); 5.119 + glScalef((float)tex.width / (float)tex.tex_width, 5.120 + (float)tex.height / (float)tex.tex_height, 5.121 + 1.0); 5.122 + 5.123 + glMatrixMode(GL_MODELVIEW); 5.124 + glPushMatrix(); 5.125 + glScalef(0.7, 0.7, 0.7); 5.126 + 5.127 + /* shadow */ 5.128 + glPushMatrix(); 5.129 + glTranslatef(0.1, -0.1, 0); 5.130 + glBegin(GL_QUADS); 5.131 + glColor3f(0, 0, 0); 5.132 + glTexCoord2f(0, 1); glVertex2f(-1, -1); 5.133 + glTexCoord2f(1, 1); glVertex2f(1, -1); 5.134 + glTexCoord2f(1, 0); glVertex2f(1, 1); 5.135 + glTexCoord2f(0, 0); glVertex2f(-1, 1); 5.136 + glEnd(); 5.137 + glPopMatrix(); 5.138 + 5.139 + /* window */ 5.140 + glBegin(GL_QUADS); 5.141 + glColor3f(1, 1, 0); 5.142 + glTexCoord2f(0, 1); glVertex2f(-1, -1); 5.143 + glTexCoord2f(1, 1); glVertex2f(1, -1); 5.144 + glTexCoord2f(1, 0); glVertex2f(1, 1); 5.145 + glTexCoord2f(0, 0); glVertex2f(-1, 1); 5.146 + glEnd(); 5.147 + 5.148 + glMatrixMode(GL_TEXTURE); 5.149 + glLoadIdentity(); 5.150 + glMatrixMode(GL_MODELVIEW); 5.151 + glPopMatrix(); 5.152 + 5.153 + glDisable(GL_BLEND); 5.154 + 5.155 + glXSwapBuffers(dpy, win); 5.156 +} 5.157 + 5.158 +void reshape(int x, int y) 5.159 +{ 5.160 + aspect = (float)x / (float)y; 5.161 + glViewport(0, 0, x, y); 5.162 + 5.163 + glMatrixMode(GL_PROJECTION); 5.164 + glLoadIdentity(); 5.165 + glScalef(1.0 / aspect, 1.0, 1.0); 5.166 +} 5.167 + 5.168 +int handle_event(XEvent *ev) 5.169 +{ 5.170 + switch(ev->type) { 5.171 + case MapNotify: 5.172 + case UnmapNotify: 5.173 + mapped = ev->type == MapNotify ? 1 : 0; 5.174 + break; 5.175 + 5.176 + case Expose: 5.177 + if(mapped && ev->xexpose.count == 0) { 5.178 + redraw(); 5.179 + } 5.180 + break; 5.181 + 5.182 + case KeyPress: 5.183 + { 5.184 + KeySym sym = XLookupKeysym(&ev->xkey, 0); 5.185 + 5.186 + switch(sym) { 5.187 + case XK_Escape: 5.188 + return -1; 5.189 + } 5.190 + } 5.191 + break; 5.192 + 5.193 + case ConfigureNotify: 5.194 + if(ev->xconfigure.width != width || ev->xconfigure.height != height) { 5.195 + width = ev->xconfigure.width; 5.196 + height = ev->xconfigure.height; 5.197 + reshape(width, height); 5.198 + } 5.199 + break; 5.200 + 5.201 + case ClientMessage: 5.202 + if(ev->xclient.message_type == xa_wm_prot) { 5.203 + if(ev->xclient.data.l[0] == xa_wm_del_win) { 5.204 + return -1; 5.205 + } 5.206 + } 5.207 + break; 5.208 + } 5.209 + return 0; 5.210 +} 5.211 + 5.212 +Window create_window(int xsz, int ysz) 5.213 +{ 5.214 + Window w, root; 5.215 + XVisualInfo *vis; 5.216 + XClassHint chint; 5.217 + XSetWindowAttributes xattr; 5.218 + unsigned int evmask, xattr_mask; 5.219 + int scr; 5.220 + int glxattr[] = { 5.221 + GLX_RGBA, GLX_DOUBLEBUFFER, 5.222 + GLX_RED_SIZE, 8, 5.223 + GLX_GREEN_SIZE, 8, 5.224 + GLX_BLUE_SIZE, 8, 5.225 + GLX_DEPTH_SIZE, 24, 5.226 + GLX_USE_GL, 1, 5.227 + None 5.228 + }; 5.229 + 5.230 + scr = DefaultScreen(dpy); 5.231 + root = RootWindow(dpy, scr); 5.232 + 5.233 + if(!(vis = glXChooseVisual(dpy, scr, glxattr))) { 5.234 + printf("failed to find a suitable visual\n"); 5.235 + return 0; 5.236 + } 5.237 + if(!(ctx = glXCreateContext(dpy, vis, 0, True))) { 5.238 + XFree(vis); 5.239 + return 0; 5.240 + } 5.241 + 5.242 + xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr); 5.243 + xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone); 5.244 + xattr_mask = CWColormap | CWBackPixel | CWBorderPixel; 5.245 + 5.246 + if(!(w = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput, 5.247 + vis->visual, xattr_mask, &xattr))) { 5.248 + printf("failed to create window\n"); 5.249 + glXDestroyContext(dpy, ctx); 5.250 + XFree(vis); 5.251 + return 0; 5.252 + } 5.253 + XFree(vis); 5.254 + 5.255 + evmask = StructureNotifyMask | VisibilityChangeMask | KeyPressMask | 5.256 + ExposureMask; 5.257 + XSelectInput(dpy, w, evmask); 5.258 + 5.259 + XSetWMProtocols(dpy, w, &xa_wm_del_win, 1); 5.260 + 5.261 + chint.res_name = chint.res_class = "xgetshape"; 5.262 + XSetClassHint(dpy, w, &chint); 5.263 + 5.264 + set_window_title(w, "GL xgetshape"); 5.265 + 5.266 + glXMakeCurrent(dpy, w, ctx); 5.267 + XMapWindow(dpy, w); 5.268 + return w; 5.269 +} 5.270 + 5.271 +void set_window_title(Window win, const char *title) 5.272 +{ 5.273 + XTextProperty wm_name; 5.274 + XStringListToTextProperty((char**)&title, 1, &wm_name); 5.275 + XSetWMName(dpy, win, &wm_name); 5.276 + XSetWMIconName(dpy, win, &wm_name); 5.277 + XFree(wm_name.value); 5.278 +} 5.279 + 5.280 +int get_window_shape(Window win, struct image *img) 5.281 +{ 5.282 + Bool buse, cuse; 5.283 + int bx, by, cx, cy; 5.284 + unsigned int bw, bh, cw, ch; 5.285 + int kind; 5.286 + int x, y, w, h; 5.287 + XRectangle *rects; 5.288 + int i, rect_count, rect_order; 5.289 + 5.290 + XShapeQueryExtents(dpy, win, &buse, &bx, &by, &bw, &bh, 5.291 + &cuse, &cx, &cy, &bw, &bh); 5.292 + if(cuse) { 5.293 + x = cx; 5.294 + y = cy; 5.295 + w = cw; 5.296 + h = ch; 5.297 + kind = ShapeClip; 5.298 + } else if(buse) { 5.299 + x = bx; 5.300 + y = by; 5.301 + w = bw; 5.302 + h = bh; 5.303 + kind = ShapeBounding; 5.304 + } else { 5.305 + fprintf(stderr, "XShapeQueryExtents returned no extents\n"); 5.306 + return -1; 5.307 + } 5.308 + 5.309 + if(image_create(img, w, h) == -1) { 5.310 + fprintf(stderr, "failed to create shape image (%dx%d)\n", w, h); 5.311 + return -1; 5.312 + } 5.313 + image_clear(img, 0, 0, 0, 0); 5.314 + 5.315 + if(!(rects = XShapeGetRectangles(dpy, win, kind, &rect_count, &rect_order))) { 5.316 + fprintf(stderr, "failed to get the shape rectangles\n"); 5.317 + image_destroy(img); 5.318 + return -1; 5.319 + } 5.320 + 5.321 + for(i=0; i<rect_count; i++) { 5.322 + image_fillrect(img, rects[i].x, rects[i].y, rects[i].width, rects[i].height, 5.323 + 255, 255, 255, 255); 5.324 + } 5.325 + return 0; 5.326 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/texture.c Tue Nov 03 00:42:08 2015 +0200 6.3 @@ -0,0 +1,33 @@ 6.4 +#include <GL/gl.h> 6.5 +#include "texture.h" 6.6 + 6.7 +static int next_pow2(int x); 6.8 + 6.9 +int image_texture(struct texture *tex, struct image *img) 6.10 +{ 6.11 + glGenTextures(1, &tex->id); 6.12 + glBindTexture(GL_TEXTURE_2D, tex->id); 6.13 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 6.14 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 6.15 + 6.16 + tex->width = img->width; 6.17 + tex->height = img->height; 6.18 + tex->tex_width = next_pow2(tex->width); 6.19 + tex->tex_height = next_pow2(tex->height); 6.20 + 6.21 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->tex_width, tex->tex_height, 0, 6.22 + GL_RGBA, GL_UNSIGNED_BYTE, 0); 6.23 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex->width, tex->height, 6.24 + GL_RGBA, GL_UNSIGNED_BYTE, img->pixels); 6.25 + return 0; 6.26 +} 6.27 + 6.28 +static int next_pow2(int x) 6.29 +{ 6.30 + --x; 6.31 + x |= x >> 1; 6.32 + x |= x >> 2; 6.33 + x |= x >> 4; 6.34 + x |= x >> 8; 6.35 + return x + 1; 6.36 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/texture.h Tue Nov 03 00:42:08 2015 +0200 7.3 @@ -0,0 +1,13 @@ 7.4 +#ifndef TEXTURE_H_ 7.5 +#define TEXTURE_H_ 7.6 + 7.7 +#include "image.h" 7.8 + 7.9 +struct texture { 7.10 + unsigned int id; 7.11 + int width, height, tex_width, tex_height; 7.12 +}; 7.13 + 7.14 +int image_texture(struct texture *tex, struct image *img); 7.15 + 7.16 +#endif /* TEXTURE_H_ */