Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
761a085
feat: Added Untiy CLI integration to keep Unity signed in without sta…
ManeFunction Nov 2, 2026
31f5bee
feat: Changed text formatting on the CLI installation popup
ManeFunction Nov 5, 2026
2544dab
feat: Added message about sudo password
ManeFunction Nov 5, 2026
b557648
fix: Fixed lost SIGCHLD wake-up that left Unity CLI commands hanging
ManeFunction Nov 5, 2026
d9bd1bd
fix: Fixed use-after-free when a Unity CLI command ends during a prog…
ManeFunction Nov 5, 2026
12f91d9
feat: Escape closes the Unity CLI install prompt as Not Now
ManeFunction Nov 5, 2026
89b526f
refactor: Moved the window minimum size code out of the main window c…
ManeFunction Nov 5, 2026
49731b0
docs: Recorded the local wxWidgets wake-up pipe patch
ManeFunction Nov 5, 2026
328b57c
build: Existing build directories pick up new source files
ManeFunction Nov 5, 2026
662b7fc
refactor: Shared one home folder lookup on macOS and Linux
ManeFunction Nov 5, 2026
81fd152
fix: Read Unity CLI JSON values by their full path
ManeFunction Nov 5, 2026
9bf5250
refactor: Wrote the Unity CLI install script as a raw string literal
ManeFunction Nov 5, 2026
50dd785
refactor: Modelled the Unity CLI as one typed status, probed once per…
ManeFunction Nov 5, 2026
cd99530
refactor: Moved the choice between the Unity CLI and a direct Editor …
ManeFunction Nov 5, 2026
7e5fa9b
feat: New projects open signed in through the Unity CLI
ManeFunction Nov 5, 2026
4743aea
refactor: Moved the Unity CLI buttons and prompts out of the main window
ManeFunction Nov 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ endif()
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/wxWidgets/build/cmake/modules" CACHE INTERNAL "")
message("module path = ${CMAKE_MODULE_PATH}")

file(GLOB source "source/*.cpp" "source/*.hpp" "source/*.h")
# CONFIGURE_DEPENDS: existing build directories pick up added or removed source files
file(GLOB source CONFIGURE_DEPENDS "source/*.cpp" "source/*.hpp" "source/*.h")
if (APPLE)
enable_language(C CXX OBJCXX)
set(OBJCPP "source/AppleUtilities.h" "source/AppleUtilities.mm")
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ UnityHubNative launches many times faster, uses far less memory and CPU, and is
## Features
- Add an existing project to the list using the Add Existing button
- Open projects by double-clicking them in the list, or by selecting them and pressing Enter
- Open projects signed in to your Unity account (Asset Store, Unity services) without the official hub running, through the official Unity CLI, for Unity 2019.1 and newer. UnityHubNative offers to install the CLI on launch, and the Install CLI and Login CLI buttons in the Editor Versions tab install it and sign it in to your Unity account. Requires Unity CLI 1.0.0-beta.10 or newer (1.0.0-beta.12 on Windows)
- Create new unity projects with templates, for any modern Unity version you have installed, with the Create New button
- View Unity installs by double clicking them in the list views in the Editor Versions section
- Manage Unity installs
Expand Down
26 changes: 26 additions & 0 deletions patches/wxWidgets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Local wxWidgets patches

`wxWidgets/` is a copy of the wxWidgets sources with the changes below applied on top.
When you update wxWidgets, re-apply each patch from the repository root, then check that
it is still needed:

```sh
git apply patches/wxWidgets/<name>.patch
```

Each patched spot in the wxWidgets sources is marked with a `UnityHubNative patch` comment.

## wakeuppipe-lost-wakeup.patch

Files: `src/unix/wakeuppipe.cpp`, `include/wx/unix/private/wakeuppipe.h` (macOS and Linux).

`wxWakeUpPipe::WakeUpNoLock()` wrote to the pipe and only then marked it as not empty. If the
main thread drained the pipe in between, the flag stayed "not empty" for good, and every later
wake up was skipped. Signals such as SIGCHLD wake the event loop through this pipe, so wxWidgets
stopped noticing that child processes had exited, and Unity CLI commands seemed to hang forever.

The patch makes the flag atomic, because signal handlers also call `WakeUpNoLock()`, and claims
it before writing.

Without it, asynchronous `wxExecute` calls (all Unity CLI commands, see `source/unity_cli.cpp`)
can stop reporting that they finished.
68 changes: 68 additions & 0 deletions patches/wxWidgets/wakeuppipe-lost-wakeup.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
diff --git a/wxWidgets/include/wx/unix/private/wakeuppipe.h b/wxWidgets/include/wx/unix/private/wakeuppipe.h
index d6bf4c33..db46e90e 100644
--- a/wxWidgets/include/wx/unix/private/wakeuppipe.h
+++ b/wxWidgets/include/wx/unix/private/wakeuppipe.h
@@ -13,6 +13,8 @@
#include "wx/unix/pipe.h"
#include "wx/evtloopsrc.h"

