xgetshape

changeset 1:9b560415bad4

blured shadow
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 03 Nov 2015 04:08:32 +0200
parents 2f02f100b20f
children b832d3b3ed98
files src/main.c src/texture.c src/texture.h
diffstat 3 files changed, 165 insertions(+), 63 deletions(-) [+]
line diff
     1.1 --- a/src/main.c	Tue Nov 03 00:42:08 2015 +0200
     1.2 +++ b/src/main.c	Tue Nov 03 04:08:32 2015 +0200
     1.3 @@ -1,6 +1,7 @@
     1.4  #include <stdio.h>
     1.5  #include <stdlib.h>
     1.6  #include <X11/Xlib.h>
     1.7 +#include <X11/cursorfont.h>
     1.8  #include <X11/extensions/shape.h>
     1.9  #include <GL/glx.h>
    1.10  #include "image.h"
    1.11 @@ -14,6 +15,7 @@
    1.12  Window create_window(int xsz, int ysz);
    1.13  void set_window_title(Window win, const char *title);
    1.14  int get_window_shape(Window win, struct image *img);
    1.15 +XID get_window_id(Display *dpy, int screen, int button);
    1.16  
    1.17  Display *dpy;
    1.18  Window win;
    1.19 @@ -26,6 +28,8 @@
    1.20  struct texture tex;
    1.21  struct texture chess_tex;
    1.22  float aspect;
    1.23 +int sel_active;
    1.24 +Cursor sel_cursor;
    1.25  
    1.26  unsigned int target_xid = 0;
    1.27  
    1.28 @@ -35,11 +39,7 @@
    1.29  	char *endp;
    1.30  	struct image chess_img;
    1.31  
    1.32 -	if(!argv[1]) {
    1.33 -		fprintf(stderr, "pass the window id to use\n");
    1.34 -		return 1;
    1.35 -	}
    1.36 -	if(!(target_xid = strtol(argv[1], &endp, 0))) {
    1.37 +	if(argv[1] && !(target_xid = strtol(argv[1], &endp, 0))) {
    1.38  		fprintf(stderr, "invalid argument: %s\n", argv[1]);
    1.39  		return 1;
    1.40  	}
    1.41 @@ -51,36 +51,53 @@
    1.42  	xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
    1.43  	xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
    1.44  
    1.45 +	sel_cursor = XCreateFontCursor(dpy, XC_crosshair);
    1.46 +
    1.47  	if(!XShapeQueryExtension(dpy, &event_base, &error_base)) {
    1.48  		fprintf(stderr, "shape extension unsupported by this X server\n");
    1.49  		XCloseDisplay(dpy);
    1.50  		return 1;
    1.51  	}
    1.52 -	if(get_window_shape(target_xid, &img) == -1) {
    1.53 -		XCloseDisplay(dpy);
    1.54 +
    1.55 +	if(!target_xid) {
    1.56 +		target_xid = get_window_id(dpy, 0, Button1);
    1.57 +	}
    1.58 +	if(target_xid) {
    1.59 +		image_destroy(&img);
    1.60 +		if(get_window_shape(target_xid, &img) == -1) {
    1.61 +			destroy_texture(&tex);
    1.62 +		}
    1.63 +	}
    1.64 +
    1.65 +	if(!(win = create_window(800 * (float)img.width / (float)img.height, 800))) {
    1.66  		return 1;
    1.67  	}
    1.68 -
    1.69 -	if(!(win = create_window(1280, 800))) {
    1.70 -		return 1;
    1.71 +	if(img.pixels) {
    1.72 +		image_texture(&tex, &img);
    1.73  	}
    1.74  
    1.75 -	image_texture(&tex, &img);
    1.76 -
    1.77  	image_create(&chess_img, 256, 256);
    1.78 -	image_chess(&chess_img, 8, 255, 128, 64, 64, 128, 255);
    1.79 +	image_chess(&chess_img, 8, 192, 100, 64, 64, 100, 192);
    1.80  	image_texture(&chess_tex, &chess_img);
    1.81  	image_destroy(&chess_img);
    1.82  
    1.83  	for(;;) {
    1.84  		XEvent ev;
    1.85 -		XNextEvent(dpy, &ev);
    1.86  
    1.87 -		if(handle_event(&ev) == -1) {
    1.88 -			break;
    1.89 +		do {
    1.90 +			XNextEvent(dpy, &ev);
    1.91 +			if(handle_event(&ev) == -1) {
    1.92 +				goto quit;
    1.93 +			}
    1.94 +		} while(XPending(dpy));
    1.95 +
    1.96 +		if(redisp_pending) {
    1.97 +			redisp_pending = 0;
    1.98 +			redraw();
    1.99  		}
   1.100  	}
   1.101  
   1.102 +quit:
   1.103  	XDestroyWindow(dpy, win);
   1.104  	XCloseDisplay(dpy);
   1.105  	return 0;
   1.106 @@ -100,54 +117,67 @@
   1.107  
   1.108  	/* background */
   1.109  	glBegin(GL_QUADS);
   1.110 +	glColor3f(1, 1, 1);
   1.111  	glTexCoord2f(0, 0); glVertex2f(-aspect, -1);
   1.112 -	glTexCoord2f(1, 0); glVertex2f(aspect, -1);
   1.113 -	glTexCoord2f(1, 1); glVertex2f(aspect, 1);
   1.114 +	glTexCoord2f(aspect, 0); glVertex2f(aspect, -1);
   1.115 +	glTexCoord2f(aspect, 1); glVertex2f(aspect, 1);
   1.116  	glTexCoord2f(0, 1); glVertex2f(-aspect, 1);
   1.117  	glEnd();
   1.118  
   1.119 -	/* draw the window shape */
   1.120 -	glEnable(GL_BLEND);
   1.121 -	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   1.122 +	if(tex.id) {
   1.123 +		int i, ssamples = 64;
   1.124 +		float ssample_weight = 1.0 / (float)ssamples;
   1.125 +		float shadow_spread = 0.05;
   1.126 +		float img_aspect = (float)tex.width / (float)tex.height;
   1.127  
   1.128 -	glBindTexture(GL_TEXTURE_2D, tex.id);
   1.129 -	glMatrixMode(GL_TEXTURE);
   1.130 -	glLoadIdentity();
   1.131 -	glScalef((float)tex.width / (float)tex.tex_width,
   1.132 -			(float)tex.height / (float)tex.tex_height,
   1.133 -			1.0);
   1.134 +		/* draw the window shape */
   1.135 +		glEnable(GL_BLEND);
   1.136 +		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   1.137  
   1.138 -	glMatrixMode(GL_MODELVIEW);
   1.139 -	glPushMatrix();
   1.140 -	glScalef(0.7, 0.7, 0.7);
   1.141 +		glBindTexture(GL_TEXTURE_2D, tex.id);
   1.142 +		glMatrixMode(GL_TEXTURE);
   1.143 +		glLoadIdentity();
   1.144 +		glScalef((float)tex.width / (float)tex.tex_width,
   1.145 +				(float)tex.height / (float)tex.tex_height,
   1.146 +				1.0);
   1.147  
   1.148 -	/* shadow */
   1.149 -	glPushMatrix();
   1.150 -	glTranslatef(0.1, -0.1, 0);
   1.151 -	glBegin(GL_QUADS);
   1.152 -	glColor3f(0, 0, 0);
   1.153 -	glTexCoord2f(0, 1); glVertex2f(-1, -1);
   1.154 -	glTexCoord2f(1, 1); glVertex2f(1, -1);
   1.155 -	glTexCoord2f(1, 0); glVertex2f(1, 1);
   1.156 -	glTexCoord2f(0, 0); glVertex2f(-1, 1);
   1.157 -	glEnd();
   1.158 -	glPopMatrix();
   1.159 +		glMatrixMode(GL_MODELVIEW);
   1.160 +		glPushMatrix();
   1.161 +		glScalef(0.9 * img_aspect, 0.9, 0.9);
   1.162  
   1.163 -	/* window */
   1.164 -	glBegin(GL_QUADS);
   1.165 -	glColor3f(1, 1, 0);
   1.166 -	glTexCoord2f(0, 1); glVertex2f(-1, -1);
   1.167 -	glTexCoord2f(1, 1); glVertex2f(1, -1);
   1.168 -	glTexCoord2f(1, 0); glVertex2f(1, 1);
   1.169 -	glTexCoord2f(0, 0); glVertex2f(-1, 1);
   1.170 -	glEnd();
   1.171 +		/* shadow */
   1.172 +		for(i=0; i<ssamples; i++) {
   1.173 +			float xoffs = shadow_spread * ((float)rand() / (float)RAND_MAX - 0.5f);
   1.174 +			float yoffs = shadow_spread * ((float)rand() / (float)RAND_MAX - 0.5f);
   1.175  
   1.176 -	glMatrixMode(GL_TEXTURE);
   1.177 -	glLoadIdentity();
   1.178 -	glMatrixMode(GL_MODELVIEW);
   1.179 -	glPopMatrix();
   1.180 +			glPushMatrix();
   1.181 +			glTranslatef(0.075 + xoffs, -0.075 + yoffs, 0);
   1.182 +			glBegin(GL_QUADS);
   1.183 +			glColor4f(0, 0, 0, ssample_weight);
   1.184 +			glTexCoord2f(0, 1); glVertex2f(-1, -1);
   1.185 +			glTexCoord2f(1, 1); glVertex2f(1, -1);
   1.186 +			glTexCoord2f(1, 0); glVertex2f(1, 1);
   1.187 +			glTexCoord2f(0, 0); glVertex2f(-1, 1);
   1.188 +			glEnd();
   1.189 +			glPopMatrix();
   1.190 +		}
   1.191  
   1.192 -	glDisable(GL_BLEND);
   1.193 +		/* window */
   1.194 +		glBegin(GL_QUADS);
   1.195 +		glColor3f(1, 1, 0);
   1.196 +		glTexCoord2f(0, 1); glVertex2f(-1, -1);
   1.197 +		glTexCoord2f(1, 1); glVertex2f(1, -1);
   1.198 +		glTexCoord2f(1, 0); glVertex2f(1, 1);
   1.199 +		glTexCoord2f(0, 0); glVertex2f(-1, 1);
   1.200 +		glEnd();
   1.201 +
   1.202 +		glMatrixMode(GL_TEXTURE);
   1.203 +		glLoadIdentity();
   1.204 +		glMatrixMode(GL_MODELVIEW);
   1.205 +		glPopMatrix();
   1.206 +
   1.207 +		glDisable(GL_BLEND);
   1.208 +	}
   1.209  
   1.210  	glXSwapBuffers(dpy, win);
   1.211  }
   1.212 @@ -171,9 +201,7 @@
   1.213  		break;
   1.214  
   1.215  	case Expose:
   1.216 -		if(mapped && ev->xexpose.count == 0) {
   1.217 -			redraw();
   1.218 -		}
   1.219 +		redisp_pending = 1;
   1.220  		break;
   1.221  
   1.222  	case KeyPress:
   1.223 @@ -183,6 +211,17 @@
   1.224  			switch(sym) {
   1.225  			case XK_Escape:
   1.226  				return -1;
   1.227 +
   1.228 +			case ' ':
   1.229 +				target_xid = get_window_id(dpy, 0, Button1);
   1.230 +				image_destroy(&img);
   1.231 +				if(get_window_shape(target_xid, &img) == -1) {
   1.232 +					destroy_texture(&tex);
   1.233 +				} else {
   1.234 +					image_texture(&tex, &img);
   1.235 +					redisp_pending = 1;
   1.236 +				}
   1.237 +				break;
   1.238  			}
   1.239  		}
   1.240  		break;
   1.241 @@ -202,6 +241,20 @@
   1.242  			}
   1.243  		}
   1.244  		break;
   1.245 +
   1.246 +	case ButtonPress:
   1.247 +		/*if(sel_active && ev->xbutton.button == Button1) {
   1.248 +			target_xid = ev->xbutton.subwindow;
   1.249 +			printf("clicked on window: %x\n", target_xid);
   1.250 +
   1.251 +			image_destroy(&img);
   1.252 +			if(get_window_shape(target_xid, &img) == -1) {
   1.253 +				destroy_texture(&tex);
   1.254 +			} else {
   1.255 +				image_texture(&tex, &img);
   1.256 +			}
   1.257 +		}*/
   1.258 +		break;
   1.259  	}
   1.260  	return 0;
   1.261  }
   1.262 @@ -280,21 +333,17 @@
   1.263  	int bx, by, cx, cy;
   1.264  	unsigned int bw, bh, cw, ch;
   1.265  	int kind;
   1.266 -	int x, y, w, h;
   1.267 +	int w, h;
   1.268  	XRectangle *rects;
   1.269  	int i, rect_count, rect_order;
   1.270  
   1.271  	XShapeQueryExtents(dpy, win, &buse, &bx, &by, &bw, &bh,
   1.272 -			&cuse, &cx, &cy, &bw, &bh);
   1.273 +			&cuse, &cx, &cy, &cw, &ch);
   1.274  	if(cuse) {
   1.275 -		x = cx;
   1.276 -		y = cy;
   1.277  		w = cw;
   1.278  		h = ch;
   1.279  		kind = ShapeClip;
   1.280  	} else if(buse) {
   1.281 -		x = bx;
   1.282 -		y = by;
   1.283  		w = bw;
   1.284  		h = bh;
   1.285  		kind = ShapeBounding;
   1.286 @@ -321,3 +370,49 @@
   1.287  	}
   1.288  	return 0;
   1.289  }
   1.290 +
   1.291 +XID get_window_id(Display *dpy, int screen, int button)
   1.292 +{
   1.293 +    Window root;		/* the current root */
   1.294 +    Window retwin = None;	/* the window that got selected */
   1.295 +    int retbutton = -1;		/* button used to select window */
   1.296 +    int pressed = 0;		/* count of number of buttons pressed */
   1.297 +
   1.298 +#define MASK (ButtonPressMask | ButtonReleaseMask)
   1.299 +
   1.300 +    root = RootWindow(dpy, screen);
   1.301 +    XSync(dpy, 0);			/* give xterm a chance */
   1.302 +
   1.303 +    if(XGrabPointer(dpy, root, False, MASK, GrabModeSync, GrabModeAsync,
   1.304 +				None, sel_cursor, CurrentTime) != GrabSuccess) {
   1.305 +		fprintf (stderr, "unable to grab cursor\n");
   1.306 +		return 0;
   1.307 +    }
   1.308 +
   1.309 +    while (retwin == None || pressed != 0) {
   1.310 +		XEvent event;
   1.311 +
   1.312 +		XAllowEvents (dpy, SyncPointer, CurrentTime);
   1.313 +		XWindowEvent (dpy, root, MASK, &event);
   1.314 +
   1.315 +		switch (event.type) {
   1.316 +		case ButtonPress:
   1.317 +			if (retwin == None) {
   1.318 +				retbutton = event.xbutton.button;
   1.319 +				retwin = ((event.xbutton.subwindow != None) ?
   1.320 +						event.xbutton.subwindow : root);
   1.321 +			}
   1.322 +			pressed++;
   1.323 +			continue;
   1.324 +
   1.325 +		case ButtonRelease:
   1.326 +			if (pressed > 0) pressed--;
   1.327 +			continue;
   1.328 +		}					/* end switch */
   1.329 +	}						/* end for */
   1.330 +
   1.331 +	XUngrabPointer (dpy, CurrentTime);
   1.332 +	XSync (dpy, 0);
   1.333 +
   1.334 +	return ((button == -1 || retbutton == button) ? retwin : None);
   1.335 +}
     2.1 --- a/src/texture.c	Tue Nov 03 00:42:08 2015 +0200
     2.2 +++ b/src/texture.c	Tue Nov 03 04:08:32 2015 +0200
     2.3 @@ -22,6 +22,12 @@
     2.4  	return 0;
     2.5  }
     2.6  
     2.7 +void destroy_texture(struct texture *tex)
     2.8 +{
     2.9 +	glDeleteTextures(1, &tex->id);
    2.10 +	tex->id = 0;
    2.11 +}
    2.12 +
    2.13  static int next_pow2(int x)
    2.14  {
    2.15  	--x;
     3.1 --- a/src/texture.h	Tue Nov 03 00:42:08 2015 +0200
     3.2 +++ b/src/texture.h	Tue Nov 03 04:08:32 2015 +0200
     3.3 @@ -9,5 +9,6 @@
     3.4  };
     3.5  
     3.6  int image_texture(struct texture *tex, struct image *img);
     3.7 +void destroy_texture(struct texture *tex);
     3.8  
     3.9  #endif	/* TEXTURE_H_ */