xgetshape
diff src/main.c @ 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/main.c Tue Nov 03 00:42:08 2015 +0200 1.3 @@ -0,0 +1,323 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <X11/Xlib.h> 1.7 +#include <X11/extensions/shape.h> 1.8 +#include <GL/glx.h> 1.9 +#include "image.h" 1.10 +#include "texture.h" 1.11 + 1.12 +void redraw(void); 1.13 +void reshape(int x, int y); 1.14 +int handle_event(XEvent *ev); 1.15 + 1.16 +/* X helper functions */ 1.17 +Window create_window(int xsz, int ysz); 1.18 +void set_window_title(Window win, const char *title); 1.19 +int get_window_shape(Window win, struct image *img); 1.20 + 1.21 +Display *dpy; 1.22 +Window win; 1.23 +GLXContext ctx; 1.24 +int width, height; 1.25 +int mapped; 1.26 +int redisp_pending; 1.27 +Atom xa_wm_prot, xa_wm_del_win; 1.28 +struct image img; 1.29 +struct texture tex; 1.30 +struct texture chess_tex; 1.31 +float aspect; 1.32 + 1.33 +unsigned int target_xid = 0; 1.34 + 1.35 +int main(int argc, char **argv) 1.36 +{ 1.37 + int event_base, error_base; 1.38 + char *endp; 1.39 + struct image chess_img; 1.40 + 1.41 + if(!argv[1]) { 1.42 + fprintf(stderr, "pass the window id to use\n"); 1.43 + return 1; 1.44 + } 1.45 + if(!(target_xid = strtol(argv[1], &endp, 0))) { 1.46 + fprintf(stderr, "invalid argument: %s\n", argv[1]); 1.47 + return 1; 1.48 + } 1.49 + 1.50 + if(!(dpy = XOpenDisplay(0))) { 1.51 + fprintf(stderr, "failed to open display\n"); 1.52 + return 1; 1.53 + } 1.54 + xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False); 1.55 + xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 1.56 + 1.57 + if(!XShapeQueryExtension(dpy, &event_base, &error_base)) { 1.58 + fprintf(stderr, "shape extension unsupported by this X server\n"); 1.59 + XCloseDisplay(dpy); 1.60 + return 1; 1.61 + } 1.62 + if(get_window_shape(target_xid, &img) == -1) { 1.63 + XCloseDisplay(dpy); 1.64 + return 1; 1.65 + } 1.66 + 1.67 + if(!(win = create_window(1280, 800))) { 1.68 + return 1; 1.69 + } 1.70 + 1.71 + image_texture(&tex, &img); 1.72 + 1.73 + image_create(&chess_img, 256, 256); 1.74 + image_chess(&chess_img, 8, 255, 128, 64, 64, 128, 255); 1.75 + image_texture(&chess_tex, &chess_img); 1.76 + image_destroy(&chess_img); 1.77 + 1.78 + for(;;) { 1.79 + XEvent ev; 1.80 + XNextEvent(dpy, &ev); 1.81 + 1.82 + if(handle_event(&ev) == -1) { 1.83 + break; 1.84 + } 1.85 + } 1.86 + 1.87 + XDestroyWindow(dpy, win); 1.88 + XCloseDisplay(dpy); 1.89 + return 0; 1.90 +} 1.91 + 1.92 +void redraw(void) 1.93 +{ 1.94 + glClearColor(0.4, 0.4, 0.4, 1); 1.95 + glClear(GL_COLOR_BUFFER_BIT); 1.96 + 1.97 + glMatrixMode(GL_MODELVIEW); 1.98 + glLoadIdentity(); 1.99 + 1.100 + glEnable(GL_TEXTURE_2D); 1.101 + glBindTexture(GL_TEXTURE_2D, chess_tex.id); 1.102 + 1.103 + 1.104 + /* background */ 1.105 + glBegin(GL_QUADS); 1.106 + glTexCoord2f(0, 0); glVertex2f(-aspect, -1); 1.107 + glTexCoord2f(1, 0); glVertex2f(aspect, -1); 1.108 + glTexCoord2f(1, 1); glVertex2f(aspect, 1); 1.109 + glTexCoord2f(0, 1); glVertex2f(-aspect, 1); 1.110 + glEnd(); 1.111 + 1.112 + /* draw the window shape */ 1.113 + glEnable(GL_BLEND); 1.114 + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 1.115 + 1.116 + glBindTexture(GL_TEXTURE_2D, tex.id); 1.117 + glMatrixMode(GL_TEXTURE); 1.118 + glLoadIdentity(); 1.119 + glScalef((float)tex.width / (float)tex.tex_width, 1.120 + (float)tex.height / (float)tex.tex_height, 1.121 + 1.0); 1.122 + 1.123 + glMatrixMode(GL_MODELVIEW); 1.124 + glPushMatrix(); 1.125 + glScalef(0.7, 0.7, 0.7); 1.126 + 1.127 + /* shadow */ 1.128 + glPushMatrix(); 1.129 + glTranslatef(0.1, -0.1, 0); 1.130 + glBegin(GL_QUADS); 1.131 + glColor3f(0, 0, 0); 1.132 + glTexCoord2f(0, 1); glVertex2f(-1, -1); 1.133 + glTexCoord2f(1, 1); glVertex2f(1, -1); 1.134 + glTexCoord2f(1, 0); glVertex2f(1, 1); 1.135 + glTexCoord2f(0, 0); glVertex2f(-1, 1); 1.136 + glEnd(); 1.137 + glPopMatrix(); 1.138 + 1.139 + /* window */ 1.140 + glBegin(GL_QUADS); 1.141 + glColor3f(1, 1, 0); 1.142 + glTexCoord2f(0, 1); glVertex2f(-1, -1); 1.143 + glTexCoord2f(1, 1); glVertex2f(1, -1); 1.144 + glTexCoord2f(1, 0); glVertex2f(1, 1); 1.145 + glTexCoord2f(0, 0); glVertex2f(-1, 1); 1.146 + glEnd(); 1.147 + 1.148 + glMatrixMode(GL_TEXTURE); 1.149 + glLoadIdentity(); 1.150 + glMatrixMode(GL_MODELVIEW); 1.151 + glPopMatrix(); 1.152 + 1.153 + glDisable(GL_BLEND); 1.154 + 1.155 + glXSwapBuffers(dpy, win); 1.156 +} 1.157 + 1.158 +void reshape(int x, int y) 1.159 +{ 1.160 + aspect = (float)x / (float)y; 1.161 + glViewport(0, 0, x, y); 1.162 + 1.163 + glMatrixMode(GL_PROJECTION); 1.164 + glLoadIdentity(); 1.165 + glScalef(1.0 / aspect, 1.0, 1.0); 1.166 +} 1.167 + 1.168 +int handle_event(XEvent *ev) 1.169 +{ 1.170 + switch(ev->type) { 1.171 + case MapNotify: 1.172 + case UnmapNotify: 1.173 + mapped = ev->type == MapNotify ? 1 : 0; 1.174 + break; 1.175 + 1.176 + case Expose: 1.177 + if(mapped && ev->xexpose.count == 0) { 1.178 + redraw(); 1.179 + } 1.180 + break; 1.181 + 1.182 + case KeyPress: 1.183 + { 1.184 + KeySym sym = XLookupKeysym(&ev->xkey, 0); 1.185 + 1.186 + switch(sym) { 1.187 + case XK_Escape: 1.188 + return -1; 1.189 + } 1.190 + } 1.191 + break; 1.192 + 1.193 + case ConfigureNotify: 1.194 + if(ev->xconfigure.width != width || ev->xconfigure.height != height) { 1.195 + width = ev->xconfigure.width; 1.196 + height = ev->xconfigure.height; 1.197 + reshape(width, height); 1.198 + } 1.199 + break; 1.200 + 1.201 + case ClientMessage: 1.202 + if(ev->xclient.message_type == xa_wm_prot) { 1.203 + if(ev->xclient.data.l[0] == xa_wm_del_win) { 1.204 + return -1; 1.205 + } 1.206 + } 1.207 + break; 1.208 + } 1.209 + return 0; 1.210 +} 1.211 + 1.212 +Window create_window(int xsz, int ysz) 1.213 +{ 1.214 + Window w, root; 1.215 + XVisualInfo *vis; 1.216 + XClassHint chint; 1.217 + XSetWindowAttributes xattr; 1.218 + unsigned int evmask, xattr_mask; 1.219 + int scr; 1.220 + int glxattr[] = { 1.221 + GLX_RGBA, GLX_DOUBLEBUFFER, 1.222 + GLX_RED_SIZE, 8, 1.223 + GLX_GREEN_SIZE, 8, 1.224 + GLX_BLUE_SIZE, 8, 1.225 + GLX_DEPTH_SIZE, 24, 1.226 + GLX_USE_GL, 1, 1.227 + None 1.228 + }; 1.229 + 1.230 + scr = DefaultScreen(dpy); 1.231 + root = RootWindow(dpy, scr); 1.232 + 1.233 + if(!(vis = glXChooseVisual(dpy, scr, glxattr))) { 1.234 + printf("failed to find a suitable visual\n"); 1.235 + return 0; 1.236 + } 1.237 + if(!(ctx = glXCreateContext(dpy, vis, 0, True))) { 1.238 + XFree(vis); 1.239 + return 0; 1.240 + } 1.241 + 1.242 + xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr); 1.243 + xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone); 1.244 + xattr_mask = CWColormap | CWBackPixel | CWBorderPixel; 1.245 + 1.246 + if(!(w = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput, 1.247 + vis->visual, xattr_mask, &xattr))) { 1.248 + printf("failed to create window\n"); 1.249 + glXDestroyContext(dpy, ctx); 1.250 + XFree(vis); 1.251 + return 0; 1.252 + } 1.253 + XFree(vis); 1.254 + 1.255 + evmask = StructureNotifyMask | VisibilityChangeMask | KeyPressMask | 1.256 + ExposureMask; 1.257 + XSelectInput(dpy, w, evmask); 1.258 + 1.259 + XSetWMProtocols(dpy, w, &xa_wm_del_win, 1); 1.260 + 1.261 + chint.res_name = chint.res_class = "xgetshape"; 1.262 + XSetClassHint(dpy, w, &chint); 1.263 + 1.264 + set_window_title(w, "GL xgetshape"); 1.265 + 1.266 + glXMakeCurrent(dpy, w, ctx); 1.267 + XMapWindow(dpy, w); 1.268 + return w; 1.269 +} 1.270 + 1.271 +void set_window_title(Window win, const char *title) 1.272 +{ 1.273 + XTextProperty wm_name; 1.274 + XStringListToTextProperty((char**)&title, 1, &wm_name); 1.275 + XSetWMName(dpy, win, &wm_name); 1.276 + XSetWMIconName(dpy, win, &wm_name); 1.277 + XFree(wm_name.value); 1.278 +} 1.279 + 1.280 +int get_window_shape(Window win, struct image *img) 1.281 +{ 1.282 + Bool buse, cuse; 1.283 + int bx, by, cx, cy; 1.284 + unsigned int bw, bh, cw, ch; 1.285 + int kind; 1.286 + int x, y, w, h; 1.287 + XRectangle *rects; 1.288 + int i, rect_count, rect_order; 1.289 + 1.290 + XShapeQueryExtents(dpy, win, &buse, &bx, &by, &bw, &bh, 1.291 + &cuse, &cx, &cy, &bw, &bh); 1.292 + if(cuse) { 1.293 + x = cx; 1.294 + y = cy; 1.295 + w = cw; 1.296 + h = ch; 1.297 + kind = ShapeClip; 1.298 + } else if(buse) { 1.299 + x = bx; 1.300 + y = by; 1.301 + w = bw; 1.302 + h = bh; 1.303 + kind = ShapeBounding; 1.304 + } else { 1.305 + fprintf(stderr, "XShapeQueryExtents returned no extents\n"); 1.306 + return -1; 1.307 + } 1.308 + 1.309 + if(image_create(img, w, h) == -1) { 1.310 + fprintf(stderr, "failed to create shape image (%dx%d)\n", w, h); 1.311 + return -1; 1.312 + } 1.313 + image_clear(img, 0, 0, 0, 0); 1.314 + 1.315 + if(!(rects = XShapeGetRectangles(dpy, win, kind, &rect_count, &rect_order))) { 1.316 + fprintf(stderr, "failed to get the shape rectangles\n"); 1.317 + image_destroy(img); 1.318 + return -1; 1.319 + } 1.320 + 1.321 + for(i=0; i<rect_count; i++) { 1.322 + image_fillrect(img, rects[i].x, rects[i].y, rects[i].width, rects[i].height, 1.323 + 255, 255, 255, 255); 1.324 + } 1.325 + return 0; 1.326 +}