ide: Fixed zombie documentor processes
[sdk] / ide / src / ide.ec
index 624ab64..30d3837 100644 (file)
@@ -9,14 +9,12 @@ public import "ec"
 import "GlobalSettingsDialog"
 import "NewProjectDialog"
 import "FindInFilesDialog"
-import "ActiveCompilerDialog"
 
 #ifdef GDB_DEBUG_GUI
 import "GDBDialog"
 #endif
 
 import "Project"
-import "ProjectActiveConfig"
 import "ProjectConfig"
 import "ProjectNode"
 import "NodeProperties"
@@ -171,7 +169,7 @@ GlobalSettingsDialog globalSettingsDialog
             break;
          case compilerSettings:
          {
-            ide.UpdateMakefiles();
+            ide.UpdateCompilerConfigs(true);
             break;
          }
       }
@@ -193,89 +191,170 @@ void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int
    }
 }
 
-// NOTE: We will move ToolBar and ToolButton classes to libecere...
-public class ToolBar : public Stacker
-{
-   direction = horizontal;
-   background = activeBorder;
-   gap = 0;
-   inactive = true;
+#define IDEItem(x)   (&((IDEWorkSpace)0).x)
 
-   anchor = Anchor { left = 0, right = 0 };
-   clientSize = { h = 32 };
-   borderStyle = bevel;
+class IDEToolbar : ToolBar
+{
+   /* File options */
+   // New
+   ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
+   // Open
+   ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
+   // Close
+   // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
+   // Save
+   ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
+   // Save All
+   ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
+
+   ToolSeparator separator1 { this };
+
+   /* Edit options */
+   // Cut
+   // Copy 
+   // Paste
+   // Undo
+   // Redo
+
+   // ToolSeparator separator2 { this };
+
+   /* Project  options */
+   // New project
+   ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
+   // Open project
+   ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
+   // Add project to workspace
+   ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
+   // Close project
+   // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
+
+   ToolSeparator separator3 { this };
+
+   /* Build/Execution options */
+   // Build
+   ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
+   // Re-link
+   ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
+   // Rebuild
+   ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
+   // Clean
+   ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
+   // Real Clean
+   // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
+   // Regenerate Makefile
+   ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
+   // Compile actual file
+   // Execute
+   ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
+#ifdef IDE_SHOW_INSTALL_MENU_BUTTON
+   ToolButton buttonInstall { this, toolTip = $"Install", menuItemPtr = IDEItem(projectInstallItem), disabled = true; };
+#endif
 
-   watch(master)
+   ToolSeparator separator4 { this };
+
+   /* Debug options */
+   // Start/Resume
+   ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
+   // Restart
+   ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
+   // Pause
+   ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
+   // Stop
+   ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
+   // Breakpoints
+   //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
+   // F11
+   ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
+   // F10
+   ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
+   // Shift+F11
+   ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
+   // Shift+F10
+   ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
+
+   ToolSeparator separator5 { this };
+
+   Window spacer5 { this, size = { 4 } };
+
+   DropBox activeConfig
    {
-      Window m = master;
-      Window w;
-      for(w = firstChild; w; w = w.next)
+      this, toolTip = $"Active Configuration(s)", size = { 160 }, disabled = true;
+      bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
       {
-         w.master = master;
-         if(eClass_IsDerived(w._class, class(ToolButton)))
-         {
-            ToolButton b = (ToolButton)w;
-            MenuItem menuItem = b.menuItem;
-            BitmapResource bmp;
-            if(menuItem && (bmp = menuItem.bitmap))
-               b.bitmap = bmp;
-         }
+         if(row)
+            ide.workspace.SelectActiveConfig(row.string);
+         return true;
       }
    };
-}
-
-public class ToolButton : public Button
-{
-   bevelOver = true;
-   size = Size { 24, 24 };
-   opacity = 0;
-   bitmapAlignment = center;
-   MenuItem * menuItemPtr;
-
-   watch(master) { Window w; for(w = firstChild; w; w = w.next) w.master = master; };
 
-   NotifyClicked = SelectMenuItem;
+   Window spacer6 { this, size = { 4 } };
 
-   bool Window::SelectMenuItem(Button button, int x, int y, Modifiers mods)
+   DropBox activeCompiler
    {
-      ToolButton toolButton = (ToolButton)button;
-      MenuItem menuItem = toolButton.menuItem;
-      return menuItem.NotifySelect(this, menuItem, 0);
-   }
+      this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
+      bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
+      {
+         if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.compiler))
+         {
+            bool silent = ide.projectView.buildInProgress == none ? false : true;
+            CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
+            ide.workspace.compiler = row.string;
+            ide.projectView.ShowOutputBuildLog(!silent);
+            if(!silent)
+               ide.projectView.DisplayCompiler(compiler, false);
+            for(prj : ide.workspace.projects)
+               ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
+            delete compiler;
+            ide.workspace.Save();
+         }
+         return true;
+      }
+   };
 
-public:
-   property MenuItem * menuItemPtr { set { menuItemPtr = value; } }
-   property MenuItem menuItem
+   DropBox activeBitDepth
    {
-      get
-      {
-         MenuItem menuItem = *(MenuItem *)((byte *)master + (uint)menuItemPtr);
-         return menuItem;
+      this, toolTip = $"Active Bit Depth", size = { 60 }, disabled = true;
+      bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
+      {
+         if(ide.workspace && ide.projectView && row)
+         {
+            bool silent = ide.projectView.buildInProgress == none ? false : true;
+            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+            ide.workspace.bitDepth = (int)row.tag;
+            ide.projectView.ShowOutputBuildLog(!silent);
+            if(!silent)
+               ide.projectView.DisplayCompiler(compiler, false);
+            for(prj : ide.workspace.projects)
+               ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
+            delete compiler;
+            ide.workspace.Save();
+         }
+         return true;
       }
-   }
-}
+   };
 
-#define IDEItem(x)   (&((IDEWorkSpace)0).x)
+   Window spacer7 { this, size = { 4 } };
+
+   void IDEToolbar()
+   {
+      DataRow row;
+      row = activeBitDepth.AddString("Auto");
+      row.tag = 0;
+      activeBitDepth.AddString("32 bit").tag = 32;
+      activeBitDepth.AddString("64 bit").tag = 64;
+      activeBitDepth.currentRow = row;
+   }
 
-class IDEToolbar : ToolBar
-{
-   ToolButton buttonNewProject { this, toolTip = $"New Project", menuItemPtr = IDEItem(projectNewItem) };
 }
 
 class IDEMainFrame : Window
 {
-   background = activeBorder;
+   background = formColor;
    borderStyle = sizable;
    hasMaximize = true;
    hasMinimize = true;
    hasClose = true;
-   size = { 840, 480 };
    minClientSize = { 600, 300 };
-   nativeDecorations = true; 
-   borderStyle = sizable;
-   hasMaximize = true;
-   hasMinimize = true;
-   hasClose = true;
    hasMenuBar = true;
    icon = { ":icon.png" };
    text = titleECEREIDE;
@@ -295,11 +374,19 @@ class IDEMainFrame : Window
       isActiveClient = true;
       gap = 0;
       direction = vertical;
-      background = activeBorder;
+      background = formColor;
       anchor = { left = 0, top = 0, right = 0, bottom = 0 };
    };
-   IDEToolbar toolBar { master = ideWorkSpace, parent = stack };
-   IDEWorkSpace ideWorkSpace { master = this, parent = stack };
+   IDEToolbar toolBar
+   {
+      stack, ideWorkSpace;
+
+      void OnDestroy(void)
+      {
+         ((IDEWorkSpace)master).toolBar = null;
+      }
+   };
+   IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
 }
 
 define ide = ideMainFrame.ideWorkSpace;
@@ -315,10 +402,12 @@ class IDEWorkSpace : Window
    isActiveClient = true;
    anchor = { left = 0, top = 0, right = 0, bottom = 0 };
    menu = Menu {  };
+   IDEToolbar toolBar;
 
    MenuItem * driverItems, * skinItems;
    StatusField pos { width = 150 };
    StatusField ovr, caps, num;
+   DualPipe documentor;
 
    BitmapResource back                 { ":ecereBack.jpg", window = this };
    BitmapResource bmpBp                { ":codeMarks/breakpoint.png", window = this };
