1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
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.
9
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.
14
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
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#define WIN32_LEAN_AND_MEAN 1
25#include <windows.h>
26
27/* Not yet in the mingw32 cross-compile headers */
28#ifndef CDS_FULLSCREEN
29#define CDS_FULLSCREEN	4
30#endif
31
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"
43
44#ifdef _WIN32_WCE
45
46#ifndef DM_DISPLAYORIENTATION
47#define DM_DISPLAYORIENTATION 0x00800000L
48#endif
49#ifndef DM_DISPLAYQUERYORIENTATION
50#define DM_DISPLAYQUERYORIENTATION 0x01000000L
51#endif
52#ifndef DMDO_0
53#define DMDO_0      0
54#endif
55#ifndef DMDO_90
56#define DMDO_90     1
57#endif
58#ifndef DMDO_180
59#define DMDO_180    2
60#endif
61#ifndef DMDO_270
62#define DMDO_270    4
63#endif
64
65#define NO_GETDIBITS
66#define NO_GAMMA_SUPPORT
67  #if _WIN32_WCE < 420
68    #define NO_CHANGEDISPLAYSETTINGS
69  #else
70    #define ChangeDisplaySettings(lpDevMode, dwFlags) ChangeDisplaySettingsEx(NULL, (lpDevMode), 0, (dwFlags), 0)
71  #endif
72#endif
73#ifndef WS_MAXIMIZE
74#define WS_MAXIMIZE	0
75#endif
76#ifndef WS_THICKFRAME
77#define WS_THICKFRAME	0
78#endif
79#ifndef SWP_NOCOPYBITS
80#define SWP_NOCOPYBITS	0
81#endif
82#ifndef PC_NOCOLLAPSE
83#define PC_NOCOLLAPSE	0
84#endif
85
86#ifdef _WIN32_WCE
87// defined and used in SDL_sysevents.c
88extern HINSTANCE aygshell;
89#endif
90
91/* Initialization/Query functions */
92static int DIB_VideoInit(_THIS, SDL_PixelFormat *vformat);
93static SDL_Rect **DIB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
94SDL_Surface *DIB_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
95static int DIB_SetColors(_THIS, int firstcolor, int ncolors,
96			 SDL_Color *colors);
97static void DIB_CheckGamma(_THIS);
98void DIB_SwapGamma(_THIS);
99void DIB_QuitGamma(_THIS);
100int DIB_SetGammaRamp(_THIS, Uint16 *ramp);
101int DIB_GetGammaRamp(_THIS, Uint16 *ramp);
102static void DIB_VideoQuit(_THIS);
103
104/* Hardware surface functions */
105static int DIB_AllocHWSurface(_THIS, SDL_Surface *surface);
106static int DIB_LockHWSurface(_THIS, SDL_Surface *surface);
107static void DIB_UnlockHWSurface(_THIS, SDL_Surface *surface);
108static void DIB_FreeHWSurface(_THIS, SDL_Surface *surface);
109
110/* Windows message handling functions */
111static void DIB_GrabStaticColors(HWND window);
112static void DIB_ReleaseStaticColors(HWND window);
113static void DIB_Activate(_THIS, BOOL active, BOOL minimized);
114static void DIB_RealizePalette(_THIS);
115static void DIB_PaletteChanged(_THIS, HWND window);
116static void DIB_WinPAINT(_THIS, HDC hdc);
117
118static void DIB_GetWinPos(_THIS, int* px, int *py);
119static void DIB_SetWinPos(_THIS, int  x, int  y);
120static int  DIB_IsWinVisible(_THIS, int recenter);
121static int  DIB_GetMonitorDPI(_THIS, int* xDpi, int *yDpi);
122static int  DIB_GetMonitorRect(_THIS, SDL_Rect*  rect);
123
124/* helper fn */
125static int DIB_SussScreenDepth();
126
127/* DIB driver bootstrap functions */
128
129static int DIB_Available(void)
130{
131	return(1);
132}
133
134static void DIB_DeleteDevice(SDL_VideoDevice *device)
135{
136	if ( device ) {
137		if ( device->hidden ) {
138			if ( device->hidden->dibInfo ) {
139				SDL_free( device->hidden->dibInfo );
140			}
141			SDL_free(device->hidden);
142		}
143		if ( device->gl_data ) {
144			SDL_free(device->gl_data);
145		}
146		SDL_free(device);
147	}
148}
149
150static SDL_VideoDevice *DIB_CreateDevice(int devindex)
151{
152	SDL_VideoDevice *device;
153
154	/* Initialize all variables that we clean on shutdown */
155	device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
156	if ( device ) {
157		SDL_memset(device, 0, (sizeof *device));
158		device->hidden = (struct SDL_PrivateVideoData *)
159				SDL_malloc((sizeof *device->hidden));
160		if(device->hidden){
161			SDL_memset(device->hidden, 0, (sizeof *device->hidden));
162			device->hidden->dibInfo = (DibInfo *)SDL_malloc((sizeof(DibInfo)));
163			if(device->hidden->dibInfo == NULL)
164			{
165				SDL_free(device->hidden);
166				device->hidden = NULL;
167			}
168		}
169
170		device->gl_data = (struct SDL_PrivateGLData *)
171				SDL_malloc((sizeof *device->gl_data));
172	}
173	if ( (device == NULL) || (device->hidden == NULL) ||
174		                 (device->gl_data == NULL) ) {
175		SDL_OutOfMemory();
176		DIB_DeleteDevice(device);
177		return(NULL);
178	}
179	SDL_memset(device->hidden->dibInfo, 0, (sizeof *device->hidden->dibInfo));
180	SDL_memset(device->gl_data, 0, (sizeof *device->gl_data));
181
182	/* Set the function pointers */
183	device->VideoInit = DIB_VideoInit;
184	device->ListModes = DIB_ListModes;
185	device->SetVideoMode = DIB_SetVideoMode;
186	device->UpdateMouse = WIN_UpdateMouse;
187	device->SetColors = DIB_SetColors;
188	device->UpdateRects = NULL;
189	device->VideoQuit = DIB_VideoQuit;
190	device->AllocHWSurface = DIB_AllocHWSurface;
191	device->CheckHWBlit = NULL;
192	device->FillHWRect = NULL;
193	device->SetHWColorKey = NULL;
194	device->SetHWAlpha = NULL;
195	device->LockHWSurface = DIB_LockHWSurface;
196	device->UnlockHWSurface = DIB_UnlockHWSurface;
197	device->FlipHWSurface = NULL;
198	device->FreeHWSurface = DIB_FreeHWSurface;
199	device->SetGammaRamp = DIB_SetGammaRamp;
200	device->GetGammaRamp = DIB_GetGammaRamp;
201#if SDL_VIDEO_OPENGL
202	device->GL_LoadLibrary = WIN_GL_LoadLibrary;
203	device->GL_GetProcAddress = WIN_GL_GetProcAddress;
204	device->GL_GetAttribute = WIN_GL_GetAttribute;
205	device->GL_MakeCurrent = WIN_GL_MakeCurrent;
206	device->GL_SwapBuffers = WIN_GL_SwapBuffers;
207#endif
208	device->SetCaption = WIN_SetWMCaption;
209	device->SetIcon = WIN_SetWMIcon;
210	device->IconifyWindow = WIN_IconifyWindow;
211	device->GrabInput = WIN_GrabInput;
212	device->GetWMInfo = WIN_GetWMInfo;
213	device->FreeWMCursor = WIN_FreeWMCursor;
214	device->CreateWMCursor = WIN_CreateWMCursor;
215	device->ShowWMCursor = WIN_ShowWMCursor;
216	device->WarpWMCursor = WIN_WarpWMCursor;
217	device->CheckMouseMode = WIN_CheckMouseMode;
218	device->InitOSKeymap = DIB_InitOSKeymap;
219	device->PumpEvents = DIB_PumpEvents;
220
221	device->GetWindowPos = DIB_GetWinPos;
222	device->SetWindowPos = DIB_SetWinPos;
223	device->IsWindowVisible = DIB_IsWinVisible;
224	device->GetMonitorDPI = DIB_GetMonitorDPI;
225	device->GetMonitorRect = DIB_GetMonitorRect;
226
227	/* Set up the windows message handling functions */
228	WIN_Activate = DIB_Activate;
229	WIN_RealizePalette = DIB_RealizePalette;
230	WIN_PaletteChanged = DIB_PaletteChanged;
231	WIN_WinPAINT = DIB_WinPAINT;
232	HandleMessage = DIB_HandleMessage;
233
234	device->free = DIB_DeleteDevice;
235
236	/* We're finally ready */
237	return device;
238}
239
240VideoBootStrap WINDIB_bootstrap = {
241	"windib", "Win95/98/NT/2000/CE GDI",
242	DIB_Available, DIB_CreateDevice
243};
244
245static int cmpmodes(const void *va, const void *vb)
246{
247    SDL_Rect *a = *(SDL_Rect **)va;
248    SDL_Rect *b = *(SDL_Rect **)vb;
249    if ( a->w == b->w )
250        return b->h - a->h;
251    else
252        return b->w - a->w;
253}
254
255static int DIB_AddMode(_THIS, int bpp, int w, int h)
256{
257	SDL_Rect *mode;
258	int i, index;
259	int next_mode;
260
261	/* Check to see if we already have this mode */
262	if ( bpp < 8 || bpp > 32 ) {  /* Not supported */
263		return(0);
264	}
265	index = ((bpp+7)/8)-1;
266	for ( i=0; i<SDL_nummodes[index]; ++i ) {
267		mode = SDL_modelist[index][i];
268		if ( (mode->w == w) && (mode->h == h) ) {
269			return(0);
270		}
271	}
272
273	/* Set up the new video mode rectangle */
274	mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
275	if ( mode == NULL ) {
276		SDL_OutOfMemory();
277		return(-1);
278	}
279	mode->x = 0;
280	mode->y = 0;
281	mode->w = w;
282	mode->h = h;
283
284	/* Allocate the new list of modes, and fill in the new mode */
285	next_mode = SDL_nummodes[index];
286	SDL_modelist[index] = (SDL_Rect **)
287	       SDL_realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
288	if ( SDL_modelist[index] == NULL ) {
289		SDL_OutOfMemory();
290		SDL_nummodes[index] = 0;
291		SDL_free(mode);
292		return(-1);
293	}
294	SDL_modelist[index][next_mode] = mode;
295	SDL_modelist[index][next_mode+1] = NULL;
296	SDL_nummodes[index]++;
297
298	return(0);
299}
300
301static void DIB_CreatePalette(_THIS, int bpp)
302{
303/*	RJR: March 28, 2000
304	moved palette creation here from "DIB_VideoInit" */
305
306	LOGPALETTE *palette;
307	HDC hdc;
308	int ncolors;
309
310	ncolors = (1 << bpp);
311	palette = (LOGPALETTE *)SDL_malloc(sizeof(*palette)+
312				ncolors*sizeof(PALETTEENTRY));
313	palette->palVersion = 0x300;
314	palette->palNumEntries = ncolors;
315	hdc = GetDC(SDL_Window);
316	GetSystemPaletteEntries(hdc, 0, ncolors, palette->palPalEntry);
317	ReleaseDC(SDL_Window, hdc);
318	screen_pal = CreatePalette(palette);
319	screen_logpal = palette;
320}
321
322int DIB_VideoInit(_THIS, SDL_PixelFormat *vformat)
323{
324	const char *env = NULL;
325#ifndef NO_CHANGEDISPLAYSETTINGS
326	int i;
327	DEVMODE settings;
328#endif
329
330	/* Create the window */
331	if ( DIB_CreateWindow(this) < 0 ) {
332		return(-1);
333	}
334
335#if !SDL_AUDIO_DISABLED
336	DX5_SoundFocus(SDL_Window);
337#endif
338
339	/* Determine the screen depth */
340	vformat->BitsPerPixel = DIB_SussScreenDepth();
341	switch (vformat->BitsPerPixel) {
342		case 15:
343			vformat->Rmask = 0x00007c00;
344			vformat->Gmask = 0x000003e0;
345			vformat->Bmask = 0x0000001f;
346			vformat->BitsPerPixel = 16;
347			break;
348		case 16:
349			vformat->Rmask = 0x0000f800;
350			vformat->Gmask = 0x000007e0;
351			vformat->Bmask = 0x0000001f;
352			break;
353		case 24:
354		case 32:
355			/* GDI defined as 8-8-8 */
356			vformat->Rmask = 0x00ff0000;
357			vformat->Gmask = 0x0000ff00;
358			vformat->Bmask = 0x000000ff;
359			break;
360		default:
361			break;
362	}
363
364	/* See if gamma is supported on this screen */
365	DIB_CheckGamma(this);
366
367#ifndef NO_CHANGEDISPLAYSETTINGS
368
369	settings.dmSize = sizeof(DEVMODE);
370	settings.dmDriverExtra = 0;
371#ifdef _WIN32_WCE
372	settings.dmFields = DM_DISPLAYQUERYORIENTATION;
373	this->hidden->supportRotation = ChangeDisplaySettingsEx(NULL, &settings, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL;
374#endif
375	/* Query for the desktop resolution */
376	SDL_desktop_mode.dmSize = sizeof(SDL_desktop_mode);
377	SDL_desktop_mode.dmDriverExtra = 0;
378	EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &SDL_desktop_mode);
379	this->info.current_w = SDL_desktop_mode.dmPelsWidth;
380	this->info.current_h = SDL_desktop_mode.dmPelsHeight;
381
382	/* Query for the list of available video modes */
383	for ( i=0; EnumDisplaySettings(NULL, i, &settings); ++i ) {
384		DIB_AddMode(this, settings.dmBitsPerPel,
385			settings.dmPelsWidth, settings.dmPelsHeight);
386#ifdef _WIN32_WCE
387		if( this->hidden->supportRotation )
388			DIB_AddMode(this, settings.dmBitsPerPel,
389				settings.dmPelsHeight, settings.dmPelsWidth);
390#endif
391	}
392	/* Sort the mode lists */
393	for ( i=0; i<NUM_MODELISTS; ++i ) {
394		if ( SDL_nummodes[i] > 0 ) {
395			SDL_qsort(SDL_modelist[i], SDL_nummodes[i], sizeof *SDL_modelist[i], cmpmodes);
396		}
397	}
398#else
399	// WinCE and fullscreen mode:
400	// We use only vformat->BitsPerPixel that allow SDL to
401	// emulate other bpp (8, 32) and use triple buffer,
402	// because SDL surface conversion is much faster than the WinCE one.
403	// Although it should be tested on devices with graphics accelerator.
404
405	DIB_AddMode(this, vformat->BitsPerPixel,
406			GetDeviceCaps(GetDC(NULL), HORZRES),
407			GetDeviceCaps(GetDC(NULL), VERTRES));
408
409#endif /* !NO_CHANGEDISPLAYSETTINGS */
410
411	/* Grab an identity palette if we are in a palettized mode */
412	if ( vformat->BitsPerPixel <= 8 ) {
413	/*	RJR: March 28, 2000
414		moved palette creation to "DIB_CreatePalette" */
415		DIB_CreatePalette(this, vformat->BitsPerPixel);
416	}
417
418	/* Fill in some window manager capabilities */
419	this->info.wm_available = 1;
420
421#ifdef _WIN32_WCE
422	this->hidden->origRotation = -1;
423#endif
424
425	/* Allow environment override of screensaver disable. */
426	env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER");
427	if ( env ) {
428		allow_screensaver = SDL_atoi(env);
429	} else {
430#ifdef SDL_VIDEO_DISABLE_SCREENSAVER
431		allow_screensaver = 0;
432#else
433		allow_screensaver = 1;
434#endif
435	}
436
437	/* We're done! */
438	return(0);
439}
440
441/* We support any format at any dimension */
442SDL_Rect **DIB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
443{
444	if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
445		return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
446	} else {
447		return((SDL_Rect **)-1);
448	}
449}
450
451
452/*
453  Helper fn to work out which screen depth windows is currently using.
454  15 bit mode is considered 555 format, 16 bit is 565.
455  returns 0 for unknown mode.
456  (Derived from code in sept 1999 Windows Developer Journal
457  http://www.wdj.com/code/archive.html)
458*/
459static int DIB_SussScreenDepth()
460{
461#ifdef NO_GETDIBITS
462	int depth;
463	HDC hdc;
464
465	hdc = GetDC(SDL_Window);
466	depth = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
467	ReleaseDC(SDL_Window, hdc);
468	return(depth);
469#else
470    int depth;
471    int dib_size;
472    LPBITMAPINFOHEADER dib_hdr;
473    HDC hdc;
474    HBITMAP hbm;
475
476    /* Allocate enough space for a DIB header plus palette (for
477     * 8-bit modes) or bitfields (for 16- and 32-bit modes)
478     */
479    dib_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof (RGBQUAD);
480    dib_hdr = (LPBITMAPINFOHEADER) SDL_malloc(dib_size);
481    SDL_memset(dib_hdr, 0, dib_size);
482    dib_hdr->biSize = sizeof(BITMAPINFOHEADER);
483
484    /* Get a device-dependent bitmap that's compatible with the
485       screen.
486     */
487    hdc = GetDC(NULL);
488    hbm = CreateCompatibleBitmap( hdc, 1, 1 );
489
490    /* Convert the DDB to a DIB.  We need to call GetDIBits twice:
491     * the first call just fills in the BITMAPINFOHEADER; the
492     * second fills in the bitfields or palette.
493     */
494    GetDIBits(hdc, hbm, 0, 1, NULL, (LPBITMAPINFO) dib_hdr, DIB_RGB_COLORS);
495    GetDIBits(hdc, hbm, 0, 1, NULL, (LPBITMAPINFO) dib_hdr, DIB_RGB_COLORS);
496    DeleteObject(hbm);
497    ReleaseDC(NULL, hdc);
498
499    depth = 0;
500    switch( dib_hdr->biBitCount )
501    {
502    case 8:     depth = 8; break;
503    case 24:    depth = 24; break;
504    case 32:    depth = 32; break;
505    case 16:
506        if( dib_hdr->biCompression == BI_BITFIELDS ) {
507            /* check the red mask */
508            switch( ((DWORD*)((char*)dib_hdr + dib_hdr->biSize))[0] ) {
509                case 0xf800: depth = 16; break;   /* 565 */
510                case 0x7c00: depth = 15; break;   /* 555 */
511            }
512        }
513    }
514    SDL_free(dib_hdr);
515    return depth;
516#endif /* NO_GETDIBITS */
517}
518
519
520/* Various screen update functions available */
521static void DIB_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);
522
523static void DIB_ResizeWindow(_THIS, int width, int height, int prev_width, int prev_height, Uint32 flags)
524{
525	RECT bounds;
526	int x, y;
527
528#ifndef _WIN32_WCE
529	/* Resize the window */
530	if ( !SDL_windowid && !IsZoomed(SDL_Window) ) {
531#else
532	if ( !SDL_windowid ) {
533#endif
534		HWND top;
535		UINT swp_flags;
536		const char *window = NULL;
537		const char *center = NULL;
538
539		if ( width != prev_width || height != prev_height ) {
540			window = SDL_getenv("SDL_VIDEO_WINDOW_POS");
541			center = SDL_getenv("SDL_VIDEO_CENTERED");
542			if ( window ) {
543				if ( SDL_sscanf(window, "%d,%d", &x, &y) == 2 ) {
544					SDL_windowX = x;
545					SDL_windowY = y;
546				}
547				if ( SDL_strcmp(window, "center") == 0 ) {
548					center = window;
549				}
550			}
551		}
552		swp_flags = (SWP_NOCOPYBITS | SWP_SHOWWINDOW);
553
554		bounds.left = SDL_windowX;
555		bounds.top = SDL_windowY;
556		bounds.right = SDL_windowX+width;
557		bounds.bottom = SDL_windowY+height;
558#ifndef _WIN32_WCE
559		AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE), (GetMenu(SDL_Window) != NULL), 0);
560#else
561		// The bMenu parameter must be FALSE; menu bars are not supported
562		AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE), 0, 0);
563#endif
564		width = bounds.right-bounds.left;
565		height = bounds.bottom-bounds.top;
566		if ( (flags & SDL_FULLSCREEN) ) {
567			x = (GetSystemMetrics(SM_CXSCREEN)-width)/2;
568			y = (GetSystemMetrics(SM_CYSCREEN)-height)/2;
569		} else if ( center ) {
570			x = (GetSystemMetrics(SM_CXSCREEN)-width)/2;
571			y = (GetSystemMetrics(SM_CYSCREEN)-height)/2;
572		} else if ( SDL_windowX || SDL_windowY || window ) {
573			x = bounds.left;
574			y = bounds.top;
575		} else {
576			x = y = -1;
577			swp_flags |= SWP_NOMOVE;
578		}
579		if ( flags & SDL_FULLSCREEN ) {
580			top = HWND_TOPMOST;
581		} else {
582			top = HWND_NOTOPMOST;
583		}
584		SetWindowPos(SDL_Window, top, x, y, width, height, swp_flags);
585		if ( !(flags & SDL_FULLSCREEN) ) {
586			SDL_windowX = SDL_bounds.left;
587			SDL_windowY = SDL_bounds.top;
588		}
589		if ( GetParent(SDL_Window) == NULL ) {
590			SetForegroundWindow(SDL_Window);
591		}
592	}
593}
594
595SDL_Surface *DIB_SetVideoMode(_THIS, SDL_Surface *current,
596				int width, int height, int bpp, Uint32 flags)
597{
598	SDL_Surface *video;
599	int prev_w, prev_h;
600	Uint32 prev_flags;
601	DWORD style;
602	const DWORD directstyle =
603			(WS_POPUP);
604	const DWORD windowstyle =
605			(WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX);
606	const DWORD resizestyle =
607			(WS_THICKFRAME|WS_MAXIMIZEBOX);
608	int binfo_size;
609	BITMAPINFO *binfo;
610	HDC hdc;
611	Uint32 Rmask, Gmask, Bmask;
612
613	prev_w = current->w;
614	prev_h = current->h;
615	prev_flags = current->flags;
616
617	/*
618	 * Special case for OpenGL windows...since the app needs to call
619	 *  SDL_SetVideoMode() in response to resize events to continue to
620	 *  function, but WGL handles the GL context details behind the scenes,
621	 *  there's no sense in tearing the context down just to rebuild it
622	 *  to what it already was...tearing it down sacrifices your GL state
623	 *  and uploaded textures. So if we're requesting the same video mode
624	 *  attributes just resize the window and return immediately.
625	 */
626	if ( SDL_Window &&
627	     ((current->flags & ~SDL_ANYFORMAT) == (flags & ~SDL_ANYFORMAT)) &&
628	     (current->format->BitsPerPixel == bpp) &&
629	     (flags & SDL_OPENGL) &&
630	     !(flags & SDL_FULLSCREEN) ) {  /* probably not safe for fs */
631		current->w = width;
632		current->h = height;
633		SDL_resizing = 1;
634		DIB_ResizeWindow(this, width, height, prev_w, prev_h, flags);
635		SDL_resizing = 0;
636		return current;
637	}
638
639	/* Clean up any GL context that may be hanging around */
640	if ( current->flags & SDL_OPENGL ) {
641		WIN_GL_ShutDown(this);
642	}
643	SDL_resizing = 1;
644
645	/* Recalculate the bitmasks if necessary */
646	if ( bpp == current->format->BitsPerPixel ) {
647		video = current;
648	} else {
649		switch (bpp) {
650			case 15:
651			case 16:
652				if ( DIB_SussScreenDepth() == 15 ) {
653					/* 5-5-5 */
654					Rmask = 0x00007c00;
655					Gmask = 0x000003e0;
656					Bmask = 0x0000001f;
657				} else {
658					/* 5-6-5 */
659					Rmask = 0x0000f800;
660					Gmask = 0x000007e0;
661					Bmask = 0x0000001f;
662				}
663				break;
664			case 24:
665			case 32:
666				/* GDI defined as 8-8-8 */
667				Rmask = 0x00ff0000;
668				Gmask = 0x0000ff00;
669				Bmask = 0x000000ff;
670				break;
671			default:
672				Rmask = 0x00000000;
673				Gmask = 0x00000000;
674				Bmask = 0x00000000;
675				break;
676		}
677		video = SDL_CreateRGBSurface(SDL_SWSURFACE,
678					0, 0, bpp, Rmask, Gmask, Bmask, 0);
679		if ( video == NULL ) {
680			SDL_OutOfMemory();
681			return(NULL);
682		}
683	}
684
685	/* Fill in part of the video surface */
686	video->flags = 0;	/* Clear flags */
687	video->w = width;
688	video->h = height;
689	video->pitch = SDL_CalculatePitch(video);
690
691	/* Small fix for WinCE/Win32 - when activating window
692	   SDL_VideoSurface is equal to zero, so activating code
693	   is not called properly for fullscreen windows because
694	   macros WINDIB_FULLSCREEN uses SDL_VideoSurface
695	*/
696	SDL_VideoSurface = video;
697
698#if defined(_WIN32_WCE)
699	if ( flags & SDL_FULLSCREEN )
700		video->flags |= SDL_FULLSCREEN;
701#endif
702
703#ifndef NO_CHANGEDISPLAYSETTINGS
704	/* Set fullscreen mode if appropriate */
705	if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
706		DEVMODE settings;
707		BOOL changed;
708
709		SDL_memset(&settings, 0, sizeof(DEVMODE));
710		settings.dmSize = sizeof(DEVMODE);
711
712#ifdef _WIN32_WCE
713		// try to rotate screen to fit requested resolution
714		if( this->hidden->supportRotation )
715		{
716			DWORD rotation;
717
718			// ask current mode
719			settings.dmFields = DM_DISPLAYORIENTATION;
720			ChangeDisplaySettingsEx(NULL, &settings, NULL, CDS_TEST, NULL);
721			rotation = settings.dmDisplayOrientation;
722
723			if( (width > GetDeviceCaps(GetDC(NULL), HORZRES))
724				&& (height < GetDeviceCaps(GetDC(NULL), VERTRES)))
725			{
726				switch( rotation )
727				{
728				case DMDO_0:
729					settings.dmDisplayOrientation = DMDO_90;
730					break;
731				case DMDO_270:
732					settings.dmDisplayOrientation = DMDO_180;
733					break;
734				}
735				if( settings.dmDisplayOrientation != rotation )
736				{
737					// go to landscape
738					this->hidden->origRotation = rotation;
739					ChangeDisplaySettingsEx(NULL,&settings,NULL,CDS_RESET,NULL);
740				}
741			}
742			if( (width < GetDeviceCaps(GetDC(NULL), HORZRES))
743				&& (height > GetDeviceCaps(GetDC(NULL), VERTRES)))
744			{
745				switch( rotation )
746				{
747				case DMDO_90:
748					settings.dmDisplayOrientation = DMDO_0;
749					break;
750				case DMDO_180:
751					settings.dmDisplayOrientation = DMDO_270;
752					break;
753				}
754				if( settings.dmDisplayOrientation != rotation )
755				{
756					// go to portrait
757					this->hidden->origRotation = rotation;
758					ChangeDisplaySettingsEx(NULL,&settings,NULL,CDS_RESET,NULL);
759				}
760			}
761
762		}
763#endif
764
765#ifndef _WIN32_WCE
766		settings.dmBitsPerPel = video->format->BitsPerPixel;
767		settings.dmPelsWidth = width;
768		settings.dmPelsHeight = height;
769		settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
770		if ( width <= (int)SDL_desktop_mode.dmPelsWidth &&
771		     height <= (int)SDL_desktop_mode.dmPelsHeight ) {
772			settings.dmDisplayFrequency = SDL_desktop_mode.dmDisplayFrequency;
773			settings.dmFields |= DM_DISPLAYFREQUENCY;
774		}
775		changed = (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL);
776		if ( ! changed && (settings.dmFields & DM_DISPLAYFREQUENCY) ) {
777			settings.dmFields &= ~DM_DISPLAYFREQUENCY;
778			changed = (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL);
779		}
780#else
781		changed = 1;
782#endif
783		if ( changed ) {
784			video->flags |= SDL_FULLSCREEN;
785			SDL_fullscreen_mode = settings;
786		}
787
788	}
789#endif /* !NO_CHANGEDISPLAYSETTINGS */
790
791	/* Reset the palette and create a new one if necessary */
792	if ( grab_palette ) {
793		DIB_ReleaseStaticColors(SDL_Window);
794		grab_palette = FALSE;
795	}
796	if ( screen_pal != NULL ) {
797	/*	RJR: March 28, 2000
798		delete identity palette if switching from a palettized mode */
799		DeleteObject(screen_pal);
800		screen_pal = NULL;
801	}
802	if ( screen_logpal != NULL ) {
803		SDL_free(screen_logpal);
804		screen_logpal = NULL;
805	}
806
807	if ( bpp <= 8 )
808	{
809	/*	RJR: March 28, 2000
810		create identity palette switching to a palettized mode */
811		DIB_CreatePalette(this, bpp);
812	}
813
814	style = GetWindowLong(SDL_Window, GWL_STYLE);
815	style &= ~(resizestyle|WS_MAXIMIZE);
816	if ( (video->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
817		style &= ~windowstyle;
818		style |= directstyle;
819	} else {
820#ifndef NO_CHANGEDISPLAYSETTINGS
821		if ( (prev_flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
822			ChangeDisplaySettings(NULL, 0);
823		}
824#endif
825		if ( flags & SDL_NOFRAME ) {
826			style &= ~windowstyle;
827			style |= directstyle;
828			video->flags |= SDL_NOFRAME;
829		} else {
830			style &= ~directstyle;
831			style |= windowstyle;
832			if ( flags & SDL_RESIZABLE ) {
833				style |= resizestyle;
834				video->flags |= SDL_RESIZABLE;
835			}
836		}
837#if WS_MAXIMIZE && !defined(_WIN32_WCE)
838		if (IsZoomed(SDL_Window)) style |= WS_MAXIMIZE;
839#endif
840	}
841
842	/* DJM: Don't piss of anyone who has setup his own window */
843	if ( !SDL_windowid )
844		SetWindowLong(SDL_Window, GWL_STYLE, style);
845
846	/* Delete the old bitmap if necessary */
847	if ( screen_bmp != NULL ) {
848		DeleteObject(screen_bmp);
849	}
850	if ( ! (flags & SDL_OPENGL) ) {
851		BOOL is16bitmode = (video->format->BytesPerPixel == 2);
852
853		/* Suss out the bitmap info header */
854		binfo_size = sizeof(*binfo);
855		if( is16bitmode ) {
856			/* 16bit modes, palette area used for rgb bitmasks */
857			binfo_size += 3*sizeof(DWORD);
858		} else if ( video->format->palette ) {
859			binfo_size += video->format->palette->ncolors *
860							sizeof(RGBQUAD);
861		}
862		binfo = (BITMAPINFO *)SDL_malloc(binfo_size);
863		if ( ! binfo ) {
864			if ( video != current ) {
865				SDL_FreeSurface(video);
866			}
867			SDL_OutOfMemory();
868			return(NULL);
869		}
870
871		binfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
872		binfo->bmiHeader.biWidth = video->w;
873		binfo->bmiHeader.biHeight = -video->h;	/* -ve for topdown bitmap */
874		binfo->bmiHeader.biPlanes = 1;
875		binfo->bmiHeader.biSizeImage = video->h * video->pitch;
876		binfo->bmiHeader.biXPelsPerMeter = 0;
877		binfo->bmiHeader.biYPelsPerMeter = 0;
878		binfo->bmiHeader.biClrUsed = 0;
879		binfo->bmiHeader.biClrImportant = 0;
880		binfo->bmiHeader.biBitCount = video->format->BitsPerPixel;
881
882		if ( is16bitmode ) {
883			/* BI_BITFIELDS tells CreateDIBSection about the rgb masks in the palette */
884			binfo->bmiHeader.biCompression = BI_BITFIELDS;
885			((Uint32*)binfo->bmiColors)[0] = video->format->Rmask;
886			((Uint32*)binfo->bmiColors)[1] = video->format->Gmask;
887			((Uint32*)binfo->bmiColors)[2] = video->format->Bmask;
888		} else {
889			binfo->bmiHeader.biCompression = BI_RGB;	/* BI_BITFIELDS for 565 vs 555 */
890			if ( video->format->palette ) {
891				SDL_memset(binfo->bmiColors, 0,
892					video->format->palette->ncolors*sizeof(RGBQUAD));
893			}
894		}
895
896		/* Create the offscreen bitmap buffer */
897		hdc = GetDC(SDL_Window);
898		screen_bmp = CreateDIBSection(hdc, binfo, DIB_RGB_COLORS,
899					(void **)(&video->pixels), NULL, 0);
900		ReleaseDC(SDL_Window, hdc);
901		SDL_free(binfo);
902		if ( screen_bmp == NULL ) {
903			if ( video != current ) {
904				SDL_FreeSurface(video);
905			}
906			SDL_SetError("Couldn't create DIB section");
907			return(NULL);
908		}
909		this->UpdateRects = DIB_NormalUpdate;
910
911		/* Set video surface flags */
912		if ( screen_pal && (flags & (SDL_FULLSCREEN|SDL_HWPALETTE)) ) {
913			grab_palette = TRUE;
914		}
915		if ( screen_pal ) {
916			/* BitBlt() maps colors for us */
917			video->flags |= SDL_HWPALETTE;
918		}
919	}
920	DIB_ResizeWindow(this, width, height, prev_w, prev_h, flags);
921	SDL_resizing = 0;
922
923	/* Set up for OpenGL */
924	if ( flags & SDL_OPENGL ) {
925		if ( WIN_GL_SetupWindow(this) < 0 ) {
926			return(NULL);
927		}
928		video->flags |= SDL_OPENGL;
929	}
930
931	/* JC 14 Mar 2006
932		Flush the message loop or this can cause big problems later
933		Especially if the user decides to use dialog boxes or assert()!
934	*/
935	WIN_FlushMessageQueue();
936
937	/* We're live! */
938	return(video);
939}
940
941/* We don't actually allow hardware surfaces in the DIB driver */
942static int DIB_AllocHWSurface(_THIS, SDL_Surface *surface)
943{
944	return(-1);
945}
946static void DIB_FreeHWSurface(_THIS, SDL_Surface *surface)
947{
948	return;
949}
950static int DIB_LockHWSurface(_THIS, SDL_Surface *surface)
951{
952	return(0);
953}
954static void DIB_UnlockHWSurface(_THIS, SDL_Surface *surface)
955{
956	return;
957}
958
959static void DIB_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
960{
961	HDC hdc, mdc;
962	int i;
963
964	hdc = GetDC(SDL_Window);
965	if ( screen_pal ) {
966		SelectPalette(hdc, screen_pal, FALSE);
967	}
968	mdc = CreateCompatibleDC(hdc);
969	SelectObject(mdc, screen_bmp);
970	for ( i=0; i<numrects; ++i ) {
971		BitBlt(hdc, rects[i].x, rects[i].y, rects[i].w, rects[i].h,
972					mdc, rects[i].x, rects[i].y, SRCCOPY);
973	}
974	DeleteDC(mdc);
975	ReleaseDC(SDL_Window, hdc);
976}
977
978static int FindPaletteIndex(LOGPALETTE *pal, BYTE r, BYTE g, BYTE b)
979{
980	PALETTEENTRY *entry;
981	int i;
982	int nentries = pal->palNumEntries;
983
984	for ( i = 0; i < nentries; ++i ) {
985		entry = &pal->palPalEntry[i];
986		if ( entry->peRed == r && entry->peGreen == g && entry->peBlue == b ) {
987			return i;
988		}
989	}
990	return -1;
991}
992
993static BOOL CheckPaletteEntry(LOGPALETTE *pal, int index, BYTE r, BYTE g, BYTE b)
994{
995	PALETTEENTRY *entry;
996	BOOL moved = 0;
997
998	entry = &pal->palPalEntry[index];
999	if ( entry->peRed != r || entry->peGreen != g || entry->peBlue != b ) {
1000		int found = FindPaletteIndex(pal, r, g, b);
1001		if ( found >= 0 ) {
1002			pal->palPalEntry[found] = *entry;
1003		}
1004		entry->peRed = r;
1005		entry->peGreen = g;
1006		entry->peBlue = b;
1007		moved = 1;
1008	}
1009	entry->peFlags = 0;
1010
1011	return moved;
1012}
1013
1014int DIB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
1015{
1016#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1017	HDC hdc, mdc;
1018	RGBQUAD *pal;
1019#else
1020	HDC hdc;
1021#endif
1022	int i;
1023	int moved_entries = 0;
1024
1025	/* Update the display palette */
1026	hdc = GetDC(SDL_Window);
1027	if ( screen_pal ) {
1028		PALETTEENTRY *entry;
1029
1030		for ( i=0; i<ncolors; ++i ) {
1031			entry = &screen_logpal->palPalEntry[firstcolor+i];
1032			entry->peRed   = colors[i].r;
1033			entry->peGreen = colors[i].g;
1034			entry->peBlue  = colors[i].b;
1035			entry->peFlags = PC_NOCOLLAPSE;
1036		}
1037#if defined(SYSPAL_NOSTATIC) && !defined(_WIN32_WCE)
1038		/* Check to make sure black and white are in position */
1039		if ( GetSystemPaletteUse(hdc) != SYSPAL_NOSTATIC256 ) {
1040			moved_entries += CheckPaletteEntry(screen_logpal, 0, 0x00, 0x00, 0x00);
1041			moved_entries += CheckPaletteEntry(screen_logpal, screen_logpal->palNumEntries-1, 0xff, 0xff, 0xff);
1042		}
1043		/* FIXME:
1044		   If we don't have full access to the palette, what we
1045		   really want to do is find the 236 most diverse colors
1046		   in the desired palette, set those entries (10-245) and
1047		   then map everything into the new system palette.
1048		 */
1049#endif
1050
1051#ifndef _WIN32_WCE
1052		/* Copy the entries into the system palette */
1053		UnrealizeObject(screen_pal);
1054#endif
1055		SetPaletteEntries(screen_pal, 0, screen_logpal->palNumEntries, screen_logpal->palPalEntry);
1056		SelectPalette(hdc, screen_pal, FALSE);
1057		RealizePalette(hdc);
1058	}
1059
1060#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1061	/* Copy palette colors into DIB palette */
1062	pal = SDL_stack_alloc(RGBQUAD, ncolors);
1063	for ( i=0; i<ncolors; ++i ) {
1064		pal[i].rgbRed = colors[i].r;
1065		pal[i].rgbGreen = colors[i].g;
1066		pal[i].rgbBlue = colors[i].b;
1067		pal[i].rgbReserved = 0;
1068	}
1069
1070	/* Set the DIB palette and update the display */
1071	mdc = CreateCompatibleDC(hdc);
1072	SelectObject(mdc, screen_bmp);
1073	SetDIBColorTable(mdc, firstcolor, ncolors, pal);
1074	if ( moved_entries || !grab_palette ) {
1075		BitBlt(hdc, 0, 0, this->screen->w, this->screen->h,
1076		       mdc, 0, 0, SRCCOPY);
1077	}
1078	DeleteDC(mdc);
1079	SDL_stack_free(pal);
1080#endif
1081	ReleaseDC(SDL_Window, hdc);
1082	return(1);
1083}
1084
1085
1086static void DIB_CheckGamma(_THIS)
1087{
1088#ifndef NO_GAMMA_SUPPORT
1089	HDC hdc;
1090	WORD ramp[3*256];
1091
1092	/* If we fail to get gamma, disable gamma control */
1093	hdc = GetDC(SDL_Window);
1094	if ( ! GetDeviceGammaRamp(hdc, ramp) ) {
1095		this->GetGammaRamp = NULL;
1096		this->SetGammaRamp = NULL;
1097	}
1098	ReleaseDC(SDL_Window, hdc);
1099#endif /* !NO_GAMMA_SUPPORT */
1100}
1101void DIB_SwapGamma(_THIS)
1102{
1103#ifndef NO_GAMMA_SUPPORT
1104	HDC hdc;
1105
1106	if ( gamma_saved ) {
1107		hdc = GetDC(SDL_Window);
1108		if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
1109			/* About to leave active state, restore gamma */
1110			SetDeviceGammaRamp(hdc, gamma_saved);
1111		} else {
1112			/* About to enter active state, set game gamma */
1113			GetDeviceGammaRamp(hdc, gamma_saved);
1114			SetDeviceGammaRamp(hdc, this->gamma);
1115		}
1116		ReleaseDC(SDL_Window, hdc);
1117	}
1118#endif /* !NO_GAMMA_SUPPORT */
1119}
1120void DIB_QuitGamma(_THIS)
1121{
1122#ifndef NO_GAMMA_SUPPORT
1123	if ( gamma_saved ) {
1124		/* Restore the original gamma if necessary */
1125		if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
1126			HDC hdc;
1127
1128			hdc = GetDC(SDL_Window);
1129			SetDeviceGammaRamp(hdc, gamma_saved);
1130			ReleaseDC(SDL_Window, hdc);
1131		}
1132
1133		/* Free the saved gamma memory */
1134		SDL_free(gamma_saved);
1135		gamma_saved = 0;
1136	}
1137#endif /* !NO_GAMMA_SUPPORT */
1138}
1139
1140int DIB_SetGammaRamp(_THIS, Uint16 *ramp)
1141{
1142#ifdef NO_GAMMA_SUPPORT
1143	SDL_SetError("SDL compiled without gamma ramp support");
1144	return -1;
1145#else
1146	HDC hdc;
1147	BOOL succeeded;
1148
1149	/* Set the ramp for the display */
1150	if ( ! gamma_saved ) {
1151		gamma_saved = (WORD *)SDL_malloc(3*256*sizeof(*gamma_saved));
1152		if ( ! gamma_saved ) {
1153			SDL_OutOfMemory();
1154			return -1;
1155		}
1156		hdc = GetDC(SDL_Window);
1157		GetDeviceGammaRamp(hdc, gamma_saved);
1158		ReleaseDC(SDL_Window, hdc);
1159	}
1160	if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
1161		hdc = GetDC(SDL_Window);
1162		succeeded = SetDeviceGammaRamp(hdc, ramp);
1163		ReleaseDC(SDL_Window, hdc);
1164	} else {
1165		succeeded = TRUE;
1166	}
1167	return succeeded ? 0 : -1;
1168#endif /* !NO_GAMMA_SUPPORT */
1169}
1170
1171int DIB_GetGammaRamp(_THIS, Uint16 *ramp)
1172{
1173#ifdef NO_GAMMA_SUPPORT
1174	SDL_SetError("SDL compiled without gamma ramp support");
1175	return -1;
1176#else
1177	HDC hdc;
1178	BOOL succeeded;
1179
1180	/* Get the ramp from the display */
1181	hdc = GetDC(SDL_Window);
1182	succeeded = GetDeviceGammaRamp(hdc, ramp);
1183	ReleaseDC(SDL_Window, hdc);
1184	return succeeded ? 0 : -1;
1185#endif /* !NO_GAMMA_SUPPORT */
1186}
1187
1188void DIB_VideoQuit(_THIS)
1189{
1190	int i, j;
1191
1192	/* Destroy the window and everything associated with it */
1193	if ( SDL_Window ) {
1194		/* Delete the screen bitmap (also frees screen->pixels) */
1195		if ( this->screen ) {
1196			if ( grab_palette ) {
1197				DIB_ReleaseStaticColors(SDL_Window);
1198			}
1199#ifndef NO_CHANGEDISPLAYSETTINGS
1200			if ( this->screen->flags & SDL_FULLSCREEN ) {
1201				ChangeDisplaySettings(NULL, 0);
1202				ShowWindow(SDL_Window, SW_HIDE);
1203			}
1204#endif
1205			if ( this->screen->flags & SDL_OPENGL ) {
1206				WIN_GL_ShutDown(this);
1207			}
1208			this->screen->pixels = NULL;
1209		}
1210		if ( screen_pal != NULL ) {
1211			DeleteObject(screen_pal);
1212			screen_pal = NULL;
1213		}
1214		if ( screen_logpal != NULL ) {
1215			SDL_free(screen_logpal);
1216			screen_logpal = NULL;
1217		}
1218		if ( screen_bmp ) {
1219			DeleteObject(screen_bmp);
1220			screen_bmp = NULL;
1221		}
1222		if ( screen_icn ) {
1223			DestroyIcon(screen_icn);
1224			screen_icn = NULL;
1225		}
1226		DIB_QuitGamma(this);
1227		DIB_DestroyWindow(this);
1228
1229		SDL_Window = NULL;
1230
1231#if defined(_WIN32_WCE)
1232
1233// Unload wince aygshell library to prevent leak
1234		if( aygshell )
1235		{
1236			FreeLibrary(aygshell);
1237			aygshell = NULL;
1238		}
1239#endif
1240	}
1241
1242	for ( i=0; i < SDL_arraysize(SDL_modelist); ++i ) {
1243		if ( !SDL_modelist[i] ) {
1244			continue;
1245		}
1246		for ( j=0; SDL_modelist[i][j]; ++j ) {
1247			SDL_free(SDL_modelist[i][j]);
1248		}
1249		SDL_free(SDL_modelist[i]);
1250		SDL_modelist[i] = NULL;
1251		SDL_nummodes[i] = 0;
1252	}
1253}
1254
1255/* Exported for the windows message loop only */
1256static void DIB_GrabStaticColors(HWND window)
1257{
1258#if defined(SYSPAL_NOSTATIC) && !defined(_WIN32_WCE)
1259	HDC hdc;
1260
1261	hdc = GetDC(window);
1262	SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC256);
1263	if ( GetSystemPaletteUse(hdc) != SYSPAL_NOSTATIC256 ) {
1264		SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
1265	}
1266	ReleaseDC(window, hdc);
1267#endif
1268}
1269static void DIB_ReleaseStaticColors(HWND window)
1270{
1271#if defined(SYSPAL_NOSTATIC) && !defined(_WIN32_WCE)
1272	HDC hdc;
1273
1274	hdc = GetDC(window);
1275	SetSystemPaletteUse(hdc, SYSPAL_STATIC);
1276	ReleaseDC(window, hdc);
1277#endif
1278}
1279static void DIB_Activate(_THIS, BOOL active, BOOL minimized)
1280{
1281	if ( grab_palette ) {
1282		if ( !active ) {
1283			DIB_ReleaseStaticColors(SDL_Window);
1284			DIB_RealizePalette(this);
1285		} else if ( !minimized ) {
1286			DIB_GrabStaticColors(SDL_Window);
1287			DIB_RealizePalette(this);
1288		}
1289	}
1290}
1291static void DIB_RealizePalette(_THIS)
1292{
1293	if ( screen_pal != NULL ) {
1294		HDC hdc;
1295
1296		hdc = GetDC(SDL_Window);
1297#ifndef _WIN32_WCE
1298		UnrealizeObject(screen_pal);
1299#endif
1300		SelectPalette(hdc, screen_pal, FALSE);
1301		if ( RealizePalette(hdc) ) {
1302			InvalidateRect(SDL_Window, NULL, FALSE);
1303		}
1304		ReleaseDC(SDL_Window, hdc);
1305	}
1306}
1307static void DIB_PaletteChanged(_THIS, HWND window)
1308{
1309	if ( window != SDL_Window ) {
1310		DIB_RealizePalette(this);
1311	}
1312}
1313
1314/* Exported for the windows message loop only */
1315static void DIB_WinPAINT(_THIS, HDC hdc)
1316{
1317	HDC mdc;
1318
1319	if ( screen_pal ) {
1320		SelectPalette(hdc, screen_pal, FALSE);
1321	}
1322	mdc = CreateCompatibleDC(hdc);
1323	SelectObject(mdc, screen_bmp);
1324	BitBlt(hdc, 0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h,
1325							mdc, 0, 0, SRCCOPY);
1326	DeleteDC(mdc);
1327}
1328
1329static void DIB_GetWinPos(_THIS, int* px, int *py)
1330{
1331	RECT  rect;
1332	GetWindowRect(SDL_Window, &rect);
1333	*px = rect.left;
1334	*py = rect.top;
1335}
1336
1337static void DIB_SetWinPos(_THIS, int  x, int  y)
1338{
1339    SetWindowPos(SDL_Window, HWND_TOPMOST,
1340                 x, y, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
1341}
1342
1343typedef struct {
1344    int   result;
1345    int   first;
1346    RECT  wrect;
1347    RECT  primary;
1348} VisibilityData;
1349
1350
1351BOOL CALLBACK visibility_cb(HMONITOR  hMonitor,
1352                            HDC       hdcMonitor,
1353                            LPRECT    mrect,
1354                            LPARAM    dwData)
1355{
1356    VisibilityData*  data = (VisibilityData*)dwData;
1357
1358    if ( data->first ) {
1359        data->first   = 0;
1360        data->primary = mrect[0];
1361    }
1362
1363    if ( data->wrect.left   >= mrect->left   &&
1364         data->wrect.right  <= mrect->right  &&
1365         data->wrect.top    >= mrect->top    &&
1366         data->wrect.bottom <= mrect->bottom )
1367    {
1368        data->result = 1;
1369        return FALSE;
1370    }
1371    return TRUE;
1372}
1373
1374static int  DIB_IsWinVisible(_THIS, int  recenter)
1375{
1376    VisibilityData  data;
1377    data.result = 0;
1378    data.first  = 1;
1379
1380    GetWindowRect(SDL_Window, &data.wrect);
1381
1382    EnumDisplayMonitors(NULL, NULL, visibility_cb, (LPARAM)&data);
1383
1384    if ( !data.result && recenter ) {
1385        int  new_x = 10;
1386        int  new_y = 10;
1387
1388        if ( !data.first ) {
1389            int  primary_w = data.primary.right  - data.primary.left;
1390            int  primary_h = data.primary.bottom - data.primary.top;
1391
1392            new_x = data.primary.left + (primary_w - this->screen->w)/2;
1393            new_y = data.primary.top  + (primary_h - this->screen->h)/2;
1394        }
1395        DIB_SetWinPos(this, new_x, new_y);
1396    }
1397    return  data.result;
1398}
1399
1400static int  DIB_GetMonitorDPI(_THIS, int* xDpi, int *yDpi)
1401{
1402    HDC  displayDC = CreateDC( "DISPLAY", NULL, NULL, NULL );
1403    int  xdpi, ydpi;
1404
1405    if (displayDC == NULL) {
1406        return -1;
1407    }
1408    xdpi = GetDeviceCaps( displayDC, LOGPIXELSX );
1409    ydpi = GetDeviceCaps( displayDC, LOGPIXELSY );
1410
1411    DeleteDC(displayDC);
1412
1413    /* sanity checks */
1414    if (xdpi < 20 || xdpi > 400 || ydpi < 20 || ydpi > 400) {
1415        return -1;
1416    }
1417
1418    *xDpi = xdpi;
1419    *yDpi = ydpi;
1420    return 0;
1421}
1422
1423
1424typedef struct {
1425    int   first;
1426    RECT  wrect;
1427	long  bestArea;
1428	RECT  bestRect;
1429	RECT  primary;
1430} ProximityData;
1431
1432BOOL CALLBACK proximity_cb(HMONITOR  hMonitor,
1433                           HDC       hdcMonitor,
1434                           LPRECT    mrect,
1435                           LPARAM    dwData)
1436{
1437    ProximityData*  data = (ProximityData*)dwData;
1438    int   x1, y1, x2, y2, area;
1439
1440	x1 = mrect->left;
1441	x2 = mrect->right;
1442	y1 = mrect->top;
1443	y2 = mrect->bottom;
1444
1445	if (data->first) {
1446		data->primary = mrect[0];
1447	}
1448
1449	if (x1 < data->wrect.left)
1450		x1 = data->wrect.left;
1451    if (x2 > data->wrect.right)
1452		x2 = data->wrect.right;
1453	if (y1 < data->wrect.top)
1454		y1 = data->wrect.top;
1455	if (y2 > data->wrect.bottom)
1456		y2 = data->wrect.bottom;
1457
1458	if (x1 >= x2 || y1 >= y2)
1459		return TRUE;
1460
1461	area = (x2-x1)*(y2-y1);
1462	if (data->first || area > data->bestArea) {
1463		data->first    = 0;
1464		data->bestRect = mrect[0];
1465		data->bestArea = area;
1466	}
1467    return TRUE;
1468}
1469
1470static int  DIB_GetMonitorRect(_THIS, SDL_Rect*  rect)
1471{
1472    ProximityData  data;
1473	RECT*          sr;
1474
1475    data.first  = 1;
1476    GetWindowRect(SDL_Window, &data.wrect);
1477
1478    EnumDisplayMonitors(NULL, NULL, proximity_cb, (LPARAM)&data);
1479
1480	if (data.first)
1481		return -1;
1482
1483	sr = &data.bestRect;
1484
1485	rect->x = sr->left;
1486	rect->y = sr->top;
1487	rect->w = sr->right - sr->left;
1488	rect->h = sr->bottom - sr->top;
1489
1490	return 0;
1491}
1492
1493/* Stub in case DirectX isn't available */
1494#if !SDL_AUDIO_DRIVER_DSOUND
1495void DX5_SoundFocus(HWND hwnd)
1496{
1497	return;
1498}
1499#endif
1500