Implementing John Tsiombikas' game mode patch per e-mail dated 3/15/11 8:04 PM
[freeglut] / src / freeglut_window.c
index 232f4ea..fc9fc55 100644 (file)
@@ -31,6 +31,7 @@
 
 #if TARGET_HOST_POSIX_X11
 #include <limits.h>  /* LONG_MAX */
+#include <unistd.h>  /* usleep */
 #endif
 
 #if defined(_WIN32_WCE)
@@ -220,7 +221,7 @@ static void fghContextCreationError( void )
  * Chooses a visual basing on the current display mode settings
  */
 
-GLXFBConfig* fgChooseFBConfig( void )
+GLXFBConfig* fgChooseFBConfig( int *numcfgs )
 {
   GLboolean wantIndexedMode = GL_FALSE;
   int attributes[ 100 ];
@@ -385,6 +386,9 @@ GLXFBConfig* fgChooseFBConfig( void )
            fbconfig = NULL;
         }
 
+       if (numcfgs)
+               *numcfgs = fbconfigArraySize;
+
         return fbconfig;
     }
 }
@@ -676,7 +680,7 @@ static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char laye
   ppfd->cGreenShift = 0;
   ppfd->cBlueShift = 0;
   ppfd->cAlphaShift = 0;
-  ppfd->cAccumBits = 0;
+  ppfd->cAccumBits = ( fgState.DisplayMode & GLUT_ACCUM ) ? 1 : 0;
   ppfd->cAccumRedBits = 0;
   ppfd->cAccumGreenBits = 0;
   ppfd->cAccumBlueBits = 0;
@@ -730,9 +734,16 @@ GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
     PIXELFORMATDESCRIPTOR pfd;
     PIXELFORMATDESCRIPTOR* ppfd = &pfd;
     int pixelformat;
+    HDC current_hDC;
+    GLboolean success;
+
+    if (checkOnly)
+      current_hDC = CreateDC(TEXT("DISPLAY"), NULL ,NULL ,NULL);
+    else
+      current_hDC = window->Window.Device;
 
-    fghFillPFD( ppfd, window->Window.Device, layer_type );
-    pixelformat = ChoosePixelFormat( window->Window.Device, ppfd );
+    fghFillPFD( ppfd, current_hDC, layer_type );
+    pixelformat = ChoosePixelFormat( current_hDC, ppfd );
 
     /* windows hack for multismapling/sRGB */
     if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) ||
@@ -754,10 +765,10 @@ GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
         hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 );
         hDC=GetDC(hWnd);
         SetPixelFormat( hDC, pixelformat, ppfd );
-        
+
         rc = wglCreateContext( hDC );
         wglMakeCurrent(hDC, rc);
-        
+
         if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) )
         {
             PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc =
@@ -770,7 +781,7 @@ GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
                 float fAttributes[] = { 0, 0 };
                 UINT numFormats;
                 fghFillPixelFormatAttributes( attributes, ppfd );
-                bValid = wglChoosePixelFormatARBProc(window->Window.Device, attributes, fAttributes, 1, &iPixelFormat, &numFormats);
+                bValid = wglChoosePixelFormatARBProc(hDC, attributes, fAttributes, 1, &iPixelFormat, &numFormats);
 
                 if ( bValid && numFormats > 0 )
                 {
@@ -786,7 +797,12 @@ GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
         UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance);
     }
 
-    return ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( window->Window.Device, pixelformat, ppfd ) );
+    success = ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( current_hDC, pixelformat, ppfd ) );
+
+    if (checkOnly)
+        DeleteDC(current_hDC);
+
+    return success;
 #endif /* defined(_WIN32_WCE) */
 }
 
@@ -809,22 +825,94 @@ void fgSetWindow ( SFG_Window *window )
         );
     }
 #elif TARGET_HOST_MS_WINDOWS
