ecere/gui/Window: Prevent uninitialized values if base Window methods not overridden...
[sdk] / ecere / src / gui / Window.ec
index 3454741..5965634 100644 (file)
@@ -25,6 +25,10 @@ import "EditBox"
 import "DataBox"
 import "ToolTip"
 
+#if defined(__WIN32__)
+import "Win32Interface"
+#endif
+
 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
 import "Desktop3D"
 #endif
@@ -38,6 +42,37 @@ import "MessageBox"
 import "WindowList"
 import "i18n"
 
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
+#define property _property
+#define new _new
+#define class _class
+#define uint _uint
+
+#define Window    X11Window
+#define Cursor    X11Cursor
+#define Font      X11Font
+#define Display   X11Display
+#define Time      X11Time
+#define KeyCode   X11KeyCode
+#define Picture   X11Picture
+
+#include <X11/Xutil.h>
+
+#undef Window
+#undef Cursor
+#undef Font
+#undef Display
+#undef Time
+#undef KeyCode
+#undef Picture
+
+#undef uint
+#undef new
+#undef property
+#undef class
+
+#endif
+
 // Had to define this here for native decorations support, because the menu bar is part of total decoration's size, but not part of the system decorations
 #ifdef HIGH_DPI
 define skinMenuHeight = 40;
