- fallback to non-sRGB visuals if the context creation failed (GLX-only)
[freeglut] / src / mswin / fg_state_mswin.c
index 07ffdb1..98468f5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * freeglut_state_mswin.c
+ * fg_state_mswin.c
  *
  * The Windows-specific state query methods.
  *
 extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
                                      unsigned char layer_type );
 
-/* 
+/*
  * Helper functions for getting client area from the window rect
  * and the window rect from the client area given the style of the window
  * (or a valid window pointer from which the style can be queried).
  */
-extern RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside );
-extern void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth);
+extern void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside );
+extern void fghGetStyleFromWindow( const SFG_Window *window, DWORD *windowStyle, DWORD *windowExStyle );
+extern void fghComputeWindowRectFromClientArea_UseStyle( RECT *clientRect, const DWORD windowStyle, const DWORD windowExStyle, BOOL posIsOutside );
 
 
 /* The following include file is available from SGI but is not standard:
  *   #include <GL/wglext.h>
  * So we copy the necessary parts out of it to support the multisampling query
  */
+#ifndef WGL_SAMPLES_ARB
 #define WGL_SAMPLES_ARB                0x2042
+#endif
+#ifndef WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB
+#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
+#endif
+
+typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
 
 #if defined(_WIN32_WCE)
 #   include <Aygshell.h>
@@ -140,86 +148,129 @@ int fgPlatformGlutGet ( GLenum eWhat )
       return returnValue;
 
     case GLUT_WINDOW_BUFFER_SIZE:
-      returnValue = 1 ;                                      /* ????? */
-      return returnValue;
+    {
+        PIXELFORMATDESCRIPTOR  pfd;
+        HDC hdc = fgStructure.CurrentWindow->Window.pContext.Device;
+        int iPixelFormat = GetPixelFormat( hdc );
+        DescribePixelFormat(hdc, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
+
+        returnValue = pfd.cColorBits;
+        if (pfd.iPixelType==PFD_TYPE_RGBA)
+            returnValue += pfd.cAlphaBits;
+
+        return returnValue;
+    }
     case GLUT_WINDOW_STENCIL_SIZE:
-      returnValue = 0 ;                                      /* ????? */
+      glGetIntegerv ( GL_STENCIL_BITS, &returnValue );
       return returnValue;
 
     case GLUT_WINDOW_X:
     case GLUT_WINDOW_Y:
-    case GLUT_WINDOW_WIDTH:
-    case GLUT_WINDOW_HEIGHT:
     {
         /*
-         *  There is considerable confusion about the "right thing to
-         *  do" concerning window  size and position.  GLUT itself is
-         *  not consistent between Windows and UNIX/X11; since
-         *  platform independence is a virtue for "freeglut", we
-         *  decided to break with GLUT's behaviour.
-         *
-         *  Under UNIX/X11, it is apparently not possible to get the
-         *  window border sizes in order to subtract them off the
-         *  window's initial position until some time after the window
-         *  has been created.  Therefore we decided on the following
-         *  behaviour, both under Windows and under UNIX/X11:
+         *  NB:
          *  - When you create a window with position (x,y) and size
          *    (w,h), the upper left hand corner of the outside of the
-         *    window is at (x,y) and the size of the drawable area  is
+         *    window is at (x,y) and the size of the drawable area is
          *    (w,h).
          *  - When you query the size and position of the window--as
          *    is happening here for Windows--"freeglut" will return
          *    the size of the drawable area--the (w,h) that you
          *    specified when you created the window--and the coordinates
-         *    of the upper left hand corner of the drawable
-         *    area--which is NOT the (x,y) you specified.
+         *    of the upper left hand corner of the drawable area, i.e.
+         *    of the client rect--which is NOT the (x,y) you specified.
          */
 
         RECT winRect;
+        POINT topLeft = {0,0};
 
         freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 );
 
 #if defined(_WIN32_WCE)
-        GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect );
+        GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect);
 #else
-        winRect = fghGetClientArea(fgStructure.CurrentWindow, FALSE);
+        ClientToScreen(fgStructure.CurrentWindow->Window.Handle, &topLeft);
+
+        if (fgStructure.CurrentWindow->Parent)
+            /* For child window, we should return relative to upper-left
+             * of parent's client area.
+             */
+            ScreenToClient(fgStructure.CurrentWindow->Parent->Window.Handle,&topLeft);
+
+        winRect.left = topLeft.x;
+        winRect.top  = topLeft.y;
 #endif /* defined(_WIN32_WCE) */
 
         switch( eWhat )
         {
-        case GLUT_WINDOW_X:      return winRect.left                ;
-        case GLUT_WINDOW_Y:      return winRect.top                 ;
-        case GLUT_WINDOW_WIDTH:  return winRect.right - winRect.left;
-        case GLUT_WINDOW_HEIGHT: return winRect.bottom - winRect.top;
+        case GLUT_WINDOW_X:      return winRect.left;
+        case GLUT_WINDOW_Y:      return winRect.top ;
+        }
+    }
+    break;
+
+    case GLUT_WINDOW_WIDTH:
+    case GLUT_WINDOW_HEIGHT:
+    {
+        RECT winRect;
+        freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 );
+
+        GetClientRect( fgStructure.CurrentWindow->Window.Handle, &winRect);
+
+        switch( eWhat )
+        {
+        case GLUT_WINDOW_WIDTH:      return winRect.right-winRect.left;
+        case GLUT_WINDOW_HEIGHT:     return winRect.bottom-winRect.top;
         }
     }
     break;
 
     case GLUT_WINDOW_BORDER_WIDTH :
