ecere: Added ChangeChars(); eda/ers: ; Avoiding bad filenames
[sdk] / ecere / src / gui / drivers / Win32Interface.ec
1 namespace gui::drivers;
2
3 import "instance"
4
5 #define UNICODE
6
7 #if defined(__WIN32__)
8
9 #undef WINVER
10 #define WINVER 0x0500
11 #undef _WIN32_WINNT
12 #define _WIN32_WINNT 0x0501
13
14 #undef JOY_BUTTON1
15 #undef JOY_BUTTON2
16 #undef JOY_BUTTON3
17 #undef JOY_BUTTON4
18
19 #define WIN32_LEAN_AND_MEAN
20 #define Method _Method
21 #define byte _byte
22 #define int64 _int64
23 #define String _String
24 #define Mutex _Mutex
25 #define Platform _Platform
26 #include <windows.h>
27 #include <wincon.h>
28 #include <shellapi.h>
29
30
31 #if defined(ECERE_VANILLA)
32 #define ECERE_NOJOYSTICK
33 #endif
34
35 #ifndef ECERE_NODINPUT
36 #ifndef ECERE_NOJOYSTICK
37 #define DIRECTINPUT_VERSION 0x700
38 #include <dinput.h>
39 #else
40 #define DIRECTINPUT_VERSION 0x300
41 #endif
42
43 #endif
44
45 #include <mmsystem.h>
46
47 #include <imm.h>
48
49 #define VK_SEMI       0xBA
50 #define VK_EQUALS     0xBB
51 #define VK_COMMA      0xBC
52 #define VK_MINUS      0xBD
53 #define VK_PERIOD     0xBE
54 #define VK_SLASH      0xBF
55 #define VK_TILDE      0xC0
56 #define VK_LBRACKET   0xDB
57 #define VK_BACK_SLASH 0xDC
58 #define VK_RBRACKET   0xDD
59 #define VK_QUOTE      0xDE
60
61 #ifndef WM_MOUSEWHEEL
62 #define WM_MOUSEWHEEL 0x20A
63 #endif
64
65 #ifndef IDC_HAND
66 #define IDC_HAND (char *)0x7F89
67 #endif
68
69 #ifndef WS_EX_LAYERED
70
71 #define LWA_COLORKEY            0x00000001
72 #define LWA_ALPHA               0x00000002
73
74 #define WS_EX_LAYERED           0x00080000
75
76 WINUSERAPI
77 BOOL
78 WINAPI
79 SetLayeredWindowAttributes(
80     HWND hwnd,
81     COLORREF crKey,
82     BYTE bAlpha,
83     DWORD dwFlags);
84
85 #endif
86
87 #undef Method
88 #undef byte
89 #undef int64
90 #undef String
91 #undef Mutex
92 #undef Platform
93
94 import "Window"
95
96 #ifdef ECERE_VANILLA
97 #define ECERE_NODINPUT
98 #define ECERE_NOJOYSTICK
99 #define ECERE_NOBLENDING
100 #endif
101
102 static byte key2VK[256] =
103 {
104    0,VK_ESCAPE,'1','2','3','4','5','6','7','8','9','0',VK_MINUS,VK_EQUALS,VK_BACK,VK_TAB,
105    'Q','W','E','R','T','Y','U','I','O','P',VK_LBRACKET,VK_RBRACKET,VK_RETURN,VK_LCONTROL,'A','S',
106    'D','F','G','H','J','K','L',VK_SEMI,VK_QUOTE,VK_TILDE,VK_LSHIFT,VK_BACK_SLASH,'Z','X','C','V',
107    'B','N','M',VK_COMMA,VK_PERIOD,VK_DIVIDE,VK_RSHIFT,VK_MULTIPLY,VK_LMENU,VK_SPACE,VK_CAPITAL,VK_F1,VK_F2,VK_F3,VK_F4,VK_F5,
108    VK_F6,VK_F7,VK_F8,VK_F9,VK_F10,VK_NUMLOCK,VK_SCROLL,VK_NUMPAD7,VK_NUMPAD8,VK_NUMPAD9,VK_SUBTRACT,VK_NUMPAD4,VK_NUMPAD5,VK_NUMPAD6,VK_ADD,VK_NUMPAD1,
109    VK_NUMPAD2,VK_NUMPAD3,VK_NUMPAD0,VK_DELETE,0,0,0,VK_F11,VK_F12,0,0,0,0,0,0,0,
110    0,VK_RCONTROL,0,0,VK_RMENU,0,VK_HOME,VK_UP,VK_PRIOR,VK_LEFT,VK_RIGHT,VK_END,VK_DOWN,VK_NEXT,VK_INSERT,VK_DELETE
111 };
112 static const uint16 className[] = L"Ecere Application";
113 static HINSTANCE hInstance;
114
115 static DEVMODE devMode;
116 #ifndef ECERE_NODINPUT
117 static HWND acquiredWindow = null;
118 #endif
119 static HCURSOR systemCursors[SystemCursor];
120 static bool fullScreenMode;
121 static int desktopX = 0, desktopY = 0, desktopW = 0, desktopH = 0;
122 static DWORD hiResTimer;
123 // static HWND topWindow;
124
125 static HWND startBar;
126
127 #ifndef ECERE_NODINPUT
128 #define NUMJOY    4
129 static HMODULE dInputDll = null;
130 static BOOL * (WINAPI * directInputCreate)(HINSTANCE, DWORD, IDirectInput **, void *);
131 static IDirectInput * dInput = null;
132 static IDirectInputDevice * directMouse = null;
133 #ifndef ECERE_NOJOYSTICK
134 static int numJoysticks = 0;
135 static IDirectInputDevice2 * directJoysticks[NUMJOY] = {null,null,null,null};
136 #endif
137 #endif
138
139 default:
140 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
141 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp;
142 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
143 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
144 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove;
145 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
146 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
147 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp;
148 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick;
149 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown;
150 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp;
151 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick;
152 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown;
153 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp;
154
155 private:
156
157 static Box lastMonitorAreas[32];
158 static Box monitorAreas[32];
159 static int monitor;
160
161 static bool EnumerateMonitors(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
162 {
163    MONITORINFO info = { 0 };
164    info.cbSize = sizeof(MONITORINFO);
165    GetMonitorInfo(hMonitor, &info);
166    monitorAreas[monitor] = { info.rcWork.left, info.rcWork.top, info.rcWork.right, info.rcWork.bottom };
167    monitor++;
168    return monitor < 32;
169 }
170
171 static bool externalDisplayChange;
172
173 static int taskBarState;
174 static WINDOWPLACEMENT taskBarPlacement;
175 static bool activateApp;
176
177 static SystemCursor lastCursor = (SystemCursor)-1;
178
179 void AeroSnapPosition(Window window, int x, int y, int w, int h)
180 {
181    int oldX = window.absPosition.x;
182
183    // To prevent having a window < minClientSize with Aero Snap, because we don't receive a WM_SIZING!
184    // The sensible implementation of this is in WM_SIZING
185    {
186       int gw = w, gh = h;
187       MinMaxValue ew, eh;
188       window.GetDecorationsSize(&ew, &eh);
189
190       gw -= ew;
191       gh -= eh;
192
193       gw = Max(gw, 1);
194       gh = Max(gh, 1);
195
196       gw = Max(gw, window.minSize.w);
197       gh = Max(gh, window.minSize.h);
198       gw = Min(gw, window.maxSize.w);
199       gh = Min(gh, window.maxSize.h);
200
201       if(!window.OnResizing(&gw, &gh))
202       {
203          gw = window.clientSize.w;
204          gh = window.clientSize.h;
205       }
206
207       gw = Max(gw, window.skinMinSize.w);
208       gh = Max(gh, window.skinMinSize.h);
209
210       gw += ew;
211       gh += eh;
212
213       if(w != gw || h != gh)
214       {
215          bool move = false;
216          // Adjust x position if we resized from top or bottom left corner
217          if(x != oldX)
218          {
219             x += w - gw;
220             move = true;
221          }
222          w = gw;
223          h = gh;
224          guiApp.interfaceDriver.PositionRootWindow(window, x, y, w, h, move, true);
225       }
226    }
227    window.ExternalPosition(x, y, w, h);
228 }
229
230 class Win32Interface : Interface
231 {
232    class_property(name) = "Win32";
233
234    void ::RepositionDesktop(bool updateChildren)
235    {
236       int c;
237       static double lastTime = 0, time;
238       int x = 0, y = 0;
239       int w = 0, h = 0;
240       //static Size lastScreen;
241       //static Point lastScreenPos;
242       static double lastAutoHideCheck = 0;
243       int newTaskBarState = taskBarState;
244       HMONITOR primaryMonitor = 0;
245
246       time = GetTime();
247       if(time - lastTime < 0.1) return;
248       lastTime = time;
249
250       // Every sec, check for the auto hide property
251       if(time - lastAutoHideCheck > 1)
252       {
253          APPBARDATA appBarData = { 0 };
254          newTaskBarState = (int)SHAppBarMessage(ABM_GETSTATE, &appBarData);
255          lastAutoHideCheck = time;
256       }
257
258       monitor = 0;
259       EnumDisplayMonitors(null, null, EnumerateMonitors, 0);
260       for(c = 0; c<monitor; c++)
261       {
262          if(monitorAreas[c].left != lastMonitorAreas[c].left ||
263             monitorAreas[c].top != lastMonitorAreas[c].top ||
264             monitorAreas[c].right != lastMonitorAreas[c].right ||
265             monitorAreas[c].bottom != lastMonitorAreas[c].bottom)
266          {
267             break;
268          }
269       }
270
271       memcpy(lastMonitorAreas, monitorAreas, sizeof(monitorAreas));
272
273       guiApp.virtualScreen =
274       {
275          GetSystemMetrics(SM_CXVIRTUALSCREEN),
276          GetSystemMetrics(SM_CYVIRTUALSCREEN)
277       };
278       guiApp.virtualScreenPos =
279       {
280          x = GetSystemMetrics(SM_XVIRTUALSCREEN),
281          y = GetSystemMetrics(SM_YVIRTUALSCREEN)
282       };
283
284       {
285          HMONITOR monitor = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY);
286          if(monitor)
287          {
288             MONITORINFO info = { 0 };
289             info.cbSize = sizeof(MONITORINFO);
290             primaryMonitor = monitor;
291             GetMonitorInfo(monitor, &info);
292             x = info.rcMonitor.left;
293             y = info.rcMonitor.top;
294             w = info.rcMonitor.right - info.rcWork.left;
295             h = info.rcMonitor.bottom - info.rcWork.top;
296          }
297       }
298
299      {
300          WINDOWPLACEMENT placement = { 0 };
301          placement.length = sizeof(WINDOWPLACEMENT);
302
303          if(!GetWindowPlacement(startBar, &placement))
304          {
305             startBar = FindWindowA("Shell_TrayWnd", null);
306             GetWindowPlacement(startBar, &placement);
307          }
308          {
309             HMONITOR taskBarMonitor = MonitorFromWindow(startBar, MONITOR_DEFAULTTONEAREST);
310             if(primaryMonitor == taskBarMonitor)
311             {
312                if(placement.rcNormalPosition.top <= 0 && placement.rcNormalPosition.bottom >= h - 1)
313                {
314                   if(placement.rcNormalPosition.left <= 0)
315                   {
316                      x = (taskBarState & ABS_AUTOHIDE) ? 1 : placement.rcNormalPosition.right;
317                      w -= x;
318                   }
319                   else
320                      w = (taskBarState & ABS_AUTOHIDE) ? (w - 1) : Min(placement.rcNormalPosition.left, w);
321                }
322                else if(placement.rcNormalPosition.left <= 0 && placement.rcNormalPosition.right >= w - 1)
323                {
324                   if(placement.rcNormalPosition.top <= 0)
325                   {
326                      y = (taskBarState & ABS_AUTOHIDE) ? 1 : placement.rcNormalPosition.bottom;
327                      h -= y;
328                   }
329                   else
330                      h = (taskBarState & ABS_AUTOHIDE) ? (h - 1) : Min(placement.rcNormalPosition.top, h);
331                }
332             }
333          }
334
335         if(c < monitor ||
336          placement.rcNormalPosition.left != taskBarPlacement.rcNormalPosition.left ||
337          placement.rcNormalPosition.top != taskBarPlacement.rcNormalPosition.top ||
338          placement.rcNormalPosition.right != taskBarPlacement.rcNormalPosition.right ||
339          placement.rcNormalPosition.bottom != taskBarPlacement.rcNormalPosition.bottom  ||
340          newTaskBarState != taskBarState)
341          {
342             taskBarState = newTaskBarState;
343             guiApp.desktop.size.w = 0;
344             desktopX = x;
345             desktopY = y;
346             desktopW = w;
347             desktopH = h;
348             taskBarPlacement = placement;
349             guiApp.SetDesktopPosition(x, y, w, h, updateChildren);
350          }
351
352          //lastScreen = guiApp.virtualScreen;
353          //lastScreenPos = guiApp.virtualScreenPos;
354       }
355    }
356
357    /****************************************************************************
358       /// PRIVATE UTILITY FUNCTIONS /////////////
359    ****************************************************************************/
360    // --- Keyboard Input ---
361    bool ::ProcessKeyMessage(Window window, DWORD msg, WPARAM wParam, LPARAM lParam, unichar ch)
362    {
363       bool result = true;
364       Key code = 0;
365       Key key;
366       // UNICODE FIX
367       bool frenchShift = (ch < 0x10000) ? (((VkKeyScan((uint16)ch) >> 8) & 6) == 6) : false;
368
369       if(msg == WM_CHAR || msg == WM_DEADCHAR)
370       {
371          wParam = 0;
372          lParam = 0;
373       }
374       if(msg == WM_MOUSEWHEEL)
375          code = (((short) HIWORD(wParam)) < 0) ? wheelDown : wheelUp;
376       else
377       {
378          key = (byte)((lParam & 0xFF0000)>>16);
379          if(lParam & 0x1000000)
380          {
381             key = Interface::GetExtendedKey(key);
382             if(!key)
383             {
384                if(wParam == 0xb3)
385                   key = KeyCode::play;
386             }
387          }
388          code = key;
389       }
390
391       if(msg == WM_MOUSEWHEEL)
392       {
393          if(::GetAsyncKeyState(VK_SHIFT) & 0x80000)
394             code.shift = true;
395          if(::GetAsyncKeyState(VK_CONTROL) & 0x80000)
396             code.ctrl = true;
397          if(::GetAsyncKeyState(VK_MENU) & 0x80000)
398             code.alt = true;
399
400          result = window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, code, 0);
401       }
402       else
403       {
404          if(key != leftShift && key != rightShift && ::GetKeyState(VK_SHIFT) & 0x80000)
405             code.shift = true;
406          if(key != leftControl && key != rightControl && ::GetKeyState(VK_CONTROL) & 0x80000 && !frenchShift)
407             code.ctrl = true;
408          if(key != leftAlt && key != rightAlt && ::GetKeyState(VK_MENU) & 0x80000 && !frenchShift)
409             code.alt = true;
410          /*
411          byte ch = Interface::TranslateKeykey, code.shift);
412          if(::GetKeyState(VK_CAPITAL))
413             ch = toupper(ch);
414          */
415
416          if(msg == WM_KEYUP || msg == WM_SYSKEYUP)
417          {
418             result = window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, code, ch);
419          }
420          else
421          {
422             if(!(lParam & 0x40000000))
423             {
424                /*
425                {
426                   char string[256];
427                   Class * keyClass = eSystem_FindClass(__ecereModule, "Key");
428                   code.OnGetString(string, null, null);
429                   eSystem_Logf("%s\n", string);
430                }
431                */
432
433                result = window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, code, ch);
434             }
435             else if(key<128)
436                result = window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, code,ch);
437          }
438       }
439
440       return result;
441    }
442
443    // --- Window procedure ---
444    DWORD CALLBACK ::ApplicationWindow(HWND windowHandle, UINT msg, WPARAM wParam, LPARAM lParam)
445    {
446 #ifdef _WIN64
447       Window window = (Window)GetWindowLongPtr(windowHandle, GWLP_USERDATA);
448 #else
449       Window window = (Window)GetWindowLong(windowHandle, GWL_USERDATA);
450 #endif
451       static Point lastPos;
452       if(window)
453       {
454          int x = 0,y = 0;
455          unichar ch = 0;
456          switch(msg)
457          {
458             case WM_QUERYNEWPALETTE:
459             case WM_PALETTECHANGED:
460                if(window.display)
461                   window.display.RestorePalette();
462                UpdateWindow(windowHandle);
463                break;
464             case WM_NCACTIVATE:
465             {
466                if(!fullScreenMode && !guiApp.IsModeSwitching())
467                {
468                   if(wParam)
469                   {
470                      Window modalRoot = window.FindModal();
471
472                      HWND modalWindow = modalRoot ? modalRoot.windowHandle : null;
473
474                      FLASHWINFO flashInfo = { 0 };
475                      flashInfo.cbSize = sizeof(FLASHWINFO);
476                      flashInfo.hwnd = window.windowHandle;
477                      flashInfo.uCount = 0;
478                      flashInfo.dwFlags = FLASHW_STOP;
479                      FlashWindowEx((void *)&flashInfo);
480
481                      if(modalWindow && modalWindow != windowHandle)
482                         modalRoot.ExternalActivate(true, true, window, null);
483                      else
484                         window.ExternalActivate(true, true, window, null);
485                   }
486                   else
487                   {
488                      HWND foreground;
489                      DWORD id;
490                      void * windowLong;
491                      foreground = GetForegroundWindow();
492                      if(foreground == windowHandle && lParam)
493                         foreground = (HWND)lParam;
494
495                      GetWindowThreadProcessId(foreground, &id);
496
497 #ifdef _WIN64
498                      windowLong = (void*)GetWindowLongPtr(foreground, GWLP_WNDPROC);
499 #else
500                      windowLong = (void*)GetWindowLong(foreground, GWL_WNDPROC);
501 #endif
502 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
503                      // The != ApplicationWindow check is for not recognizing the Console window as an Ecere Window
504                      // That check causes a problem with the OpenGL driver which seems to popup a window of a different class
505                      if(window.displaySystem && window.displaySystem.driver == class(OpenGLDisplayDriver))
506                         windowLong = (void *)ApplicationWindow;
507 #endif
508                      if(id != GetCurrentProcessId() || windowLong != (void *)ApplicationWindow)
509                         window.ExternalActivate(false, true, window, null);
510                      // DefWindowProc for WM_NCACTIVATE draws the decorations, make sure it's drawn in the right state
511                      return (uint)DefWindowProc(windowHandle, msg, window.active, lParam);
512                   }
513                }
514                if(activateApp)
515                {
516                   for(window = guiApp.desktop.firstChild; window; window = window.next)
517                      SetWindowPos(window.windowHandle, window.style.stayOnTop ? HWND_TOPMOST : HWND_TOP, 0,0,0,0,
518                         SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOSIZE); //|SWP_NOREDRAW);
519                   activateApp = false;
520                }
521
522                return (uint)DefWindowProc(windowHandle, msg, window ? window.active : wParam, lParam);
523             }
524             case WM_ACTIVATEAPP:
525                if(!guiApp.IsModeSwitching())
526                {
527                   if(fullScreenMode)
528                   {
529                      HDC hdc = GetDC(windowHandle);
530                      if(wParam != TRUE)
531                      {
532                         guiApp.SetAppFocus(false);
533                         ShowWindow(windowHandle, SW_MINIMIZE);
534                         ChangeDisplaySettings(null,0);
535                         SetSystemPaletteUse(hdc, SYSPAL_STATIC);
536                      }
537                      else
538                      {
539                         ChangeDisplaySettings(&devMode, CDS_FULLSCREEN);
540                         SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
541                         if(window.display)
542                            window.display.RestorePalette();
543                         ShowWindow(windowHandle, SW_SHOWNORMAL);
544                         guiApp.SetAppFocus(true);
545                         if(window.display)
546                            window.display.Resize(window.clientSize.w, window.clientSize.h);
547                         window.Update(null);
548                      }
549                      ReleaseDC(windowHandle, hdc);
550                   }
551                   else
552                   {
553                      //Window window;
554
555                      if(wParam && !guiApp.desktop.active /*&& lParam != GetCurrentThreadID()*/)
556                      {
557                         activateApp = true;
558                         /*
559                         for(window = guiApp.desktop.firstChild; window; window = window.next)
560                            SetWindowPos(window.windowHandle, window.style.stayOnTop ? HWND_TOPMOST : HWND_TOP, 0,0,0,0,
561                               SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOSIZE); //|SWP_NOREDRAW);
562                         */
563                      }
564                      guiApp.SetAppFocus((bool)wParam);
565                   }
566                }
567                else
568                   guiApp.SetAppFocus((bool)wParam);
569                break;
570             case WM_PAINT:
571             {
572                if(!window.alphaBlend || window.display.pixelFormat != pixelFormat888)
573                {
574                   PAINTSTRUCT ps;
575
576 /*
577 #define ACCESS_ITEM(l, id) \
578       ((FastItem)(((id) == -1) ? null : (((byte *)((l).items)) + (id) * (l).itemSize)))
579 */
580
581 #define ACCESS_ITEM(l, id) \
582    id
583
584                   BoxItem item = window.dirtyArea.count ? (BoxItem)ACCESS_ITEM(window.dirtyArea, window.dirtyArea.first) : null;
585
586                   BeginPaint(windowHandle, &ps);
587
588                   // Prevent flickering if we're going to update anyways
589                   /*
590                   printf("   Paint message (%d, %d)-(%d, %d)\n",
591                      item ? item.box.left : 0,
592                      item ? item.box.top : 0,
593                      item ? item.box.right : 0,
594                      item ? item.box.bottom : 0);
595                   */
596                   // Causes redraw bug...
597                   if(!window.manageDisplay || !item ||
598                      item.box.left > 0 ||
599                      item.box.top > 0 ||
600                      item.box.right < window.size.w - 1 ||
601                      item.box.bottom < window.size.h - 1)
602                   {
603                      Box box { ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right-1, ps.rcPaint.bottom-1 };
604                      window.UpdateDirty(box);
605                   }
606                      // TODO: Fix precompiler with
607                      // window.UpdateDirty((Box *)&ps.rcPaint);
608                   EndPaint(windowHandle, &ps);
609                }
610                break;
611             }
612             case WM_DISPLAYCHANGE:
613             {
614                static int lastBits = 0;
615                static int lastRes = 0;
616                if(lastBits != wParam || lastRes != lParam)
617                {
618                   lastBits = (int)wParam;
619                   lastRes = (int)lParam;
620
621                   externalDisplayChange = true;
622                   if(guiApp.desktop.DisplayModeChanged())
623                   {
624                      char caption[2048];
625                      if(!window.style.hidden)
626                         ShowWindow(windowHandle, SW_SHOWNOACTIVATE /*SW_SHOWNORMAL*/);
627                      window.FigureCaption(caption);
628                      SetRootWindowCaption(window, caption);
629                   }
630                   externalDisplayChange = false;
631                }
632                break;
633             }
634             // Keyboard Messages
635             case WM_SYSKEYDOWN:
636             case WM_KEYDOWN:
637             case WM_SYSKEYUP:
638             case WM_KEYUP:
639             case WM_CHAR:
640             //case WM_DEADCHAR:
641             {
642                MSG charMsg;
643                DWORD min = 0, max = 0;
644
645                if(msg != WM_CHAR && window.composing)
646                   break;
647
648                switch(msg)
649                {
650                   case WM_SYSKEYDOWN: min = max = WM_SYSCHAR; break;
651                   case WM_KEYDOWN: min = max = WM_CHAR; break;
652                   case WM_SYSKEYUP: min = WM_SYSCHAR; max = WM_SYSDEADCHAR; break;
653                   case WM_KEYUP: min = WM_CHAR; max = WM_DEADCHAR; break;
654                }
655
656                // This is very annoying.
657                // PeekMessage somehow invokes this function directly... don't know why.
658                // Only crashes when running through debug mode in visual studio
659                incref window;
660                if(msg == WM_CHAR || msg == WM_DEADCHAR || PeekMessage(&charMsg, windowHandle, min, max, PM_REMOVE))
661                {
662                   ch = (msg == WM_CHAR || msg == WM_DEADCHAR) ? (unichar)wParam : (unichar)charMsg.wParam;
663                   // TOCHECK: What is this for again? Fixing some obscure activation status?
664                   // -- I believe this was somehow allowing 'unmaximizing', but was causing problems
665                   // as there was no way to prevent AltEnter from doing so (e.g. when it is used for a node property)
666                   // Worked around by fixing ProcessHotKeys to properly check for sysButtons in parent.parent when sys buttons
667                   // are placed inside a menu bar for a document
668                   /*
669                   if(msg == WM_SYSKEYDOWN && ch == 13)
670                   {
671                      ShowWindow(window.windowHandle, window.state == maximized ? SW_MAXIMIZE : SW_SHOWNORMAL);
672                      // This last line been commented out for a long time:
673                      // window.ExternalActivate(true, true, window, null);
674                   }
675                   */
676                   if(msg == WM_SYSKEYUP || msg == WM_KEYUP)
677                   {
678                      if(!ProcessKeyMessage(window, WM_KEYDOWN, 0x40000000, 0, ch))
679                         break;
680                   }
681                }
682             }
683             case WM_MOUSEWHEEL:
684                ProcessKeyMessage(window, msg, wParam, lParam, ch);
685                if(window.composing && msg == WM_CHAR)
686                {
687                   COMPOSITIONFORM form;
688                   Window caretOwner = guiApp.caretOwner;
689                   if(caretOwner)
690                   {
691                      HIMC ctx = ImmGetContext(windowHandle);
692                      form.dwStyle = CFS_POINT;
693                      form.ptCurrentPos.x = caretOwner.caretPos.x - caretOwner.scroll.x + caretOwner.absPosition.x - window.absPosition.x + 4;
694                      form.ptCurrentPos.y = caretOwner.caretPos.y - caretOwner.scroll.x + caretOwner.absPosition.y - window.absPosition.y + 2;
695                      window.composing = true;
696                      ImmSetCompositionWindow(ctx, &form);
697                      ImmReleaseContext(windowHandle, ctx);
698                   }
699                }
700                if(msg != WM_MOUSEWHEEL)
701                   delete window;
702                break;
703
704             case WM_IME_STARTCOMPOSITION:
705             {
706                COMPOSITIONFORM form;
707                Window caretOwner = guiApp.caretOwner;
708                if(caretOwner)
709                {
710                   HIMC ctx = ImmGetContext(windowHandle);
711                   form.dwStyle = CFS_POINT;
712                   form.ptCurrentPos.x = caretOwner.caretPos.x - caretOwner.scroll.x + caretOwner.absPosition.x - window.absPosition.x + 4;
713                   form.ptCurrentPos.y = caretOwner.caretPos.y - caretOwner.scroll.y + caretOwner.absPosition.y - window.absPosition.y + 2;
714                   /*
715                   form.rcArea.left = window.caretPos.x;
716                   form.rcArea.top = 250;
717                   form.rcArea.right = 500;
718                   form.rcArea.bottom = 300;
719                   */
720                   window.composing = true;
721                   DefWindowProc(windowHandle, msg, wParam, lParam);
722                   ImmSetCompositionWindow(ctx, &form);
723                   ImmSetStatusWindowPos(ctx, &form.ptCurrentPos);
724                   {
725                      FontResource res = caretOwner.font;
726                      LOGFONT font = { 0 };
727                      HDC hdc = GetDC(0);
728                      int pixels = GetDeviceCaps(hdc, LOGPIXELSY);
729                      ReleaseDC(0, hdc);
730                      font.lfHeight = -(int)((float)res.size * pixels / 72 + 0.5);
731                      font.lfWeight = res.flags.bold ? FW_BOLD : FW_NORMAL;
732                      font.lfItalic = res.flags.italic ? TRUE : FALSE,
733                      font.lfUnderline = res.flags.underline ? TRUE : FALSE;
734                      font.lfCharSet = DEFAULT_CHARSET;
735                      font.lfOutPrecision = OUT_DEFAULT_PRECIS;
736                      font.lfClipPrecision = CLIP_DEFAULT_PRECIS;
737                      font.lfQuality = DEFAULT_QUALITY;
738                      font.lfPitchAndFamily = (byte)(DEFAULT_PITCH|FF_DONTCARE); // TODO: Fix compiler 0 | 0 to produce byte, not int
739                      UTF8toUTF16Buffer(res.faceName, font.lfFaceName, LF_FACESIZE);
740
741                      ImmSetCompositionFont(ctx, &font);
742                      ImmReleaseContext(windowHandle, ctx);
743                   }
744                   return 1;
745                }
746                break;
747             }
748             case WM_IME_ENDCOMPOSITION:
749                window.composing = false;
750                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
751             /*case WM_IME_COMPOSITION:
752                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
753             case WM_IME_REQUEST:
754                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
755             case WM_IME_NOTIFY:
756                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
757             case WM_IME_KEYDOWN:
758                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
759             case WM_IME_KEYUP:
760                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
761             case WM_IME_SELECT:
762                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
763             case WM_IME_SETCONTEXT:
764                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
765             case WM_IME_CONTROL:
766                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
767             case WM_IME_CHAR:
768                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
769             case WM_IME_COMPOSITIONFULL:
770                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
771             */
772             case WM_NCHITTEST:
773                if(window.nativeDecorations)
774                   return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
775                else
776                // return HTCAPTION;
777                   return HTCLIENT;
778
779             // Mouse Messages
780             case WM_LBUTTONUP:
781             case WM_RBUTTONUP:
782             case WM_MBUTTONUP:
783             case WM_LBUTTONDOWN:
784             case WM_LBUTTONDBLCLK:
785             case WM_RBUTTONDOWN:
786             case WM_RBUTTONDBLCLK:
787             case WM_MBUTTONDOWN:
788             case WM_MBUTTONDBLCLK:
789             case WM_MOUSEMOVE:
790                x = window.absPosition.x;
791                y = window.absPosition.y;
792             /*case WM_NCLBUTTONUP:
793             case WM_NCRBUTTONUP:
794             case WM_NCMBUTTONUP:
795             case WM_NCLBUTTONDOWN:
796             case WM_NCLBUTTONDBLCLK:
797             case WM_NCRBUTTONDOWN:
798             case WM_NCRBUTTONDBLCLK:
799             case WM_NCMBUTTONDOWN:
800             case WM_NCMBUTTONDBLCLK:*/
801             case WM_NCMOUSEMOVE:
802             {
803                Modifiers code = 0;
804                bool consequential = false;
805
806                x += (short)LOWORD(lParam);
807                y += (short)HIWORD(lParam);
808
809                if(window.nativeDecorations && msg != WM_NCMOUSEMOVE)
810                {
811                   x += window.clientStart.x;
812                   y += window.clientStart.y - (window.hasMenuBar ? skinMenuHeight : 0);
813                }
814
815                if(::GetKeyState(VK_SHIFT) & 0x80000)   code.shift = true;
816                if(::GetKeyState(VK_CONTROL) & 0x80000) code.ctrl = true;
817                if(::GetKeyState(VK_MENU) & 0x80000)    code.alt = true;
818                if(wParam & MK_LBUTTON) code.left = true;
819                if(wParam & MK_MBUTTON) code.middle = true;
820                if(wParam & MK_RBUTTON) code.right = true;
821
822                if(msg == WM_MOUSEMOVE)
823                {
824                   if(lastPos.x == x && lastPos.y == y)
825                      consequential = true;
826                   lastPos.x = x;
827                   lastPos.y = y;
828                }
829
830                incref window;
831                switch(msg)
832                {
833                   case WM_NCMOUSEMOVE:
834                   case WM_MOUSEMOVE:
835                      window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x,y,&code, consequential, false);
836                      break;
837                   //case WM_NCLBUTTONDBLCLK:
838                   case WM_LBUTTONDBLCLK:
839                      if(!window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick, x,y,&code, false, true))
840                         break;
841                   //case WM_NCLBUTTONDOWN:
842                   case WM_LBUTTONDOWN:
843                      window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown,x,y,&code, false,
844                                              /*(msg == WM_LBUTTONDBLCLK) ? false: */true);
845                      break;
846                   //case WM_NCLBUTTONUP:
847                   case WM_LBUTTONUP:      window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp, x,y,&code, false, false);break;
848                   //case WM_NCMBUTTONDBLCLK:
849                   case WM_MBUTTONDBLCLK:
850                      if(!window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick, x,y,&code, false, false))
851                         break;
852                   //case WM_NCMBUTTONDOWN:
853                   case WM_MBUTTONDOWN:
854                      window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown, x,y,&code, false,
855                                              (msg == WM_LBUTTONDBLCLK) ? false: true);
856                      break;
857                   //case WM_NCMBUTTONUP:
858                   case WM_MBUTTONUP:
859                      window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp, x,y,&code, false, false);
860                      break;
861                   //case WM_NCRBUTTONDBLCLK:
862                   case WM_RBUTTONDBLCLK:
863                      if(!window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick, x,y,&code, false, true))
864                         break;
865                   //case WM_NCRBUTTONDOWN:
866                   case WM_RBUTTONDOWN:
867                      window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown, x,y,&code, false,
868                                              (msg == WM_LBUTTONDBLCLK) ? false: true);
869                      break;
870                   //case WM_NCRBUTTONUP:
871                   case WM_RBUTTONUP:
872                      window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp, x,y,&code, false, false);
873                      break;
874                }
875                delete window;
876                if(msg == WM_NCMOUSEMOVE)
877                   return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
878                break;
879             }
880             case WM_SETCURSOR:
881             {
882                if(window.nativeDecorations)
883                {
884                   if(DefWindowProc(windowHandle, msg, wParam, lParam))
885                      return 1;
886                }
887                // SetCursor(systemCursors[0]);
888                SetCursor((lastCursor == (SystemCursor)-1) ? null : systemCursors[lastCursor]);
889                return 0;
890             }
891             case WM_EXITMENULOOP:
892             case WM_EXITSIZEMOVE:
893                // We had some DirectInput stuff in here
894                break;
895             case WM_ENTERMENULOOP:
896             case WM_ENTERSIZEMOVE:
897                // We had some DirectInput stuff in here
898                break;
899             case WM_CLOSE:
900             {
901                window.Destroy(0);
902                return 0;
903             }
904             case WM_MOVE:
905             {
906                int x, y, w, h;
907                WINDOWPLACEMENT placement = { 0 };
908                RECT rcWindow;
909                placement.length = sizeof(WINDOWPLACEMENT);
910                GetWindowRect(windowHandle, &rcWindow);
911                GetWindowPlacement(windowHandle, &placement);
912
913                x = rcWindow.left - desktopX;
914                y = rcWindow.top  - desktopY;
915                w = rcWindow.right - rcWindow.left;
916                h = rcWindow.bottom - rcWindow.top;
917
918                AeroSnapPosition(window, x, y, w, h);
919                break;
920             }
921             /*case WM_MOVING:
922                break;*/
923             case WM_SIZING:
924             {
925                RECT * rect = (RECT *)lParam;
926                MinMaxValue ew, eh;
927                int w, h;
928
929                window.GetDecorationsSize(&ew, &eh);
930
931                w = rect->right - rect->left;
932                h = rect->bottom - rect->top;
933
934                w -= ew;
935                h -= eh;
936
937                w = Max(w, 1);
938                h = Max(h, 1);
939
940                w = Max(w, window.minSize.w);
941                h = Max(h, window.minSize.h);
942                w = Min(w, window.maxSize.w);
943                h = Min(h, window.maxSize.h);
944
945                if(!window.OnResizing(&w, &h))
946                {
947                   w = window.clientSize.w;
948                   h = window.clientSize.h;
949                }
950
951                w = Max(w, window.skinMinSize.w);
952                h = Max(h, window.skinMinSize.h);
953
954                w += ew;
955                h += eh;
956
957                if(wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT)
958                   rect->left = rect->right - w;
959                else
960                   rect->right = rect->left + w;
961
962                if(wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOP || wParam == WMSZ_TOPRIGHT)
963                   rect->top = rect->bottom - h;
964                else
965                   rect->bottom = rect->top + h;
966
967                return 1;
968             }
969             case WM_SIZE:
970             {
971                if(window.nativeDecorations)
972                {
973                   int x, y, w, h;
974                   RECT rcWindow;
975                   GetWindowRect(windowHandle, &rcWindow);
976
977                   if(wParam == SIZE_MAXIMIZED && window.state != maximized)
978                      window.state = maximized;
979                   else if(wParam == SIZE_MINIMIZED && window.state != minimized)
980                      window.state = minimized;
981                   else if(wParam == SIZE_RESTORED && window.state != normal && window.visible)
982                      window.state = normal;
983
984                   x = rcWindow.left - desktopX;
985                   y = rcWindow.top  - desktopY;
986                   w = rcWindow.right - rcWindow.left;
987                   h = rcWindow.bottom - rcWindow.top;
988
989                   AeroSnapPosition(window, x, y, w, h);
990                   if(!guiApp.modeSwitching)
991                      window.UpdateVisual(null);
992                }
993                else
994                   return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
995                break;
996             }
997             default:
998                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
999          }
1000       }
1001       else
1002          return (uint)DefMDIChildProc(windowHandle, msg, wParam, lParam);
1003          // return DefWindowProc(windowHandle, msg, wParam, lParam);
1004       return 0;
1005    }
1006
1007    // --- DirectInput ---
1008
1009    #ifndef ECERE_NODINPUT
1010
1011    #ifndef ECERE_NOJOYSTICK
1012    bool CALLBACK ::JoystickCallback( const DIDEVICEINSTANCE* pdidInstance, void * context )
1013    {
1014       if(!dInput->lpVtbl->CreateDevice(dInput, &GUID_Joystick,
1015          (IDirectInputDevice **)&directJoysticks[numJoysticks], null ))
1016          numJoysticks++;
1017       return DIENUM_CONTINUE;
1018    }
1019
1020    bool CALLBACK ::JoystickAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, void * context )
1021    {
1022       DIPROPRANGE diprg;
1023       IDirectInputDevice2 * curJoy = (IDirectInputDevice2 *)context;
1024
1025       diprg.diph.dwSize       = sizeof(DIPROPRANGE);
1026       diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1027       diprg.diph.dwHow        = DIPH_BYOFFSET;
1028       diprg.diph.dwObj        = pdidoi->dwOfs;
1029       diprg.lMin              = -128;
1030       diprg.lMax              = 127;
1031       if(curJoy->lpVtbl->SetProperty(curJoy, DIPROP_RANGE, &diprg.diph))
1032          return DIENUM_STOP;
1033       return DIENUM_CONTINUE;
1034    }
1035    #endif
1036
1037    void ::TerminateDirectInput()
1038    {
1039       int j;
1040       if (directMouse)
1041       {
1042          directMouse->lpVtbl->Unacquire(directMouse);
1043          directMouse->lpVtbl->Release(directMouse);
1044          directMouse = null;
1045       }
1046    #ifndef ECERE_NOJOYSTICK
1047       for(j=0; j<numJoysticks; j++)
1048       {
1049          if (directJoysticks[j])
1050          {
1051             directJoysticks[j]->lpVtbl->Unacquire(directJoysticks[j]);
1052             directJoysticks[j]->lpVtbl->Release(directJoysticks[j]);
1053             directJoysticks[j] = null;
1054          }
1055       }
1056       numJoysticks = 0;
1057    #endif
1058       if(dInput)
1059       {
1060          dInput->lpVtbl->Release(dInput);
1061          dInput = null;
1062       }
1063
1064       directInputCreate = null;
1065
1066       if(dInputDll)
1067       {
1068          FreeLibrary(dInputDll);
1069          dInputDll = null;
1070       }
1071    }
1072
1073    bool ::InitDirectInput()
1074    {
1075       bool result = false;
1076
1077       dInputDll = LoadLibraryA("dinput.dll");
1078       if(dInputDll)
1079       {
1080          if((directInputCreate = (void *)GetProcAddress(dInputDll, "DirectInputCreateA")))
1081          {
1082             if(!directInputCreate( hInstance, DIRECTINPUT_VERSION, &dInput, null ))
1083             {
1084                int j;
1085
1086                // Mouse
1087                if(!dInput->lpVtbl->CreateDevice(dInput, &GUID_SysMouse, &directMouse, null ))
1088                   directMouse->lpVtbl->SetDataFormat(directMouse, &c_dfDIMouse );
1089
1090    #ifndef ECERE_NOJOYSTICK
1091                // Joystick
1092                dInput->lpVtbl->EnumDevices(dInput, DIDEVTYPE_JOYSTICK, JoystickCallback, null, DIEDFL_ATTACHEDONLY );
1093                for(j=0; j<NUMJOY; j++)
1094                   if(directJoysticks[j])
1095                      if(!directJoysticks[j]->lpVtbl->SetDataFormat(directJoysticks[j], &c_dfDIJoystick ))
1096                         directJoysticks[j]->lpVtbl->EnumObjects(directJoysticks[j], JoystickAxesCallback, directJoysticks[j], DIDFT_AXIS );
1097    #endif
1098                result = true;
1099             }
1100          }
1101       }
1102       return result;
1103    }
1104
1105    void ::AcquireDirectInput(HWND windowHandle, bool state)
1106    {
1107       if((state && !acquiredWindow) || (!state && acquiredWindow == windowHandle))
1108       {
1109          int j;
1110          if(directMouse)
1111          {
1112             if(state)
1113             {
1114                directMouse->lpVtbl->SetCooperativeLevel(directMouse, /*fullScreenMode ? */windowHandle /*: HWND_DESKTOP*/, DISCL_EXCLUSIVE|DISCL_FOREGROUND);
1115                directMouse->lpVtbl->Acquire(directMouse);
1116             }
1117             else
1118                directMouse->lpVtbl->Unacquire(directMouse);
1119          }
1120    #ifndef ECERE_NOJOYSTICK
1121          for(j = 0; j<NUMJOY; j++)
1122             if(directJoysticks[j])
1123             {
1124                if(state)
1125                {
1126                   directJoysticks[j]->lpVtbl->SetCooperativeLevel(directJoysticks[j], /*fullScreenMode ? */windowHandle /*: HWND_DESKTOP*/, DISCL_EXCLUSIVE|DISCL_FOREGROUND);
1127                   directJoysticks[j]->lpVtbl->Acquire(directJoysticks[j]);
1128                }
1129                else
1130                   directJoysticks[j]->lpVtbl->Unacquire(directJoysticks[j]);
1131             }
1132    #endif
1133          acquiredWindow = state ? windowHandle : null;
1134       }
1135    }
1136    #endif
1137
1138    /****************************************************************************
1139       /// INTEGRATION FUNCTIONALITY /////////////
1140    ****************************************************************************/
1141    bool eisWIN32ProcessKey(Window window, DWORD msg, DWORD wParam, DWORD lParam, byte ch)
1142    {
1143       return ProcessKeyMessage(window, msg, wParam, lParam, ch);
1144    }
1145
1146    HWND eisWIN32GetWindowHandle(Window window)
1147    {
1148       return window.windowHandle ? window.windowHandle : window.rootWindow.windowHandle;
1149    }
1150
1151    /****************************************************************************
1152       /// DRIVER IMPLEMENTATION /////////////
1153    ****************************************************************************/
1154
1155 #ifdef _WIN64
1156    void CALLBACK ::TimerProc(UINT uTimerID, UINT uMsg, uint64 dwUser, uint64 dw1, uint64 dw2)
1157 #else
1158    void CALLBACK ::TimerProc(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
1159 #endif
1160    {
1161       guiApp.SignalEvent();
1162    }
1163
1164    // --- User Interface System ---
1165    bool Initialize()
1166    {
1167       WNDCLASS wcl =
1168       {
1169          CS_DBLCLKS, ApplicationWindow, 0L, 0L, 0,
1170          LoadIcon(null, IDI_APPLICATION),
1171          null,
1172          null,
1173          null,
1174          className
1175       };
1176       AttachConsole(-1);
1177       wcl.hInstance = hInstance = GetModuleHandle(null);
1178       RegisterClass(&wcl);
1179
1180       // Move that in reposition desktop
1181       startBar = FindWindowA("Shell_TrayWnd", null);
1182
1183       systemCursors[arrow] = LoadCursor(null, IDC_ARROW);
1184       systemCursors[iBeam] = LoadCursor(null, IDC_IBEAM);
1185       systemCursors[cross] = LoadCursor(null, IDC_CROSS);
1186       systemCursors[moving] = LoadCursor(null, IDC_SIZEALL);
1187       systemCursors[sizeNESW] = LoadCursor(null, IDC_SIZENESW);
1188       systemCursors[sizeNS  ] = LoadCursor(null, IDC_SIZENS);
1189       systemCursors[sizeNWSE] = LoadCursor(null, IDC_SIZENWSE);
1190       systemCursors[sizeWE  ] = LoadCursor(null, IDC_SIZEWE);
1191       systemCursors[hand    ] = LoadCursor(null, IDC_HAND);
1192
1193       SetTimer(null, 0, (DWORD)(1000.0 / 18.2), null);
1194       //SetTimer(null, 0, 1, null);
1195       /*
1196       timeBeginPeriod(1);
1197
1198       hiResTimer = timeSetEvent(
1199          1000.0 / 250.0,
1200          1000.0 / 250.0,
1201          TimerProc,0,TIME_PERIODIC);
1202       */
1203       /*
1204       hiResTimer = timeSetEvent(
1205          1000.0 / 500.0,
1206          1000.0 / 500.0,
1207          TimerProc,0,TIME_PERIODIC);
1208          */
1209
1210    /*
1211       topWindow = CreateWindowEx(0, className, "",WS_POPUP,0,0,1,1,HWND_DESKTOP,
1212          null, hInstance, null);
1213    */
1214       return true;
1215    }
1216
1217    void Terminate()
1218    {
1219       if(hiResTimer) timeKillEvent(hiResTimer);
1220    #ifndef ECERE_NODINPUT
1221       TerminateDirectInput();
1222    #endif
1223    }
1224
1225    void SetTimerResolution(uint hertz)
1226    {
1227       if(hiResTimer) timeKillEvent(hiResTimer);
1228       if(hertz)
1229          hiResTimer = timeSetEvent(1000 / hertz, 1000 / hertz, TimerProc, 0, TIME_PERIODIC);
1230    }
1231
1232    bool ProcessInput(bool processAll)
1233    {
1234       MSG msg;
1235       if(!fullScreenMode)
1236          RepositionDesktop(true);
1237       if(PeekMessage(&msg,0,0,0,PM_NOREMOVE))
1238       {
1239          while(PeekMessage(&msg,0,0,0,PM_REMOVE))
1240          {
1241             TranslateMessage(&msg);
1242             DispatchMessage(&msg);
1243             // printf("%d\n", msg.message);
1244             if(!processAll || msg.message == WM_TIMER) break;
1245          }
1246          return true;
1247       }
1248       return false;
1249    }
1250
1251    void Wait()
1252    {
1253       MsgWaitForMultipleObjects(1, (void **)guiApp.semaphore, FALSE, (uint)(1000 / 18.2) /*INFINITE*/, QS_ALLINPUT);
1254    }
1255
1256    void Lock(Window window)
1257    {
1258
1259    }
1260
1261    void Unlock(Window window)
1262    {
1263
1264    }
1265
1266    const char ** GraphicsDrivers(int * numDrivers)
1267    {
1268       static const char *graphicsDrivers[] = { "GDI", "DirectDraw", "OpenGL", "Direct3D", "Direct3D8", "Direct3D9" };
1269       *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
1270       return (const char **)graphicsDrivers;
1271    }
1272
1273    void GetCurrentMode(bool * fullScreen, Resolution * resolution, PixelFormat * colorDepth, int * refreshRate)
1274    {
1275       *fullScreen = fullScreenMode;
1276       if(fullScreenMode)
1277       {
1278          Resolution c;
1279          for(c = 0; c<Resolution::enumSize; c++)
1280             if(GetResolutionWidth(c) == devMode.dmPelsWidth && GetResolutionHeight(c) == devMode.dmPelsHeight)
1281             {
1282                *resolution = c;
1283                break;
1284             }
1285          switch(devMode.dmBitsPerPel)
1286          {
1287             case 8: *colorDepth = pixelFormat8; break;
1288             case 16: *colorDepth = pixelFormat555; break;
1289             default: *colorDepth = pixelFormat888; break;
1290          }
1291          * refreshRate = devMode.dmDisplayFrequency;
1292       }
1293    }
1294
1295    void EnsureFullScreen(bool *fullScreen)
1296    {
1297
1298    }
1299
1300    bool ScreenMode(bool fullScreen, Resolution resolution, PixelFormat colorDepth, int refreshRate, bool * textMode)
1301    {
1302       bool result = true;
1303       HDC hdc = GetDC(0);
1304
1305       fullScreenMode = fullScreen;
1306
1307       if(fullScreen)
1308       {
1309          FillBytes(&devMode, 0, sizeof(DEVMODE));
1310            devMode.dmSize = (uint16)sizeof(devMode);
1311          devMode.dmFields |=DM_BITSPERPEL;
1312          devMode.dmFields |=DM_PELSWIDTH|DM_PELSHEIGHT;
1313          devMode.dmFields |= DM_DISPLAYFREQUENCY;
1314          devMode.dmBitsPerPel = colorDepth ? GetDepthBits(colorDepth) : GetDeviceCaps(hdc, BITSPIXEL);
1315          devMode.dmPelsWidth = resolution ? GetResolutionWidth(resolution) : GetSystemMetrics(SM_CXSCREEN);
1316          devMode.dmPelsHeight = resolution ? GetResolutionHeight(resolution) : GetSystemMetrics(SM_CYSCREEN);
1317          devMode.dmDisplayFrequency = refreshRate ? refreshRate : GetDeviceCaps(hdc, VREFRESH);
1318          if(ChangeDisplaySettings(&devMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
1319             result = false;
1320          else
1321          {
1322             SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
1323             guiApp.SetDesktopPosition(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), false);
1324          }
1325       }
1326       else
1327       {
1328          static bool firstTime = true;
1329          if(!firstTime)
1330             ChangeDisplaySettings(null, 0);
1331          firstTime = false;
1332          SetSystemPaletteUse(hdc, SYSPAL_STATIC);
1333          desktopX = desktopY = desktopW = desktopH = 0;
1334
1335          RepositionDesktop(false);
1336       }
1337       ReleaseDC(0,hdc);
1338
1339       return result;
1340    }
1341
1342    // --- Window Creation ---
1343    void * CreateRootWindow(Window window)
1344    {
1345       HWND windowHandle;
1346       uint16 * text = UTF8toUTF16(window.text, null);
1347       if(fullScreenMode)
1348       {
1349          windowHandle = CreateWindowEx(0, className, text,
1350                         WS_POPUP,
1351                         0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),
1352                         HWND_DESKTOP,
1353                         null, hInstance, null);
1354          ShowWindow(windowHandle, SW_SHOWNORMAL);
1355       }
1356       else if(window.systemParent)
1357          windowHandle = CreateWindowEx(0, className, text,
1358          WS_CHILD,0,0,1,1, window.systemParent, null, hInstance, null);
1359       else
1360       {
1361          DWORD style = 0;
1362          DWORD exStyle = 0;
1363          HWND parentWindow = null; //HWND_DESKTOP; // we get different behaviors with desktop...
1364          Window master = window.master, rootWindow = (master && master != guiApp.desktop) ? master.rootWindow : null;
1365          if(window.style.stayOnTop)
1366             exStyle |= WS_EX_TOPMOST;
1367
1368          if(rootWindow && (window._isModal || window.style.interim))
1369             parentWindow = rootWindow.is3D ? rootWindow.parent.windowHandle : rootWindow.windowHandle;
1370
1371          if(window.alphaBlend)
1372          // if(window.background.a < 255) //&& window.style & ES_REDRAW) Not needed anymore?
1373             exStyle |= WS_EX_LAYERED; // | WS_EX_TRANSPARENT;
1374
1375          // Toolwindow will disappear if they don't have AppWindow set
1376          if(window.style.showInTaskBar || (!parentWindow && window.style.thin))
1377          {
1378             exStyle |= WS_EX_APPWINDOW;
1379             parentWindow = null;
1380          }
1381
1382          if(window.style.thin)
1383             exStyle |= WS_EX_TOOLWINDOW;
1384
1385          if(window.windowHandle)
1386             windowHandle = window.windowHandle;
1387          else
1388          {
1389             if(window.nativeDecorations)
1390             {
1391                BorderBits borderStyle = window.borderStyle; // FIXME!
1392                style = WS_OVERLAPPED;
1393                if(borderStyle.fixed)
1394                   style |= WS_CAPTION;
1395                if(window.hasClose)
1396                   style |= WS_SYSMENU;
1397                if(borderStyle.sizable)
1398                   style |= WS_THICKFRAME;
1399                if(window.hasMinimize)
1400                   style |= WS_MINIMIZEBOX;
1401                if(window.hasMaximize)
1402                   style |= WS_MAXIMIZEBOX;
1403             }
1404             windowHandle = CreateWindowEx(
1405                exStyle,
1406                className, text,
1407                style | (window.systemParent ? WS_CHILD :
1408                (WS_POPUP | (window.style.hasMinimize ? WS_MINIMIZEBOX : 0))),
1409                   0,0,1,1, parentWindow, null, hInstance, null);
1410    #if 0
1411             if(exStyle & WS_EX_LAYERED)
1412                SetLayeredWindowAttributes(windowHandle, 0, 255 /*A(window.background)*/, LWA_ALPHA);
1413    #endif
1414          }
1415       }
1416       delete text;
1417 #ifdef _WIN64
1418       SetWindowLongPtr(windowHandle, GWLP_USERDATA, (int64)window);
1419 #else
1420       SetWindowLong(windowHandle, GWL_USERDATA, (DWORD)window);
1421 #endif
1422
1423       return windowHandle;
1424    }
1425
1426    void DestroyRootWindow(Window window)
1427    {
1428       HICON oldIcon;
1429       int c, lockCount = guiApp.lockMutex.lockCount;
1430       for(c = 0; c < lockCount; c++)
1431          guiApp.lockMutex.Release();
1432
1433       oldIcon = (HICON)SendMessage(window.windowHandle, WM_GETICON, ICON_BIG, 0);
1434 #ifdef _WIN64
1435       if(oldIcon && oldIcon != (HICON)GetClassLongPtr(window.windowHandle, GCLP_HICON))
1436 #else
1437       if(oldIcon && oldIcon != (HICON)GetClassLong(window.windowHandle, GCL_HICON))
1438 #endif
1439          DestroyIcon(oldIcon);
1440
1441         ShowWindow(window.windowHandle, SW_HIDE);
1442
1443 #ifdef _WIN64
1444       SetWindowLongPtr(window.windowHandle, GWLP_USERDATA, (int64)null);
1445 #else
1446       SetWindowLong(window.windowHandle, GWL_USERDATA, 0);
1447 #endif
1448       DestroyWindow(window.windowHandle);
1449
1450       for(c = 0; c < lockCount; c++)
1451          guiApp.lockMutex.Wait();
1452
1453       window.windowHandle = null;
1454    }
1455
1456    // -- Window manipulation ---
1457
1458    void SetRootWindowCaption(Window window, const char * name)
1459    {
1460       uint16 * text = UTF8toUTF16(name, null);
1461       guiApp.Unlock();
1462       SetWindowText(window.windowHandle, text);
1463       guiApp.Lock();
1464       delete text;
1465    }
1466
1467    void PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize)
1468    {
1469       int flags = SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS;
1470
1471       if(!window.systemParent && !fullScreenMode)
1472       {
1473          x += desktopX;
1474          y += desktopY;
1475       }
1476
1477       if(!move) flags |= SWP_NOMOVE;
1478       if(!resize) flags |= SWP_NOSIZE;
1479
1480       /*if(move && resize)
1481       {
1482          flags |= SWP_NOMOVE;
1483          SetWindowPos(window.windowHandle, null, x, y, w, h, flags);
1484          flags &=~SWP_NOMOVE;
1485          flags |= SWP_NOSIZE;
1486       }*/
1487       if(!window.nativeDecorations || window.state != maximized || !window.visible || guiApp.modeSwitching)
1488          SetWindowPos(window.windowHandle, null, x, y, w, h, flags);
1489    }
1490
1491    void OrderRootWindow(Window window, bool topMost)
1492    {
1493       SetWindowPos(window.windowHandle, topMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0,0,0,0,
1494          SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOSIZE|SWP_NOREDRAW);
1495    }
1496
1497    void SetRootWindowColor(Window window)
1498    {
1499       if(window.alphaBlend && window.display.pixelFormat == pixelFormat888)
1500       {
1501          /*if(A(window.background) == 255)
1502          {
1503             if((style & WS_EX_LAYERED) == WS_EX_LAYERED)
1504                SetWindowLong(window.windowHandle, GWL_EXSTYLE, style &~WS_EX_LAYERED);
1505          }
1506          else*/
1507          {
1508 #ifndef ECERE_NOBLENDING
1509             DWORD style = GetWindowLong(window.windowHandle, GWL_EXSTYLE);
1510             if((style & WS_EX_LAYERED) != WS_EX_LAYERED)
1511                SetWindowLong(window.windowHandle, GWL_EXSTYLE, style | WS_EX_LAYERED);
1512 #endif
1513             // SetLayeredWindowAttributes(window.windowHandle, 0, 255 /*Max(A(window.background),1)*/, LWA_ALPHA);
1514          }
1515       }
1516    }
1517
1518    void OffsetWindow(Window window, int * x, int * y)
1519    {
1520       if(window.systemParent)
1521       {
1522          POINT point = {*x,*y};
1523          ClientToScreen(GetParent(window.windowHandle), &point);
1524          *x = point.x;
1525          *y = point.y;
1526       }
1527    }
1528
1529    void UpdateRootWindow(Window window)
1530    {
1531       UpdateWindow(window.windowHandle);
1532    }
1533
1534    void SetRootWindowState(Window window, WindowState state, bool visible)
1535    {
1536       if(visible)
1537       {
1538          switch(state)
1539          {
1540             case maximized:
1541             case normal:
1542             {
1543                if((window.active || window.creationActivation == activate) && !externalDisplayChange)
1544                   ShowWindow(window.windowHandle, (window.nativeDecorations && state == maximized) ? SW_MAXIMIZE : SW_SHOWNORMAL);
1545                else
1546                {
1547                   WINDOWPLACEMENT plc = { 0 };
1548                   GetWindowPlacement(window.windowHandle, &plc);
1549                   plc.showCmd = (window.nativeDecorations && state == maximized) ? SW_MAXIMIZE : SW_SHOWNORMAL;
1550                   ShowWindow(window.windowHandle, SW_SHOWNOACTIVATE);
1551                   SetWindowPlacement(window.windowHandle, &plc);
1552                }
1553                break;
1554             }
1555             case minimized:
1556                ShowWindow(window.windowHandle, SW_MINIMIZE);
1557                break;
1558          }
1559       }
1560       else
1561       {
1562          ShowWindow(window.windowHandle, SW_HIDE);
1563       }
1564    }
1565
1566    void ActivateRootWindow(Window window)
1567    {
1568       if(!externalDisplayChange)
1569          SetForegroundWindow(window.windowHandle);
1570    }
1571
1572    void FlashRootWindow(Window window)
1573    {
1574       FLASHWINFO flashInfo = { 0 };
1575       flashInfo.cbSize = sizeof(FLASHWINFO);
1576       flashInfo.hwnd = window.windowHandle;
1577       flashInfo.uCount = 1;
1578       flashInfo.dwFlags = FLASHW_TRAY; // FLASHW_ALL;
1579       guiApp.Unlock();
1580       FlashWindowEx((void *)&flashInfo);
1581       guiApp.Lock();
1582    }
1583
1584    // --- Mouse-based window movement ---
1585    void StartMoving(Window window, int x, int y, bool fromKeyBoard)
1586    {
1587       if(!fullScreenMode && !window.systemParent)
1588          // Commented out for Chess game because AI thread takes over the moving of main window... Still required?
1589          //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
1590          ; //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
1591       if(fromKeyBoard)
1592       {
1593          SetWindowPos(window.windowHandle, HWND_TOPMOST, 0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
1594          mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
1595          if(!window.stayOnTop)
1596             SetWindowPos(window.windowHandle, HWND_NOTOPMOST, 0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
1597       }
1598    }
1599
1600    void StopMoving(Window window)
1601    {
1602       if(!fullScreenMode && !window.systemParent)
1603          SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
1604    }
1605
1606    // -- Mouse manipulation ---
1607
1608    void GetMousePosition(int *x, int *y)
1609    {
1610       POINT point;
1611       GetCursorPos(&point);
1612       *x = point.x;
1613       *y = point.y;
1614    }
1615
1616    void SetMousePosition(int x, int y)
1617    {
1618       SetCursorPos(x, y);
1619    }
1620
1621    void SetMouseRange(Window window, Box box)
1622    {
1623       ClipCursor((RECT *) box);
1624    }
1625
1626    void SetMouseCapture(Window window)
1627    {
1628       if(window)
1629          SetCapture(window.windowHandle);
1630       else
1631          ReleaseCapture();
1632    }
1633
1634    // -- Mouse cursor ---
1635
1636    void SetMouseCursor(Window window, SystemCursor cursor)
1637    {
1638       if(lastCursor != cursor)
1639       {
1640          lastCursor = cursor;
1641          SetCursor((cursor == (SystemCursor)-1) ? null : systemCursors[cursor]);
1642       }
1643    }
1644
1645    // --- Caret ---
1646
1647    void SetCaret(int x, int y, int size)
1648    {
1649
1650    }
1651
1652    // --- Clipboard manipulation ---
1653
1654    void ClearClipboard()
1655    {
1656         if(OpenClipboard(null))
1657         {
1658          EmptyClipboard();
1659            CloseClipboard();
1660       }
1661    }
1662
1663    bool AllocateClipboard(ClipBoard clipBoard, uint size)
1664    {
1665       bool result = false;
1666       clipBoard.text = new byte[size];
1667       result = true;
1668       return result;
1669    }
1670
1671    bool SaveClipboard(ClipBoard clipBoard)
1672    {
1673       bool result = false;
1674       if(clipBoard.text)
1675       {
1676          int wordCount;
1677          uint16 * u16text = UTF8toUTF16(clipBoard.text, &wordCount);
1678          wordCount++;
1679          clipBoard.handle = GlobalAlloc(GHND | GMEM_DDESHARE, wordCount * 2);
1680          if(clipBoard.handle)
1681          {
1682             uint16 * text = GlobalLock(clipBoard.handle);
1683             if(text)
1684             {
1685                memcpy(text, u16text, wordCount * 2);
1686                GlobalUnlock(clipBoard.handle);
1687                    if(OpenClipboard(null))
1688                    {
1689                   EmptyClipboard();
1690                       if(SetClipboardData(CF_UNICODETEXT, clipBoard.handle))
1691                   {
1692                          CloseClipboard();
1693                      result= true;
1694                   }
1695                }
1696             }
1697             if(!result)
1698                GlobalFree(clipBoard.handle);
1699          }
1700          delete u16text;
1701       }
1702       return result;
1703    }
1704
1705    bool LoadClipboard(ClipBoard clipBoard)
1706    {
1707       bool result = false;
1708         if(OpenClipboard(null))
1709         {
1710          if((clipBoard.handle = GetClipboardData(CF_UNICODETEXT)))
1711          {
1712             uint16 * u16text = GlobalLock(clipBoard.handle);
1713             if(u16text)
1714             {
1715                clipBoard.text = UTF16toUTF8(u16text);
1716                result = true;
1717                GlobalUnlock(clipBoard.handle);
1718             }
1719          }
1720          CloseClipboard();
1721       }
1722       return result;
1723    }
1724
1725    void UnloadClipboard(ClipBoard clipBoard)
1726    {
1727       delete clipBoard.text;
1728    }
1729
1730    // --- State based input ---
1731
1732    bool AcquireInput(Window window, bool state)
1733    {
1734    #ifndef ECERE_NODINPUT
1735       if(dInput || InitDirectInput())
1736       {
1737          AcquireDirectInput(window.windowHandle, state);
1738          return true;
1739       }
1740    #endif
1741       return false;
1742    }
1743
1744    bool GetMouseState(MouseButtons * buttons, int * x, int * y)
1745    {
1746       bool result = false;
1747    #ifndef ECERE_NODINPUT
1748       DIMOUSESTATE dims = {0};
1749
1750       if(acquiredWindow && directMouse)
1751       {
1752          if(directMouse->lpVtbl->GetDeviceState(directMouse, sizeof(DIMOUSESTATE), &dims ))
1753          {
1754             FillBytes(&dims, 0, sizeof(dims));
1755             directMouse->lpVtbl->Acquire(directMouse);
1756          }
1757          result = true;
1758       }
1759       /*  We don't really want this...
1760       else
1761       {
1762          if(GetAsyncKeyState(VK_LBUTTON))
1763             dims.rgbButtons[0] |= 0x80;
1764          if(GetAsyncKeyState(VK_RBUTTON))
1765             dims.rgbButtons[1] |= 0x80;
1766          if(GetAsyncKeyState(VK_MBUTTON))
1767             dims.rgbButtons[2] |= 0x80;
1768       }
1769       */
1770
1771       if(x)*x = dims.lX;
1772       if(y)*y = dims.lY;
1773       if(dims.lZ)
1774       {
1775 #ifdef _WIN64
1776          Window window = (Window)GetWindowLongPtr(acquiredWindow, GWLP_USERDATA);
1777 #else
1778          Window window = (Window)GetWindowLong(acquiredWindow, GWL_USERDATA);
1779 #endif
1780          ProcessKeyMessage(window, WM_MOUSEWHEEL, ((uint16)(short)dims.lZ) << 16, 0, 0);
1781       }
1782       if(buttons)
1783       {
1784          *buttons = MouseButtons {
1785              left = (dims.rgbButtons[0] & 0x80) ? true : false,
1786              right = (dims.rgbButtons[1] & 0x80) ? true : false,
1787              middle = (dims.rgbButtons[2] & 0x80) ? true : false };
1788       }
1789    #endif
1790
1791       return result;
1792    }
1793
1794    bool GetJoystickState(int device, Joystick joystick)
1795    {
1796       bool result = false;
1797    #ifndef ECERE_NODINPUT
1798       if(joystick != null)
1799       {
1800          DIJOYSTATE dijs = {0};
1801    #ifndef ECERE_NOJOYSTICK
1802          if(acquiredWindow && device < numJoysticks)
1803          {
1804             if(directJoysticks[device])
1805             {
1806                directJoysticks[device]->lpVtbl->Poll(directJoysticks[device]);
1807                if(directJoysticks[device]->lpVtbl->GetDeviceState(directJoysticks[device], sizeof(DIJOYSTATE), &dijs ))
1808                   directJoysticks[device]->lpVtbl->Acquire(directJoysticks[device]);
1809                result = true;
1810             }
1811          }
1812    #endif
1813          joystick.x = dijs.lX;
1814          joystick.y = dijs.lY;
1815          joystick.z = dijs.lZ;
1816          joystick.rx = dijs.lRx;
1817          joystick.ry = dijs.lRy;
1818          joystick.rz = dijs.lRz;
1819          joystick.buttons =
1820               ((dijs.rgbButtons[0] & 0x80) ? JOY_BUTTON1 : 0)
1821             | ((dijs.rgbButtons[1] & 0x80) ? JOY_BUTTON2 : 0)
1822             | ((dijs.rgbButtons[2] & 0x80) ? JOY_BUTTON3 : 0)
1823             | ((dijs.rgbButtons[3] & 0x80) ? JOY_BUTTON4 : 0);
1824       }
1825    #endif
1826       return result;
1827    }
1828
1829    bool GetKeyState(Key key)
1830    {
1831       bool keyState = false;
1832       if(key < 256 || key == alt || key == shift || key == control)
1833       {
1834          uint ks = 0;
1835          if(key == alt)
1836             ks = GetAsyncKeyState(VK_MENU);
1837          else if(key == control)
1838             ks = GetAsyncKeyState(VK_CONTROL);
1839          else if(key == shift)
1840             ks = GetAsyncKeyState(VK_SHIFT);
1841          else if(key2VK[key])
1842             ks = GetAsyncKeyState(key2VK[key]);
1843          keyState = (ks & 0x80000) ? true : false;
1844       }
1845       else if(key == capsState)
1846          keyState = (::GetKeyState(VK_CAPITAL) & 0x00000001) != 0;
1847       else if(key == numState)
1848          keyState = (::GetKeyState(VK_NUMLOCK) & 0x00000001) != 0;
1849       else if(key == scrollState)
1850          keyState = (::GetKeyState(VK_SCROLL) & 0x00000001) != 0;
1851       return keyState;
1852    }
1853
1854    bool SetIcon(Window window, BitmapResource resource)
1855    {
1856       HICON icon = null;
1857       HICON oldIcon = (HICON)SendMessage(window.windowHandle, WM_GETICON, ICON_BIG, 0);
1858
1859       // Dialogs Inherit master's icon if none set
1860       if(!window.style.showInTaskBar && window.hasClose)
1861       {
1862          Window master = window.master;
1863          while(master && !resource)
1864          {
1865             Window rootWindow = (master && master != guiApp.desktop) ? master.rootWindow : null;
1866             if(rootWindow && rootWindow.icon)
1867                resource = rootWindow.icon;
1868             else
1869                master = master.master;
1870          }
1871       }
1872
1873       // WARNING -- putting this here as it is right after CreateRootWindow
1874       // Take out Layered flag if we're not in 24 bit
1875       {
1876          if(window.alphaBlend && window.display.pixelFormat != pixelFormat888)
1877          {
1878 #ifndef ECERE_NOBLENDING
1879             DWORD style = GetWindowLong(window.windowHandle, GWL_EXSTYLE);
1880             style &= ~WS_EX_LAYERED;
1881             SetWindowLong(window.windowHandle, GWL_EXSTYLE, style);
1882 #endif
1883          }
1884       }
1885
1886 #ifdef _WIN64
1887       if(oldIcon && oldIcon != (HICON)GetClassLongPtr(window.windowHandle, GCLP_HICON))
1888 #else
1889       if(oldIcon && oldIcon != (HICON)GetClassLong(window.windowHandle, GCL_HICON))
1890 #endif
1891       {
1892          DestroyIcon(oldIcon);
1893       }
1894
1895       if(resource)
1896       {
1897          Bitmap bitmap { };
1898          if(bitmap.Load(resource.fileName, null, null))
1899          {
1900             Bitmap and { };
1901             PixelFormat format = window.display.pixelFormat;
1902             int bits = GetDepthBits(format);
1903             bool blend;
1904
1905             bitmap.Convert(null, pixelFormat888, null);
1906             and.Allocate(null, (bitmap.width+7/8), bitmap.height, 0, pixelFormat8, false);
1907
1908             blend = bits == 32 || bitmap.pixelFormat != pixelFormat888;
1909
1910             {
1911                byte * picture = and.picture;
1912                int c = 0;
1913                int b = 0;
1914                uint size = bitmap.height * bitmap.width;
1915                while(c < size)
1916                {
1917                   int m = 0;
1918                   byte mask = 0;
1919                   while(m < 8 && c < size)
1920                   {
1921                      mask <<= 1;
1922                      mask |= blend ? (!((ColorAlpha *)bitmap.picture)[c].a) : (((ColorAlpha *)bitmap.picture)[c].a <= 192);
1923                      c++;
1924                      m++;
1925                   }
1926                   picture[b++] = mask;
1927                }
1928                c = 0;
1929                while(c < size)
1930                {
1931                   ColorAlpha color = ((ColorAlpha *)bitmap.picture)[c];
1932                   if(blend ? (!color.a) : (color.a <= 192))
1933                   {
1934                      color.color = { 0, 0, 0 };
1935                      ((ColorAlpha *)bitmap.picture)[c] = color;
1936                   }
1937                   c++;
1938                }
1939             }
1940             if(bits == 15) { bits = 16; format = pixelFormat565; };
1941             bitmap.Convert(null, format, null);
1942
1943             icon = CreateIcon(hInstance, bitmap.width, bitmap.height, 1, (byte)bits, and.picture, bitmap.picture);
1944             delete and;
1945          }
1946          delete bitmap;
1947       }
1948       SendMessage(window.windowHandle, WM_SETICON, ICON_BIG, (LPARAM)icon);
1949       SendMessage(window.windowHandle, WM_SETICON, ICON_SMALL, (LPARAM)icon);
1950       return true;
1951    }
1952
1953    void ::GetScreenArea(Window window, Box box)
1954    {
1955       HMONITOR monitor = MonitorFromWindow(window.windowHandle, MONITOR_DEFAULTTONEAREST);
1956       HMONITOR taskBarMonitor = MonitorFromWindow(startBar, MONITOR_DEFAULTTONEAREST);
1957       if(monitor)
1958       {
1959          MONITORINFO info = { 0 };
1960          info.cbSize = sizeof(MONITORINFO);
1961          GetMonitorInfo(monitor, &info);
1962          // box = { info.rcWork.left, info.rcWork.top, info.rcWork.right, info.rcWork.bottom };
1963          box = { info.rcMonitor.left, info.rcMonitor.top, info.rcMonitor.right-1, info.rcMonitor.bottom-1 };
1964
1965          if(taskBarMonitor == monitor)
1966          {
1967             if(taskBarPlacement.rcNormalPosition.top <= box.top && taskBarPlacement.rcNormalPosition.bottom >= box.bottom)
1968             {
1969                if(taskBarPlacement.rcNormalPosition.left <= box.left)
1970                {
1971                   if(taskBarState & ABS_AUTOHIDE)
1972                      box.left++;
1973                   else
1974                      box.left = taskBarPlacement.rcNormalPosition.right;
1975                }
1976                else if(taskBarState & ABS_AUTOHIDE)
1977                   box.right -= 1;
1978                else
1979                   box.right = taskBarPlacement.rcNormalPosition.left;
1980             }
1981             else if(taskBarPlacement.rcNormalPosition.left <= box.left && taskBarPlacement.rcNormalPosition.right >= box.right)
1982             {
1983                if(taskBarPlacement.rcNormalPosition.top <= box.top)
1984                {
1985                   if(taskBarState & ABS_AUTOHIDE)
1986                      box.top += 1;
1987                   else
1988                      box.top = taskBarPlacement.rcNormalPosition.bottom;
1989                }
1990                else if(taskBarState & ABS_AUTOHIDE)
1991                   box.bottom -= 1;
1992                else
1993                   box.bottom = taskBarPlacement.rcNormalPosition.top;
1994             }
1995          }
1996
1997          box.left -= desktopX;
1998          box.top -= desktopY;
1999          box.right -= desktopX;
2000          box.bottom -= desktopY;
2001       }
2002    }
2003 }
2004
2005 #endif