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