glxheads.c revision 32001f49
1
2/*
3 * Exercise multiple GLX connections on multiple X displays.
4 * Direct GLX contexts are attempted first, then indirect.
5 * Each window will display a spinning green triangle.
6 *
7 * Copyright (C) 2000  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28#include <GL/gl.h>
29#include <GL/glx.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34
35
36
37/*
38 * Each display/window/context:
39 */
40struct head {
41   char DisplayName[1000];
42   Display *Dpy;
43   Window Win;
44   GLXContext Context;
45   float Angle;
46   char Renderer[1000];
47   char Vendor[1000];
48   char Version[1000];
49};
50
51
52#define MAX_HEADS 20
53static struct head Heads[MAX_HEADS];
54static int NumHeads = 0;
55
56
57static void
58Error(const char *display, const char *msg)
59{
60   fprintf(stderr, "Error on display %s - %s\n", XDisplayName(display), msg);
61   exit(1);
62}
63
64
65static struct head *
66AddHead(const char *displayName)
67{
68   Display *dpy;
69   Window win;
70   GLXContext ctx;
71   int attrib[] = { GLX_RGBA,
72		    GLX_RED_SIZE, 1,
73		    GLX_GREEN_SIZE, 1,
74		    GLX_BLUE_SIZE, 1,
75		    GLX_DOUBLEBUFFER,
76		    None };
77   int scrnum;
78   XSetWindowAttributes attr;
79   unsigned long mask;
80   Window root;
81   XVisualInfo *visinfo;
82   int width = 300, height = 300;
83   int xpos = 10, ypos = 10;
84
85   if (NumHeads >= MAX_HEADS)
86      return NULL;
87
88   dpy = XOpenDisplay(displayName);
89   if (!dpy) {
90      Error(displayName, "Unable to open display");
91      return NULL;
92   }
93
94   scrnum = DefaultScreen(dpy);
95   root = RootWindow(dpy, scrnum);
96
97   visinfo = glXChooseVisual(dpy, scrnum, attrib);
98   if (!visinfo) {
99      Error(displayName, "Unable to find RGB, double-buffered visual");
100      return NULL;
101   }
102
103   /* window attributes */
104   attr.background_pixel = 0;
105   attr.border_pixel = 0;
106   attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
107   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
108   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
109
110   win = XCreateWindow(dpy, root, 0, 0, width, height,
111		        0, visinfo->depth, InputOutput,
112		        visinfo->visual, mask, &attr);
113   if (!win) {
114      Error(displayName, "Couldn't create window");
115      return NULL;
116   }
117
118   {
119      XSizeHints sizehints;
120      sizehints.x = xpos;
121      sizehints.y = ypos;
122      sizehints.width  = width;
123      sizehints.height = height;
124      sizehints.flags = USSize | USPosition;
125      XSetNormalHints(dpy, win, &sizehints);
126      XSetStandardProperties(dpy, win, displayName, displayName,
127                              None, (char **)NULL, 0, &sizehints);
128   }
129
130
131   ctx = glXCreateContext(dpy, visinfo, NULL, True);
132   if (!ctx) {
133      Error(displayName, "Couldn't create GLX context");
134      return NULL;
135   }
136
137   XMapWindow(dpy, win);
138
139   if (!glXMakeCurrent(dpy, win, ctx)) {
140      Error(displayName, "glXMakeCurrent failed");
141      printf("glXMakeCurrent failed in Redraw()\n");
142      return NULL;
143   }
144
145   /* save the info for this head */
146   {
147      struct head *h = &Heads[NumHeads];
148      const char * tmp;
149
150      if (strlen(displayName) + 1 > sizeof(h->DisplayName)) {
151         Error(displayName, "displayName string length overflow");
152         return NULL;
153      }
154      strcpy(h->DisplayName, displayName);
155
156      h->Dpy = dpy;
157      h->Win = win;
158      h->Context = ctx;
159      h->Angle = 0.0;
160
161      tmp = (char *) glGetString(GL_VERSION);
162      if (strlen(tmp) + 1 > sizeof(h->Version)) {
163         Error(displayName, "GL_VERSION string length overflow");
164         return NULL;
165      }
166      strcpy(h->Version, tmp);
167
168      tmp = (char *) glGetString(GL_VENDOR);
169      if (strlen(tmp) + 1 > sizeof(h->Vendor)) {
170         Error(displayName, "GL_VENDOR string length overflow");
171         return NULL;
172      }
173      strcpy(h->Vendor, tmp);
174
175      tmp = (char *) glGetString(GL_RENDERER);
176      if (strlen(tmp) + 1 > sizeof(h->Renderer)) {
177         Error(displayName, "GL_RENDERER string length overflow");
178         return NULL;
179      }
180      strcpy(h->Renderer, tmp);
181
182      NumHeads++;
183      return &Heads[NumHeads-1];
184   }
185
186}
187
188
189static void
190Redraw(struct head *h)
191{
192   if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
193      Error(h->DisplayName, "glXMakeCurrent failed");
194      printf("glXMakeCurrent failed in Redraw()\n");
195      return;
196   }
197
198   h->Angle += 1.0;
199
200   glShadeModel(GL_FLAT);
201   glClearColor(0.5, 0.5, 0.5, 1.0);
202   glClear(GL_COLOR_BUFFER_BIT);
203
204   /* draw green triangle */
205   glColor3f(0.0, 1.0, 0.0);
206   glPushMatrix();
207   glRotatef(h->Angle, 0, 0, 1);
208   glBegin(GL_TRIANGLES);
209   glVertex2f(0, 0.8);
210   glVertex2f(-0.8, -0.7);
211   glVertex2f(0.8, -0.7);
212   glEnd();
213   glPopMatrix();
214
215   glXSwapBuffers(h->Dpy, h->Win);
216}
217
218
219
220static void
221Resize(const struct head *h, unsigned int width, unsigned int height)
222{
223   if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
224      Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
225      return;
226   }
227   glFlush();
228   glViewport(0, 0, width, height);
229   glMatrixMode(GL_PROJECTION);
230   glLoadIdentity();
231   glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
232}
233
234
235
236static void
237EventLoop(void)
238{
239   while (1) {
240      int i;
241      for (i = 0; i < NumHeads; i++) {
242         struct head *h = &Heads[i];
243         while (XPending(h->Dpy) > 0) {
244            XEvent event;
245            XNextEvent(h->Dpy, &event);
246            if (event.xany.window == h->Win) {
247               switch (event.type) {
248                  case Expose:
249                     Redraw(h);
250                     break;
251                  case ConfigureNotify:
252                     Resize(h, event.xconfigure.width, event.xconfigure.height);
253                     break;
254                  case KeyPress:
255                     return;
256                  default:
257                     /*no-op*/ ;
258               }
259            }
260            else {
261               printf("window mismatch\n");
262            }
263         }
264         Redraw(h);
265      }
266      usleep(1);
267   }
268}
269
270
271
272static void
273PrintInfo(const struct head *h)
274{
275   printf("Name: %s\n", h->DisplayName);
276   printf("  Display:     %p\n", (void *) h->Dpy);
277   printf("  Window:      0x%x\n", (int) h->Win);
278   printf("  Context:     0x%lx\n", (long) h->Context);
279   printf("  GL_VERSION:  %s\n", h->Version);
280   printf("  GL_VENDOR:   %s\n", h->Vendor);
281   printf("  GL_RENDERER: %s\n", h->Renderer);
282}
283
284
285int
286main(int argc, char *argv[])
287{
288   int i;
289   if (argc == 1) {
290      struct head *h;
291      printf("glxheads: exercise multiple GLX connections (any key = exit)\n");
292      printf("Usage:\n");
293      printf("  glxheads xdisplayname ...\n");
294      printf("Example:\n");
295      printf("  glxheads :0 mars:0 venus:1\n");
296
297      h = AddHead(XDisplayName(NULL));
298      if (h)
299         PrintInfo(h);
300   }
301   else {
302      for (i = 1; i < argc; i++) {
303         const char *name = argv[i];
304         struct head *h = AddHead(name);
305         if (h) {
306            PrintInfo(h);
307         }
308      }
309   }
310
311   EventLoop();
312   return 0;
313}
314