SDL-1.2.14
[sdl_omap.git] / src / video / wincommon / SDL_sysevents.c
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 */