ecere/gui/3D Desktop; samples/orbitWithMouse: Fixes to run in window with native...
[sdk] / ecere / src / gui / Window.ec
index 7977ff7..5fa4cf2 100644 (file)
@@ -490,12 +490,12 @@ private class HotKeySlot : struct
 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); }
@@ -568,6 +568,16 @@ private:
       OldLink slave;
       ResPtr ptr;
 
+      if(fileMonitor)
+      {
+         int i, lockCount = guiApp.lockMutex.lockCount;
+         for(i = 0; i < lockCount; i++)
+            guiApp.lockMutex.Release();
+         delete fileMonitor;
+         for(i = 0; i < lockCount; i++)
+            guiApp.lockMutex.Wait();
+      }
+
       if(parent)
       {
          stopwatching(parent, font);
@@ -606,7 +616,7 @@ private:
       delete order;
       /////////////////////////////////
 
-      while(ptr = resources.first)
+      while((ptr = resources.first))
       {
          delete ptr.resource;
          resources.Delete(ptr);
@@ -625,7 +635,7 @@ private:
          *&child.parent = null;
       }
 
-      while(slave = slaves.first)
+      while((slave = slaves.first))
       {
          // Don't want property here
          *&((Window)slave.data).master = null;
@@ -688,23 +698,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
       {
-         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 +755,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 +767,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,7 +811,7 @@ 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);
@@ -802,13 +822,21 @@ private:
             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 +977,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)
@@ -1050,7 +1078,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;
@@ -1602,6 +1630,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,7 +1646,8 @@ private:
                   }
                }
             }
-            //if(!found)
+            if(!found)
+            */
             {
                Window parent = this.parent;
                parent.Position(
@@ -1642,7 +1673,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;
@@ -1840,8 +1871,8 @@ private:
       {
          MinMaxValue cw = 0, ch = 0;
          bool sbvVisible, sbhVisible;
-         int rangeH, rangeV;
-         int positionH, positionV;
+         int rangeH = 0, rangeV = 0;
+         int positionH = 0, positionV;
 
          // First get client area with no respect to scroll bars
 
@@ -2233,6 +2264,7 @@ private:
    Window GetParentMenuBar()
    {
       Window menuBarParent;
+      if(formDesigner) return null;
       for(menuBarParent = this ? parent : null; menuBarParent; menuBarParent = menuBarParent.parent)
       {
          if(menuBarParent.menuBar) return menuBarParent.menuBar;
@@ -2311,18 +2343,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 == maximized)
          {
-            skin = restore;
+            //skin = restore;
             method = RestoreButtonClicked;
             symbol = '\x12';
          }
          else
          {
-            skin = maximize;
+            //skin = maximize;
             method = MaximizeButtonClicked;
             symbol = '\x18';
          }
@@ -2344,18 +2376,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)
          {
-            skin = restore;
+            //skin = restore;
             method = RestoreButtonClicked;
             symbol = '\x12';
          }
          else
          {
-            skin = minimize;
+            //skin = minimize;
             method = MinimizeButtonClicked;
             symbol = '\x19';
          }
@@ -2439,7 +2471,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 +2483,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 +2512,7 @@ private:
       if(menu)
       {
          MenuItem item;
-         bool disabled;
+         //bool disabled;
 
          if(menu)
             menu.Clean(this);
@@ -2493,7 +2527,6 @@ 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)
                   {
@@ -2514,10 +2547,10 @@ 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);
@@ -2564,7 +2597,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);
@@ -2720,7 +2753,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 +2764,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)
          {
@@ -3253,8 +3284,7 @@ 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)
                   {
@@ -3265,8 +3295,7 @@ private:
                }
                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 +3328,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)
                {
@@ -3357,7 +3386,7 @@ private:
       mouseWindow = rootWindow ? rootWindow.GetAtPosition(x,y, true, false, null) : null;
 
       if((guiApp.windowMoving && !guiApp.windowIsResizing) || guiApp.windowScrolling)
-         guiApp.SetCurrentCursor(guiApp.windowMoving, guiApp.systemCursors[moving]);
+         guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[moving]);
       else if(mouseWindow)
       {
          modalWindow = mouseWindow.FindModal();
@@ -3370,13 +3399,13 @@ private:
             rx = guiApp.resizeX;
             ry = guiApp.resizeY;
             if((rex && rey) || (rx && ry))
-               guiApp.SetCurrentCursor(guiApp.windowMoving, guiApp.systemCursors[sizeNWSE]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNWSE]);
             else if((rex && ry) || (rx && rey))
-               guiApp.SetCurrentCursor(guiApp.windowMoving, guiApp.systemCursors[sizeNESW]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNESW]);
             else if((ry || rey) && (!rx && !rex))
-               guiApp.SetCurrentCursor(guiApp.windowMoving, guiApp.systemCursors[sizeNS]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNS]);
             else if((rx || rex) && (!ry && !rey))
