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