e14743d1 |
1 | /* |
2 | SDL - Simple DirectMedia Layer |
3 | Copyright (C) 1997-2009 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 | /* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */ |
28 | #ifndef WM_XBUTTONDOWN |
29 | #define WM_XBUTTONDOWN 0x020B |
30 | #endif |
31 | #ifndef WM_XBUTTONUP |
32 | #define WM_XBUTTONUP 0x020C |
33 | #endif |
34 | #ifndef GET_XBUTTON_WPARAM |
35 | #define GET_XBUTTON_WPARAM(w) (HIWORD(w)) |
36 | #endif |
37 | |
38 | #include "SDL_events.h" |
39 | #include "SDL_video.h" |
40 | #include "SDL_syswm.h" |
41 | #include "../SDL_sysvideo.h" |
42 | #include "../../events/SDL_sysevents.h" |
43 | #include "../../events/SDL_events_c.h" |
44 | #include "SDL_lowvideo.h" |
45 | #include "SDL_syswm_c.h" |
46 | #include "SDL_main.h" |
47 | #include "SDL_loadso.h" |
48 | |
49 | #ifdef WMMSG_DEBUG |
50 | #include "wmmsg.h" |
51 | #endif |
52 | |
53 | #include "../windib/SDL_gapidibvideo.h" |
54 | |
55 | #ifdef SDL_VIDEO_DRIVER_GAPI |
56 | #include "../gapi/SDL_gapivideo.h" |
57 | #endif |
58 | |
59 | #ifdef _WIN32_WCE |
60 | #define IsZoomed(HWND) 1 |
61 | #define NO_GETKEYBOARDSTATE |
62 | #if _WIN32_WCE < 420 |
63 | #define NO_CHANGEDISPLAYSETTINGS |
64 | #endif |
65 | #endif |
66 | |
67 | /* The window we use for everything... */ |
68 | #ifdef _WIN32_WCE |
69 | LPWSTR SDL_Appname = NULL; |
70 | #else |
71 | LPSTR SDL_Appname = NULL; |
72 | #endif |
73 | Uint32 SDL_Appstyle = 0; |
74 | HINSTANCE SDL_Instance = NULL; |
75 | HWND SDL_Window = NULL; |
76 | RECT SDL_bounds = {0, 0, 0, 0}; |
77 | int SDL_windowX = 0; |
78 | int SDL_windowY = 0; |
79 | int SDL_resizing = 0; |
80 | int mouse_relative = 0; |
81 | int posted = 0; |
82 | #ifndef NO_CHANGEDISPLAYSETTINGS |
83 | DEVMODE SDL_desktop_mode; |
84 | DEVMODE SDL_fullscreen_mode; |
85 | #endif |
86 | WORD *gamma_saved = NULL; |
87 | |
88 | |
89 | /* Functions called by the message processing function */ |
90 | LONG (*HandleMessage)(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)=NULL; |
91 | void (*WIN_Activate)(_THIS, BOOL active, BOOL iconic); |
92 | void (*WIN_RealizePalette)(_THIS); |
93 | void (*WIN_PaletteChanged)(_THIS, HWND window); |
94 | void (*WIN_WinPAINT)(_THIS, HDC hdc); |
95 | extern void DIB_SwapGamma(_THIS); |
96 | |
97 | #ifndef NO_GETKEYBOARDSTATE |
98 | /* Variables and support functions for SDL_ToUnicode() */ |
99 | static int codepage; |
100 | static int Is9xME(); |
101 | static int GetCodePage(); |
102 | static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, BYTE *keystate, LPWSTR wchars, int wsize, UINT flags); |
103 | |
104 | ToUnicodeFN SDL_ToUnicode = ToUnicode9xME; |
105 | #endif /* !NO_GETKEYBOARDSTATE */ |
106 | |
107 | |
108 | #if defined(_WIN32_WCE) |
109 | |
110 | //AdjustWindowRect is not available under WinCE 2003 |
111 | #define AdjustWindowRect(a,b,c) (AdjustWindowRectEx((a),(b),(c),0)) |
112 | |
113 | // dynamically load aygshell dll because we want SDL to work on HPC and be300 |
114 | HINSTANCE aygshell = NULL; |
115 | BOOL (WINAPI *SHFullScreen)(HWND hwndRequester, DWORD dwState) = 0; |
116 | |
117 | #define SHFS_SHOWTASKBAR 0x0001 |
118 | #define SHFS_HIDETASKBAR 0x0002 |
119 | #define SHFS_SHOWSIPBUTTON 0x0004 |
120 | #define SHFS_HIDESIPBUTTON 0x0008 |
121 | #define SHFS_SHOWSTARTICON 0x0010 |
122 | #define SHFS_HIDESTARTICON 0x0020 |
123 | |
124 | static void LoadAygshell(void) |
125 | { |
126 | if( !aygshell ) |
127 | aygshell = SDL_LoadObject("aygshell.dll"); |
128 | if( (aygshell != 0) && (SHFullScreen == 0) ) |
129 | { |
130 | SHFullScreen = (int (WINAPI *)(struct HWND__ *,unsigned long)) SDL_LoadFunction(aygshell, "SHFullScreen"); |
131 | } |
132 | } |
133 | |
134 | #endif |
135 | |
136 | /* JC 14 Mar 2006 |
137 | This is used all over the place, in the windib driver and in the dx5 driver |
138 | So we may as well stick it here instead of having multiple copies scattered |
139 | about |
140 | */ |
141 | void WIN_FlushMessageQueue() |
142 | { |
143 | MSG msg; |
144 | while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) { |
145 | if ( msg.message == WM_QUIT ) break; |
146 | TranslateMessage( &msg ); |
147 | DispatchMessage( &msg ); |
148 | } |
149 | } |
150 | |
151 | static void SDL_RestoreGameMode(void) |
152 | { |
153 | #ifdef _WIN32_WCE //Under ce we don't minimize, therefore no restore |
154 | |
155 | #ifdef SDL_VIDEO_DRIVER_GAPI |
156 | SDL_VideoDevice *this = current_video; |
157 | if(SDL_strcmp(this->name, "gapi") == 0) |
158 | { |
159 | if( this->hidden->gapiInfo->suspended ) |
160 | { |
161 | this->hidden->gapiInfo->suspended = 0; |
162 | } |
163 | } |
164 | #endif |
165 | |
166 | #else |
167 | ShowWindow(SDL_Window, SW_RESTORE); |
168 | #endif |
169 | |
170 | #ifndef NO_CHANGEDISPLAYSETTINGS |
171 | #ifndef _WIN32_WCE |
172 | ChangeDisplaySettings(&SDL_fullscreen_mode, CDS_FULLSCREEN); |
173 | #endif |
174 | #endif /* NO_CHANGEDISPLAYSETTINGS */ |
175 | } |
176 | static void SDL_RestoreDesktopMode(void) |
177 | { |
178 | |
179 | #ifdef _WIN32_WCE |
180 | |
181 | #ifdef SDL_VIDEO_DRIVER_GAPI |
182 | SDL_VideoDevice *this = current_video; |
183 | if(SDL_strcmp(this->name, "gapi") == 0) |
184 | { |
185 | if( !this->hidden->gapiInfo->suspended ) |
186 | { |
187 | this->hidden->gapiInfo->suspended = 1; |
188 | } |
189 | } |
190 | #endif |
191 | |
192 | #else |
193 | /* WinCE does not have a taskbar, so minimizing is not convenient */ |
194 | ShowWindow(SDL_Window, SW_MINIMIZE); |
195 | #endif |
196 | |
197 | #ifndef NO_CHANGEDISPLAYSETTINGS |
198 | #ifndef _WIN32_WCE |
199 | ChangeDisplaySettings(NULL, 0); |
200 | #endif |
201 | #endif /* NO_CHANGEDISPLAYSETTINGS */ |
202 | } |
203 | |
204 | #ifdef WM_MOUSELEAVE |
205 | /* |
206 | Special code to handle mouse leave events - this sucks... |
207 | http://support.microsoft.com/support/kb/articles/q183/1/07.asp |
208 | |
209 | TrackMouseEvent() is only available on Win98 and WinNT. |
210 | _TrackMouseEvent() is available on Win95, but isn't yet in the mingw32 |
211 | development environment, and only works on systems that have had IE 3.0 |
212 | or newer installed on them (which is not the case with the base Win95). |
213 | Therefore, we implement our own version of _TrackMouseEvent() which |
214 | uses our own implementation if TrackMouseEvent() is not available. |
215 | */ |
216 | static BOOL (WINAPI *_TrackMouseEvent)(TRACKMOUSEEVENT *ptme) = NULL; |
217 | |
218 | static VOID CALLBACK |
219 | TrackMouseTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime) |
220 | { |
221 | RECT rect; |
222 | POINT pt; |
223 | |
224 | GetClientRect(hWnd, &rect); |
225 | MapWindowPoints(hWnd, NULL, (LPPOINT)&rect, 2); |
226 | GetCursorPos(&pt); |
227 | if ( !PtInRect(&rect, pt) || (WindowFromPoint(pt) != hWnd) ) { |
228 | if ( !KillTimer(hWnd, idEvent) ) { |
229 | /* Error killing the timer! */ |
230 | } |
231 | PostMessage(hWnd, WM_MOUSELEAVE, 0, 0); |
232 | } |
233 | } |
234 | static BOOL WINAPI WIN_TrackMouseEvent(TRACKMOUSEEVENT *ptme) |
235 | { |
236 | if ( ptme->dwFlags == TME_LEAVE ) { |
237 | return SetTimer(ptme->hwndTrack, ptme->dwFlags, 100, |
238 | (TIMERPROC)TrackMouseTimerProc) != 0; |
239 | } |
240 | return FALSE; |
241 | } |
242 | #endif /* WM_MOUSELEAVE */ |
243 | |
244 | /* Function to retrieve the current keyboard modifiers */ |
245 | static void WIN_GetKeyboardState(void) |
246 | { |
247 | #ifndef NO_GETKEYBOARDSTATE |
248 | SDLMod state; |
249 | BYTE keyboard[256]; |
250 | Uint8 *kstate = SDL_GetKeyState(NULL); |
251 | |
252 | state = KMOD_NONE; |
253 | if ( GetKeyboardState(keyboard) ) { |
254 | if ( keyboard[VK_LSHIFT] & 0x80) { |
255 | state |= KMOD_LSHIFT; |
256 | kstate[SDLK_LSHIFT] = SDL_PRESSED; |
257 | } |
258 | if ( keyboard[VK_RSHIFT] & 0x80) { |
259 | state |= KMOD_RSHIFT; |
260 | kstate[SDLK_RSHIFT] = SDL_PRESSED; |
261 | } |
262 | if ( keyboard[VK_LCONTROL] & 0x80) { |
263 | state |= KMOD_LCTRL; |
264 | kstate[SDLK_LCTRL] = SDL_PRESSED; |
265 | } |
266 | if ( keyboard[VK_RCONTROL] & 0x80) { |
267 | state |= KMOD_RCTRL; |
268 | kstate[SDLK_RCTRL] = SDL_PRESSED; |
269 | } |
270 | if ( keyboard[VK_LMENU] & 0x80) { |
271 | state |= KMOD_LALT; |
272 | kstate[SDLK_LALT] = SDL_PRESSED; |
273 | } |
274 | if ( keyboard[VK_RMENU] & 0x80) { |
275 | state |= KMOD_RALT; |
276 | kstate[SDLK_RALT] = SDL_PRESSED; |
277 | } |
278 | if ( keyboard[VK_NUMLOCK] & 0x01) { |
279 | state |= KMOD_NUM; |
280 | kstate[SDLK_NUMLOCK] = SDL_PRESSED; |
281 | } |
282 | if ( keyboard[VK_CAPITAL] & 0x01) { |
283 | state |= KMOD_CAPS; |
284 | kstate[SDLK_CAPSLOCK] = SDL_PRESSED; |
285 | } |
286 | } |
287 | SDL_SetModState(state); |
288 | #endif /* !NO_GETKEYBOARDSTATE */ |
289 | } |
290 | |
291 | /* The main Win32 event handler |
292 | DJM: This is no longer static as (DX5/DIB)_CreateWindow needs it |
293 | */ |
294 | LRESULT CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
295 | { |
296 | SDL_VideoDevice *this = current_video; |
297 | static int mouse_pressed = 0; |
298 | #ifdef WMMSG_DEBUG |
299 | fprintf(stderr, "Received windows message: "); |
300 | if ( msg > MAX_WMMSG ) { |
301 | fprintf(stderr, "%d", msg); |
302 | } else { |
303 | fprintf(stderr, "%s", wmtab[msg]); |
304 | } |
305 | fprintf(stderr, " -- 0x%X, 0x%X\n", wParam, lParam); |
306 | #endif |
307 | switch (msg) { |
308 | |
309 | case WM_ACTIVATE: { |
310 | SDL_VideoDevice *this = current_video; |
311 | BOOL active, minimized; |
312 | Uint8 appstate; |
313 | |
314 | minimized = HIWORD(wParam); |
315 | active = (LOWORD(wParam) != WA_INACTIVE) && !minimized; |
316 | if ( active ) { |
317 | /* Gain the following states */ |
318 | appstate = SDL_APPACTIVE|SDL_APPINPUTFOCUS; |
319 | if ( this->input_grab != SDL_GRAB_OFF ) { |
320 | WIN_GrabInput(this, SDL_GRAB_ON); |
321 | } |
322 | if ( !(SDL_GetAppState()&SDL_APPINPUTFOCUS) ) { |
323 | if ( ! DDRAW_FULLSCREEN() ) { |
324 | DIB_SwapGamma(this); |
325 | } |
326 | if ( WINDIB_FULLSCREEN() ) { |
327 | SDL_RestoreGameMode(); |
328 | } |
329 | } |
330 | #if defined(_WIN32_WCE) |
331 | if ( WINDIB_FULLSCREEN() ) { |
332 | LoadAygshell(); |
333 | if( SHFullScreen ) |
334 | SHFullScreen(SDL_Window, SHFS_HIDESTARTICON|SHFS_HIDETASKBAR|SHFS_HIDESIPBUTTON); |
335 | else |
336 | ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_HIDE); |
337 | } |
338 | #endif |
339 | posted = SDL_PrivateAppActive(1, appstate); |
340 | WIN_GetKeyboardState(); |
341 | } else { |
342 | /* Lose the following states */ |
343 | appstate = SDL_APPINPUTFOCUS; |
344 | if ( minimized ) { |
345 | appstate |= SDL_APPACTIVE; |
346 | } |
347 | if ( this->input_grab != SDL_GRAB_OFF ) { |
348 | WIN_GrabInput(this, SDL_GRAB_OFF); |
349 | } |
350 | if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) { |
351 | if ( ! DDRAW_FULLSCREEN() ) { |
352 | DIB_SwapGamma(this); |
353 | } |
354 | if ( WINDIB_FULLSCREEN() ) { |
355 | SDL_RestoreDesktopMode(); |
356 | #if defined(_WIN32_WCE) |
357 | LoadAygshell(); |
358 | if( SHFullScreen ) |
359 | SHFullScreen(SDL_Window, SHFS_SHOWSTARTICON|SHFS_SHOWTASKBAR|SHFS_SHOWSIPBUTTON); |
360 | else |
361 | ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOW); |
362 | #endif |
363 | } |
364 | } |
365 | posted = SDL_PrivateAppActive(0, appstate); |
366 | } |
367 | WIN_Activate(this, active, minimized); |
368 | return(0); |
369 | } |
370 | break; |
371 | |
372 | case WM_MOUSEMOVE: { |
373 | |
374 | #ifdef WM_MOUSELEAVE |
375 | /* No need to handle SDL_APPMOUSEFOCUS when fullscreen */ |
376 | if ( SDL_VideoSurface && !FULLSCREEN() ) { |
377 | /* mouse has entered the window */ |
378 | |
379 | if ( !(SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) { |
380 | TRACKMOUSEEVENT tme; |
381 | |
382 | tme.cbSize = sizeof(tme); |
383 | tme.dwFlags = TME_LEAVE; |
384 | tme.hwndTrack = SDL_Window; |
385 | _TrackMouseEvent(&tme); |
386 | } |
387 | } |
388 | #endif /* WM_MOUSELEAVE */ |
389 | |
390 | /* Mouse motion is handled in DIB_PumpEvents or |
391 | * DX5_PumpEvents, depending on the video driver |
392 | * in use */ |
393 | |
394 | posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); |
395 | } |
396 | return(0); |
397 | |
398 | #ifdef WM_MOUSELEAVE |
399 | case WM_MOUSELEAVE: { |
400 | |
401 | /* No need to handle SDL_APPMOUSEFOCUS when fullscreen */ |
402 | if ( SDL_VideoSurface && !FULLSCREEN() ) { |
403 | /* mouse has left the window */ |
404 | /* or */ |
405 | /* Elvis has left the building! */ |
406 | posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); |
407 | } |
408 | } |
409 | return(0); |
410 | #endif /* WM_MOUSELEAVE */ |
411 | |
412 | case WM_LBUTTONDOWN: |
413 | case WM_LBUTTONUP: |
414 | case WM_MBUTTONDOWN: |
415 | case WM_MBUTTONUP: |
416 | case WM_RBUTTONDOWN: |
417 | case WM_RBUTTONUP: |
418 | case WM_XBUTTONDOWN: |
419 | case WM_XBUTTONUP: { |
420 | /* Mouse is handled by DirectInput when fullscreen */ |
421 | if ( SDL_VideoSurface && ! DINPUT() ) { |
422 | WORD xbuttonval = 0; |
423 | Uint8 button, state; |
424 | |
425 | /* DJM: |
426 | We want the SDL window to take focus so that |
427 | it acts like a normal windows "component" |
428 | (e.g. gains keyboard focus on a mouse click). |
429 | */ |
430 | SetFocus(SDL_Window); |
431 | |
432 | /* Figure out which button to use */ |
433 | switch (msg) { |
434 | case WM_LBUTTONDOWN: |
435 | button = SDL_BUTTON_LEFT; |
436 | state = SDL_PRESSED; |
437 | break; |
438 | case WM_LBUTTONUP: |
439 | button = SDL_BUTTON_LEFT; |
440 | state = SDL_RELEASED; |
441 | break; |
442 | case WM_MBUTTONDOWN: |
443 | button = SDL_BUTTON_MIDDLE; |
444 | state = SDL_PRESSED; |
445 | break; |
446 | case WM_MBUTTONUP: |
447 | button = SDL_BUTTON_MIDDLE; |
448 | state = SDL_RELEASED; |
449 | break; |
450 | case WM_RBUTTONDOWN: |
451 | button = SDL_BUTTON_RIGHT; |
452 | state = SDL_PRESSED; |
453 | break; |
454 | case WM_RBUTTONUP: |
455 | button = SDL_BUTTON_RIGHT; |
456 | state = SDL_RELEASED; |
457 | break; |
458 | case WM_XBUTTONDOWN: |
459 | xbuttonval = GET_XBUTTON_WPARAM(wParam); |
460 | button = SDL_BUTTON_X1 + xbuttonval - 1; |
461 | state = SDL_PRESSED; |
462 | break; |
463 | case WM_XBUTTONUP: |
464 | xbuttonval = GET_XBUTTON_WPARAM(wParam); |
465 | button = SDL_BUTTON_X1 + xbuttonval - 1; |
466 | state = SDL_RELEASED; |
467 | break; |
468 | default: |
469 | /* Eh? Unknown button? */ |
470 | return(0); |
471 | } |
472 | if ( state == SDL_PRESSED ) { |
473 | /* Grab mouse so we get up events */ |
474 | if ( ++mouse_pressed > 0 ) { |
475 | SetCapture(hwnd); |
476 | } |
477 | } else { |
478 | /* Release mouse after all up events */ |
479 | if ( --mouse_pressed <= 0 ) { |
480 | ReleaseCapture(); |
481 | mouse_pressed = 0; |
482 | } |
483 | } |
484 | posted = SDL_PrivateMouseButton( |
485 | state, button, 0, 0); |
486 | |
487 | /* |
488 | * MSDN says: |
489 | * "Unlike the WM_LBUTTONUP, WM_MBUTTONUP, and WM_RBUTTONUP |
490 | * messages, an application should return TRUE from [an |
491 | * XBUTTON message] if it processes it. Doing so will allow |
492 | * software that simulates this message on Microsoft Windows |
493 | * systems earlier than Windows 2000 to determine whether |
494 | * the window procedure processed the message or called |
495 | * DefWindowProc to process it. |
496 | */ |
497 | if (xbuttonval > 0) |
498 | return(TRUE); |
499 | } |
500 | } |
501 | return(0); |
502 | |
503 | |
504 | #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) |
505 | case WM_MOUSEWHEEL: |
506 | if ( SDL_VideoSurface && ! DINPUT() ) { |
507 | int move = (short)HIWORD(wParam); |
508 | if ( move ) { |
509 | Uint8 button; |
510 | if ( move > 0 ) |
511 | button = SDL_BUTTON_WHEELUP; |
512 | else |
513 | button = SDL_BUTTON_WHEELDOWN; |
514 | posted = SDL_PrivateMouseButton( |
515 | SDL_PRESSED, button, 0, 0); |
516 | posted |= SDL_PrivateMouseButton( |
517 | SDL_RELEASED, button, 0, 0); |
518 | } |
519 | } |
520 | return(0); |
521 | #endif |
522 | |
523 | #ifdef WM_GETMINMAXINFO |
524 | /* This message is sent as a way for us to "check" the values |
525 | * of a position change. If we don't like it, we can adjust |
526 | * the values before they are changed. |
527 | */ |
528 | case WM_GETMINMAXINFO: { |
529 | MINMAXINFO *info; |
530 | RECT size; |
531 | int x, y; |
532 | int style; |
533 | int width; |
534 | int height; |
535 | |
536 | /* We don't want to clobber an internal resize */ |
537 | if ( SDL_resizing ) |
538 | return(0); |
539 | |
540 | /* We allow resizing with the SDL_RESIZABLE flag */ |
541 | if ( SDL_PublicSurface && |
542 | (SDL_PublicSurface->flags & SDL_RESIZABLE) ) { |
543 | return(0); |
544 | } |
545 | |
546 | /* Get the current position of our window */ |
547 | GetWindowRect(SDL_Window, &size); |
548 | x = size.left; |
549 | y = size.top; |
550 | |
551 | /* Calculate current width and height of our window */ |
552 | size.top = 0; |
553 | size.left = 0; |
554 | if ( SDL_PublicSurface != NULL ) { |
555 | size.bottom = SDL_PublicSurface->h; |
556 | size.right = SDL_PublicSurface->w; |
557 | } else { |
558 | size.bottom = 0; |
559 | size.right = 0; |
560 | } |
561 | |
562 | /* DJM - according to the docs for GetMenu(), the |
563 | return value is undefined if hwnd is a child window. |
564 | Aparently it's too difficult for MS to check |
565 | inside their function, so I have to do it here. |
566 | */ |
567 | style = GetWindowLong(hwnd, GWL_STYLE); |
568 | AdjustWindowRect( |
569 | &size, |
570 | style, |
571 | style & WS_CHILDWINDOW ? FALSE |
572 | : GetMenu(hwnd) != NULL); |
573 | |
574 | width = size.right - size.left; |
575 | height = size.bottom - size.top; |
576 | |
577 | /* Fix our size to the current size */ |
578 | info = (MINMAXINFO *)lParam; |
579 | info->ptMaxSize.x = width; |
580 | info->ptMaxSize.y = height; |
581 | info->ptMaxPosition.x = x; |
582 | info->ptMaxPosition.y = y; |
583 | info->ptMinTrackSize.x = width; |
584 | info->ptMinTrackSize.y = height; |
585 | info->ptMaxTrackSize.x = width; |
586 | info->ptMaxTrackSize.y = height; |
587 | } |
588 | return(0); |
589 | #endif /* WM_GETMINMAXINFO */ |
590 | |
591 | case WM_WINDOWPOSCHANGING: { |
592 | WINDOWPOS *windowpos = (WINDOWPOS*)lParam; |
593 | |
594 | /* When menu is at the side or top, Windows likes |
595 | to try to reposition the fullscreen window when |
596 | changing video modes. |
597 | */ |
598 | if ( !SDL_resizing && |
599 | SDL_PublicSurface && |
600 | (SDL_PublicSurface->flags & SDL_FULLSCREEN) ) { |
601 | windowpos->x = 0; |
602 | windowpos->y = 0; |
603 | } |
604 | } |
605 | return(0); |
606 | |
607 | case WM_WINDOWPOSCHANGED: { |
608 | SDL_VideoDevice *this = current_video; |
609 | int w, h; |
610 | |
611 | GetClientRect(SDL_Window, &SDL_bounds); |
612 | ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds); |
613 | ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds+1); |
614 | if ( !SDL_resizing && !IsZoomed(SDL_Window) && |
615 | SDL_PublicSurface && |
616 | !(SDL_PublicSurface->flags & SDL_FULLSCREEN) ) { |
617 | SDL_windowX = SDL_bounds.left; |
618 | SDL_windowY = SDL_bounds.top; |
619 | } |
620 | w = SDL_bounds.right-SDL_bounds.left; |
621 | h = SDL_bounds.bottom-SDL_bounds.top; |
622 | if ( this->input_grab != SDL_GRAB_OFF ) { |
623 | ClipCursor(&SDL_bounds); |
624 | } |
625 | if ( SDL_PublicSurface && |
626 | (SDL_PublicSurface->flags & SDL_RESIZABLE) ) { |
627 | SDL_PrivateResize(w, h); |
628 | } |
629 | } |
630 | break; |
631 | |
632 | /* We need to set the cursor */ |
633 | case WM_SETCURSOR: { |
634 | Uint16 hittest; |
635 | |
636 | hittest = LOWORD(lParam); |
637 | if ( hittest == HTCLIENT ) { |
638 | SetCursor(SDL_hcursor); |
639 | return(TRUE); |
640 | } |
641 | } |
642 | break; |
643 | |
644 | /* We are about to get palette focus! */ |
645 | case WM_QUERYNEWPALETTE: { |
646 | WIN_RealizePalette(current_video); |
647 | return(TRUE); |
648 | } |
649 | break; |
650 | |
651 | /* Another application changed the palette */ |
652 | case WM_PALETTECHANGED: { |
653 | WIN_PaletteChanged(current_video, (HWND)wParam); |
654 | } |
655 | break; |
656 | |
657 | /* We were occluded, refresh our display */ |
658 | case WM_PAINT: { |
659 | HDC hdc; |
660 | PAINTSTRUCT ps; |
661 | |
662 | hdc = BeginPaint(SDL_Window, &ps); |
663 | if ( current_video->screen && |
664 | !(current_video->screen->flags & SDL_OPENGL) ) { |
665 | WIN_WinPAINT(current_video, hdc); |
666 | } |
667 | EndPaint(SDL_Window, &ps); |
668 | } |
669 | return(0); |
670 | |
671 | /* DJM: Send an expose event in this case */ |
672 | case WM_ERASEBKGND: { |
673 | posted = SDL_PrivateExpose(); |
674 | } |
675 | return(0); |
676 | |
677 | case WM_CLOSE: { |
678 | if ( (posted = SDL_PrivateQuit()) ) |
679 | PostQuitMessage(0); |
680 | } |
681 | return(0); |
682 | |
683 | case WM_DESTROY: { |
684 | PostQuitMessage(0); |
685 | } |
686 | return(0); |
687 | |
688 | #ifndef NO_GETKEYBOARDSTATE |
689 | case WM_INPUTLANGCHANGE: { |
690 | codepage = GetCodePage(); |
691 | } |
692 | return(TRUE); |
693 | #endif |
694 | |
695 | default: { |
696 | /* Special handling by the video driver */ |
697 | if (HandleMessage) { |
698 | return(HandleMessage(current_video, |
699 | hwnd, msg, wParam, lParam)); |
700 | } |
701 | } |
702 | break; |
703 | } |
704 | return(DefWindowProc(hwnd, msg, wParam, lParam)); |
705 | } |
706 | |
707 | /* Allow the application handle to be stored and retrieved later */ |
708 | static void *SDL_handle = NULL; |
709 | |
710 | void SDL_SetModuleHandle(void *handle) |
711 | { |
712 | SDL_handle = handle; |
713 | } |
714 | void *SDL_GetModuleHandle(void) |
715 | { |
716 | void *handle; |
717 | |
718 | if ( SDL_handle ) { |
719 | handle = SDL_handle; |
720 | } else { |
721 | handle = GetModuleHandle(NULL); |
722 | } |
723 | return(handle); |
724 | } |
725 | |
726 | /* This allows the SDL_WINDOWID hack */ |
727 | BOOL SDL_windowid = FALSE; |
728 | |
729 | static int app_registered = 0; |
730 | |
731 | /* Register the class for this application -- exported for winmain.c */ |
732 | int SDL_RegisterApp(char *name, Uint32 style, void *hInst) |
733 | { |
734 | WNDCLASS class; |
735 | #ifdef WM_MOUSELEAVE |
736 | HMODULE handle; |
737 | #endif |
738 | |
739 | /* Only do this once... */ |
740 | if ( app_registered ) { |
741 | ++app_registered; |
742 | return(0); |
743 | } |
744 | |
745 | #ifndef CS_BYTEALIGNCLIENT |
746 | #define CS_BYTEALIGNCLIENT 0 |
747 | #endif |
748 | if ( ! name && ! SDL_Appname ) { |
749 | name = "SDL_app"; |
750 | SDL_Appstyle = CS_BYTEALIGNCLIENT; |
751 | SDL_Instance = hInst ? hInst : SDL_GetModuleHandle(); |
752 | } |
753 | |
754 | if ( name ) { |
755 | #ifdef _WIN32_WCE |
756 | /* WinCE uses the UNICODE version */ |
757 | SDL_Appname = SDL_iconv_utf8_ucs2(name); |
758 | #else |
759 | SDL_Appname = SDL_iconv_utf8_locale(name); |
760 | #endif /* _WIN32_WCE */ |
761 | SDL_Appstyle = style; |
762 | SDL_Instance = hInst ? hInst : SDL_GetModuleHandle(); |
763 | } |
764 | |
765 | /* Register the application class */ |
766 | class.hCursor = NULL; |
767 | class.hIcon = LoadImage(SDL_Instance, SDL_Appname, |
768 | IMAGE_ICON, |
769 | 0, 0, LR_DEFAULTCOLOR); |
770 | class.lpszMenuName = NULL; |
771 | class.lpszClassName = SDL_Appname; |
772 | class.hbrBackground = NULL; |
773 | class.hInstance = SDL_Instance; |
774 | class.style = SDL_Appstyle; |
775 | #if SDL_VIDEO_OPENGL |
776 | class.style |= CS_OWNDC; |
777 | #endif |
778 | class.lpfnWndProc = WinMessage; |
779 | class.cbWndExtra = 0; |
780 | class.cbClsExtra = 0; |
781 | if ( ! RegisterClass(&class) ) { |
782 | SDL_SetError("Couldn't register application class"); |
783 | return(-1); |
784 | } |
785 | |
786 | #ifdef WM_MOUSELEAVE |
787 | /* Get the version of TrackMouseEvent() we use */ |
788 | _TrackMouseEvent = NULL; |
789 | handle = GetModuleHandle("USER32.DLL"); |
790 | if ( handle ) { |
791 | _TrackMouseEvent = (BOOL (WINAPI *)(TRACKMOUSEEVENT *))GetProcAddress(handle, "TrackMouseEvent"); |
792 | } |
793 | if ( _TrackMouseEvent == NULL ) { |
794 | _TrackMouseEvent = WIN_TrackMouseEvent; |
795 | } |
796 | #endif /* WM_MOUSELEAVE */ |
797 | |
798 | #ifndef NO_GETKEYBOARDSTATE |
799 | /* Initialise variables for SDL_ToUnicode() */ |
800 | codepage = GetCodePage(); |
801 | SDL_ToUnicode = Is9xME() ? ToUnicode9xME : ToUnicode; |
802 | #endif |
803 | |
804 | app_registered = 1; |
805 | return(0); |
806 | } |
807 | |
808 | /* Unregisters the windowclass registered in SDL_RegisterApp above. */ |
809 | void SDL_UnregisterApp() |
810 | { |
811 | WNDCLASS class; |
812 | |
813 | /* SDL_RegisterApp might not have been called before */ |
814 | if ( !app_registered ) { |
815 | return; |
816 | } |
817 | --app_registered; |
818 | if ( app_registered == 0 ) { |
819 | /* Check for any registered window classes. */ |
820 | if ( GetClassInfo(SDL_Instance, SDL_Appname, &class) ) { |
821 | UnregisterClass(SDL_Appname, SDL_Instance); |
822 | } |
823 | SDL_free(SDL_Appname); |
824 | SDL_Appname = NULL; |
825 | } |
826 | } |
827 | |
828 | #ifndef NO_GETKEYBOARDSTATE |
829 | /* JFP: Implementation of ToUnicode() that works on 9x/ME/2K/XP */ |
830 | |
831 | static int Is9xME() |
832 | { |
833 | OSVERSIONINFO info; |
834 | |
835 | SDL_memset(&info, 0, sizeof(info)); |
836 | info.dwOSVersionInfoSize = sizeof(info); |
837 | if (!GetVersionEx(&info)) { |
838 | return 0; |
839 | } |
840 | return (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); |
841 | } |
842 | |
843 | static int GetCodePage() |
844 | { |
845 | char buff[8]; |
846 | int lcid = MAKELCID(LOWORD(GetKeyboardLayout(0)), SORT_DEFAULT); |
847 | int cp = GetACP(); |
848 | |
849 | if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buff, sizeof(buff))) { |
850 | cp = SDL_atoi(buff); |
851 | } |
852 | return cp; |
853 | } |
854 | |
855 | static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, PBYTE keystate, LPWSTR wchars, int wsize, UINT flags) |
856 | { |
857 | BYTE chars[2]; |
858 | |
859 | if (ToAsciiEx(vkey, scancode, keystate, (WORD*)chars, 0, GetKeyboardLayout(0)) == 1) { |
860 | return MultiByteToWideChar(codepage, 0, chars, 1, wchars, wsize); |
861 | } |
862 | return 0; |
863 | } |
864 | |
865 | #endif /* !NO_GETKEYBOARDSTATE */ |