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