@@ -140,7 +175,7 @@ private struct FastList
       {
          int c;
          int newSize;
-               
+
          if(size)
          {
             newSize = (size + (size >> 1));
@@ -255,10 +290,10 @@ public /*private */struct Extent : OldList //FastList
 
       temp.Copy(this);
       Empty();
-      
+
       for(extentBox = (BoxItem)temp.first; extentBox; extentBox = (BoxItem)extentBox.next)
       {
-         if(extentBox.box.left < box.right && extentBox.box.right > box.left && 
+         if(extentBox.box.left < box.right && extentBox.box.right > box.left &&
             extentBox.box.top < box.bottom && extentBox.box.bottom > box.top)
          {
             // Top box
@@ -266,7 +301,7 @@ public /*private */struct Extent : OldList //FastList
             {
                Box newBox
                {
-                  extentBox.box.left, extentBox.box.top, 
+                  extentBox.box.left, extentBox.box.top,
                   extentBox.box.right, Min(extentBox.box.bottom, box.top -1)
                };
                AddBox(newBox);
@@ -324,14 +359,14 @@ public /*private */struct Extent : OldList //FastList
       // First pass: check if this box is not already covered by one of the extent's box
       for(extentBox = (BoxItem)this.first; extentBox; extentBox = (BoxItem)extentBox.next)
       {
-         if(extentBox.box.left <= box.left && extentBox.box.right >= box.right && 
+         if(extentBox.box.left <= box.left && extentBox.box.right >= box.right &&
             extentBox.box.top <= box.top && extentBox.box.bottom >= box.bottom)
          {
             // No change
             return;
          }
       }
-        
+
       // Second pass: only keep boxes not completely covered in the new box
       for(extentBox = (BoxItem)this.first; extentBox; extentBox = next)
       {
@@ -377,7 +412,7 @@ public /*private */struct Extent : OldList //FastList
                }
             }
          }
-         
+
          // Else, add it
          if(!extentBox)
             AddBox(box);
@@ -411,7 +446,7 @@ public /*private */struct Extent : OldList //FastList
 
    void Exclusion(Extent b, Extent temp)
    {
-      BoxItem extentBox;   
+      BoxItem extentBox;
       for(extentBox = (BoxItem)b.first; extentBox; extentBox = (BoxItem)extentBox.next)
          ExcludeBox(extentBox.box, temp);
    }
@@ -436,7 +471,7 @@ private define CASCADE_SPACE = 16;
 
 private class ScrollFlags
 {
-   bool snapX:1, snapY:1, dontHide:1;   
+   bool snapX:1, snapY:1, dontHide:1;
 };
 
 public class BorderBits { public: bool contour:1, fixed:1, sizable:1, deep:1, bevel:1, thin:1; };
@@ -487,15 +522,24 @@ private class HotKeySlot : struct
    Key key;
 };
 
+public struct TouchPointerInfo
+{
+   int id;
+   Point point;
+   float size, pressure;
+};
+
+public enum TouchPointerEvent { move, up, down, pointerUp, pointerDown };
+
 public class Window
 {
 private:
-   class_data char * icon;
+   class_data const char * icon;
    class_no_expansion
    class_default_property caption;
    // class_initialize GuiApplication::Initialize;
    class_designer FormDesigner;
-   class_property char * icon
+   class_property const char * icon
    {
       set { class_data(icon) = value; }
       get { return class_data(icon); }
@@ -527,7 +571,7 @@ private:
             }
          }
       }
-      
+
       //tempExtents[0] = { /*first = -1, last = -1, free = -1*/ };
       //tempExtents[1] = { /*first = -1, last = -1, free = -1*/ };
       //tempExtents[2] = { /*first = -1, last = -1, free = -1*/ };
@@ -544,7 +588,7 @@ private:
       maxSize = Size { MAXINT, MAXINT };
       background = white;
       foreground = black;
-      
+
       //style.isActiveClient = true;
       mergeMenus = true;
       autoCreate = true;
@@ -568,6 +612,27 @@ private:
       OldLink slave;
       ResPtr ptr;
 
+#if !defined(__EMSCRIPTEN__)
+      if(fileMonitor)
+      {
+         int i, lockCount = guiApp.lockMutex.lockCount;
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
+         if(xGlobalDisplay)
+            XUnlockDisplay(xGlobalDisplay);
+#endif
+
+         for(i = 0; i < lockCount; i++)
+            guiApp.lockMutex.Release();
+         delete fileMonitor;
+         for(i = 0; i < lockCount; i++)
+            guiApp.lockMutex.Wait();
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
+         if(xGlobalDisplay)
+            XLockDisplay(xGlobalDisplay);
+#endif
+      }
+#endif
+
       if(parent)
       {
          stopwatching(parent, font);
@@ -578,7 +643,7 @@ private:
       }
 
       if(!destroyed)
-      { 
+      {
          // Prevent destructor from being called again...
          incref this;
          incref this;
@@ -606,7 +671,7 @@ private:
       delete order;
       /////////////////////////////////
 
-      while(ptr = resources.first)
+      while((ptr = resources.first))
       {
          delete ptr.resource;
          resources.Delete(ptr);
@@ -625,7 +690,7 @@ private:
          *&child.parent = null;
       }
 
-      while(slave = slaves.first)
+      while((slave = slaves.first))
       {
          // Don't want property here
          *&((Window)slave.data).master = null;
@@ -651,7 +716,9 @@ private:
       delete statusBar;
 
       OnDestroyed();
+#if !defined(__EMSCRIPTEN__)
       delete mutex;
+#endif
       delete icon;
 
       if(((subclass(Window))_class).pureVTbl)
@@ -688,23 +755,25 @@ private:
          tempExtents[3].Free(null);
          delete tempExtents;
       }
+
+      delete controller;
    }
 
 //#if !defined(ECERE_VANILLA)
-   char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
+   const char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
    {
       if(this == activeDesigner)
          return "(Desktop)";
-      else 
+      else
       {
-         char * name = property::name;
+         const char * name = property::name;
          return name ? name : "";
       }
    }
 //#endif
 
 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
-   bool OnGetDataFromString(char * string)
+   bool OnGetDataFromString(const char * string)
    {
       FormDesigner designer = (FormDesigner)activeDesigner.classDesigner;
       if(string[0])
@@ -743,7 +812,7 @@ private:
       {
          int x = absPosition.x + clientStart.x;
          int y = absPosition.y + clientStart.y;
-         if(rootWindow.nativeDecorations && rootWindow.windowHandle)
+         if(rootWindow.nativeDecorations && rootWindow.windowHandle && !is3D)
          {
             x -= rootWindow.clientStart.x;
             y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
@@ -755,13 +824,21 @@ private:
 
             if(rootWindow.is3D)
             {
-               x += rootWindow.parent.clientStart.x;
-               y += rootWindow.parent.clientStart.y;
+               int dx = rootWindow.parent.parent.clientStart.x;
+               int dy = rootWindow.parent.parent.clientStart.y;
+               if(!rootWindow.parent.nativeDecorations)
+               {
+                  dx += rootWindow.parent.clientStart.x;
+                  dy += rootWindow.parent.clientStart.y;
+               }
+               x += dx;
+               y += dy;
+
                /*
-               mox.left += rootWindow.parent.clientStart.x;
-               mox.top += rootWindow.parent.clientStart.y;
-               mox.right += rootWindow.parent.clientStart.x;
-               mox.bottom += rootWindow.parent.clientStart.y;
+               mox.left += dx;
+               mox.top += dy;
+               mox.right += dx;
+               mox.bottom += dy;
                */
             }
          }
@@ -791,24 +868,34 @@ private:
       {
          int x = absPosition.x;
          int y = absPosition.y;
-         if(rootWindow.nativeDecorations && rootWindow.windowHandle)
+         if(rootWindow.nativeDecorations && rootWindow.windowHandle && !is3D)
          {
             x -= rootWindow.clientStart.x;
             y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
          }
+#if !defined(__EMSCRIPTEN__)
          if(!guiApp.fullScreenMode || is3D)
+#endif
          {
             x -= rootWindow.absPosition.x;
             y -= rootWindow.absPosition.y;
             if(rootWindow.is3D)
             {
-               x += rootWindow.parent.clientStart.x;
-               y += rootWindow.parent.clientStart.y;
+               int dx = rootWindow.parent.parent.clientStart.x;
+               int dy = rootWindow.parent.parent.clientStart.y;
+               if(!rootWindow.parent.nativeDecorations)
+               {
+                  dx += rootWindow.parent.clientStart.x;
+                  dy += rootWindow.parent.clientStart.y;
+               }
+               x += dx;
+               y += dy;
+
                /*
-               mox.left += rootWindow.parent.clientStart.x;
-               mox.top += rootWindow.parent.clientStart.y;
-               mox.right += rootWindow.parent.clientStart.x;
-               mox.bottom += rootWindow.parent.clientStart.y;
+               mox.left += dx;
+               mox.top += dy;
+               mox.right += dx;
+               mox.bottom += dy;
                */
             }
          }
@@ -949,12 +1036,12 @@ private:
       int ph = parent ? parent.clientSize.h : 0;
       int w = sizeAnchor.size.w, h = sizeAnchor.size.h;
       int x = anchor.left.distance, y = anchor.top.distance;
-      float ex, ey;
+      float ex = 0, ey = 0;
       MinMaxValue ew = 0, eh = 0;
       int numCascade;
       float cascadeW, cascadeH;
       int numTiling;
-      int tilingW, tilingH, tilingSplit, tilingLastH;
+      int tilingW, tilingH, tilingSplit, tilingLastH = 0;
       int addX = 0, addY = 0;
 
       if(parent && rootWindow == this && guiApp && guiApp.interfaceDriver)
@@ -981,7 +1068,7 @@ private:
             ph = vph = box.bottom - box.top + 1;
          }
       }
-      
+
       if(!parent)
       {
          *ow = w;
@@ -1028,7 +1115,7 @@ private:
 
          if(anchor.top.type)
          {
-            SNAPUP(y, textCellH);   
+            SNAPUP(y, textCellH);
          }
          else if(anchor.bottom.type)
          {
@@ -1050,7 +1137,7 @@ private:
          int loX = 0, loY = 0, hiX = pw, hiY = ph;
          for(win = parent.children.first; win; win = win.next)
          {
-            if(!win.isActiveClient && win.visible)
+            if(!win.nonClient && !win.isActiveClient && win.visible)
             {
                Size size = win.size;
                Point pos = win.position;
@@ -1077,7 +1164,7 @@ private:
          pw = hiX - loX;
          ph = hiY - loY;
 
-         if(parent.sbv && !parent.sbv.style.hidden) 
+         if(parent.sbv && !parent.sbv.style.hidden)
             pw += guiApp.currentSkin.VerticalSBW();
          if(parent.sbh && !parent.sbh.style.hidden)
             ph += guiApp.currentSkin.HorizontalSBH();
@@ -1096,13 +1183,23 @@ private:
             if(parent.numIcons) ph -= guiApp.textMode ? 16 : 24;
             if(anchor.left.type == vTiled)
             {
-               tilingH = (int)sqrt(numTiling);
-               tilingW = numTiling / tilingH;
+               if(numTiling)
+               {
+                  tilingH = (int)sqrt(numTiling);
+                  tilingW = numTiling / tilingH;
+               }
+               else
+                  tilingH = tilingW = 0;
             }
             else
             {
-               tilingW = (int)sqrt(numTiling);
-               tilingH = numTiling / tilingW;
+               if(numTiling)
+               {
+                  tilingW = (int)sqrt(numTiling);
+                  tilingH = numTiling / tilingW;
+               }
+               else
+                  tilingH = tilingW = 0;
             }
 
             leftOver = numTiling - tilingH * tilingW;
@@ -1114,19 +1211,30 @@ private:
             else
                tilingSplit = numTiling;
 
-            if(positionID >= tilingSplit)
+            if(tilingW && tilingH)
             {
-               x = xOffset + pw * (tilingSplit / tilingH + (positionID - tilingSplit) / tilingLastH)/tilingW;
-               y = yOffset + ph * ((positionID - tilingSplit) % tilingLastH) / tilingLastH;
-               x2 = xOffset + pw * (tilingSplit/tilingH + (positionID - tilingSplit) / tilingLastH + 1)/tilingW;
-               y2 = yOffset + ph * (((positionID - tilingSplit) % tilingLastH) + 1) / tilingLastH;
+               if(positionID >= tilingSplit)
+               {
+                  x = xOffset + pw * (tilingSplit / tilingH + (positionID - tilingSplit) / tilingLastH)/tilingW;
+                  y = yOffset + ph * ((positionID - tilingSplit) % tilingLastH) / tilingLastH;
+                  x2 = xOffset + pw * (tilingSplit/tilingH + (positionID - tilingSplit) / tilingLastH + 1)/tilingW;
+                  y2 = yOffset + ph * (((positionID - tilingSplit) % tilingLastH) + 1) / tilingLastH;
+               }
+               else
+               {
+                  x = xOffset + pw * (positionID / tilingH) / tilingW;
+                  y = yOffset + ph * (positionID % tilingH) / tilingH;
+                  x2 = xOffset + pw * (positionID / tilingH + 1) / tilingW;
+                  y2 = yOffset + ph * ((positionID % tilingH) + 1) / tilingH;
+               }
             }
             else
             {
-               x = xOffset + pw * (positionID / tilingH) / tilingW;
-               y = yOffset + ph * (positionID % tilingH) / tilingH;
-               x2 = xOffset + pw * (positionID / tilingH + 1) / tilingW;
-               y2 = yOffset + ph * ((positionID % tilingH) + 1) / tilingH;
+               // How can this happen? From ec2 parsing test
+               x = 0;
+               y = 0;
+               x2 = 0;
+               y2 = 0;
             }
             if(guiApp.textMode)
             {
@@ -1143,7 +1251,7 @@ private:
       {
          if(sizeAnchor.isClientW) w += ew;
          if(sizeAnchor.isClientH) h += eh;
-         
+
          if(anchor.left.type == offset)
             x = anchor.left.distance;
          else if(anchor.left.type == relative)
@@ -1168,8 +1276,8 @@ private:
          {
             switch(anchor.right.type)
             {
-               case relative: 
-                  ex = pw * (1.0f-anchor.right.percent); 
+               case relative:
+                  ex = pw * (1.0f-anchor.right.percent);
                   w = Max((int)(ex + 0.5) - x, 0);
                   break;
                case offset:
@@ -1195,7 +1303,7 @@ private:
       }
 
       w -= ew;
-      h -= eh; 
+      h -= eh;
 
       if(state == normal /*|| state == Hidden*/)
       {
@@ -1209,12 +1317,12 @@ private:
          w = Min(w, maxSize.w);
          h = Min(h, maxSize.h);
 
-         if((sizeAnchor.isClientW || !w || (anchor.left.type && anchor.right.type)) && reqScrollArea.h > h /*&& w*/ && sbv) 
+         if((sizeAnchor.isClientW || !w || (anchor.left.type && anchor.right.type)) && reqScrollArea.h > h /*&& w*/ && sbv)
          {
             if(w) w -= guiApp.currentSkin.VerticalSBW();
             addSbV = true;
          }
-         if((sizeAnchor.isClientH || !h ||  (anchor.top.type && anchor.bottom.type)) && reqScrollArea.w > w /*&& h*/ && sbh) 
+         if((sizeAnchor.isClientH || !h ||  (anchor.top.type && anchor.bottom.type)) && reqScrollArea.w > w /*&& h*/ && sbh)
          {
             if(h) h -= guiApp.currentSkin.HorizontalSBH();
             addSbH = true;
@@ -1226,7 +1334,7 @@ private:
             h = clientSize.h;
          }
 
-         if((addSbV)) // || reqScrollArea.h > h) && sbv) 
+         if((addSbV)) // || reqScrollArea.h > h) && sbv)
             w += guiApp.currentSkin.VerticalSBW();
          if((addSbH)) // || reqScrollArea.w > w) && sbh)
             h += guiApp.currentSkin.HorizontalSBH();
@@ -1241,7 +1349,7 @@ private:
       }
 
       w += ew;
-      h += eh; 
+      h += eh;
 
       if(guiApp.textMode)
       {
@@ -1254,9 +1362,9 @@ private:
          if(parent.numIcons) ph -= guiApp.textMode ? 16 : 24;
 
          numCascade = Min(
-            (pw - w) / CASCADE_SPACE, 
+            (pw - w) / CASCADE_SPACE,
             (ph - h) / CASCADE_SPACE);
-         
+
          if(guiApp.textMode)
          {
                int cascW, cascH;
@@ -1302,7 +1410,7 @@ private:
                if(anchor.vert.type == middleRelative)
                   y = (int)(vph * (0.5 + anchor.vert.percent) - h / 2);
                else
-                  y = vph / 2 + anchor.vert.distance - h / 2;      
+                  y = vph / 2 + anchor.vert.distance - h / 2;
             }
             else
                y = (int)(ey - h);
@@ -1348,13 +1456,13 @@ private:
          int y = caretPos.y - scroll.y;
 
          if((erase || this.caretSize) &&
-            x >= clientArea.left && x <= clientArea.right && 
+            x >= clientArea.left && x <= clientArea.right &&
             y >= clientArea.top  && y <= clientArea.bottom)
          {
             if(!erase)
             {
                guiApp.interfaceDriver.SetCaret(
-                  x + absPosition.x + clientStart.x, 
+                  x + absPosition.x + clientStart.x,
                   y + absPosition.y + clientStart.y, this.caretSize);
                guiApp.caretEnabled = true;
             }
@@ -1453,7 +1561,7 @@ private:
                //if((w > reqScrollArea.w) || (h > reqScrollArea.w))
                {
                   int stepX = sbStep.x, stepY = sbStep.y;
-                  // Needed to make snapped down position match the skin's check of client area 
+                  // Needed to make snapped down position match the skin's check of client area
                   // against realvirtual
                   if(guiApp.textMode)
                   {
@@ -1483,7 +1591,7 @@ private:
       // Automatic MDI Client Scrolling Area Adjustment
       if(parent && !parent.noAutoScrollArea)
       {
-         if(modifyArea && modifyVirtArea /*&& !anchored*/ && (parent.sbv || parent.sbh) && 
+         if(modifyArea && modifyVirtArea /*&& !anchored*/ && (parent.sbv || parent.sbh) &&
             !style.dontScrollHorz && !style.dontScrollVert && !style.nonClient)
          {
             Window parent = this.parent;
@@ -1499,12 +1607,12 @@ private:
             else if(stateAnchor.bottom.type == none && stateAnchor.top.type == none)
                h = Max(h, Max(position.y, 0) + size.h);
 
-            if((w > parent.clientSize.w && w > parent.reqScrollArea.w) || 
+            if((w > parent.clientSize.w && w > parent.reqScrollArea.w) ||
                (h > parent.clientSize.h && h > parent.reqScrollArea.h))
             {
                /*bool resize = false;
                int stepX = parent.sbStep.x, stepY = parent.sbStep.y;
-               // Needed to make snapped down position match the skin's check of client area 
+               // Needed to make snapped down position match the skin's check of client area
                // against realvirtual
                if(guiApp.textMode)
                {
@@ -1523,12 +1631,12 @@ private:
                   parent.reqScrollArea.h = h;*/
 
                  // parent.UpdateScrollBars(true, true);
-                  parent.Position(parent.position.x, parent.position.y, parent.size.w, parent.size.h, 
+                  parent.Position(parent.position.x, parent.position.y, parent.size.w, parent.size.h,
                      false, true, true, true, false, false);
                   return;
                //}
             }
-            else 
+            else
                GetRidOfVirtualArea();
          }
       }
@@ -1602,6 +1710,8 @@ private:
       {
          if(!parent.noAutoScrollArea)
          {
+            // TODO: Review the logic of all this? Each child is going to reposition the parent?
+            /*
             Window child;
             bool found = false;
             for(child = children.first; child; child = child.next)
@@ -1616,11 +1726,12 @@ private:
                   }
                }
             }
-            //if(!found)
+            if(!found)
+            */
             {
                Window parent = this.parent;
                parent.Position(
-                  parent.position.x, parent.position.y, parent.size.w, parent.size.h, 
+                  parent.position.x, parent.position.y, parent.size.w, parent.size.h,
                   false, true, true, true, false, false);
                /*
                parent.SetScrollArea(0,0,true);
@@ -1642,7 +1753,7 @@ private:
       int oldCW = clientSize.w, oldCH = clientSize.h;
       bool clientResized, windowResized, windowMoved;
       Window child;
-      bool realResized = size.w != w || size.h != h;
+      //bool realResized = size.w != w || size.h != h;
 
       // TOCHECK: This wasn't in ecere.dll
       //if(!parent) return true;
@@ -1652,16 +1763,16 @@ private:
 
       // windowResized = realResized || force;
       windowResized = size.w != w || size.h != h || force;
-     
+
       if(rootWindow != this && display && !display.flags.flipping && scrolledPos.x != MININT)
       {
          if(style.nonClient)
          {
             Box box
-            { 
-               scrolledPos.x - parent.clientStart.x + this.box.left, scrolledPos.y - parent.clientStart.y + this.box.top, 
+            {
+               scrolledPos.x - parent.clientStart.x + this.box.left, scrolledPos.y - parent.clientStart.y + this.box.top,
                scrolledPos.x - parent.clientStart.x + this.box.right,
-               scrolledPos.y - parent.clientStart.y + this.box.bottom 
+               scrolledPos.y - parent.clientStart.y + this.box.bottom
             };
             parent.Update(box);
          }
@@ -1706,7 +1817,7 @@ private:
                   int x,y,w,h;
                   for(child = children.first; child; child = child.next)
                   {
-                     if(child.created && 
+                     if(child.created &&
                      ((child.stateAnchor.left.type != offset ||
                        child.stateAnchor.top.type != offset ||
                        child.stateAnchor.right.type != none ||
@@ -1751,7 +1862,11 @@ private:
                   if(display && !display.flags.memBackBuffer && changeRootWindow)
                      guiApp.interfaceDriver.PositionRootWindow(this, x, y, w, h, windowMoved, windowResized); //realResized);
 
-               if(!guiApp.fullScreenMode && this != guiApp.desktop && (windowResized || windowMoved))
+               if(
+#if !defined(__EMSCRIPTEN__)
+                  !guiApp.fullScreenMode &&
+#endif
+                  this != guiApp.desktop && (windowResized || windowMoved))
                   for(child = parent.children.first; child && child != this; child = child.next)
                      if(child.rootWindow)
                         guiApp.interfaceDriver.UpdateRootWindow(child.rootWindow);
@@ -1786,22 +1901,22 @@ private:
                else if(clientResized)
                   Update(clientArea);
                // --- Major Slow Down / Fix OpenGL Resizing Main Window Lag
-               
+
                /*
                if(!guiApp.fullScreenMode && !guiApp.modeSwitching && this == rootWindow)
                   UpdateDisplay();
                */
-               
+
                if(windowMoved || windowResized)
                {
                   display.Unlock();
                }
             }
-            if(guiApp.driver && changeRootWindow && windowHandle)
+            if(guiApp.driver && !guiApp.modeSwitching && changeRootWindow && windowHandle)
             {
                if(windowResized || windowMoved)
                   if(!display || display.flags.memBackBuffer)
-                     guiApp.interfaceDriver.PositionRootWindow(this, 
+                     guiApp.interfaceDriver.PositionRootWindow(this,
                         x, y, w, h, windowMoved, windowResized);
                guiApp.interfaceDriver.UpdateRootWindow(this);
             }
@@ -1816,7 +1931,9 @@ private:
                   child.display.width = display.width;
                   child.display.height = display.height;
                   child.display.driverData = display.driverData;
+#if !defined(__EMSCRIPTEN__)
                   child.display.mutex = null;
+#endif
                }
             }
          }
@@ -1839,9 +1956,9 @@ private:
       if(guiApp.currentSkin)
       {
          MinMaxValue cw = 0, ch = 0;
-         bool sbvVisible, sbhVisible;
-         int rangeH, rangeV;
-         int positionH, positionV;
+         bool sbvVisible = false, sbhVisible = false;
+         int rangeH = 0, rangeV = 0;
+         int positionH = 0, positionV;
 
          // First get client area with no respect to scroll bars
 
@@ -1973,7 +2090,7 @@ private:
             if(flag && (resizeH || resizeV) && fullThing)
             {
                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, false);
-               
+
                if(!positioned)
                {
                   positioned = true;
@@ -1981,7 +2098,7 @@ private:
                   positioned = false;
                }
             }
-      
+
             if(resizeH && sbh)
                sbh.visible = sbhVisible;
             if(resizeV && sbv)
@@ -2226,14 +2343,15 @@ private:
                Update(null);
                break;
             }
-         }         
+         }
       }
    }
 
    Window GetParentMenuBar()
    {
       Window menuBarParent;
-      for(menuBarParent = this; menuBarParent; menuBarParent = menuBarParent.parent)
+      if(formDesigner) return null;
+      for(menuBarParent = this ? parent : null; menuBarParent; menuBarParent = menuBarParent.parent)
       {
          if(menuBarParent.menuBar) return menuBarParent.menuBar;
          if(menuBarParent && !menuBarParent.isActiveClient)
@@ -2286,7 +2404,7 @@ private:
       {
          if(!sysButtons[2])
          {
-            sysButtons[2] = 
+            sysButtons[2] =
                Button
                {
                   parent, master = this,
@@ -2304,25 +2422,25 @@ private:
                sysButtons[2].hotKey = ctrlF4;
             sysButtons[2].Create();
          }
-         
+
          sysButtons[2].symbol = 'X';
          sysButtons[2].disabled = !style.hasClose;
       }
 
       if(hasMaxMin && parent)
       {
-         SkinBitmap skin;
+         //SkinBitmap skin;
          unichar symbol;
          bool (* method)(Window window, Button button, int x, int y, Modifiers mods);
-         if(state == maximized) 
+         if(state == maximized)
          {
-            skin = restore;
+            //skin = restore;
             method = RestoreButtonClicked;
             symbol = '\x12';
          }
          else
          {
-            skin = maximize;
+            //skin = maximize;
             method = MaximizeButtonClicked;
             symbol = '\x18';
          }
@@ -2344,18 +2462,18 @@ private:
 
       if(hasMaxMin && parent)
       {
-         SkinBitmap skin;
+         //SkinBitmap skin;
          unichar symbol;
          bool (* method)(Window window, Button button, int x, int y, Modifiers mods);
-         if (state == minimized) 
+         if (state == minimized)
          {
-            skin = restore;
+            //skin = restore;
             method = RestoreButtonClicked;
             symbol = '\x12';
          }
          else
          {
-            skin = minimize;
+            //skin = minimize;
             method = MinimizeButtonClicked;
             symbol = '\x19';
          }
@@ -2421,9 +2539,9 @@ private:
       }
       if(scrollBarChanged)
       {
-         SetScrollLineStep(sbStep.x, sbStep.y);   
+         SetScrollLineStep(sbStep.x, sbStep.y);
          UpdateScrollBars(true, true);
-      }   
+      }
       UpdateNonClient();
 
       if(scrollBarChanged)
@@ -2439,7 +2557,8 @@ private:
       {
          char caption[2048];
          FigureCaption(caption);
-         guiApp.interfaceDriver.SetRootWindowCaption(this, caption);
+         if(guiApp.interfaceDriver)
+            guiApp.interfaceDriver.SetRootWindowCaption(this, caption);
       }
       UpdateDecorations();
       if(parent)
@@ -2450,7 +2569,8 @@ private:
             {
                char caption[2048];
                parent.FigureCaption(caption);
-               guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
+               if(guiApp.interfaceDriver)
+                  guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
             }
             else
                parent.UpdateCaption();
@@ -2478,7 +2598,7 @@ private:
       if(menu)
       {
          MenuItem item;
-         bool disabled;
+         //bool disabled;
 
          if(menu)
             menu.Clean(this);
@@ -2493,17 +2613,16 @@ private:
                int id;
                for(id = 0, cycle = activeClient.cycle; cycle && id<10;)
                {
-                  MenuItem item;
                   Window document = cycle.data;
                   if(!document.style.nonClient && document.style.isActiveClient && document.visible)
                   {
                      char name[2048], caption[2048];
                      document.FigureCaption(caption);
                      sprintf(name, "%d %s", id+1, caption);
-                     windowMenu.AddDynamic(MenuItem 
-                        { 
-                           copyText = true, text = name, hotKey = Key { k1 + id }, id = id++, 
-                           NotifySelect = MenuWindowSelectWindow 
+                     windowMenu.AddDynamic(MenuItem
+                        {
+                           copyText = true, text = name, hotKey = Key { k1 + id }, id = id++,
+                           NotifySelect = MenuWindowSelectWindow
                         }, this, false);
                   }
                   cycle = cycle.next;
@@ -2511,13 +2630,13 @@ private:
                }
             }
          }
-         
+
          if((!previous && activeClient) || !activeClient)
          {
-            if(!activeClient)
+            /*if(!activeClient)
                disabled = true;
             else
-               disabled = false;
+               disabled = false;*/
             item = menu.FindItem(MenuWindowCloseAll, 0);
             if(item) item.disabled = false;
             item = menu.FindItem(MenuWindowNext, 0);
@@ -2534,7 +2653,7 @@ private:
             if(item) item.disabled = false;
             item = menu.FindItem(MenuWindowWindows, 0);
             if(item) item.disabled = false;
-         }      
+         }
 
          item = menu.FindItem(MenuFileClose, 0);
          if(item) item.disabled = !activeClient || !activeClient.style.hasClose;
@@ -2564,7 +2683,7 @@ private:
 
    void _ShowDecorations(Box box, bool post)
    {
-      if(rootWindow == this && nativeDecorations) return;
+      if(rootWindow == this && nativeDecorations && !is3D) return;
       if(visible && this != guiApp.desktop)
       {
          Surface surface = RedrawFull(box);
@@ -2572,7 +2691,7 @@ private:
          {
             char caption[2048];
             FigureCaption(caption);
-            
+
             if(post)
                ShowDecorations(captionFont.font,
                   surface,
@@ -2585,7 +2704,7 @@ private:
                   caption,
                   active, //parent.activeClient == this
                   guiApp.windowMoving == this);
-               
+
             delete surface;
          }
       }
@@ -2598,9 +2717,9 @@ private:
       if(!manageDisplay) { OnRedraw(null);return; }
       _ShowDecorations(refresh, false);
 
-      surface = Redraw(refresh);               
+      surface = Redraw(refresh);
       // Opaque background: just fill before EW_REDRAW (clear?)
-      if(surface) 
+      if(surface)
       {
          surface.SetBackground(background);
          surface.SetForeground(foreground);
@@ -2644,6 +2763,7 @@ private:
          // Default Settings
          surface.TextFont(usedFont.font);
          surface.TextOpacity(false);
+         surface.outlineColor = black;
 
          OnRedraw(surface);
 
@@ -2662,8 +2782,8 @@ private:
 
    void DrawOverChildren(Box refresh)
    {
-      Surface surface = Redraw(refresh);               
-      if(surface) 
+      Surface surface = Redraw(refresh);
+      if(surface)
       {
          // Default Settings
          surface.DrawingChar(' ');
@@ -2672,6 +2792,7 @@ private:
 
          surface.TextFont(usedFont.font);
          surface.TextOpacity(false);
+         surface.outlineColor = black;
 
          OnDrawOverChildren(surface);
 
@@ -2687,12 +2808,12 @@ private:
       Extent clipExtent { /*first = -1, last = -1, free = -1*/ };
 
       clipExtent.Copy(this.clipExtent);
-      
+
       for(child = children.last; child; child = child.prev)
       {
          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
          {
-            bool opaque = child.IsOpaque(); // TODO: acess background directly 
+            bool opaque = child.IsOpaque(); // TODO: acess background directly
             int dx = child.absPosition.x - absPosition.x, dy = child.absPosition.y - absPosition.y;
 
             child.clipExtent.Copy(clipExtent);
@@ -2707,7 +2828,7 @@ private:
                Box box { child.box.left + dx, child.box.top + dy, child.box.right + dx, child.box.bottom + dy };
                clipExtent.ExcludeBox(box, rootWindow.tempExtents[0]);
             }
-            
+
          }
       }
       // ??? Only do this for overlapped window or if parent has with clip children flag
@@ -2720,7 +2841,6 @@ private:
 
    void ComputeRenderAreaNonOpaque(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate)
    {
-      bool opaque = IsOpaque();
       Window child;
       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
       if(rootWindow.nativeDecorations && rootWindow.windowHandle)
@@ -2732,7 +2852,6 @@ private:
 
       for(child = children.last; child; child = child.prev)
       {
-         ColorAlpha background = *(ColorAlpha *)&child.background;
          bool opaque = child.IsOpaque();
          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
          {
@@ -2751,7 +2870,7 @@ private:
 
                /*
                Extent childRenderArea;
-               
+
                if(backBufferUpdate != null)
                {
                   childRenderArea.Copy(backBufferUpdate);
@@ -2843,16 +2962,16 @@ private:
       {
          renderArea.Copy(backBufferUpdate);
          renderArea.Offset(-offsetX, -offsetY);
-         
+
          overRenderArea.Copy(backBufferUpdate);
          overRenderArea.Offset(-offsetX, -offsetY);
-         
-         
+
+
       }
       else
       {
          renderArea.Copy(dirtyArea);
-         
+
          overRenderArea.Copy(dirtyArea);
       }
 
@@ -2889,8 +3008,8 @@ private:
                FASTLIST_LOOP(renderArea, extentBox)
                {
       #ifdef _DEBUG
-                  printf("(%d, %d) - (%d, %d)\n", 
-                     extentBox.box.left, extentBox.box.top, 
+                  printf("(%d, %d) - (%d, %d)\n",
+                     extentBox.box.left, extentBox.box.top,
                      extentBox.box.right, extentBox.box.bottom);
       #endif
                }
@@ -2900,7 +3019,7 @@ private:
          }
       }
       */
-      
+
       // WHY WAS THIS COMMENTED ??
 
       // Add extent forced by DrawOverChildren to the dirty area, adjusting dirty extent to the window
@@ -2911,7 +3030,7 @@ private:
 
       // Intersect with the clip extent
       overRenderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
-      
+
 
       if(opaque)
       {
@@ -2964,17 +3083,17 @@ private:
          dirtyExtent.Union(renderArea);
          renderArea.Free();
       }*/
-      
-      
+
+
       {
          Extent renderArea { };
-         
+
          renderArea.Copy(overRenderArea);
          renderArea.Offset(offsetX, offsetY);
          overDirtyExtent.Union(renderArea, rootWindow.tempExtents[0]);
          renderArea.Empty();
       }
-      
+
 
       if(backBufferUpdate != null)
       {
@@ -3018,22 +3137,22 @@ private:
          foreground = (background.color.r > 128 || background.color.g > 128) ? black : white;
          */
 #endif
-            
+
 #ifdef _DEBUG
          /*if(renderArea.count)
             printf("\n\nRendering %s (%x):\n------------------------------------------\n", _class.name, this);*/
 #endif
-            
+
          for(extentBox = (BoxItem)renderArea.first; extentBox; extentBox = (BoxItem)extentBox.next)
          {
             Box box = extentBox.box;
 
 #ifdef _DEBUG
-               /*printf("(%d, %d) - (%d, %d)\n", 
-                  extentBox.box.left, extentBox.box.top, 
+               /*printf("(%d, %d) - (%d, %d)\n",
+                  extentBox.box.left, extentBox.box.top,
                   extentBox.box.right, extentBox.box.bottom);*/
 #endif
-               
+
             UpdateExtent(box);
 
             box.left += offsetX;
@@ -3083,7 +3202,7 @@ private:
    public void UpdateDisplay(void)
    {
       if(!manageDisplay) { OnRedraw(null);return; }
-      if(rootWindow && this != rootWindow) 
+      if(rootWindow && this != rootWindow)
          rootWindow.UpdateDisplay();
       else if(display)
       {
@@ -3096,6 +3215,7 @@ private:
 
          clipExtent.AddBox(box);
 
+         display.Lock(true);
          display.StartUpdate();
 
          if(!rootWindow.fullRender)
@@ -3105,7 +3225,7 @@ private:
             ComputeRenderArea(dirtyExtent, overExtent, null);
          }
          else
-            clipExtent.Free(null);                     
+            clipExtent.Free(null);
 
          dirtyExtent.Free(null);
          overExtent.Free(null);
@@ -3123,27 +3243,28 @@ private:
             Render(updateExtent);
             if(fullRender)
                updateExtent.UnionBox(this.box, tempExtents[0]);
-            
+
 #ifdef _DEBUG
             //printf("\n\nUpdate:\n------------------------------------------\n");
 #endif
-            
+
             //FASTLIST_LOOP(updateExtent, extentBox)
             for(extentBox = (BoxItem)updateExtent.first; extentBox; extentBox = (BoxItem)extentBox.next)
             {
 #ifdef _DEBUG
-               /*printf("Updating (%d, %d) - (%d, %d)\n", 
-                  extentBox.box.left, extentBox.box.top, 
+               /*printf("Updating (%d, %d) - (%d, %d)\n",
+                  extentBox.box.left, extentBox.box.top,
                   extentBox.box.right, extentBox.box.bottom);*/
 #endif
-               
+
                display.Update(extentBox.box);
-               
+
             }
             updateExtent.Free(null);
          }
 
          display.EndUpdate();
+         display.Unlock();
          dirtyBack.Empty();
 
          dirty = false;
@@ -3166,12 +3287,12 @@ private:
          {
             intersection.Copy(dirtyBack);
             intersection.IntersectBox(box);
-         
+
             dirtyExtent.Clear();
             overExtent.Clear();
 
             clipExtent.AddBox(box);
-         
+
             if(!rootWindow.fullRender)
             {
                ComputeClipExtents();
@@ -3253,20 +3374,18 @@ private:
                Window ancestor = null;
                if(isD)
                   for(ancestor = last; ancestor && ancestor.parent != this; ancestor = ancestor.parent);
-               // for(child = isD ? (last.previous == children.first ? null : last.previous) : children.last; child; child = child.prev)
-               for(child = isD ? (ancestor.previous == children.first ? null : ancestor) : children.last; child; child = child.prev)
+               for(child = (isD ? (last != ancestor ? ancestor : ancestor.previous) : children.last); child; child = child.prev)
                {
                   if(child != statusBar && child.rootWindow == rootWindow)
                   {
                      Window childResult = child.GetAtPosition(x, y, clickThru, acceptDisabled, last);
-                     if(childResult) 
+                     if(childResult)
                         return childResult;
                   }
                }
                if(clickThru)
                {
-                  //for(child = isD ? (last.previous == children.first ? null : last.previous) : children.last; child; child = child.prev)
-                  for(child = isD ? (ancestor.previous == children.first ? null : ancestor.previous) : children.last; child; child = child.prev)
+                  for(child = (isD ? (last != ancestor ? ancestor : ancestor.previous) : children.last); child; child = child.prev)
                   {
                      if(child != statusBar && child.rootWindow == rootWindow)
                      {
@@ -3299,7 +3418,7 @@ private:
          // TESTING THIS FOR DROPBOX...
          if(!rootWindow || !rootWindow.style.interim)
          {
-            for(check2 = check; check2.activeChild; check2 = check2.activeChild)
+            for(check2 = check; check2 /*.activeChild*/; check2 = check2.activeChild)
             {
                if(check2.modalSlave && check2.modalSlave.created)
                {
@@ -3339,7 +3458,7 @@ private:
             if(rootWindow.active)
                guiApp.interfaceDriver.StopMoving(rootWindow);
          }
-         ReleaseCapture();
+         guiApp.windowCaptured.ReleaseCapture();
          guiApp.resizeX = guiApp.resizeY = guiApp.resizeEndX = guiApp.resizeEndY = false;
          guiApp.windowIsResizing = false;
       }
@@ -3357,7 +3476,7 @@ private:
       mouseWindow = rootWindow ? rootWindow.GetAtPosition(x,y, true, false, null) : null;
 
       if((guiApp.windowMoving && !guiApp.windowIsResizing) || guiApp.windowScrolling)
-         guiApp.SetCurrentCursor(guiApp.systemCursors[moving]);
+         guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[moving]);
       else if(mouseWindow)
       {
          modalWindow = mouseWindow.FindModal();
@@ -3370,30 +3489,31 @@ private:
             rx = guiApp.resizeX;
             ry = guiApp.resizeY;
             if((rex && rey) || (rx && ry))
-               guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNWSE]);
             else if((rex && ry) || (rx && rey))
-               guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNESW]);
             else if((ry || rey) && (!rx && !rex))
-               guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNS]);
             else if((rx || rex) && (!ry && !rey))
-               guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeWE]);
          }
          else if(!modalWindow && !guiApp.windowCaptured &&
             mouseWindow.IsMouseResizing(x, y, mouseWindow.size.w, mouseWindow.size.h,
                &rx, &ry, &rex, &rey))
          {
             if((rex && rey) || (rx && ry))
-               guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNWSE]);
             else if((rex && ry) || (rx && rey))
-               guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNESW]);
             else if((ry || rey) && (!rx && !rex))
-               guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNS]);
             else if((rx || rex) && (!ry && !rey))
-               guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeWE]);
          }
          else if(!guiApp.windowCaptured && !modalWindow && !guiApp.interimWindow)
          {
-            if(!mouseWindow.clientArea.IsPointInside({x - mouseWindow.clientStart.x, y - mouseWindow.clientStart.y}))
+            if(!mouseWindow.clientArea.IsPointInside({x - mouseWindow.clientStart.x, y - mouseWindow.clientStart.y}) &&
+               mouseWindow.rootWindow != mouseWindow)
                cursorWindow = mouseWindow.parent;
             else
                cursorWindow = mouseWindow;
@@ -3402,19 +3522,19 @@ private:
             cursorWindow = guiApp.windowCaptured;
          if(cursorWindow)
          {
-            for(; !cursorWindow.cursor && !cursorWindow.style.nonClient; cursorWindow = cursorWindow.parent);
-            guiApp.SetCurrentCursor(cursorWindow.cursor ? cursorWindow.cursor : guiApp.systemCursors[arrow]);
+            for(; !cursorWindow.cursor && !cursorWindow.style.nonClient && cursorWindow.rootWindow != cursorWindow; cursorWindow = cursorWindow.parent);
+            guiApp.SetCurrentCursor(mouseWindow, cursorWindow.cursor ? cursorWindow.cursor : guiApp.systemCursors[arrow]);
          }
          else if(modalWindow)
          {
-            guiApp.SetCurrentCursor(guiApp.systemCursors[arrow]);
+            guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[arrow]);
          }
          else if(guiApp.interimWindow)
          {
             if(guiApp.interimWindow.cursor)
-               guiApp.SetCurrentCursor(guiApp.interimWindow.cursor);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.interimWindow.cursor);
             else
-               guiApp.SetCurrentCursor(mouseWindow.cursor ? mouseWindow.cursor : guiApp.systemCursors[arrow]);
+               guiApp.SetCurrentCursor(mouseWindow, mouseWindow.cursor ? mouseWindow.cursor : guiApp.systemCursors[arrow]);
          }
       }
    }
@@ -3423,7 +3543,7 @@ private:
    bool AcquireInputEx(bool state)
    {
       bool result;
-      if(state) 
+      if(state)
       {
          guiApp.interfaceDriver.GetMousePosition(&guiApp.acquiredMouseX, &guiApp.acquiredMouseY);
          guiApp.interfaceDriver.SetMousePosition(clientSize.w/2 + absPosition.x, clientSize.h/2 + absPosition.y);
@@ -3434,7 +3554,7 @@ private:
       if(state && result)
       {
          SetMouseRangeToClient();
-         guiApp.interfaceDriver.SetMouseCursor((SystemCursor)-1);
+         guiApp.interfaceDriver.SetMouseCursor(guiApp.acquiredWindow, (SystemCursor)-1);
       }
       else
       {
@@ -3457,6 +3577,15 @@ private:
          if(rootWindow == this)
             Log(active ? "active\n" : "inactive\n");
          */
+         if(active && requireRemaximize)
+         {
+            if(state == maximized)
+            {
+               property::state = normal;
+               property::state = maximized;
+            }
+            requireRemaximize = false;
+         }
 
          // Testing this here...
          if(!parent || parent == guiApp.desktop || parent.active)
@@ -3466,7 +3595,7 @@ private:
 
          // TESTING THIS HERE
          UpdateDecorations();
-         if(result = OnActivate(active, previous, goOnWithActivation, direct) && *goOnWithActivation && master)
+         if((result = OnActivate(active, previous, goOnWithActivation, direct) && *goOnWithActivation && master))
             result = NotifyActivate(master, this, active, previous);
          else
          {
@@ -3480,17 +3609,17 @@ private:
                this.active = active;
                if(acquiredInput)
                   AcquireInputEx(active);
-               if(active)
+               if(active && isEnabled)
                {
                   if(caretSize)
                   {
                      if(guiApp.caretOwner)
                      {
-                        Box extent 
+                        Box extent
                         {
-                           guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 1, 
+                           guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 1,
                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + 1,
-                           guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 2, 
+                           guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 2,
                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + guiApp.caretOwner.caretSize - 1
                         };
                         guiApp.caretOwner.Update(extent);
@@ -3550,7 +3679,7 @@ private:
 
    void ConsequentialMouseMove(bool kbMoving)
    {
-      if(rootWindow)
+      if(rootWindow && !noConsequential)
       {
          if(kbMoving || !guiApp.windowMoving)
          {
@@ -3558,7 +3687,8 @@ private:
             int x,y;
             if(rootWindow == guiApp.desktop || rootWindow.parent == guiApp.desktop)
             {
-               guiApp.interfaceDriver.GetMousePosition(&x, &y);
+               if(guiApp.interfaceDriver)
+                  guiApp.interfaceDriver.GetMousePosition(&x, &y);
 
                if(guiApp.windowMoving || rootWindow.GetAtPosition(x, y, true, false, null))
                   rootWindow.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &mods, true, false);
@@ -3595,8 +3725,8 @@ private:
          {
             if(!active)
                StopMoving();
-            if(activateParent && 
-               (parent.activeChild != this || 
+            if(activateParent &&
+               (parent.activeChild != this ||
                (guiApp.interimWindow && !IsDescendantOf(guiApp.interimWindow))) &&
                active && _isModal &&
                parent != master && master)
@@ -3609,8 +3739,8 @@ private:
                   bool real = parent.activeChild != this;
 
                   // TEST THIS: New activateParent check here!!! CAUSED MENUS NOT GOING AWAY
-                  if(!style.inactive && /*activateParent && */guiApp.interimWindow && 
-                     !IsDescendantOf(guiApp.interimWindow) && 
+                  if(!style.inactive && /*activateParent && */guiApp.interimWindow &&
+                     !IsDescendantOf(guiApp.interimWindow) &&
                      !IsSlaveOf(guiApp.interimWindow))
                   {
                      Window interimWindow = guiApp.interimWindow;
@@ -3642,7 +3772,7 @@ private:
 
                   if(real)
                   {
-                     bool acquireInput = false;
+                     //bool acquireInput = false;
                      bool maximize =
                         parent.activeChild &&
                         parent.activeChild.state == maximized &&
@@ -3674,12 +3804,12 @@ private:
                         {
                            bool goOn = true;
                            result = PropagateActive(true, swap, &goOn, true);
-                           if(!result && !goOn) 
+                           if(!result && !goOn)
                            {
                               delete this;
                               return false;
                            }
-                           acquireInput = true;
+                           //acquireInput = true;
                         }
                      }
 
@@ -3726,7 +3856,10 @@ private:
                         if(activateParent && parent && !parent.active /*parent != parent.parent.activeChild*/)
                            parent.ActivateEx(true, true, moveInactive, activateRoot, external, externalSwap);
                      }
-                     else if(!guiApp.fullScreenMode)
+                     else
+#if !defined(__EMSCRIPTEN__)
+                     if(!guiApp.fullScreenMode)
+#endif
                      {
                         Window modalRoot = FindModal();
                         if(!modalRoot) modalRoot = this;
@@ -3742,14 +3875,14 @@ private:
                         }
                      }
                   }
-               
+
                   if(result && real && (!style.inactive || moveInactive) && parent)
                   {
                      Window last = parent.children.last;
 
                      if(!style.stayOnTop)
                         for(; last && last.style.stayOnTop; last = last.prev);
-                     
+
                      parent.children.Move(this, last);
 
                      // Definitely don't want that:   why not?
@@ -3760,7 +3893,7 @@ private:
                   }
                }
             }
-            else 
+            else
             {
                if(!parent || style.interim || (parent.activeChild == this && !style.inactive))
                {
@@ -3817,9 +3950,9 @@ private:
       if(guiApp.windowScrolling && !consequential)
       {
          guiApp.windowScrolling.SetScrollPosition(
-            (guiApp.windowScrolling.sbh) ? 
+            (guiApp.windowScrolling.sbh) ?
                (guiApp.windowScrollingBefore.x - mouseX + guiApp.windowScrollingStart.x) : 0,
-            (guiApp.windowScrolling.sbv) ? 
+            (guiApp.windowScrolling.sbv) ?
                (guiApp.windowScrollingBefore.y - mouseY + guiApp.windowScrollingStart.y) : 0);
       }
       if(guiApp.windowMoving)
@@ -3912,7 +4045,7 @@ private:
                   h = guiApp.windowResizingBefore.h - ry;
                }
             }
-         
+
             // Position
             if(!guiApp.windowIsResizing || guiApp.resizeX)
                x = guiApp.windowMovingBefore.x + rx;
@@ -3966,7 +4099,7 @@ private:
 
             // Break the anchors for moveable/resizable windows
             // Will probably cause problem with IDE windows... Will probably need a way to specify if anchors should break
-            if(window.style.fixed) 
+            if(window.style.fixed)
             {
                if(window.state == normal)
                {
@@ -3990,11 +4123,77 @@ private:
       reEntrancy = false;
    }
 
+   public bool MultiTouchMessage(TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers * mods, bool consequential, bool activate)
+   {
+      bool result = true;
+      if((infos && infos.count) || (event == up || event == pointerUp))
+      {
+         Window w = null;
+         while(result && w != this)
+         {
+            // TODO: How to handle this?
+            int x = (infos && infos.count) ? infos[0].point.x : 0;
+            int y = (infos && infos.count) ? infos[0].point.y : 0;
+            Window msgWindow = GetAtPosition(x,y, false, true, w);
+            Window window;
+            delete w;
+            w = msgWindow;
+            if(w) incref w;
+            window = (w && !w.disabled) ? w : null;
+
+            if(guiApp.windowCaptured && (guiApp.windowCaptured.rootWindow == this))
+            {
+               if(!guiApp.windowCaptured.isEnabled)
+                  guiApp.windowCaptured.ReleaseCapture();
+               else
+                  window = guiApp.windowCaptured;
+            }
+
+            if(consequential) mods->isSideEffect = true;
+            if(!result || (window && window.destroyed)) window = null;
+
+            if(window)
+            {
+               if(window.OnMultiTouch && !window.disabled)
+               {
+                  Array<TouchPointerInfo> in = null;
+                  if(infos && infos.count)
+                  {
+                     in = { size = infos.size };
+                     memcpy(in.array, infos.array, sizeof(TouchPointerInfo) * infos.size);
+
+                     for(i : in)
+                     {
+                        i.point.x -= (window.absPosition.x + window.clientStart.x);
+                        i.point.y -= (window.absPosition.y + window.clientStart.y);
+
+                        i.point.x = Max(Min(i.point.x, 32767),-32768);
+                        i.point.y = Max(Min(i.point.y, 32767),-32768);
+                     }
+                  }
+
+                  incref window;
+                  if(!window.OnMultiTouch(event, in, *mods))
+                     result = false;
+
+                  delete in;
+                  delete window;
+               }
+            }
+            if(!result || !w || !w.clickThrough)
+               break;
+         }
+         delete w;
+      }
+      return result;
+   }
+
    public bool MouseMessage(uint method, int x, int y, Modifiers * mods, bool consequential, bool activate)
    {
       bool result = true;
       bool wasMoving = guiApp.windowMoving ? true : false;
       bool wasScrolling = guiApp.windowScrolling ? true : false;
+      bool firstPass = true;
       Window w = null;
       while(result && w != this)
       {
@@ -4006,7 +4205,7 @@ private:
          w = msgWindow;
          if(w) incref w;
          window = (w && !w.disabled) ? w : null;
-         
+
          if(trueWindow) incref trueWindow;
 
          if(consequential) mods->isSideEffect = true;
@@ -4031,9 +4230,9 @@ private:
             {
                Window moved = trueWindow;
                for(moved = trueWindow; moved; moved = moved.parent)
-                  if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
+                  if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized))
                      break;
-               if(moved) 
+               if(moved)
                {
                   window = moved;
                   windowDragged = true;
@@ -4056,9 +4255,9 @@ private:
             {
                Window moved = window;
                for(moved = window; moved; moved = moved.parent)
-                  if(method == OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
+                  if(method == OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized))
                      break;
-               if(moved) 
+               if(moved)
                {
                   window = moved;
                   windowDragged = true;
@@ -4092,7 +4291,7 @@ private:
                      doActivation = false;
                   */
 
-                  if((doActivation && (activateWindow.parent != guiApp.desktop || guiApp.fullScreen)) || 
+                  if((doActivation && (activateWindow.parent != guiApp.desktop || guiApp.fullScreen)) ||
                      (guiApp.interimWindow && !window.IsDescendantOf(guiApp.interimWindow)))
                   {
                      // Let the OnLeftButtonDown do the activating instead
@@ -4161,7 +4360,7 @@ private:
                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown)
                   {
                      if(window.style.fixed &&
-                        (windowDragged || 
+                        (windowDragged ||
                         window.IsMouseMoving(
                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
                      {
@@ -4183,8 +4382,8 @@ private:
                   }
                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)
                   {
-                     if(window.style.hasMaximize && 
-                        window.IsMouseMoving( 
+                     if(window.style.hasMaximize &&
+                        window.IsMouseMoving(
                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h))
                      {
                         window.SetState(
@@ -4196,7 +4395,7 @@ private:
             }
             else
                window = null;
-            if(guiApp.windowMoving) 
+            if(guiApp.windowMoving)
             {
                if(guiApp.windowMoving.parent)
                {
@@ -4233,7 +4432,7 @@ private:
 
          if(trueWindow && trueWindow.FindModal())
             delete trueWindow;
-         
+
          /*if(trueWindow)
             incref trueWindow;
          */
@@ -4244,17 +4443,40 @@ private:
             msgWindow.SelectMouseCursor();
          */
 
-         if(guiApp.windowCaptured || trueWindow)
+         if(firstPass && (guiApp.windowCaptured || trueWindow))
          {
             Window prevWindow = guiApp.prevWindow;
-            if(guiApp.prevWindow && trueWindow != guiApp.prevWindow)
+            List<Window> overWindows = guiApp.overWindows;
+            Iterator<Window> it { overWindows };
+
+            while(it.Next())
+            {
+               Window ww = it.data;
+               if(trueWindow != ww && !trueWindow.IsDescendantOf(ww))
+               {
+                  it.pointer = null;
+                  result = ww.OnMouseLeave(*mods);
+                  if(!result) break;
+                  overWindows.TakeOut(ww);
+               }
+            }
+
+            if(result && guiApp.prevWindow && trueWindow != guiApp.prevWindow)
             {
                guiApp.prevWindow.mouseInside = false;
                guiApp.prevWindow = null;
 
-               // Eventually fix this not to include captured?
-               if(!trueWindow.IsDescendantOf(prevWindow) && !prevWindow.OnMouseLeave(*mods))
-                  result = false;
+               if(result)
+               {
+                  if(trueWindow.IsDescendantOf(prevWindow))
+                  {
+                     if(!overWindows.Find(prevWindow))
+                        overWindows.Add(prevWindow);
+                  }
+                  // Eventually fix this not to include captured?
+                  else if(!prevWindow.OnMouseLeave(*mods))
+                     result = false;
+               }
             }
             if(result && trueWindow && !trueWindow.destroyed/* && trueWindow == window*/)
             {
@@ -4278,13 +4500,22 @@ private:
                }
             }
             if(trueWindow && trueWindow._refCount > 1 && !trueWindow.destroyed)
+            {
+               for(wi : guiApp.overWindows; wi == trueWindow)
+               {
+                  OnMouseLeave(0);
+                  guiApp.overWindows.TakeOut(wi);
+                  break;
+               }
                guiApp.prevWindow = trueWindow;
+            }
             else
                guiApp.prevWindow = null;
          }
          SelectMouseCursor();
 
-         if(window && !guiApp.windowMoving && !wasMoving && !wasScrolling)
+         if(window && ((!guiApp.windowMoving && !wasMoving) ||
+            (wasMoving && guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp)) && !wasScrolling)
          {
             int clientX = x - (window.absPosition.x + window.clientStart.x);
             int clientY = y - (window.absPosition.y + window.clientStart.y);
@@ -4301,6 +4532,11 @@ private:
                incref window;
                if(!MouseMethod(window, clientX, clientY, *mods))
                   result = false;
+
+#ifdef __ANDROID__
+               if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp)
+                  window.OnMouseLeave(*mods);
+#endif
                delete window;
             }
          }
@@ -4313,6 +4549,7 @@ private:
          */
          if(!result || !w || !w.clickThrough)
             break;
+         firstPass = false;
       }
       delete w;
       return result;
@@ -4343,7 +4580,9 @@ private:
 
          if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
             status = OnSysKeyDown(key, character);
-         else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
+         if(status &&
+            (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown ||
+             method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit))
             status = OnSysKeyHit(key, character);
          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
             status = OnSysKeyUp(key, character);
@@ -4357,7 +4596,7 @@ private:
          if(status && !destroyed && menuBar && state != minimized)
          {
             // Disable the ALT
-            if((SmartKey)key != alt) 
+            if((SmartKey)key != alt)
                menuBar.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
             if(menuBar.focus)
             {
@@ -4430,7 +4669,7 @@ private:
 
                         if(!guiApp.windowIsResizing || guiApp.resizeY)
                            y = (y - guiApp.windowMovingBefore.y) + guiApp.windowMovingStart.y;
-                        else                           
+                        else
                            y = (h - guiApp.windowResizingBefore.h) + guiApp.windowMovingStart.y;
 
                         guiApp.interfaceDriver.SetMousePosition(x, y);
@@ -4446,7 +4685,7 @@ private:
                      {
                         guiApp.windowMoving.StopMoving();
                         ConsequentialMouseMove(false);
-                  
+
                         status = false;
                      }
                      break;
@@ -4488,7 +4727,7 @@ private:
                   if((defaultControl.active ||
                      defaultControl.ActivateEx(true, true, false, true, null, null)) && !defaultControl.disabled)
                      defaultControl.KeyMessage(method, defaultKey, character);
-                  status = false;                       
+                  status = false;
                }
             }
          }
@@ -4541,19 +4780,19 @@ private:
                         Window cycleParent = this;
                         if(this == guiApp.interimWindow && master && !master.style.interim && !cycleParent.style.tabCycle && master.parent)
                            cycleParent = master.parent;
-                        
+
                         if(!guiApp.windowCaptured && cycleParent.style.tabCycle)
                         {
                            if(cycleParent.CycleChildren(!key.shift, false, false, true))
                            {
+                              /*
                               Window child = cycleParent.activeChild;
 
                               // Scroll the window to include the active control
-                              /*
                               if(cycleParent.sbh && !child.style.dontScrollHorz)
                               {
                                  if(child.scrolledPos.x < 0)
-                                    cycleParent.sbh.Action(Position, 
+                                    cycleParent.sbh.Action(Position,
                                        cycleParent.scroll.x + child.scrolledPos.x, 0);
                                  else if(child.scrolledPos.x + child.size.w > cycleParent.clientSize.w)
                                     cycleParent.sbh.Action(Position,
@@ -4562,7 +4801,7 @@ private:
                               if(cycleParent.sbv && !child.style.dontScrollVert)
                               {
                                  if(child.scrolledPos.y < 0)
-                                    cycleParent.sbv.Action(Position, 
+                                    cycleParent.sbv.Action(Position,
                                        cycleParent.scroll.y + child.scrolledPos.y, 0);
                                  else if(child.scrolledPos.y + child.size.w > window.clientSize.h)
                                     cycleParent.sbv.Action(Position,
@@ -4632,7 +4871,7 @@ private:
                               }
                            }
                         }
-                        break;            
+                        break;
                      }
                      */
                   }
@@ -4783,8 +5022,12 @@ private:
       Window child;
 
       // Setup relationship with outside world (bb root || !bb)
-      if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop || 
+#if defined(__EMSCRIPTEN__)
+      if(this == guiApp.desktop)
+#else
+      if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop ||
          (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver))
+#endif
       {
          rootWindow = this;
          if(!tempExtents)
@@ -4816,19 +5059,24 @@ private:
       bool result = false;
       Window child;
 
+#if defined(__EMSCRIPTEN__)
+      if(this == guiApp.desktop)
+#else
       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || (guiApp.fullScreenMode && (this == guiApp.desktop || (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver))))
+#endif
       {
          subclass(DisplayDriver) dDriver = (dispDriver && !formDesigner) ? dispDriver : GetDisplayDriver(guiApp.defaultDisplayDriver);
          DisplaySystem displaySystem = dDriver ? dDriver.displaySystem : null;
 
-         windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this);
+         if(!windowHandle)
+            windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this);
 
          // This was here, is it really needed?
          //guiApp.interfaceDriver.ActivateRootWindow(this);
 
          if(!displaySystem)
          {
-            displaySystem = DisplaySystem {};
+            displaySystem = DisplaySystem { glCapabilities = glCapabilities };
             if(!displaySystem.Create(dDriver.name, guiApp.fullScreenMode ? windowHandle : windowHandle /*null*/, guiApp.fullScreenMode))
             {
                delete displaySystem;
@@ -4836,7 +5084,7 @@ private:
          }
          if(displaySystem)
          {
-            display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, windowDriverData = windowData };
+            display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, glCapabilities = glCapabilities, windowDriverData = windowData };
             if(display.Create(displaySystem, windowHandle))
                result = true;
             else
@@ -4861,7 +5109,10 @@ private:
       for(child = children.first; child; child = child.next)
       {
          if(child.created && !child.Setup(false))
-            result = false; 
+            result = false;
+
+         if(guiApp.modeSwitching && guiApp.fullScreen && child.rootWindow == child)
+            child.UpdateCaption();
       }
       return result;
    }
@@ -4869,8 +5120,8 @@ private:
    bool SetupDisplay(void)
    {
 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
-      if(is3D) return Window3D_SetupDisplay(this); else 
-#endif   
+      if(is3D) return Window3D_SetupDisplay(this); else
+#endif
       if(SetupRoot())
          return Setup(true);
       return false;
@@ -4917,8 +5168,12 @@ private:
             }
          }
       }
-      
-      if(guiApp.fullScreenMode || this != guiApp.desktop)
+
+      if(
+#if !defined(__EMSCRIPTEN__)
+      guiApp.fullScreenMode ||
+#endif
+         this != guiApp.desktop)
       {
          SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
          if(display)
@@ -4956,7 +5211,7 @@ private:
                      }
                   for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
                   {
-                     cursor.bitmap = eBitmap_LoadT(cursor.bitmapName, null, 
+                     cursor.bitmap = eBitmap_LoadT(cursor.bitmapName, null,
                         cursor.paletteShades ? null : guiApp.desktop.display.displaySystem);
                      if(cursor.bitmap)
                         cursor.bitmap.paletteShades = cursor.paletteShades;
@@ -4973,7 +5228,7 @@ private:
             }
 
             // Load Window Graphic Resources
-            
+
             /*
             if(usedFont == setFont || usedFont == window.systemFont)
                RemoveResource(usedFont);
@@ -4983,13 +5238,14 @@ private:
 
             if(systemFont)
                RemoveResource(systemFont);
-            
+
             if(captionFont)
                RemoveResource(captionFont);
 
             for(ptr = resources.first; ptr; ptr = ptr.next)
             {
-               ptr.loaded = display.displaySystem.LoadResource(ptr.resource);
+               if(!ptr.loaded)   // This check prevents a leak in case a watcher on 'font' calls AddResource (ListBox FontResource leak)
+                  ptr.loaded = display.displaySystem.LoadResource(ptr.resource);
             }
             if(setFont)
                AddResource(setFont);
@@ -5035,7 +5291,7 @@ private:
                display.Unlock();
 
                //SetScrollLineStep(sbStep.x, sbStep.y);
-               
+
                if(this != guiApp.desktop)
                {
                   if(resetAnchors)
@@ -5059,22 +5315,22 @@ private:
                   switch(state)
                   {
                      case maximized:
-                     
+
                         stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
                         stateSizeAnchor = SizeAnchor {};
                         break;
-                     
+
                      case minimized:
                      {
                         int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
 
-                        stateAnchor = 
-                           Anchor 
+                        stateAnchor =
+                           Anchor
                            {
                               left = (iconID % maxIcons) * MINIMIZED_WIDTH,
                               bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24)
                            };
-                        
+
                         stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
                         break;
                      }
@@ -5149,15 +5405,11 @@ private:
          if(activeChild)
             guiApp.interfaceDriver.ActivateRootWindow(activeChild);
       }
-      /*
-      TODO:
       if(!success)
-         //guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, caption);
-         guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, class.name);
-      */
+         LogErrorCode(graphicsLoadingFailed, _class.name);
 
       // Do this here to avoid problems on Windows
-      if(stateBackup == maximized)
+      if(rootWindow == this && parent && stateBackup == maximized)
          property::state = maximized;
       return result;
    }
@@ -5310,7 +5562,7 @@ private:
       if(interimWindow && interimWindow.master)
          interimMaster = interimWindow.master.rootWindow;
 
-      if(active && state == minimized) // && (!window.nativeDecorations || window.rootWindow != window)
+      if(active && state == minimized && window.parent) // && (!window.nativeDecorations || window.rootWindow != window)
          // SetState(normal, false, 0);
          SetState(lastState, false, 0);
 
@@ -5321,7 +5573,7 @@ private:
       /* WTH is this doing here?
       while(swap && swap.activeChild)
       {
-         swap = swap.activeChild;         
+         swap = swap.activeChild;
       }
       */
       // TESTING THIS BEFORE...
@@ -5371,7 +5623,7 @@ private:
       OldLink prevOrder = null;
       Window client = null;
 
-      if(parent) stopwatching(parent, font); 
+      if(parent) stopwatching(parent, font);
 
       // if(window.modalSlave) return false;
       if(destroyed || !created)
@@ -5407,7 +5659,16 @@ private:
          guiApp.prevWindow = null;
          OnMouseLeave(0);
       }
-      if(guiApp.caretOwner == this) 
+      else
+      {
+         for(w : guiApp.overWindows; w == this)
+         {
+            OnMouseLeave(0);
+            guiApp.overWindows.TakeOut(w);
+            break;
+         }
+      }
+      if(guiApp.caretOwner == this)
       {
          guiApp.interfaceDriver.SetCaret(0,0,0);
          UpdateCaret(false, true);
@@ -5447,7 +5708,7 @@ private:
                if(client == this) { client = null; break; }
                if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
                   tmpPrev = client.order.prev;
-               else 
+               else
                {
                   if(client)
                      prevOrder = tmpPrev;
@@ -5497,7 +5758,7 @@ private:
                   parent.UpdateActiveDocument(null);
                }
             }
-            else 
+            else
             {
                if(guiApp.interimWindow == this)
                {
@@ -5750,35 +6011,38 @@ private:
                break;
             case minimized:
             {
-               int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
-               Window child;
-               int size = 256;
-               byte * idBuffer = new0 byte[size];
-               int c;
-               for(child = parent.children.first; child; child = child.next)
+               if(hasMinimize)
                {
-                  if(child != this && child.state == minimized)
+                  int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
+                  Window child;
+                  int size = 256;
+                  byte * idBuffer = new0 byte[size];
+                  int c;
+                  for(child = parent.children.first; child; child = child.next)
                   {
-                     if(child.iconID > size - 2)
+                     if(child != this && child.state == minimized)
                      {
-                        idBuffer = renew0 idBuffer byte[size*2];
-                        memset(idBuffer + size, 0, size);
-                        size *= 2;
+                        if(child.iconID > size - 2)
+                        {
+                           idBuffer = renew0 idBuffer byte[size*2];
+                           memset(idBuffer + size, 0, size);
+                           size *= 2;
+                        }
+                        idBuffer[child.iconID] = (byte)bool::true;
                      }
-                     idBuffer[child.iconID] = (byte)bool::true;
                   }
-               }
-               for(c = 0; c<size; c++)
-                  if(!idBuffer[c])
-                     break;
-               iconID = c;
-               delete idBuffer;
-               if(style.isActiveClient && !style.hidden)
-                  parent.numIcons++;
+                  for(c = 0; c<size; c++)
+                     if(!idBuffer[c])
+                        break;
+                  iconID = c;
+                  delete idBuffer;
+                  if(style.isActiveClient && !style.hidden)
+                     parent.numIcons++;
 
-               stateAnchor = Anchor { left = (iconID % maxIcons) * MINIMIZED_WIDTH, bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24) };
-               stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
-               break;
+                  stateAnchor = Anchor { left = (iconID % maxIcons) * MINIMIZED_WIDTH, bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24) };
+                  stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
+                  break;
+               }
             }
          }
          // TOCHECK: Why was this here?
@@ -5786,13 +6050,15 @@ private:
          //position.y = (ty > 0) ? ty & 0xFFFFF : ty;
          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
 
-         Position(x, y, w, h, true, true, true, true, false, true);
+         if(state != minimized || hasMinimize)
+            Position(x, y, w, h, true, true, true, true, false, true);
 
-         if(!style.inactive && !style.interim && this == parent.activeClient)
+         if(!style.inactive && !style.interim && parent && this == parent.activeClient)
             parent.UpdateActiveDocument(null);
       }
 
-      CreateSystemChildren();
+      if(state != minimized || hasMinimize)
+         CreateSystemChildren();
       // ------------------------------------------------------
    }
 
@@ -5835,7 +6101,7 @@ private:
    public bool AcquireInput(bool acquired)
    {
       bool result = true;
-      if(acquiredInput != acquired)
+      if((guiApp.acquiredWindow && acquiredInput) != acquired)
       {
          if(active || (!visible && creationActivation == activate))
             result = AcquireInputEx(acquired);
@@ -5857,7 +6123,7 @@ private:
          if(child.cycle && !child.style.nonClient && child.style.isActiveClient && child.visible)
          {
             DataRow row = listBox.AddRow();
-            row.tag = (int64)child;
+            row.tag = (int64)(intptr)child;
             child.FigureCaption(caption);
             row.SetData(null, caption);
          }
@@ -5868,11 +6134,17 @@ private:
    {
       if(guiApp.driver != null)
       {
+#if !defined(__EMSCRIPTEN__)
          if(guiApp.fullScreenMode && guiApp.desktop.display)
+#else
+         if(true)
+#endif
          {
+#if !defined(__EMSCRIPTEN__)
             guiApp.desktop.mutex.Wait();
+#endif
             guiApp.desktop.display.Lock(true);
-         
+
             Update(extent);
             if(guiApp.desktop.active)
             {
@@ -5892,22 +6164,28 @@ private:
                   guiApp.RestoreCursorBackground();
                }
             }
-         
+
             guiApp.desktop.display.Unlock();
+#if !defined(__EMSCRIPTEN__)
             guiApp.desktop.mutex.Release();
+#endif
          }
          else
          {
             Window rootWindow = this.rootWindow;
+#if !defined(__EMSCRIPTEN__)
             rootWindow.mutex.Wait();
+#endif
             display.Lock(true);
-         
+
             Update(extent);
             if(guiApp.waiting)
                guiApp.SignalEvent();
             else
             {
+#if !defined(__EMSCRIPTEN__)
                guiApp.waitMutex.Wait();
+#endif
                guiApp.interfaceDriver.Lock(rootWindow);
                if(!rootWindow.style.hidden && rootWindow.dirty)
                {
@@ -5919,10 +6197,14 @@ private:
                   rootWindow.dirty = false;
                }
                guiApp.interfaceDriver.Unlock(rootWindow);
+#if !defined(__EMSCRIPTEN__)
                guiApp.waitMutex.Release();
+#endif
             }
             display.Unlock();
+#if !defined(__EMSCRIPTEN__)
             rootWindow.mutex.Release();
+#endif
          }
       }
    }
@@ -5955,7 +6237,7 @@ private:
          isForegroundWindow = true;
          ActivateEx(active, active, false, false, null, null);
          isForegroundWindow = false;
-      }  
+      }
    }
    */
 
@@ -6025,18 +6307,18 @@ private:
          guiApp.windowMovingBefore = scrolledPos;
          guiApp.windowResizingBefore = size;
          guiApp.windowMoving.UpdateDecorations();
-         if(guiApp.windowIsResizing) 
+         if(guiApp.windowIsResizing)
             guiApp.resizeEndX = guiApp.resizeEndY = true;
 
          if(setCursorPosition)
             guiApp.interfaceDriver.SetMousePosition(guiApp.windowMovingStart.x, guiApp.windowMovingStart.y);
          else
          {
-            int x, y;
+            int x = 0, y = 0;
             guiApp.interfaceDriver.GetMousePosition(&x, &y);
             guiApp.windowMovingStart.x += x - absPosition.x;
             guiApp.windowMovingStart.y += y - absPosition.y;
-         } 
+         }
 
          if(guiApp.windowMoving)
          {
@@ -6053,6 +6335,30 @@ private:
       }
    }
 
+   void SetupFileMonitor()
+   {
+#if !defined(__EMSCRIPTEN__)
+      if(!fileMonitor)
+      {
+         fileMonitor = FileMonitor
+         {
+            this, FileChange { modified = true };
+
+            bool OnFileNotify(FileChange action, const char * param)
+            {
+               incref this;
+               fileMonitor.StopMonitoring();
+               if(OnFileModified(action, param))
+                  fileMonitor.StartMonitoring();
+               delete this;
+               return true;
+            }
+         };
+         incref fileMonitor;
+      }
+#endif
+   }
+
 public:
    // normal Methods
    bool Create()
@@ -6063,12 +6369,11 @@ public:
          result = true;
       else if(guiApp && guiApp.driver != null)
       {
-         void * systemParent = null;
          OldLink slaveHolder;
          Window last;
          bool visible = !style.hidden;
 
-         if(style.embedded) 
+         if(style.embedded)
          {
             systemParent = parent;
             parent = guiApp.desktop;
@@ -6102,8 +6407,10 @@ public:
                }
          }
 
+#if !defined(__EMSCRIPTEN__)
          if(parent == guiApp.desktop && !mutex)
             mutex = Mutex {};
+#endif
 
          if(style.isDocument)
          {
@@ -6148,7 +6455,7 @@ public:
 
             this.visible = false;
             style.hidden = true;
-    
+
             //created = true;
             // autoCreate = true;
             wasCreated = true;
@@ -6178,7 +6485,7 @@ public:
 
                      if(style.hasMenuBar /*&& menu*/)
                      {
-                        menuBar = 
+                        menuBar =
                            PopupMenu
                            {
                               this,
@@ -6190,7 +6497,7 @@ public:
 
                      if(statusBar)
                         statusBar.Create();
-                     
+
                      // Create the system buttons
                      CreateSystemChildren();
 
@@ -6260,6 +6567,8 @@ public:
 
                      parent.OnChildAddedOrRemoved(this, false);
 
+                     if(rootWindow == this && visible)   // So that X11 windows don't show as 'unknown'
+                        UpdateCaption();
                      // Real set state & activate for proper display & activation
                      property::visible = visible;
                      //  SetState(state & 0x00000003, true, 0);
@@ -6271,13 +6580,17 @@ public:
                         /*if(rootWindow == this)
                            guiApp.interfaceDriver.ActivateRootWindow(this);
                         else*/
-                        if(creationActivation == activate)
+                        if(creationActivation == activate && guiApp.desktop.active)
                            ActivateEx(true, false, true, true, null, null);
-                        else if(creationActivation == flash)
-                           Flash();
+                        else if(creationActivation == activate || creationActivation == flash)
+                        {
+                           MakeActive();
+                           if(this == rootWindow)
+                              Flash();
+                        }
                      }
 
-                     if(!destroyed)
+                     if(!destroyed && !noConsequential)
                         rootWindow.ConsequentialMouseMove(false);
 
                      result = true;
@@ -6326,8 +6639,13 @@ public:
          {
             Window child;
             Box realBox;
-            
+
             // Testing this to avoid repetitve full update to take time...
+            if(rootWindow.fullRender)
+            {
+               rootWindow.dirty = true;
+               return;
+            }
             if(dirtyArea.count == 1)
             {
                BoxItem item = (BoxItem)ACCESS_ITEM(dirtyArea, dirtyArea.first);
@@ -6351,7 +6669,7 @@ public:
                   return;
                }
             }
-            
+
             rootWindow.dirty = true;
 
             if(region != null)
@@ -6366,7 +6684,7 @@ public:
             else
                realBox = box;
 
-            if(realBox.right >= realBox.left && 
+            if(realBox.right >= realBox.left &&
                realBox.bottom >= realBox.top)
             {
                // if(!rootWindow.fullRender)
@@ -6415,7 +6733,7 @@ public:
                      childBox.top     -= window.absPosition.y - guiApp.desktop.absPosition.y;
                      childBox.right   -= window.absPosition.x - guiApp.desktop.absPosition.x;
                      childBox.bottom  -= window.absPosition.y - guiApp.desktop.absPosition.y;
-       
+
                      window.Update(childBox);
                   }
                   else
@@ -6496,11 +6814,10 @@ public:
 
    void SetScrollArea(int width, int height, bool snapToStep)
    {
-      bool resize = false;
       if(snapToStep)
       {
          int stepX = sbStep.x, stepY = sbStep.y;
-         // Needed to make snapped down position match the skin's check of client area 
+         // Needed to make snapped down position match the skin's check of client area
          // against realvirtual
          if(guiApp.textMode)
          {
@@ -6608,7 +6925,7 @@ public:
       {
          if(state == newState || OnStateChange(newState, mods))
          {
-            WindowState prevState = state;
+            //WindowState prevState = state;
 
             StopMoving();
 
@@ -6616,7 +6933,7 @@ public:
             // This has the effect of activating the window through the system...
             if(rootWindow == this)
                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
-      
+
             SetStateEx(newState, activate);
 
             if(rootWindow == this && !rootWindow.nativeDecorations)
@@ -6647,15 +6964,15 @@ public:
                parent.UpdateScrollBars(true, true);
 
             /*
-            // Do we really need this stuff here? 
-            // Shouldn't the Activate stuff take care of it?              
+            // Do we really need this stuff here?
+            // Shouldn't the Activate stuff take care of it?
             if(parent.rootWindow == parent && style)
             {
                char caption[2048];
                parent.FigureCaption(caption);
                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
                parent.UpdateDecorations();
-            }         
+            }
             */
 
             rootWindow.ConsequentialMouseMove(false);
@@ -6723,32 +7040,32 @@ public:
       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
       MenuItem
       {
-         menu, $"Restore", r, NotifySelect = MenuWindowRestore, 
+         menu, $"Restore", r, NotifySelect = MenuWindowRestore,
          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
       };
       MenuItem
       {
-         menu, $"Move", m, NotifySelect = MenuWindowMove, 
+         menu, $"Move", m, NotifySelect = MenuWindowMove,
          disabled = !style.fixed || state == maximized
       };
       MenuItem
       {
-         menu, $"Size", s, NotifySelect = MenuWindowSize, 
+         menu, $"Size", s, NotifySelect = MenuWindowSize,
          disabled = !style.sizable || state != normal
       };
       MenuItem
       {
-         menu, $"Minimize", n, NotifySelect = MenuWindowMinimize, 
+         menu, $"Minimize", n, NotifySelect = MenuWindowMinimize,
          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
       };
       MenuItem
       {
-         menu, $"Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize, 
+         menu, $"Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize,
          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
       };
       MenuItem
       {
-         menu, $"Stay On Top", t, NotifySelect = MenuWindowStayOnTop, 
+         menu, $"Stay On Top", t, NotifySelect = MenuWindowStayOnTop,
          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
       };
       MenuDivider { menu };
@@ -6775,7 +7092,11 @@ public:
       if(guiApp.desktop.active)
          Activate();
       else if(!active)
-         Flash();
+      {
+         MakeActive();
+         if(this == rootWindow)
+            Flash();
+      }
    }
 
    void Deactivate(void)
@@ -6819,7 +7140,7 @@ public:
             }
          }
          /*
-         if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) && 
+         if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) &&
             parent.tabCycle && parent.CycleChildren(backward, false, false))
             return true;
          */
@@ -6886,7 +7207,8 @@ public:
          if(/*created && */display)
          {
             display.Lock(false);
-            ptr.loaded = display.displaySystem.LoadResource(resource);
+            if(!ptr.loaded)   // This check prevents a leak in case a watcher on 'font' calls AddResource (ListBox FontResource leak)
+               ptr.loaded = display.displaySystem.LoadResource(resource);
             display.Unlock();
          }
          /*
@@ -6938,7 +7260,7 @@ public:
          caretPos.x = x;
          caretPos.y = y;
          caretSize = size;
-         if(active && !style.interim)
+         if(active && !style.interim && isEnabled)
          {
             if(visible || !guiApp.caretOwner)
                guiApp.caretOwner = size ? this : null;
@@ -7010,7 +7332,7 @@ public:
       }
    }
 
-   private void _SetCaption(char * format, va_list args)
+   private void _SetCaption(const char * format, va_list args)
    {
       if(this)
       {
@@ -7030,7 +7352,7 @@ public:
       }
    }
 
-   /*deprecated*/ void SetText(char * format, ...)
+   /*deprecated*/ void SetText(const char * format, ...)
    {
       va_list args;
       va_start(args, format);
@@ -7038,7 +7360,7 @@ public:
       va_end(args);
    }
 
-   void SetCaption(char * format, ...)
+   void SetCaption(const char * format, ...)
    {
       va_list args;
       va_start(args, format);
@@ -7069,10 +7391,16 @@ public:
             clip.bottom += absPosition.y;
          }
 
-         clip.left += decorations ? 0 : clientStart.x;
-         clip.top += decorations ? 0 : clientStart.y;
-         clip.right += decorations ? 0 : clientStart.x;
-         clip.bottom += decorations ? 0 : clientStart.y;
+         if(!nativeDecorations)
+         {
+            clip.left += decorations ? 0 : clientStart.x;
+            clip.top += decorations ? 0 : clientStart.y;
+            clip.right += decorations ? 0 : clientStart.x;
+            clip.bottom += decorations ? 0 : clientStart.y;
+         }
+
+         if(decorations && this == guiApp.desktop)
+            clip = { 0, 0, guiApp.virtualScreen.w, guiApp.virtualScreen.h };
 
          if(display && display.flags.flipping)
          {
@@ -7084,12 +7412,12 @@ public:
          {
             Window window { };
             window.Create();
-            result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top, 
+            result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top,
                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
             delete window;
          }
          else
-            result = display.Grab(bitmap, clip.left, clip.top, 
+            result = display.Grab(bitmap, clip.left, clip.top,
                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
 
          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
@@ -7217,7 +7545,7 @@ public:
          return false;
       if(terminateX > 1)
          return true;
-         
+
       closing = true;
 
       if(!OnClose(parentClosing))
@@ -7249,19 +7577,28 @@ public:
          for(slave = slaves.first; slave; slave = slave.next)
          {
             Window w = slave.data;
-            if((w.parent == this || !w.IsDescendantOf(this)) && !w.CloseConfirmation(true))
+            if(w.parent != this && !w.IsDescendantOf(this) && !w.CloseConfirmation(true))
             {
-               // ((Window)slave.data).CloseConfirmation(true);
                result = false;
                break;
             }
          }
       }
 
+      // Confirm closure of active clients first (We use OnClose() to hide instead of destroy in the IDE)
       if(result)
       {
          for(child = children.first; child; child = child.next)
-            if(child.master != this && !child.CloseConfirmation(true))
+            if(child.isActiveClient && !child.CloseConfirmation(true))
+            {
+               result = false;
+               break;
+            }
+      }
+      if(result)
+      {
+         for(child = children.first; child; child = child.next)
+            if(!child.isActiveClient && !child.CloseConfirmation(true))
             {
                result = false;
                break;
@@ -7300,9 +7637,12 @@ public:
 
    bool MenuFileSave(MenuItem selection, Modifiers mods)
    {
+      SetupFileMonitor();
       if(fileName)
       {
+#if !defined(__EMSCRIPTEN__)
          fileMonitor.fileName = null;
+#endif
          saving = true;
 
          if(OnSaveFile(fileName))
@@ -7310,7 +7650,9 @@ public:
             //if(OnFileModified != Window::OnFileModified)
             {
                saving = false;
+#if !defined(__EMSCRIPTEN__)
                fileMonitor.fileName = fileName;
+#endif
             }
             return true;
          }
@@ -7330,6 +7672,8 @@ public:
       DialogResult result = (DialogResult)bool::true;
       FileDialog fileDialog = saveDialog;
 
+      SetupFileMonitor();
+
       if(!fileDialog)
          fileDialog = FileDialog {};
       if(fileDialog)
@@ -7343,7 +7687,9 @@ public:
             sprintf(filePath, "Untitled %d", documentID);
             fileDialog.filePath = filePath;
          }
+#if !defined(__EMSCRIPTEN__)
          fileMonitor.fileName = null;
+#endif
 
          fileDialog.type = save;
          fileDialog.text = $"Save As";
@@ -7353,7 +7699,7 @@ public:
             fileDialog.master = master.parent ? master : this;
             if(fileDialog.Modal() == ok)
             {
-               char * filePath = fileDialog.filePath;
+               const char * filePath = fileDialog.filePath;
                saving = true;
                if(OnSaveFile(filePath))
                {
@@ -7367,7 +7713,7 @@ public:
                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
                   DialogResult answer = dialog.Modal();
                   saving = false;
-                  if(answer != yes) 
+                  if(answer != yes)
                   {
                      result = answer;
                      break;
@@ -7380,11 +7726,13 @@ public:
                break;
             }
          }
+#if !defined(__EMSCRIPTEN__)
          //if(OnFileModified != Window::OnFileModified && fileName)
          {
             if(fileName)
                fileMonitor.fileName = fileName;
          }
+#endif
          delete fileDialog;
       }
       return (bool)result; // Actually returning result from Yes/NoCancel message box
@@ -7452,11 +7800,10 @@ public:
                         (*&child.normalAnchor).top = y;
                         (*&child.normalAnchor).right.type = none;
                         (*&child.normalAnchor).bottom.type = none;
-
-                        child.normalSizeAnchor.isClientW = false;
-                        child.normalSizeAnchor.isClientH = false;
-                        child.normalSizeAnchor.size.w = w;
-                        child.normalSizeAnchor.size.h = h;
+                        (*&child.normalSizeAnchor).isClientW = false;
+                        (*&child.normalSizeAnchor).isClientH = false;
+                        (*&child.normalSizeAnchor).size.w = w;
+                        (*&child.normalSizeAnchor).size.h = h;
                         child.anchored = false;
                      }
 
@@ -7500,7 +7847,7 @@ public:
 
       for(document = children.first; document; document = next)
       {
-         for(next = document.next; next && !(next.style.isActiveClient; next = next.next);
+         for(next = document.next; next && !next.style.isActiveClient; next = next.next);
          if(document.style.isActiveClient)
             if(!document.Destroy(0) && !document.style.hidden)
                return false;
@@ -7576,7 +7923,7 @@ public:
       }
       document = cycle.data;
       document.Activate();
-      
+
       //if(activeChild.state == maximized)
       //  document.SetState(maximized, false, mods);
       //else if(document.state == minimized)
@@ -7627,10 +7974,10 @@ public:
                         (*&child.normalAnchor).top = y;
                         (*&child.normalAnchor).right.type = none;
                         (*&child.normalAnchor).bottom.type = none;
-                        child.normalSizeAnchor.isClientW = false;
-                        child.normalSizeAnchor.isClientH = false;
-                        child.normalSizeAnchor.size.w = w;
-                        child.normalSizeAnchor.size.h = h;
+                        (*&child.normalSizeAnchor).isClientW = false;
+                        (*&child.normalSizeAnchor).isClientH = false;
+                        (*&child.normalSizeAnchor).size.w = w;
+                        (*&child.normalSizeAnchor).size.h = h;
                         child.anchored = false;
                      }
 
@@ -7692,10 +8039,10 @@ public:
                         (*&child.normalAnchor).top = y;
                         (*&child.normalAnchor).right.type = none;
                         (*&child.normalAnchor).bottom.type = none;
-                        child.normalSizeAnchor.isClientW = false;
-                        child.normalSizeAnchor.isClientH = false;
-                        child.normalSizeAnchor.size.w = w;
-                        child.normalSizeAnchor.size.h = h;
+                        (*&child.normalSizeAnchor).isClientW = false;
+                        (*&child.normalSizeAnchor).isClientH = false;
+                        (*&child.normalSizeAnchor).size.w = w;
+                        (*&child.normalSizeAnchor).size.h = h;
                         child.anchored = false;
                      }
 
@@ -7720,16 +8067,23 @@ public:
 
    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
    {
-      WindowList dialog { master = this };
-      Window document = (Window)dialog.Modal();
-      if(document)
+      WindowList
       {
-         if(activeChild.state == maximized)
-            document.SetState(maximized, false, mods);
-         else if(document.state == minimized)
-            document.SetState(normal, false, mods);
-         document.Activate();
-      }
+         master = this; isModal = true;
+
+         void NotifyDestroyed(Window window, DialogResult result)
+         {
+            Window document = (Window)(intptr)result;
+            if(document)
+            {
+               if(activeChild.state == maximized)
+                  document.SetState(maximized, false, 0);
+               else if(document.state == minimized)
+                  document.SetState(normal, false, 0);
+               document.Activate();
+            }
+         }
+      }.Create();
       return true;
    }
 
@@ -7768,12 +8122,13 @@ public:
    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
+   virtual bool OnMultiTouch(TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers mods);
    virtual void OnMouseCaptureLost(void);
    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
    virtual void OnDrawOverChildren(Surface surface);
-   virtual bool OnFileModified(FileChange fileChange, char * param);
-   virtual bool OnSaveFile(char * fileName);
+   virtual bool OnFileModified(FileChange fileChange, const char * param);
+   virtual bool OnSaveFile(const char * fileName);
 
    // Virtual Methods -- Children management (To support Stacker, for lack of built-in auto-layout)
    // Note: A 'client' would refer to isActiveClient, rather than
@@ -7783,15 +8138,16 @@ public:
    virtual void OnChildResized(Window child, int x, int y, int w, int h);
 
    // Skins Virtual Functions
-   virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
-   virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
+   virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h) { *w = 0, *h = 0; }
+   virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh) { *mw = 0, *mh = 0; }
    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
    {
+      *x = 0, *y = 0;
       *cw = *w;
-      *ch = *h;      
+      *ch = *h;
    }
-   virtual void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
-   virtual void PreShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
+   virtual void ShowDecorations(Font captionFont, Surface surface, const char * name, bool active, bool moving);
+   virtual void PreShowDecorations(Font captionFont, Surface surface, const char * name, bool active, bool moving);
    virtual bool IsMouseMoving(int x, int y, int w, int h)
    {
       return false;
@@ -7801,7 +8157,7 @@ public:
       return false;
    }
    virtual void UpdateNonClient();
-   virtual void SetBox(Box box);    // This isn't used anywhere at this time
+   virtual void SetBox(Box box);    // This is used in the MySkin skin
    virtual bool IsInside(int x, int y)
    {
       return box.IsPointInside({x, y});
@@ -7814,7 +8170,7 @@ public:
    // Notifications
    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
-   virtual void Window::NotifySaved(Window window, char * filePath);
+   virtual void Window::NotifySaved(Window window, const char * filePath);
 
    // Public Methods
 
@@ -7839,7 +8195,7 @@ public:
 
             if(!master || (master == this.parent && master == guiApp.desktop))
                property::master = value;
-            
+
             if(parent)
             {
                parent.children.Remove(this);
@@ -7895,12 +8251,12 @@ public:
                if(created)
                {
                   int x = position.x, y = position.y, w = size.w, h = size.h;
-                  
+
                   int vpw, vph;
 
                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
-                  
+
                   vpw = value.clientSize.w;
                   vph = value.clientSize.h;
                   if(style.nonClient)
@@ -7949,11 +8305,11 @@ public:
                   if(!style.noCycle)
                      parent.childrenCycle.Insert(
                         // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
-                        //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
+                        //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
                         null,
                         cycle = OldLink { data = this });
                   parent.childrenOrder.Insert(
-                     (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last, 
+                     (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
                      order = OldLink { data = this });
                }
 
@@ -7965,7 +8321,7 @@ public:
                }
 
                // *** FONT INHERITANCE ***
-               if(!setFont && oldParent) 
+               if(!setFont && oldParent)
                   stopwatching(oldParent, font);
 
                if(systemFont)
@@ -7998,21 +8354,21 @@ public:
                         Update(null);
                      }
                   };
-               
+
                firewatchers font;
 
 
-               if(value.rootWindow && value.rootWindow.display && rootWindow)
+               if(value.rootWindow && value.rootWindow.display && rootWindow && created)
                {
-                  bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) || 
+                  bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) ||
                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
-                  
+
                   if(reloadGraphics)
                      UnloadGraphics(false);
                   SetupDisplay();
                   if(reloadGraphics)
                      LoadGraphics(false, false);
-                     
+
                   /*
                   if(value.rootWindow != rootWindow)
                      DisplayModeChanged();
@@ -8089,7 +8445,7 @@ public:
       get { return master ? master : parent; }
    };
 
-   property char * caption
+   property const char * caption
    {
       property_category $"Appearance"
       watchable
@@ -8200,7 +8556,7 @@ public:
             CreateSystemChildren();
          }
       }
-      get { return (BorderStyle)style.borderBits; } 
+      get { return (BorderStyle)style.borderBits; }
    };
 
    property Size minClientSize
@@ -8277,7 +8633,7 @@ public:
       }
       get { return style.hasClose; }
    };
-   
+
    property bool nonClient
    {
       property_category $"Layout"
@@ -8295,7 +8651,7 @@ public:
       property_category $"Behavior"
       set
       {
-         if(value) 
+         if(value)
          {
             // *** NEW HERE: ***
             if(!style.inactive)
@@ -8325,7 +8681,7 @@ public:
                {
                   parent.childrenCycle.Insert(
                      // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
-                     //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
+                     //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
                      null,
                      cycle = OldLink { data = this });
                }
@@ -8380,7 +8736,7 @@ public:
       set { style.tabCycle = value; }
       get { return style.tabCycle; }
    };
-     
+
    property bool isDefault
    {
       property_category $"Behavior"
@@ -8390,8 +8746,8 @@ public:
          {
             if(value)
             {
-               Window sibling;
-               /*for(sibling = parent.children.first; sibling; sibling = sibling.next)
+               /*Window sibling;
+               for(sibling = parent.children.first; sibling; sibling = sibling.next)
                   if(sibling != this && sibling.style.isDefault)
                      sibling.style.isDefault = false;*/
                if(master.defaultControl)
@@ -8422,7 +8778,7 @@ public:
       property_category $"Window Style"
       set
       {
-         if(value) 
+         if(value)
          {
             if(!menu)
             {
@@ -8432,13 +8788,13 @@ public:
             if(created && !menuBar)
             {
                menuBar =
-                  PopupMenu 
+                  PopupMenu
                   {
                      this, menu = menu,
                      isMenuBar = true,
                      anchor = Anchor { top = 23, left = 1, right = 1 },
                      size.h = 24,
-                     inactive = true, nonClient = true                            
+                     inactive = true, nonClient = true
                   };
                menuBar.Create();
             }
@@ -8505,14 +8861,14 @@ public:
                   if(order)
                   {
                      OldLink order;
-                     for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev; 
+                     for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev;
                          order && ((Window)order.data).style.stayOnTop;
                          order = (order == parent.childrenOrder.first) ? null : order.prev);
                       last = order ? order.data : null;
                   }
                   else
                   {
-                     for(last = parent.children.last; 
+                     for(last = parent.children.last;
                          last && last.style.stayOnTop;
                          last = last.prev);
                   }
@@ -8549,9 +8905,9 @@ public:
             if(!menuBar && style.hasMenuBar && value)
             {
                menuBar = PopupMenu
-                         { 
-                            this, menu = value, isMenuBar = true, 
-                            anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24, 
+                         {
+                            this, menu = value, isMenuBar = true,
+                            anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24,
                             inactive = true, nonClient = true
                          };
                 menuBar.Create();
@@ -8624,7 +8980,7 @@ public:
       property_category $"Layout"
       isset
       {
-         return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
+         return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
             sizeAnchor.isClientW != sizeAnchor.isClientH;
       }
@@ -8660,12 +9016,7 @@ public:
       property_category $"Layout"
       isset
       {
-         Anchor thisAnchor = anchor;
-         SizeAnchor thisSizeAnchor = sizeAnchor;
-         bool leftRight = (anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none);
-         bool topBottom = (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none);
-         bool isClient = !sizeAnchor.isClientW && !sizeAnchor.isClientH;
-         return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
+         return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
       }
@@ -8697,7 +9048,7 @@ public:
       property_category $"Layout"
       isset
       {
-         return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
+         return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
       }
@@ -8720,7 +9071,7 @@ public:
             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
          }
       }
-      get { value = clientSize; }
+      get { value = this ? clientSize : { 0, 0 }; }
    };
 
    property Size initSize { get { value = sizeAnchor.size; } };
@@ -8746,7 +9097,7 @@ public:
             }
             anchor = value;
 
-            if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type)) 
+            if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type))
             {
                anchor.left.distance = 0;
                anchor.horz.type = 0;
@@ -8764,7 +9115,7 @@ public:
                int x, y, w, h;
 
                normalAnchor = anchor;
-               
+
                // Break the anchors for moveable/resizable windows
                /*if(style.fixed ) //&& value.left.type == cascade)
                {
@@ -8943,7 +9294,7 @@ public:
                         {
                            tmpPrev = client.order.prev;
                         }
-                        else 
+                        else
                         {
                            if(client)
                               prevOrder = tmpPrev;
@@ -8983,7 +9334,7 @@ public:
                cycle = null;
                order = null;
                */
-               
+
                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
             }
 
@@ -9015,7 +9366,7 @@ public:
                   if(!(style.noCycle))
                   {
                      cycle = parent.childrenCycle.AddAfter(
-                        (parent.activeChild && parent.activeChild.cycle) ? 
+                        (parent.activeChild && parent.activeChild.cycle) ?
                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
                      cycle.data = this;
                   }
@@ -9025,15 +9376,19 @@ public:
                   order.data = this;
                }
                */
-     
+
                /*
                if(true || !parent.activeChild)
                   ActivateEx(true, false, true, true, null, null);
                */
-               if(creationActivation == activate)
+               if(creationActivation == activate && guiApp.desktop.active)
                   ActivateEx(true, false, true, true, null, null);
-               else if(creationActivation == flash && !object)
-                  Flash();               
+               else if((creationActivation == activate || creationActivation == flash) && !object)
+               {
+                  MakeActive();
+                  if(this == rootWindow)
+                     Flash();
+               }
 
                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
                Update(null);
@@ -9050,11 +9405,11 @@ public:
 
       get { return (style.hidden || !setVisible) ? false : true; }
    };
-    
+
    property bool isDocument
    {
       property_category $"Document"
-      set { style.isDocument = value; }
+      set { style.isDocument = value; if(value) SetupFileMonitor(); }
       get { return style.isDocument; }
    };
 
@@ -9074,7 +9429,7 @@ public:
          {
             if(!style.hasHorzScroll && created)
             {
-               CreateSystemChildren();         
+               CreateSystemChildren();
                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
             }
          }
@@ -9172,7 +9527,7 @@ public:
    property Point scroll
    {
       property_category $"Behavior"
-      set { SetScrollPosition(value.x, value.y); }
+      set { if(this) SetScrollPosition(value.x, value.y); }
       get { value = scroll; }
    };
 
@@ -9191,11 +9546,13 @@ public:
       get { return (bool)noAutoScrollArea; }
    };
 
-   property char * fileName
+   property const char * fileName
    {
       property_category $"Document"
       set
       {
+         SetupFileMonitor();
+
          if(menu && ((!fileName && value) || (fileName && !value)))
          {
             MenuItem item = menu.FindItem(MenuFileSave, 0);
@@ -9213,8 +9570,10 @@ public:
             UpdateCaption();
 
          // if(style.isDocument)
+#if !defined(__EMSCRIPTEN__)
          if(!saving)
             fileMonitor.fileName = value;
+#endif
       }
       get { return fileName; }
    };
@@ -9253,14 +9612,36 @@ public:
    property bool showInTaskBar
    {
       property_category $"Window Style"
-      set { style.showInTaskBar = value; }
-      get { return (style.showInTaskBar; }
+      set
+      {
+         style.showInTaskBar = value;
+#if defined(__WIN32__)
+         Win32UpdateStyle(this);
+#endif
+      }
+      get { return style.showInTaskBar; }
    };
    property FileDialog saveDialog { set { saveDialog = value; } };
    property bool isActiveClient
    {
       property_category $"Behavior"
-      set { style.isActiveClient = value; }
+      set
+      {
+         if(parent && style.isActiveClient != value && !style.hidden)
+         {
+            if(value)
+            {
+               if(state == minimized) parent.numIcons++;
+               parent.numPositions++;
+            }
+            else
+            {
+               if(state == minimized) parent.numIcons--;
+               parent.numPositions--;
+            }
+         }
+         style.isActiveClient = value;
+      }
       get { return style.isActiveClient; }
    };
 
@@ -9273,10 +9654,10 @@ public:
          SelectMouseCursor();
       }
       get { return cursor; }
-   };      
+   };
 
 //#if !defined(ECERE_VANILLA)
-   property char * name
+   property const char * name
    {
       property_category $"Design"
       get
@@ -9290,7 +9671,7 @@ public:
       }
    };
 //#endif
-   property char * displayDriver
+   property const char * displayDriver
    {
       property_category $"Behavior"
       set
@@ -9330,19 +9711,19 @@ public:
    };
 
    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
-                                                                                                            
+
    // Will be merged with font later
    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
    property Point clientStart { get { value = clientStart; } };
    property Point absPosition { get { value = absPosition; } };
-   property Anchor normalAnchor { get {value = normalAnchor; } };
-   // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
+   property Anchor normalAnchor { get { value = normalAnchor; } };
+   property SizeAnchor normalSizeAnchor { get { value = normalSizeAnchor; } };
    property bool active { get { return (bool)active; } };
    property bool created { get { return (bool)created; } };
    property bool destroyed { get { return (bool)destroyed; } };
    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
-   property Window firstChild { get { return children.first; } };   
-   property Window lastChild { get { return children.last; } };   
+   property Window firstChild { get { return children.first; } };
+   property Window lastChild { get { return children.last; } };
    property Window activeClient { get { return activeClient; } };
    property Window activeChild { get { return activeChild; } };
    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
@@ -9350,7 +9731,7 @@ public:
    property ScrollBar horzScroll { get { return sbh; } };
    property ScrollBar vertScroll { get { return sbv; } };
    property StatusBar statusBar { get { return statusBar; } };
-   property Window rootWindow { get { return rootWindow; } };   
+   property Window rootWindow { get { return rootWindow; } };
    property bool closing { get { return (bool)closing; } set { closing = value; } };
    property int documentID { get { return documentID; } };
    property Window previous { get { return prev; } }
@@ -9362,7 +9743,7 @@ public:
    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
    property void * systemHandle { get { return windowHandle; } }
    property Button minimizeButton { get { return sysButtons[0]; } };
-   property Button maximizeButton { get { return sysButtons[1]; } };   
+   property Button maximizeButton { get { return sysButtons[1]; } };
    property Button closeButton { get { return sysButtons[2]; } };
    property BitmapResource icon
    {
@@ -9376,8 +9757,38 @@ public:
       }
    };
    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
-   property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
+   property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; if(value) nativeDecorations = false; /* Native Decorations are not supported with alphaBlend */ } };
    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
+   property GLCapabilities glCapabilities
+   {
+      get { return glCapabilities; }
+      set
+      {
+         bool reload = display != null &&
+            (glCapabilities.nonPow2Textures != value.nonPow2Textures ||
+             glCapabilities.intAndDouble != value.intAndDouble ||
+             glCapabilities.vertexBuffer != value.vertexBuffer ||
+             glCapabilities.compatible != value.compatible ||
+             glCapabilities.legacyFormats != value.legacyFormats ||
+             glCapabilities.debug != value.debug ||
+             glCapabilities.vertexPointer != value.vertexPointer ||
+             glCapabilities.quads != value.quads);
+         guiApp.modeSwitching = true;
+         if(reload)
+            UnloadGraphics(false);
+
+         glCapabilities = value;
+
+         if(reload)
+         {
+            if(SetupDisplay())
+               LoadGraphics(false, false);
+         }
+         else if(display)
+            display.glCapabilities = value;
+         guiApp.modeSwitching = false;
+      }
+   };
    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
    property bool nativeDecorations
    {
@@ -9409,7 +9820,7 @@ public:
    };
    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
 
-   property char * text
+   property const char * text
    {
       property_category $"Deprecated"
       watchable
@@ -9468,7 +9879,7 @@ private:
    void * windowHandle;    // System window handle
 
    DialogResult returnCode;// Return code for modal windows
-  
+
    Point sbStep;           // Scrollbar line scrolling steps
 
    Anchor stateAnchor;
@@ -9506,23 +9917,15 @@ private:
    int numIcons;
    int positionID;
 
+#if !defined(__EMSCRIPTEN__)
    Mutex mutex;
+#endif
    WindowState lastState;
 
-   FileMonitor fileMonitor
-   {
-      this, FileChange { modified = true };
+#if !defined(__EMSCRIPTEN__)
+   FileMonitor fileMonitor;
+#endif
 
-      bool OnFileNotify(FileChange action, char * param)
-      {
-         incref this;
-         fileMonitor.StopMonitoring();
-         if(OnFileModified(action, param))
-            fileMonitor.StartMonitoring();
-         delete this;
-         return true;
-      }
-   };
    FontResource setFont, systemFont;
    FontResource usedFont;
    FontResource captionFont;
@@ -9538,6 +9941,8 @@ private:
    BitmapResource icon;
    void * windowData;
    CreationActivationOption creationActivation;
+   GLCapabilities glCapabilities;
+   glCapabilities = { true, true, true, true, true, true, true, true, true /*false*/, true, true, true, true, true, true, true };
    struct
    {
       bool active:1;            // true if window and ancestors are active
@@ -9570,14 +9975,38 @@ private:
       bool nativeDecorations:1;
       bool manageDisplay:1;
       bool formDesigner:1; // True if we this is running in the form editor
-   }; 
+      bool requireRemaximize:1;
+      bool noConsequential:1;
+   };
 
    // Checks used internally for them not to take effect in FormDesigner
    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
 
    WindowController controller;
-   public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
+
+   public property WindowController controller
+   {
+      get { return controller; }
+      set
+      {
+         if(controller)
+            controller.setWindow(null);
+         delete controller;
+         controller = value;
+         if(controller)
+         {
+            incref controller;
+            controller.setWindow(this);
+         }
+      }
+   }
+
+   public property bool noConsequential
+   {
+      set { noConsequential = value; }
+      get { return noConsequential; }
+   }
 };
 
 public class CommonControl : Window
@@ -9585,7 +10014,7 @@ public class CommonControl : Window
    // creationActivation = doNothing;
 
    ToolTip toolTip;
-   public property String toolTip
+   public property const String toolTip
    {
       property_category $"Appearance"
       set
@@ -9622,7 +10051,7 @@ public class CommonControl : Window
 
 public class Percentage : float
 {
-   char * OnGetString(char * string, float * fieldData, bool * needClass)
+   const char * OnGetString(char * string, float * fieldData, bool * needClass)
    {
       int c;
       int last = 0;
@@ -9630,7 +10059,7 @@ public class Percentage : float
       c = strlen(string)-1;
       for( ; c >= 0; c--)
       {
-         if(string[c] != '0') 
+         if(string[c] != '0')
             last = Max(last, c);
          if(string[c] == '.')
          {
@@ -9645,7 +10074,7 @@ public class Percentage : float
    }
 };
 
-public void ApplySkin(Class c, char * name, void ** vTbl)
+public void ApplySkin(Class c, const char * name, void ** vTbl)
 {
    char className[1024];
    Class sc;
@@ -9660,7 +10089,7 @@ public void ApplySkin(Class c, char * name, void ** vTbl)
    c._vTbl = new void *[c.vTblSize];
    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
    sc = eSystem_FindClass(c.module.application, className);
-   
+
    if(vTbl)
    {
       for(m = 0; m < c.base.vTblSize; m++)
@@ -9677,7 +10106,7 @@ public void ApplySkin(Class c, char * name, void ** vTbl)
             c._vTbl[m] = sc._vTbl[m];
       }
    }
-      
+
    for(d = c.derivatives.first; d; d = d.next)
    {
       ApplySkin(d.data, name, c._vTbl);
@@ -9686,10 +10115,7 @@ public void ApplySkin(Class c, char * name, void ** vTbl)
 
 public void UnapplySkin(Class c)
 {
-   char className[1024];
-   Class sc;
    subclass(Window) wc = (subclass(Window))c;
-   subclass(Window) base = (subclass(Window))c.base;
    OldLink d;
 
    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
@@ -9733,176 +10159,267 @@ class WindowControllerInterface : ControllableWindow
 {
    bool OnKeyDown(Key key, unichar ch)
    {
-      bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyDown)((Window)controller.controlled, controller, key, ch);
+      bool result = controller.OnKeyDown ? ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyDown)((Window)controller.controlled, controller, key, ch) : true;
       if(result)
-         result = ((bool (*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown])(controller.window, key, ch);
+      {
+         bool (* onKeyDown)(Window, Key, unichar) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown];
+         if(onKeyDown)
+            result = onKeyDown(controller.window, key, ch);
+      }
       return result;
    }
 
    bool OnKeyUp(Key key, unichar ch)
    {
-      bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyUp)((Window)controller.controlled, controller, key, ch);
+      bool result = controller.OnKeyUp ? ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyUp)((Window)controller.controlled, controller, key, ch) : true;
       if(result)
-         result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp])(controller.window, key, ch);
+      {
+         bool (* onKeyUp)(Window, Key, unichar) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp];
+         if(onKeyUp)
+            result = onKeyUp(controller.window, key, ch);
+      }
       return result;
    }
 
    bool OnKeyHit(Key key, unichar ch)
    {
-      bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyHit)((Window)controller.controlled, controller, key, ch);
+      bool result = controller.OnKeyHit ? ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyHit)((Window)controller.controlled, controller, key, ch) : true;
       if(result)
-         result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit])(controller.window, key, ch);
+      {
+         bool (* onKeyHit)(Window, Key, unichar) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit];
+         if(onKeyHit)
+            result = onKeyHit(controller.window, key, ch);
+      }
       return result;
    }
 
    bool OnMouseMove(int x, int y, Modifiers mods)
    {
-      bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMouseMove)((Window)controller.controlled, controller, x, y, mods);
+      bool result = controller.OnMouseMove ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMouseMove)((Window)controller.controlled, controller, x, y, mods) : true;
       if(result)
-         result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove])(controller.window, x, y, mods);
+      {
+         bool(* onMouseMove)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove];
+         if(onMouseMove)
+            result = onMouseMove(controller.window, x, y, mods);
+      }
       return result;
    }
 
    bool OnLeftButtonDown(int x, int y, Modifiers mods)
    {
-      bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonDown)((Window)controller.controlled, controller, x, y, mods);
+      bool result = controller.OnLeftButtonDown ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonDown)((Window)controller.controlled, controller, x, y, mods) : true;
       if(result)
