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