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