xgetshape

annotate 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
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@0 3 #include <X11/Xlib.h>
nuclear@0 4 #include <X11/extensions/shape.h>
nuclear@0 5 #include <GL/glx.h>
nuclear@0 6 #include "image.h"
nuclear@0 7 #include "texture.h"
nuclear@0 8
nuclear@0 9 void redraw(void);
nuclear@0 10 void reshape(int x, int y);
nuclear@0 11 int handle_event(XEvent *ev);
nuclear@0 12
nuclear@0 13 /* X helper functions */
nuclear@0 14 Window create_window(int xsz, int ysz);
nuclear@0 15 void set_window_title(Window win, const char *title);
nuclear@0 16 int get_window_shape(Window win, struct image *img);
nuclear@0 17
nuclear@0 18 Display *dpy;
nuclear@0 19 Window win;
nuclear@0 20 GLXContext ctx;
nuclear@0 21 int width, height;
nuclear@0 22 int mapped;
nuclear@0 23 int redisp_pending;
nuclear@0 24 Atom xa_wm_prot, xa_wm_del_win;
nuclear@0 25 struct image img;
nuclear@0 26 struct texture tex;
nuclear@0 27 struct texture chess_tex;
nuclear@0 28 float aspect;
nuclear@0 29
nuclear@0 30 unsigned int target_xid = 0;
nuclear@0 31
nuclear@0 32 int main(int argc, char **argv)
nuclear@0 33 {
nuclear@0 34 int event_base, error_base;
nuclear@0 35 char *endp;
nuclear@0 36 struct image chess_img;
nuclear@0 37
nuclear@0 38 if(!argv[1]) {
nuclear@0 39 fprintf(stderr, "pass the window id to use\n");
nuclear@0 40 return 1;
nuclear@0 41 }
nuclear@0 42 if(!(target_xid = strtol(argv[1], &endp, 0))) {
nuclear@0 43 fprintf(stderr, "invalid argument: %s\n", argv[1]);
nuclear@0 44 return 1;
nuclear@0 45 }
nuclear@0 46
nuclear@0 47 if(!(dpy = XOpenDisplay(0))) {
nuclear@0 48 fprintf(stderr, "failed to open display\n");
nuclear@0 49 return 1;
nuclear@0 50 }
nuclear@0 51 xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
nuclear@0 52 xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
nuclear@0 53
nuclear@0 54 if(!XShapeQueryExtension(dpy, &event_base, &error_base)) {
nuclear@0 55 fprintf(stderr, "shape extension unsupported by this X server\n");
nuclear@0 56 XCloseDisplay(dpy);
nuclear@0 57 return 1;
nuclear@0 58 }
nuclear@0 59 if(get_window_shape(target_xid, &img) == -1) {
nuclear@0 60 XCloseDisplay(dpy);
nuclear@0 61 return 1;
nuclear@0 62 }
nuclear@0 63
nuclear@0 64 if(!(win = create_window(1280, 800))) {
nuclear@0 65 return 1;
nuclear@0 66 }
nuclear@0 67
nuclear@0 68 image_texture(&tex, &img);
nuclear@0 69
nuclear@0 70 image_create(&chess_img, 256, 256);
nuclear@0 71 image_chess(&chess_img, 8, 255, 128, 64, 64, 128, 255);
nuclear@0 72 image_texture(&chess_tex, &chess_img);
nuclear@0 73 image_destroy(&chess_img);
nuclear@0 74
nuclear@0 75 for(;;) {
nuclear@0 76 XEvent ev;
nuclear@0 77 XNextEvent(dpy, &ev);
nuclear@0 78
nuclear@0 79 if(handle_event(&ev) == -1) {
nuclear@0 80 break;
nuclear@0 81 }
nuclear@0 82 }
nuclear@0 83
nuclear@0 84 XDestroyWindow(dpy, win);
nuclear@0 85 XCloseDisplay(dpy);
nuclear@0 86 return 0;
nuclear@0 87 }
nuclear@0 88
nuclear@0 89 void redraw(void)
nuclear@0 90 {
nuclear@0 91 glClearColor(0.4, 0.4, 0.4, 1);
nuclear@0 92 glClear(GL_COLOR_BUFFER_BIT);
nuclear@0 93
nuclear@0 94 glMatrixMode(GL_MODELVIEW);
nuclear@0 95 glLoadIdentity();
nuclear@0 96
nuclear@0 97 glEnable(GL_TEXTURE_2D);
nuclear@0 98 glBindTexture(GL_TEXTURE_2D, chess_tex.id);
nuclear@0 99
nuclear@0 100
nuclear@0 101 /* background */
nuclear@0 102 glBegin(GL_QUADS);
nuclear@0 103 glTexCoord2f(0, 0); glVertex2f(-aspect, -1);
nuclear@0 104 glTexCoord2f(1, 0); glVertex2f(aspect, -1);
nuclear@0 105 glTexCoord2f(1, 1); glVertex2f(aspect, 1);
nuclear@0 106 glTexCoord2f(0, 1); glVertex2f(-aspect, 1);
nuclear@0 107 glEnd();
nuclear@0 108
nuclear@0 109 /* draw the window shape */
nuclear@0 110 glEnable(GL_BLEND);
nuclear@0 111 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
nuclear@0 112
nuclear@0 113 glBindTexture(GL_TEXTURE_2D, tex.id);
nuclear@0 114 glMatrixMode(GL_TEXTURE);
nuclear@0 115 glLoadIdentity();
nuclear@0 116 glScalef((float)tex.width / (float)tex.tex_width,
nuclear@0 117 (float)tex.height / (float)tex.tex_height,
nuclear@0 118 1.0);
nuclear@0 119
nuclear@0 120 glMatrixMode(GL_MODELVIEW);
nuclear@0 121 glPushMatrix();
nuclear@0 122 glScalef(0.7, 0.7, 0.7);
nuclear@0 123
nuclear@0 124 /* shadow */
nuclear@0 125 glPushMatrix();
nuclear@0 126 glTranslatef(0.1, -0.1, 0);
nuclear@0 127 glBegin(GL_QUADS);
nuclear@0 128 glColor3f(0, 0, 0);
nuclear@0 129 glTexCoord2f(0, 1); glVertex2f(-1, -1);
nuclear@0 130 glTexCoord2f(1, 1); glVertex2f(1, -1);
nuclear@0 131 glTexCoord2f(1, 0); glVertex2f(1, 1);
nuclear@0 132 glTexCoord2f(0, 0); glVertex2f(-1, 1);
nuclear@0 133 glEnd();
nuclear@0 134 glPopMatrix();
nuclear@0 135
nuclear@0 136 /* window */
nuclear@0 137 glBegin(GL_QUADS);
nuclear@0 138 glColor3f(1, 1, 0);
nuclear@0 139 glTexCoord2f(0, 1); glVertex2f(-1, -1);
nuclear@0 140 glTexCoord2f(1, 1); glVertex2f(1, -1);
nuclear@0 141 glTexCoord2f(1, 0); glVertex2f(1, 1);
nuclear@0 142 glTexCoord2f(0, 0); glVertex2f(-1, 1);
nuclear@0 143 glEnd();
nuclear@0 144
nuclear@0 145 glMatrixMode(GL_TEXTURE);
nuclear@0 146 glLoadIdentity();
nuclear@0 147 glMatrixMode(GL_MODELVIEW);
nuclear@0 148 glPopMatrix();
nuclear@0 149
nuclear@0 150 glDisable(GL_BLEND);
nuclear@0 151
nuclear@0 152 glXSwapBuffers(dpy, win);
nuclear@0 153 }
nuclear@0 154
nuclear@0 155 void reshape(int x, int y)
nuclear@0 156 {
nuclear@0 157 aspect = (float)x / (float)y;
nuclear@0 158 glViewport(0, 0, x, y);
nuclear@0 159
nuclear@0 160 glMatrixMode(GL_PROJECTION);
nuclear@0 161 glLoadIdentity();
nuclear@0 162 glScalef(1.0 / aspect, 1.0, 1.0);
nuclear@0 163 }
nuclear@0 164
nuclear@0 165 int handle_event(XEvent *ev)
nuclear@0 166 {
nuclear@0 167 switch(ev->type) {
nuclear@0 168 case MapNotify:
nuclear@0 169 case UnmapNotify:
nuclear@0 170 mapped = ev->type == MapNotify ? 1 : 0;
nuclear@0 171 break;
nuclear@0 172
nuclear@0 173 case Expose:
nuclear@0 174 if(mapped && ev->xexpose.count == 0) {
nuclear@0 175 redraw();
nuclear@0 176 }
nuclear@0 177 break;
nuclear@0 178
nuclear@0 179 case KeyPress:
nuclear@0 180 {
nuclear@0 181 KeySym sym = XLookupKeysym(&ev->xkey, 0);
nuclear@0 182
nuclear@0 183 switch(sym) {
nuclear@0 184 case XK_Escape:
nuclear@0 185 return -1;
nuclear@0 186 }
nuclear@0 187 }
nuclear@0 188 break;
nuclear@0 189
nuclear@0 190 case ConfigureNotify:
nuclear@0 191 if(ev->xconfigure.width != width || ev->xconfigure.height != height) {
nuclear@0 192 width = ev->xconfigure.width;
nuclear@0 193 height = ev->xconfigure.height;
nuclear@0 194 reshape(width, height);
nuclear@0 195 }
nuclear@0 196 break;
nuclear@0 197
nuclear@0 198 case ClientMessage:
nuclear@0 199 if(ev->xclient.message_type == xa_wm_prot) {
nuclear@0 200 if(ev->xclient.data.l[0] == xa_wm_del_win) {
nuclear@0 201 return -1;
nuclear@0 202 }
nuclear@0 203 }
nuclear@0 204 break;
nuclear@0 205 }
nuclear@0 206 return 0;
nuclear@0 207 }
nuclear@0 208
nuclear@0 209 Window create_window(int xsz, int ysz)
nuclear@0 210 {
nuclear@0 211 Window w, root;
nuclear@0 212 XVisualInfo *vis;
nuclear@0 213 XClassHint chint;
nuclear@0 214 XSetWindowAttributes xattr;
nuclear@0 215 unsigned int evmask, xattr_mask;
nuclear@0 216 int scr;
nuclear@0 217 int glxattr[] = {
nuclear@0 218 GLX_RGBA, GLX_DOUBLEBUFFER,
nuclear@0 219 GLX_RED_SIZE, 8,
nuclear@0 220 GLX_GREEN_SIZE, 8,
nuclear@0 221 GLX_BLUE_SIZE, 8,
nuclear@0 222 GLX_DEPTH_SIZE, 24,
nuclear@0 223 GLX_USE_GL, 1,
nuclear@0 224 None
nuclear@0 225 };
nuclear@0 226
nuclear@0 227 scr = DefaultScreen(dpy);
nuclear@0 228 root = RootWindow(dpy, scr);
nuclear@0 229
nuclear@0 230 if(!(vis = glXChooseVisual(dpy, scr, glxattr))) {
nuclear@0 231 printf("failed to find a suitable visual\n");
nuclear@0 232 return 0;
nuclear@0 233 }
nuclear@0 234 if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
nuclear@0 235 XFree(vis);
nuclear@0 236 return 0;
nuclear@0 237 }
nuclear@0 238
nuclear@0 239 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
nuclear@0 240 xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
nuclear@0 241 xattr_mask = CWColormap | CWBackPixel | CWBorderPixel;
nuclear@0 242
nuclear@0 243 if(!(w = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
nuclear@0 244 vis->visual, xattr_mask, &xattr))) {
nuclear@0 245 printf("failed to create window\n");
nuclear@0 246 glXDestroyContext(dpy, ctx);
nuclear@0 247 XFree(vis);
nuclear@0 248 return 0;
nuclear@0 249 }
nuclear@0 250 XFree(vis);
nuclear@0 251
nuclear@0 252 evmask = StructureNotifyMask | VisibilityChangeMask | KeyPressMask |
nuclear@0 253 ExposureMask;
nuclear@0 254 XSelectInput(dpy, w, evmask);
nuclear@0 255
nuclear@0 256 XSetWMProtocols(dpy, w, &xa_wm_del_win, 1);
nuclear@0 257
nuclear@0 258 chint.res_name = chint.res_class = "xgetshape";
nuclear@0 259 XSetClassHint(dpy, w, &chint);
nuclear@0 260
nuclear@0 261 set_window_title(w, "GL xgetshape");
nuclear@0 262
nuclear@0 263 glXMakeCurrent(dpy, w, ctx);
nuclear@0 264 XMapWindow(dpy, w);
nuclear@0 265 return w;
nuclear@0 266 }
nuclear@0 267
nuclear@0 268 void set_window_title(Window win, const char *title)
nuclear@0 269 {
nuclear@0 270 XTextProperty wm_name;
nuclear@0 271 XStringListToTextProperty((char**)&title, 1, &wm_name);
nuclear@0 272 XSetWMName(dpy, win, &wm_name);
nuclear@0 273 XSetWMIconName(dpy, win, &wm_name);
nuclear@0 274 XFree(wm_name.value);
nuclear@0 275 }
nuclear@0 276
nuclear@0 277 int get_window_shape(Window win, struct image *img)
nuclear@0 278 {
nuclear@0 279 Bool buse, cuse;
nuclear@0 280 int bx, by, cx, cy;
nuclear@0 281 unsigned int bw, bh, cw, ch;
nuclear@0 282 int kind;
nuclear@0 283 int x, y, w, h;
nuclear@0 284 XRectangle *rects;
nuclear@0 285 int i, rect_count, rect_order;
nuclear@0 286
nuclear@0 287 XShapeQueryExtents(dpy, win, &buse, &bx, &by, &bw, &bh,
nuclear@0 288 &cuse, &cx, &cy, &bw, &bh);
nuclear@0 289 if(cuse) {
nuclear@0 290 x = cx;
nuclear@0 291 y = cy;
nuclear@0 292 w = cw;
nuclear@0 293 h = ch;
nuclear@0 294 kind = ShapeClip;
nuclear@0 295 } else if(buse) {
nuclear@0 296 x = bx;
nuclear@0 297 y = by;
nuclear@0 298 w = bw;
nuclear@0 299 h = bh;
nuclear@0 300 kind = ShapeBounding;
nuclear@0 301 } else {
nuclear@0 302 fprintf(stderr, "XShapeQueryExtents returned no extents\n");
nuclear@0 303 return -1;
nuclear@0 304 }
nuclear@0 305
nuclear@0 306 if(image_create(img, w, h) == -1) {
nuclear@0 307 fprintf(stderr, "failed to create shape image (%dx%d)\n", w, h);
nuclear@0 308 return -1;
nuclear@0 309 }
nuclear@0 310 image_clear(img, 0, 0, 0, 0);
nuclear@0 311
nuclear@0 312 if(!(rects = XShapeGetRectangles(dpy, win, kind, &rect_count, &rect_order))) {
nuclear@0 313 fprintf(stderr, "failed to get the shape rectangles\n");
nuclear@0 314 image_destroy(img);
nuclear@0 315 return -1;
nuclear@0 316 }
nuclear@0 317
nuclear@0 318 for(i=0; i<rect_count; i++) {
nuclear@0 319 image_fillrect(img, rects[i].x, rects[i].y, rects[i].width, rects[i].height,
nuclear@0 320 255, 255, 255, 255);
nuclear@0 321 }
nuclear@0 322 return 0;
nuclear@0 323 }