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