/* This program demonstrates a gl_available() function that tells you
 * whether the current system has a display capable of running GL
 * programs.
 *
 * The program is not linked against libGL.
 *
 * Build with:
 *   gcc -g -Wall -W testglx.c -L/usr/X11R6/lib/ -lX11 -ldl -o testglx
 *
 * With the exception of the screen_number() function this program was
 * written by Johan Walles, walles@mailblocks.com 2005may21.  All code
 * except for screen_number() is placed in the public domain, do with
 * it what you wish.
 */

/*
 * screen_number() was taken from visual.c of XScreensaver 4.21.  It
 * comes with the following license agreement:
 *
 * xscreensaver, Copyright (c) 2000, 2002 by Jamie Zawinski <jwz@jwz.org>
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation.  No representations are made about the suitability of this
 * software for any purpose.  It is provided "as is" without express or
 * implied warranty.
 */

#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include <dlfcn.h>

#include <stdio.h>  // For printf()
#include <stdlib.h> // For abort()

typedef XVisualInfo* (*glXChooseVisual_t)(Display *dpy,
					  int screen,
					  int *attribList);

/* This function stolen from XScreensaver, visual.c */
int
screen_number (Screen *screen)
{
  Display *dpy = DisplayOfScreen (screen);
  int i;
  for (i = 0; i < ScreenCount (dpy); i++)
    if (ScreenOfDisplay (dpy, i) == screen)
      return i;
  abort ();
  return 0;
}


/* Return 1 if this system can run GL programs, 0 otherwise. */
int
gl_available()
{
  int returnMe = 0;
  Display *display;
  Screen *screen;
  void *libGl;
  glXChooseVisual_t glXChooseVisual;
  XVisualInfo *glXVisual;
  int attribList[] = { None };
  
  display = XOpenDisplay(NULL);
  if (display == NULL)
  {
    // No X
    goto fail;
  }
  
  libGl = dlopen("libGL.so.1", RTLD_LAZY);
  if (libGl == NULL)
  {
    // No GL library
    goto fail;
  }

  glXChooseVisual = dlsym(libGl, "glXChooseVisual");
  if (glXChooseVisual == NULL)
  {
    // The GL library doesn't contain any glXChooseVisual()!
    goto closeLib;
  }

  screen = DefaultScreenOfDisplay(display);
  glXVisual = glXChooseVisual(display, screen_number(screen), attribList);
  if (glXVisual != NULL)
  {
    returnMe = 1;
  }
  
 closeLib:
  dlclose(libGl);
 fail:
  return returnMe;
}

int main(int argc, char *argv[])
{
  (void)argc;
  (void)argv;
  
  printf("Your system %s GL programs.\n", gl_available() ? "can run" : "can not run");
  
  return 0;
}
