]> git.cworth.org Git - apitrace/blob - glws_glx.cpp
gui: let the edit mode work.
[apitrace] / glws_glx.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 #include <assert.h>
27 #include <stdlib.h>
28
29 #include <iostream>
30
31 #include "glws.hpp"
32
33 #include "glproc.hpp"
34
35
36 namespace glws {
37
38
39 static Display *display = NULL;
40 static int screen = 0;
41
42 static unsigned glxVersion = 0;
43 static const char *extensions = 0;
44 static bool has_GLX_ARB_create_context = false;
45
46
47 class GlxVisual : public Visual
48 {
49 public:
50     GLXFBConfig fbconfig;
51     XVisualInfo *visinfo;
52
53     GlxVisual() :
54         fbconfig(0),
55         visinfo(0)
56     {}
57
58     ~GlxVisual() {
59         XFree(visinfo);
60     }
61 };
62
63
64 static void describeEvent(const XEvent &event) {
65     if (0) {
66         switch (event.type) {
67         case ConfigureNotify:
68             std::cerr << "ConfigureNotify";
69             break;
70         case Expose:
71             std::cerr << "Expose";
72             break;
73         case KeyPress:
74             std::cerr << "KeyPress";
75             break;
76         case MapNotify:
77             std::cerr << "MapNotify";
78             break;
79         case ReparentNotify:
80             std::cerr << "ReparentNotify";
81             break;
82         default:
83             std::cerr << "Event " << event.type;
84         }
85         std::cerr << " " << event.xany.window << "\n";
86     }
87 }
88
89 class GlxDrawable : public Drawable
90 {
91 public:
92     Window window;
93
94     GlxDrawable(const Visual *vis, int w, int h) :
95         Drawable(vis, w, h)
96     {
97         XVisualInfo *visinfo = static_cast<const GlxVisual *>(visual)->visinfo;
98
99         Window root = RootWindow(display, screen);
100
101         /* window attributes */
102         XSetWindowAttributes attr;
103         attr.background_pixel = 0;
104         attr.border_pixel = 0;
105         attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
106         attr.event_mask = StructureNotifyMask;
107
108         unsigned long mask;
109         mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
110
111         int x = 0, y = 0;
112
113         window = XCreateWindow(
114             display, root,
115             x, y, width, height,
116             0,
117             visinfo->depth,
118             InputOutput,
119             visinfo->visual,
120             mask,
121             &attr);
122
123         XSizeHints sizehints;
124         sizehints.x = x;
125         sizehints.y = y;
126         sizehints.width  = width;
127         sizehints.height = height;
128         sizehints.flags = USSize | USPosition;
129         XSetNormalHints(display, window, &sizehints);
130
131         const char *name = "glretrace";
132         XSetStandardProperties(
133             display, window, name, name,
134             None, (char **)NULL, 0, &sizehints);
135
136         glXWaitX();
137     }
138
139     void waitForEvent(int type) {
140         XEvent event;
141         do {
142             XWindowEvent(display, window, StructureNotifyMask, &event);
143             describeEvent(event);
144         } while (event.type != type);
145     }
146
147     ~GlxDrawable() {
148         XDestroyWindow(display, window);
149     }
150
151     void
152     resize(int w, int h) {
153         if (w == width && h == height) {
154             return;
155         }
156
157         glXWaitGL();
158
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);
163
164         Drawable::resize(w, h);
165
166         XResizeWindow(display, window, w, h);
167
168         // Tell the window manager to respect the requested size
169         XSizeHints size_hints;
170         size_hints.max_width  = size_hints.min_width  = w;
171         size_hints.max_height = size_hints.min_height = h;
172         size_hints.flags = PMinSize | PMaxSize;
173         XSetWMNormalHints(display, window, &size_hints);
174
175         waitForEvent(ConfigureNotify);
176
177         glXWaitX();
178     }
179
180     void show(void) {
181         if (visible) {
182             return;
183         }
184
185         glXWaitGL();
186
187         XMapWindow(display, window);
188
189         waitForEvent(MapNotify);
190
191         glXWaitX();
192
193         Drawable::show();
194     }
195
196     void swapBuffers(void) {
197         glXSwapBuffers(display, window);
198     }
199 };
200
201
202 class GlxContext : public Context
203 {
204 public:
205     GLXContext context;
206
207     GlxContext(const Visual *vis, Profile prof, GLXContext ctx) :
208         Context(vis, prof),
209         context(ctx)
210     {}
211
212     ~GlxContext() {
213         glXDestroyContext(display, context);
214     }
215 };
216
217 void
218 init(void) {
219     display = XOpenDisplay(NULL);
220     if (!display) {
221         std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
222         exit(1);
223     }
224
225     screen = DefaultScreen(display);
226
227     int major = 0, minor = 0;
228     glXQueryVersion(display, &major, &minor);
229     glxVersion = (major << 8) | minor;
230
231     extensions = glXQueryExtensionsString(display, screen);
232     has_GLX_ARB_create_context = checkExtension("GLX_ARB_create_context", extensions);
233 }
234
235 void
236 cleanup(void) {
237     if (display) {
238         XCloseDisplay(display);
239         display = NULL;
240     }
241 }
242
243 Visual *
244 createVisual(bool doubleBuffer) {
245     GlxVisual *visual = new GlxVisual;
246
247     if (glxVersion >= 0x0103) {
248         Attributes<int> attribs;
249         attribs.add(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
250         attribs.add(GLX_RENDER_TYPE, GLX_RGBA_BIT);
251         attribs.add(GLX_RED_SIZE, 1);
252         attribs.add(GLX_GREEN_SIZE, 1);
253         attribs.add(GLX_BLUE_SIZE, 1);
254         attribs.add(GLX_ALPHA_SIZE, 1);
255         attribs.add(GLX_DOUBLEBUFFER, doubleBuffer ? GL_TRUE : GL_FALSE);
256         attribs.add(GLX_DEPTH_SIZE, 1);
257         attribs.add(GLX_STENCIL_SIZE, 1);
258         attribs.end();
259
260         int num_configs = 0;
261         GLXFBConfig * fbconfigs;
262         fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_configs);
263         assert(num_configs && fbconfigs);
264         visual->fbconfig = fbconfigs[0];
265         assert(visual->fbconfig);
266         visual->visinfo = glXGetVisualFromFBConfig(display, visual->fbconfig);
267         assert(visual->visinfo);
268     } else {
269         Attributes<int> attribs;
270         attribs.add(GLX_RGBA);
271         attribs.add(GLX_RED_SIZE, 1);
272         attribs.add(GLX_GREEN_SIZE, 1);
273         attribs.add(GLX_BLUE_SIZE, 1);
274         attribs.add(GLX_ALPHA_SIZE, 1);
275         if (doubleBuffer) {
276             attribs.add(GLX_DOUBLEBUFFER);
277         }
278         attribs.add(GLX_DEPTH_SIZE, 1);
279         attribs.add(GLX_STENCIL_SIZE, 1);
280         attribs.end();
281
282         visual->visinfo = glXChooseVisual(display, screen, attribs);
283     }
284
285     return visual;
286 }
287
288 Drawable *
289 createDrawable(const Visual *visual, int width, int height)
290 {
291     return new GlxDrawable(visual, width, height);
292 }
293
294 Context *
295 createContext(const Visual *_visual, Context *shareContext, Profile profile)
296 {
297     const GlxVisual *visual = static_cast<const GlxVisual *>(_visual);
298     GLXContext share_context = NULL;
299     GLXContext context;
300
301     if (profile != PROFILE_COMPAT) {
302         return NULL;
303     }
304
305     if (shareContext) {
306         share_context = static_cast<GlxContext*>(shareContext)->context;
307     }
308
309     if (glxVersion >= 0x0104 && has_GLX_ARB_create_context) {
310         Attributes<int> attribs;
311         attribs.add(GLX_RENDER_TYPE, GLX_RGBA_TYPE);
312         if (debug) {
313             attribs.add(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
314         }
315         attribs.end();
316
317         context = glXCreateContextAttribsARB(display, visual->fbconfig, share_context, True, attribs);
318     } else 
319            if (glxVersion >= 0x103) {
320         context = glXCreateNewContext(display, visual->fbconfig, GLX_RGBA_TYPE, share_context, True);
321     } else {
322         context = glXCreateContext(display, visual->visinfo, share_context, True);
323     }
324
325     return new GlxContext(visual, profile, context);
326 }
327
328 bool
329 makeCurrent(Drawable *drawable, Context *context)
330 {
331     if (!drawable || !context) {
332         return glXMakeCurrent(display, None, NULL);
333     } else {
334         GlxDrawable *glxDrawable = static_cast<GlxDrawable *>(drawable);
335         GlxContext *glxContext = static_cast<GlxContext *>(context);
336
337         return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
338     }
339 }
340
341 bool
342 processEvents(void) {
343     while (XPending(display) > 0) {
344         XEvent event;
345         XNextEvent(display, &event);
346         describeEvent(event);
347     }
348     return true;
349 }
350
351
352 } /* namespace glws */