nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@1: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "image.h" nuclear@0: #include "texture.h" nuclear@0: nuclear@0: void redraw(void); nuclear@0: void reshape(int x, int y); nuclear@0: int handle_event(XEvent *ev); nuclear@0: nuclear@0: /* X helper functions */ nuclear@0: Window create_window(int xsz, int ysz); nuclear@0: void set_window_title(Window win, const char *title); nuclear@0: int get_window_shape(Window win, struct image *img); nuclear@1: XID get_window_id(Display *dpy, int screen, int button); nuclear@0: nuclear@0: Display *dpy; nuclear@0: Window win; nuclear@0: GLXContext ctx; nuclear@0: int width, height; nuclear@0: int mapped; nuclear@0: int redisp_pending; nuclear@0: Atom xa_wm_prot, xa_wm_del_win; nuclear@0: struct image img; nuclear@0: struct texture tex; nuclear@0: struct texture chess_tex; nuclear@0: float aspect; nuclear@1: int sel_active; nuclear@1: Cursor sel_cursor; nuclear@0: nuclear@0: unsigned int target_xid = 0; nuclear@0: nuclear@0: int main(int argc, char **argv) nuclear@0: { nuclear@0: int event_base, error_base; nuclear@0: char *endp; nuclear@0: struct image chess_img; nuclear@0: nuclear@1: if(argv[1] && !(target_xid = strtol(argv[1], &endp, 0))) { nuclear@0: fprintf(stderr, "invalid argument: %s\n", argv[1]); nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: if(!(dpy = XOpenDisplay(0))) { nuclear@0: fprintf(stderr, "failed to open display\n"); nuclear@0: return 1; nuclear@0: } nuclear@0: xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False); nuclear@0: xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False); nuclear@0: nuclear@1: sel_cursor = XCreateFontCursor(dpy, XC_crosshair); nuclear@1: nuclear@0: if(!XShapeQueryExtension(dpy, &event_base, &error_base)) { nuclear@0: fprintf(stderr, "shape extension unsupported by this X server\n"); nuclear@0: XCloseDisplay(dpy); nuclear@0: return 1; nuclear@0: } nuclear@1: nuclear@1: if(!target_xid) { nuclear@1: target_xid = get_window_id(dpy, 0, Button1); nuclear@1: } nuclear@1: if(target_xid) { nuclear@1: image_destroy(&img); nuclear@1: if(get_window_shape(target_xid, &img) == -1) { nuclear@1: destroy_texture(&tex); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: if(!(win = create_window(800 * (float)img.width / (float)img.height, 800))) { nuclear@0: return 1; nuclear@0: } nuclear@1: if(img.pixels) { nuclear@1: image_texture(&tex, &img); nuclear@0: } nuclear@0: nuclear@0: image_create(&chess_img, 256, 256); nuclear@1: image_chess(&chess_img, 8, 192, 100, 64, 64, 100, 192); nuclear@0: image_texture(&chess_tex, &chess_img); nuclear@0: image_destroy(&chess_img); nuclear@0: nuclear@0: for(;;) { nuclear@0: XEvent ev; nuclear@0: nuclear@1: do { nuclear@1: XNextEvent(dpy, &ev); nuclear@1: if(handle_event(&ev) == -1) { nuclear@1: goto quit; nuclear@1: } nuclear@1: } while(XPending(dpy)); nuclear@1: nuclear@1: if(redisp_pending) { nuclear@1: redisp_pending = 0; nuclear@1: redraw(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@1: quit: nuclear@0: XDestroyWindow(dpy, win); nuclear@0: XCloseDisplay(dpy); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void redraw(void) nuclear@0: { nuclear@0: glClearColor(0.4, 0.4, 0.4, 1); nuclear@0: glClear(GL_COLOR_BUFFER_BIT); nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glLoadIdentity(); nuclear@0: nuclear@0: glEnable(GL_TEXTURE_2D); nuclear@0: glBindTexture(GL_TEXTURE_2D, chess_tex.id); nuclear@0: nuclear@0: nuclear@0: /* background */ nuclear@0: glBegin(GL_QUADS); nuclear@1: glColor3f(1, 1, 1); nuclear@0: glTexCoord2f(0, 0); glVertex2f(-aspect, -1); nuclear@1: glTexCoord2f(aspect, 0); glVertex2f(aspect, -1); nuclear@1: glTexCoord2f(aspect, 1); glVertex2f(aspect, 1); nuclear@0: glTexCoord2f(0, 1); glVertex2f(-aspect, 1); nuclear@0: glEnd(); nuclear@0: nuclear@1: if(tex.id) { nuclear@1: int i, ssamples = 64; nuclear@1: float ssample_weight = 1.0 / (float)ssamples; nuclear@1: float shadow_spread = 0.05; nuclear@1: float img_aspect = (float)tex.width / (float)tex.height; nuclear@0: nuclear@1: /* draw the window shape */ nuclear@1: glEnable(GL_BLEND); nuclear@1: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); nuclear@0: nuclear@1: glBindTexture(GL_TEXTURE_2D, tex.id); nuclear@1: glMatrixMode(GL_TEXTURE); nuclear@1: glLoadIdentity(); nuclear@1: glScalef((float)tex.width / (float)tex.tex_width, nuclear@1: (float)tex.height / (float)tex.tex_height, nuclear@1: 1.0); nuclear@0: nuclear@1: glMatrixMode(GL_MODELVIEW); nuclear@1: glPushMatrix(); nuclear@1: glScalef(0.9 * img_aspect, 0.9, 0.9); nuclear@0: nuclear@1: /* shadow */ nuclear@1: for(i=0; itype) { nuclear@0: case MapNotify: nuclear@0: case UnmapNotify: nuclear@0: mapped = ev->type == MapNotify ? 1 : 0; nuclear@0: break; nuclear@0: nuclear@0: case Expose: nuclear@1: redisp_pending = 1; nuclear@0: break; nuclear@0: nuclear@0: case KeyPress: nuclear@0: { nuclear@0: KeySym sym = XLookupKeysym(&ev->xkey, 0); nuclear@0: nuclear@0: switch(sym) { nuclear@0: case XK_Escape: nuclear@0: return -1; nuclear@1: nuclear@1: case ' ': nuclear@1: target_xid = get_window_id(dpy, 0, Button1); nuclear@1: image_destroy(&img); nuclear@1: if(get_window_shape(target_xid, &img) == -1) { nuclear@1: destroy_texture(&tex); nuclear@1: } else { nuclear@1: image_texture(&tex, &img); nuclear@1: redisp_pending = 1; nuclear@1: } nuclear@1: break; nuclear@0: } nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case ConfigureNotify: nuclear@0: if(ev->xconfigure.width != width || ev->xconfigure.height != height) { nuclear@0: width = ev->xconfigure.width; nuclear@0: height = ev->xconfigure.height; nuclear@0: reshape(width, height); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case ClientMessage: nuclear@0: if(ev->xclient.message_type == xa_wm_prot) { nuclear@0: if(ev->xclient.data.l[0] == xa_wm_del_win) { nuclear@0: return -1; nuclear@0: } nuclear@0: } nuclear@0: break; nuclear@1: nuclear@1: case ButtonPress: nuclear@1: /*if(sel_active && ev->xbutton.button == Button1) { nuclear@1: target_xid = ev->xbutton.subwindow; nuclear@1: printf("clicked on window: %x\n", target_xid); nuclear@1: nuclear@1: image_destroy(&img); nuclear@1: if(get_window_shape(target_xid, &img) == -1) { nuclear@1: destroy_texture(&tex); nuclear@1: } else { nuclear@1: image_texture(&tex, &img); nuclear@1: } nuclear@1: }*/ nuclear@1: break; nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: Window create_window(int xsz, int ysz) nuclear@0: { nuclear@0: Window w, root; nuclear@0: XVisualInfo *vis; nuclear@0: XClassHint chint; nuclear@0: XSetWindowAttributes xattr; nuclear@0: unsigned int evmask, xattr_mask; nuclear@0: int scr; nuclear@0: int glxattr[] = { nuclear@0: GLX_RGBA, GLX_DOUBLEBUFFER, nuclear@0: GLX_RED_SIZE, 8, nuclear@0: GLX_GREEN_SIZE, 8, nuclear@0: GLX_BLUE_SIZE, 8, nuclear@0: GLX_DEPTH_SIZE, 24, nuclear@0: GLX_USE_GL, 1, nuclear@0: None nuclear@0: }; nuclear@0: nuclear@0: scr = DefaultScreen(dpy); nuclear@0: root = RootWindow(dpy, scr); nuclear@0: nuclear@0: if(!(vis = glXChooseVisual(dpy, scr, glxattr))) { nuclear@0: printf("failed to find a suitable visual\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: if(!(ctx = glXCreateContext(dpy, vis, 0, True))) { nuclear@0: XFree(vis); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr); nuclear@0: xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone); nuclear@0: xattr_mask = CWColormap | CWBackPixel | CWBorderPixel; nuclear@0: nuclear@0: if(!(w = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput, nuclear@0: vis->visual, xattr_mask, &xattr))) { nuclear@0: printf("failed to create window\n"); nuclear@0: glXDestroyContext(dpy, ctx); nuclear@0: XFree(vis); nuclear@0: return 0; nuclear@0: } nuclear@0: XFree(vis); nuclear@0: nuclear@0: evmask = StructureNotifyMask | VisibilityChangeMask | KeyPressMask | nuclear@0: ExposureMask; nuclear@0: XSelectInput(dpy, w, evmask); nuclear@0: nuclear@0: XSetWMProtocols(dpy, w, &xa_wm_del_win, 1); nuclear@0: nuclear@0: chint.res_name = chint.res_class = "xgetshape"; nuclear@0: XSetClassHint(dpy, w, &chint); nuclear@0: nuclear@0: set_window_title(w, "GL xgetshape"); nuclear@0: nuclear@0: glXMakeCurrent(dpy, w, ctx); nuclear@0: XMapWindow(dpy, w); nuclear@0: return w; nuclear@0: } nuclear@0: nuclear@0: void set_window_title(Window win, const char *title) nuclear@0: { nuclear@0: XTextProperty wm_name; nuclear@0: XStringListToTextProperty((char**)&title, 1, &wm_name); nuclear@0: XSetWMName(dpy, win, &wm_name); nuclear@0: XSetWMIconName(dpy, win, &wm_name); nuclear@0: XFree(wm_name.value); nuclear@0: } nuclear@0: nuclear@0: int get_window_shape(Window win, struct image *img) nuclear@0: { nuclear@0: Bool buse, cuse; nuclear@0: int bx, by, cx, cy; nuclear@0: unsigned int bw, bh, cw, ch; nuclear@0: int kind; nuclear@2: int xoffs, yoffs, w, h; nuclear@0: XRectangle *rects; nuclear@0: int i, rect_count, rect_order; nuclear@0: nuclear@0: XShapeQueryExtents(dpy, win, &buse, &bx, &by, &bw, &bh, nuclear@1: &cuse, &cx, &cy, &cw, &ch); nuclear@2: if(buse) { nuclear@2: w = bw; nuclear@2: h = bh; nuclear@2: xoffs = bx; nuclear@2: yoffs = by; nuclear@2: kind = ShapeBounding; nuclear@2: } else if(cuse) { nuclear@0: w = cw; nuclear@0: h = ch; nuclear@2: xoffs = cx; nuclear@2: yoffs = cy; nuclear@0: kind = ShapeClip; nuclear@0: } else { nuclear@0: fprintf(stderr, "XShapeQueryExtents returned no extents\n"); nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: if(image_create(img, w, h) == -1) { nuclear@0: fprintf(stderr, "failed to create shape image (%dx%d)\n", w, h); nuclear@0: return -1; nuclear@0: } nuclear@0: image_clear(img, 0, 0, 0, 0); nuclear@0: nuclear@0: if(!(rects = XShapeGetRectangles(dpy, win, kind, &rect_count, &rect_order))) { nuclear@0: fprintf(stderr, "failed to get the shape rectangles\n"); nuclear@0: image_destroy(img); nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: for(i=0; i 0) pressed--; nuclear@1: continue; nuclear@1: } /* end switch */ nuclear@1: } /* end for */ nuclear@1: nuclear@1: XUngrabPointer (dpy, CurrentTime); nuclear@1: XSync (dpy, 0); nuclear@1: nuclear@1: return ((button == -1 || retbutton == button) ? retwin : None); nuclear@1: }