Implemented gamma correction on Windows. SDL-1.3
authorSam Lantinga <slouken@libsdl.org>
Sun, 09 Jul 2006 09:02:26 +0000
branchSDL-1.3
changeset 1733 0b1070f2f94d
parent 1732 fd65f12b6de6
child 1734 f7c667ded87d
Implemented gamma correction on Windows. Added general code to restore the video mode and gamma when windows lose focus.
include/SDL_video.h
src/SDL_compat.c
src/events/SDL_windowevents.c
src/video/SDL_gamma.c
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/win32/SDL_win32events.c
src/video/win32/SDL_win32gamma.c
src/video/win32/SDL_win32gamma.h
src/video/win32/SDL_win32modes.c
src/video/win32/SDL_win32modes.h
src/video/win32/SDL_win32video.c
src/video/win32/SDL_win32video.h
src/video/win32/SDL_win32window.c
test/testsprite2.c
test/testwm2.c
--- a/include/SDL_video.h	Sat Jul 08 20:55:39 2006 +0000
+++ b/include/SDL_video.h	Sun Jul 09 09:02:26 2006 +0000
@@ -98,6 +98,7 @@
  * \sa SDL_RaiseWindow()
  * \sa SDL_RestoreWindow()
  * \sa SDL_SetWindowData()
+ * \sa SDL_SetWindowFullscreen()
  * \sa SDL_SetWindowGrab()
  * \sa SDL_SetWindowIcon()
  * \sa SDL_SetWindowPosition()
@@ -474,15 +475,28 @@
                                                                    * closest);
 
 /**
- * \fn int SDL_SetDisplayMode(const SDL_DisplayMode *mode)
+ * \fn int SDL_SetFullscreenDisplayMode(const SDL_DisplayMode *mode)
  *
- * \brief Set up the closest available mode on the current display.
+ * \brief Set the display mode used when a fullscreen window is visible
+ *        on the currently selected display.
  *
- * \param mode The desired display mode, or NULL to set the desktop mode.
+ * \param mode The mode to use, or NULL for the desktop mode.
  *
  * \return 0 on success, or -1 if setting the display mode failed.
+ *
+ * \sa SDL_SetWindowFullscreen()
  */
