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