-    if( fgStructure.CurrentWindow )
-        ReleaseDC( fgStructure.CurrentWindow->Window.Handle,
-                   fgStructure.CurrentWindow->Window.Device );
-
-    if ( window )
+    if ( window != fgStructure.CurrentWindow )
     {
-        window->Window.Device = GetDC( window->Window.Handle );
-        wglMakeCurrent(
-            window->Window.Device,
-            window->Window.Context
-        );
+        if( fgStructure.CurrentWindow )
+            ReleaseDC( fgStructure.CurrentWindow->Window.Handle,
+                       fgStructure.CurrentWindow->Window.Device );
+
+        if ( window )
+        {
+            window->Window.Device = GetDC( window->Window.Handle );
+            wglMakeCurrent(
+                window->Window.Device,
+                window->Window.Context
+            );
+        }
     }
 #endif
     fgStructure.CurrentWindow = window;
 }
 
+#if TARGET_HOST_MS_WINDOWS
+
+#if(WINVER >= 0x500)
+typedef struct {
+      int *x;
+      int *y;
+      const char *name;
+}m_proc_t ;
+
+static BOOL CALLBACK m_proc(HMONITOR mon,
+                           HDC hdc,
+                           LPRECT rect,
+                           LPARAM data)
+{
+      m_proc_t *dp=(m_proc_t *)data;
+      MONITORINFOEX info;
+      BOOL res;
+      info.cbSize=sizeof(info);
+      res=GetMonitorInfo(mon,(LPMONITORINFO)&info);
+      if( res )
+      {
+          if( !strcmp(dp->name,info.szDevice) )
+          {
+              *(dp->x)=info.rcMonitor.left;
+              *(dp->y)=info.rcMonitor.top;
+              return FALSE;
+          }
+      }
+      return TRUE;
+}
+
+/* 
+ * this function is only used in fgOpenWindow. Currently it only sets 
+ * its output parameters, if the DisplayName is set in fgDisplay 
+ * (and if it is able to recognize the display)
+ */
+
+static void get_display_origin(int *xp,int *yp)
+{
+    if( fgDisplay.DisplayName )
+    {
+        m_proc_t st;
+        st.x=xp;
+        st.y=yp;
+        st.name=fgDisplay.DisplayName;
+        EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st);
+     }
+}
+#else
+#pragma message( "-display parameter only works if compiled with WINVER >= 0x0500")
+
+static void get_display_origin(int *xp,int *yp)
+{
+    if( fgDisplay.DisplayName )
+    {
+        fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500");
+    }
+}
+#endif
+#endif
+
+
+#if TARGET_HOST_POSIX_X11
+static Bool fghWindowIsVisible( Display *display, XEvent *event, XPointer arg)
+{
+    Window window = arg;
+    return (event->type == MapNotify) && (event->xmap.window == window);
+}
+#endif
 
 
 /*
@@ -842,14 +930,16 @@ void fgOpenWindow( SFG_Window* window, const char* title,
     XTextProperty textProperty;
     XSizeHints sizeHints;
     XWMHints wmHints;
+    XEvent eventReturnBuffer; /* return buffer required for a call */
     unsigned long mask;
+    int num_FBConfigs, i;
     unsigned int current_DisplayMode = fgState.DisplayMode ;
 
     /* Save the display mode if we are creating a menu window */
     if( window->IsMenu && ( ! fgStructure.MenuContext ) )
         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ;
 
-    window->Window.FBConfig = fgChooseFBConfig( );
+    window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs );
 
     if( window->IsMenu && ( ! fgStructure.MenuContext ) )
         fgState.DisplayMode = current_DisplayMode ;
@@ -864,14 +954,14 @@ void fgOpenWindow( SFG_Window* window, const char* title,
         if( !( fgState.DisplayMode & GLUT_DOUBLE ) )
         {
             fgState.DisplayMode |= GLUT_DOUBLE ;
-            window->Window.FBConfig = fgChooseFBConfig( );
+            window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs );
             fgState.DisplayMode &= ~GLUT_DOUBLE;
         }
 
         if( fgState.DisplayMode & GLUT_MULTISAMPLE )
         {
             fgState.DisplayMode &= ~GLUT_MULTISAMPLE ;
-            window->Window.FBConfig = fgChooseFBConfig( );
+            window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs );
             fgState.DisplayMode |= GLUT_MULTISAMPLE;
         }
     }
