1
2/* Copyright (c) Mark J. Kilgard, 1994, 1997. */
3
4/* This program is freely distributable without licensing fees
5   and is provided without guarantee or warrantee expressed or
6   implied. This program is -not- in the public domain. */
7
8#ifdef __VMS
9#include <GL/vms_x_fix.h>
10#endif
11
12#include <stdlib.h>
13#include <string.h>
14#include <stdio.h>
15
16#if !defined(_WIN32)
17#include <X11/Xlib.h>
18#endif
19
20/* SGI optimization introduced in IRIX 6.3 to avoid X server
21   round trips for interning common X atoms. */
22#if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
23#include <X11/SGIFastAtom.h>
24#else
25#define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
26#endif
27
28#include "glutint.h"
29
30/* GLUT inter-file variables */
31/* *INDENT-OFF* */
32char *__glutProgramName = NULL;
33int __glutArgc = 0;
34char **__glutArgv = NULL;
35char *__glutGeometry = NULL;
36Display *__glutDisplay = NULL;
37int __glutScreen;
38Window __glutRoot;
39int __glutScreenHeight;
40int __glutScreenWidth;
41GLboolean __glutIconic = GL_FALSE;
42GLboolean __glutDebug = GL_FALSE;
43unsigned int __glutDisplayMode =
44  GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH;
45char *__glutDisplayString = NULL;
46int __glutConnectionFD;
47XSizeHints __glutSizeHints = {0};
48int __glutInitWidth = 300, __glutInitHeight = 300;
49int __glutInitX = -1, __glutInitY = -1;
50GLboolean __glutForceDirect = GL_FALSE,
51  __glutTryDirect = GL_TRUE;
52Atom __glutWMDeleteWindow;
53char *__glutPPMFile = NULL;
54/* *INDENT-ON* */
55
56#ifdef _WIN32
57void (__cdecl *__glutExitFunc)(int retval) = NULL;
58#endif
59
60static Bool synchronize = False;
61
62#if defined(_WIN32)
63
64#ifdef __BORLANDC__
65#include <float.h>  /* For masking floating point exceptions. */
66#endif
67
68void
69__glutOpenWin32Connection(char* display)
70{
71  static char *classname;
72  WNDCLASS  wc;
73  HINSTANCE hInstance = GetModuleHandle(NULL);
74
75  /* Make sure we register the window only once. */
76  if(classname)
77    return;
78
79#ifdef __BORLANDC__
80  /* Under certain conditions (e.g. while rendering solid surfaces with
81     lighting enabled) Microsoft OpenGL libraries cause some illegal
82     operations like floating point overflow or division by zero. The
83     default behaviour of Microsoft compilers is to mask (ignore)
84     floating point exceptions, while Borland compilers do not.  The
85     following function of Borland RTL allows to mask exceptions.
86     Advice from Pier Giorgio Esposito (mc2172@mclink.it). */
87  _control87(MCW_EM,MCW_EM);
88#endif
89
90  classname = "GLUT";
91
92  /* Clear (important!) and then fill in the window class structure. */
93  memset(&wc, 0, sizeof(WNDCLASS));
94  wc.style         = CS_OWNDC;
95  wc.lpfnWndProc   = (WNDPROC)__glutWindowProc;
96  wc.hInstance     = hInstance;
97  wc.hIcon         = LoadIcon(hInstance, "GLUT_ICON");
98  wc.hCursor       = LoadCursor(hInstance, IDC_ARROW);
99  wc.hbrBackground = NULL;
100  wc.lpszMenuName  = NULL;
101  wc.lpszClassName = classname;
102
103  /* Fill in a default icon if one isn't specified as a resource. */
104  if(!wc.hIcon)
105    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
106
107  if(!RegisterClass(&wc)) {
108    __glutFatalError("RegisterClass() failed:"
109		     "Cannot register GLUT window class.");
110  }
111
112  __glutScreenWidth     = GetSystemMetrics(SM_CXSCREEN);
113  __glutScreenHeight    = GetSystemMetrics(SM_CYSCREEN);
114
115  /* Set the root window to NULL because windows creates a top-level
116     window when the parent is NULL.  X creates a top-level window
117     when the parent is the root window. */
118  __glutRoot            = NULL;
119
120  /* Set the display to 1 -- we shouldn't be using this anywhere
121     (except as an argument to X calls). */
122  __glutDisplay         = (Display*)1;
123
124  /* There isn't any concept of multiple screens in Win32, therefore,
125     we don't need to keep track of the screen we're on... it's always
126     the same one. */
127  __glutScreen          = 0;
128}
129#else /* !_WIN32 */
130void
131__glutOpenXConnection(char *display)
132{
133  int errorBase, eventBase;
134
135  __glutDisplay = XOpenDisplay(display);
136  if (!__glutDisplay)
137    __glutFatalError("could not open display: %s",
138      XDisplayName(display));
139  if (synchronize)
140    XSynchronize(__glutDisplay, True);
141  if (!glXQueryExtension(__glutDisplay, &errorBase, &eventBase))
142    __glutFatalError(
143      "OpenGL GLX extension not supported by display: %s",
144      XDisplayName(display));
145  __glutScreen = DefaultScreen(__glutDisplay);
146  __glutRoot = RootWindow(__glutDisplay, __glutScreen);
147  __glutScreenWidth = DisplayWidth(__glutDisplay, __glutScreen);
148  __glutScreenHeight = DisplayHeight(__glutDisplay,
149    __glutScreen);
150  __glutConnectionFD = ConnectionNumber(__glutDisplay);
151  __glutWMDeleteWindow = XSGIFastInternAtom(__glutDisplay,
152    "WM_DELETE_WINDOW", SGI_XA_WM_DELETE_WINDOW, False);
153}
154#endif /* _WIN32 */
155
156void
157#ifdef OLD_VMS
158  __glutInitTime(struct timeval6 *beginning)
159#else
160  __glutInitTime(struct timeval *beginning)
161#endif
162{
163  static int beenhere = 0;
164#ifdef OLD_VMS
165   static struct timeval6 genesis;
166#else
167   static struct timeval genesis;
168#endif
169
170  if (!beenhere) {
171    GETTIMEOFDAY(&genesis);
172    beenhere = 1;
173  }
174  *beginning = genesis;
175}
176
177static void
178removeArgs(int *argcp, char **argv, int numToRemove)
179{
180  int i, j;
181
182  for (i = 0, j = numToRemove; argv[j]; i++, j++) {
183    argv[i] = argv[j];
184  }
185  argv[i] = NULL;
186  *argcp -= numToRemove;
187}
188
189void GLUTAPIENTRY
190glutInit(int *argcp, char **argv)
191{
192  char *display = NULL;
193  char *str, *geometry = NULL;
194#ifdef OLD_VMS
195   struct timeval6 unused;
196#else
197   struct timeval unused;
198#endif
199   int i;
200
201  if (__glutDisplay) {
202    __glutWarning("glutInit being called a second time.");
203    return;
204  }
205  /* Determine temporary program name. */
206  str = strrchr(argv[0], '/');
207  if (str == NULL) {
208    __glutProgramName = argv[0];
209  } else {
210    __glutProgramName = str + 1;
211  }
212
213  /* Make private copy of command line arguments. */
214  __glutArgc = *argcp;
215  __glutArgv = (char **) malloc(__glutArgc * sizeof(char *));
216  if (!__glutArgv)
217    __glutFatalError("out of memory.");
218  for (i = 0; i < __glutArgc; i++) {
219    __glutArgv[i] = __glutStrdup(argv[i]);
220    if (!__glutArgv[i])
221      __glutFatalError("out of memory.");
222  }
223
224  /* determine permanent program name */
225  str = strrchr(__glutArgv[0], '/');
226  if (str == NULL) {
227    __glutProgramName = __glutArgv[0];
228  } else {
229    __glutProgramName = str + 1;
230  }
231
232  /* parse arguments for standard options */
233  for (i = 1; i < __glutArgc; i++) {
234    if (!strcmp(__glutArgv[i], "-display")) {
235#if defined(_WIN32)
236      __glutWarning("-display option not supported by Win32 GLUT.");
237#endif
238      if (++i >= __glutArgc) {
239        __glutFatalError(
240          "follow -display option with X display name.");
241      }
242      display = __glutArgv[i];
243      removeArgs(argcp, &argv[1], 2);
244    } else if (!strcmp(__glutArgv[i], "-geometry")) {
245      if (++i >= __glutArgc) {
246        __glutFatalError(
247          "follow -geometry option with geometry parameter.");
248      }
249      geometry = __glutArgv[i];
250      removeArgs(argcp, &argv[1], 2);
251    } else if (!strcmp(__glutArgv[i], "-direct")) {
252#if defined(_WIN32)
253      __glutWarning("-direct option not supported by Win32 GLUT.");
254#endif
255      if (!__glutTryDirect)
256        __glutFatalError(
257          "cannot force both direct and indirect rendering.");
258      __glutForceDirect = GL_TRUE;
259      removeArgs(argcp, &argv[1], 1);
260    } else if (!strcmp(__glutArgv[i], "-indirect")) {
261#if defined(_WIN32)
262      __glutWarning("-indirect option not supported by Win32 GLUT.");
263#endif
264      if (__glutForceDirect)
265        __glutFatalError(
266          "cannot force both direct and indirect rendering.");
267      __glutTryDirect = GL_FALSE;
268      removeArgs(argcp, &argv[1], 1);
269    } else if (!strcmp(__glutArgv[i], "-iconic")) {
270      __glutIconic = GL_TRUE;
271      removeArgs(argcp, &argv[1], 1);
272    } else if (!strcmp(__glutArgv[i], "-gldebug")) {
273      __glutDebug = GL_TRUE;
274      removeArgs(argcp, &argv[1], 1);
275    } else if (!strcmp(__glutArgv[i], "-sync")) {
276#if defined(_WIN32)
277      __glutWarning("-sync option not supported by Win32 GLUT.");
278#endif
279      synchronize = GL_TRUE;
280      removeArgs(argcp, &argv[1], 1);
281    } else {
282      /* Once unknown option encountered, stop command line
283         processing. */
284      break;
285    }
286  }
287#if defined(_WIN32)
288  __glutOpenWin32Connection(display);
289#else
290  __glutOpenXConnection(display);
291#endif
292  if (geometry) {
293    int flags, x, y, width, height;
294
295    /* Fix bogus "{width|height} may be used before set"
296       warning */
297    width = 0;
298    height = 0;
299
300    flags = XParseGeometry(geometry, &x, &y,
301      (unsigned int *) &width, (unsigned int *) &height);
302    if (WidthValue & flags) {
303      /* Careful because X does not allow zero or negative
304         width windows */
305      if (width > 0)
306        __glutInitWidth = width;
307    }
308    if (HeightValue & flags) {
309      /* Careful because X does not allow zero or negative
310         height windows */
311      if (height > 0)
312        __glutInitHeight = height;
313    }
314    glutInitWindowSize(__glutInitWidth, __glutInitHeight);
315    if (XValue & flags) {
316      if (XNegative & flags)
317        x = DisplayWidth(__glutDisplay, __glutScreen) +
318          x - __glutSizeHints.width;
319      /* Play safe: reject negative X locations */
320      if (x >= 0)
321        __glutInitX = x;
322    }
323    if (YValue & flags) {
324      if (YNegative & flags)
325        y = DisplayHeight(__glutDisplay, __glutScreen) +
326          y - __glutSizeHints.height;
327      /* Play safe: reject negative Y locations */
328      if (y >= 0)
329        __glutInitY = y;
330    }
331    glutInitWindowPosition(__glutInitX, __glutInitY);
332  }
333  __glutInitTime(&unused);
334
335  /* check if GLUT_FPS env var is set */
336  {
337     const char *fps = getenv("GLUT_FPS");
338     if (fps) {
339        sscanf(fps, "%d", &__glutFPS);
340        if (__glutFPS <= 0)
341           __glutFPS = 5000;  /* 5000 milliseconds */
342     }
343  }
344
345  /* check if GLUT_PPM_FILE env var is set */
346  __glutPPMFile = getenv("GLUT_PPM_FILE");
347}
348
349#ifdef _WIN32
350void GLUTAPIENTRY
351__glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int))
352{
353  __glutExitFunc = exitfunc;
354  glutInit(argcp, argv);
355}
356#endif
357
358/* CENTRY */
359void GLUTAPIENTRY
360glutInitWindowPosition(int x, int y)
361{
362  __glutInitX = x;
363  __glutInitY = y;
364  if (x >= 0 && y >= 0) {
365    __glutSizeHints.x = x;
366    __glutSizeHints.y = y;
367    __glutSizeHints.flags |= USPosition;
368  } else {
369    __glutSizeHints.flags &= ~USPosition;
370  }
371}
372
373void GLUTAPIENTRY
374glutInitWindowSize(int width, int height)
375{
376  __glutInitWidth = width;
377  __glutInitHeight = height;
378  if (width > 0 && height > 0) {
379    __glutSizeHints.width = width;
380    __glutSizeHints.height = height;
381    __glutSizeHints.flags |= USSize;
382  } else {
383    __glutSizeHints.flags &= ~USSize;
384  }
385}
386
387void GLUTAPIENTRY
388glutInitDisplayMode(unsigned int mask)
389{
390  __glutDisplayMode = mask;
391}
392
393/* ENDCENTRY */
394