diff options
Diffstat (limited to 'pugl/pugl_x11.c')
-rw-r--r-- | pugl/pugl_x11.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/pugl/pugl_x11.c b/pugl/pugl_x11.c new file mode 100644 index 0000000..33f0b42 --- /dev/null +++ b/pugl/pugl_x11.c @@ -0,0 +1,242 @@ +/* + Copyright 2012 David Robillard <http://drobilla.net> + Copyright 2011-2012 Ben Loftis, Harrison Consoles + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <GL/gl.h> +#include <GL/glx.h> +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/keysym.h> + +#include "pugl_internal.h" + +struct PuglPlatformDataImpl { + Display* display; + int screen; + Window win; + GLXContext ctx; + Bool doubleBuffered; +}; + +/** + Attributes for single-buffered RGBA with at least + 4 bits per color and a 16 bit depth buffer. +*/ +static int attrListSgl[] = { + GLX_RGBA, + GLX_RED_SIZE, 4, + GLX_GREEN_SIZE, 4, + GLX_BLUE_SIZE, 4, + GLX_DEPTH_SIZE, 16, + None +}; + +/** + Attributes for double-buffered RGBA with at least + 4 bits per color and a 16 bit depth buffer. +*/ +static int attrListDbl[] = { + GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 4, + GLX_GREEN_SIZE, 4, + GLX_BLUE_SIZE, 4, + GLX_DEPTH_SIZE, 16, + None +}; + +PuglWindow* +puglCreate(PuglNativeWindow parent, const char* title, int width, int height) +{ + PuglWindow* win = (PuglWindow*)calloc(1, sizeof(PuglWindow)); + + win->impl = (PuglPlatformData*)calloc(1, sizeof(PuglPlatformData)); + + PuglPlatformData* impl = win->impl; + + win->width = width; + win->height = height; + impl->display = XOpenDisplay(0); + impl->screen = DefaultScreen(impl->display); + + XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); + if (vi == NULL) { + vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); + impl->doubleBuffered = False; + printf("singlebuffered rendering will be used, no doublebuffering available\n"); + } else { + impl->doubleBuffered = True; + printf("doublebuffered rendering available\n"); + } + + int glxMajor, glxMinor; + glXQueryVersion(impl->display, &glxMajor, &glxMinor); + printf("GLX-Version %d.%d\n", glxMajor, glxMinor); + + impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); + + Window xParent = parent + ? (Window)parent + : RootWindow(impl->display, impl->screen); + + Colormap cmap = XCreateColormap( + impl->display, xParent, vi->visual, AllocNone); + + XSetWindowAttributes attr; + memset(&attr, 0, sizeof(XSetWindowAttributes)); + attr.colormap = cmap; + attr.border_pixel = 0; + + attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask + | ButtonPressMask | PointerMotionMask | StructureNotifyMask; + + impl->win = XCreateWindow( + impl->display, xParent, + 0, 0, win->width, win->height, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &attr); + + if (title) { + XStoreName(impl->display, impl->win, title); + } + + if (!parent) { + Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True); + XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); + } + + XMapRaised(impl->display, impl->win); + + if (glXIsDirect(impl->display, impl->ctx)) { + printf("DRI enabled\n"); + } else { + printf("no DRI available\n"); + } + + return win; +} + +void +puglDestroy(PuglWindow* win) +{ + if (win->impl->ctx) { + if (!glXMakeCurrent(win->impl->display, None, NULL)) { + printf("Could not release drawing context.\n"); + } + /* destroy the context */ + glXDestroyContext(win->impl->display, win->impl->ctx); + win->impl->ctx = NULL; + } + + XCloseDisplay(win->impl->display); + free(win); +} + +void +puglDisplay(PuglWindow* win) +{ + glXMakeCurrent(win->impl->display, win->impl->win, win->impl->ctx); + glViewport(0, 0, win->width, win->height); + + if (win->displayFunc) { + win->displayFunc(win); + } + + if (win->impl->doubleBuffered) { + glXSwapBuffers(win->impl->display, win->impl->win); + } +} + +PuglStatus +puglProcessEvents(PuglWindow* win) +{ + XEvent event; + + /* handle the events in the queue */ + while (XPending(win->impl->display) > 0) { + XNextEvent(win->impl->display, &event); + switch (event.type) { + case Expose: + if (event.xexpose.count != 0) { + break; + } + puglDisplay(win); + win->redisplay = false; + break; + case ConfigureNotify: + if ((event.xconfigure.width != win->width) || + (event.xconfigure.height != win->height)) { + if (win->reshapeFunc) { + win->reshapeFunc(win, + event.xconfigure.width, + event.xconfigure.height); + } + } + break; + case MotionNotify: + if (win->motionFunc) { + win->motionFunc(win, event.xmotion.x, event.xmotion.y); + } + break; + case ButtonPress: + if (win->mouseFunc) { + win->mouseFunc(win, + event.xbutton.button, event.xbutton.state, + event.xbutton.x, event.xbutton.y); + } + break; + case KeyPress: + case KeyRelease: + if (win->keyboardFunc) { + KeySym sym = XKeycodeToKeysym( + win->impl->display, event.xkey.keycode, 0); + win->keyboardFunc(win, event.type == KeyPress, sym); + } + break; + case ClientMessage: + if (!strcmp(XGetAtomName(win->impl->display, + event.xclient.message_type), + "WM_PROTOCOLS")) { + if (win->closeFunc) { + win->closeFunc(win); + } + } + break; + default: + break; + } + } + + if (win->redisplay) { + puglDisplay(win); + } + + return PUGL_SUCCESS; +} + +void +puglPostRedisplay(PuglWindow* win) +{ + win->redisplay = true; +} + +PuglNativeWindow +puglGetNativeWindow(PuglWindow* win) +{ + return win->impl->win; +} |