nuclear@0: #include nuclear@0: #include nuclear@0: #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@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@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@0: if(!argv[1]) { nuclear@0: fprintf(stderr, "pass the window id to use\n"); nuclear@0: return 1; nuclear@0: } nuclear@0: if(!(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@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@0: if(get_window_shape(target_xid, &img) == -1) { nuclear@0: XCloseDisplay(dpy); nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: if(!(win = create_window(1280, 800))) { nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: image_texture(&tex, &img); nuclear@0: nuclear@0: image_create(&chess_img, 256, 256); nuclear@0: image_chess(&chess_img, 8, 255, 128, 64, 64, 128, 255); 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: XNextEvent(dpy, &ev); nuclear@0: nuclear@0: if(handle_event(&ev) == -1) { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: 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@0: glTexCoord2f(0, 0); glVertex2f(-aspect, -1); nuclear@0: glTexCoord2f(1, 0); glVertex2f(aspect, -1); nuclear@0: glTexCoord2f(1, 1); glVertex2f(aspect, 1); nuclear@0: glTexCoord2f(0, 1); glVertex2f(-aspect, 1); nuclear@0: glEnd(); nuclear@0: nuclear@0: /* draw the window shape */ nuclear@0: glEnable(GL_BLEND); nuclear@0: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); nuclear@0: nuclear@0: glBindTexture(GL_TEXTURE_2D, tex.id); nuclear@0: glMatrixMode(GL_TEXTURE); nuclear@0: glLoadIdentity(); nuclear@0: glScalef((float)tex.width / (float)tex.tex_width, nuclear@0: (float)tex.height / (float)tex.tex_height, nuclear@0: 1.0); nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glPushMatrix(); nuclear@0: glScalef(0.7, 0.7, 0.7); nuclear@0: nuclear@0: /* shadow */ nuclear@0: glPushMatrix(); nuclear@0: glTranslatef(0.1, -0.1, 0); nuclear@0: glBegin(GL_QUADS); nuclear@0: glColor3f(0, 0, 0); nuclear@0: glTexCoord2f(0, 1); glVertex2f(-1, -1); nuclear@0: glTexCoord2f(1, 1); glVertex2f(1, -1); nuclear@0: glTexCoord2f(1, 0); glVertex2f(1, 1); nuclear@0: glTexCoord2f(0, 0); glVertex2f(-1, 1); nuclear@0: glEnd(); nuclear@0: glPopMatrix(); nuclear@0: nuclear@0: /* window */ nuclear@0: glBegin(GL_QUADS); nuclear@0: glColor3f(1, 1, 0); nuclear@0: glTexCoord2f(0, 1); glVertex2f(-1, -1); nuclear@0: glTexCoord2f(1, 1); glVertex2f(1, -1); nuclear@0: glTexCoord2f(1, 0); glVertex2f(1, 1); nuclear@0: glTexCoord2f(0, 0); glVertex2f(-1, 1); nuclear@0: glEnd(); nuclear@0: nuclear@0: glMatrixMode(GL_TEXTURE); nuclear@0: glLoadIdentity(); nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glPopMatrix(); nuclear@0: nuclear@0: glDisable(GL_BLEND); nuclear@0: nuclear@0: glXSwapBuffers(dpy, win); nuclear@0: } nuclear@0: nuclear@0: void reshape(int x, int y) nuclear@0: { nuclear@0: aspect = (float)x / (float)y; nuclear@0: glViewport(0, 0, x, y); nuclear@0: nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glLoadIdentity(); nuclear@0: glScalef(1.0 / aspect, 1.0, 1.0); nuclear@0: } nuclear@0: nuclear@0: int handle_event(XEvent *ev) nuclear@0: { nuclear@0: switch(ev->type) { 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@0: if(mapped && ev->xexpose.count == 0) { nuclear@0: redraw(); nuclear@0: } 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@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@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@0: int x, y, 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@0: &cuse, &cx, &cy, &bw, &bh); nuclear@0: if(cuse) { nuclear@0: x = cx; nuclear@0: y = cy; nuclear@0: w = cw; nuclear@0: h = ch; nuclear@0: kind = ShapeClip; nuclear@0: } else if(buse) { nuclear@0: x = bx; nuclear@0: y = by; nuclear@0: w = bw; nuclear@0: h = bh; nuclear@0: kind = ShapeBounding; 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