-         result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown])(controller.window, x, y, mods);
+      {
+         bool(* onLeftButtonDown)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown];
+         if(onLeftButtonDown)
+            result = onLeftButtonDown(controller.window, x, y, mods);
+      }
       return result;
    }
 
    bool OnLeftButtonUp(int x, int y, Modifiers mods)
    {
-      bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonUp)((Window)controller.controlled, controller, x, y, mods);
+      bool result = controller.OnLeftButtonUp ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonUp)((Window)controller.controlled, controller, x, y, mods) : true;
       if(result)
-         result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp])(controller.window, x, y, mods);
+      {
+         bool(* onLeftButtonUp)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp];
+         if(onLeftButtonUp)
+            result = onLeftButtonUp(controller.window, x, y, mods);
+      }
       return result;
    }
 
    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
    {
-      bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftDoubleClick)((Window)controller.controlled, controller, x, y, mods);
+      bool result = controller.OnLeftDoubleClick ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftDoubleClick)((Window)controller.controlled, controller, x, y, mods) : true;
       if(result)
-         result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick])(controller.window, x, y, mods);
+      {
+         bool(* onLeftDoubleClick)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick];
+         if(onLeftDoubleClick)
+            result = onLeftDoubleClick(controller.window, x, y, mods);
+      }
       return result;
    }
 
    bool OnRightButtonDown(int x, int y, Modifiers mods)
    {
-      bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonDown)((Window)controller.controlled, controller, x, y, mods);
+      bool result = controller.OnRightButtonDown ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonDown)((Window)controller.controlled, controller, x, y, mods) : true;
       if(result)
