diff --git a/src/modules/Workspaces/WorkspacesEditor/Data/TempProjectData.cs b/src/modules/Workspaces/WorkspacesEditor/Data/TempProjectData.cs index b3de2f5b4d..e893cafc7c 100644 --- a/src/modules/Workspaces/WorkspacesEditor/Data/TempProjectData.cs +++ b/src/modules/Workspaces/WorkspacesEditor/Data/TempProjectData.cs @@ -16,6 +16,14 @@ namespace WorkspacesEditor.Data } } + public static string LaunchFile + { + get + { + return FolderUtils.DataFolder() + "\\tempLaunch-workspaces.json"; + } + } + public static void DeleteTempFile() { if (System.IO.File.Exists(File)) diff --git a/src/modules/Workspaces/WorkspacesEditor/Models/Project.cs b/src/modules/Workspaces/WorkspacesEditor/Models/Project.cs index b0065dd2ee..2df15d5cb6 100644 --- a/src/modules/Workspaces/WorkspacesEditor/Models/Project.cs +++ b/src/modules/Workspaces/WorkspacesEditor/Models/Project.cs @@ -207,9 +207,9 @@ namespace WorkspacesEditor.Models private BitmapImage _previewImage; private double _previewImageWidth; - public Project(Project selectedProject) + public Project(Project selectedProject, string newId = "") { - Id = selectedProject.Id; + Id = newId == string.Empty ? selectedProject.Id : newId; Name = selectedProject.Name; PreviewIcons = selectedProject.PreviewIcons; PreviewImage = selectedProject.PreviewImage; diff --git a/src/modules/Workspaces/WorkspacesEditor/Utils/WorkspacesEditorIO.cs b/src/modules/Workspaces/WorkspacesEditor/Utils/WorkspacesEditorIO.cs index 3c0c2a787d..6b0d4150fc 100644 --- a/src/modules/Workspaces/WorkspacesEditor/Utils/WorkspacesEditorIO.cs +++ b/src/modules/Workspaces/WorkspacesEditor/Utils/WorkspacesEditorIO.cs @@ -15,6 +15,13 @@ namespace WorkspacesEditor.Utils { public class WorkspacesEditorIO { + public enum StorageFile + { + Common, + Temporaly, + TemporallyLaunch, + } + public WorkspacesEditorIO() { } @@ -72,7 +79,7 @@ namespace WorkspacesEditor.Utils } } - public void SerializeWorkspaces(List workspaces, bool useTempFile = false) + public void SerializeWorkspaces(List workspaces, StorageFile storageFile = StorageFile.Common) { WorkspacesData serializer = new WorkspacesData(); WorkspacesData.WorkspacesListWrapper workspacesWrapper = new WorkspacesData.WorkspacesListWrapper { }; @@ -148,7 +155,14 @@ namespace WorkspacesEditor.Utils try { IOUtils ioUtils = new IOUtils(); - ioUtils.WriteFile(useTempFile ? TempProjectData.File : serializer.File, serializer.Serialize(workspacesWrapper)); + string fileName = storageFile switch + { + StorageFile.Temporaly => TempProjectData.File, + StorageFile.TemporallyLaunch => TempProjectData.LaunchFile, + _ => serializer.File, + }; + + ioUtils.WriteFile(fileName, serializer.Serialize(workspacesWrapper)); } catch (Exception e) { @@ -176,7 +190,22 @@ namespace WorkspacesEditor.Utils internal void SerializeTempProject(Project project) { - SerializeWorkspaces(new List() { project }, true); + SerializeWorkspaces(new List() { project }, StorageFile.Temporaly); + } + + internal void RemoveFile(StorageFile storageFile) + { + string fileName = storageFile switch + { + StorageFile.Temporaly => TempProjectData.File, + StorageFile.TemporallyLaunch => TempProjectData.LaunchFile, + _ => string.Empty, + }; + + if (File.Exists(fileName)) + { + File.Delete(fileName); + } } } } diff --git a/src/modules/Workspaces/WorkspacesEditor/ViewModels/MainViewModel.cs b/src/modules/Workspaces/WorkspacesEditor/ViewModels/MainViewModel.cs index 1ad14f4a87..15ec46e984 100644 --- a/src/modules/Workspaces/WorkspacesEditor/ViewModels/MainViewModel.cs +++ b/src/modules/Workspaces/WorkspacesEditor/ViewModels/MainViewModel.cs @@ -509,7 +509,13 @@ namespace WorkspacesEditor.ViewModels internal async void LaunchAndEdit(Project project) { - await Task.Run(() => RunLauncher(project.Id, InvokePoint.LaunchAndEdit)); + // the project might contain removed apps, creating a temporaly copy of it (without removed apps) and launching the copy. + Project launchProject = new Project(project, Guid.NewGuid().ToString()); + _workspacesEditorIO.SerializeWorkspaces(new List() { launchProject }, WorkspacesEditorIO.StorageFile.TemporallyLaunch); + + await Task.Run(() => RunLauncher(launchProject.Id, InvokePoint.LaunchAndEdit)); + + _workspacesEditorIO.RemoveFile(WorkspacesEditorIO.StorageFile.TemporallyLaunch); projectBeforeLaunch = new Project(project); EnterSnapshotMode(true); } diff --git a/src/modules/Workspaces/WorkspacesLauncher/main.cpp b/src/modules/Workspaces/WorkspacesLauncher/main.cpp index b3d7f28bbb..cb1e1f6de8 100644 --- a/src/modules/Workspaces/WorkspacesLauncher/main.cpp +++ b/src/modules/Workspaces/WorkspacesLauncher/main.cpp @@ -24,7 +24,7 @@ const std::wstring internalPath = L""; int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdline, int cmdShow) { LoggerHelpers::init_logger(moduleName, internalPath, LogSettings::workspacesLauncherLoggerName); - InitUnhandledExceptionHandler(); + InitUnhandledExceptionHandler(); if (powertoys_gpo::getConfiguredWorkspacesEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled) { @@ -41,7 +41,7 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdline, int cm GetModuleFileNameW(nullptr, exe_path.get(), exe_path_size); const auto modulePath = get_module_folderpath(); - + std::string cmdLineStr(cmdline); std::wstring cmdLineWStr(cmdLineStr.begin(), cmdLineStr.end()); @@ -57,7 +57,7 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdline, int cm } SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); - + std::string cmdLineStr(cmdline); auto cmdArgs = split(cmdLineStr, " "); if (cmdArgs.size() < 1) @@ -66,7 +66,7 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdline, int cm MessageBox(NULL, GET_RESOURCE_STRING(IDS_INCORRECT_ARGS).c_str(), GET_RESOURCE_STRING(IDS_WORKSPACES).c_str(), MB_ICONERROR | MB_OK); return 1; } - + std::wstring id(cmdArgs[0].begin(), cmdArgs[0].end()); if (id.empty()) { @@ -94,45 +94,103 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdline, int cm WorkspacesData::WorkspacesProject projectToLaunch{}; if (invokePoint == InvokePoint::LaunchAndEdit) { - // check the temp file in case the project is just created and not saved to the workspaces.json yet - if (std::filesystem::exists(WorkspacesData::TempWorkspacesFile())) + // check the temp launch file in case the project is launched from the editor + if (std::filesystem::exists(WorkspacesData::TempLaunchWorkspacesFile())) { try { - auto savedWorkspacesJson = json::from_file(WorkspacesData::TempWorkspacesFile()); + auto savedWorkspacesJson = json::from_file(WorkspacesData::TempLaunchWorkspacesFile()); if (savedWorkspacesJson.has_value()) { - auto savedWorkspaces = WorkspacesData::WorkspacesProjectJSON::FromJson(savedWorkspacesJson.value()); + auto savedWorkspaces = WorkspacesData::WorkspacesListJSON::FromJson(savedWorkspacesJson.value()); if (savedWorkspaces.has_value()) { - projectToLaunch = savedWorkspaces.value(); + workspaces = savedWorkspaces.value(); } else { - Logger::critical("Incorrect Workspaces file"); - std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_INCORRECT_FILE_ERROR), WorkspacesData::TempWorkspacesFile()); + Logger::critical("Incorrect temporaly launch Workspaces file"); + std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_INCORRECT_FILE_ERROR), WorkspacesData::TempLaunchWorkspacesFile()); MessageBox(NULL, formattedMessage.c_str(), GET_RESOURCE_STRING(IDS_WORKSPACES).c_str(), MB_ICONERROR | MB_OK); return 1; } } else { - Logger::critical("Incorrect Workspaces file"); - std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_INCORRECT_FILE_ERROR), WorkspacesData::TempWorkspacesFile()); + Logger::critical("Incorrect temporaly launch Workspaces file"); + std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_INCORRECT_FILE_ERROR), WorkspacesData::TempLaunchWorkspacesFile()); MessageBox(NULL, formattedMessage.c_str(), GET_RESOURCE_STRING(IDS_WORKSPACES).c_str(), MB_ICONERROR | MB_OK); return 1; } } catch (std::exception ex) { - Logger::critical("Exception on reading Workspaces file: {}", ex.what()); - std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_FILE_READING_ERROR), WorkspacesData::TempWorkspacesFile()); + Logger::critical("Exception on reading temporaly launch Workspaces file: {}", ex.what()); + std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_FILE_READING_ERROR), WorkspacesData::TempLaunchWorkspacesFile()); MessageBox(NULL, formattedMessage.c_str(), GET_RESOURCE_STRING(IDS_WORKSPACES).c_str(), MB_ICONERROR | MB_OK); return 1; } + + if (workspaces.empty()) + { + Logger::warn("Temp Launch Workspaces file is empty"); + std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_EMPTY_FILE), WorkspacesData::TempLaunchWorkspacesFile()); + MessageBox(NULL, formattedMessage.c_str(), GET_RESOURCE_STRING(IDS_WORKSPACES).c_str(), MB_ICONERROR | MB_OK); + return 1; + } + + for (const auto& proj : workspaces) + { + if (proj.id == id) + { + projectToLaunch = proj; + break; + } + } + } + + if (projectToLaunch.id.empty()) + { + // check the temp file in case the project is just created and not saved to the workspaces.json yet + if (std::filesystem::exists(WorkspacesData::TempWorkspacesFile())) + { + try + { + auto savedWorkspacesJson = json::from_file(WorkspacesData::TempWorkspacesFile()); + if (savedWorkspacesJson.has_value()) + { + auto savedWorkspaces = WorkspacesData::WorkspacesProjectJSON::FromJson(savedWorkspacesJson.value()); + if (savedWorkspaces.has_value()) + { + projectToLaunch = savedWorkspaces.value(); + } + else + { + Logger::critical("Incorrect temporaly Workspaces file"); + std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_INCORRECT_FILE_ERROR), WorkspacesData::TempWorkspacesFile()); + MessageBox(NULL, formattedMessage.c_str(), GET_RESOURCE_STRING(IDS_WORKSPACES).c_str(), MB_ICONERROR | MB_OK); + return 1; + } + } + else + { + Logger::critical("Incorrect temporaly Workspaces file"); + std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_INCORRECT_FILE_ERROR), WorkspacesData::TempWorkspacesFile()); + MessageBox(NULL, formattedMessage.c_str(), GET_RESOURCE_STRING(IDS_WORKSPACES).c_str(), MB_ICONERROR | MB_OK); + return 1; + } + } + catch (std::exception ex) + { + Logger::critical("Exception on reading temporaly Workspaces file: {}", ex.what()); + std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_FILE_READING_ERROR), WorkspacesData::TempWorkspacesFile()); + MessageBox(NULL, formattedMessage.c_str(), GET_RESOURCE_STRING(IDS_WORKSPACES).c_str(), MB_ICONERROR | MB_OK); + return 1; + } + } } } - + if (projectToLaunch.id.empty()) { try @@ -201,7 +259,7 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdline, int cm std::vector> launchErrors{}; auto start = std::chrono::high_resolution_clock::now(); bool launchedSuccessfully = Launch(projectToLaunch, monitors, launchErrors); - + // update last-launched time if (invokePoint != InvokePoint::LaunchAndEdit) { diff --git a/src/modules/Workspaces/WorkspacesLib/WorkspacesData.cpp b/src/modules/Workspaces/WorkspacesLib/WorkspacesData.cpp index b9748aa993..fc5b0fa127 100644 --- a/src/modules/Workspaces/WorkspacesLib/WorkspacesData.cpp +++ b/src/modules/Workspaces/WorkspacesLib/WorkspacesData.cpp @@ -22,6 +22,12 @@ namespace WorkspacesData return settingsFolderPath + L"\\temp-workspaces.json"; } + std::wstring TempLaunchWorkspacesFile() + { + std::wstring settingsFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey); + return settingsFolderPath + L"\\tempLaunch-workspaces.json"; + } + std::wstring LaunchWorkspacesFile() { std::wstring settingsFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey); diff --git a/src/modules/Workspaces/WorkspacesLib/WorkspacesData.h b/src/modules/Workspaces/WorkspacesLib/WorkspacesData.h index 908552530f..1aee4f3375 100644 --- a/src/modules/Workspaces/WorkspacesLib/WorkspacesData.h +++ b/src/modules/Workspaces/WorkspacesLib/WorkspacesData.h @@ -6,6 +6,7 @@ namespace WorkspacesData { std::wstring WorkspacesFile(); std::wstring TempWorkspacesFile(); + std::wstring TempLaunchWorkspacesFile(); std::wstring LaunchWorkspacesFile(); struct WorkspacesProject