+#include <atomic>
+
// ----------------------------------------------------------------------------
// wxWakeUpPipe: allows to wake up the event loop by writing to it
// ----------------------------------------------------------------------------
@@ -51,11 +53,20 @@ public:
private:
wxPipe m_pipe;

- // This flag is set to true after writing to the pipe and reset to false
+ // UnityHubNative patch (see patches/wxWidgets/README.md): made atomic and
+ // cleared before writing, to fix a lost wake up.
+ //
+ // This flag is set to false before writing to the pipe and reset to true
// after reading from it in the main thread. Having it allows us to avoid
// overflowing the pipe with too many writes if the main thread can't keep
// up with reading from it.
- bool m_pipeIsEmpty;
+ //
+ // It is atomic because WakeUpNoLock() is also called from signal handlers,
+ // which can run on any thread, concurrently with OnReadWaiting(). It must
+ // be cleared before writing: clearing it after the write let the main
+ // thread drain the pipe in between, leaving the flag wrongly false for good,
+ // so that no later wake up (e.g. SIGCHLD) was ever written to the pipe.
+ std::atomic<bool> m_pipeIsEmpty;
};

// ----------------------------------------------------------------------------
diff --git a/wxWidgets/src/unix/wakeuppipe.cpp b/wxWidgets/src/unix/wakeuppipe.cpp
index d3af838f..b6bddfab 100644
--- a/wxWidgets/src/unix/wakeuppipe.cpp
+++ b/wxWidgets/src/unix/wakeuppipe.cpp
@@ -67,8 +67,10 @@ wxWakeUpPipe::wxWakeUpPipe()

void wxWakeUpPipe::WakeUpNoLock()
{
- // No need to do anything if the pipe already contains something.
- if ( !m_pipeIsEmpty )
+ // UnityHubNative patch (see patches/wxWidgets/README.md): fixes a lost wake up
+ // No need to do anything if the pipe already contains something. Claim the
+ // right to write before writing, see the comment on m_pipeIsEmpty.
+ if ( !m_pipeIsEmpty.exchange(false) )
return;

if ( write(m_pipe[wxPipe::Write], "s", 1) != 1 )
@@ -76,11 +78,9 @@ void wxWakeUpPipe::WakeUpNoLock()
// don't use wxLog here, we can be in another thread and this could
// result in dead locks
perror("write(wake up pipe)");
- }
- else
- {
- // We just wrote to it, so it's not empty any more.
- m_pipeIsEmpty = false;
+
+ // Nothing was written, so allow trying again.
+ m_pipeIsEmpty = true;
}
}

35 changes: 3 additions & 32 deletions source/create_dialog_derived.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,7 @@ void CreateProjectDialogD::OnCreate(wxCommandEvent& event){
if (message == ""){


//assemble the command that will create the project described by the dialog

editor& e = editors[GetSelectedEditorIndex()];
auto executablePath = e.executablePath();
auto executableTemplatesPath = e.templatePath();
string projName = projNameTxt->GetValue().ToStdString();
string projPath = projLocTxt->GetValue().ToStdString();

Expand All @@ -95,35 +91,10 @@ void CreateProjectDialogD::OnCreate(wxCommandEvent& event){
if (itemIndex > -1){
templateName = templateCtrl->GetItemText(itemIndex);
}
auto templatePath = e.templatePath() / std::format("{}.{}", templatePrefix, templateName);

//create the command string
#if defined __APPLE__
string command = std::format("\"{}\" -createProject \"{}\" -cloneFromTemplate \"{}{}.{}\"",
executablePath.string(),
outPath.string(),
executableTemplatesPath.string(),
templatePrefix,
templateName
);
#elif defined _WIN32
auto fullProj = filesystem::path(projPath) / projName;
auto fullTemplate = executableTemplatesPath / std::format("{}.{}",templatePrefix,templateName);
string command = std::format("\"{}\" -createproject \"{}\" -cloneFromTemplate \"{}\"",
executablePath.string(),
fullProj.string(),
fullTemplate.string());
#elif defined __linux__
string command = std::format("\"{}\" -createproject \"{}\" -cloneFromTemplate \"{}{}.{}\"",
executablePath.string(),
(filesystem::path(projPath) / projName).string(),
executableTemplatesPath.string(),
templatePrefix,
templateName
);
#endif
//TODO: return this command to what summoned this dialog
project p = {projName,e.name,0,filesystem::path(projPath) / filesystem::path(projName)};
this->callback(command,p);
project p = {projName,e.name,0,outPath};
this->callback(p, e, templatePath);

//close and dispose self
this->EndModal(0);
Expand Down
Loading
Loading