-         result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown])(controller.window, x, y, mods);
+      {
+         bool(* onRightButtonDown)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown];
+         if(onRightButtonDown)
+            result = onRightButtonDown(controller.window, x, y, mods);
+      }
       return result;
    }
 
    bool OnRightButtonUp(int x, int y, Modifiers mods)
    {
-      bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonUp)((Window)controller.controlled, controller, x, y, mods);
+      bool result = controller.OnRightButtonUp ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonUp)((Window)controller.controlled, controller, x, y, mods) : true;
       if(result)
-         result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp])(controller.window, x, y, mods);
+      {
+         bool(* onRightButtonUp)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp];
+         if(onRightButtonUp)
+            result = onRightButtonUp(controller.window, x, y, mods);
+      }
       return result;
    }
 
    bool OnRightDoubleClick(int x, int y, Modifiers mods)
    {
-      bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightDoubleClick)((Window)controller.controlled, controller, x, y, mods);
+      bool result = controller.OnRightDoubleClick ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightDoubleClick)((Window)controller.controlled, controller, x, y, mods) : true;
       if(result)
-         result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick])(controller.window, x, y, mods);
+      {
+         bool(* onRightDoubleClick)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick];
+         if(onRightDoubleClick)
+            result = onRightDoubleClick(controller.window, x, y, mods);
+      }
       return result;
    }
 
    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
    {
-      bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonDown)((Window)controller.controlled, controller, x, y, mods);
+      bool result = controller.OnMiddleButtonDown ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonDown)((Window)controller.controlled, controller, x, y, mods) : true;
       if(result)
