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.
7 * Copyright (C) 2000 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
38 * Each display/window/context:
41 char DisplayName
[1000];
53 static struct head Heads
[MAX_HEADS
];
54 static int NumHeads
= 0;
58 Error(const char *display
, const char *msg
)
60 fprintf(stderr
, "Error on display %s - %s\n", XDisplayName(display
), msg
);
66 AddHead(const char *displayName
)
71 int attrib
[] = { GLX_RGBA
,
78 XSetWindowAttributes attr
;
82 int width
= 300, height
= 300;
83 int xpos
= 10, ypos
= 10;
85 if (NumHeads
>= MAX_HEADS
)
88 dpy
= XOpenDisplay(displayName
);
90 Error(displayName
, "Unable to open display");
94 scrnum
= DefaultScreen(dpy
);
95 root
= RootWindow(dpy
, scrnum
);
97 visinfo
= glXChooseVisual(dpy
, scrnum
, attrib
);
99 Error(displayName
, "Unable to find RGB, double-buffered visual");
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
;
110 win
= XCreateWindow(dpy
, root
, 0, 0, width
, height
,
111 0, visinfo
->depth
, InputOutput
,
112 visinfo
->visual
, mask
, &attr
);
114 Error(displayName
, "Couldn't create window");
119 XSizeHints sizehints
;
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
);
131 ctx
= glXCreateContext(dpy
, visinfo
, NULL
, True
);
133 Error(displayName
, "Couldn't create GLX context");
137 XMapWindow(dpy
, win
);
139 if (!glXMakeCurrent(dpy
, win
, ctx
)) {
140 Error(displayName
, "glXMakeCurrent failed");
141 printf("glXMakeCurrent failed in Redraw()\n");
145 /* save the info for this head */
147 struct head
*h
= &Heads
[NumHeads
];
150 if (strlen(displayName
) + 1 > sizeof(h
->DisplayName
)) {
151 Error(displayName
, "displayName string length overflow");
154 strcpy(h
->DisplayName
, displayName
);
161 tmp
= (char *) glGetString(GL_VERSION
);
162 if (strlen(tmp
) + 1 > sizeof(h
->Version
)) {
163 Error(displayName
, "GL_VERSION string length overflow");
166 strcpy(h
->Version
, tmp
);
168 tmp
= (char *) glGetString(GL_VENDOR
);
169 if (strlen(tmp
) + 1 > sizeof(h
->Vendor
)) {
170 Error(displayName
, "GL_VENDOR string length overflow");
173 strcpy(h
->Vendor
, tmp
);
175 tmp
= (char *) glGetString(GL_RENDERER
);
176 if (strlen(tmp
) + 1 > sizeof(h
->Renderer
)) {
177 Error(displayName
, "GL_RENDERER string length overflow");
180 strcpy(h
->Renderer
, tmp
);
183 return &Heads
[NumHeads
-1];
190 Redraw(struct head
*h
)
192 if (!glXMakeCurrent(h
->Dpy
, h
->Win
, h
->Context
)) {
193 Error(h
->DisplayName
, "glXMakeCurrent failed");
194 printf("glXMakeCurrent failed in Redraw()\n");
200 glShadeModel(GL_FLAT
);
201 glClearColor(0.5, 0.5, 0.5, 1.0);
202 glClear(GL_COLOR_BUFFER_BIT
);
204 /* draw green triangle */
205 glColor3f(0.0, 1.0, 0.0);
207 glRotatef(h
->Angle
, 0, 0, 1);
208 glBegin(GL_TRIANGLES
);
210 glVertex2f(-0.8, -0.7);
211 glVertex2f(0.8, -0.7);
215 glXSwapBuffers(h
->Dpy
, h
->Win
);
221 Resize(const struct head
*h
, unsigned int width
, unsigned int height
)
223 if (!glXMakeCurrent(h
->Dpy
, h
->Win
, h
->Context
)) {
224 Error(h
->DisplayName
, "glXMakeCurrent failed in Resize()");
228 glViewport(0, 0, width
, height
);
229 glMatrixMode(GL_PROJECTION
);
231 glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
241 for (i
= 0; i
< NumHeads
; i
++) {
242 struct head
*h
= &Heads
[i
];
243 while (XPending(h
->Dpy
) > 0) {
245 XNextEvent(h
->Dpy
, &event
);
246 if (event
.xany
.window
== h
->Win
) {
247 switch (event
.type
) {
251 case ConfigureNotify
:
252 Resize(h
, event
.xconfigure
.width
, event
.xconfigure
.height
);
261 printf("window mismatch\n");
273 PrintInfo(const struct head
*h
)
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
);
286 main(int argc
, char *argv
[])
291 printf("glxheads: exercise multiple GLX connections (any key = exit)\n");
293 printf(" glxheads xdisplayname ...\n");
294 printf("Example:\n");
295 printf(" glxheads :0 mars:0 venus:1\n");
297 h
= AddHead(XDisplayName(NULL
));
302 for (i
= 1; i
< argc
; i
++) {
303 const char *name
= argv
[i
];
304 struct head
*h
= AddHead(name
);