1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2006 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
25#include <windows.h>
26
27#include "SDL_version.h"
28#include "SDL_video.h"
29#include "SDL_loadso.h"
30#include "SDL_syswm.h"
31#include "../SDL_pixels_c.h"
32#include "../SDL_cursor_c.h"
33#include "SDL_syswm_c.h"
34#include "SDL_wingl_c.h"
35
36
37#ifdef _WIN32_WCE
38#define DISABLE_ICON_SUPPORT
39#endif
40
41/* The screen icon -- needs to be freed on SDL_VideoQuit() */
42HICON   screen_icn = NULL;
43
44/* Win32 icon mask semantics are different from those of SDL:
45     SDL applies the mask to the icon and copies result to desktop.
46     Win32 applies the mask to the desktop and XORs the icon on.
47   This means that the SDL mask needs to be applied to the icon and
48   then inverted and passed to Win32.
49*/
50void WIN_SetWMIcon(_THIS, SDL_Surface *icon, Uint8 *mask)
51{
52#ifdef DISABLE_ICON_SUPPORT
53	return;
54#else
55	SDL_Palette *pal_256;
56	SDL_Surface *icon_256;
57	Uint8 *pdata, *pwin32;
58	Uint8 *mdata, *mwin32, m = 0;
59	int icon_len;
60	int icon_plen;
61	int icon_mlen;
62	int icon_pitch;
63	int mask_pitch;
64	SDL_Rect bounds;
65	int i, skip;
66	int row, col;
67	struct /* quasi-BMP format */ Win32Icon {
68		Uint32 biSize;
69		Sint32 biWidth;
70		Sint32 biHeight;
71		Uint16 biPlanes;
72		Uint16 biBitCount;
73		Uint32 biCompression;
74		Uint32 biSizeImage;
75		Sint32 biXPelsPerMeter;
76		Sint32 biYPelsPerMeter;
77		Uint32 biClrUsed;
78		Uint32 biClrImportant;
79		struct /* RGBQUAD -- note it's BGR ordered */ {
80			Uint8 rgbBlue;
81			Uint8 rgbGreen;
82			Uint8 rgbRed;
83			Uint8 rgbReserved;
84		} biColors[256];
85		/* Pixels:
86		Uint8 pixels[]
87		*/
88		/* Mask:
89		Uint8 mask[]
90		*/
91	} *icon_win32;
92
93	/* Allocate the win32 bmp icon and set everything to zero */
94	icon_pitch = ((icon->w+3)&~3);
95	mask_pitch = ((icon->w+7)/8);
96	icon_plen = icon->h*icon_pitch;
97	icon_mlen = icon->h*mask_pitch;
98	icon_len = sizeof(*icon_win32)+icon_plen+icon_mlen;
99	icon_win32 = (struct Win32Icon *)SDL_stack_alloc(Uint8, icon_len);
100	if ( icon_win32 == NULL ) {
101		return;
102	}
103	SDL_memset(icon_win32, 0, icon_len);
104
105	/* Set the basic BMP parameters */
106	icon_win32->biSize = sizeof(*icon_win32)-sizeof(icon_win32->biColors);
107	icon_win32->biWidth = icon->w;
108	icon_win32->biHeight = icon->h*2;
109	icon_win32->biPlanes = 1;
110	icon_win32->biBitCount = 8;
111	icon_win32->biSizeImage = icon_plen+icon_mlen;
112
113	/* Allocate a standard 256 color icon surface */
114	icon_256 = SDL_CreateRGBSurface(SDL_SWSURFACE, icon->w, icon->h,
115					 icon_win32->biBitCount, 0, 0, 0, 0);
116	if ( icon_256 == NULL ) {
117		SDL_stack_free(icon_win32);
118		return;
119	}
120	pal_256 = icon_256->format->palette;
121	if (icon->format->palette &&
122		(icon->format->BitsPerPixel == icon_256->format->BitsPerPixel)){
123		Uint8 black;
124		SDL_memcpy(pal_256->colors, icon->format->palette->colors,
125					pal_256->ncolors*sizeof(SDL_Color));
126		/* Make sure that 0 is black! */
127		black = SDL_FindColor(pal_256, 0x00, 0x00, 0x00);
128		pal_256->colors[black] = pal_256->colors[0];
129		pal_256->colors[0].r = 0x00;
130		pal_256->colors[0].g = 0x00;
131		pal_256->colors[0].b = 0x00;
132	} else {
133		SDL_DitherColors(pal_256->colors,
134					icon_256->format->BitsPerPixel);
135	}
136
137	/* Now copy color data to the icon BMP */
138	for ( i=0; i<(1<<icon_win32->biBitCount); ++i ) {
139		icon_win32->biColors[i].rgbRed = pal_256->colors[i].r;
140		icon_win32->biColors[i].rgbGreen = pal_256->colors[i].g;
141		icon_win32->biColors[i].rgbBlue = pal_256->colors[i].b;
142	}
143
144	/* Convert icon to a standard surface format.  This may not always
145	   be necessary, as Windows supports a variety of BMP formats, but
146	   it greatly simplifies our code.
147	*/
148    bounds.x = 0;
149    bounds.y = 0;
150    bounds.w = icon->w;
151    bounds.h = icon->h;
152    if ( SDL_LowerBlit(icon, &bounds, icon_256, &bounds) < 0 ) {
153	    SDL_stack_free(icon_win32);
154		SDL_FreeSurface(icon_256);
155        return;
156	}
157
158	/* Copy pixels upside-down to icon BMP, masked with the icon mask */
159	if ( SDL_MUSTLOCK(icon_256) || (icon_256->pitch != icon_pitch) ) {
160		SDL_stack_free(icon_win32);
161		SDL_FreeSurface(icon_256);
162		SDL_SetError("Warning: Unexpected icon_256 characteristics");
163		return;
164	}
165	pdata = (Uint8 *)icon_256->pixels;
166	mdata = mask;
167	pwin32 = (Uint8 *)icon_win32+sizeof(*icon_win32)+icon_plen-icon_pitch;
168	skip = icon_pitch - icon->w;
169	for ( row=0; row<icon->h; ++row ) {
170		for ( col=0; col<icon->w; ++col ) {
171			if ( (col%8) == 0 ) {
172				m = *mdata++;
173			}
174			if ( (m&0x80) != 0x00 ) {
175				*pwin32 = *pdata;
176			}
177			m <<= 1;
178			++pdata;
179			++pwin32;
180		}
181		pdata  += skip;
182		pwin32 += skip;
183		pwin32 -= 2*icon_pitch;
184	}
185	SDL_FreeSurface(icon_256);
186
187	/* Copy mask inverted and upside-down to icon BMP */
188	mdata = mask;
189	mwin32 = (Uint8 *)icon_win32
190			+sizeof(*icon_win32)+icon_plen+icon_mlen-mask_pitch;
191	for ( row=0; row<icon->h; ++row ) {
192		for ( col=0; col<mask_pitch; ++col ) {
193			*mwin32++ = ~*mdata++;
194		}
195		mwin32 -= 2*mask_pitch;
196	}
197
198	/* Finally, create the icon handle and set the window icon */
199	screen_icn = CreateIconFromResourceEx((Uint8 *)icon_win32, icon_len,
200			TRUE, 0x00030000, icon->w, icon->h, LR_DEFAULTCOLOR);
201	if ( screen_icn == NULL ) {
202		SDL_SetError("Couldn't create Win32 icon handle");
203	} else {
204		SetClassLongPtr(SDL_Window, GCLP_HICON, (LONG_PTR)screen_icn);
205	}
206	SDL_stack_free(icon_win32);
207#endif /* DISABLE_ICON_SUPPORT */
208}
209
210typedef BOOL (WINAPI *PtrSetWindowTextW)(HWND hWnd, LPCWSTR lpString);
211
212void WIN_SetWMCaption(_THIS, const char *title, const char *icon)
213{
214#ifdef _WIN32_WCE
215	/* WinCE uses the UNICODE version */
216	LPWSTR lpszW = SDL_iconv_utf8_ucs2((char *)title);
217	SetWindowText(SDL_Window, lpszW);
218	SDL_free(lpszW);
219#else
220	/*
221	 * Try loading SetWindowTextW from kernel32.dll first, and if it exists,
222	 *  pass the UCS-2 string to it. If it doesn't, use
223	 *  WideCharToMultiByte(CP_ACP) and hope that the codepage can support the
224	 *  string data in question. This lets us keep binary compatibility with
225	 *  Win95/98/ME but still use saner Unicode on NT-based Windows.
226	 */
227	static int tried_loading = 0;
228	static PtrSetWindowTextW swtw = NULL;
229	Uint16 *lpsz = SDL_iconv_utf8_ucs2(title);
230	if (!tried_loading) {
231		HMODULE dll = LoadLibrary("user32.dll");
232		if (dll != NULL) {
233			swtw = (PtrSetWindowTextW) GetProcAddress(dll, "SetWindowTextW");
234			if (swtw == NULL) {
235				FreeLibrary(dll);
236			}
237		}
238		tried_loading = 1;
239	}
240
241	if (swtw != NULL) {
242		swtw(SDL_Window, lpsz);
243	} else {
244		size_t len = WideCharToMultiByte(CP_ACP, 0, lpsz, -1, NULL, 0, NULL, NULL);
245		char *cvt = SDL_malloc(len + 1);
246		WideCharToMultiByte(CP_ACP, 0, lpsz, -1, cvt, len, NULL, NULL);
247		SetWindowText(SDL_Window, cvt);
248		SDL_free(cvt);
249	}
250	SDL_free(lpsz);
251#endif
252}
253
254int WIN_IconifyWindow(_THIS)
255{
256	ShowWindow(SDL_Window, SW_MINIMIZE);
257	return(1);
258}
259
260SDL_GrabMode WIN_GrabInput(_THIS, SDL_GrabMode mode)
261{
262	if ( mode == SDL_GRAB_OFF ) {
263		ClipCursor(NULL);
264		if ( !(SDL_cursorstate & CURSOR_VISIBLE) ) {
265		/*	RJR: March 28, 2000
266			must be leaving relative mode, move mouse from
267			center of window to where it belongs ... */
268			POINT pt;
269			int x, y;
270			SDL_GetMouseState(&x,&y);
271			pt.x = x;
272			pt.y = y;
273			ClientToScreen(SDL_Window, &pt);
274			SetCursorPos(pt.x,pt.y);
275		}
276#ifdef _WIN32_WCE
277		AllKeys(0);
278#endif
279	} else {
280		ClipCursor(&SDL_bounds);
281		if ( !(SDL_cursorstate & CURSOR_VISIBLE) ) {
282		/*	RJR: March 28, 2000
283			must be entering relative mode, get ready by
284			moving mouse to	center of window ... */
285			POINT pt;
286			pt.x = (SDL_VideoSurface->w/2);
287			pt.y = (SDL_VideoSurface->h/2);
288			ClientToScreen(SDL_Window, &pt);
289			SetCursorPos(pt.x, pt.y);
290		}
291#ifdef _WIN32_WCE
292		AllKeys(1);
293#endif
294	}
295	return(mode);
296}
297
298/* If 'info' is the right version, this function fills it and returns 1.
299   Otherwise, in case of a version mismatch, it returns -1.
300*/
301int WIN_GetWMInfo(_THIS, SDL_SysWMinfo *info)
302{
303	if ( info->version.major <= SDL_MAJOR_VERSION ) {
304		info->window = SDL_Window;
305		if ( SDL_VERSIONNUM(info->version.major,
306		                    info->version.minor,
307		                    info->version.patch) >=
308		     SDL_VERSIONNUM(1, 2, 5) ) {
309#if SDL_VIDEO_OPENGL
310			info->hglrc = GL_hrc;
311#else
312			info->hglrc = NULL;
313#endif
314		}
315		return(1);
316	} else {
317		SDL_SetError("Application not compiled with SDL %d.%d\n",
318					SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
319		return(-1);
320	}
321}
322