-    case GLUT_WINDOW_HEADER_HEIGHT :
+    case GLUT_WINDOW_BORDER_HEIGHT :
 #if defined(_WIN32_WCE)
         return 0;
 #else
         {
-            DWORD windowStyle;
-
+            /* We can't get the border width or header height in the simple way
+             * with some calls to GetSystemMetrics. We'd then have to assume which
+             * elements are present for a given decoration, and such calculations
+             * wouldn't be valid for every version of Windows. The below should be
+             * robust. */
+            int borderWidth, captionHeight;
+            DWORD windowStyle, windowExStyle;
+            RECT clientRect, winRect;
+
+            /* Get style of window, or default style */
+            fghGetStyleFromWindow( fgStructure.CurrentWindow, &windowStyle, &windowExStyle );
+            /* Get client area if we have a current window, else use dummy rect */
+            /* Also get window rect (including non-client area) */
             if (fgStructure.CurrentWindow && fgStructure.CurrentWindow->Window.Handle)
-                windowStyle = GetWindowLong(fgStructure.CurrentWindow->Window.Handle, GWL_STYLE);
+            {
+                fghGetClientArea(&clientRect,fgStructure.CurrentWindow, FALSE);
+                GetWindowRect(fgStructure.CurrentWindow->Window.Handle,&winRect);
+            }
             else
-                /* If no window, return sizes for a default window with title bar and border */
-                windowStyle = WS_OVERLAPPEDWINDOW;
-            
+            {
+                SetRect(&clientRect,0,0,200,200);
+                CopyRect(&winRect,&clientRect);
+                fghComputeWindowRectFromClientArea_UseStyle(&winRect,windowStyle,windowExStyle,FALSE);
+            }
+
+            /* Calculate border width by taking width of whole window minus width of client area and divide by two
+             * NB: we assume horizontal and vertical borders have the same size, which should always be the case
+             * unless the user bypassed FreeGLUT and messed with the windowstyle himself.
+             * Once borderwidth is known, account for it when comparing height of window to height of client area.
+             * all other extra pixels are assumed to be atop the window, forming the caption.
+             */
+            borderWidth   = ((winRect.right-winRect.left)-(clientRect.right-clientRect.left))/2;
+            captionHeight = (winRect.bottom-winRect.top)-(clientRect.bottom-clientRect.top)-borderWidth; /* include top border in caption height */
+
             switch( eWhat )
             {
             case GLUT_WINDOW_BORDER_WIDTH:
-                {
-                    int xBorderWidth, yBorderWidth;
-                    fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth);
-                    return xBorderWidth;
-                }
-            case GLUT_WINDOW_HEADER_HEIGHT:
-                /* Need to query for WS_MAXIMIZEBOX to see if we have a title bar, the WS_CAPTION query is also true for a WS_DLGFRAME only... */
-                return (windowStyle & WS_MAXIMIZEBOX)? GetSystemMetrics( SM_CYCAPTION ) : 0;
+                return borderWidth;
+            case GLUT_WINDOW_BORDER_HEIGHT:
+                return captionHeight;
             }
         }
 #endif /* defined(_WIN32_WCE) */
@@ -240,12 +291,31 @@ int fgPlatformGlutGet ( GLenum eWhat )
 #endif /* defined(_WIN32_WCE) */
         return 0;
 
+    case GLUT_WINDOW_SRGB:
+        if( fgStructure.CurrentWindow != NULL ) {
+            static int attr = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
+            static PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB;
+            HDC hdc = fgStructure.CurrentWindow->Window.pContext.Device;
+            int ipixfmt = GetPixelFormat(hdc);
+            int val;
+
+            if(!wglGetPixelFormatAttribivARB) {
+                if(!(wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB"))) {
+                    return 0;
+                }
+            }
+            if(wglGetPixelFormatAttribivARB(hdc, ipixfmt, 0, 1, &attr, &val)) {
+                return val;
+            }
+        }
+        return 0;
+
     default:
         fgWarning( "glutGet(): missing enum handle %d", eWhat );
         break;
     }
 
-       return -1;
+    return -1;
 }
 
 
@@ -283,11 +353,9 @@ int fgPlatformGlutDeviceGet ( GLenum eWhat )
 
     default:
         fgWarning( "glutDeviceGet(): missing enum handle %d", eWhat );
+        return -1;
         break;
     }
-
-    /* And now -- the failure. */
-    return -1;
 }
 
 /*
@@ -303,4 +371,4 @@ int *fgPlatformGlutGetModeValues(GLenum eWhat, int *size)
 {
   *size = 0;
   return NULL;
-}
\ No newline at end of file
+}