Skip to content

Commit f1c05eb

Browse files
committed
fix: replace detached threads with BackgroundWorker for safe shutdown
1 parent a62050f commit f1c05eb

6 files changed

Lines changed: 134 additions & 17 deletions

File tree

src/components/titlebar.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
#include <dpi.h>
3434
#include <components.h>
3535
#include <animate.h>
36-
#include <iostream>
3736
#include <math.h>
37+
#include <worker.h>
3838

3939
using namespace ImGui;
4040

@@ -106,7 +106,8 @@ bool RenderTitleBarComponent(std::shared_ptr<RouterNav> router)
106106
PopStyleVar();
107107
EndChild();
108108

109-
if (IsItemClicked(ImGuiMouseButton_Left)) {
109+
if (IsItemClicked(ImGuiMouseButton_Left) && !IsWorkerBusy()) {
110+
JoinWorker();
110111
ExitProcess(0);
111112
}
112113

@@ -120,4 +121,4 @@ bool RenderTitleBarComponent(std::shared_ptr<RouterNav> router)
120121
PopStyleVar();
121122

122123
return IsItemHovered() || (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && IsMouseDown(ImGuiMouseButton_Left));
123-
}
124+
}

src/include/worker.h

Lines changed: 78 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/routes/home.cc

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,12 @@
3535
#include <memory>
3636
#include <router.h>
3737
#include <imgui_internal.h>
38-
#include <iostream>
3938
#include <dpi.h>
4039
#include <unordered_map>
4140
#include <components.h>
42-
#include <thread>
4341
#include <atomic>
4442
#include <imspinner.h>
43+
#include <worker.h>
4544

4645
using namespace ImGui;
4746
using namespace ImSpinner;
@@ -174,7 +173,7 @@ const void RenderHome(std::shared_ptr<RouterNav> router, float xPos)
174173

175174
PushStyleColor(ImGuiCol_Border, ImVec4(0.169f, 0.173f, 0.18f, 1.0f));
176175

177-
SetCursorPos({ xPos + (viewport->Size.x - ((ContainerWidth * 2) + ContainerSpacing)) / 2, ((viewport->Size.y - BottomNavBarHeight) / 2.0f) - ContainerHeight / 2 });
176+
SetCursorPos({ xPos + (viewport->Size.x - ((ContainerWidth * 2) + ContainerSpacing)) / 2, ((viewport->Size.y - BottomNavBarHeight) / 2.0f) - ContainerHeight / 2.0f });
178177

179178
RenderOption({ "Install", "Integrate Millennium into your Steam® Client.", INSTALL }, ContainerWidth, ContainerHeight, ContainerSpacing);
180179
RenderOption({ "Remove", "Selectively uninstall portions of Millennium.", REMOVE }, ContainerWidth, ContainerHeight, ContainerSpacing);
@@ -242,7 +241,7 @@ const void RenderHome(std::shared_ptr<RouterNav> router, float xPos)
242241
isLoading.store(false, std::memory_order_relaxed);
243242
};
244243

245-
std::thread(StartInstall).detach();
244+
GetWorker().run(StartInstall);
246245
break;
247246
}
248247
case REMOVE:
@@ -257,7 +256,7 @@ const void RenderHome(std::shared_ptr<RouterNav> router, float xPos)
257256
isLoading.store(false, std::memory_order_relaxed);
258257
};
259258

260-
std::thread(StartUninstall).detach();
259+
GetWorker().run(StartUninstall);
261260
break;
262261
}
263262
default:
@@ -314,4 +313,4 @@ const void RenderHome(std::shared_ptr<RouterNav> router, float xPos)
314313

315314
PopStyleVar(2);
316315
PopStyleColor(4);
317-
}
316+
}

src/routes/install_prompt.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,14 @@
3838
#include <router.h>
3939
#include <iostream>
4040
#include <dpi.h>
41-
#include <unordered_map>
4241
#include <components.h>
43-
#include <filesystem>
4442
#include <nlohmann/json.hpp>
4543
#include <http.h>
4644
#include <util.h>
4745
#include <imgui_markdown.h>
4846
#include <mini/ini.h>
4947
#include <format>
48+
#include <worker.h>
5049

5150
using namespace ImGui;
5251

@@ -429,7 +428,12 @@ const void RenderInstallPrompt(std::shared_ptr<RouterNav> router, float xPos)
429428
PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(currentColor, currentColor, currentColor, 1.0f));
430429

431430
if (Button("Install", ImVec2(xPos + GetContentRegionAvail().x, GetContentRegionAvail().y))) {
432-
std::thread(StartInstaller, steamPath, std::ref(selectedRelease), std::ref(osReleaseInfo)).detach();
431+
auto path = steamPath;
432+
auto release = selectedRelease;
433+
auto osRelease = osReleaseInfo;
434+
GetWorker().run([path, release, osRelease]() {
435+
StartInstaller(path, release, osRelease);
436+
});
433437
router->navigateNext();
434438
}
435439

src/routes/uninstall_select.cc

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,11 @@
3838
#include <router.h>
3939
#include <iostream>
4040
#include <dpi.h>
41-
#include <unordered_map>
4241
#include <components.h>
43-
#include <map>
4442
#include <filesystem>
4543
#include <imspinner.h>
4644
#include <util.h>
47-
#include <thread>
45+
#include <worker.h>
4846

4947
using namespace ImGui;
5048
using namespace ImSpinner;
@@ -421,7 +419,7 @@ const void RenderUninstallSelect(std::shared_ptr<RouterNav> router, float xPos)
421419
std::cout << "Uninstalling components..." << std::endl;
422420

423421
isUninstalling = true;
424-
std::thread(StartUninstall).detach();
422+
GetWorker().run(StartUninstall);
425423
}
426424

427425
if (isButtonHovered) {
@@ -432,4 +430,4 @@ const void RenderUninstallSelect(std::shared_ptr<RouterNav> router, float xPos)
432430
isButtonHovered = IsItemHovered() || (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && IsMouseDown(ImGuiMouseButton_Left));
433431
}
434432
});
435-
}
433+
}

src/util/worker.cc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* ==================================================
3+
* _____ _ _ _ _
4+
* | |_| | |___ ___ ___|_|_ _ _____
5+
* | | | | | | | -_| | | | | | |
6+
* |_|_|_|_|_|_|___|_|_|_|_|_|___|_|_|_|
7+
*
8+
* ==================================================
9+
*
10+
* Copyright (c) 2025 Project Millennium
11+
*
12+
* Permission is hereby granted, free of charge, to any person obtaining a copy
13+
* of this software and associated documentation files (the "Software"), to deal
14+
* in the Software without restriction, including without limitation the rights
15+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16+
* copies of the Software, and to permit persons to whom the Software is
17+
* furnished to do so, subject to the following conditions:
18+
*
19+
* The above copyright notice and this permission notice shall be included in all
20+
* copies or substantial portions of the Software.
21+
*
22+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28+
* SOFTWARE.
29+
*/
30+
31+
#include <worker.h>
32+
33+
static BackgroundWorker g_worker;
34+
35+
BackgroundWorker& GetWorker() { return g_worker; }
36+
bool IsWorkerBusy() { return g_worker.busy(); }
37+
void JoinWorker() { g_worker.join(); }

0 commit comments

Comments
 (0)