-extern DECLSPEC int SDLCALL SDL_SetDisplayMode(const SDL_DisplayMode * mode);
+extern DECLSPEC int SDLCALL SDL_SetFullscreenDisplayMode(const SDL_DisplayMode
+                                                         * mode);
+
+/**
+ * \fn const SDL_DisplayMode *SDL_GetFullscreenDisplayMode(void)
+ *
+ * \brief Query the display mode used when a fullscreen window is visible
+ *        on the currently selected display.
+ */
+extern DECLSPEC const SDL_DisplayMode *SDLCALL
+SDL_GetFullscreenDisplayMode(void);
 
 /**
  * \fn int SDL_SetDisplayPalette(const SDL_Color *colors, int firstcolor, int ncolors)
@@ -507,6 +521,57 @@
                                                   int ncolors);
 
 /**
+ * \fn int SDL_SetGamma(float red, float green, float blue)
+ *
+ * \brief Set the gamma correction for each of the color channels on the currently selected display.
+ *
+ * \return 0 on success, or -1 if setting the gamma isn't supported.
+ *
+ * \sa SDL_SetGammaRamp()
+ */
+extern DECLSPEC int SDLCALL SDL_SetGamma(float red, float green, float blue);
+
+/**
+ * \fn int SDL_SetGammaRamp(const Uint16 * red, const Uint16 * green, const Uint16 * blue)
+ *
+ * \brief Set the gamma ramp for the currently selected display.
+ *
+ * \param red The translation table for the red channel, or NULL
+ * \param green The translation table for the green channel, or NULL
+ * \param blue The translation table for the blue channel, or NULL
+ *
+ * \return 0 on success, or -1 if gamma ramps are unsupported.
+ *
+ * Set the gamma translation table for the red, green, and blue channels
+ * of the video hardware.  Each table is an array of 256 16-bit quantities,
+ * representing a mapping between the input and output for that channel.
+ * The input is the index into the array, and the output is the 16-bit
+ * gamma value at that index, scaled to the output color precision.
+ * 
+ * \sa SDL_GetGammaRamp()
+ */
+extern DECLSPEC int SDLCALL SDL_SetGammaRamp(const Uint16 * red,
+                                             const Uint16 * green,
+                                             const Uint16 * blue);
+
+/**
+ * \fn int SDL_GetGammaRamp(Uint16 * red, Uint16 * green, Uint16 * blue)
+ *
+ * \brief Get the gamma ramp for the currently selected display.
+ *
+ * \param red A pointer to a 256 element array of 16-bit quantities to hold the translation table for the red channel, or NULL.
+ * \param green A pointer to a 256 element array of 16-bit quantities to hold the translation table for the green channel, or NULL.
+ * \param blue A pointer to a 256 element array of 16-bit quantities to hold the translation table for the blue channel, or NULL.
+ * 
+ * \return 0 on success, or -1 if gamma ramps are unsupported.
+ *
+ * \sa SDL_SetGammaRamp()
+ */
+extern DECLSPEC int SDLCALL SDL_GetGammaRamp(Uint16 * red, Uint16 * green,
+                                             Uint16 * blue);
+
+
+/**
  * \fn SDL_WindowID SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  *
  * \brief Create a window with the specified position, dimensions, and flags.
@@ -516,7 +581,7 @@
  * \param y The y position of the window
  * \param w The width of the window
  * \param h The height of the window
- * \param flags The flags for the window
+ * \param flags The flags for the window, a mask of any of the following: SDL_WINDOW_FULLSCREEN, SDL_WINDOW_OPENGL, SDL_WINDOW_SHOWN, SDL_WINDOW_BORDERLESS, SDL_WINDOW_RESIZABLE, SDL_WINDOW_MAXIMIZED, SDL_WINDOW_MINIMIZED, SDL_WINDOW_INPUT_GRABBED
  *
  * \return The id of the window created, or zero if window creation failed.
  *
@@ -702,13 +767,24 @@
 extern DECLSPEC void SDLCALL SDL_RestoreWindow(SDL_WindowID windowID);
 
 /**
+ * \fn int SDL_SetWindowFullscreen(SDL_WindowID windowID, int fullscreen)
+ *
+ * \brief Set the window's fullscreen state.
+ *
+ * \return 0 on success, or -1 if setting the display mode failed.
+ *
+ * \sa SDL_SetFullscreenDisplayMode()
+ */
+extern DECLSPEC int SDLCALL SDL_SetWindowFullscreen(SDL_WindowID windowID,
+                                                    int fullscreen);
+
+/**
  * \fn void SDL_SetWindowGrab(SDL_WindowID windowID, int mode)
  *
  * \brief Set the window's input grab mode.
  *
  * \param mode This is 1 to grab input, and 0 to release input.
  *
- * \sa SDL_GrabMode
  * \sa SDL_GetWindowGrab()
  */
 extern DECLSPEC void SDLCALL SDL_SetWindowGrab(SDL_WindowID windowID,
@@ -721,7 +797,6 @@
  *
  * \return This returns 1 if input is grabbed, and 0 otherwise.
  *
- * \sa SDL_GrabMode
  * \sa SDL_SetWindowGrab()
  */
 extern DECLSPEC int SDLCALL SDL_GetWindowGrab(SDL_WindowID windowID);
@@ -1070,44 +1145,6 @@
 extern DECLSPEC void SDLCALL SDL_DestroyRenderer(SDL_WindowID windowID);
 
 /*
- * Set the gamma correction for each of the color channels.
- * The gamma values range (approximately) between 0.1 and 10.0
- * 
- * If this function isn't supported directly by the hardware, it will
- * be emulated using gamma ramps, if available.  If successful, this
- * function returns 0, otherwise it returns -1.
- */
-extern DECLSPEC int SDLCALL SDL_SetGamma(float red, float green, float blue);
-
-/*
- * Set the gamma translation table for the red, green, and blue channels
- * of the video hardware.  Each table is an array of 256 16-bit quantities,
- * representing a mapping between the input and output for that channel.
- * The input is the index into the array, and the output is the 16-bit
- * gamma value at that index, scaled to the output color precision.
- * 
- * You may pass NULL for any of the channels to leave it unchanged.
- * If the call succeeds, it will return 0.  If the display driver or
- * hardware does not support gamma translation, or otherwise fails,
- * this function will return -1.
- */
-extern DECLSPEC int SDLCALL SDL_SetGammaRamp(const Uint16 * red,
-                                             const Uint16 * green,
-                                             const Uint16 * blue);
-
-/*
- * Retrieve the current values of the gamma translation tables.
- * 
- * You must pass in valid pointers to arrays of 256 16-bit quantities.
- * Any of the pointers may be NULL to ignore that channel.
- * If the call succeeds, it will return 0.  If the display driver or
- * hardware does not support gamma translation, or otherwise fails,
- * this function will return -1.
- */
-extern DECLSPEC int SDLCALL SDL_GetGammaRamp(Uint16 * red, Uint16 * green,
-                                             Uint16 * blue);
-
-/*
  * Maps an RGB triple to an opaque pixel value for a given pixel format
  */
 extern DECLSPEC Uint32 SDLCALL SDL_MapRGB
--- a/src/SDL_compat.c	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/SDL_compat.c	Sun Jul 09 09:02:26 2006 +0000
@@ -360,9 +360,8 @@
     if (flags & SDL_NOFRAME) {
         window_flags |= SDL_WINDOW_BORDERLESS;
     }
-    if (SDL_getenv("SDL_WINDOW_POS")) {
-    }
     GetEnvironmentWindowPosition(width, height, &window_x, &window_y);
+    SDL_SetFullscreenDisplayMode(NULL);
     SDL_VideoWindow =
         SDL_CreateWindow(wm_title, window_x, window_y, width, height,
                          window_flags);
@@ -427,21 +426,9 @@
 
     /* Set the desired display mode */
     if (flags & SDL_FULLSCREEN) {
-        if (!SDL_GetClosestDisplayMode(&mode, &mode)) {
+        if (SDL_SetFullscreenDisplayMode(&mode) < 0) {
             return NULL;
         }
-    } else {
-        if (desktop_format) {
-            mode.format = desktop_format;
-        }
-        if (desktop_mode->w && desktop_mode->h) {
-            mode.w = desktop_mode->w;
-            mode.h = desktop_mode->h;
-        }
-        mode.refresh_rate = desktop_mode->refresh_rate;
-    }
-    if (SDL_SetDisplayMode(&mode) < 0) {
-        return NULL;
     }
 
     /* If we're in OpenGL mode, just create a stub surface and we're done! */
--- a/src/events/SDL_windowevents.c	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/events/SDL_windowevents.c	Sun Jul 09 09:02:26 2006 +0000
@@ -44,19 +44,27 @@
             return 0;
         }
         window->flags |= SDL_WINDOW_SHOWN;
+        SDL_OnWindowShown(window);
         break;
     case SDL_WINDOWEVENT_HIDDEN:
         if (!(window->flags & SDL_WINDOW_SHOWN)) {
             return 0;
         }
         window->flags &= ~SDL_WINDOW_SHOWN;
+        SDL_OnWindowHidden(window);
         break;
     case SDL_WINDOWEVENT_MOVED:
+        if (window->flags & SDL_WINDOW_FULLSCREEN) {
+            return 0;
+        }
         if (data1 == window->x && data2 == window->y) {
             return 0;
         }
         break;
     case SDL_WINDOWEVENT_RESIZED:
+        if (window->flags & SDL_WINDOW_FULLSCREEN) {
+            return 0;
+        }
         if (data1 == window->w && data2 == window->h) {
             return 0;
         }
@@ -96,12 +104,14 @@
             return 0;
         }
         window->flags |= SDL_WINDOW_KEYBOARD_FOCUS;