@@ -880,8 +970,15 @@ void fgOpenWindow( SFG_Window* window, const char* title,
                                   "FBConfig with necessary capabilities not found", "fgOpenWindow" );
 
     /*  Get the X visual.  */
-    visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display,
-                                           *(window->Window.FBConfig) );
+    for (i = 0; i < num_FBConfigs; i++) {
+           visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display,
+                                                  window->Window.FBConfig[i] );
+           if (visualInfo)
+               break;
+    }
+
+    FREEGLUT_INTERNAL_ERROR_EXIT( visualInfo != NULL,
+                                  "visualInfo could not be retrieved from FBConfig", "fgOpenWindow" );
 
     /*
      * XXX HINT: the masks should be updated when adding/removing callbacks.
@@ -1027,6 +1124,9 @@ void fgOpenWindow( SFG_Window* window, const char* title,
 
     XFree(visualInfo);
 
+    if( !isSubWindow)
+        XPeekIfEvent( fgDisplay.Display, &eventReturnBuffer, &fghWindowIsVisible, window->Window.Handle );
+
 #elif TARGET_HOST_MS_WINDOWS
 
     WNDCLASS wc;
@@ -1137,17 +1237,24 @@ void fgOpenWindow( SFG_Window* window, const char* title,
         UpdateWindow(window->Window.Handle);
     }
 #else
-    window->Window.Handle = CreateWindowEx(
-        exFlags,
-        _T("FREEGLUT"),
-        title,
-        flags,
-        x, y, w, h,
-        (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
-        (HMENU) NULL,
-        fgDisplay.Instance,
-        (LPVOID) window
-    );
+    {
+      /* xoff and yoff are used to place window relative to current display */
+      /* The operation of gamemode also depends on this */
+        int xoff=0,yoff=0;
+        get_display_origin(&xoff,&yoff);
+
+        window->Window.Handle = CreateWindowEx(
+            exFlags,
+            _T("FREEGLUT"),
+            title,
+            flags,
+            x+xoff, y+yoff, w, h,
+            (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
+            (HMENU) NULL,
+            fgDisplay.Instance,
+            (LPVOID) window
+        );
+    }
 #endif /* defined(_WIN32_WCE) */
 
     if( !( window->Window.Handle ) )
@@ -1209,12 +1316,21 @@ void fgOpenWindow( SFG_Window* window, const char* title,
  */
 void fgCloseWindow( SFG_Window* window )
 {
+    /* if we're in gamemode, call glutLeaveGameMode first to make sure the
+     * gamemode is properly closed before closing the window
+     */
+    if (fgStructure.GameModeWindow != NULL)
+        glutLeaveGameMode();
+
 #if TARGET_HOST_POSIX_X11
 
     if( window->Window.Context )
         glXDestroyContext( fgDisplay.Display, window->Window.Context );
     XFree( window->Window.FBConfig );
-    XDestroyWindow( fgDisplay.Display, window->Window.Handle );
+
+    if( window->Window.Handle ) {
+        XDestroyWindow( fgDisplay.Display, window->Window.Handle );
+    }
     /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */
 
 #elif TARGET_HOST_MS_WINDOWS
@@ -1680,8 +1796,9 @@ void FGAPIENTRY glutFullScreen( void )
 
         rect.left   = 0;
         rect.top    = 0;
-        rect.right  = fgDisplay.ScreenWidth;
-        rect.bottom = fgDisplay.ScreenHeight;
+       get_display_origin(&rect.left,&rect.top);
+        rect.right  = fgDisplay.ScreenWidth+rect.left;
+        rect.bottom = fgDisplay.ScreenHeight+rect.top;
 
         AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS |
                                   WS_CLIPCHILDREN, FALSE );