-               guiApp.SetCurrentCursor(guiApp.windowMoving, guiApp.systemCursors[sizeWE]);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeWE]);
          }
          else if(!modalWindow && !guiApp.windowCaptured &&
             mouseWindow.IsMouseResizing(x, y, mouseWindow.size.w, mouseWindow.size.h,
@@ -3404,16 +3433,16 @@ private:
          if(cursorWindow)
          {
             for(; !cursorWindow.cursor && !cursorWindow.style.nonClient && cursorWindow.rootWindow != cursorWindow; cursorWindow = cursorWindow.parent);
-            guiApp.SetCurrentCursor(cursorWindow, cursorWindow.cursor ? cursorWindow.cursor : guiApp.systemCursors[arrow]);
+            guiApp.SetCurrentCursor(mouseWindow, cursorWindow.cursor ? cursorWindow.cursor : guiApp.systemCursors[arrow]);
          }
          else if(modalWindow)
          {
-            guiApp.SetCurrentCursor(null, guiApp.systemCursors[arrow]);
+            guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[arrow]);
          }
          else if(guiApp.interimWindow)
          {
             if(guiApp.interimWindow.cursor)
-               guiApp.SetCurrentCursor(guiApp.interimWindow, guiApp.interimWindow.cursor);
+               guiApp.SetCurrentCursor(mouseWindow, guiApp.interimWindow.cursor);
             else
                guiApp.SetCurrentCursor(mouseWindow, mouseWindow.cursor ? mouseWindow.cursor : guiApp.systemCursors[arrow]);
          }
@@ -3458,6 +3487,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)
@@ -3467,7 +3505,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
          {
@@ -3481,7 +3519,7 @@ private:
                this.active = active;
                if(acquiredInput)
                   AcquireInputEx(active);
-               if(active)
+               if(active && isEnabled)
                {
                   if(caretSize)
                   {
@@ -3559,7 +3597,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);
@@ -3643,7 +3682,7 @@ private:
 
                   if(real)
                   {
-                     bool acquireInput = false;
+                     //bool acquireInput = false;
                      bool maximize =
                         parent.activeChild &&
                         parent.activeChild.state == maximized &&
@@ -3680,7 +3719,7 @@ private:
                               delete this;
                               return false;
                            }
-                           acquireInput = true;
+                           //acquireInput = true;
                         }
                      }
 
@@ -4248,14 +4287,37 @@ private:
          if(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 w = it.data;
+               if(trueWindow != w && !trueWindow.IsDescendantOf(w))
+               {
+                  it.pointer = null;
+                  result = w.OnMouseLeave(*mods);
+                  if(!result) break;
+                  overWindows.TakeOut(w);
+               }
+            }
+
+            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*/)
             {
@@ -4279,13 +4341,22 @@ private:
                }
             }
             if(trueWindow && trueWindow._refCount > 1 && !trueWindow.destroyed)
+            {
+               for(w : guiApp.overWindows; w == trueWindow)
+               {
+                  OnMouseLeave(0);
+                  guiApp.overWindows.TakeOut(w);
+                  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);
@@ -4547,10 +4618,10 @@ private:
                         {
                            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)
@@ -4822,7 +4893,8 @@ private:
          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);
@@ -4863,6 +4935,9 @@ private:
       {
          if(child.created && !child.Setup(false))
             result = false;
+
+         if(guiApp.modeSwitching && guiApp.fullScreen && child.rootWindow == child)
+            child.UpdateCaption();
       }
       return result;
    }
@@ -4990,7 +5065,8 @@ private:
 
             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);
@@ -5150,15 +5226,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;
    }
@@ -5311,7 +5383,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);
 
@@ -5408,6 +5480,15 @@ private:
          guiApp.prevWindow = null;
          OnMouseLeave(0);
       }
+      else
+      {
+         for(w : guiApp.overWindows; w == this)
+         {
+            OnMouseLeave(0);
+            guiApp.overWindows.TakeOut(w);
+            break;
+         }
+      }
       if(guiApp.caretOwner == this)
       {
          guiApp.interfaceDriver.SetCaret(0,0,0);
@@ -5789,7 +5870,7 @@ private:
 
          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);
       }
 
@@ -5858,7 +5939,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);
          }
@@ -6054,6 +6135,28 @@ private:
       }
    }
 
+   void SetupFileMonitor()
+   {
+      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;
+      }
+   }
+
 public:
    // normal Methods
    bool Create()
