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