nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@1: #include nuclear@5: #include nuclear@0: #include "cwin.h" nuclear@2: #include "opengl.h" nuclear@1: #include "logger.h" nuclear@9: #include "xerr.h" nuclear@9: nuclear@1: nuclear@5: static bool query_extensions(); nuclear@1: static bool register_compositor(); nuclear@2: static void start_comp(); nuclear@2: static void manage_window(Window xwin); nuclear@2: static void unmanage_window(Window xwin); nuclear@7: static void damage_window(XDamageNotifyEvent *ev); nuclear@2: static void redraw(); nuclear@3: static void draw_window(CompWindow *cwin); nuclear@2: static void reshape(int x, int y); nuclear@1: nuclear@2: Display *dpy; nuclear@2: int screen_num; nuclear@2: Window root_win, comp_win; nuclear@2: int root_width, root_height; nuclear@1: nuclear@5: static int xdmg_ev_base, xdmg_err_base; nuclear@5: static int xshape_ev_base, xshape_err_base; nuclear@5: nuclear@1: int main(int argc, char **argv) nuclear@1: { nuclear@1: if(!(dpy = XOpenDisplay(0))) { nuclear@1: log_error("failed to open X display\n"); nuclear@1: return 1; nuclear@1: } nuclear@2: screen_num = DefaultScreen(dpy); nuclear@2: root_win = RootWindow(dpy, screen_num); nuclear@2: root_width = DisplayWidth(dpy, screen_num); nuclear@2: root_height = DisplayHeight(dpy, screen_num); nuclear@1: log_info("display size %dx%d\n", root_width, root_height); nuclear@1: nuclear@5: if(!query_extensions()) { nuclear@1: return 1; nuclear@1: } nuclear@1: nuclear@1: if(!register_compositor()) { nuclear@1: return 1; nuclear@1: } nuclear@1: nuclear@2: comp_win = XCompositeGetOverlayWindow(dpy, root_win); nuclear@2: if(!create_gl(comp_win)) { nuclear@2: return 1; nuclear@2: } nuclear@2: nuclear@2: start_comp(); nuclear@2: reshape(root_width, root_height); nuclear@2: redraw(); nuclear@1: nuclear@1: for(;;) { nuclear@1: XEvent ev; nuclear@1: XNextEvent(dpy, &ev); nuclear@2: nuclear@3: CompWindow *cwin; nuclear@2: switch(ev.type) { nuclear@2: case CreateNotify: nuclear@9: log_debug("CreateNotify: %x\n", ev.xcreatewindow.window); nuclear@2: manage_window(ev.xcreatewindow.window); nuclear@2: break; nuclear@2: nuclear@2: case ConfigureNotify: nuclear@5: // XXX is this right? nuclear@5: if((cwin = find_window_xid(ev.xconfigure.window))) { nuclear@9: log_debug("updating window attributes for: %x\n", cwin->xwin); nuclear@5: XGetWindowAttributes(dpy, cwin->xwin, &cwin->attr); nuclear@5: } nuclear@2: break; nuclear@2: nuclear@2: case DestroyNotify: nuclear@9: log_debug("DestroyNotify: %x\n", ev.xdestroywindow.window); nuclear@2: unmanage_window(ev.xdestroywindow.window); nuclear@2: break; nuclear@2: nuclear@2: case MapNotify: nuclear@3: if((cwin = find_window_xid(ev.xmap.window))) { nuclear@3: cwin->mapped = true; nuclear@3: } nuclear@2: break; nuclear@3: nuclear@2: case UnmapNotify: nuclear@3: if((cwin = find_window_xid(ev.xunmap.window))) { nuclear@3: cwin->mapped = false; nuclear@3: } nuclear@2: break; nuclear@2: nuclear@2: case ReparentNotify: nuclear@2: if(ev.xreparent.parent == root_win) { nuclear@2: manage_window(ev.xreparent.window); nuclear@2: } else { nuclear@2: unmanage_window(ev.xreparent.window); nuclear@2: } nuclear@2: break; nuclear@2: nuclear@2: case CirculateNotify: nuclear@2: break; nuclear@2: nuclear@2: case Expose: nuclear@3: // TODO? nuclear@2: break; nuclear@2: nuclear@2: default: nuclear@2: if(ev.type == xdmg_ev_base + XDamageNotify) { nuclear@7: damage_window((XDamageNotifyEvent*)&ev); nuclear@2: } nuclear@2: } nuclear@5: nuclear@5: redraw(); nuclear@1: } nuclear@1: } nuclear@1: nuclear@5: static bool query_extensions() nuclear@5: { nuclear@5: int xcomp_ev_base, xcomp_err_base; nuclear@5: if(!XCompositeQueryExtension(dpy, &xcomp_ev_base, &xcomp_err_base)) { nuclear@5: log_error("X server doesn't support the composite extension\n"); nuclear@5: return false; nuclear@5: } nuclear@5: int xcomp_ver_major, xcomp_ver_minor; nuclear@5: XCompositeQueryVersion(dpy, &xcomp_ver_major, &xcomp_ver_minor); nuclear@5: log_info("Found composite extension version %d.%d\n", xcomp_ver_major, xcomp_ver_minor); nuclear@5: if(xcomp_ver_major <= 0 && xcomp_ver_minor < 3) { nuclear@5: // for NameWindowPixmap & CompositeGetoverlayWindow nuclear@5: log_error("I need at least version 0.3\n"); nuclear@5: return false; nuclear@5: } nuclear@5: nuclear@5: if(!XDamageQueryExtension(dpy, &xdmg_ev_base, &xdmg_err_base)) { nuclear@5: log_error("X server doesn't support the damage extension\n"); nuclear@5: return false; nuclear@5: } nuclear@5: nuclear@5: if(!XShapeQueryExtension(dpy, &xshape_ev_base, &xshape_err_base)) { nuclear@5: log_error("X server doesn't support the shape extension\n"); nuclear@5: return false; nuclear@5: } nuclear@5: nuclear@5: int xfix_ev_base, xfix_err_base; nuclear@5: if(!XFixesQueryExtension(dpy, &xfix_ev_base, &xfix_err_base)) { nuclear@5: log_error("X server doesn't support the Xfixes extension\n"); nuclear@5: return false; nuclear@5: } nuclear@5: nuclear@5: int xfix_ver_major, xfix_ver_minor; nuclear@5: XFixesQueryVersion(dpy, &xfix_ver_major, &xfix_ver_minor); nuclear@5: log_info("Found xfixes version %d.%d\n", xfix_ver_major, xfix_ver_minor); nuclear@5: if(xfix_ver_major < 2) { nuclear@5: // for SetWindowShapeRegion nuclear@5: log_error("I need at least version 2.0\n"); nuclear@5: return false; nuclear@5: } nuclear@5: return true; nuclear@5: } nuclear@5: nuclear@1: static bool register_compositor() nuclear@1: { nuclear@1: char atom_name[64]; nuclear@2: sprintf(atom_name, "_NET_WM_CM_S%d", screen_num); nuclear@1: Atom xa_wm_cm = XInternAtom(dpy, atom_name, False); nuclear@1: nuclear@1: Window win = XGetSelectionOwner(dpy, xa_wm_cm); nuclear@1: if(win != None) { nuclear@1: log_error("Another compositor is running. Stop it and try again.\n"); nuclear@1: return false; nuclear@1: } nuclear@1: nuclear@1: win = XCreateSimpleWindow(dpy, root_win, 0, 0, 1, 1, 0, None, None); nuclear@1: XSetSelectionOwner(dpy, xa_wm_cm, win, 0); nuclear@1: return true; nuclear@1: } nuclear@2: nuclear@2: static void start_comp() nuclear@2: { nuclear@2: XGrabServer(dpy); nuclear@2: XCompositeRedirectSubwindows(dpy, root_win, CompositeRedirectManual); nuclear@2: XSelectInput(dpy, root_win, SubstructureNotifyMask | ExposureMask | StructureNotifyMask); nuclear@2: nuclear@2: // manage all top-level windows nuclear@2: Window root_ret, parent; nuclear@2: Window *children; nuclear@2: unsigned int num_children; nuclear@2: XQueryTree(dpy, root_win, &root_ret, &parent, &children, &num_children); nuclear@2: nuclear@2: for(unsigned int i=0; imapped = cwin->attr.map_state != IsUnmapped; nuclear@2: } nuclear@2: nuclear@2: static void unmanage_window(Window xwin) nuclear@2: { nuclear@2: //log_debug("unmanage_window %u\n", xwin); nuclear@2: CompWindow *cwin = find_window_xid(xwin); nuclear@3: if(!cwin) return; nuclear@3: nuclear@3: remove_window(cwin); nuclear@3: delete cwin; nuclear@2: } nuclear@2: nuclear@7: static void damage_window(XDamageNotifyEvent *ev) nuclear@7: { nuclear@7: XserverRegion region; nuclear@7: CompWindow *cwin = find_window_xid(ev->drawable); nuclear@9: if(!cwin || !cwin->damage) return; nuclear@7: nuclear@7: region = XFixesCreateRegion(dpy, 0, 0); nuclear@9: nuclear@9: push_xerr_handler(xerr_debug); nuclear@7: XDamageSubtract(dpy, cwin->damage, None, region); nuclear@9: pop_xerr_handler(); nuclear@11: nuclear@11: XFixesDestroyRegion(dpy, region); nuclear@7: } nuclear@7: nuclear@2: static void redraw() nuclear@2: { nuclear@2: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@2: nuclear@3: glPushAttrib(GL_ENABLE_BIT); nuclear@3: glEnable(GL_TEXTURE_2D); nuclear@2: glEnable(GL_BLEND); nuclear@2: glBlendFunc(GL_ONE, GL_ONE); nuclear@2: nuclear@2: int num_win = get_window_count(); nuclear@2: for(int i=0; imapped) continue; nuclear@3: nuclear@3: if(cwin->attr.x + cwin->attr.width <= 0 || nuclear@3: cwin->attr.y + cwin->attr.height <= 0 || nuclear@3: cwin->attr.x >= root_width || cwin->attr.y >= root_height) { nuclear@3: continue; nuclear@3: } nuclear@3: nuclear@3: draw_window(cwin); nuclear@2: } nuclear@2: nuclear@3: glPopAttrib(); nuclear@2: nuclear@2: glXSwapBuffers(dpy, comp_win); nuclear@2: } nuclear@2: nuclear@3: static void draw_window(CompWindow *cwin) nuclear@3: { nuclear@3: if(!cwin->xpixmap) { nuclear@3: cwin->xpixmap = XCompositeNameWindowPixmap(dpy, cwin->xwin); nuclear@3: if(!cwin->xpixmap) { nuclear@3: log_warning("failed to get pixmap\n"); nuclear@3: return; nuclear@3: } nuclear@3: cwin->tex.set_image(dpy, cwin->xpixmap); nuclear@3: } nuclear@3: nuclear@3: glBindTexture(GL_TEXTURE_2D, cwin->tex.get_id()); nuclear@3: nuclear@3: glBegin(GL_QUADS); nuclear@3: glColor3f(0.3, 0.3, 0.3); nuclear@3: glTexCoord2f(0, 0); nuclear@3: glVertex2f(cwin->attr.x, cwin->attr.y); nuclear@3: glTexCoord2f(1, 0); nuclear@3: glVertex2f(cwin->attr.x + cwin->attr.width, cwin->attr.y); nuclear@3: glTexCoord2f(1, 1); nuclear@3: glVertex2f(cwin->attr.x + cwin->attr.width, cwin->attr.y + cwin->attr.height); nuclear@3: glTexCoord2f(0, 1); nuclear@3: glVertex2f(cwin->attr.x, cwin->attr.y + cwin->attr.height); nuclear@3: glEnd(); nuclear@3: } nuclear@3: nuclear@2: static void reshape(int x, int y) nuclear@2: { nuclear@2: glViewport(0, 0, x, y); nuclear@2: nuclear@2: glMatrixMode(GL_PROJECTION); nuclear@2: glLoadIdentity(); nuclear@2: glOrtho(0, x, y, 0, -1, 1); nuclear@2: }