+        SDL_OnWindowFocusGained(window);
         break;
     case SDL_WINDOWEVENT_FOCUS_LOST:
         if (!(window->flags & SDL_WINDOW_KEYBOARD_FOCUS)) {
             return 0;
         }
         window->flags &= ~SDL_WINDOW_KEYBOARD_FOCUS;
+        SDL_OnWindowFocusLost(window);
         break;
     }
 
--- a/src/video/SDL_gamma.c	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/video/SDL_gamma.c	Sun Jul 09 09:02:26 2006 +0000
@@ -96,24 +96,13 @@
 int
 SDL_SetGamma(float red, float green, float blue)
 {
-    SDL_VideoDevice *_this = SDL_GetVideoDevice();
-    int succeeded;
-
-    succeeded = -1;
-    /* Prefer using SetGammaRamp(), as it's more flexible */
-    {
-        Uint16 ramp[3][256];
+    Uint16 ramp[3][256];
 
-        CalculateGammaRamp(red, ramp[0]);
-        CalculateGammaRamp(green, ramp[1]);
-        CalculateGammaRamp(blue, ramp[2]);
-        succeeded = SDL_SetGammaRamp(ramp[0], ramp[1], ramp[2]);
-    }
-    if ((succeeded < 0) && _this && _this->SetGamma) {
-        SDL_ClearError();
-        succeeded = _this->SetGamma(_this, red, green, blue);
-    }
-    return succeeded;
+    CalculateGammaRamp(red, ramp[0]);
+    CalculateGammaRamp(green, ramp[1]);
+    CalculateGammaRamp(blue, ramp[2]);
+
+    return SDL_SetGammaRamp(ramp[0], ramp[1], ramp[2]);
 }
 
 /* Calculating the gamma by integrating the gamma ramps isn't exact,
@@ -122,24 +111,14 @@
 int
 SDL_GetGamma(float *red, float *green, float *blue)
 {
-    SDL_VideoDevice *_this = SDL_GetVideoDevice();
     int succeeded;
-
-    succeeded = -1;
-    /* Prefer using GetGammaRamp(), as it's more flexible */
-    {
-        Uint16 ramp[3][256];
+    Uint16 ramp[3][256];
 
-        succeeded = SDL_GetGammaRamp(ramp[0], ramp[1], ramp[2]);
-        if (succeeded >= 0) {
-            CalculateGammaFromRamp(red, ramp[0]);
-            CalculateGammaFromRamp(green, ramp[1]);
-            CalculateGammaFromRamp(blue, ramp[2]);
-        }
-    }
-    if ((succeeded < 0) && _this && _this->GetGamma) {
-        SDL_ClearError();
-        succeeded = _this->GetGamma(_this, red, green, blue);
+    succeeded = SDL_GetGammaRamp(ramp[0], ramp[1], ramp[2]);
+    if (succeeded >= 0) {
+        CalculateGammaFromRamp(red, ramp[0]);
+        CalculateGammaFromRamp(green, ramp[1]);
+        CalculateGammaFromRamp(blue, ramp[2]);
     }
     return succeeded;
 }
@@ -152,28 +131,29 @@
     int succeeded;
 
     /* Lazily allocate the gamma tables */
