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#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	Uint16 *lpsz = SDL_iconv_utf8_ucs2(title);
221	size_t len = WideCharToMultiByte(CP_ACP, 0, lpsz, -1, NULL, 0, NULL, NULL);
222	char *cvt = SDL_stack_alloc(char, len + 1);
223	WideCharToMultiByte(CP_ACP, 0, lpsz, -1, cvt, len, NULL, NULL);
224	SetWindowText(SDL_Window, cvt);
225	SDL_stack_free(cvt);
226	SDL_free(lpsz);
227#endif
228}
229
230int WIN_IconifyWindow(_THIS)
231{
232	ShowWindow(SDL_Window, SW_MINIMIZE);
233	return(1);
234}
235
236SDL_GrabMode WIN_GrabInput(_THIS, SDL_GrabMode mode)
237{
238	if ( mode == SDL_GRAB_OFF ) {
239		ClipCursor(NULL);
240		if ( !(SDL_cursorstate & CURSOR_VISIBLE) ) {
241		/*	RJR: March 28, 2000
242			must be leaving relative mode, move mouse from
243			center of window to where it belongs ... */
244			POINT pt;
245			int x, y;
246			SDL_GetMouseState(&x,&y);
247			pt.x = x;
248			pt.y = y;
249			ClientToScreen(SDL_Window, &pt);
250			SetCursorPos(pt.x,pt.y);
251		}
252#ifdef _WIN32_WCE
253		AllKeys(0);
254#endif
255	} else {
256		ClipCursor(&SDL_bounds);
257		if ( !(SDL_cursorstate & CURSOR_VISIBLE) ) {
258		/*	RJR: March 28, 2000
259			must be entering relative mode, get ready by
260			moving mouse to	center of window ... */
261			POINT pt;
262			pt.x = (SDL_VideoSurface->w/2);
263			pt.y = (SDL_VideoSurface->h/2);
264			ClientToScreen(SDL_Window, &pt);
265			SetCursorPos(pt.x, pt.y);
266		}
267#ifdef _WIN32_WCE
268		AllKeys(1);
269#endif
270	}
271	return(mode);
272}
273
274/* If 'info' is the right version, this function fills it and returns 1.
275   Otherwise, in case of a version mismatch, it returns -1.
276*/
277int WIN_GetWMInfo(_THIS, SDL_SysWMinfo *info)
278{
279	if ( info->version.major <= SDL_MAJOR_VERSION ) {
280		info->window = SDL_Window;
281		if ( SDL_VERSIONNUM(info->version.major,
282		                    info->version.minor,
283		                    info->version.patch) >=
284		     SDL_VERSIONNUM(1, 2, 5) ) {
285#if SDL_VIDEO_OPENGL
286			info->hglrc = GL_hrc;
287#else
288			info->hglrc = NULL;
289#endif
290		}
291		return(1);
292	} else {
293		SDL_SetError("Application not compiled with SDL %d.%d\n",
294					SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
295		return(-1);
296	}
297}
298