1/*
2 * Client application for querying drivers' configuration information
3 * Copyright (C) 2003 Felix Kuehling
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * FELIX KUEHLING, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
21 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25#ifdef HAVE_CONFIG_H
26# include "config.h"
27#endif
28
29#define GLX_GLXEXT_PROTOTYPES
30#include <GL/glx.h>
31#include <GL/glxext.h>
32#include <X11/Xlib.h>
33#include <stdio.h>
34#include <unistd.h>
35#include <string.h>
36
37typedef const char * glXGetScreenDriver_t (Display *dpy, int scrNum);
38typedef const char * glXGetDriverConfig_t (const char *driverName);
39
40static glXGetScreenDriver_t *GetScreenDriver;
41static glXGetDriverConfig_t *GetDriverConfig;
42
43enum INFO_FUNC {
44    LIST, NSCREENS, DRIVER, OPTIONS
45};
46
47void printUsage (void);
48
49void printUsage (void) {
50    fprintf (stderr,
51"Usage: xdriinfo [-display <dpy>] [-version] [command]\n"
52"Commands:\n"
53"  nscreens               print the number of screens on display\n"
54"  driver screen          print the DRI driver name of screen\n"
55"  options screen|driver  print configuration information about screen or driver\n"
56"If no command is given then the DRI drivers for all screens are listed.\n");
57}
58
59int main (int argc, char *argv[]) {
60    Display *dpy;
61    int nScreens, screenNum;
62    enum INFO_FUNC func = LIST;
63    char *funcArg = NULL;
64    char *dpyName = NULL;
65
66    GetScreenDriver = (glXGetScreenDriver_t *)glXGetProcAddressARB ((const GLubyte *)"glXGetScreenDriver");
67    GetDriverConfig = (glXGetDriverConfig_t *)glXGetProcAddressARB ((const GLubyte *)"glXGetDriverConfig");
68    if (!GetScreenDriver || !GetDriverConfig) {
69	fprintf (stderr, "libGL is too old.\n");
70	return 1;
71    }
72
73  /* parse the command line */
74    for (int i = 1; i < argc; ++i) {
75	char **argPtr = NULL;
76	if (!strcmp (argv[i], "-display"))
77	    argPtr = &dpyName;
78	else if (!strcmp (argv[i], "nscreens"))
79	    func = NSCREENS;
80	else if (!strcmp (argv[i], "driver")) {
81	    func = DRIVER;
82	    argPtr = &funcArg;
83	} else if (!strcmp (argv[i], "options")) {
84	    func = OPTIONS;
85	    argPtr = &funcArg;
86	} else if (!strcmp (argv[i], "-version")) {
87	    puts(PACKAGE_STRING);
88	    return 0;
89	} else {
90	    fprintf (stderr, "%s: unrecognized argument '%s'\n",
91		     argv[0], argv[i]);
92	    printUsage ();
93	    return 1;
94	}
95	if (argPtr) {
96	    if (++i == argc) {
97		fprintf (stderr, "%s: '%s' requires an argument\n",
98			 argv[0], argv[i-1]);
99		printUsage ();
100		return 1;
101	    }
102	    *argPtr = argv[i];
103	}
104    }
105
106  /* parse screen number argument */
107    if (func == DRIVER || func == OPTIONS) {
108	if (sscanf (funcArg, "%i", &screenNum) != 1)
109	    screenNum = -1;
110	else if (screenNum < 0) {
111	    fprintf (stderr, "Negative screen number \"%s\".\n", funcArg);
112	    return 1;
113	}
114    }
115    else
116        screenNum = -1;
117
118  /* driver command needs a valid screen number */
119    if (func == DRIVER && screenNum == -1) {
120	fprintf (stderr, "Invalid screen number \"%s\".\n", funcArg);
121	return 1;
122    }
123
124  /* open display and count the number of screens */
125    if (!(dpy = XOpenDisplay (dpyName))) {
126	fprintf (stderr, "Error: Couldn't open display\n");
127	return 1;
128    }
129    nScreens = ScreenCount (dpy);
130
131  /* final check on the screen number argument (if any)*/
132    if ((func == DRIVER || func == OPTIONS) && screenNum >= nScreens) {
133	fprintf (stderr, "Screen number \"%d\" out of range.\n", screenNum);
134	return 1;
135    }
136
137   /* Call glXGetClientString to load vendor libs on glvnd enabled systems */
138    glXGetClientString (dpy, GLX_EXTENSIONS);
139
140    switch (func) {
141      case NSCREENS:
142	printf ("%d", nScreens);
143	if (isatty (STDOUT_FILENO))
144	    printf ("\n");
145	break;
146      case DRIVER: {
147	  const char *name = (*GetScreenDriver) (dpy, screenNum);
148	  if (!name) {
149	      fprintf (stderr, "Screen \"%d\" is not direct rendering capable.\n",
150		       screenNum);
151	      return 1;
152	  }
153	  printf ("%s", name);
154	  if (isatty (STDOUT_FILENO))
155	      printf ("\n");
156	  break;
157      }
158      case OPTIONS: {
159	  const char *name, *options;
160
161	  if (screenNum == -1) {
162	      name = funcArg;
163	  } else {
164	      name = (*GetScreenDriver) (dpy, screenNum);
165	  }
166	  if (!name) {
167	      fprintf (stderr, "Screen \"%d\" is not direct rendering capable.\n",
168		       screenNum);
169	      return 1;
170	  }
171	  options = (*GetDriverConfig) (name);
172	  if (!options) {
173	      fprintf (stderr,
174		       "Driver \"%s\" is not installed or does not support configuration.\n",
175		       name);
176	      return 1;
177	  }
178	  printf ("%s", options);
179	  if (isatty (STDOUT_FILENO))
180	      printf ("\n");
181	  break;
182      }
183      case LIST:
184	for (int i = 0; i < nScreens; ++i) {
185	    const char *name = (*GetScreenDriver) (dpy, i);
186	    if (name)
187		printf ("Screen %d: %s\n", i, name);
188	    else
189		printf ("Screen %d: not direct rendering capable.\n", i);
190	}
191    }
192
193    return 0;
194}
195