-    if (!SDL_CurrentWindow.gamma) {
-        SDL_GetGammaRamp(0, 0, 0);
+    if (!SDL_CurrentDisplay.gamma) {
+        SDL_GetGammaRamp(NULL, NULL, NULL);
     }
 
     /* Fill the gamma table with the new values */
     if (red) {
-        SDL_memcpy(&SDL_CurrentWindow.gamma[0 * 256], red,
-                   256 * sizeof(*SDL_CurrentWindow.gamma));
+        SDL_memcpy(&SDL_CurrentDisplay.gamma[0 * 256], red,
+                   256 * sizeof(*SDL_CurrentDisplay.gamma));
     }
     if (green) {
-        SDL_memcpy(&SDL_CurrentWindow.gamma[1 * 256], green,
-                   256 * sizeof(*SDL_CurrentWindow.gamma));
+        SDL_memcpy(&SDL_CurrentDisplay.gamma[1 * 256], green,
+                   256 * sizeof(*SDL_CurrentDisplay.gamma));
     }
     if (blue) {
-        SDL_memcpy(&SDL_CurrentWindow.gamma[2 * 256], blue,
-                   256 * sizeof(*SDL_CurrentWindow.gamma));
+        SDL_memcpy(&SDL_CurrentDisplay.gamma[2 * 256], blue,
+                   256 * sizeof(*SDL_CurrentDisplay.gamma));
     }
 
     /* Try to set the gamma ramp in the driver */
     succeeded = -1;
-    if (_this && _this->SetGammaRamp) {
-        succeeded = _this->SetGammaRamp(_this, SDL_CurrentWindow.gamma);
+    if (_this && _this->SetDisplayGammaRamp) {
+        succeeded =
+            _this->SetDisplayGammaRamp(_this, SDL_CurrentDisplay.gamma);
     } else {
         SDL_SetError("Gamma ramp manipulation not supported");
     }
@@ -186,38 +166,42 @@
     SDL_VideoDevice *_this = SDL_GetVideoDevice();
 
     /* Lazily allocate the gamma table */
-    if (!SDL_CurrentWindow.gamma) {
-        SDL_CurrentWindow.gamma =
-            SDL_malloc(3 * 256 * sizeof(*SDL_CurrentWindow.gamma));
-        if (!SDL_CurrentWindow.gamma) {
+    if (!SDL_CurrentDisplay.gamma) {
+        size_t rampsize = (3 * 256 * sizeof(*SDL_CurrentDisplay.gamma));
+
+        SDL_CurrentDisplay.gamma = SDL_malloc(rampsize * 2);
+        if (!SDL_CurrentDisplay.gamma) {
             SDL_OutOfMemory();
             return -1;
         }
-        if (_this && _this->GetGammaRamp) {
+        if (_this && _this->GetDisplayGammaRamp) {
             /* Get the real hardware gamma */
-            _this->GetGammaRamp(_this, SDL_CurrentWindow.gamma);
+            _this->GetDisplayGammaRamp(_this, SDL_CurrentDisplay.gamma);
         } else {
             /* Assume an identity gamma */
             int i;
             for (i = 0; i < 256; ++i) {
-                SDL_CurrentWindow.gamma[0 * 256 + i] = (i << 8) | i;
-                SDL_CurrentWindow.gamma[1 * 256 + i] = (i << 8) | i;
-                SDL_CurrentWindow.gamma[2 * 256 + i] = (i << 8) | i;
+                SDL_CurrentDisplay.gamma[0 * 256 + i] = (i << 8) | i;
+                SDL_CurrentDisplay.gamma[1 * 256 + i] = (i << 8) | i;
+                SDL_CurrentDisplay.gamma[2 * 256 + i] = (i << 8) | i;
             }
         }
+        SDL_CurrentDisplay.saved_gamma = SDL_CurrentDisplay.gamma + (3 * 256);
+        SDL_memcpy(SDL_CurrentDisplay.saved_gamma, SDL_CurrentDisplay.gamma,
+                   rampsize);
     }
 
     /* Just copy from our internal table */
     if (red) {
-        SDL_memcpy(red, &SDL_CurrentWindow.gamma[0 * 256],
+        SDL_memcpy(red, &SDL_CurrentDisplay.gamma[0 * 256],
                    256 * sizeof(*red));
     }
     if (green) {
-        SDL_memcpy(green, &SDL_CurrentWindow.gamma[1 * 256],
+        SDL_memcpy(green, &SDL_CurrentDisplay.gamma[1 * 256],
                    256 * sizeof(*green));
     }
     if (blue) {
-        SDL_memcpy(blue, &SDL_CurrentWindow.gamma[2 * 256],
+        SDL_memcpy(blue, &SDL_CurrentDisplay.gamma[2 * 256],
                    256 * sizeof(*blue));
     }
     return 0;
--- a/src/video/SDL_sysvideo.h	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/video/SDL_sysvideo.h	Sun Jul 09 09:02:26 2006 +0000
@@ -117,14 +117,16 @@
     int w, h;
     Uint32 flags;
 
-    Uint16 *gamma;
-
     int display;
     SDL_Renderer *renderer;
 
     void *userdata;
     void *driverdata;
 };
+#define FULLSCREEN_VISIBLE(W) \
+    ((W->flags & SDL_WINDOW_FULLSCREEN) && \
+     (W->flags & SDL_WINDOW_SHOWN) && \
+     !(W->flags & SDL_WINDOW_MINIMIZED))
 
 /* Define the SDL display structure
    This corresponds to physical monitors attached to the system.
@@ -136,8 +138,13 @@
     SDL_DisplayMode *display_modes;
     SDL_DisplayMode desktop_mode;
     SDL_DisplayMode current_mode;
+    SDL_DisplayMode desired_mode;
+    SDL_DisplayMode *fullscreen_mode;
     SDL_Palette *palette;
 
+    Uint16 *gamma;
+    Uint16 *saved_gamma;        /* (just offset into gamma) */
+
     int num_render_drivers;
     SDL_RenderDriver *render_drivers;
 
@@ -174,6 +181,12 @@
     /* * * */
     /* Display functions
      */
+
+    /* Get a list of the available display modes.
+     * e.g.  SDL_AddDisplayMode(_this->current_display, mode)
+     */
+    void (*GetDisplayModes) (_THIS);
+
     /* Setting the display mode is independent of creating windows,
      * so when the display mode is changed, all existing windows
      * should have their data updated accordingly, including the
@@ -181,12 +194,18 @@
      */
     int (*SetDisplayMode) (_THIS, SDL_DisplayMode * mode);
 
-    /* Sets the color entries of the display palette to those in 'colors'.
-       The return value is 0 if all entries could be set properly or -1
-       otherwise.
-     */
+    /* Set the color entries of the display palette */
     int (*SetDisplayPalette) (_THIS, SDL_Palette * palette);
 
+    /* Get the color entries of the display palette */
+    int (*GetDisplayPalette) (_THIS, SDL_Palette * palette);
+
+    /* Set the gamma ramp */
+    int (*SetDisplayGammaRamp) (_THIS, Uint16 * ramp);
+
+    /* Get the gamma ramp */
+    int (*GetDisplayGammaRamp) (_THIS, Uint16 * ramp);
+
     /* * * */
     /* Window functions
      */
@@ -214,21 +233,6 @@
     void (*VideoQuit) (_THIS);
 
     /* * * */
-    /* Gamma support */
-
-    /* Set the gamma correction directly (emulated with gamma ramps) */
-    int (*SetGamma) (_THIS, float red, float green, float blue);
-
-    /* Get the gamma correction directly (emulated with gamma ramps) */
-    int (*GetGamma) (_THIS, float *red, float *green, float *blue);
-
-    /* Set the gamma ramp */
-    int (*SetGammaRamp) (_THIS, Uint16 * ramp);
-
-    /* Get the gamma ramp */
-    int (*GetGammaRamp) (_THIS, Uint16 * ramp);
-
-    /* * * */
     /* OpenGL support */
 
     /* Sets the dll to use for OpenGL and loads it */
@@ -405,7 +409,6 @@
 #endif
 
 #define SDL_CurrentDisplay	(_this->displays[_this->current_display])
-#define SDL_CurrentWindow	(SDL_CurrentDisplay.windows[0])
 
 extern SDL_VideoDevice *SDL_GetVideoDevice();
 extern int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode);
@@ -418,6 +421,11 @@
 extern SDL_Window *SDL_GetWindowFromID(SDL_WindowID windowID);
 extern SDL_VideoDisplay *SDL_GetDisplayFromWindow(SDL_Window * window);
 
+extern void SDL_OnWindowShown(SDL_Window * window);
+extern void SDL_OnWindowHidden(SDL_Window * window);
+extern void SDL_OnWindowFocusGained(SDL_Window * window);
+extern void SDL_OnWindowFocusLost(SDL_Window * window);
+
 #endif /* _SDL_sysvideo_h */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/SDL_video.c	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/video/SDL_video.c	Sun Jul 09 09:02:26 2006 +0000
@@ -267,13 +267,6 @@
         return (-1);
     }
 
-    /* Sort the video modes */
-    for (i = 0; i < _this->num_displays; ++i) {
-        SDL_qsort(_this->displays[i].display_modes,
-                  _this->displays[i].num_display_modes,
-                  sizeof(SDL_DisplayMode), cmpmodes);
-    }
-
     /* The software renderer is always available */
     for (i = 0; i < _this->num_displays; ++i) {
         if (_this->displays[i].num_render_drivers > 0) {
@@ -398,7 +391,13 @@
 SDL_GetNumDisplayModes()
 {
     if (_this) {
-        return SDL_CurrentDisplay.num_display_modes;
+        SDL_VideoDisplay *display = &SDL_CurrentDisplay;
+        if (!display->num_display_modes && _this->GetDisplayModes) {
+            _this->GetDisplayModes(_this);
+            SDL_qsort(display->display_modes, display->num_display_modes,
+                      sizeof(SDL_DisplayMode), cmpmodes);
+        }
+        return display->num_display_modes;
     }
     return 0;
 }
@@ -460,7 +459,7 @@
     }
 
     match = NULL;
-    for (i = 0; i < SDL_CurrentDisplay.num_display_modes; ++i) {
+    for (i = 0; i < SDL_GetNumDisplayModes(); ++i) {
         current = &SDL_CurrentDisplay.display_modes[i];
 
         if ((current->w && current->h) &&
@@ -602,7 +601,7 @@
     /* Move any fullscreen windows into position */
     for (i = 0; i < display->num_windows; ++i) {
         SDL_Window *window = &display->windows[i];
-        if (window->flags & SDL_WINDOW_FULLSCREEN) {
+        if (FULLSCREEN_VISIBLE(window)) {
             SDL_SetWindowPosition(window->id,
                                   ((display_mode.w - window->w) / 2),
                                   ((display_mode.h - window->h) / 2));
@@ -613,6 +612,44 @@
 }
 
 int
+SDL_SetFullscreenDisplayMode(const SDL_DisplayMode * mode)
+{
+    SDL_VideoDisplay *display;
+    int i;
+
+    if (!_this) {
+        SDL_SetError("Video subsystem has not been initialized");
+        return -1;
+    }
+
+    display = &SDL_CurrentDisplay;
+    if (mode) {
+        SDL_GetClosestDisplayMode(mode, &display->desired_mode);
+        display->fullscreen_mode = &display->desired_mode;
+    } else {
+        display->fullscreen_mode = NULL;
+    }
+
+    /* Actually set the mode if we have a fullscreen window visible */
+    for (i = 0; i < display->num_windows; ++i) {
+        SDL_Window *window = &display->windows[i];
+        if (FULLSCREEN_VISIBLE(window)) {
+            return SDL_SetDisplayMode(display->fullscreen_mode);
+        }
+    }
+    return 0;
+}
+
+const SDL_DisplayMode *
+SDL_GetFullscreenDisplayMode(void)
+{
+    if (_this) {
+        return SDL_CurrentDisplay.fullscreen_mode;
+    }
+    return NULL;
+}
+
+int
 SDL_SetDisplayPalette(const SDL_Color * colors, int firstcolor, int ncolors)
 {
     SDL_Palette *palette;
@@ -939,7 +976,7 @@
         return;
     }
 
-    window->flags |= SDL_WINDOW_SHOWN;
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_SHOWN, 0, 0);
 
     if (_this->ShowWindow) {
         _this->ShowWindow(_this, window);
@@ -955,7 +992,7 @@
         return;
     }
 
-    window->flags &= ~SDL_WINDOW_SHOWN;
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_HIDDEN, 0, 0);
 
     if (_this->HideWindow) {
         _this->HideWindow(_this, window);
@@ -985,7 +1022,7 @@
         return;
     }
 
-    window->flags |= SDL_WINDOW_MAXIMIZED;
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
 
     if (_this->MaximizeWindow) {
         _this->MaximizeWindow(_this, window);
@@ -1001,7 +1038,7 @@
         return;
     }
 
-    window->flags |= SDL_WINDOW_MINIMIZED;
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
 
     if (_this->MinimizeWindow) {
         _this->MinimizeWindow(_this, window);
@@ -1018,7 +1055,7 @@
         return;
     }
 
-    window->flags &= ~(SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED);
+    SDL_SendWindowEvent(window->id, SDL_WINDOWEVENT_RESTORED, 0, 0);
 
     if (_this->RestoreWindow) {
         _this->RestoreWindow(_this, window);
@@ -1058,6 +1095,43 @@
 }
 
 void
+SDL_OnWindowShown(SDL_Window * window)
+{
+}
+
+void
+SDL_OnWindowHidden(SDL_Window * window)
+{
+}
+
+void
+SDL_OnWindowFocusGained(SDL_Window * window)
+{
+    SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
+
+    if (window->flags & SDL_WINDOW_FULLSCREEN) {
+        SDL_SetDisplayMode(display->fullscreen_mode);
+    }
+    if (display->gamma && _this->SetDisplayGammaRamp) {
+        _this->SetDisplayGammaRamp(_this, display->gamma);
+    }
+}
+
+void
+SDL_OnWindowFocusLost(SDL_Window * window)
+{
+    SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
+
+    if (window->flags & SDL_WINDOW_FULLSCREEN) {
+        SDL_SetDisplayMode(NULL);
+        SDL_MinimizeWindow(window->id);
+    }
+    if (display->gamma && _this->SetDisplayGammaRamp) {
+        _this->SetDisplayGammaRamp(_this, display->saved_gamma);
+    }
+}
+
+void
 SDL_DestroyWindow(SDL_WindowID windowID)
 {
     int i, j;
@@ -1073,6 +1147,12 @@
             if (window->id != windowID) {
                 continue;
             }
+            if (window->flags & SDL_WINDOW_FULLSCREEN) {
+                SDL_SetDisplayMode(NULL);
+            }
+            if (display->gamma && _this->SetDisplayGammaRamp) {
+                _this->SetDisplayGammaRamp(_this, display->saved_gamma);
+            }
             if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
                 window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
                 _this->SetWindowGrab(_this, window);
@@ -1086,9 +1166,6 @@
             if (window->title) {
                 SDL_free(window->title);
             }
-            if (window->gamma) {
-                SDL_free(window->gamma);
-            }
             if (j != display->num_windows - 1) {
                 SDL_memcpy(&display->windows[i],
                            &display->windows[i + 1],
@@ -1868,6 +1945,12 @@
             SDL_FreePalette(display->palette);
             display->palette = NULL;
         }
+        if (display->gamma) {
+            SDL_free(display->gamma);
+        }
+        if (display->driverdata) {
+            SDL_free(display->driverdata);
+        }
     }
     if (_this->displays) {
         SDL_free(_this->displays);
--- a/src/video/win32/SDL_win32events.c	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/video/win32/SDL_win32events.c	Sun Jul 09 09:02:26 2006 +0000
@@ -421,6 +421,18 @@
 
     switch (msg) {
 
+    case WM_SHOWWINDOW:
+        {
+            if (wParam) {
+                SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0,
+                                    0);
+            } else {
+                SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0,
+                                    0);
+            }
+        }
+        break;
+
     case WM_ACTIVATE:
         {
             int index;
@@ -452,7 +464,6 @@
                         ClipCursor(&rect);
                     }
                 }
-                /* FIXME: Restore mode state (mode, gamma) */
                 /* FIXME: Update keyboard state */
             } else {
                 if (keyboard && keyboard->focus == data->windowID) {
@@ -467,7 +478,6 @@
                     SDL_SendWindowEvent(data->windowID,
                                         SDL_WINDOWEVENT_MINIMIZED, 0, 0);
                 }
-                /* FIXME: Restore desktop state (mode, gamma) */
             }
             return (0);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/win32/SDL_win32gamma.c	Sun Jul 09 09:02:26 2006 +0000
@@ -0,0 +1,63 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2006 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "SDL_win32video.h"
+
+
+int
+WIN_SetDisplayGammaRamp(_THIS, Uint16 * ramp)
+{
+    SDL_DisplayData *data = (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
+    HDC hdc;
+    BOOL succeeded = FALSE;
+
+    hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
+    if (hdc) {
+        succeeded = SetDeviceGammaRamp(hdc, ramp);
+        if (!succeeded) {
+            WIN_SetError("SetDeviceGammaRamp()");
+        }
+        DeleteDC(hdc);
+    }
+    return succeeded ? 0 : -1;
+}
+
+int
+WIN_GetDisplayGammaRamp(_THIS, Uint16 * ramp)
+{
+    SDL_DisplayData *data = (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
+    HDC hdc;
+    BOOL succeeded = FALSE;
+
+    hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
+    if (hdc) {
+        succeeded = GetDeviceGammaRamp(hdc, ramp);
+        if (!succeeded) {
+            WIN_SetError("GetDeviceGammaRamp()");
+        }
+        DeleteDC(hdc);
+    }
+    return succeeded ? 0 : -1;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/win32/SDL_win32gamma.h	Sun Jul 09 09:02:26 2006 +0000
@@ -0,0 +1,32 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2006 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_win32gamma_h
+#define _SDL_win32gamma_h
+
+extern int WIN_SetDisplayGammaRamp(_THIS, Uint16 * ramp);
+extern int WIN_GetDisplayGammaRamp(_THIS, Uint16 * ramp);
+
+#endif /* _SDL_win32gamma_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/win32/SDL_win32modes.c	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/video/win32/SDL_win32modes.c	Sun Jul 09 09:02:26 2006 +0000
@@ -24,12 +24,6 @@
 #include "SDL_win32video.h"
 
 
-typedef struct
-{
-    TCHAR DeviceName[32];
-    DEVMODE DeviceMode;
-} SDL_DisplayModeData;
-
 /* FIXME: Each call to EnumDisplaySettings() takes about 6 ms on my laptop.
           With 500 or so modes, this takes almost 3 seconds to run!
 */
@@ -123,7 +117,7 @@
 WIN_InitModes(_THIS)
 {
     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
-    DWORD i, j, k;
+    DWORD i, j;
     DISPLAY_DEVICE device;
 
     device.cb = sizeof(device);
@@ -143,6 +137,7 @@
         for (j = 0;; ++j) {
             int index;
             SDL_VideoDisplay display;
+            SDL_DisplayData *displaydata;
             SDL_DisplayMode mode;
 
             if (!EnumDisplayDevices(DeviceName, j, &device, 0)) {
@@ -157,19 +152,37 @@
             if (!WIN_GetDisplayMode(DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
                 break;
             }
+
+            displaydata =
+                (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
+            if (!displaydata) {
+                continue;
+            }
+            SDL_memcpy(displaydata->DeviceName, DeviceName,
+                       sizeof(DeviceName));
+
             SDL_zero(display);
             display.desktop_mode = mode;
             display.current_mode = mode;
-            index = SDL_AddVideoDisplay(&display);
+            display.driverdata = displaydata;
+            SDL_AddVideoDisplay(&display);
+        }
+    }
+}
 
-            for (k = 0;; ++k) {
-                if (!WIN_GetDisplayMode(DeviceName, k, &mode)) {
-                    break;
-                }
-                if (!SDL_AddDisplayMode(index, &mode)) {
-                    SDL_free(mode.driverdata);
-                }
-            }
+void
+WIN_GetDisplayModes(_THIS)
+{
+    SDL_DisplayData *data = (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
+    DWORD i;
+    SDL_DisplayMode mode;
+
+    for (i = 0;; ++i) {
+        if (!WIN_GetDisplayMode(data->DeviceName, i, &mode)) {
+            break;
+        }
+        if (!SDL_AddDisplayMode(_this->current_display, &mode)) {
+            SDL_free(mode.driverdata);
         }
     }
 }
--- a/src/video/win32/SDL_win32modes.h	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/video/win32/SDL_win32modes.h	Sun Jul 09 09:02:26 2006 +0000
@@ -24,7 +24,19 @@
 #ifndef _SDL_win32modes_h
 #define _SDL_win32modes_h
 
+typedef struct
+{
+    TCHAR DeviceName[32];
+} SDL_DisplayData;
+
+typedef struct
+{
+    TCHAR DeviceName[32];
+    DEVMODE DeviceMode;
+} SDL_DisplayModeData;
+
 extern void WIN_InitModes(_THIS);
+extern void WIN_GetDisplayModes(_THIS);
 extern int WIN_SetDisplayMode(_THIS, SDL_DisplayMode * mode);
 extern void WIN_QuitModes(_THIS);
 
--- a/src/video/win32/SDL_win32video.c	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/video/win32/SDL_win32video.c	Sun Jul 09 09:02:26 2006 +0000
@@ -84,11 +84,11 @@
 #if SDL_VIDEO_RENDER_D3D
     data->d3dDLL = LoadLibrary(TEXT("D3D9.DLL"));
     if (data->d3dDLL) {
-        IDirect3D9 *WINAPI(*D3DCreate) (UINT SDKVersion);
+        IDirect3D9 *(WINAPI * D3DCreate) (UINT SDKVersion);
 
         D3DCreate =
-            (IDirect3D9 * WINAPI(*)(UINT)) GetProcAddress(data->d3dDLL,
-                                                          "Direct3DCreate9");
+            (IDirect3D9 * (WINAPI *) (UINT)) GetProcAddress(data->d3dDLL,
+                                                            "Direct3DCreate9");
         if (D3DCreate) {
             data->d3d = D3DCreate(D3D_SDK_VERSION);
         }
@@ -101,7 +101,10 @@
 
     /* Set the function pointers */
     device->VideoInit = WIN_VideoInit;
+    device->GetDisplayModes = WIN_GetDisplayModes;
     device->SetDisplayMode = WIN_SetDisplayMode;
+    device->SetDisplayGammaRamp = WIN_SetDisplayGammaRamp;
+    device->GetDisplayGammaRamp = WIN_GetDisplayGammaRamp;
     device->VideoQuit = WIN_VideoQuit;
     device->PumpEvents = WIN_PumpEvents;
 
--- a/src/video/win32/SDL_win32video.h	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/video/win32/SDL_win32video.h	Sun Jul 09 09:02:26 2006 +0000
@@ -36,6 +36,7 @@
 #endif
 
 #include "SDL_win32events.h"
+#include "SDL_win32gamma.h"
 #include "SDL_win32keyboard.h"
 #include "SDL_win32modes.h"
 #include "SDL_win32mouse.h"
--- a/src/video/win32/SDL_win32window.c	Sat Jul 08 20:55:39 2006 +0000
+++ b/src/video/win32/SDL_win32window.c	Sun Jul 09 09:02:26 2006 +0000
@@ -22,6 +22,7 @@
 #include "SDL_config.h"
 
 #include "../SDL_sysvideo.h"
+#include "../../events/SDL_keyboard_c.h"
 
 #include "SDL_win32video.h"
 
@@ -110,6 +111,14 @@
         int index = data->videodata->keyboard;
         window->flags |= SDL_WINDOW_KEYBOARD_FOCUS;
         SDL_SetKeyboardFocus(index, data->windowID);
+
+        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
+            RECT rect;
+            GetClientRect(hwnd, &rect);
+            ClientToScreen(hwnd, (LPPOINT) & rect);
+            ClientToScreen(hwnd, (LPPOINT) & rect + 1);
+            ClipCursor(&rect);
+        }
     }
 
     /* All done! */
--- a/test/testsprite2.c	Sat Jul 08 20:55:39 2006 +0000
+++ b/test/testsprite2.c	Sun Jul 09 09:02:26 2006 +0000
@@ -162,14 +162,7 @@
         SDL_zero(fullscreen_mode);
         fullscreen_mode.w = window_w;
         fullscreen_mode.h = window_h;
-        mode = &fullscreen_mode;
-    } else {
-        /* Set the desktop mode, we don't care what it is */
-        mode = NULL;
-    }
-    if (SDL_SetDisplayMode(mode) < 0) {
-        fprintf(stderr, "Couldn't set display mode: %s\n", SDL_GetError());
-        quit(2);
+        SDL_SetFullscreenDisplayMode(&fullscreen_mode);
     }
 
     /* Create the windows, initialize the renderers, and load the textures */
--- a/test/testwm2.c	Sat Jul 08 20:55:39 2006 +0000
+++ b/test/testwm2.c	Sun Jul 09 09:02:26 2006 +0000
@@ -49,12 +49,6 @@
         }
     }
 
-    /* Set the desktop mode, we don't care what it is */
-    if (SDL_SetDisplayMode(NULL) < 0) {
-        fprintf(stderr, "Couldn't set display mode: %s\n", SDL_GetError());
-        quit(2);
-    }
-
     /* Create the windows */
     windows = (SDL_WindowID *) SDL_malloc(num_windows * sizeof(*windows));
     if (!windows) {