480edd721fa39efb191e1ae70a81785b1eebcff2
[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_GETMINMAXINFO:
948             {
949                MINMAXINFO * mmi = (MINMAXINFO *)lParam;
950                if(window.nativeDecorations)
951                {
952                   WINDOWPLACEMENT place = { 0 };
953                   place.length = sizeof(WINDOWPLACEMENT);
954                   GetWindowPlacement(windowHandle, &place);
955                   if((place.showCmd & SW_SHOWMAXIMIZED) && window.state != maximized)
956                      window.state = maximized;
957                   else if((place.showCmd & SW_SHOWMINIMIZED) && window.state != minimized)
958                      window.state = minimized;
959                   else if((place.showCmd & SW_SHOWNORMAL) && window.state != normal && window.visible)
960                      window.state = normal;
961                }
962                else
963                   return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
964                break;
965             }*/
966 #if 0
967             case WM_WINDOWPOSCHANGED:
968             {
969                if(window.nativeDecorations)
970                {
971                   int x, y, w, h;
972                   WINDOWPOS * pos = (WINDOWPOS *)lParam;
973                   //if((pos->flags & SWP_SHOWWINDOW))
974 #if 0
975                   if((pos->flags & 0x800)) // SWP_STATECHANGED
976                   {
977                   WINDOWPLACEMENT place = { 0 };
978                   place.length = sizeof(WINDOWPLACEMENT);
979                   GetWindowPlacement(windowHandle, &place);
980                printf("WM_WINDOWPOSCHANGED: ");
981                   printf("SWP_STATECHANGED (");
982                   if((place.showCmd & SW_SHOWMAXIMIZED))
983                      printf("maximized");
984                   else if((place.showCmd & SW_SHOWMINIMIZED))
985                      printf("minimized");
986                   else if((place.showCmd & SW_SHOWNORMAL))
987                      printf("normal");
988                   printf(") ");
989
990                   /*if((place.showCmd & SW_SHOWMAXIMIZED) && window.state != maximized)
991                      window.state = maximized;
992                   else if((place.showCmd & SW_SHOWMINIMIZED) && window.state != minimized)
993                      window.state = minimized;
994                   else if((place.showCmd & SW_SHOWNORMAL) && window.state != normal && window.visible)
995                      window.state = normal;*/
996                printf("\n");
997                   }
998 #endif
999                   if(!(pos->flags & SWP_NOMOVE) || !(pos->flags & SWP_NOSIZE))
1000                   {
1001                   //RECT rcWindow;
1002                   //GetWindowRect(windowHandle, &rcWindow);
1003                   WINDOWPLACEMENT place = { 0 };
1004                   place.length = sizeof(WINDOWPLACEMENT);
1005                   GetWindowPlacement(windowHandle, &place);
1006                printf("WM_WINDOWPOSCHANGED: ");
1007                   printf("!SWP_NOMOVE || !SWP_NOSIZE (");
1008
1009                   if(wParam == SIZE_MAXIMIZED && window.state != maximized)
1010                      window.state = maximized;
1011                   else if(wParam == SIZE_MINIMIZED && window.state != minimized)
1012                      window.state = minimized;
1013                   else if(wParam == SIZE_RESTORED && window.state != normal && window.visible)
1014                      window.state = normal;
1015
1016                   /*if((place.showCmd & SW_MAXIMIZE) && window.state != maximized)
1017                      window.state = maximized;
1018                   else if((place.showCmd & SW_MINIMIZE) && window.state != minimized)
1019                      window.state = minimized;
1020                   else if((place.showCmd & SW_RESTORE) && window.state != normal && window.visible)
1021                      window.state = normal;*/
1022
1023                   //x = rcWindow.left - desktopX;
1024                   //y = rcWindow.top  - desktopY;
1025                   //w = rcWindow.right - rcWindow.left;
1026                   //h = rcWindow.bottom - rcWindow.top;
1027                   x = pos->x - desktopX;
1028                   y = pos->y  - desktopY;
1029                   w = pos->cx;
1030                   h = pos->cy;
1031                   printf("%d, %d, %d, %d) ", x, y, w, h);
1032
1033                   AeroSnapPosition(window, x, y, w, h);
1034                   if(!(pos->flags & SWP_NOSIZE) && !guiApp.modeSwitching)
1035                      window.UpdateVisual(null);
1036                   }
1037                //printf("\n");
1038                }
1039                //else
1040                   return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
1041                break;
1042             }
1043 #endif
1044             case WM_MOVE:
1045             {
1046                int x, y, w, h;
1047                //WINDOWPLACEMENT place = { 0 };
1048                RECT rcWindow;
1049                //place.length = sizeof(WINDOWPLACEMENT);
1050                //GetWindowPlacement(windowHandle, &place);
1051                GetWindowRect(windowHandle, &rcWindow);
1052
1053 #if 0
1054                if((place.showCmd & SW_SHOWMAXIMIZED) && window.state != maximized)
1055                   window.state = maximized;
1056                else if((place.showCmd & SW_SHOWMINIMIZED) && window.state != minimized)
1057                   window.state = minimized;
1058                else if((place.showCmd & SW_SHOWNORMAL) && window.state != normal && window.visible)
1059                   window.state = normal;
1060 #endif
1061
1062                x = rcWindow.left - desktopX;
1063                y = rcWindow.top  - desktopY;
1064                w = rcWindow.right - rcWindow.left;
1065                h = rcWindow.bottom - rcWindow.top;
1066
1067                //printf("WM_MOVE - (%d,%d) (%dx%d) (%s) \n", x, y, w, h,
1068                //      window.state == maximized ? "maximized" : window.state == minimized ? "minimized" : window.state == normal ? "normal" : "BAD");
1069
1070                AeroSnapPosition(window, x, y, w, h);
1071                break;
1072             }
1073             /*case WM_MOVING:
1074                break;*/
1075             case WM_SIZING:
1076             {
1077                RECT * rect = (RECT *)lParam;
1078                MinMaxValue ew, eh;
1079                int w, h;
1080
1081                window.GetDecorationsSize(&ew, &eh);
1082
1083                w = rect->right - rect->left;
1084                h = rect->bottom - rect->top;
1085
1086                w -= ew;
1087                h -= eh;
1088
1089                w = Max(w, 1);
1090                h = Max(h, 1);
1091
1092                w = Max(w, window.minSize.w);
1093                h = Max(h, window.minSize.h);
1094                w = Min(w, window.maxSize.w);
1095                h = Min(h, window.maxSize.h);
1096
1097                if(!window.OnResizing(&w, &h))
1098                {
1099                   w = window.clientSize.w;
1100                   h = window.clientSize.h;
1101                }
1102
1103                w = Max(w, window.skinMinSize.w);
1104                h = Max(h, window.skinMinSize.h);
1105
1106                w += ew;
1107                h += eh;
1108
1109                if(wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT)
1110                   rect->left = rect->right - w;
1111                else
1112                   rect->right = rect->left + w;
1113
1114                if(wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOP || wParam == WMSZ_TOPRIGHT)
1115                   rect->top = rect->bottom - h;
1116                else
1117                   rect->bottom = rect->top + h;
1118
1119                return 1;
1120             }
1121             case WM_SIZE:
1122             {
1123                if(window.nativeDecorations)
1124                {
1125                   int x, y, w, h;
1126                   RECT rcWindow;
1127                   GetWindowRect(windowHandle, &rcWindow);
1128
1129                   if(wParam == SIZE_MAXIMIZED && window.state != maximized)
1130                      window.state = maximized;
1131                   else if(wParam == SIZE_MINIMIZED && window.state != minimized)
1132                      window.state = minimized;
1133                   else if(wParam == SIZE_RESTORED && window.state != normal && window.visible)
1134                      window.state = normal;
1135
1136                   x = rcWindow.left - desktopX;
1137                   y = rcWindow.top  - desktopY;
1138                   w = rcWindow.right - rcWindow.left;
1139                   h = rcWindow.bottom - rcWindow.top;
1140
1141                   //printf("WM_SIZE - (%d,%d) (%dx%d) (%s) \n", x, y, w, h,
1142                   //      wParam == SIZE_MAXIMIZED ? "SIZE_MAXIMIZED" : wParam == SIZE_MINIMIZED ? "SIZE_MINIMIZED" : wParam == SIZE_RESTORED ? "SIZE_RESTORED" : "BAD");
1143
1144                   AeroSnapPosition(window, x, y, w, h);
1145                   if(!guiApp.modeSwitching)
1146                      window.UpdateVisual(null);
1147                }
1148                else
1149                   return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
1150                break;
1151             }
1152             default:
1153                return (uint)DefWindowProc(windowHandle, msg, wParam, lParam);
1154          }
1155       }
1156       else
1157          return (uint)DefMDIChildProc(windowHandle, msg, wParam, lParam);
1158          // return DefWindowProc(windowHandle, msg, wParam, lParam);
1159       return 0;
1160    }
1161
1162    // --- DirectInput ---
1163
1164    #ifndef ECERE_NODINPUT
1165
1166    #ifndef ECERE_NOJOYSTICK
1167    bool CALLBACK ::JoystickCallback( const DIDEVICEINSTANCE* pdidInstance, void * context )
1168    {
1169       if(!dInput->lpVtbl->CreateDevice(dInput, &GUID_Joystick,
1170          (IDirectInputDevice **)&directJoysticks[numJoysticks], null ))
1171          numJoysticks++;
1172       return DIENUM_CONTINUE;
1173    }
1174
1175    bool CALLBACK ::JoystickAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, void * context )
1176    {
1177       DIPROPRANGE diprg;
1178       IDirectInputDevice2 * curJoy = (IDirectInputDevice2 *)context;
1179
1180       diprg.diph.dwSize       = sizeof(DIPROPRANGE);
1181       diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1182       diprg.diph.dwHow        = DIPH_BYOFFSET;
1183       diprg.diph.dwObj        = pdidoi->dwOfs;
1184       diprg.lMin              = -128;
1185       diprg.lMax              = 127;
1186       if(curJoy->lpVtbl->SetProperty(curJoy, DIPROP_RANGE, &diprg.diph))
1187          return DIENUM_STOP;
1188       return DIENUM_CONTINUE;
1189    }
1190    #endif
1191
1192    void ::TerminateDirectInput()
1193    {
1194       int j;
1195       if (directMouse)
1196       {
1197          directMouse->lpVtbl->Unacquire(directMouse);
1198          directMouse->lpVtbl->Release(directMouse);
1199          directMouse = null;
1200       }
1201    #ifndef ECERE_NOJOYSTICK
1202       for(j=0; j<numJoysticks; j++)
1203       {
1204          if (directJoysticks[j])
1205          {
1206             directJoysticks[j]->lpVtbl->Unacquire(directJoysticks[j]);
1207             directJoysticks[j]->lpVtbl->Release(directJoysticks[j]);
1208             directJoysticks[j] = null;
1209          }
1210       }
1211       numJoysticks = 0;
1212    #endif
1213       if(dInput)
1214       {
1215          dInput->lpVtbl->Release(dInput);
1216          dInput = null;
1217       }
1218
1219       directInputCreate = null;
1220
1221       if(dInputDll)
1222       {
1223          FreeLibrary(dInputDll);
1224          dInputDll = null;
1225       }
1226    }
1227
1228    bool ::InitDirectInput()
1229    {
1230       bool result = false;
1231
1232       dInputDll = LoadLibraryA("dinput.dll");
1233       if(dInputDll)
1234       {
1235          if((directInputCreate = (void *)GetProcAddress(dInputDll, "DirectInputCreateA")))
1236          {
1237             if(!directInputCreate( hInstance, DIRECTINPUT_VERSION, &dInput, null ))
1238             {
1239                int j;
1240
1241                // Mouse
1242                if(!dInput->lpVtbl->CreateDevice(dInput, &GUID_SysMouse, &directMouse, null ))
1243                   directMouse->lpVtbl->SetDataFormat(directMouse, &c_dfDIMouse );
1244
1245    #ifndef ECERE_NOJOYSTICK
1246                // Joystick
1247                dInput->lpVtbl->EnumDevices(dInput, DIDEVTYPE_JOYSTICK, JoystickCallback, null, DIEDFL_ATTACHEDONLY );
1248                for(j=0; j<NUMJOY; j++)
1249                   if(directJoysticks[j])
1250                      if(!directJoysticks[j]->lpVtbl->SetDataFormat(directJoysticks[j], &c_dfDIJoystick ))
1251                         directJoysticks[j]->lpVtbl->EnumObjects(directJoysticks[j], JoystickAxesCallback, directJoysticks[j], DIDFT_AXIS );
1252    #endif
1253                result = true;
1254             }
1255          }
1256       }
1257       return result;
1258    }
1259
1260    void ::AcquireDirectInput(HWND windowHandle, bool state)
1261    {
1262       if((state && !acquiredWindow) || (!state && acquiredWindow == windowHandle))
1263       {
1264          int j;
1265          if(directMouse)
1266          {
1267             if(state)
1268             {
1269                directMouse->lpVtbl->SetCooperativeLevel(directMouse, /*fullScreenMode ? */windowHandle /*: HWND_DESKTOP*/, DISCL_EXCLUSIVE|DISCL_FOREGROUND);
1270                directMouse->lpVtbl->Acquire(directMouse);
1271             }
1272             else
1273                directMouse->lpVtbl->Unacquire(directMouse);
1274          }
1275    #ifndef ECERE_NOJOYSTICK
1276          for(j = 0; j<NUMJOY; j++)
1277             if(directJoysticks[j])
1278             {
1279                if(state)
1280                {
1281                   directJoysticks[j]->lpVtbl->SetCooperativeLevel(directJoysticks[j], /*fullScreenMode ? */windowHandle /*: HWND_DESKTOP*/, DISCL_EXCLUSIVE|DISCL_FOREGROUND);
1282                   directJoysticks[j]->lpVtbl->Acquire(directJoysticks[j]);
1283                }
1284                else
1285                   directJoysticks[j]->lpVtbl->Unacquire(directJoysticks[j]);
1286             }
1287    #endif
1288          acquiredWindow = state ? windowHandle : null;
1289       }
1290    }
1291    #endif
1292
1293    /****************************************************************************
1294       /// INTEGRATION FUNCTIONALITY /////////////
1295    ****************************************************************************/
1296    bool eisWIN32ProcessKey(Window window, DWORD msg, DWORD wParam, DWORD lParam, byte ch)
1297    {
1298       return ProcessKeyMessage(window, msg, wParam, lParam, ch);
1299    }
1300
1301    HWND eisWIN32GetWindowHandle(Window window)
1302    {
1303       return window.windowHandle ? window.windowHandle : window.rootWindow.windowHandle;
1304    }
1305
1306    /****************************************************************************
1307       /// DRIVER IMPLEMENTATION /////////////
1308    ****************************************************************************/
1309
1310 #ifdef _WIN64
1311    void CALLBACK ::TimerProc(UINT uTimerID, UINT uMsg, uint64 dwUser, uint64 dw1, uint64 dw2)
1312 #else
1313    void CALLBACK ::TimerProc(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
1314 #endif
1315    {
1316       guiApp.SignalEvent();
1317    }
1318
1319    // --- User Interface System ---
1320    bool Initialize()
1321    {
1322       WNDCLASS wcl =
1323       {
1324          CS_DBLCLKS, ApplicationWindow, 0L, 0L, 0,
1325          LoadIcon(null, IDI_APPLICATION),
1326          null,
1327          null,
1328          null,
1329          className
1330       };
1331       HDC hdc = GetDC(0);
1332       lastRes = MAKELPARAM(GetSystemMetrics(SM_CYSCREEN), GetSystemMetrics(SM_CXSCREEN));
1333       lastBits = (WPARAM)GetDeviceCaps(hdc, BITSPIXEL);
1334       ReleaseDC(0, hdc);
1335
1336       AttachConsole(-1);
1337       wcl.hInstance = hInstance = GetModuleHandle(null);
1338       RegisterClass(&wcl);
1339
1340       // Move that in reposition desktop
1341       startBar = FindWindowA("Shell_TrayWnd", null);
1342
1343       systemCursors[arrow] = LoadCursor(null, IDC_ARROW);
1344       systemCursors[iBeam] = LoadCursor(null, IDC_IBEAM);
1345       systemCursors[cross] = LoadCursor(null, IDC_CROSS);
1346       systemCursors[moving] = LoadCursor(null, IDC_SIZEALL);
1347       systemCursors[sizeNESW] = LoadCursor(null, IDC_SIZENESW);
1348       systemCursors[sizeNS  ] = LoadCursor(null, IDC_SIZENS);
1349       systemCursors[sizeNWSE] = LoadCursor(null, IDC_SIZENWSE);
1350       systemCursors[sizeWE  ] = LoadCursor(null, IDC_SIZEWE);
1351       systemCursors[hand    ] = LoadCursor(null, IDC_HAND);
1352
1353       SetTimer(null, 0, (DWORD)(1000.0 / 18.2), null);
1354       //SetTimer(null, 0, 1, null);
1355       /*
1356       timeBeginPeriod(1);
1357
1358       hiResTimer = timeSetEvent(
1359          1000.0 / 250.0,
1360          1000.0 / 250.0,
1361          TimerProc,0,TIME_PERIODIC);
1362       */
1363       /*
1364       hiResTimer = timeSetEvent(
1365          1000.0 / 500.0,
1366          1000.0 / 500.0,
1367          TimerProc,0,TIME_PERIODIC);
1368          */
1369
1370    /*
1371       topWindow = CreateWindowEx(0, className, "",WS_POPUP,0,0,1,1,HWND_DESKTOP,
1372          null, hInstance, null);
1373    */
1374       return true;
1375    }
1376
1377    void Terminate()
1378    {
1379       if(hiResTimer) timeKillEvent(hiResTimer);
1380    #ifndef ECERE_NODINPUT
1381       TerminateDirectInput();
1382    #endif
1383    }
1384
1385    void SetTimerResolution(uint hertz)
1386    {
1387       if(hiResTimer) timeKillEvent(hiResTimer);
1388       if(hertz)
1389          hiResTimer = timeSetEvent(1000 / hertz, 1000 / hertz, TimerProc, 0, TIME_PERIODIC);
1390    }
1391
1392    bool ProcessInput(bool processAll)
1393    {
1394       MSG msg;
1395       if(!fullScreenMode)
1396          RepositionDesktop(true);
1397       if(PeekMessage(&msg,0,0,0,PM_NOREMOVE))
1398       {
1399          while(PeekMessage(&msg,0,0,0,PM_REMOVE))
1400          {
1401             TranslateMessage(&msg);
1402             DispatchMessage(&msg);
1403             // printf("%d\n", msg.message);
1404             if(!processAll || msg.message == WM_TIMER) break;
1405          }
1406          return true;
1407       }
1408       return false;
1409    }
1410
1411    void Wait()
1412    {
1413       MsgWaitForMultipleObjects(1, (void **)guiApp.semaphore, FALSE, (uint)(1000 / 18.2) /*INFINITE*/, QS_ALLINPUT);
1414    }
1415
1416    void Lock(Window window)
1417    {
1418
1419    }
1420
1421    void Unlock(Window window)
1422    {
1423
1424    }
1425
1426    const char ** GraphicsDrivers(int * numDrivers)
1427    {
1428       static const char *graphicsDrivers[] = { "GDI", "DirectDraw", "OpenGL", "Direct3D", "Direct3D8", "Direct3D9" };
1429       *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
1430       return (const char **)graphicsDrivers;
1431    }
1432
1433    void GetCurrentMode(bool * fullScreen, Resolution * resolution, PixelFormat * colorDepth, int * refreshRate)
1434    {
1435       *fullScreen = fullScreenMode;
1436       if(fullScreenMode)
1437       {
1438          Resolution c;
1439          for(c = 0; c<Resolution::enumSize; c++)
1440             if(GetResolutionWidth(c) == devMode.dmPelsWidth && GetResolutionHeight(c) == devMode.dmPelsHeight)
1441             {
1442                *resolution = c;
1443                break;
1444             }
1445          switch(devMode.dmBitsPerPel)
1446          {
1447             case 8: *colorDepth = pixelFormat8; break;
1448             case 16: *colorDepth = pixelFormat555; break;
1449             default: *colorDepth = pixelFormat888; break;
1450          }
1451          * refreshRate = devMode.dmDisplayFrequency;
1452       }
1453    }
1454
1455    void EnsureFullScreen(bool *fullScreen)
1456    {
1457
1458    }
1459
1460    bool ScreenMode(bool fullScreen, Resolution resolution, PixelFormat colorDepth, int refreshRate, bool * textMode)
1461    {
1462       bool result = true;
1463       HDC hdc = GetDC(0);
1464
1465       fullScreenMode = fullScreen;
1466
1467       if(fullScreen)
1468       {
1469          FillBytes(&devMode, 0, sizeof(DEVMODE));
1470            devMode.dmSize = (uint16)sizeof(devMode);
1471          devMode.dmFields |=DM_BITSPERPEL;
1472          devMode.dmFields |=DM_PELSWIDTH|DM_PELSHEIGHT;
1473          devMode.dmFields |= DM_DISPLAYFREQUENCY;
1474          devMode.dmBitsPerPel = colorDepth ? GetDepthBits(colorDepth) : GetDeviceCaps(hdc, BITSPIXEL);
1475          devMode.dmPelsWidth = resolution ? GetResolutionWidth(resolution) : GetSystemMetrics(SM_CXSCREEN);
1476          devMode.dmPelsHeight = resolution ? GetResolutionHeight(resolution) : GetSystemMetrics(SM_CYSCREEN);
1477          devMode.dmDisplayFrequency = refreshRate ? refreshRate : GetDeviceCaps(hdc, VREFRESH);
1478          if(ChangeDisplaySettings(&devMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
1479             result = false;
1480          else
1481          {
1482             SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
1483             guiApp.SetDesktopPosition(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), false);
1484          }
1485       }
1486       else
1487       {
1488          static bool firstTime = true;
1489          if(!firstTime)
1490             ChangeDisplaySettings(null, 0);
1491          firstTime = false;
1492          SetSystemPaletteUse(hdc, SYSPAL_STATIC);
1493          desktopX = desktopY = desktopW = desktopH = 0;
1494
1495          RepositionDesktop(false);
1496       }
1497       ReleaseDC(0,hdc);
1498
1499       return result;
1500    }
1501
1502    // --- Window Creation ---
1503    void * CreateRootWindow(Window window)
1504    {
1505       HWND windowHandle;
1506       uint16 * text = UTF8toUTF16(window.text, null);
1507       if(fullScreenMode)
1508       {
1509          windowHandle = CreateWindowEx(0, className, text,
1510                         WS_POPUP,
1511                         0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),
1512                         HWND_DESKTOP,
1513                         null, hInstance, null);
1514          ShowWindow(windowHandle, SW_SHOWNORMAL);
1515       }
1516       else if(window.systemParent)
1517          windowHandle = CreateWindowEx(0, className, text,
1518          WS_CHILD,0,0,1,1, window.systemParent, null, hInstance, null);
1519       else
1520       {
1521          DWORD style = 0;
1522          DWORD exStyle = 0;
1523          HWND parentWindow = null; //HWND_DESKTOP; // we get different behaviors with desktop...
1524          Window master = window.master, rootWindow = (master && master != guiApp.desktop) ? master.rootWindow : null;
1525          if(window.style.stayOnTop)
1526             exStyle |= WS_EX_TOPMOST;
1527
1528          if(rootWindow && (window._isModal || window.style.interim || (window.style.thin && !window.style.showInTaskBar)))
1529             parentWindow = rootWindow.is3D ? rootWindow.parent.windowHandle : rootWindow.windowHandle;
1530
1531          if(window.alphaBlend)
1532          // if(window.background.a < 255) //&& window.style & ES_REDRAW) Not needed anymore?
1533             exStyle |= WS_EX_LAYERED; // | WS_EX_TRANSPARENT;
1534
1535          // Toolwindow will disappear if they don't have AppWindow set
1536          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))
1537          {
1538             exStyle |= WS_EX_APPWINDOW;
1539             parentWindow = null;
1540          }
1541
1542          if(window.style.thin)
1543             exStyle |= WS_EX_TOOLWINDOW;
1544
1545          if(window.windowHandle)
1546             windowHandle = window.windowHandle;
1547          else
1548          {
1549             if(window.nativeDecorations)
1550             {
1551                BorderBits borderStyle = window.borderStyle; // FIXME!
1552                style = WS_OVERLAPPED;
1553                if(borderStyle.fixed)
1554                   style |= WS_CAPTION;
1555                if(window.hasClose)
1556                   style |= WS_SYSMENU;
1557                if(borderStyle.sizable)
1558                   style |= WS_THICKFRAME;
1559                if(window.hasMinimize)
1560                   style |= WS_MINIMIZEBOX;
1561                if(window.hasMaximize)
1562                   style |= WS_MAXIMIZEBOX;
1563             }
1564             windowHandle = CreateWindowEx(
1565                exStyle,
1566                className, text,
1567                style | (window.systemParent ? WS_CHILD :
1568                (WS_POPUP | (window.style.hasMinimize ? WS_MINIMIZEBOX : 0))),
1569                   0,0,1,1, parentWindow, null, hInstance, null);
1570    #if 0
1571             if(exStyle & WS_EX_LAYERED)
1572                SetLayeredWindowAttributes(windowHandle, 0, 255 /*A(window.background)*/, LWA_ALPHA);
1573    #endif
1574          }
1575       }
1576       delete text;
1577 #ifdef _WIN64
1578       SetWindowLongPtr(windowHandle, GWLP_USERDATA, (int64)window);
1579 #else
1580       SetWindowLong(windowHandle, GWL_USERDATA, (DWORD)window);
1581 #endif
1582
1583       return windowHandle;
1584    }
1585
1586    void DestroyRootWindow(Window window)
1587    {
1588       HICON oldIcon;
1589       int c, lockCount = guiApp.lockMutex.lockCount;
1590       for(c = 0; c < lockCount; c++)
1591          guiApp.lockMutex.Release();
1592
1593       oldIcon = (HICON)SendMessage(window.windowHandle, WM_GETICON, ICON_BIG, 0);
1594 #ifdef _WIN64
1595       if(oldIcon && oldIcon != (HICON)GetClassLongPtr(window.windowHandle, GCLP_HICON))
1596 #else
1597       if(oldIcon && oldIcon != (HICON)GetClassLong(window.windowHandle, GCL_HICON))
1598 #endif
1599          DestroyIcon(oldIcon);
1600
1601         ShowWindow(window.windowHandle, SW_HIDE);
1602
1603 #ifdef _WIN64
1604       SetWindowLongPtr(window.windowHandle, GWLP_USERDATA, (int64)null);
1605 #else
1606       SetWindowLong(window.windowHandle, GWL_USERDATA, 0);
1607 #endif
1608       DestroyWindow(window.windowHandle);
1609
1610       for(c = 0; c < lockCount; c++)
1611          guiApp.lockMutex.Wait();
1612
1613       window.windowHandle = null;
1614    }
1615
1616    // -- Window manipulation ---
1617
1618    void SetRootWindowCaption(Window window, const char * name)
1619    {
1620       uint16 * text = UTF8toUTF16(name, null);
1621       guiApp.Unlock();
1622       SetWindowText(window.windowHandle, text);
1623       guiApp.Lock();
1624       delete text;
1625    }
1626
1627    void PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize)
1628    {
1629       int flags = SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS;
1630
1631       if(!window.systemParent && !fullScreenMode)
1632       {
1633          x += desktopX;
1634          y += desktopY;
1635       }
1636
1637       if(!move) flags |= SWP_NOMOVE;
1638       if(!resize) flags |= SWP_NOSIZE;
1639
1640       /*if(move && resize)
1641       {
1642          flags |= SWP_NOMOVE;
1643          SetWindowPos(window.windowHandle, null, x, y, w, h, flags);
1644          flags &=~SWP_NOMOVE;
1645          flags |= SWP_NOSIZE;
1646       }*/
1647       if(!window.nativeDecorations || window.state != maximized || !window.visible || guiApp.modeSwitching)
1648          SetWindowPos(window.windowHandle, null, x, y, w, h, flags);
1649    }
1650
1651    void OrderRootWindow(Window window, bool topMost)
1652    {
1653       SetWindowPos(window.windowHandle, topMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0,0,0,0,
1654          SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOSIZE|SWP_NOREDRAW);
1655    }
1656
1657    void SetRootWindowColor(Window window)
1658    {
1659       if(window.alphaBlend && window.display.pixelFormat == pixelFormat888)
1660       {
1661          /*if(A(window.background) == 255)
1662          {
1663             if((style & WS_EX_LAYERED) == WS_EX_LAYERED)
1664                SetWindowLong(window.windowHandle, GWL_EXSTYLE, style &~WS_EX_LAYERED);
1665          }
1666          else*/
1667          {
1668 #ifndef ECERE_NOBLENDING
1669             DWORD style = GetWindowLong(window.windowHandle, GWL_EXSTYLE);
1670             if((style & WS_EX_LAYERED) != WS_EX_LAYERED)
1671                SetWindowLong(window.windowHandle, GWL_EXSTYLE, style | WS_EX_LAYERED);
1672 #endif
1673             // SetLayeredWindowAttributes(window.windowHandle, 0, 255 /*Max(A(window.background),1)*/, LWA_ALPHA);
1674          }
1675       }
1676    }
1677
1678    void OffsetWindow(Window window, int * x, int * y)
1679    {
1680       if(window.systemParent)
1681       {
1682          POINT point = {*x,*y};
1683          ClientToScreen(GetParent(window.windowHandle), &point);
1684          *x = point.x;
1685          *y = point.y;
1686       }
1687    }
1688
1689    void UpdateRootWindow(Window window)
1690    {
1691       UpdateWindow(window.windowHandle);
1692    }
1693
1694    void SetRootWindowState(Window window, WindowState state, bool visible)
1695    {
1696       if(visible)
1697       {
1698          WindowState curState = window.state;
1699          *&window.state = state;
1700          switch(state)
1701          {
1702             case maximized:
1703             case normal:
1704                SmartShowWindow(window.windowHandle, window.nativeDecorations ? state : normal, (window.active || window.creationActivation == activate) && !externalDisplayChange);
1705                break;
1706             case minimized:
1707                ShowWindow(window.windowHandle, SW_MINIMIZE);
1708                break;
1709          }
1710          *&window.state = curState;
1711       }
1712       else
1713       {
1714          ShowWindow(window.windowHandle, SW_HIDE);
1715       }
1716    }
1717
1718    void ActivateRootWindow(Window window)
1719    {
1720       if(!externalDisplayChange)
1721          SetForegroundWindow(window.windowHandle);
1722    }
1723
1724    void FlashRootWindow(Window window)
1725    {
1726       HWND hwnd = window.windowHandle;
1727       FLASHWINFO flashInfo = { 0 };
1728       Window master = window.master, rootWindow = (master && master != guiApp.desktop) ? master.rootWindow : null;
1729       if(!window.style.showInTaskBar && rootWindow && (window._isModal || window.style.interim))
1730          hwnd = rootWindow.windowHandle;
1731
1732       flashInfo.cbSize = sizeof(FLASHWINFO);
1733       flashInfo.hwnd = hwnd;
1734       flashInfo.uCount = 1;
1735       flashInfo.dwFlags = FLASHW_TRAY; // FLASHW_ALL;
1736       guiApp.Unlock();
1737       FlashWindowEx((void *)&flashInfo);
1738       guiApp.Lock();
1739    }
1740
1741    // --- Mouse-based window movement ---
1742    void StartMoving(Window window, int x, int y, bool fromKeyBoard)
1743    {
1744       if(!fullScreenMode && !window.systemParent)
1745          // Commented out for Chess game because AI thread takes over the moving of main window... Still required?
1746          //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
1747          ; //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
1748       if(fromKeyBoard)
1749       {
1750          SetWindowPos(window.windowHandle, HWND_TOPMOST, 0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
1751          mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
1752          if(!window.stayOnTop)
1753             SetWindowPos(window.windowHandle, HWND_NOTOPMOST, 0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
1754       }
1755    }
1756
1757    void StopMoving(Window window)
1758    {
1759       if(!fullScreenMode && !window.systemParent)
1760          SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
1761    }
1762
1763    // -- Mouse manipulation ---
1764
1765    void GetMousePosition(int *x, int *y)
1766    {
1767       POINT point;
1768       GetCursorPos(&point);
1769       *x = point.x;
1770       *y = point.y;
1771    }
1772
1773    void SetMousePosition(int x, int y)
1774    {
1775       SetCursorPos(x, y);
1776    }
1777
1778    void SetMouseRange(Window window, Box box)
1779    {
1780       ClipCursor((RECT *) box);
1781    }
1782
1783    void SetMouseCapture(Window window)
1784    {
1785       if(window)
1786          SetCapture(window.windowHandle);
1787       else
1788          ReleaseCapture();
1789    }
1790
1791    // -- Mouse cursor ---
1792
1793    void SetMouseCursor(Window window, SystemCursor cursor)
1794    {
1795       if(lastCursor != cursor)
1796       {
1797          lastCursor = cursor;
1798          SetCursor((cursor == (SystemCursor)-1) ? null : systemCursors[cursor]);
1799       }
1800    }
1801
1802    // --- Caret ---
1803
1804    void SetCaret(int x, int y, int size)
1805    {
1806
1807    }
1808
1809    // --- Clipboard manipulation ---
1810
1811    void ClearClipboard()
1812    {
1813         if(OpenClipboard(null))
1814         {
1815          EmptyClipboard();
1816            CloseClipboard();
1817       }
1818    }
1819
1820    bool AllocateClipboard(ClipBoard clipBoard, uint size)
1821    {
1822       bool result = false;
1823       clipBoard.text = new byte[size];
1824       result = true;
1825       return result;
1826    }
1827
1828    bool SaveClipboard(ClipBoard clipBoard)
1829    {
1830       bool result = false;
1831       if(clipBoard.text)
1832       {
1833          int wordCount;
1834          uint16 * u16text = UTF8toUTF16(clipBoard.text, &wordCount);
1835          wordCount++;
1836          clipBoard.handle = GlobalAlloc(GHND | GMEM_DDESHARE, wordCount * 2);
1837          if(clipBoard.handle)
1838          {
1839             uint16 * text = GlobalLock(clipBoard.handle);
1840             if(text)
1841             {
1842                memcpy(text, u16text, wordCount * 2);
1843                GlobalUnlock(clipBoard.handle);
1844                    if(OpenClipboard(null))
1845                    {
1846                   EmptyClipboard();
1847                       if(SetClipboardData(CF_UNICODETEXT, clipBoard.handle))
1848                   {
1849                          CloseClipboard();
1850                      result= true;
1851                   }
1852                }
1853             }
1854             if(!result)
1855                GlobalFree(clipBoard.handle);
1856          }
1857          delete u16text;
1858       }
1859       return result;
1860    }
1861
1862    bool LoadClipboard(ClipBoard clipBoard)
1863    {
1864       bool result = false;
1865         if(OpenClipboard(null))
1866         {
1867          if((clipBoard.handle = GetClipboardData(CF_UNICODETEXT)))
1868          {
1869             uint16 * u16text = GlobalLock(clipBoard.handle);
1870             if(u16text)
1871             {
1872                clipBoard.text = UTF16toUTF8(u16text);
1873                result = true;
1874                GlobalUnlock(clipBoard.handle);
1875             }
1876          }
1877          CloseClipboard();
1878       }
1879       return result;
1880    }
1881
1882    void UnloadClipboard(ClipBoard clipBoard)
1883    {
1884       delete clipBoard.text;
1885    }
1886
1887    // --- State based input ---
1888
1889    bool AcquireInput(Window window, bool state)
1890    {
1891    #ifndef ECERE_NODINPUT
1892       if(dInput || InitDirectInput())
1893       {
1894          AcquireDirectInput(window.windowHandle, state);
1895          return true;
1896       }
1897    #endif
1898       return false;
1899    }
1900
1901    bool GetMouseState(MouseButtons * buttons, int * x, int * y)
1902    {
1903       bool result = false;
1904    #ifndef ECERE_NODINPUT
1905       DIMOUSESTATE dims = {0};
1906
1907       if(acquiredWindow && directMouse)
1908       {
1909          if(directMouse->lpVtbl->GetDeviceState(directMouse, sizeof(DIMOUSESTATE), &dims ))
1910          {
1911             FillBytes(&dims, 0, sizeof(dims));
1912             directMouse->lpVtbl->Acquire(directMouse);
1913          }
1914          result = true;
1915       }
1916       /*  We don't really want this...
1917       else
1918       {
1919          if(GetAsyncKeyState(VK_LBUTTON))
1920             dims.rgbButtons[0] |= 0x80;
1921          if(GetAsyncKeyState(VK_RBUTTON))
1922             dims.rgbButtons[1] |= 0x80;
1923          if(GetAsyncKeyState(VK_MBUTTON))
1924             dims.rgbButtons[2] |= 0x80;
1925       }
1926       */
1927
1928       if(x)*x = dims.lX;
1929       if(y)*y = dims.lY;
1930       if(dims.lZ)
1931       {
1932 #ifdef _WIN64
1933          Window window = (Window)GetWindowLongPtr(acquiredWindow, GWLP_USERDATA);
1934 #else
1935          Window window = (Window)GetWindowLong(acquiredWindow, GWL_USERDATA);
1936 #endif
1937          ProcessKeyMessage(window, WM_MOUSEWHEEL, ((uint16)(short)dims.lZ) << 16, 0, 0);
1938       }
1939       if(buttons)
1940       {
1941          *buttons = MouseButtons {
1942              left = (dims.rgbButtons[0] & 0x80) ? true : false,
1943              right = (dims.rgbButtons[1] & 0x80) ? true : false,
1944              middle = (dims.rgbButtons[2] & 0x80) ? true : false };
1945       }
1946    #endif
1947
1948       return result;
1949    }
1950
1951    bool GetJoystickState(int device, Joystick joystick)
1952    {
1953       bool result = false;
1954    #ifndef ECERE_NODINPUT
1955       if(joystick != null)
1956       {
1957          DIJOYSTATE dijs = {0};
1958    #ifndef ECERE_NOJOYSTICK
1959          if(acquiredWindow && device < numJoysticks)
1960          {
1961             if(directJoysticks[device])
1962             {
1963                directJoysticks[device]->lpVtbl->Poll(directJoysticks[device]);
1964                if(directJoysticks[device]->lpVtbl->GetDeviceState(directJoysticks[device], sizeof(DIJOYSTATE), &dijs ))
1965                   directJoysticks[device]->lpVtbl->Acquire(directJoysticks[device]);
1966                result = true;
1967             }
1968          }
1969    #endif
1970          joystick.x = dijs.lX;
1971          joystick.y = dijs.lY;
1972          joystick.z = dijs.lZ;
1973          joystick.rx = dijs.lRx;
1974          joystick.ry = dijs.lRy;
1975          joystick.rz = dijs.lRz;
1976          joystick.buttons =
1977               ((dijs.rgbButtons[0] & 0x80) ? JOY_BUTTON1 : 0)
1978             | ((dijs.rgbButtons[1] & 0x80) ? JOY_BUTTON2 : 0)
1979             | ((dijs.rgbButtons[2] & 0x80) ? JOY_BUTTON3 : 0)
1980             | ((dijs.rgbButtons[3] & 0x80) ? JOY_BUTTON4 : 0);
1981       }
1982    #endif
1983       return result;
1984    }
1985
1986    bool GetKeyState(Key key)
1987    {
1988       bool keyState = false;
1989       if(key < 256 || key == alt || key == shift || key == control)
1990       {
1991          uint ks = 0;
1992          if(key == alt)
1993             ks = GetAsyncKeyState(VK_MENU);
1994          else if(key == control)
1995             ks = GetAsyncKeyState(VK_CONTROL);
1996          else if(key == shift)
1997             ks = GetAsyncKeyState(VK_SHIFT);
1998          else if(key2VK[key])
1999             ks = GetAsyncKeyState(key2VK[key]);
2000          keyState = (ks & 0x80000) ? true : false;
2001       }
2002       else if(key == capsState)
2003          keyState = (::GetKeyState(VK_CAPITAL) & 0x00000001) != 0;
2004       else if(key == numState)
2005          keyState = (::GetKeyState(VK_NUMLOCK) & 0x00000001) != 0;
2006       else if(key == scrollState)
2007          keyState = (::GetKeyState(VK_SCROLL) & 0x00000001) != 0;
2008       return keyState;
2009    }
2010
2011    bool SetIcon(Window window, BitmapResource resource)
2012    {
2013       HICON icon = null;
2014       HICON oldIcon = (HICON)SendMessage(window.windowHandle, WM_GETICON, ICON_BIG, 0);
2015
2016       // Dialogs Inherit master's icon if none set
2017       if(!window.style.showInTaskBar && window.hasClose)
2018       {
2019          Window master = window.master;
2020          while(master && !resource)
2021          {
2022             Window rootWindow = (master && master != guiApp.desktop) ? master.rootWindow : null;
2023             if(rootWindow && rootWindow.icon)
2024                resource = rootWindow.icon;
2025             else
2026                master = master.master;
2027          }
2028       }
2029
2030       // WARNING -- putting this here as it is right after CreateRootWindow
2031       // Take out Layered flag if we're not in 24 bit
2032       {
2033          if(window.alphaBlend && window.display.pixelFormat != pixelFormat888)
2034          {
2035 #ifndef ECERE_NOBLENDING
2036             DWORD style = GetWindowLong(window.windowHandle, GWL_EXSTYLE);
2037             style &= ~WS_EX_LAYERED;
2038             SetWindowLong(window.windowHandle, GWL_EXSTYLE, style);
2039 #endif
2040          }
2041       }
2042
2043 #ifdef _WIN64
2044       if(oldIcon && oldIcon != (HICON)GetClassLongPtr(window.windowHandle, GCLP_HICON))
2045 #else
2046       if(oldIcon && oldIcon != (HICON)GetClassLong(window.windowHandle, GCL_HICON))
2047 #endif
2048       {
2049          DestroyIcon(oldIcon);
2050       }
2051
2052       if(resource)
2053       {
2054          Bitmap bitmap { };
2055          if(bitmap.Load(resource.fileName, null, null))
2056          {
2057             Bitmap and { };
2058             PixelFormat format = window.display.pixelFormat;
2059             int bits = GetDepthBits(format);
2060             bool blend;
2061
2062             bitmap.Convert(null, pixelFormat888, null);
2063             and.Allocate(null, (bitmap.width+7/8), bitmap.height, 0, pixelFormat8, false);
2064
2065             blend = bits == 32 || bitmap.pixelFormat != pixelFormat888;
2066
2067             {
2068                byte * picture = and.picture;
2069                int c = 0;
2070                int b = 0;
2071                uint size = bitmap.height * bitmap.width;
2072                while(c < size)
2073                {
2074                   int m = 0;
2075                   byte mask = 0;
2076                   while(m < 8 && c < size)
2077                   {
2078                      mask <<= 1;
2079                      mask |= blend ? (!((ColorAlpha *)bitmap.picture)[c].a) : (((ColorAlpha *)bitmap.picture)[c].a <= 192);
2080                      c++;
2081                      m++;
2082                   }
2083                   picture[b++] = mask;
2084                }
2085                c = 0;
2086                while(c < size)
2087                {
2088                   ColorAlpha color = ((ColorAlpha *)bitmap.picture)[c];
2089                   if(blend ? (!color.a) : (color.a <= 192))
2090                   {
2091                      color.color = { 0, 0, 0 };
2092                      ((ColorAlpha *)bitmap.picture)[c] = color;
2093                   }
2094                   c++;
2095                }
2096             }
2097             if(bits == 15) { bits = 16; format = pixelFormat565; };
2098             bitmap.Convert(null, format, null);
2099
2100             icon = CreateIcon(hInstance, bitmap.width, bitmap.height, 1, (byte)bits, and.picture, bitmap.picture);
2101             delete and;
2102          }
2103          delete bitmap;
2104       }
2105       SendMessage(window.windowHandle, WM_SETICON, ICON_BIG, (LPARAM)icon);
2106       SendMessage(window.windowHandle, WM_SETICON, ICON_SMALL, (LPARAM)icon);
2107       return true;
2108    }
2109
2110    void ::GetScreenArea(Window window, Box box)
2111    {
2112       HMONITOR monitor = MonitorFromWindow(window.windowHandle, MONITOR_DEFAULTTONEAREST);
2113       HMONITOR taskBarMonitor = MonitorFromWindow(startBar, MONITOR_DEFAULTTONEAREST);
2114       if(monitor)
2115       {
2116          MONITORINFO info = { 0 };
2117          info.cbSize = sizeof(MONITORINFO);
2118          GetMonitorInfo(monitor, &info);
2119          // box = { info.rcWork.left, info.rcWork.top, info.rcWork.right, info.rcWork.bottom };
2120          box = { info.rcMonitor.left, info.rcMonitor.top, info.rcMonitor.right-1, info.rcMonitor.bottom-1 };
2121
2122          if(taskBarMonitor == monitor)
2123          {
2124             if(taskBarPlacement.rcNormalPosition.top <= box.top && taskBarPlacement.rcNormalPosition.bottom >= box.bottom)
2125             {
2126                if(taskBarPlacement.rcNormalPosition.left <= box.left)
2127                {
2128                   if(taskBarState & ABS_AUTOHIDE)
2129                      box.left++;
2130                   else
2131                      box.left = taskBarPlacement.rcNormalPosition.right;
2132                }
2133                else if(taskBarState & ABS_AUTOHIDE)
2134                   box.right -= 1;
2135                else
2136                   box.right = taskBarPlacement.rcNormalPosition.left;
2137             }
2138             else if(taskBarPlacement.rcNormalPosition.left <= box.left && taskBarPlacement.rcNormalPosition.right >= box.right)
2139             {
2140                if(taskBarPlacement.rcNormalPosition.top <= box.top)
2141                {
2142                   if(taskBarState & ABS_AUTOHIDE)
2143                      box.top += 1;
2144                   else
2145                      box.top = taskBarPlacement.rcNormalPosition.bottom;
2146                }
2147                else if(taskBarState & ABS_AUTOHIDE)
2148                   box.bottom -= 1;
2149                else
2150                   box.bottom = taskBarPlacement.rcNormalPosition.top;
2151             }
2152          }
2153
2154          box.left -= desktopX;
2155          box.top -= desktopY;
2156          box.right -= desktopX;
2157          box.bottom -= desktopY;
2158       }
2159    }
2160 }
2161
2162 #endif