1 /**************************************************************************
3 * Copyright 2011 Jose Fonseca
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
39 static Display *display = NULL;
40 static int screen = 0;
42 static unsigned glxVersion = 0;
43 static const char *extensions = 0;
44 static bool has_GLX_ARB_create_context = false;
47 class GlxVisual : public Visual
65 static void describeEvent(const XEvent &event) {
69 std::cerr << "ConfigureNotify";
72 std::cerr << "Expose";
75 std::cerr << "KeyPress";
78 std::cerr << "MapNotify";
81 std::cerr << "ReparentNotify";
84 std::cerr << "Event " << event.type;
86 std::cerr << " " << event.xany.window << "\n";
90 static void waitForEvent(Window window, int type) {
94 XNextEvent(display, &event);
96 } while (event.type != type ||
97 event.xany.window != window);
101 class GlxDrawable : public Drawable
106 GlxDrawable(const Visual *vis, int w, int h) :
109 XVisualInfo *visinfo = dynamic_cast<const GlxVisual *>(visual)->visinfo;
111 Window root = RootWindow(display, screen);
113 /* window attributes */
114 XSetWindowAttributes attr;
115 attr.background_pixel = 0;
116 attr.border_pixel = 0;
117 attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
118 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
121 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
125 window = XCreateWindow(
135 XSizeHints sizehints;
138 sizehints.width = width;
139 sizehints.height = height;
140 sizehints.flags = USSize | USPosition;
141 XSetNormalHints(display, window, &sizehints);
143 const char *name = "glretrace";
144 XSetStandardProperties(
145 display, window, name, name,
146 None, (char **)NULL, 0, &sizehints);
152 XDestroyWindow(display, window);
156 resize(int w, int h) {
159 // We need to ensure that pending events are processed here, and XSync
160 // with discard = True guarantees that, but it appears the limited
161 // event processing we do so far is sufficient
162 //XSync(display, True);
164 Drawable::resize(w, h);
166 XResizeWindow(display, window, w, h);
168 // Tell the window manager to respect the requested size
169 XSizeHints *size_hints;
170 size_hints = XAllocSizeHints();
171 size_hints->max_width = size_hints->min_width = w;
172 size_hints->max_height = size_hints->min_height = h;
173 size_hints->flags = PMinSize | PMaxSize;
174 XSetWMNormalHints(display, window, size_hints);
177 waitForEvent(window, ConfigureNotify);
184 XMapWindow(display, window);
186 waitForEvent(window, Expose);
192 void swapBuffers(void) {
193 glXSwapBuffers(display, window);
198 class GlxContext : public Context
203 GlxContext(const Visual *vis, GLXContext ctx) :
209 glXDestroyContext(display, context);
215 display = XOpenDisplay(NULL);
217 std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
221 screen = DefaultScreen(display);
223 int major = 0, minor = 0;
224 glXQueryVersion(display, &major, &minor);
225 glxVersion = (major << 8) | minor;
227 extensions = glXQueryExtensionsString(display, screen);
228 has_GLX_ARB_create_context = checkExtension("GLX_ARB_create_context", extensions);
234 XCloseDisplay(display);
240 createVisual(bool doubleBuffer) {
241 GlxVisual *visual = new GlxVisual;
243 if (glxVersion >= 0x0103) {
244 Attributes<int> attribs;
245 attribs.add(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
246 attribs.add(GLX_RENDER_TYPE, GLX_RGBA_BIT);
247 attribs.add(GLX_RED_SIZE, 1);
248 attribs.add(GLX_GREEN_SIZE, 1);
249 attribs.add(GLX_BLUE_SIZE, 1);
250 attribs.add(GLX_ALPHA_SIZE, 1);
251 attribs.add(GLX_DOUBLEBUFFER, doubleBuffer ? GL_TRUE : GL_FALSE);
252 attribs.add(GLX_DEPTH_SIZE, 1);
253 attribs.add(GLX_STENCIL_SIZE, 1);
257 GLXFBConfig * fbconfigs;
258 fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_configs);
259 assert(num_configs && fbconfigs);
260 visual->fbconfig = fbconfigs[0];
261 assert(visual->fbconfig);
262 visual->visinfo = glXGetVisualFromFBConfig(display, visual->fbconfig);
263 assert(visual->visinfo);
265 Attributes<int> attribs;
266 attribs.add(GLX_RGBA);
267 attribs.add(GLX_RED_SIZE, 1);
268 attribs.add(GLX_GREEN_SIZE, 1);
269 attribs.add(GLX_BLUE_SIZE, 1);
270 attribs.add(GLX_ALPHA_SIZE, 1);
272 attribs.add(GLX_DOUBLEBUFFER);
274 attribs.add(GLX_DEPTH_SIZE, 1);
275 attribs.add(GLX_STENCIL_SIZE, 1);
278 visual->visinfo = glXChooseVisual(display, screen, attribs);
285 createDrawable(const Visual *visual, int width, int height)
287 return new GlxDrawable(visual, width, height);
291 createContext(const Visual *_visual, Context *shareContext)
293 const GlxVisual *visual = dynamic_cast<const GlxVisual *>(_visual);
294 GLXContext share_context = NULL;
298 share_context = dynamic_cast<GlxContext*>(shareContext)->context;
301 if (glxVersion >= 0x0104 && has_GLX_ARB_create_context) {
302 Attributes<int> attribs;
303 attribs.add(GLX_RENDER_TYPE, GLX_RGBA_TYPE);
305 attribs.add(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
309 context = glXCreateContextAttribsARB(display, visual->fbconfig, share_context, True, attribs);
311 if (glxVersion >= 0x103) {
312 context = glXCreateNewContext(display, visual->fbconfig, GLX_RGBA_TYPE, share_context, True);
314 context = glXCreateContext(display, visual->visinfo, share_context, True);
317 return new GlxContext(visual, context);
321 makeCurrent(Drawable *drawable, Context *context)
323 if (!drawable || !context) {
324 return glXMakeCurrent(display, None, NULL);
326 GlxDrawable *glxDrawable = dynamic_cast<GlxDrawable *>(drawable);
327 GlxContext *glxContext = dynamic_cast<GlxContext *>(context);
329 return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
334 processEvents(void) {
336 while (XPending(display) > 0) {
338 XNextEvent(display, &event);
339 describeEvent(event);
345 } /* namespace glws */