-         result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown])(controller.window, x, y, mods);
+      {
+         bool(* onMiddleButtonDown)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown];
+         if(onMiddleButtonDown)
+            result = onMiddleButtonDown(controller.window, x, y, mods);
+      }
       return result;
    }
 
    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
    {
-      bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonUp)((Window)controller.controlled, controller, x, y, mods);
+      bool result = controller.OnMiddleButtonUp ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonUp)((Window)controller.controlled, controller, x, y, mods) : true;
       if(result)
-         result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp])(controller.window, x, y, mods);
+      {
+         bool(* onMiddleButtonUp)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp];
+         if(onMiddleButtonUp)
+            result = onMiddleButtonUp(controller.window, x, y, mods);
+      }
       return result;
    }
 
    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
    {
-      bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleDoubleClick)((Window)controller.controlled, controller, x, y, mods);
+      bool result = controller.OnMiddleDoubleClick ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleDoubleClick)((Window)controller.controlled, controller, x, y, mods) : true;
       if(result)
-         result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick])(controller.window, x, y, mods);
+      {
+         bool(* onMiddleDoubleClick)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick];
+         if(onMiddleDoubleClick)
+            onMiddleDoubleClick(controller.window, x, y, mods);
+      }
+      return result;
+   }
+
+   bool OnMultiTouch(TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers mods)
+   {
+      bool result = controller.OnMultiTouch ? ((bool(*)(Window, WindowController, TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers))(void *)controller.OnMultiTouch)((Window)controller.controlled, controller, event, infos, mods) : true;
+      if(result)
+      {
+         bool(* onMultiTouch)(Window, TouchPointerEvent, Array<TouchPointerInfo>, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMultiTouch];
+         if(onMultiTouch)
+            onMultiTouch(controller.window, event, infos, mods);
+      }
       return result;
    }
 
    void OnResize(int width, int height)
    {
-      ((void(*)(Window, WindowController, int, int))(void *)controller.OnResize)((Window)controller.controlled, controller, width, height);
-      ((void(*)(Window, int, int))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize])(controller.window, width, height);
+      if(controller.OnResize)
+         ((void(*)(Window, WindowController, int, int))(void *)controller.OnResize)((Window)controller.controlled, controller, width, height);
+      {
+         void(* onResize)(Window, int, int) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize];
+         if(onResize)
+            onResize(controller.window, width, height);
+      }
    }
 
    void OnRedraw(Surface surface)
    {
-      ((void(*)(Window, WindowController, Surface))(void *)controller.OnRedraw)((Window)controller.controlled, controller, surface);
-      ((void(*)(Window, Surface))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw])(controller.window, surface);
+      if(controller.OnRedraw)
+         ((void(*)(Window, WindowController, Surface))(void *)controller.OnRedraw)((Window)controller.controlled, controller, surface);
+      {
+         void(* onRedraw)(Window, Surface) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw];
+         if(onRedraw)
+            onRedraw(controller.window, surface);
+      }
    }
 
    bool OnCreate()
    {
-      bool result = ((bool(*)(Window, WindowController))(void *)controller.OnCreate)((Window)controller.controlled, controller);
+      bool result = controller.OnCreate ? ((bool(*)(Window, WindowController))(void *)controller.OnCreate)((Window)controller.controlled, controller) : true;
       if(result)
-         result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate])(controller.window);
+      {
+         bool(* onCreate)(Window) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate];
+         if(onCreate)
+            result = onCreate(controller.window);
+      }
       return result;
    }
 
    bool OnLoadGraphics()
    {
-      bool result = ((bool(*)(Window, WindowController))(void *)controller.OnLoadGraphics)((Window)controller.controlled, controller);
+      bool result = controller.OnLoadGraphics ? ((bool(*)(Window, WindowController))(void *)controller.OnLoadGraphics)((Window)controller.controlled, controller) : true;
       if(result)
-         result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics])(controller.window);
+      {
+         bool(* onLoadGraphics)(Window) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics];
+         if(onLoadGraphics)
+            result = onLoadGraphics(controller.window);
+      }
       return result;
    }
 
    void OnUnloadGraphics()
    {
-      ((void(*)(Window, WindowController))(void *)controller.OnUnloadGraphics)((Window)controller.controlled, controller);
-      ((void(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics])(controller.window);
+      if(controller.OnUnloadGraphics)
+         ((void(*)(Window, WindowController))(void *)controller.OnUnloadGraphics)((Window)controller.controlled, controller);
+      {
+         void(* onUnloadGraphics)(Window) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics];
+         if(onUnloadGraphics)
+            onUnloadGraphics(controller.window);
+      }
    }
 }
 
 public class WindowController<class V>
 {
-public:
-   property Window window
+   void setWindow(Window value)
    {
-      set
+      uint size = class(Window).vTblSize;
+      if(value)
       {
-         uint size = class(Window).vTblSize;
-         if(value)
+         delete windowVTbl;
+         windowVTbl = new void *[size];
+         memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
+         if(value._vTbl == value._class._vTbl)
          {
-            windowVTbl = new void *[size];
-            memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
-            if(value._vTbl == value._class._vTbl)
-            {
-               value._vTbl = new void *[value._class.vTblSize];
-               memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
-            }
+            value._vTbl = new void *[value._class.vTblSize];
+            memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
+         }
+         {
+            int c;
+            for(c = 0; c < size; c++)
             {
-               int c;
-               for(c = 0; c < size; c++)
-               {
-                  void * function = class(WindowControllerInterface)._vTbl[c];
-                  if(function != DefaultFunction)
-                     value._vTbl[c] = function;
-                  else
-                     value._vTbl[c] = windowVTbl[c];
-               }
+               void * function = class(WindowControllerInterface)._vTbl[c];
+               if(function && function != DefaultFunction)
+                  value._vTbl[c] = function;
+               else
+                  value._vTbl[c] = windowVTbl[c];
             }
          }
-         else
-            memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
-         window = value;
       }
+      else if(window)
+      {
+         memcpy(window._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
+         delete windowVTbl;
+      }
+      window = value;
+   }
+public:
+   property Window window
+   {
       get { return window; }
    }
    property V controlled
@@ -9910,6 +10427,7 @@ public:
       set { controlled = value; }
       get { return controlled; }
    }
+   // TODO: Add OnStateChange so we can implement SavedConfigWindow as a WindowController instead
    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
@@ -9923,6 +10441,7 @@ public:
    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
+   virtual bool V::OnMultiTouch(WindowController controller, TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers mods);
    virtual void V::OnResize(WindowController controller, int width, int height);
    virtual void V::OnRedraw(WindowController controller, Surface surface);
    virtual bool V::OnCreate(WindowController controller);
@@ -9930,7 +10449,7 @@ public:
    virtual void V::OnUnloadGraphics(WindowController controller);
 
 private:
-   int (** windowVTbl)();   
+   public int (** windowVTbl)();
    V controlled;
    Window window;