Home | History | Annotate | Download | only in wincommon
      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 (at) 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() */
     42 HICON   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 */
     50 void 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 
    210 typedef BOOL (WINAPI *PtrSetWindowTextW)(HWND hWnd, LPCWSTR lpString);
    211 
    212 void 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 
    254 int WIN_IconifyWindow(_THIS)
    255 {
    256 	ShowWindow(SDL_Window, SW_MINIMIZE);
    257 	return(1);
    258 }
    259 
    260 SDL_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 */
    301 int 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