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 **************************************************************************/
38 static Display *display = NULL;
39 static int screen = 0;
41 static unsigned glxVersion = 0;
42 static const char *extensions = 0;
43 static bool has_GLX_ARB_create_context = false;
46 class GlxVisual : public Visual
64 processEvent(XEvent &event) {
68 std::cerr << "ConfigureNotify";
71 std::cerr << "Expose";
74 std::cerr << "KeyPress";
77 std::cerr << "MapNotify";
80 std::cerr << "ReparentNotify";
83 std::cerr << "Event " << event.type;
85 std::cerr << " " << event.xany.window << "\n";
93 XLookupString(&event.xkey, buffer, sizeof buffer - 1, &keysym, NULL);
94 if (keysym == XK_Escape) {
102 class GlxDrawable : public Drawable
107 GlxDrawable(const Visual *vis, int w, int h) :
110 XVisualInfo *visinfo = static_cast<const GlxVisual *>(visual)->visinfo;
112 Window root = RootWindow(display, screen);
114 /* window attributes */
115 XSetWindowAttributes attr;
116 attr.background_pixel = 0;
117 attr.border_pixel = 0;
118 attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
119 attr.event_mask = StructureNotifyMask | KeyPressMask;
122 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
126 window = XCreateWindow(
136 XSizeHints sizehints;
139 sizehints.width = width;
140 sizehints.height = height;
141 sizehints.flags = USSize | USPosition;
142 XSetNormalHints(display, window, &sizehints);
144 const char *name = "glretrace";
145 XSetStandardProperties(
146 display, window, name, name,
147 None, (char **)NULL, 0, &sizehints);
152 void processKeys(void) {
154 while (XCheckWindowEvent(display, window, StructureNotifyMask | KeyPressMask, &event)) {
159 void waitForEvent(int type) {
162 XWindowEvent(display, window, StructureNotifyMask | KeyPressMask, &event);
164 } while (event.type != type);
168 XDestroyWindow(display, window);
172 resize(int w, int h) {
173 if (w == width && h == height) {
179 // We need to ensure that pending events are processed here, and XSync
180 // with discard = True guarantees that, but it appears the limited
181 // event processing we do so far is sufficient
182 //XSync(display, True);
184 Drawable::resize(w, h);
186 XResizeWindow(display, window, w, h);
188 // Tell the window manager to respect the requested size
189 XSizeHints size_hints;
190 size_hints.max_width = size_hints.min_width = w;
191 size_hints.max_height = size_hints.min_height = h;
192 size_hints.flags = PMinSize | PMaxSize;
193 XSetWMNormalHints(display, window, &size_hints);
195 waitForEvent(ConfigureNotify);
207 XMapWindow(display, window);
209 waitForEvent(MapNotify);
216 void swapBuffers(void) {
217 glXSwapBuffers(display, window);
224 class GlxContext : public Context
229 GlxContext(const Visual *vis, Profile prof, GLXContext ctx) :
235 glXDestroyContext(display, context);
241 display = XOpenDisplay(NULL);
243 std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
247 screen = DefaultScreen(display);
249 int major = 0, minor = 0;
250 glXQueryVersion(display, &major, &minor);
251 glxVersion = (major << 8) | minor;
253 extensions = glXQueryExtensionsString(display, screen);
254 has_GLX_ARB_create_context = checkExtension("GLX_ARB_create_context", extensions);
260 XCloseDisplay(display);
266 createVisual(bool doubleBuffer, Profile profile) {
267 if (profile != PROFILE_COMPAT &&
268 profile != PROFILE_CORE) {
272 GlxVisual *visual = new GlxVisual;
274 if (glxVersion >= 0x0103) {
275 Attributes<int> attribs;
276 attribs.add(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
277 attribs.add(GLX_RENDER_TYPE, GLX_RGBA_BIT);
278 attribs.add(GLX_RED_SIZE, 1);
279 attribs.add(GLX_GREEN_SIZE, 1);
280 attribs.add(GLX_BLUE_SIZE, 1);
281 attribs.add(GLX_ALPHA_SIZE, 1);
282 attribs.add(GLX_DOUBLEBUFFER, doubleBuffer ? GL_TRUE : GL_FALSE);
283 attribs.add(GLX_DEPTH_SIZE, 1);
284 attribs.add(GLX_STENCIL_SIZE, 1);
288 GLXFBConfig * fbconfigs;
289 fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_configs);
290 assert(num_configs && fbconfigs);
291 visual->fbconfig = fbconfigs[0];
292 assert(visual->fbconfig);
293 visual->visinfo = glXGetVisualFromFBConfig(display, visual->fbconfig);
294 assert(visual->visinfo);
296 Attributes<int> attribs;
297 attribs.add(GLX_RGBA);
298 attribs.add(GLX_RED_SIZE, 1);
299 attribs.add(GLX_GREEN_SIZE, 1);
300 attribs.add(GLX_BLUE_SIZE, 1);
301 attribs.add(GLX_ALPHA_SIZE, 1);
303 attribs.add(GLX_DOUBLEBUFFER);
305 attribs.add(GLX_DEPTH_SIZE, 1);
306 attribs.add(GLX_STENCIL_SIZE, 1);
309 visual->visinfo = glXChooseVisual(display, screen, attribs);
316 createDrawable(const Visual *visual, int width, int height)
318 return new GlxDrawable(visual, width, height);
322 createContext(const Visual *_visual, Context *shareContext, Profile profile, bool debug)
324 const GlxVisual *visual = static_cast<const GlxVisual *>(_visual);
325 GLXContext share_context = NULL;
329 share_context = static_cast<GlxContext*>(shareContext)->context;
332 if (glxVersion >= 0x0104 && has_GLX_ARB_create_context) {
333 Attributes<int> attribs;
335 attribs.add(GLX_RENDER_TYPE, GLX_RGBA_TYPE);
337 attribs.add(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
344 // XXX: This will invariable return a 3.2 context, when supported.
345 // We probably should have a PROFILE_CORE_XX per version.
346 attribs.add(GLX_CONTEXT_MAJOR_VERSION_ARB, 3);
347 attribs.add(GLX_CONTEXT_MINOR_VERSION_ARB, 2);
348 attribs.add(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
356 context = glXCreateContextAttribsARB(display, visual->fbconfig, share_context, True, attribs);
358 if (profile != PROFILE_COMPAT) {
362 if (glxVersion >= 0x103) {
363 context = glXCreateNewContext(display, visual->fbconfig, GLX_RGBA_TYPE, share_context, True);
365 context = glXCreateContext(display, visual->visinfo, share_context, True);
373 return new GlxContext(visual, profile, context);
377 makeCurrent(Drawable *drawable, Context *context)
379 if (!drawable || !context) {
380 return glXMakeCurrent(display, None, NULL);
382 GlxDrawable *glxDrawable = static_cast<GlxDrawable *>(drawable);
383 GlxContext *glxContext = static_cast<GlxContext *>(context);
385 return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
390 processEvents(void) {
391 while (XPending(display) > 0) {
393 XNextEvent(display, &event);
400 } /* namespace glws */