2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SDL_config.h"
24 #define WIN32_LEAN_AND_MEAN
27 /* Not yet in the mingw32 cross-compile headers */
28 #ifndef CDS_FULLSCREEN
29 #define CDS_FULLSCREEN 4
32 #include "SDL_syswm.h"
33 #include "../SDL_sysvideo.h"
34 #include "../SDL_pixels_c.h"
35 #include "../../events/SDL_sysevents.h"
36 #include "../../events/SDL_events_c.h"
37 #include "SDL_gapidibvideo.h"
38 #include "SDL_dibvideo.h"
39 #include "../wincommon/SDL_syswm_c.h"
40 #include "../wincommon/SDL_sysmouse_c.h"
41 #include "SDL_dibevents_c.h"
42 #include "../wincommon/SDL_wingl_c.h"
46 #ifndef DM_DISPLAYORIENTATION
47 #define DM_DISPLAYORIENTATION 0x00800000L
49 #ifndef DM_DISPLAYQUERYORIENTATION
50 #define DM_DISPLAYQUERYORIENTATION 0x01000000L
66 #define NO_GAMMA_SUPPORT
68 #define NO_CHANGEDISPLAYSETTINGS
70 #define ChangeDisplaySettings(lpDevMode, dwFlags) ChangeDisplaySettingsEx(NULL, (lpDevMode), 0, (dwFlags), 0)
77 #define WS_THICKFRAME 0
79 #ifndef SWP_NOCOPYBITS
80 #define SWP_NOCOPYBITS 0
83 #define PC_NOCOLLAPSE 0
87 // defined and used in SDL_sysevents.c
88 extern HINSTANCE aygshell;
91 /* Initialization/Query functions */
92 static int DIB_VideoInit(_THIS, SDL_PixelFormat *vformat);
93 static SDL_Rect **DIB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
94 SDL_Surface *DIB_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
95 static int DIB_SetColors(_THIS, int firstcolor, int ncolors,
97 static void DIB_CheckGamma(_THIS);
98 void DIB_SwapGamma(_THIS);
99 void DIB_QuitGamma(_THIS);
100 int DIB_SetGammaRamp(_THIS, Uint16 *ramp);
101 int DIB_GetGammaRamp(_THIS, Uint16 *ramp);
102 static void DIB_VideoQuit(_THIS);
104 /* Hardware surface functions */
105 static int DIB_AllocHWSurface(_THIS, SDL_Surface *surface);
106 static int DIB_LockHWSurface(_THIS, SDL_Surface *surface);
107 static void DIB_UnlockHWSurface(_THIS, SDL_Surface *surface);
108 static void DIB_FreeHWSurface(_THIS, SDL_Surface *surface);
110 /* Windows message handling functions */
111 static void DIB_GrabStaticColors(HWND window);
112 static void DIB_ReleaseStaticColors(HWND window);
113 static void DIB_Activate(_THIS, BOOL active, BOOL minimized);
114 static void DIB_RealizePalette(_THIS);
115 static void DIB_PaletteChanged(_THIS, HWND window);
116 static void DIB_WinPAINT(_THIS, HDC hdc);
119 static int DIB_SussScreenDepth();
121 /* DIB driver bootstrap functions */
123 static int DIB_Available(void)
128 static void DIB_DeleteDevice(SDL_VideoDevice *device)
131 if ( device->hidden ) {
132 if ( device->hidden->dibInfo ) {
133 SDL_free( device->hidden->dibInfo );
135 SDL_free(device->hidden);
137 if ( device->gl_data ) {
138 SDL_free(device->gl_data);
144 static SDL_VideoDevice *DIB_CreateDevice(int devindex)
146 SDL_VideoDevice *device;
148 /* Initialize all variables that we clean on shutdown */
149 device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
151 SDL_memset(device, 0, (sizeof *device));
152 device->hidden = (struct SDL_PrivateVideoData *)
153 SDL_malloc((sizeof *device->hidden));
155 SDL_memset(device->hidden, 0, (sizeof *device->hidden));
156 device->hidden->dibInfo = (DibInfo *)SDL_malloc((sizeof(DibInfo)));
157 if(device->hidden->dibInfo == NULL)
159 SDL_free(device->hidden);
160 device->hidden = NULL;
164 device->gl_data = (struct SDL_PrivateGLData *)
165 SDL_malloc((sizeof *device->gl_data));
167 if ( (device == NULL) || (device->hidden == NULL) ||
168 (device->gl_data == NULL) ) {
170 DIB_DeleteDevice(device);
173 SDL_memset(device->hidden->dibInfo, 0, (sizeof *device->hidden->dibInfo));
174 SDL_memset(device->gl_data, 0, (sizeof *device->gl_data));
176 /* Set the function pointers */
177 device->VideoInit = DIB_VideoInit;
178 device->ListModes = DIB_ListModes;
179 device->SetVideoMode = DIB_SetVideoMode;
180 device->UpdateMouse = WIN_UpdateMouse;
181 device->SetColors = DIB_SetColors;
182 device->UpdateRects = NULL;
183 device->VideoQuit = DIB_VideoQuit;
184 device->AllocHWSurface = DIB_AllocHWSurface;
185 device->CheckHWBlit = NULL;
186 device->FillHWRect = NULL;
187 device->SetHWColorKey = NULL;
188 device->SetHWAlpha = NULL;
189 device->LockHWSurface = DIB_LockHWSurface;
190 device->UnlockHWSurface = DIB_UnlockHWSurface;
191 device->FlipHWSurface = NULL;
192 device->FreeHWSurface = DIB_FreeHWSurface;
193 device->SetGammaRamp = DIB_SetGammaRamp;
194 device->GetGammaRamp = DIB_GetGammaRamp;
196 device->GL_LoadLibrary = WIN_GL_LoadLibrary;
197 device->GL_GetProcAddress = WIN_GL_GetProcAddress;
198 device->GL_GetAttribute = WIN_GL_GetAttribute;
199 device->GL_MakeCurrent = WIN_GL_MakeCurrent;
200 device->GL_SwapBuffers = WIN_GL_SwapBuffers;
202 device->SetCaption = WIN_SetWMCaption;
203 device->SetIcon = WIN_SetWMIcon;
204 device->IconifyWindow = WIN_IconifyWindow;
205 device->GrabInput = WIN_GrabInput;
206 device->GetWMInfo = WIN_GetWMInfo;
207 device->FreeWMCursor = WIN_FreeWMCursor;
208 device->CreateWMCursor = WIN_CreateWMCursor;
209 device->ShowWMCursor = WIN_ShowWMCursor;
210 device->WarpWMCursor = WIN_WarpWMCursor;
211 device->CheckMouseMode = WIN_CheckMouseMode;
212 device->InitOSKeymap = DIB_InitOSKeymap;
213 device->PumpEvents = DIB_PumpEvents;
215 /* Set up the windows message handling functions */
216 WIN_Activate = DIB_Activate;
217 WIN_RealizePalette = DIB_RealizePalette;
218 WIN_PaletteChanged = DIB_PaletteChanged;
219 WIN_WinPAINT = DIB_WinPAINT;
220 HandleMessage = DIB_HandleMessage;
222 device->free = DIB_DeleteDevice;
224 /* We're finally ready */
228 VideoBootStrap WINDIB_bootstrap = {
229 "windib", "Win95/98/NT/2000/CE GDI",
230 DIB_Available, DIB_CreateDevice
233 static int cmpmodes(const void *va, const void *vb)
235 SDL_Rect *a = *(SDL_Rect **)va;
236 SDL_Rect *b = *(SDL_Rect **)vb;
243 static int DIB_AddMode(_THIS, int bpp, int w, int h)
249 /* Check to see if we already have this mode */
250 if ( bpp < 8 || bpp > 32 ) { /* Not supported */
253 index = ((bpp+7)/8)-1;
254 for ( i=0; i<SDL_nummodes[index]; ++i ) {
255 mode = SDL_modelist[index][i];
256 if ( (mode->w == w) && (mode->h == h) ) {
261 /* Set up the new video mode rectangle */
262 mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
263 if ( mode == NULL ) {
272 /* Allocate the new list of modes, and fill in the new mode */
273 next_mode = SDL_nummodes[index];
274 SDL_modelist[index] = (SDL_Rect **)
275 SDL_realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
276 if ( SDL_modelist[index] == NULL ) {
278 SDL_nummodes[index] = 0;
282 SDL_modelist[index][next_mode] = mode;
283 SDL_modelist[index][next_mode+1] = NULL;
284 SDL_nummodes[index]++;
289 static void DIB_CreatePalette(_THIS, int bpp)
291 /* RJR: March 28, 2000
292 moved palette creation here from "DIB_VideoInit" */
298 ncolors = (1 << bpp);
299 palette = (LOGPALETTE *)SDL_malloc(sizeof(*palette)+
300 ncolors*sizeof(PALETTEENTRY));
301 palette->palVersion = 0x300;
302 palette->palNumEntries = ncolors;
303 hdc = GetDC(SDL_Window);
304 GetSystemPaletteEntries(hdc, 0, ncolors, palette->palPalEntry);
305 ReleaseDC(SDL_Window, hdc);
306 screen_pal = CreatePalette(palette);
307 screen_logpal = palette;
310 int DIB_VideoInit(_THIS, SDL_PixelFormat *vformat)
312 const char *env = NULL;
313 #ifndef NO_CHANGEDISPLAYSETTINGS
318 /* Create the window */
319 if ( DIB_CreateWindow(this) < 0 ) {
323 #if !SDL_AUDIO_DISABLED
324 DX5_SoundFocus(SDL_Window);
327 /* Determine the screen depth */
328 vformat->BitsPerPixel = DIB_SussScreenDepth();
329 switch (vformat->BitsPerPixel) {
331 vformat->Rmask = 0x00007c00;
332 vformat->Gmask = 0x000003e0;
333 vformat->Bmask = 0x0000001f;
334 vformat->BitsPerPixel = 16;
337 vformat->Rmask = 0x0000f800;
338 vformat->Gmask = 0x000007e0;
339 vformat->Bmask = 0x0000001f;
343 /* GDI defined as 8-8-8 */
344 vformat->Rmask = 0x00ff0000;
345 vformat->Gmask = 0x0000ff00;
346 vformat->Bmask = 0x000000ff;
352 /* See if gamma is supported on this screen */
353 DIB_CheckGamma(this);
355 #ifndef NO_CHANGEDISPLAYSETTINGS
357 settings.dmSize = sizeof(DEVMODE);
358 settings.dmDriverExtra = 0;
360 settings.dmFields = DM_DISPLAYQUERYORIENTATION;
361 this->hidden->supportRotation = ChangeDisplaySettingsEx(NULL, &settings, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL;
363 /* Query for the desktop resolution */
364 SDL_desktop_mode.dmSize = sizeof(SDL_desktop_mode);
365 SDL_desktop_mode.dmDriverExtra = 0;
366 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &SDL_desktop_mode);
367 this->info.current_w = SDL_desktop_mode.dmPelsWidth;
368 this->info.current_h = SDL_desktop_mode.dmPelsHeight;
370 /* Query for the list of available video modes */
371 for ( i=0; EnumDisplaySettings(NULL, i, &settings); ++i ) {
372 DIB_AddMode(this, settings.dmBitsPerPel,
373 settings.dmPelsWidth, settings.dmPelsHeight);
375 if( this->hidden->supportRotation )
376 DIB_AddMode(this, settings.dmBitsPerPel,
377 settings.dmPelsHeight, settings.dmPelsWidth);
380 /* Sort the mode lists */
381 for ( i=0; i<NUM_MODELISTS; ++i ) {
382 if ( SDL_nummodes[i] > 0 ) {
383 SDL_qsort(SDL_modelist[i], SDL_nummodes[i], sizeof *SDL_modelist[i], cmpmodes);
387 // WinCE and fullscreen mode:
388 // We use only vformat->BitsPerPixel that allow SDL to
389 // emulate other bpp (8, 32) and use triple buffer,
390 // because SDL surface conversion is much faster than the WinCE one.
391 // Although it should be tested on devices with graphics accelerator.
393 DIB_AddMode(this, vformat->BitsPerPixel,
394 GetDeviceCaps(GetDC(NULL), HORZRES),
395 GetDeviceCaps(GetDC(NULL), VERTRES));
397 #endif /* !NO_CHANGEDISPLAYSETTINGS */
399 /* Grab an identity palette if we are in a palettized mode */
400 if ( vformat->BitsPerPixel <= 8 ) {
401 /* RJR: March 28, 2000
402 moved palette creation to "DIB_CreatePalette" */
403 DIB_CreatePalette(this, vformat->BitsPerPixel);
406 /* Fill in some window manager capabilities */
407 this->info.wm_available = 1;
410 this->hidden->origRotation = -1;
413 /* Allow environment override of screensaver disable. */
414 env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER");
416 allow_screensaver = SDL_atoi(env);
418 #ifdef SDL_VIDEO_DISABLE_SCREENSAVER
419 allow_screensaver = 0;
421 allow_screensaver = 1;
429 /* We support any format at any dimension */
430 SDL_Rect **DIB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
432 if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
433 return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
435 return((SDL_Rect **)-1);
441 Helper fn to work out which screen depth windows is currently using.
442 15 bit mode is considered 555 format, 16 bit is 565.
443 returns 0 for unknown mode.
444 (Derived from code in sept 1999 Windows Developer Journal
445 http://www.wdj.com/code/archive.html)
447 static int DIB_SussScreenDepth()
453 hdc = GetDC(SDL_Window);
454 depth = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
455 ReleaseDC(SDL_Window, hdc);
460 LPBITMAPINFOHEADER dib_hdr;
464 /* Allocate enough space for a DIB header plus palette (for
465 * 8-bit modes) or bitfields (for 16- and 32-bit modes)
467 dib_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof (RGBQUAD);
468 dib_hdr = (LPBITMAPINFOHEADER) SDL_malloc(dib_size);
469 SDL_memset(dib_hdr, 0, dib_size);
470 dib_hdr->biSize = sizeof(BITMAPINFOHEADER);
472 /* Get a device-dependent bitmap that's compatible with the
476 hbm = CreateCompatibleBitmap( hdc, 1, 1 );
478 /* Convert the DDB to a DIB. We need to call GetDIBits twice:
479 * the first call just fills in the BITMAPINFOHEADER; the
480 * second fills in the bitfields or palette.
482 GetDIBits(hdc, hbm, 0, 1, NULL, (LPBITMAPINFO) dib_hdr, DIB_RGB_COLORS);
483 GetDIBits(hdc, hbm, 0, 1, NULL, (LPBITMAPINFO) dib_hdr, DIB_RGB_COLORS);
485 ReleaseDC(NULL, hdc);
488 switch( dib_hdr->biBitCount )
490 case 8: depth = 8; break;
491 case 24: depth = 24; break;
492 case 32: depth = 32; break;
494 if( dib_hdr->biCompression == BI_BITFIELDS ) {
495 /* check the red mask */
496 switch( ((DWORD*)((char*)dib_hdr + dib_hdr->biSize))[0] ) {
497 case 0xf800: depth = 16; break; /* 565 */
498 case 0x7c00: depth = 15; break; /* 555 */
504 #endif /* NO_GETDIBITS */
508 /* Various screen update functions available */
509 static void DIB_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);
511 static void DIB_ResizeWindow(_THIS, int width, int height, int prev_width, int prev_height, Uint32 flags)
517 /* Resize the window */
518 if ( !SDL_windowid && !IsZoomed(SDL_Window) ) {
520 if ( !SDL_windowid ) {
524 const char *window = NULL;
525 const char *center = NULL;
527 if ( width != prev_width || height != prev_height ) {
528 window = SDL_getenv("SDL_VIDEO_WINDOW_POS");
529 center = SDL_getenv("SDL_VIDEO_CENTERED");
531 if ( SDL_sscanf(window, "%d,%d", &x, &y) == 2 ) {
535 if ( SDL_strcmp(window, "center") == 0 ) {
540 swp_flags = (SWP_NOCOPYBITS | SWP_SHOWWINDOW);
542 bounds.left = SDL_windowX;
543 bounds.top = SDL_windowY;
544 bounds.right = SDL_windowX+width;
545 bounds.bottom = SDL_windowY+height;
547 AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE), (GetMenu(SDL_Window) != NULL), 0);
549 // The bMenu parameter must be FALSE; menu bars are not supported
550 AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE), 0, 0);
552 width = bounds.right-bounds.left;
553 height = bounds.bottom-bounds.top;
554 if ( (flags & SDL_FULLSCREEN) ) {
555 x = (GetSystemMetrics(SM_CXSCREEN)-width)/2;
556 y = (GetSystemMetrics(SM_CYSCREEN)-height)/2;
557 } else if ( center ) {
558 x = (GetSystemMetrics(SM_CXSCREEN)-width)/2;
559 y = (GetSystemMetrics(SM_CYSCREEN)-height)/2;
560 } else if ( SDL_windowX || SDL_windowY || window ) {
565 swp_flags |= SWP_NOMOVE;
567 if ( flags & SDL_FULLSCREEN ) {
570 top = HWND_NOTOPMOST;
572 SetWindowPos(SDL_Window, top, x, y, width, height, swp_flags);
573 if ( !(flags & SDL_FULLSCREEN) ) {
574 SDL_windowX = SDL_bounds.left;
575 SDL_windowY = SDL_bounds.top;
577 if ( GetParent(SDL_Window) == NULL ) {
578 SetForegroundWindow(SDL_Window);
583 SDL_Surface *DIB_SetVideoMode(_THIS, SDL_Surface *current,
584 int width, int height, int bpp, Uint32 flags)
590 const DWORD directstyle =
592 const DWORD windowstyle =
593 (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX);
594 const DWORD resizestyle =
595 (WS_THICKFRAME|WS_MAXIMIZEBOX);
599 Uint32 Rmask, Gmask, Bmask;
603 prev_flags = current->flags;
606 * Special case for OpenGL windows...since the app needs to call
607 * SDL_SetVideoMode() in response to resize events to continue to
608 * function, but WGL handles the GL context details behind the scenes,
609 * there's no sense in tearing the context down just to rebuild it
610 * to what it already was...tearing it down sacrifices your GL state
611 * and uploaded textures. So if we're requesting the same video mode
612 * attributes just resize the window and return immediately.
615 ((current->flags & ~SDL_ANYFORMAT) == (flags & ~SDL_ANYFORMAT)) &&
616 (current->format->BitsPerPixel == bpp) &&
617 (flags & SDL_OPENGL) &&
618 !(flags & SDL_FULLSCREEN) ) { /* probably not safe for fs */
622 DIB_ResizeWindow(this, width, height, prev_w, prev_h, flags);
627 /* Clean up any GL context that may be hanging around */
628 if ( current->flags & SDL_OPENGL ) {
629 WIN_GL_ShutDown(this);
633 /* Recalculate the bitmasks if necessary */
634 if ( bpp == current->format->BitsPerPixel ) {
640 if ( DIB_SussScreenDepth() == 15 ) {
654 /* GDI defined as 8-8-8 */
665 video = SDL_CreateRGBSurface(SDL_SWSURFACE,
666 0, 0, bpp, Rmask, Gmask, Bmask, 0);
667 if ( video == NULL ) {
673 /* Fill in part of the video surface */
674 video->flags = 0; /* Clear flags */
677 video->pitch = SDL_CalculatePitch(video);
679 /* Small fix for WinCE/Win32 - when activating window
680 SDL_VideoSurface is equal to zero, so activating code
681 is not called properly for fullscreen windows because
682 macros WINDIB_FULLSCREEN uses SDL_VideoSurface
684 SDL_VideoSurface = video;
686 #if defined(_WIN32_WCE)
687 if ( flags & SDL_FULLSCREEN )
688 video->flags |= SDL_FULLSCREEN;
691 #ifndef NO_CHANGEDISPLAYSETTINGS
692 /* Set fullscreen mode if appropriate */
693 if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
697 SDL_memset(&settings, 0, sizeof(DEVMODE));
698 settings.dmSize = sizeof(DEVMODE);
701 // try to rotate screen to fit requested resolution
702 if( this->hidden->supportRotation )
707 settings.dmFields = DM_DISPLAYORIENTATION;
708 ChangeDisplaySettingsEx(NULL, &settings, NULL, CDS_TEST, NULL);
709 rotation = settings.dmDisplayOrientation;
711 if( (width > GetDeviceCaps(GetDC(NULL), HORZRES))
712 && (height < GetDeviceCaps(GetDC(NULL), VERTRES)))
717 settings.dmDisplayOrientation = DMDO_90;
720 settings.dmDisplayOrientation = DMDO_180;
723 if( settings.dmDisplayOrientation != rotation )
726 this->hidden->origRotation = rotation;
727 ChangeDisplaySettingsEx(NULL,&settings,NULL,CDS_RESET,NULL);
730 if( (width < GetDeviceCaps(GetDC(NULL), HORZRES))
731 && (height > GetDeviceCaps(GetDC(NULL), VERTRES)))
736 settings.dmDisplayOrientation = DMDO_0;
739 settings.dmDisplayOrientation = DMDO_270;
742 if( settings.dmDisplayOrientation != rotation )
745 this->hidden->origRotation = rotation;
746 ChangeDisplaySettingsEx(NULL,&settings,NULL,CDS_RESET,NULL);
754 settings.dmBitsPerPel = video->format->BitsPerPixel;
755 settings.dmPelsWidth = width;
756 settings.dmPelsHeight = height;
757 settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
758 if ( width <= (int)SDL_desktop_mode.dmPelsWidth &&
759 height <= (int)SDL_desktop_mode.dmPelsHeight ) {
760 settings.dmDisplayFrequency = SDL_desktop_mode.dmDisplayFrequency;
761 settings.dmFields |= DM_DISPLAYFREQUENCY;
763 changed = (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL);
764 if ( ! changed && (settings.dmFields & DM_DISPLAYFREQUENCY) ) {
765 settings.dmFields &= ~DM_DISPLAYFREQUENCY;
766 changed = (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL);
772 video->flags |= SDL_FULLSCREEN;
773 SDL_fullscreen_mode = settings;
777 #endif /* !NO_CHANGEDISPLAYSETTINGS */
779 /* Reset the palette and create a new one if necessary */
780 if ( grab_palette ) {
781 DIB_ReleaseStaticColors(SDL_Window);
782 grab_palette = FALSE;
784 if ( screen_pal != NULL ) {
785 /* RJR: March 28, 2000
786 delete identity palette if switching from a palettized mode */
787 DeleteObject(screen_pal);
790 if ( screen_logpal != NULL ) {
791 SDL_free(screen_logpal);
792 screen_logpal = NULL;
797 /* RJR: March 28, 2000
798 create identity palette switching to a palettized mode */
799 DIB_CreatePalette(this, bpp);
802 style = GetWindowLong(SDL_Window, GWL_STYLE);
803 style &= ~(resizestyle|WS_MAXIMIZE);
804 if ( (video->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
805 style &= ~windowstyle;
806 style |= directstyle;
808 #ifndef NO_CHANGEDISPLAYSETTINGS
809 if ( (prev_flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
810 ChangeDisplaySettings(NULL, 0);
813 if ( flags & SDL_NOFRAME ) {
814 style &= ~windowstyle;
815 style |= directstyle;
816 video->flags |= SDL_NOFRAME;
818 style &= ~directstyle;
819 style |= windowstyle;
820 if ( flags & SDL_RESIZABLE ) {
821 style |= resizestyle;
822 video->flags |= SDL_RESIZABLE;
825 #if WS_MAXIMIZE && !defined(_WIN32_WCE)
826 if (IsZoomed(SDL_Window)) style |= WS_MAXIMIZE;
830 /* DJM: Don't piss of anyone who has setup his own window */
832 SetWindowLong(SDL_Window, GWL_STYLE, style);
834 /* Delete the old bitmap if necessary */
835 if ( screen_bmp != NULL ) {
836 DeleteObject(screen_bmp);
838 if ( ! (flags & SDL_OPENGL) ) {
839 BOOL is16bitmode = (video->format->BytesPerPixel == 2);
841 /* Suss out the bitmap info header */
842 binfo_size = sizeof(*binfo);
844 /* 16bit modes, palette area used for rgb bitmasks */
845 binfo_size += 3*sizeof(DWORD);
846 } else if ( video->format->palette ) {
847 binfo_size += video->format->palette->ncolors *
850 binfo = (BITMAPINFO *)SDL_malloc(binfo_size);
852 if ( video != current ) {
853 SDL_FreeSurface(video);
859 binfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
860 binfo->bmiHeader.biWidth = video->w;
861 binfo->bmiHeader.biHeight = -video->h; /* -ve for topdown bitmap */
862 binfo->bmiHeader.biPlanes = 1;
863 binfo->bmiHeader.biSizeImage = video->h * video->pitch;
864 binfo->bmiHeader.biXPelsPerMeter = 0;
865 binfo->bmiHeader.biYPelsPerMeter = 0;
866 binfo->bmiHeader.biClrUsed = 0;
867 binfo->bmiHeader.biClrImportant = 0;
868 binfo->bmiHeader.biBitCount = video->format->BitsPerPixel;
871 /* BI_BITFIELDS tells CreateDIBSection about the rgb masks in the palette */
872 binfo->bmiHeader.biCompression = BI_BITFIELDS;
873 ((Uint32*)binfo->bmiColors)[0] = video->format->Rmask;
874 ((Uint32*)binfo->bmiColors)[1] = video->format->Gmask;
875 ((Uint32*)binfo->bmiColors)[2] = video->format->Bmask;
877 binfo->bmiHeader.biCompression = BI_RGB; /* BI_BITFIELDS for 565 vs 555 */
878 if ( video->format->palette ) {
879 SDL_memset(binfo->bmiColors, 0,
880 video->format->palette->ncolors*sizeof(RGBQUAD));
884 /* Create the offscreen bitmap buffer */
885 hdc = GetDC(SDL_Window);
886 screen_bmp = CreateDIBSection(hdc, binfo, DIB_RGB_COLORS,
887 (void **)(&video->pixels), NULL, 0);
888 ReleaseDC(SDL_Window, hdc);
890 if ( screen_bmp == NULL ) {
891 if ( video != current ) {
892 SDL_FreeSurface(video);
894 SDL_SetError("Couldn't create DIB section");
897 this->UpdateRects = DIB_NormalUpdate;
899 /* Set video surface flags */
900 if ( screen_pal && (flags & (SDL_FULLSCREEN|SDL_HWPALETTE)) ) {
904 /* BitBlt() maps colors for us */
905 video->flags |= SDL_HWPALETTE;
908 DIB_ResizeWindow(this, width, height, prev_w, prev_h, flags);
911 /* Set up for OpenGL */
912 if ( flags & SDL_OPENGL ) {
913 if ( WIN_GL_SetupWindow(this) < 0 ) {
916 video->flags |= SDL_OPENGL;
920 Flush the message loop or this can cause big problems later
921 Especially if the user decides to use dialog boxes or assert()!
923 WIN_FlushMessageQueue();
929 /* We don't actually allow hardware surfaces in the DIB driver */
930 static int DIB_AllocHWSurface(_THIS, SDL_Surface *surface)
934 static void DIB_FreeHWSurface(_THIS, SDL_Surface *surface)
938 static int DIB_LockHWSurface(_THIS, SDL_Surface *surface)
942 static void DIB_UnlockHWSurface(_THIS, SDL_Surface *surface)
947 static void DIB_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
952 hdc = GetDC(SDL_Window);
954 SelectPalette(hdc, screen_pal, FALSE);
956 mdc = CreateCompatibleDC(hdc);
957 SelectObject(mdc, screen_bmp);
958 for ( i=0; i<numrects; ++i ) {
959 BitBlt(hdc, rects[i].x, rects[i].y, rects[i].w, rects[i].h,
960 mdc, rects[i].x, rects[i].y, SRCCOPY);
963 ReleaseDC(SDL_Window, hdc);
966 static int FindPaletteIndex(LOGPALETTE *pal, BYTE r, BYTE g, BYTE b)
970 int nentries = pal->palNumEntries;
972 for ( i = 0; i < nentries; ++i ) {
973 entry = &pal->palPalEntry[i];
974 if ( entry->peRed == r && entry->peGreen == g && entry->peBlue == b ) {
981 static BOOL CheckPaletteEntry(LOGPALETTE *pal, int index, BYTE r, BYTE g, BYTE b)
986 entry = &pal->palPalEntry[index];
987 if ( entry->peRed != r || entry->peGreen != g || entry->peBlue != b ) {
988 int found = FindPaletteIndex(pal, r, g, b);
990 pal->palPalEntry[found] = *entry;
1002 int DIB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
1004 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1011 int moved_entries = 0;
1013 /* Update the display palette */
1014 hdc = GetDC(SDL_Window);
1016 PALETTEENTRY *entry;
1018 for ( i=0; i<ncolors; ++i ) {
1019 entry = &screen_logpal->palPalEntry[firstcolor+i];
1020 entry->peRed = colors[i].r;
1021 entry->peGreen = colors[i].g;
1022 entry->peBlue = colors[i].b;
1023 entry->peFlags = PC_NOCOLLAPSE;
1025 #if defined(SYSPAL_NOSTATIC) && !defined(_WIN32_WCE)
1026 /* Check to make sure black and white are in position */
1027 if ( GetSystemPaletteUse(hdc) != SYSPAL_NOSTATIC256 ) {
1028 moved_entries += CheckPaletteEntry(screen_logpal, 0, 0x00, 0x00, 0x00);
1029 moved_entries += CheckPaletteEntry(screen_logpal, screen_logpal->palNumEntries-1, 0xff, 0xff, 0xff);
1032 If we don't have full access to the palette, what we
1033 really want to do is find the 236 most diverse colors
1034 in the desired palette, set those entries (10-245) and
1035 then map everything into the new system palette.
1040 /* Copy the entries into the system palette */
1041 UnrealizeObject(screen_pal);
1043 SetPaletteEntries(screen_pal, 0, screen_logpal->palNumEntries, screen_logpal->palPalEntry);
1044 SelectPalette(hdc, screen_pal, FALSE);
1045 RealizePalette(hdc);
1048 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1049 /* Copy palette colors into DIB palette */
1050 pal = SDL_stack_alloc(RGBQUAD, ncolors);
1051 for ( i=0; i<ncolors; ++i ) {
1052 pal[i].rgbRed = colors[i].r;
1053 pal[i].rgbGreen = colors[i].g;
1054 pal[i].rgbBlue = colors[i].b;
1055 pal[i].rgbReserved = 0;
1058 /* Set the DIB palette and update the display */
1059 mdc = CreateCompatibleDC(hdc);
1060 SelectObject(mdc, screen_bmp);
1061 SetDIBColorTable(mdc, firstcolor, ncolors, pal);
1062 if ( moved_entries || !grab_palette ) {
1063 BitBlt(hdc, 0, 0, this->screen->w, this->screen->h,
1064 mdc, 0, 0, SRCCOPY);
1067 SDL_stack_free(pal);
1069 ReleaseDC(SDL_Window, hdc);
1074 static void DIB_CheckGamma(_THIS)
1076 #ifndef NO_GAMMA_SUPPORT
1080 /* If we fail to get gamma, disable gamma control */
1081 hdc = GetDC(SDL_Window);
1082 if ( ! GetDeviceGammaRamp(hdc, ramp) ) {
1083 this->GetGammaRamp = NULL;
1084 this->SetGammaRamp = NULL;
1086 ReleaseDC(SDL_Window, hdc);
1087 #endif /* !NO_GAMMA_SUPPORT */
1089 void DIB_SwapGamma(_THIS)
1091 #ifndef NO_GAMMA_SUPPORT
1094 if ( gamma_saved ) {
1095 hdc = GetDC(SDL_Window);
1096 if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
1097 /* About to leave active state, restore gamma */
1098 SetDeviceGammaRamp(hdc, gamma_saved);
1100 /* About to enter active state, set game gamma */
1101 GetDeviceGammaRamp(hdc, gamma_saved);
1102 SetDeviceGammaRamp(hdc, this->gamma);
1104 ReleaseDC(SDL_Window, hdc);
1106 #endif /* !NO_GAMMA_SUPPORT */
1108 void DIB_QuitGamma(_THIS)
1110 #ifndef NO_GAMMA_SUPPORT
1111 if ( gamma_saved ) {
1112 /* Restore the original gamma if necessary */
1113 if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
1116 hdc = GetDC(SDL_Window);
1117 SetDeviceGammaRamp(hdc, gamma_saved);
1118 ReleaseDC(SDL_Window, hdc);
1121 /* Free the saved gamma memory */
1122 SDL_free(gamma_saved);
1125 #endif /* !NO_GAMMA_SUPPORT */
1128 int DIB_SetGammaRamp(_THIS, Uint16 *ramp)
1130 #ifdef NO_GAMMA_SUPPORT
1131 SDL_SetError("SDL compiled without gamma ramp support");
1137 /* Set the ramp for the display */
1138 if ( ! gamma_saved ) {
1139 gamma_saved = (WORD *)SDL_malloc(3*256*sizeof(*gamma_saved));
1140 if ( ! gamma_saved ) {
1144 hdc = GetDC(SDL_Window);
1145 GetDeviceGammaRamp(hdc, gamma_saved);
1146 ReleaseDC(SDL_Window, hdc);
1148 if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
1149 hdc = GetDC(SDL_Window);
1150 succeeded = SetDeviceGammaRamp(hdc, ramp);
1151 ReleaseDC(SDL_Window, hdc);
1155 return succeeded ? 0 : -1;
1156 #endif /* !NO_GAMMA_SUPPORT */
1159 int DIB_GetGammaRamp(_THIS, Uint16 *ramp)
1161 #ifdef NO_GAMMA_SUPPORT
1162 SDL_SetError("SDL compiled without gamma ramp support");
1168 /* Get the ramp from the display */
1169 hdc = GetDC(SDL_Window);
1170 succeeded = GetDeviceGammaRamp(hdc, ramp);
1171 ReleaseDC(SDL_Window, hdc);
1172 return succeeded ? 0 : -1;
1173 #endif /* !NO_GAMMA_SUPPORT */
1176 void DIB_VideoQuit(_THIS)
1180 /* Destroy the window and everything associated with it */
1182 /* Delete the screen bitmap (also frees screen->pixels) */
1183 if ( this->screen ) {
1184 if ( grab_palette ) {
1185 DIB_ReleaseStaticColors(SDL_Window);
1187 #ifndef NO_CHANGEDISPLAYSETTINGS
1188 if ( this->screen->flags & SDL_FULLSCREEN ) {
1189 ChangeDisplaySettings(NULL, 0);
1190 ShowWindow(SDL_Window, SW_HIDE);
1193 if ( this->screen->flags & SDL_OPENGL ) {
1194 WIN_GL_ShutDown(this);
1196 this->screen->pixels = NULL;
1198 if ( screen_pal != NULL ) {
1199 DeleteObject(screen_pal);
1202 if ( screen_logpal != NULL ) {
1203 SDL_free(screen_logpal);
1204 screen_logpal = NULL;
1207 DeleteObject(screen_bmp);
1211 DestroyIcon(screen_icn);
1214 DIB_QuitGamma(this);
1215 DIB_DestroyWindow(this);
1219 #if defined(_WIN32_WCE)
1221 // Unload wince aygshell library to prevent leak
1224 FreeLibrary(aygshell);
1230 for ( i=0; i < SDL_arraysize(SDL_modelist); ++i ) {
1231 if ( !SDL_modelist[i] ) {
1234 for ( j=0; SDL_modelist[i][j]; ++j ) {
1235 SDL_free(SDL_modelist[i][j]);
1237 SDL_free(SDL_modelist[i]);
1238 SDL_modelist[i] = NULL;
1239 SDL_nummodes[i] = 0;
1243 /* Exported for the windows message loop only */
1244 static void DIB_GrabStaticColors(HWND window)
1246 #if defined(SYSPAL_NOSTATIC) && !defined(_WIN32_WCE)
1249 hdc = GetDC(window);
1250 SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC256);
1251 if ( GetSystemPaletteUse(hdc) != SYSPAL_NOSTATIC256 ) {
1252 SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
1254 ReleaseDC(window, hdc);
1257 static void DIB_ReleaseStaticColors(HWND window)
1259 #if defined(SYSPAL_NOSTATIC) && !defined(_WIN32_WCE)
1262 hdc = GetDC(window);
1263 SetSystemPaletteUse(hdc, SYSPAL_STATIC);
1264 ReleaseDC(window, hdc);
1267 static void DIB_Activate(_THIS, BOOL active, BOOL minimized)
1269 if ( grab_palette ) {
1271 DIB_ReleaseStaticColors(SDL_Window);
1272 DIB_RealizePalette(this);
1273 } else if ( !minimized ) {
1274 DIB_GrabStaticColors(SDL_Window);
1275 DIB_RealizePalette(this);
1279 static void DIB_RealizePalette(_THIS)
1281 if ( screen_pal != NULL ) {
1284 hdc = GetDC(SDL_Window);
1286 UnrealizeObject(screen_pal);
1288 SelectPalette(hdc, screen_pal, FALSE);
1289 if ( RealizePalette(hdc) ) {
1290 InvalidateRect(SDL_Window, NULL, FALSE);
1292 ReleaseDC(SDL_Window, hdc);
1295 static void DIB_PaletteChanged(_THIS, HWND window)
1297 if ( window != SDL_Window ) {
1298 DIB_RealizePalette(this);
1302 /* Exported for the windows message loop only */
1303 static void DIB_WinPAINT(_THIS, HDC hdc)
1308 SelectPalette(hdc, screen_pal, FALSE);
1310 mdc = CreateCompatibleDC(hdc);
1311 SelectObject(mdc, screen_bmp);
1312 BitBlt(hdc, 0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h,
1313 mdc, 0, 0, SRCCOPY);
1317 /* Stub in case DirectX isn't available */
1318 #if !SDL_AUDIO_DRIVER_DSOUND
1319 void DX5_SoundFocus(HWND hwnd)