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