@@ -6064,7 +6167,6 @@ public:
          result = true;
       else if(guiApp && guiApp.driver != null)
       {
-         void * systemParent = null;
          OldLink slaveHolder;
          Window last;
          bool visible = !style.hidden;
@@ -6261,6 +6363,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);
@@ -6272,10 +6376,14 @@ 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)
@@ -6497,7 +6605,6 @@ public:
 
    void SetScrollArea(int width, int height, bool snapToStep)
    {
-      bool resize = false;
       if(snapToStep)
       {
          int stepX = sbStep.x, stepY = sbStep.y;
@@ -6609,7 +6716,7 @@ public:
       {
          if(state == newState || OnStateChange(newState, mods))
          {
-            WindowState prevState = state;
+            //WindowState prevState = state;
 
             StopMoving();
 
@@ -6776,7 +6883,11 @@ public:
       if(guiApp.desktop.active)
          Activate();
       else if(!active)
-         Flash();
+      {
+         MakeActive();
+         if(this == rootWindow)
+            Flash();
+      }
    }
 
    void Deactivate(void)
@@ -6887,7 +6998,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();
          }
          /*
@@ -6939,7 +7051,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;
@@ -7011,7 +7123,7 @@ public:
       }
    }
 
-   private void _SetCaption(char * format, va_list args)
+   private void _SetCaption(const char * format, va_list args)
    {
       if(this)
       {
@@ -7031,7 +7143,7 @@ public:
       }
    }
 
-   /*deprecated*/ void SetText(char * format, ...)
+   /*deprecated*/ void SetText(const char * format, ...)
    {
       va_list args;
       va_start(args, format);
@@ -7039,7 +7151,7 @@ public:
       va_end(args);
    }
 
-   void SetCaption(char * format, ...)
+   void SetCaption(const char * format, ...)
    {
       va_list args;
       va_start(args, format);
@@ -7250,19 +7362,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;
@@ -7301,6 +7422,7 @@ public:
 
    bool MenuFileSave(MenuItem selection, Modifiers mods)
    {
+      SetupFileMonitor();
       if(fileName)
       {
          fileMonitor.fileName = null;
@@ -7331,6 +7453,8 @@ public:
       DialogResult result = (DialogResult)bool::true;
       FileDialog fileDialog = saveDialog;
 
+      SetupFileMonitor();
+
       if(!fileDialog)
          fileDialog = FileDialog {};
       if(fileDialog)
@@ -7354,7 +7478,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))
                {
@@ -7501,7 +7625,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;
@@ -7722,7 +7846,7 @@ public:
    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
    {
       WindowList dialog { master = this };
-      Window document = (Window)dialog.Modal();
+      Window document = (Window)(intptr)dialog.Modal();
       if(document)
       {
          if(activeChild.state == maximized)
@@ -7773,8 +7897,8 @@ public:
    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
@@ -7791,8 +7915,8 @@ public:
       *cw = *w;
       *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;
@@ -7802,7 +7926,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});
@@ -7815,7 +7939,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
 
@@ -8003,7 +8127,7 @@ public:
                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) ||
                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
@@ -8090,7 +8214,7 @@ public:
       get { return master ? master : parent; }
    };
 
-   property char * caption
+   property const char * caption
    {
       property_category $"Appearance"
       watchable
@@ -8391,8 +8515,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)
@@ -8661,11 +8785,6 @@ 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) ||
                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
@@ -9031,10 +9150,14 @@ public:
                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);
@@ -9055,7 +9178,7 @@ public:
    property bool isDocument
    {
       property_category $"Document"
-      set { style.isDocument = value; }
+      set { style.isDocument = value; if(value) SetupFileMonitor(); }
       get { return style.isDocument; }
    };
 
@@ -9192,11 +9315,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);
@@ -9255,13 +9380,29 @@ public:
    {
       property_category $"Window Style"
       set { style.showInTaskBar = value; }
-      get { return (style.showInTaskBar; }
+      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; }
    };
 
@@ -9277,7 +9418,7 @@ public:
    };
 
 //#if !defined(ECERE_VANILLA)
-   property char * name
+   property const char * name
    {
       property_category $"Design"
       get
@@ -9291,7 +9432,7 @@ public:
       }
    };
 //#endif
-   property char * displayDriver
+   property const char * displayDriver
    {
       property_category $"Behavior"
       set
@@ -9410,7 +9551,7 @@ public:
    };
    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
 
-   property char * text
+   property const char * text
    {
       property_category $"Deprecated"
       watchable
@@ -9510,20 +9651,8 @@ private:
    Mutex mutex;
    WindowState lastState;
 
-   FileMonitor fileMonitor
-   {
-      this, FileChange { modified = true };
+   FileMonitor fileMonitor;
 
-      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;
@@ -9571,6 +9700,7 @@ private:
       bool nativeDecorations:1;
       bool manageDisplay:1;
       bool formDesigner:1; // True if we this is running in the form editor
+      bool requireRemaximize:1;
    };
 
    // Checks used internally for them not to take effect in FormDesigner
@@ -9586,7 +9716,7 @@ public class CommonControl : Window
    // creationActivation = doNothing;
 
    ToolTip toolTip;
-   public property String toolTip
+   public property const String toolTip
    {
       property_category $"Appearance"
       set
@@ -9623,7 +9753,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;
@@ -9646,7 +9776,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;
@@ -9687,10 +9817,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)