@@ -340,9 +429,9 @@ class IDEWorkSpace : Window
    {
       parent = this;
 
-      void OnGotoError(char * line)
+      void OnGotoError(char * line, bool noParsing)
       {
-         ide.GoToError(line);
+         ide.GoToError(line, noParsing);
       }
 
       void OnCodeLocationParseAndGoTo(char * line)
@@ -355,12 +444,9 @@ class IDEWorkSpace : Window
          switch(key)
          {
             case escape: 
-               if(!ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
+               if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
                   ide.ShowCodeEditor(); 
                break;
-            case ctrlS:
-               ide.projectView.stopBuild = true;
-               break;
             default:
             {
                OutputView::OnKeyDown(key, ch);
@@ -370,13 +456,6 @@ class IDEWorkSpace : Window
          return true;
       }
 
-      bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
-      {
-         if(active)
-            ide.RepositionWindows(false);
-         return true;
-      }
-
       bool OnClose(bool parentClosing)
       {
          visible = false;
@@ -390,16 +469,11 @@ class IDEWorkSpace : Window
    {
       parent = this, font = { panelFont.faceName, panelFont.size };
 
-      void OnGotoLine(char * line)
+      void OnSelectFrame(int frameIndex)
       {
-         int stackLvl;
-         stackLvl = atoi(line);
-         ide.debugger.GoToStackFrameLine(stackLvl, true);
-      }
-
-      void OnSelectFrame(int lineNumber)
-      {
-         ide.debugger.SelectFrame(lineNumber);
+         ide.debugger.GoToStackFrameLine(frameIndex, true);
+         if(frameIndex >= 0)
+            ide.debugger.SelectFrame(frameIndex);
       }
 
       void OnToggleBreakpoint()
@@ -426,7 +500,7 @@ class IDEWorkSpace : Window
                {
                   for(p : ide.workspace.projects)
                   {
-                     if(eString_PathInsideOf(debugger.activeFrame.absoluteFile, p.topNode.path))
+                     if(IsPathInsideOf(debugger.activeFrame.absoluteFile, p.topNode.path))
                      {
                         prj = p;
                         break;
@@ -452,13 +526,6 @@ class IDEWorkSpace : Window
          return true;
       }
 
-      bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
-      {
-         if(active)
-            ide.RepositionWindows(false);
-         return true;
-      }
-
       bool OnClose(bool parentClosing)
       {
          visible = false;
@@ -469,53 +536,54 @@ class IDEWorkSpace : Window
 
       void OnRedraw(Surface surface)
       {
-         bool error;
-         int lineCursor, lineTopFrame, activeThread, hitThread;
-         int lineH, scrollY, boxH;
-         BitmapResource bmp;
-         Breakpoint bp = null;
          Debugger debugger = ide.debugger;
          Frame activeFrame = debugger.activeFrame;
+         if(activeFrame)
+         {
+            bool error;
+            int lineCursor, lineTopFrame, activeThread, hitThread;
+            int lineH, scrollY, boxH;
+            BitmapResource bmp;
+            Breakpoint bp = null;
 
-         boxH = clientSize.h;
-         scrollY = editBox.scroll.y;
-         displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
-
-         activeThread = debugger.activeThread;
-         hitThread = debugger.hitThread;
-         debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
+            boxH = clientSize.h;
+            scrollY = editBox.scroll.y;
+            displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
+            activeThread = debugger.activeThread;
+            hitThread = debugger.hitThread;
+            debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
 
-         if(activeFrame && activeFrame.absoluteFile)
-         {
-            for(i : ide.workspace.breakpoints; i.type == user)
+            // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
+            if(activeFrame.absoluteFile)
             {
-               if(i.absoluteFilePath && i.absoluteFilePath[0] && 
-                  !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
-                  activeFrame.line == i.line)
+               for(i : ide.workspace.breakpoints; i.type == user)
                {
-                  bp = i;
-                  break;
+                  if(i.absoluteFilePath && i.absoluteFilePath[0] &&
+                     !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
+                     activeFrame.line == i.line)
+                  {
+                     bp = i;
+                     break;
+                  }
                }
             }
+            if(bp)
+               DrawLineMarginIcon(surface,
+                     /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
+                     lineCursor /*1*/, lineH, scrollY, boxH);
+            /*
+            if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
+               DrawLineMarginIcon(surface,
+                     (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
+                     1, lineH, scrollY, boxH);
+            */
+            DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
+            if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
+               bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
+            else
+               bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
+            DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
          }
-
-         if(bp)
-            DrawLineMarginIcon(surface,
-                  /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
-                  lineCursor /*1*/, lineH, scrollY, boxH);
-
-         /*
-         if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
-            DrawLineMarginIcon(surface,
-                  (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
-                  1, lineH, scrollY, boxH);
-         */
-         DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
-         if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
-            bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
-         else
-            bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
-         DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
          if(editBox.horzScroll && editBox.horzScroll.visible)
          {
             surface.SetBackground(control);
@@ -538,13 +606,6 @@ class IDEWorkSpace : Window
          return true;
       }
 
-      bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
-      {
-         if(active)
-            ide.RepositionWindows(false);
-         return true;
-      }
-
       bool OnClose(bool parentClosing)
       {
          visible = false;
@@ -578,10 +639,11 @@ class IDEWorkSpace : Window
    char * tmpPrjDir;
    property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
 
-   Menu fileMenu { menu, $"File", f };
+   Menu fileMenu { menu, $"File", f, hasMargin = true };
       MenuItem fileNewItem
       {
          fileMenu, $"New", n, ctrlN;
+         bitmap = { ":actions/docNew.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             Window document = (Window)NewCodeEditor(this, normal, false);
@@ -592,6 +654,7 @@ class IDEWorkSpace : Window
       MenuItem fileOpenItem
       {
          fileMenu, $"Open...", o, ctrlO;
+         bitmap = { ":actions/docOpen.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(!projectView && ideSettings.ideFileDialogLocation)
@@ -607,7 +670,7 @@ class IDEWorkSpace : Window
 
                   for(c = 0; c < numSelections; c++)
                   {
-                     if(OpenFile(multiFilePaths[c], normal, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal))
+                     if(OpenFile(multiFilePaths[c], normal, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
                         gotWhatWeWant = true;
                   }
                   if(gotWhatWeWant ||
@@ -616,6 +679,7 @@ class IDEWorkSpace : Window
                   {
                      if(!projectView && gotWhatWeWant)
                         ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
+                     ide.RepositionWindows(false);
                      break;
                   }
                }
@@ -627,9 +691,21 @@ class IDEWorkSpace : Window
       }
       MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
       MenuDivider { fileMenu };
-      MenuItem fileSaveItem { fileMenu, $"Save", s, ctrlS };
+      MenuItem fileSaveItem
+      {
+         fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
+
+         // For the toolbar button; clients can still override that for the menu item
+         bool Window::NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            Window w = activeClient;
+            if(w)
+               w.MenuFileSave(null, 0);
+            return true;
+         }
+      };
       MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
-      MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll };
+      MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
       MenuDivider { fileMenu };
       MenuItem findInFiles
       {
@@ -672,7 +748,7 @@ class IDEWorkSpace : Window
       MenuDivider { fileMenu };
       MenuItem exitItem
       {
-         fileMenu, $"Exit", x, altF4, NotifySelect = MenuFileExit;
+         fileMenu, $"Exit", x, altF4;
 
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
@@ -688,7 +764,21 @@ class IDEWorkSpace : Window
          {
             if(id == selection.id)
             {
-               OpenFile(file, normal, true, null, no, normal);
+               bool isProjectFile;
+               char extension[MAX_EXTENSION] = "";
+               GetExtension(file, extension);
+               isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
+               if(mods.ctrl)
+               {
+                  char * command = PrintString("ide ", isProjectFile ? "-t " : "", file);
+                  Execute(command);
+                  delete command;
+               }
+               else
+               {
+                  OpenFile(file, normal, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
+                  ide.RepositionWindows(false);
+               }
                break;
             }
             id++;
@@ -703,7 +793,14 @@ class IDEWorkSpace : Window
          {
             if(id == selection.id)
             {
-               OpenFile(file, normal, true, null, no, normal);
+               if(mods.ctrl)
+               {
+                  char * command = PrintString("ide ", file);
+                  Execute(command);
+                  delete command;
+               }
+               else
+                  OpenFile(file, normal, true, null, no, normal, mods.ctrl && mods.shift);
                break;
             }
             id++;
@@ -717,36 +814,37 @@ class IDEWorkSpace : Window
       MenuItem projectNewItem
       {
          projectMenu, $"New...", n, Key { n, true, true };
-         bitmap = { "<:ecere>actions/listAdd.png" };
+         bitmap = { ":actions/projNew.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(!DontTerminateDebugSession($"New Project"))
-               if(MenuWindowCloseAll(null, 0))
+            {
+               DialogResult result;
+               NewProjectDialog newProjectDialog { master = this };
+               incref newProjectDialog;
+               result = newProjectDialog.Modal();
+               if(result == ok)
                {
-                  NewProjectDialog newProjectDialog;
-
-                  if(projectView)
-                  {
-                     projectView.visible = false;
-                     if(!projectView.Destroy(0))
-                        return true;
-                  }
-                  
-                  newProjectDialog = { master = this };
-                  newProjectDialog.Modal();
-                  if(projectView)
+                  if(ProjectClose())
                   {
-                     ideSettings.AddRecentProject(projectView.fileName);
-                     ide.UpdateRecentMenus();
-                     settingsContainer.Save();
+                     newProjectDialog.CreateNewProject();
+                     if(projectView)
+                     {
+                        ideSettings.AddRecentProject(projectView.fileName);
+                        ide.UpdateRecentMenus();
+                        settingsContainer.Save();
+                     }
                   }
                }
+               delete newProjectDialog;
+            }
             return true;
          }
       }
       MenuItem projectOpenItem
       {
          projectMenu, $"Open...", o, Key { o, true, true };
+         bitmap = { ":actions/projOpen.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(ideSettings.ideProjectFileDialogLocation)
@@ -755,7 +853,7 @@ class IDEWorkSpace : Window
             ideProjectFileDialog.text = openProjectFileDialogTitle;
             if(ideProjectFileDialog.Modal() == ok)
             {
-               OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal);
+               OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
                //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
             }
             return true;
@@ -763,17 +861,18 @@ class IDEWorkSpace : Window
       }
       MenuItem projectQuickItem
       {
-         projectMenu, $"Quick...", q, f7;
+         projectMenu, $"Quick...", q, f7, disabled = true;
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(!projectView)
-               QuickProjectDialog{ this }.Modal();
+               QuickProjectDialog { this }.Modal();
             return true;
          }
       }
       MenuItem projectAddItem
       {
          projectMenu, $"Add project to workspace...", a, Key { a, true, true };
+         bitmap = { ":actions/projAdd.png" };
          disabled = true;
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
@@ -785,7 +884,7 @@ class IDEWorkSpace : Window
             {
                if(ideProjectFileDialog.Modal() == ok)
                {
-                  if(OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add))
+                  if(OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
                      break;
                   if(MessageBox { type = yesNo, master = this, text = $"Error opening project file", 
                         contents = $"Add a different project?" }.Modal() == no)
@@ -807,41 +906,12 @@ class IDEWorkSpace : Window
             if(projectView)
             {
                if(!ide.DontTerminateDebugSession($"Project Close"))
-               {
-                  if(findInFilesDialog)
-                     findInFilesDialog.SearchStop();
-                  projectView.visible = false;
-                  if(projectView.Destroy(0))
-                     MenuWindowCloseAll(null, 0);
-                  {
-                     char workingDir[MAX_LOCATION];
-                     GetWorkingDir(workingDir, MAX_LOCATION);
-                     findInFilesDialog.currentDirectory = workingDir;
-                  }
-               }
+                  ProjectClose();
             }
             return true;
          }
       }
       MenuDivider { projectMenu };
-      MenuItem activeCompilerItem
-      {
-         projectMenu, $"Active Compiler...", g, /*altF5, */disabled = true;
-         bool NotifySelect(MenuItem selection, Modifiers mods)
-         {
-            projectView.MenuCompiler(null, mods);
-            return true;
-         }
-      }
-      MenuItem projectActiveConfigItem
-      {
-         projectMenu, $"Active Configuration...", g, altF5, disabled = true;
-         bool NotifySelect(MenuItem selection, Modifiers mods)
-         {
-            projectView.MenuConfig(projectView.active ? selection : null, mods);
-            return true;
-         }
-      }
       MenuItem projectSettingsItem
       {
          projectMenu, $"Settings...", s, altF7, disabled = true;
@@ -866,6 +936,7 @@ class IDEWorkSpace : Window
       MenuItem projectRunItem
       {
          projectMenu, $"Run", r, ctrlF5, disabled = true;
+         bitmap = { ":actions/run.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -876,16 +947,23 @@ class IDEWorkSpace : Window
       MenuItem projectBuildItem
       {
          projectMenu, $"Build", b, f7, disabled = true;
+         bitmap = { ":actions/build.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
-               projectView.ProjectBuild(projectView.active ? selection : null, mods);
+            {
+               if(projectView.buildInProgress == none)
+                  projectView.ProjectBuild(projectView.active ? selection : null, mods);
+               else
+                  projectView.stopBuild = true;
+            }
             return true;
          }
       }
       MenuItem projectLinkItem
       {
          projectMenu, $"Relink", l, disabled = true;
+         bitmap = { ":actions/relink.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -896,6 +974,7 @@ class IDEWorkSpace : Window
       MenuItem projectRebuildItem
       {
          projectMenu, $"Rebuild", d, shiftF7, disabled = true;
+         bitmap = { ":actions/rebuild.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -903,9 +982,24 @@ class IDEWorkSpace : Window
             return true;
          }
       }
+      MenuItem projectCleanTargetItem
+      {
+         projectMenu, $"Clean Target", g, disabled = true;
+         bitmap = { ":actions/clean.png" };
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            if(projectView)
+            {
+               debugger.Stop();
+               projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
+            }
+            return true;
+         }
+      }
       MenuItem projectCleanItem
       {
          projectMenu, $"Clean", e, disabled = true;
+         bitmap = { ":actions/clean.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -916,9 +1010,24 @@ class IDEWorkSpace : Window
             return true;
          }
       }
+      MenuItem projectRealCleanItem
+      {
+         projectMenu, $"Real Clean", disabled = true;
+         bitmap = { ":actions/clean.png" };
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            if(projectView)
+            {
+               debugger.Stop();
+               projectView.ProjectRealClean(projectView.active ? selection : null, mods);
+            }
+            return true;
+         }
+      }
       MenuItem projectRegenerateItem
       {
          projectMenu, $"Regenerate Makefile", m, disabled = true;
+         bitmap = { ":actions/regMakefile.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -926,11 +1035,25 @@ class IDEWorkSpace : Window
             return true;
          }
       }
+      MenuItem projectInstallItem
+      {
+#ifdef IDE_SHOW_INSTALL_MENU_BUTTON
+         projectMenu, $"Install", t, disabled = true;
+#endif
+         bitmap = { ":status/software-update-available.png" };
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            if(projectView)
+               projectView.ProjectInstall(projectView.active ? selection : null, mods);
+            return true;
+         }
+      }
       MenuItem projectCompileItem;
-   Menu debugMenu { menu, $"Debug", d };
+   Menu debugMenu { menu, $"Debug", d, hasMargin = true };
       MenuItem debugStartResumeItem
       {
          debugMenu, $"Start", s, f5, disabled = true;
+         bitmap = { ":actions/debug.png" };
          NotifySelect = MenuDebugStart;
       }
       bool MenuDebugStart(MenuItem selection, Modifiers mods)
@@ -952,6 +1075,7 @@ class IDEWorkSpace : Window
       MenuItem debugRestartItem
       {
          debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
+         bitmap = { ":actions/restart.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -962,8 +1086,11 @@ class IDEWorkSpace : Window
       MenuItem debugBreakItem
       {
          debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
+         bitmap = { ":actions/pause.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
+            if(projectView && projectView.buildInProgress != none)
+               return true;
             if(projectView)
                projectView.DebugBreak();
             return true;
@@ -972,6 +1099,7 @@ class IDEWorkSpace : Window
       MenuItem debugStopItem
       {
          debugMenu, $"Stop", p, shiftF5, disabled = true;
+         bitmap = { ":actions/stopDebug.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -979,10 +1107,99 @@ class IDEWorkSpace : Window
             return true;
          }
       }
+#ifndef __WIN32__
+      MenuDivider { debugMenu };
+      MenuItem debugUseValgrindItem
+      {
+         debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            if(ide.workspace)
+            {
+               ide.workspace.useValgrind = selection.checked;
+               ide.workspace.Save();
+            }
+            ide.AdjustValgrindMenus();
+            return true;
+         }
+      }
+      Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
+         MenuItem debugValgrindNoLeakCheckItem      { debugValgrindLeakCheckItem, $"No"     , f, id = ValgrindLeakCheck::no     , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; }
+         MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; }
+         MenuItem debugValgrindYesLeakCheckItem     { debugValgrindLeakCheckItem, $"Yes"    , f, id = ValgrindLeakCheck::yes    , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; }
+         MenuItem debugValgrindFullLeakCheckItem    { debugValgrindLeakCheckItem, $"Full"   , f, id = ValgrindLeakCheck::full   , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; }
+         bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
+         {
+            if(ide.workspace)
+            {
+               if(selection.checked)
+               {
+                  ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
+
+                  debugValgrindNoLeakCheckItem.checked      = debugValgrindNoLeakCheckItem.id      == vgLeakCheck;
+                  debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
+                  debugValgrindYesLeakCheckItem.checked     = debugValgrindYesLeakCheckItem.id     == vgLeakCheck;
+                  debugValgrindFullLeakCheckItem.checked    = debugValgrindFullLeakCheckItem.id    == vgLeakCheck;
+
+                  ide.workspace.vgLeakCheck = vgLeakCheck;
+                  ide.workspace.Save();
+               }
+               else
+                  selection.checked = true;
+            }
+            return true;
+         }
+      Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
+         MenuItem debugValgrindRS0Item   { debugValgrindRedzoneSizeItem, $"0"  , f, id =   0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; }
+         MenuItem debugValgrindRS16Item  { debugValgrindRedzoneSizeItem, $"16" , f, id =  16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; }
+         MenuItem debugValgrindRS32Item  { debugValgrindRedzoneSizeItem, $"32" , f, id =  32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; }
+         MenuItem debugValgrindRS64Item  { debugValgrindRedzoneSizeItem, $"64" , f, id =  64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; }
+         MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, $"128", f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; }
+         MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, $"256", f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; }
+         MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, $"512", f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; }
+         bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
+         {
+            if(ide.workspace)
+            {
+               if(selection.checked)
+               {
+                  int vgRedzoneSize = (int)selection.id;
+
+                  debugValgrindRS0Item.checked   = debugValgrindRS0Item.id   == vgRedzoneSize;
+                  debugValgrindRS16Item.checked  = debugValgrindRS16Item.id  == vgRedzoneSize;
+                  debugValgrindRS32Item.checked  = debugValgrindRS32Item.id  == vgRedzoneSize;
+                  debugValgrindRS64Item.checked  = debugValgrindRS64Item.id  == vgRedzoneSize;
+                  debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
+                  debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
+                  debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
+
+                  ide.workspace.vgRedzoneSize = vgRedzoneSize;
+                  ide.workspace.Save();
+               }
+               else
+                  selection.checked = true;
+            }
+            return true;
+         }
+      MenuItem debugValgrindTrackOriginsItem
+      {
+         debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            if(ide.workspace)
+            {
+               ide.workspace.vgTrackOrigins = selection.checked;
+               ide.workspace.Save();
+            }
+            return true;
+         }
+      };
+#endif
       MenuDivider { debugMenu };
       MenuItem debugStepIntoItem
       {
          debugMenu, $"Step Into", i, f11, disabled = true;
+         bitmap = { ":actions/stepInto.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -993,6 +1210,7 @@ class IDEWorkSpace : Window
       MenuItem debugStepOverItem
       {
          debugMenu, $"Step Over", v, f10, disabled = true;
+         bitmap = { ":actions/stepOver.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -1003,6 +1221,7 @@ class IDEWorkSpace : Window
       MenuItem debugStepOutItem
       {
          debugMenu, $"Step Out", o, shiftF11, disabled = true;
+         bitmap = { ":actions/stepOut.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -1024,6 +1243,7 @@ class IDEWorkSpace : Window
       MenuItem debugSkipStepOutItem
       {
          debugMenu, $"Step Out Skipping Breakpoints", t, Key { f11, ctrl = true, shift = true }, disabled = true;
+         bitmap = { ":actions/skipBreaks.png" };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
             if(projectView)
@@ -1032,6 +1252,7 @@ class IDEWorkSpace : Window
          }
       }
       MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
+      MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", l };
       //MenuDivider { debugMenu };
       //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
    MenuPlacement imageMenu { menu, $"Image", i };
@@ -1194,8 +1415,8 @@ class IDEWorkSpace : Window
          viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
-            ColorPicker colorPicker { master = this, parent = this, stayOnTop = true };
-            colorPicker.Create();
+            ColorPicker colorPicker { master = this };
+            colorPicker.Modal();
             return true;
          }
       }
@@ -1234,7 +1455,74 @@ class IDEWorkSpace : Window
          helpMenu, $"API Reference", r, f1;
          bool NotifySelect(MenuItem selection, Modifiers mods)
          {
-            Execute("documentor");
+            if(!documentor)
+            {
+               char * p = new char[MAX_LOCATION];
+               p[0] = '\0';
+               strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+               PathCat(p, "documentor");
+   #if defined(__WIN32__)
+               ChangeExtension(p, "exe", p);
+   #endif
+               if(!FileExists(p).isFile)
+                  strcpy(p, "documentor");
+
+               documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
+               delete p;
+            }
+            else
+            {
+               Process_ShowWindows(documentor.GetProcessID());
+               // documentor.Puts("Activate\n");
+            }
+            return true;
+         }
+      }
+      MenuDivider { helpMenu };
+      MenuItem
+      {
+         helpMenu, $"Ecere Tao of Programming [work in progress]", t;
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
+            return true;
+         }
+      }
+      MenuDivider { helpMenu };
+      MenuItem
+      {
+         helpMenu, $"Documentation Folder", d;
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            FindAndShellOpenInstalledFolder("doc");
+            return true;
+         }
+      }
+      MenuItem
+      {
+         helpMenu, $"Samples Folder", s;
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            FindAndShellOpenInstalledFolder("samples");
+            return true;
+         }
+      }
+      MenuItem
+      {
+         helpMenu, $"Extras Folder", x;
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            FindAndShellOpenInstalledFolder("extras");
+            return true;
+         }
+      }
+      MenuDivider { helpMenu };
+      MenuItem
+      {
+         helpMenu, $"Community Forums", f;
+         bool NotifySelect(MenuItem selection, Modifiers mods)
+         {
+            ShellOpen("http://ecere.com/forums");
             return true;
          }
       }
@@ -1271,16 +1559,18 @@ class IDEWorkSpace : Window
 
    FindInFilesDialog findInFilesDialog
    {
-      master = this, parent = this;
+      master = this,
       filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
       filter = 1;
    };
 
+   bool noParsing;
+
 #ifdef GDB_DEBUG_GUI
    GDBDialog gdbDialog
    {
       master = this, parent = this;
-      anchor = { left = 100, top = 100, right = 100, bottom = 100 };
+      //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
 
       void OnCommand(char * string)
       {
@@ -1293,7 +1583,7 @@ class IDEWorkSpace : Window
    bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
    {
       //app.driver = app.drivers[selection.id];
-#ifdef __unix__
+#if defined(__unix__) || defined(__APPLE__)
       app.driver = selection.id ? "OpenGL" : "X";
 #else
       app.driver = selection.id ? "OpenGL" : "GDI";
@@ -1369,17 +1659,23 @@ class IDEWorkSpace : Window
       return projectView;
    }
 
-   bool GetDebugMenusDisabled()
+   bool ProjectClose()
    {
-      if(projectView)
+      projectView.visible = false;
+      if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
       {
-         Project project = projectView.project;
-         if(project)
-            if(project.GetTargetType(project.config) == executable)
-               return false;
-           
+         if(findInFilesDialog)
+         {
+            char workingDir[MAX_LOCATION];
+            GetWorkingDir(workingDir, MAX_LOCATION);
+            findInFilesDialog.SearchStop();
+            findInFilesDialog.currentDirectory = workingDir;
+         }
+         ideMainFrame.text = titleECEREIDE;
+         ide.AdjustMenus();
+         return true;
       }
-      return true;
+      return false;
    }
 
    void RepositionWindows(bool expand)
@@ -1407,6 +1703,7 @@ class IDEWorkSpace : Window
                anchor.bottom = bottomDistance;
                if(child._class == class(CodeEditor) || child._class == class(Designer))
                {
+                  anchor.left = 300;
                   anchor.right = toolBoxVisible ? 150 : 0;
                }
                child.anchor = anchor;
@@ -1440,15 +1737,11 @@ class IDEWorkSpace : Window
       return false;
    }
 
-   bool ShouldStopBuild()
-   {
-      return projectView.stopBuild;
-   }
-
    void DocumentSaved(Window document, char * fileName)
    {
       ideSettings.AddRecentFile(fileName);
       ide.UpdateRecentMenus();
+      ide.AdjustFileMenus();
       settingsContainer.Save();
    }
 
@@ -1460,6 +1753,7 @@ class IDEWorkSpace : Window
       if(MessageBox { type = yesNo, master = this/*.parent*/,
             text = $"Document has been modified", contents = temp }.Modal() == yes)
       {
+         bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
          char * fileName = CopyString(this.fileName);
          WindowState state = this.state;
          Anchor anchor = this.anchor;
@@ -1467,7 +1761,7 @@ class IDEWorkSpace : Window
 
          this.modifiedDocument = false;
          this.Destroy(0);
-         this = ide.OpenFile(fileName, normal, true, null, no, normal);
+         this = ide.OpenFile(fileName, normal, true, null, no, normal, noParsing);
          if(this)
          {
             this.anchor = anchor;
@@ -1484,85 +1778,324 @@ class IDEWorkSpace : Window
    {
       if(workspace)
       {
-         for(prj : workspace.projects)
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
+         for(prj : workspace.projects)
+            projectView.ProjectUpdateMakefileForAllConfigs(prj);
+         delete compiler;
+      }
+   }
+
+   void UpdateCompilerConfigs(bool mute)
+   {
+      UpdateToolBarActiveCompilers();
+      if(workspace)
+      {
+         bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
+         if(!silent)
+         {
+            projectView.ShowOutputBuildLog(true);
+            projectView.DisplayCompiler(compiler, false);
+         }
+         for(prj : workspace.projects)
+            projectView.ProjectPrepareCompiler(prj, compiler, silent);
+         delete compiler;
+      }
+   }
+
+   void UpdateToolBarActiveCompilers()
+   {
+      toolBar.activeCompiler.Clear();
+      for(compiler : ideSettings.compilerConfigs)
+      {
+         DataRow row = toolBar.activeCompiler.AddString(compiler.name);
+         if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
+            toolBar.activeCompiler.currentRow = row;
+      }
+      if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
+         toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
+   }
+
+   void UpdateToolBarActiveConfigs(bool selectionOnly)
+   {
+      bool commonSelected = false;
+      DataRow row = toolBar.activeConfig.currentRow;
+      if(selectionOnly)
+         row = toolBar.activeConfig.FindRow(1);
+      else
+      {
+         toolBar.activeConfig.Clear();
+         row = toolBar.activeConfig.AddString($"(Mixed)");
+         row.tag = 1;
+      }
+      if(workspace)
+      {
+         char * configName = null;
+         if(!selectionOnly)
+         {
+            Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
+            for(prj : workspace.projects)
+            {
+               for(cfg : prj.configurations)
+               {
+                  if(cfg.name)
+                     configs[cfg.name] = 1;
+               }
+            }
+            for(name : configs)
+            {
+               toolBar.activeConfig.AddString(&name);
+            }
+            delete configs;
+         }
+         if(projectView && projectView.project)
+         {
+            for(prj : workspace.projects)
+            {
+               if(prj.config && prj.config.name)
+               {
+                  configName = prj.config.name;
+                  break;
+               }
+            }
+            if(configName)
+            {
+               commonSelected = true;
+               for(prj : workspace.projects)
+               {
+                  if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
+                  {
+                     commonSelected = false;
+                     break;
+                  }
+               }
+            }
+         }
+         if(commonSelected)
          {
-            bool first = prj == workspace.projects.firstIterator.data;
-            projectView.ProjectUpdateMakefileForAllConfigs(prj, first, first);
+            commonSelected = false;
+            for(row = toolBar.activeConfig.firstRow; row; row = row.next)
+            {
+               if(!strcmp(row.string, configName))
+               {
+                  toolBar.activeConfig.currentRow = row;
+                  commonSelected = true;
+                  break;
+               }
+            }
          }
       }
+      if(!selectionOnly)
+         toolBar.activeConfig.Sort(null, 0);
+      if(!commonSelected)
+         toolBar.activeConfig.currentRow = row;
    }
 
    void AdjustMenus()
    {
       bool unavailable = !project;
 
-      projectQuickItem.disabled           = !unavailable;
-
       projectAddItem.disabled             = unavailable;
+      toolBar.buttonAddProject.disabled   = unavailable;
 
-      activeCompilerItem.disabled         = unavailable;
-      projectActiveConfigItem.disabled    = unavailable;
       projectSettingsItem.disabled        = unavailable;
 
       projectBrowseFolderItem.disabled    = unavailable;
 
       viewProjectItem.disabled            = unavailable;
 
+      toolBar.activeConfig.disabled       = unavailable;
+      toolBar.activeCompiler.disabled     = unavailable;
+      toolBar.activeBitDepth.disabled     = unavailable;
+
+#ifndef __WIN32__
+      debugUseValgrindItem.disabled       = unavailable;
+      AdjustValgrindMenus();
+#endif
+
+      AdjustFileMenus();
       AdjustBuildMenus();
       AdjustDebugMenus();
    }
 
+#ifndef __WIN32__
+   void AdjustValgrindMenus()
+   {
+      bool unavailable = !project || !debugUseValgrindItem.checked;
+      debugValgrindNoLeakCheckItem.disabled        = unavailable;
+      debugValgrindSummaryLeakCheckItem.disabled   = unavailable;
+      debugValgrindYesLeakCheckItem.disabled       = unavailable;
+      debugValgrindFullLeakCheckItem.disabled      = unavailable;
+
+      debugValgrindTrackOriginsItem.disabled       = unavailable;
+
+      debugValgrindRS0Item.disabled   = unavailable;
+      debugValgrindRS16Item.disabled  = unavailable;
+      debugValgrindRS32Item.disabled  = unavailable;
+      debugValgrindRS64Item.disabled  = unavailable;
+      debugValgrindRS128Item.disabled = unavailable;
+      debugValgrindRS256Item.disabled = unavailable;
+      debugValgrindRS512Item.disabled = unavailable;
+   }
+#endif
+
+   property bool hasOpenedCodeEditors
+   {
+      get
+      {
+         Window w;
+         for(w = firstChild; w; w = w.next)
+            if(w._class == class(CodeEditor) &&
+                  w.isDocument && !w.closing && w.visible && w.created &&
+                  w.fileName && w.fileName[0])
+               return true;
+         return false;
+      }
+   }
+
+   void AdjustFileMenus()
+   {
+      bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
+
+      projectQuickItem.disabled           = unavailable;
+   }
+
    void AdjustBuildMenus()
    {
       bool unavailable = project && projectView.buildInProgress;
+      bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
 
-      projectNewItem.disabled          = unavailable;
-      projectOpenItem.disabled         = unavailable;
+      projectNewItem.disabled             = unavailable;
+      toolBar.buttonNewProject.disabled   = unavailable;
+      projectOpenItem.disabled            = unavailable;
+      toolBar.buttonOpenProject.disabled  = unavailable;
 
       unavailable = !project || projectView.buildInProgress;
 
-      projectCloseItem.disabled        = unavailable;
+      projectCloseItem.disabled           = unavailable;
+      // toolBar.buttonCloseProject.disabled = unavailable;
+
+      projectRunItem.disabled    = naForRun;
+      toolBar.buttonRun.disabled = naForRun;
+
+      projectBuildItem.disabled = false;
+      projectBuildItem.text     = unavailable ? $"Stop Build" : $"Build";
+      projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
+
+      projectLinkItem.disabled                  = unavailable;
+      toolBar.buttonReLink.disabled             = unavailable;
+      projectRebuildItem.disabled               = unavailable;
+      toolBar.buttonRebuild.disabled            = unavailable;
+      projectCleanItem.disabled                 = unavailable;
+      toolBar.buttonClean.disabled              = unavailable;
+      projectCleanTargetItem.disabled           = unavailable;
+      projectRealCleanItem.disabled             = unavailable;
+      // toolBar.buttonRealClean.disabled          = unavailable;
+      projectRegenerateItem.disabled            = unavailable;
+      toolBar.buttonRegenerateMakefile.disabled = unavailable;
+#ifdef IDE_SHOW_INSTALL_MENU_BUTTON
+      projectInstallItem.disabled               = unavailable;
+      toolBar.buttonInstall.disabled            = unavailable;
+#endif
+      projectCompileItem.disabled               = unavailable;
+
+      AdjustPopupBuildMenus();
+   }
 
-      projectRunItem.disabled          = unavailable || project.GetTargetType(project.config) != executable;
-      projectBuildItem.disabled        = unavailable;
-      projectLinkItem.disabled         = unavailable;
-      projectRebuildItem.disabled      = unavailable;
-      projectCleanItem.disabled        = unavailable;
-      projectRegenerateItem.disabled   = unavailable;
-      projectCompileItem.disabled      = unavailable;
+   void AdjustPopupBuildMenus()
+   {
+      bool unavailable = !project || projectView.buildInProgress;
+
+      if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
+      {
+         MenuItem menu;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
+         if(menu)
+         {
+            menu.disabled = false;
+            menu.text   = unavailable ? $"Stop Build" : $"Build";
+            menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
+         }
+
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0);              if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0);           if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0);       if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0);             if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0);         if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0);        if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0);           if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0);            if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0);                if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0);              if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0);      if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0);         if(menu) menu.disabled = unavailable;
+         menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
+         projectView.popupMenu.Update(null);
+      }
    }
 
+   property bool areDebugMenusUnavailable { get {
+      return !project ||
+            project.GetTargetType(project.config) != executable ||
+            projectView.buildInProgress == buildingMainProject;
+   } }
+
+   property bool isBreakpointTogglingUnavailable { get {
+      return !project;
+   } }
+
+   property bool isDebuggerExecuting { get {
+      if(!ide.debugger)
+         return false;
+      else
+         return ide.debugger.state == running;
+   } }
+
    void AdjustDebugMenus()
    {
-      bool unavailable = !project || project.GetTargetType(project.config) != executable ||
-               projectView.buildInProgress == buildingMainProject;
-      bool active = ide.debugger.isActive;
-      bool executing = ide.debugger.state == running;
-      //bool holding = ide.debugger.state == stopped;
+      bool unavailable = areDebugMenusUnavailable;
+      bool active = debugger.isActive;
+      bool bpNoToggle = isBreakpointTogglingUnavailable;
+      bool executing = isDebuggerExecuting;
+      //bool holding = debugger.state == stopped;
 
       debugStartResumeItem.disabled       = unavailable || executing;
-
       debugStartResumeItem.text           = active ? $"Resume" : $"Start";
       debugStartResumeItem.NotifySelect   = active ? MenuDebugResume : MenuDebugStart;
+      if(toolBar)
+      {
+         toolBar.buttonDebugStartResume.disabled      = unavailable || executing;
+         toolBar.buttonDebugStartResume.toolTip       = active ? $"Resume" : $"Start";
+      }
 
       debugBreakItem.disabled             = unavailable || !executing;
       debugStopItem.disabled              = unavailable || !active;
       debugRestartItem.disabled           = unavailable || !active;
+      if(toolBar)
+      {
+         toolBar.buttonDebugPause.disabled            = unavailable || !executing;
+         toolBar.buttonDebugStop.disabled             = unavailable || !active;
+         toolBar.buttonDebugRestart.disabled          = unavailable || !active;
+      }
 
       debugStepIntoItem.disabled          = unavailable || executing;
       debugStepOverItem.disabled          = unavailable || executing;
       debugStepOutItem.disabled           = unavailable || executing || !active;
       debugSkipStepOverItem.disabled      = unavailable || executing;
       debugSkipStepOutItem.disabled       = unavailable || executing || !active;
-
+      if(toolBar)
+      {
+         toolBar.buttonDebugStepInto.disabled         = unavailable || executing;
+         toolBar.buttonDebugStepOver.disabled         = unavailable || executing;
+         toolBar.buttonDebugStepOut.disabled          = unavailable || executing || !active;
+         toolBar.buttonDebugSkipStepOver.disabled     = unavailable || executing;
+         // toolBar.buttonDebugSkipStepOutItem.disabled  = unavailable || executing;
+      }
       if((Designer)GetActiveDesigner())
       {
          CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
          if(codeEditor)
-         {
-            codeEditor.debugRunToCursor.disabled      = unavailable || executing;
-            codeEditor.debugSkipRunToCursor.disabled  = unavailable || executing;
-         }
+            codeEditor.AdjustDebugMenus(unavailable, bpNoToggle, executing);
       }
    }
 
@@ -1629,7 +2162,7 @@ class IDEWorkSpace : Window
       return false;
    }
 
-   Window OpenFile(char * origFilePath, WindowState state, bool visible, char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod)
+   Window OpenFile(char * origFilePath, WindowState state, bool visible, char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
    {
       char extension[MAX_EXTENSION] = "";
       Window document = null;
@@ -1654,7 +2187,8 @@ class IDEWorkSpace : Window
             if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
             {
                document.visible = true;
-               document.Activate();
+               if(visible)
+                  document.Activate();
                return document;
             }
          }
@@ -1664,19 +2198,14 @@ class IDEWorkSpace : Window
          ;
       else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
       {
+         needFileModified = false;
          if(openMethod == normal)
          {
             if(DontTerminateDebugSession($"Open Project"))
                return null;
             isProject = true;
-            if(MenuWindowCloseAll(null, 0))
+            if(ProjectClose())
             {
-               if(projectView)
-               {
-                  projectView.visible = false;
-                  projectView.Destroy(0);
-                  // Where did this come from? projectView = null;
-               }
                if(!projectView)
                {
                   for(;;)
@@ -1697,9 +2226,9 @@ class IDEWorkSpace : Window
                            workspace = LoadWorkspace(filePath, null);
                         else
                            return null;
-                        //project = LoadProject(filePath);
+                        //project = LoadProject(filePath, null);
                      }
-                     
+
                      if(workspace)
                      {
                         char absolutePath[MAX_LOCATION];
@@ -1715,6 +2244,7 @@ class IDEWorkSpace : Window
                            ide.projectView.DisplayCompiler(compiler, false);
                            delete compiler;
                         }
+                        UpdateCompilerConfigs(false);
                         UpdateMakefiles();
                         {
                            char newWorkingDir[MAX_LOCATION];
@@ -1734,7 +2264,7 @@ class IDEWorkSpace : Window
                         {
                            if(ofi.state != closed)
                            {
-                              Window file = OpenFile(ofi.path, normal, true, null, no, normal);
+                              Window file = OpenFile(ofi.path, normal, true, null, no, normal, noParsing);
                               if(file)
                               {
                                  char fileName[MAX_LOCATION];
@@ -1746,6 +2276,7 @@ class IDEWorkSpace : Window
                               }
                            }
                         }
+                        ide.RepositionWindows(false);
                         workspace.holdTracking = false;
 
                         workspace.timer.Start();
@@ -1768,7 +2299,7 @@ class IDEWorkSpace : Window
                      }
                      else 
                      {
-                        if(MessageBox { type = yesNo, parent = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
+                        if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
                         {
                            ideProjectFileDialog.text = openProjectFileDialogTitle;
                            if(ideProjectFileDialog.Modal() == cancel)
@@ -1783,7 +2314,7 @@ class IDEWorkSpace : Window
                }
             }
             else
-               return document;
+               return null;
          }
          else if(openMethod == add)
          {
@@ -1807,16 +2338,36 @@ class IDEWorkSpace : Window
                }
                else
                {
-                  prj = LoadProject(filePath);
+                  prj = LoadProject(filePath, null);
                   if(prj)
                   {
+                     char * activeConfigName = null;
+                     CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
+                     prj.StartMonitoring();
                      workspace.projects.Add(prj);
+                     if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
+                           toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
+                        activeConfigName = toolBar.activeConfig.currentRow.string;
+                     if(activeConfigName)
+                     {
+                        for(cfg : prj.configurations)
+                        {
+                           if(cfg.name && !strcmp(cfg.name, activeConfigName))
+                           {
+                              prj.config = cfg;
+                              break;
+                           }
+                        }
+                     }
                      if(projectView)
                         projectView.AddNode(prj.topNode, null);
                      workspace.modified = true;
                      workspace.Save();
                      findInFilesDialog.AddProjectItem(prj);
-                     projectView.ProjectUpdateMakefileForAllConfigs(prj, true, true);
+                     projectView.ShowOutputBuildLog(true);
+                     projectView.DisplayCompiler(compiler, false);
+                     projectView.ProjectUpdateMakefileForAllConfigs(prj);
+                     delete compiler;
 
                      {
                         char location[MAX_LOCATION];
@@ -1843,7 +2394,7 @@ class IDEWorkSpace : Window
                                        visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
                                     };
          if(!document)
-            MessageBox { type = ok, parent = this, text = filePath, contents = $"File doesn't exist." }.Modal();
+            MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
       }
 #ifndef NO3D
       else if(!strcmp(extension, "3ds"))
@@ -1855,7 +2406,7 @@ class IDEWorkSpace : Window
                                     };
 
          if(!document)
-            MessageBox { type = ok, parent = this, text = filePath, contents = $"File doesn't exist." }.Modal();
+            MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
       }
 #endif
       else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
@@ -1864,7 +2415,7 @@ class IDEWorkSpace : Window
             !strcmp(extension, "css") || !strcmp(extension, "php") ||
             !strcmp(extension, "js"))
       {
-         CodeEditor editor { parent = this, state = state, visible = false };
+         CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
          editor.updatingCode = true;
          if(editor.LoadFile(filePath))
          {
@@ -1877,7 +2428,7 @@ class IDEWorkSpace : Window
       }
       else
       {
-         CodeEditor editor { parent = this, state = state, visible = false };
+         CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
          if(editor.LoadFile(filePath))
          {
             document = editor;
@@ -1903,7 +2454,7 @@ class IDEWorkSpace : Window
       if(!document && createIfFails != no)
       {
          if(createIfFails != yes && !needFileModified && 
-               MessageBox { type = yesNo, parent = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
+               MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
             createIfFails = yes;
          if(createIfFails == yes || createIfFails == whatever)
          {
@@ -1941,6 +2492,7 @@ class IDEWorkSpace : Window
          else
             ideSettings.AddRecentFile(document.fileName);
          ide.UpdateRecentMenus();
+         ide.AdjustFileMenus();
          settingsContainer.Save();
          
          return document;
@@ -2002,29 +2554,71 @@ class IDEWorkSpace : Window
       return true;
    }
 
-   void GoToError(const char * line)
+   void GoToError(const char * line, bool noParsing)
    {
       if(projectView)
-         projectView.GoToError(line);
+         projectView.GoToError(line, noParsing);
    }
 
    void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
    {
+      char *s = null;
       char *path = text;
       char *colon = strchr(text, ':');
-      char filePath[MAX_LOCATION];
+      char filePath[MAX_LOCATION] = "";
       char completePath[MAX_LOCATION];
       int line = 0, col = 0;
+      int len = strlen(text);
       Project prj = null;
+      FileAttribs fileAttribs;
 
-      if(text[3] == '(')
+      // support for valgrind output
+      if((s = strstr(text, "==")) && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
+      {
+         colon = s;
+         for(; s>text; s--)
+         {
+            if(*s == '(')
+            {
+               path = s+1;
+               break;
+            }
+         }
+         /*for(s=colon; *s; s++)
+         {
+            if(*s == ')')
+            {
+               *s = '\0';;
+               break;
+            }
+         }*/
+         //*colon = '\0';
+         //line = atoi(colon+1);
+      }
+      // support for "Found n match(es) in "file/path";
+      else if(path[len-1] == '\"' && strstr(path, $"Found %d match%s in \"%s\"%s\n\n"."Found") && strstr(path, $"match") && strstr(path, $"in") && (s = strstr(path, "\"")) && s != path+len-1)
+      {
+         path = s+1;
+      }
+      else
       {
-         char * close = strchr(text, ')');
+         if(colon && (colon[1] == '/' || colon[1] == '\\'))
+         {
+            path = (colon - 1 > path) ? colon - 1 : path;
+            colon = strstr(colon + 1, ":");
+         }
+         if(*path == '*' && (s = strchr(path+1, '*')))
+            path = s+1;
+         while(isspace(*path)) path++;
+      }
+      if(*path == '(')
+      {
+         char * close = strchr(path, ')');
          if(close)
          {
             char name[256];
-            strncpy(name, &text[4], close - text - 4);
-            name[close - text - 4] = '\0';
+            strncpy(name, path+1, close - path - 1);
+            name[close - path - 1] = '\0';
             for(p : ide.workspace.projects)
             {
                if(!strcmp(p.name, name))
@@ -2038,12 +2632,6 @@ class IDEWorkSpace : Window
       }
       if(!prj)
          prj = project ? project : (dir ? null : ide.project);
-      if(colon && (colon[1] == '/' || colon[1] == '\\'))
-      {
-         path = (colon - 1 > path) ? colon - 1 : path;
-         colon = strstr(colon + 1, ":");
-      }
-      while(isspace(*path)) path++;
       if(colon)
       {
          strncpy(filePath, path, colon - path);
@@ -2053,7 +2641,7 @@ class IDEWorkSpace : Window
          if(colon)
             col = atoi(colon + 1);
       }
-      else if(path - 1 >= path && *(path - 1) == '\"')
+      else if(path - 1 >= text && *(path - 1) == '\"')
       {
          colon = strchr(path, '\"');
          if(colon)
@@ -2062,25 +2650,84 @@ class IDEWorkSpace : Window
             filePath[colon - path] = '\0';
          }
       }
+      else if(path && !colon)
+      {
+         strcpy(filePath, path);
+      }
 
-      if(prj)
-         strcpy(completePath, prj.topNode.path);
-      else if(dir && dir[0])
-         strcpy(completePath, dir);
-      else
-         completePath[0] = '\0';
-      PathCat(completePath, filePath);
+      if(filePath[0])
+      {
+         if(prj)
+            strcpy(completePath, prj.topNode.path);
+         else if(dir && dir[0])
+            strcpy(completePath, dir);
+         else
+            completePath[0] = '\0';
+         PathCat(completePath, filePath);
+
+         if((fileAttribs = FileExists(completePath)))
+            CodeLocationGoTo(completePath, fileAttribs, line, col);
+         else if(ide.workspace)
+         {
+            bool done = false;
+            for(p : ide.workspace.projects)
+            {
+               strcpy(completePath, p.topNode.path);
+               PathCat(completePath, filePath);
+               if((fileAttribs = FileExists(completePath)).isFile)
+               {
+                  CodeLocationGoTo(completePath, fileAttribs, line, col);
+                  done = true;
+                  break;
+               }
+            }
+            if(!done)
+            {
+               for(p : ide.workspace.projects)
+               {
+                  ProjectNode node = p.topNode.Find(filePath, false);
+                  if(node)
+                  {
+                     node.GetFullFilePath(completePath);
+                     if((fileAttribs = FileExists(completePath)).isFile)
+                     {
+                        CodeLocationGoTo(completePath, fileAttribs, line, col);
+                        break;
+                     }
+                  }
+               }
+            }
+         }
+      }
+   }
 
-      if(FileExists(completePath).isFile)
+   void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
+   {
+      if(fileAttribs.isFile)
       {
-         CodeEditor codeEditor = (CodeEditor)OpenFile(completePath, normal, true, "", no, normal);
-         if(codeEditor && line)
+         char ext[MAX_EXTENSION];
+         GetExtension(path, ext);
+         if(!strcmp(ext, "mp3") || !strcmp(ext, "flac") || !strcmp(ext, "ogg") || !strcmp(ext, "avi") || !strcmp(ext, "mkv"))
+            ShellOpen(path);
+         else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
          {
-            EditBox editBox = codeEditor.editBox;
-            editBox.GoToLineNum(line - 1);
-            editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
+            char dirPath[MAX_LOCATION];
+            StripLastDirectory(path, dirPath);
+            ShellOpen(dirPath);
+         }
+         else
+         {
+            CodeEditor codeEditor = (CodeEditor)OpenFile(path, normal, true, ext, no, normal, false);
+            if(codeEditor && line)
+            {
+               EditBox editBox = codeEditor.editBox;
+               editBox.GoToLineNum(line - 1);
+               editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
+            }
          }
       }
+      else if(fileAttribs.isDirectory)
+         ShellOpen(path);
    }
 
    void OnRedraw(Surface surface)
@@ -2243,7 +2890,7 @@ class IDEWorkSpace : Window
             caps = { width = 40, text = $"CAPS", color = app.GetKeyState(capsState) ? black : Color { 128, 128, 128 } };
             statusBar.AddField(caps);
 
-            ovr = { width = 30, text = $"OVR", color = editBox.overwrite ? black : Color { 128, 128, 128 } };
+            ovr = { width = 30, text = $"OVR", color = (editBox && editBox.overwrite) ? black : Color { 128, 128, 128 } };
             statusBar.AddField(ovr);
 
             num = { width = 30, text = $"NUM", color = app.GetKeyState(numState) ? black : Color { 128, 128, 128 } };
@@ -2253,11 +2900,17 @@ class IDEWorkSpace : Window
 
             if(projectView && projectView.project)
             {
-               ProjectNode node = projectView.GetNodeFromWindow(client, null);
+               bool isCObject = false;
+               ProjectNode node = projectView.GetNodeFromWindow(client, null, false);
+               if(!node && (node = projectView.GetNodeFromWindow(client, null, true)))
+                  isCObject = true;
                if(node)
                {
-                  char name[1024];
-                  sprintf(name, $"Compile %s", node.name);
+                  char nodeName[MAX_FILENAME];
+                  char name[MAX_FILENAME+96];
+                  if(isCObject)
+                     ChangeExtension(node.name, "c", nodeName);
+                  sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
                   projectCompileItem = 
                   {
                      copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
@@ -2266,9 +2919,26 @@ class IDEWorkSpace : Window
                      {
                         if(projectView)
                         {
-                           ProjectNode node = projectView.GetNodeFromWindow(activeClient, null);
+                           bool result = false;
+                           bool isCObject = false;
+                           ProjectNode node = null;
+                           for(p : ide.workspace.projects)
+                           {
+                              node = projectView.GetNodeFromWindow(activeClient, p, false);
+                              if(node) break;
+                           }
+                           if(!node && (node = projectView.GetNodeFromWindow(activeClient, null, true)))
+                              isCObject = true;
                            if(node)
-                              projectView.Compile(node);
+                           {
+                              List<ProjectNode> nodes { };
+                              nodes.Add(node);
+                              projectView.Compile(node.project, nodes, mods.ctrl && mods.shift, isCObject ? cObject : normal);
+                              delete nodes;
+                              result = true;
+                           }
+                           if(!result && node)
+                              ide.outputView.buildBox.Logf($"File %s is excluded from current build configuration.\n", node.name);
                         }
                         return true;
                      }
@@ -2305,14 +2975,114 @@ class IDEWorkSpace : Window
    bool OnPostCreate()
    {
       int c;
+      bool passThrough = false;
+      bool debugStart = false;
+      bool debugWorkDir = false;
+      char * passDebugWorkDir = null;
+      bool openAsText = false;
+      DynamicString passArgs { };
+      int ptArg = 0;
+
       for(c = 1; c<app.argc; c++)
       {
-         char fullPath[MAX_LOCATION];
-         GetWorkingDir(fullPath, MAX_LOCATION);
-         PathCat(fullPath, app.argv[c]);
-         if(FileExists(fullPath))
-            ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
+         if(passThrough)
+         {
+            char * arg = app.argv[c];
+            char * buf = new char[strlen(arg)*2+1];
+            if(ptArg++ > 0)
+               passArgs.concat(" ");
+            PassArg(buf, arg);
+            passArgs.concat(buf);
+            delete buf;
+         }
+         else if(debugWorkDir)
+         {
+            passDebugWorkDir = CopyString(app.argv[c]);
+            StripQuotes(passDebugWorkDir, passDebugWorkDir);
+            debugWorkDir = false;
+         }
+         else if(!strcmp(app.argv[c], "-t"))
+            openAsText = true;
+         else if(!strcmp(app.argv[c], "-no-parsing"))
+            ide.noParsing = true;
+         else if(!strcmp(app.argv[c], "-debug-start"))
+            debugStart = true;
+         else if(!strcmp(app.argv[c], "-debug-work-dir"))
+            debugWorkDir = true;
+         else if(!strcmp(app.argv[c], "-@"))
+            passThrough = true;
+         else
+         {
+            char fullPath[MAX_LOCATION];
+            char parentPath[MAX_LOCATION];
+            char ext[MAX_EXTENSION];
+            bool isProject;
+            FileAttribs dirAttribs;
+            GetWorkingDir(fullPath, MAX_LOCATION);
+            PathCat(fullPath, app.argv[c]);
+            StripLastDirectory(fullPath, parentPath);
+            GetExtension(app.argv[c], ext);
+            isProject = !openAsText && !strcmpi(ext, "epj");
+
+            if(isProject && c > (debugStart ? 2 : 1)) continue;
+
+            // Create directory for projects (only)
+            if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
+            {
+               if(isProject && !FileExists(fullPath))
+               {
+                  char name[MAX_LOCATION];
+                  NewProjectDialog newProjectDialog;
+
+                  if(projectView)
+                  {
+                     projectView.visible = false;
+                     if(!projectView.Destroy(0))
+                        return true;
+                  }
+
+                  newProjectDialog = { master = this };
+
+                  strcpy(name, app.argv[c]);
+                  StripExtension(name);
+                  GetLastDirectory(name, name);
+                  newProjectDialog.projectName.contents = name;
+                  newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
+                  newProjectDialog.locationEditBox.path = parentPath;
+                  newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
+
+                  incref newProjectDialog;
+                  newProjectDialog.Modal();
+                  if(projectView)
+                  {
+                     ideSettings.AddRecentProject(projectView.fileName);
+                     ide.UpdateRecentMenus();
+                     settingsContainer.Save();
+                  }
+                  delete newProjectDialog;
+                  // Open only one project
+                  break;
+               }
+               else
+                  ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, openAsText ? "txt" : null, yes, normal, false);
+            }
+            else if(strstr(fullPath, "http://") == fullPath)
+               ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, openAsText ? "txt" : null, yes, normal, false);
+         }
       }
+      if(passThrough && projectView && projectView.project && workspace)
+         workspace.commandLineArgs = passArgs;
+      if(passDebugWorkDir && projectView && projectView.project && workspace)
+      {
+         workspace.debugDir = passDebugWorkDir;
+         delete passDebugWorkDir;
+      }
+      if(debugStart)
+         ;//MenuDebugStart(debugStartResumeItem, 0); // <-- how TODO this without getting into the app.Wait lock
+
+      UpdateToolBarActiveConfigs(false);
+      UpdateToolBarActiveCompilers();
+      delete passArgs;
       return true;
    }
 
@@ -2331,7 +3101,7 @@ class IDEWorkSpace : Window
 #endif
    }
 
-   void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config)
+   void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
    {
       int c, len, count;
       char * newList;
@@ -2360,7 +3130,7 @@ class IDEWorkSpace : Window
             //       To go with the initial state, e.g. when F5 was pressed,
             //       we nould need to keep a list of all project's active
             //       config upon startup.
-            targetDirExp = prj.GetTargetDir(compiler, prj.config);
+            targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
 
             /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
                cfg = prj.config;
@@ -2462,8 +3232,9 @@ class IDEWorkSpace : Window
       {
          if(!libPathExists[item])  // fstrcmp should be used
          {
-            newLibPaths.Add(item);
-            libPathExists[item] = true;
+            String s = CopyString(item);
+            newLibPaths.Add(s);
+            libPathExists[s] = true;
          }
       }
 
@@ -2480,8 +3251,9 @@ class IDEWorkSpace : Window
       {
          if(!libPathExists[oldPaths[c]])  // fstrcmp should be used
          {
-            newLibPaths.Add(oldPaths[c]);
-            libPathExists[oldPaths[c]] = true;
+            String s = CopyString(oldPaths[c]);
+            newLibPaths.Add(s);
+            libPathExists[s] = true;
          }
       }
 
@@ -2506,6 +3278,7 @@ class IDEWorkSpace : Window
 #endif*/
       delete newList;
 
+      newLibPaths.Free();
       delete newLibPaths;
       delete libPathExists;
 #endif
@@ -2580,7 +3353,8 @@ class IDEWorkSpace : Window
       Menu fileMenu = menu.FindMenu($"File");
       Menu recentFiles = fileMenu.FindMenu($"Recent Files");
       Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
-      char itemName[MAX_LOCATION + 4];
+      char * itemPath = new char[MAX_LOCATION];
+      char * itemName = new char[MAX_LOCATION+4];
       MenuItem item;
 
       recentFiles.Clear();
@@ -2588,8 +3362,9 @@ class IDEWorkSpace : Window
 
       for(recent : ideSettings.recentFiles)
       {
-         sprintf(itemName, "%d %s", 1 + c, recent);
-         MakeSystemPath(itemName);
+         strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
+         MakeSystemPath(itemPath);
+         snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
          recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
          c++;
       }
@@ -2598,11 +3373,15 @@ class IDEWorkSpace : Window
       c = 0;
       for(recent : ideSettings.recentProjects)
       {
-         sprintf(itemName, "%d %s", 1 + c, recent);
-         MakeSystemPath(itemName);
+         strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
+         MakeSystemPath(itemPath);
+         snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
          recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
          c++;
       }
+
+      delete itemPath;
+      delete itemName;
    }
 
    ~IDEWorkSpace()
@@ -2610,6 +3389,12 @@ class IDEWorkSpace : Window
       delete driverItems;
       delete skinItems;
       delete ideSettings;
+      if(documentor)
+      {
+         documentor.Puts("Quit\n");
+         documentor.Wait();
+         delete documentor;
+      }
    }
 }
 
@@ -2620,6 +3405,148 @@ void DestroyDir(char * path)
    delete fsi;
 }
 
+#if defined(__WIN32__)
+define sdkDirName = "Ecere SDK";
+#else
+define sdkDirName = "ecere";
+#endif
+
+void FindAndShellOpenInstalledFolder(char * name)
+{
+   char * p = new char[MAX_LOCATION];
+   char * v = new char[maxPathLen];
+   byte * tokens[256];
+   int c, numTokens;
+   Array<String> paths { };
+   p[0] = v[0] = '\0';
+   strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+   StripLastDirectory(p, p);
+   PathCat(p, name);
+   paths.Add(CopyString(p));
+#if defined(__WIN32__)
+   GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
+   if(v[0])
+   {
+      strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, name); paths.Add(CopyString(p));
+   }
+   GetEnvironment("AppData", v, maxPathLen);
+   if(v[0])
+   {
+      strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
+   }
+   GetEnvironment("ProgramFiles", v, maxPathLen);
+   if(v[0])
+   {
+      strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
+   }
+   GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
+   if(v[0])
+   {
+      strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
+   }
+   GetEnvironment("SystemDrive", v, maxPathLen);
+   if(v[0])
+   {
+      strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, "Program Files"); PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
+   }
+#else
+   GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
+   numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
+   for(c=0; c<numTokens; c++)
+   {
+      strncpy(p, tokens[c], MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
+   }
+#endif
+   for(path : paths)
+   {
+      strncpy(p, path, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      if(FileExists(p).isDirectory)
+      {
+         ShellOpen(p);
+         break;
+      }
+   }
+   delete p;
+   delete v;
+   paths.Free();
+   delete paths;
+}
+
+void FindAndShellOpenInstalledFile(char * subdir, char * name)
+{
+   char * p = new char[MAX_LOCATION];
+   char * v = new char[maxPathLen];
+   byte * tokens[256];
+   int c, numTokens;
+   Array<String> paths { };
+   p[0] = v[0] = '\0';
+   strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+   paths.Add(CopyString(p));
+   StripLastDirectory(p, p);
+   PathCat(p, subdir);
+   paths.Add(CopyString(p));
+#if defined(__WIN32__)
+   GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
+   if(v[0])
+   {
+      strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
+   }
+   GetEnvironment("AppData", v, maxPathLen);
+   if(v[0])
+   {
+      strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
+   }
+   GetEnvironment("ProgramFiles", v, maxPathLen);
+   if(v[0])
+   {
+      strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
+   }
+   GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
+   if(v[0])
+   {
+      strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
+   }
+   GetEnvironment("SystemDrive", v, maxPathLen);
+   if(v[0])
+   {
+      strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, "Program Files"); PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
+   }
+#else
+   GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
+   numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
+   for(c=0; c<numTokens; c++)
+   {
+      strncpy(p, tokens[c], MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
+   }
+#endif
+   for(path : paths)
+   {
+      strncpy(p, path, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
+      PathCat(p, name);
+      if(FileExists(p).isFile)
+      {
+         ShellOpen(p);
+         break;
+      }
+   }
+   delete p;
+   delete v;
+   paths.Free();
+   delete paths;
+}
+
 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
 {
    bool preserveRootFolder;
@@ -2643,18 +3570,30 @@ class IDEApp : GuiApplication
    // driver = "OpenGL";
    // skin = "Aqua";
    //skin = "TVision";
+
+   TempFile includeFile { };
+
    bool Init()
    {
+      char ext[MAX_EXTENSION];
       SetLoggingMode(stdOut, null);
       //SetLoggingMode(debug, null);
 
       settingsContainer.Load();
+      if(argc > 1 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
+      {
+         app.driver = "OpenGL";
+         ide.driverItems[1].checked = true;
+      }
+      else
+      {
 #if defined(__unix__) || defined(__APPLE__)
-      app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
+         app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
 #else
-      app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
+         app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
 #endif
-      ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
+         ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
+      }
 
       SetInIDE(true);
 
@@ -2666,11 +3605,64 @@ class IDEApp : GuiApplication
          char fullPath[MAX_LOCATION];
          GetWorkingDir(fullPath, MAX_LOCATION);
          PathCat(fullPath, app.argv[c]);
-         ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
+         ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal, false);
       }
       */
+
+      if(!LoadIncludeFile())
+         PrintLn("error: unable to load :crossplatform.mk file inside ide binary.");
+
+      return true;
+   }
+
+   bool Cycle(bool idle)
+   {
+      if(ide.documentor)
+      {
+         if(ide.documentor.Peek())
+         {
+            char line[1024];
+            ide.documentor.GetLine(line, sizeof(line));
+            if(!strcmpi(line, "Exited"))
+            {
+               ide.documentor.CloseInput();
+               ide.documentor.CloseOutput();
+               ide.documentor.Wait();
+               delete ide.documentor;
+            }
+         }
+         if(ide.documentor && ide.documentor.eof)
+         {
+            ide.documentor.CloseInput();
+            ide.documentor.CloseOutput();
+            ide.documentor.Wait();
+            delete ide.documentor;
+         }
+      }
       return true;
    }
+
+   bool LoadIncludeFile()
+   {
+      bool result = false;
+      File include = FileOpen(":crossplatform.mk", read);
+      if(include)
+      {
+         File f = includeFile;
+         if(f)
+         {
+            for(; !include.Eof(); )
+            {
+               char buffer[4096];
+               int count = include.Read(buffer, 1, 4096);
+               f.Write(buffer, 1, count);
+            }
+            result = true;
+         }
+         delete include;
+      }
+      return result;
+   }
 }
 
 IDEMainFrame ideMainFrame { };