mirror of
https://github.com/usatiuk/dhfs.git
synced 2025-10-28 20:47:49 +01:00
Compare commits
9 Commits
fac2feb598
...
launcher
| Author | SHA1 | Date | |
|---|---|---|---|
| c941a7fd0e | |||
| 83aaaf65fa | |||
| 27cd6a339d | |||
| ef4de7fa43 | |||
| fee594b56e | |||
| f3ba0d810a | |||
| cc69874ebc | |||
| 08f61ef9e4 | |||
| 0180958621 |
@@ -1,13 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(launcher)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
enable_language(OBJC)
|
||||
enable_language(OBJCXX)
|
||||
endif ()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
# if (NOT DEFINED SANITIZE)
|
||||
# set(SANITIZE YES)
|
||||
# endif ()
|
||||
# if (NOT DEFINED SANITIZE)
|
||||
# set(SANITIZE YES)
|
||||
# endif ()
|
||||
endif ()
|
||||
|
||||
if (SANITIZE STREQUAL "YES")
|
||||
@@ -28,6 +35,8 @@ if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_link_options(-O3)
|
||||
endif ()
|
||||
|
||||
include(wxWidgets)
|
||||
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(backend)
|
||||
add_subdirectory(gui)
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
find_package(wxWidgets REQUIRED COMPONENTS base)
|
||||
if (wxWidgets_USE_FILE) # not defined in CONFIG mode
|
||||
include(${wxWidgets_USE_FILE})
|
||||
endif ()
|
||||
|
||||
add_library(backend
|
||||
src/DhfsInstance.cpp
|
||||
include_public/DhfsInstance.hpp
|
||||
|
||||
@@ -15,11 +15,15 @@
|
||||
#include "DhfsWxProcess.hpp"
|
||||
|
||||
enum class DhfsInstanceState {
|
||||
STARTING,
|
||||
RUNNING,
|
||||
STOPPING,
|
||||
STOPPED,
|
||||
};
|
||||
|
||||
class DhfsInstance {
|
||||
friend DhfsWxProcess;
|
||||
|
||||
public:
|
||||
DhfsInstance();
|
||||
|
||||
@@ -31,14 +35,16 @@ public:
|
||||
|
||||
void stop();
|
||||
|
||||
virtual void OnTerminate(int pid, int status) = 0;
|
||||
protected:
|
||||
virtual void OnStateChange() = 0;
|
||||
|
||||
virtual void OnRead(std::string s) = 0;
|
||||
|
||||
protected:
|
||||
private:
|
||||
std::unique_ptr<DhfsWxProcess> process = std::make_unique<DhfsWxProcess>(*this);
|
||||
|
||||
private:
|
||||
void OnTerminateInternal(int pid, int status);
|
||||
|
||||
DhfsInstanceState _state = DhfsInstanceState::STOPPED;
|
||||
std::thread _readThread;
|
||||
std::thread _readThreadErr;
|
||||
|
||||
@@ -25,13 +25,17 @@ void DhfsInstance::start(DhfsStartOptions options) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
switch (_state) {
|
||||
case DhfsInstanceState::RUNNING:
|
||||
case DhfsInstanceState::STARTING:
|
||||
case DhfsInstanceState::STOPPING:
|
||||
return;
|
||||
case DhfsInstanceState::STOPPED:
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown DhfsInstanceState");
|
||||
}
|
||||
_state = DhfsInstanceState::RUNNING;
|
||||
|
||||
_state = DhfsInstanceState::STARTING;
|
||||
OnStateChange();
|
||||
|
||||
std::vector<char*> args;
|
||||
auto readyOptions = options.getOptions();
|
||||
@@ -46,18 +50,36 @@ void DhfsInstance::start(DhfsStartOptions options) {
|
||||
throw Exception("Failed to start DHFS");
|
||||
}
|
||||
|
||||
OnRead("Started! " + std::to_string(ret) + " PID: " + std::to_string(process->GetPid()) + "\n");
|
||||
OnRead("Started! PID: " + std::to_string(process->GetPid()) + "\n");
|
||||
|
||||
_readThread = std::thread([&]() {
|
||||
auto stream = process->GetInputStream();
|
||||
|
||||
bool searching = true;
|
||||
std::string lastLine;
|
||||
|
||||
while (!stream->Eof() || stream->CanRead()) {
|
||||
char buffer[1024];
|
||||
size_t bytesRead = stream->Read(buffer, sizeof(buffer) - 1).LastRead();
|
||||
if (bytesRead > 0) {
|
||||
buffer[bytesRead] = '\0'; // Null-terminate the string
|
||||
buffer[bytesRead] = '\0';
|
||||
if (searching) {
|
||||
for (size_t i = 0; i < bytesRead; i++) {
|
||||
lastLine += buffer[i];
|
||||
if (buffer[i] == '\n') {
|
||||
if (lastLine.find("Listening on:") != std::string::npos) {
|
||||
searching = false;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (_state == DhfsInstanceState::STARTING) {
|
||||
_state = DhfsInstanceState::RUNNING;
|
||||
OnStateChange();
|
||||
}
|
||||
}
|
||||
lastLine = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
OnRead(std::string(buffer));
|
||||
} else if (bytesRead == 0) {
|
||||
break; // EOF reached
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -67,10 +89,8 @@ void DhfsInstance::start(DhfsStartOptions options) {
|
||||
char buffer[1024];
|
||||
size_t bytesRead = stream->Read(buffer, sizeof(buffer) - 1).LastRead();
|
||||
if (bytesRead > 0) {
|
||||
buffer[bytesRead] = '\0'; // Null-terminate the string
|
||||
buffer[bytesRead] = '\0';
|
||||
OnRead(std::string(buffer));
|
||||
} else if (bytesRead == 0) {
|
||||
break; // EOF reached
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -80,21 +100,30 @@ void DhfsInstance::stop() {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
switch (_state) {
|
||||
case DhfsInstanceState::RUNNING:
|
||||
case DhfsInstanceState::STARTING:
|
||||
break;
|
||||
case DhfsInstanceState::STOPPED:
|
||||
case DhfsInstanceState::STOPPING:
|
||||
return;
|
||||
default:
|
||||
throw std::runtime_error("Unknown DhfsInstanceState");
|
||||
}
|
||||
|
||||
_state = DhfsInstanceState::STOPPED;
|
||||
_state = DhfsInstanceState::STOPPING;
|
||||
OnStateChange();
|
||||
|
||||
int err = wxProcess::Kill(process->GetPid(), wxSIGTERM, wxKILL_CHILDREN);
|
||||
_readThread.join();
|
||||
_readThreadErr.join();
|
||||
OnRead("Stopped!\n");
|
||||
if (err != wxKILL_OK) {
|
||||
OnRead("Failed to stop DHFS: " + std::to_string(err) + "\n");
|
||||
}
|
||||
OnTerminate(0, 0);
|
||||
}
|
||||
|
||||
void DhfsInstance::OnTerminateInternal(int pid, int status) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_state = DhfsInstanceState::STOPPED;
|
||||
|
||||
_readThread.join();
|
||||
_readThreadErr.join();
|
||||
OnRead("Stopped!\n");
|
||||
OnStateChange();
|
||||
}
|
||||
|
||||
@@ -10,5 +10,5 @@ DhfsWxProcess::DhfsWxProcess(DhfsInstance& parent): wxProcess(wxPROCESS_REDIRECT
|
||||
}
|
||||
|
||||
void DhfsWxProcess::OnTerminate(int pid, int status) {
|
||||
_instance.stop();
|
||||
_instance.OnTerminateInternal(pid, status);
|
||||
}
|
||||
|
||||
26
launcher/cmake/wxWidgets.cmake
Normal file
26
launcher/cmake/wxWidgets.cmake
Normal file
@@ -0,0 +1,26 @@
|
||||
# if linux
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
option(wxWidgets_IN_TREE_BUILD "Build wxWidgets in-tree" OFF)
|
||||
else ()
|
||||
option(wxWidgets_IN_TREE_BUILD "Build wxWidgets in-tree" ON)
|
||||
endif ()
|
||||
|
||||
if (wxWidgets_IN_TREE_BUILD)
|
||||
message(STATUS "Building wxWidgets in-tree")
|
||||
include(FetchContent)
|
||||
set(wxBUILD_SHARED OFF)
|
||||
FetchContent_Declare(wx
|
||||
GIT_REPOSITORY https://github.com/wxWidgets/wxWidgets.git
|
||||
GIT_TAG v3.2.8.1
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(wx)
|
||||
set(wxWidgets_LIBRARIES wx::core wx::base wx::webview wx::net)
|
||||
else ()
|
||||
message(STATUS "Using system wxWidgets")
|
||||
find_package(wxWidgets REQUIRED COMPONENTS net core base webview)
|
||||
if (wxWidgets_USE_FILE) # not defined in CONFIG mode
|
||||
include(${wxWidgets_USE_FILE})
|
||||
endif ()
|
||||
endif ()
|
||||
@@ -1,16 +1,28 @@
|
||||
|
||||
find_package(wxWidgets REQUIRED COMPONENTS net core base webview)
|
||||
if (wxWidgets_USE_FILE) # not defined in CONFIG mode
|
||||
include(${wxWidgets_USE_FILE})
|
||||
endif ()
|
||||
|
||||
add_executable(launcher
|
||||
add_executable(DhfsLauncher
|
||||
src/LauncherApp.cpp
|
||||
src/GLauncherApp.cpp
|
||||
src/LauncherAppMainFrame.cpp
|
||||
src/DhfsGuiInstance.cpp
|
||||
src/DhfsGuiInstance.hpp
|
||||
src/DhfsWxServer.cpp
|
||||
src/DhfsWxServer.hpp
|
||||
src/DhfsWxConnection.cpp
|
||||
src/DhfsWxConnection.hpp
|
||||
)
|
||||
|
||||
target_link_libraries(launcher ${wxWidgets_LIBRARIES})
|
||||
target_link_libraries(launcher backend utils)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
target_sources(DhfsLauncher PRIVATE
|
||||
src/macos/utils.m
|
||||
src/macos/utils.h
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
||||
target_link_libraries(DhfsLauncher ${wxWidgets_LIBRARIES})
|
||||
target_link_libraries(DhfsLauncher backend utils)
|
||||
|
||||
set_target_properties(DhfsLauncher PROPERTIES
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "com.usatiuk.dhfs.launcher"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "DHFS Launcher"
|
||||
)
|
||||
@@ -6,18 +6,19 @@
|
||||
|
||||
#include "LauncherAppMainFrame.h"
|
||||
|
||||
DhfsGuiInstance::DhfsGuiInstance(LauncherAppMainFrame& parent): _parent(parent) {
|
||||
wxDEFINE_EVENT(NEW_LINE_OUTPUT_EVENT, wxCommandEvent);
|
||||
wxDEFINE_EVENT(DHFS_STATE_CHANGE_EVENT, wxCommandEvent);
|
||||
|
||||
DhfsGuiInstance::DhfsGuiInstance(wxEvtHandler& parent): _evtHandler(parent) {
|
||||
}
|
||||
|
||||
void DhfsGuiInstance::OnTerminate(int pid, int status) {
|
||||
wxCommandEvent* event = new wxCommandEvent(SHUTDOWN_EVENT, _parent.GetId());
|
||||
event->SetEventObject(&_parent);
|
||||
_parent.GetEventHandler()->QueueEvent(event);
|
||||
void DhfsGuiInstance::OnStateChange() {
|
||||
wxCommandEvent* event = new wxCommandEvent(DHFS_STATE_CHANGE_EVENT);
|
||||
_evtHandler.QueueEvent(event);
|
||||
}
|
||||
|
||||
void DhfsGuiInstance::OnRead(std::string s) {
|
||||
wxCommandEvent* event = new wxCommandEvent(NEW_LINE_OUTPUT_EVENT, _parent.GetId());
|
||||
event->SetEventObject(&_parent);
|
||||
wxCommandEvent* event = new wxCommandEvent(NEW_LINE_OUTPUT_EVENT);
|
||||
event->SetString(std::move(s));
|
||||
_parent.GetEventHandler()->QueueEvent(event);
|
||||
_evtHandler.QueueEvent(event);
|
||||
}
|
||||
|
||||
@@ -6,19 +6,19 @@
|
||||
#define DHFSGUIINSTANCE_HPP
|
||||
#include "DhfsInstance.hpp"
|
||||
|
||||
|
||||
class LauncherAppMainFrame;
|
||||
wxDECLARE_EVENT(NEW_LINE_OUTPUT_EVENT, wxCommandEvent);
|
||||
wxDECLARE_EVENT(DHFS_STATE_CHANGE_EVENT, wxCommandEvent);
|
||||
|
||||
class DhfsGuiInstance : public DhfsInstance {
|
||||
public:
|
||||
DhfsGuiInstance(LauncherAppMainFrame& parent);
|
||||
DhfsGuiInstance(wxEvtHandler& parent);
|
||||
|
||||
void OnTerminate(int pid, int status) override;
|
||||
void OnStateChange() override;
|
||||
|
||||
void OnRead(std::string s) override;
|
||||
|
||||
protected:
|
||||
LauncherAppMainFrame& _parent;
|
||||
wxEvtHandler& _evtHandler;
|
||||
};
|
||||
|
||||
|
||||
|
||||
21
launcher/gui/src/DhfsWxConnection.cpp
Normal file
21
launcher/gui/src/DhfsWxConnection.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 29.06.2025.
|
||||
//
|
||||
|
||||
#include "DhfsWxConnection.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "wx/app.h"
|
||||
#include "LauncherApp.h"
|
||||
|
||||
DhfsWxConnection::DhfsWxConnection() : wxConnection() {
|
||||
}
|
||||
|
||||
bool DhfsWxConnection::OnExec(const wxString& wx_uni_char_refs, const wxString& wx_uni_chars) {
|
||||
std::cout << "DhfsWxConnection::OnExec called with topic: " << wx_uni_char_refs << " and item: " << wx_uni_chars <<
|
||||
std::endl;
|
||||
|
||||
wxGetApp().Open();
|
||||
return true;
|
||||
}
|
||||
18
launcher/gui/src/DhfsWxConnection.hpp
Normal file
18
launcher/gui/src/DhfsWxConnection.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 29.06.2025.
|
||||
//
|
||||
|
||||
#ifndef DHFSWXCONNECTION_HPP
|
||||
#define DHFSWXCONNECTION_HPP
|
||||
#include "wx/ipc.h"
|
||||
|
||||
|
||||
class DhfsWxConnection : public wxConnection {
|
||||
public:
|
||||
DhfsWxConnection();
|
||||
|
||||
bool OnExec(const wxString&, const wxString&) override;
|
||||
};
|
||||
|
||||
|
||||
#endif //DHFSWXCONNECTION_HPP
|
||||
11
launcher/gui/src/DhfsWxServer.cpp
Normal file
11
launcher/gui/src/DhfsWxServer.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 29.06.2025.
|
||||
//
|
||||
|
||||
#include "DhfsWxServer.hpp"
|
||||
|
||||
#include "DhfsWxConnection.hpp"
|
||||
|
||||
wxConnectionBase* DhfsWxServer::OnAcceptConnection(const wxString& topic) {
|
||||
return new DhfsWxConnection();
|
||||
}
|
||||
16
launcher/gui/src/DhfsWxServer.hpp
Normal file
16
launcher/gui/src/DhfsWxServer.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 29.06.2025.
|
||||
//
|
||||
|
||||
#ifndef DHFSWXSERVER_HPP
|
||||
#define DHFSWXSERVER_HPP
|
||||
|
||||
#include "wx/ipc.h"
|
||||
|
||||
class DhfsWxServer : public wxServer {
|
||||
public:
|
||||
wxConnectionBase* OnAcceptConnection(const wxString& topic) override;
|
||||
};
|
||||
|
||||
|
||||
#endif //DHFSWXSERVER_HPP
|
||||
@@ -137,9 +137,9 @@ MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, co
|
||||
m_panel4 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
m_notebook1->AddPage( m_panel4, _("Advanced Settings"), false );
|
||||
m_panel5 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
m_notebook1->AddPage( m_panel5, _("a page"), false );
|
||||
m_notebook1->AddPage( m_panel5, _("Web UI"), false );
|
||||
|
||||
bSizer3->Add( m_notebook1, 1, wxEXPAND, 5 );
|
||||
bSizer3->Add( m_notebook1, 1, wxBOTTOM|wxEXPAND|wxTOP, 5 );
|
||||
|
||||
|
||||
this->SetSizer( bSizer3 );
|
||||
@@ -148,6 +148,9 @@ MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, co
|
||||
this->Centre( wxBOTH );
|
||||
|
||||
// Connect Events
|
||||
this->Connect( wxEVT_ACTIVATE, wxActivateEventHandler( MainFrame::OnActivate ) );
|
||||
this->Connect( wxEVT_ACTIVATE_APP, wxActivateEventHandler( MainFrame::OnActivateApp ) );
|
||||
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainFrame::OnClose ) );
|
||||
m_notebook1->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( MainFrame::OnNotebookPageChanged ), NULL, this );
|
||||
m_notebook1->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, wxNotebookEventHandler( MainFrame::OnNotebookPageChanging ), NULL, this );
|
||||
m_startStopButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::OnStartStopButtonClick ), NULL, this );
|
||||
|
||||
@@ -59,6 +59,9 @@ class MainFrame : public wxFrame
|
||||
wxPanel* m_panel5;
|
||||
|
||||
// Virtual event handlers, override them in your derived class
|
||||
virtual void OnActivate( wxActivateEvent& event ) { event.Skip(); }
|
||||
virtual void OnActivateApp( wxActivateEvent& event ) { event.Skip(); }
|
||||
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
|
||||
virtual void OnNotebookPageChanged( wxNotebookEvent& event ) { event.Skip(); }
|
||||
virtual void OnNotebookPageChanging( wxNotebookEvent& event ) { event.Skip(); }
|
||||
virtual void OnStartStopButtonClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
|
||||
@@ -2,34 +2,62 @@
|
||||
// Created by Stepan Usatiuk on 11.07.2024.
|
||||
//
|
||||
|
||||
// For compilers that don't support precompilation, include "wx/wx.h"
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
# include "wx/wx.h"
|
||||
#endif
|
||||
|
||||
#include "wx/notebook.h"
|
||||
|
||||
#include "LauncherApp.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "LauncherAppMainFrame.h"
|
||||
#include "wx/taskbar.h"
|
||||
#include <wx/fileconf.h>
|
||||
#include <wx/stdpaths.h>
|
||||
|
||||
#include "wx/snglinst.h"
|
||||
|
||||
IMPLEMENT_APP(LauncherApp)
|
||||
|
||||
static std::string getServerSocket() {
|
||||
#ifdef __WIN32__
|
||||
return "dhfs-sock-" + wxGetUserId().ToStdString();
|
||||
#else
|
||||
return wxStandardPaths::Get().GetUserLocalDataDir().ToStdString()
|
||||
+ "/" + "dhfs-sock-" + wxGetUserId().ToStdString();
|
||||
#endif
|
||||
}
|
||||
|
||||
// This is executed upon startup, like 'main()' in non-wxWidgets programs.
|
||||
bool LauncherApp::OnInit() {
|
||||
wxFileConfig::Get()->SetAppName("DHFS");
|
||||
m_checker = new wxSingleInstanceChecker;
|
||||
if (!std::filesystem::is_directory(wxStandardPaths::Get().GetUserLocalDataDir().ToStdString())
|
||||
&& !std::filesystem::create_directories(wxStandardPaths::Get().GetUserLocalDataDir().ToStdString())) {
|
||||
wxLogError("Couldn't create data directory: %s", wxStandardPaths::Get().GetUserLocalDataDir());
|
||||
return false;
|
||||
}
|
||||
if (m_checker->IsAnotherRunning()) {
|
||||
// wxLogError(_("Another program instance is already running, aborting."));
|
||||
|
||||
delete m_checker; // OnExit() won't be called if we return false
|
||||
m_checker = NULL;
|
||||
|
||||
auto clinet = new wxClient();
|
||||
auto conn = clinet->MakeConnection("dhfs", getServerSocket(), "dhfs");
|
||||
conn->Execute("wakeup");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_server.Create(getServerSocket())) {
|
||||
wxLogError("Couldn't create server!");
|
||||
return false;
|
||||
}
|
||||
|
||||
wxFrame* frame = new LauncherAppMainFrame(NULL);
|
||||
frame->Show(true);
|
||||
SetTopWindow(frame);
|
||||
|
||||
// wxTaskBarIcon* tb = new wxTaskBarIcon();
|
||||
// auto img = new wxImage(32, 32, false);
|
||||
// img->Clear(128);
|
||||
// tb->SetIcon(*(new wxBitmapBundle(*(new wxBitmap(*img)))), "e");
|
||||
Bind(NEW_LINE_OUTPUT_EVENT, &LauncherApp::forwardEventToTopWindow, this);
|
||||
Bind(DHFS_STATE_CHANGE_EVENT, &LauncherApp::forwardEventToTopWindow, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -42,3 +70,41 @@ bool LauncherApp::OnExceptionInMainLoop() {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int LauncherApp::OnExit() {
|
||||
delete m_checker;
|
||||
|
||||
return wxApp::OnExit();
|
||||
}
|
||||
|
||||
void LauncherApp::Open() {
|
||||
if (m_topWindow) {
|
||||
m_topWindow->SetFocus();
|
||||
m_topWindow->Raise();
|
||||
if (auto frame = dynamic_cast<wxFrame*>(m_topWindow)) {
|
||||
frame->RequestUserAttention();
|
||||
}
|
||||
} else {
|
||||
wxFrame* frame = new LauncherAppMainFrame(NULL);
|
||||
frame->Show(true);
|
||||
SetTopWindow(frame);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherApp::OnTopFrameClose(wxCloseEvent& event) {
|
||||
SetTopWindow(nullptr);
|
||||
}
|
||||
|
||||
void LauncherApp::forwardEventToTopWindow(wxCommandEvent& event) {
|
||||
if (m_topWindow) {
|
||||
m_topWindow->GetEventHandler()->ProcessEvent(event);
|
||||
} else {
|
||||
event.Skip();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
void LauncherApp::MacReopenApp() {
|
||||
this->Open();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5,13 +5,38 @@
|
||||
#ifndef HELLOWORLDAPP_H
|
||||
#define HELLOWORLDAPP_H
|
||||
|
||||
#include "DhfsGuiInstance.hpp"
|
||||
#include "wx/wx.h"
|
||||
|
||||
#include "DhfsWxServer.hpp"
|
||||
|
||||
class wxSingleInstanceChecker;
|
||||
|
||||
// The HelloWorldApp class. This class shows a window
|
||||
// containing a statusbar with the text "Hello World"
|
||||
class LauncherApp : public wxApp {
|
||||
public:
|
||||
virtual bool OnInit() override;
|
||||
|
||||
virtual int OnExit() override;
|
||||
|
||||
virtual bool OnExceptionInMainLoop() override;
|
||||
|
||||
#ifdef __APPLE__
|
||||
void MacReopenApp() override;
|
||||
#endif
|
||||
|
||||
void Open();
|
||||
|
||||
void OnTopFrameClose(wxCloseEvent& event);
|
||||
|
||||
private:
|
||||
wxSingleInstanceChecker* m_checker = nullptr;
|
||||
DhfsWxServer m_server;
|
||||
void forwardEventToTopWindow(wxCommandEvent& event);
|
||||
|
||||
public:
|
||||
DhfsGuiInstance m_dhfsInstance{*this};
|
||||
};
|
||||
|
||||
DECLARE_APP(LauncherApp)
|
||||
|
||||
@@ -2,11 +2,25 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <wx/fileconf.h>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <filesystem>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "macos/utils.h"
|
||||
#endif
|
||||
|
||||
#include "LauncherApp.h"
|
||||
#include "Exception.h"
|
||||
|
||||
wxDEFINE_EVENT(NEW_LINE_OUTPUT_EVENT, wxCommandEvent);
|
||||
wxDEFINE_EVENT(SHUTDOWN_EVENT, wxCommandEvent);
|
||||
std::string getBundlePath() {
|
||||
if (wxGetenv("DHFS_BUNDLE_PATH") == NULL)
|
||||
return std::filesystem::path(wxStandardPaths::Get().GetExecutablePath().ToStdString())
|
||||
#ifndef __APPLE__
|
||||
.parent_path()
|
||||
#endif
|
||||
.parent_path().string();
|
||||
return wxGetenv("DHFS_BUNDLE_PATH");
|
||||
}
|
||||
|
||||
LauncherAppMainFrame::LauncherAppMainFrame(wxWindow* parent)
|
||||
: MainFrame(parent) {
|
||||
@@ -20,26 +34,56 @@ LauncherAppMainFrame::LauncherAppMainFrame(wxWindow* parent)
|
||||
m_webViewSizer->Fit(m_panel5);
|
||||
|
||||
Bind(NEW_LINE_OUTPUT_EVENT, &LauncherAppMainFrame::onNewLineOutput, this);
|
||||
Bind(SHUTDOWN_EVENT, &LauncherAppMainFrame::onShutdown, this);
|
||||
Bind(DHFS_STATE_CHANGE_EVENT, &LauncherAppMainFrame::onDhfsInstanceStateChange, this);
|
||||
wxFont font = wxFont(wxSize(16, 16),
|
||||
wxFontFamily::wxFONTFAMILY_TELETYPE,
|
||||
wxFontStyle::wxFONTSTYLE_NORMAL,
|
||||
wxFontWeight::wxFONTWEIGHT_NORMAL);
|
||||
m_logOutputTextCtrl->SetFont(font);
|
||||
updateState();
|
||||
#ifdef __APPLE__
|
||||
SetAppAsRegular();
|
||||
#endif
|
||||
}
|
||||
|
||||
static DhfsInstance& getDhfsInstance() {
|
||||
return wxGetApp().m_dhfsInstance;
|
||||
}
|
||||
|
||||
void LauncherAppMainFrame::updateState() {
|
||||
switch (_dhfsInstance.state()) {
|
||||
case DhfsInstanceState::RUNNING:
|
||||
switch (getDhfsInstance().state()) {
|
||||
case DhfsInstanceState::RUNNING: {
|
||||
m_statusText->SetLabel("Running");
|
||||
m_startStopButton->SetLabel("Stop");
|
||||
m_statusBar1->SetStatusText("Running", 0);
|
||||
|
||||
if (m_notebook1->GetSelection() == 4) {
|
||||
if (m_webView != nullptr)
|
||||
m_webView->LoadURL("http://localhost:8080");
|
||||
}
|
||||
|
||||
wxGetApp().SetExitOnFrameDelete(false);
|
||||
break;
|
||||
}
|
||||
case DhfsInstanceState::STARTING: {
|
||||
m_statusText->SetLabel("Starting");
|
||||
m_startStopButton->SetLabel("Stop");
|
||||
m_statusBar1->SetStatusText("Starting", 0);
|
||||
wxGetApp().SetExitOnFrameDelete(false);
|
||||
break;
|
||||
}
|
||||
case DhfsInstanceState::STOPPED: {
|
||||
m_statusText->SetLabel("Stopped");
|
||||
m_startStopButton->SetLabel("Start");
|
||||
m_statusBar1->SetStatusText("Stopped", 0);
|
||||
wxGetApp().SetExitOnFrameDelete(true);
|
||||
break;
|
||||
}
|
||||
case DhfsInstanceState::STOPPING: {
|
||||
m_statusText->SetLabel("Stopping");
|
||||
m_startStopButton->SetLabel("Kill");
|
||||
m_statusBar1->SetStatusText("Stopping", 0);
|
||||
wxGetApp().SetExitOnFrameDelete(false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -48,21 +92,26 @@ void LauncherAppMainFrame::updateState() {
|
||||
}
|
||||
|
||||
void LauncherAppMainFrame::OnStartStopButtonClick(wxCommandEvent& event) {
|
||||
switch (_dhfsInstance.state()) {
|
||||
switch (getDhfsInstance().state()) {
|
||||
case DhfsInstanceState::RUNNING:
|
||||
_dhfsInstance.stop();
|
||||
case DhfsInstanceState::STARTING: {
|
||||
getDhfsInstance().stop();
|
||||
break;
|
||||
}
|
||||
case DhfsInstanceState::STOPPED: {
|
||||
DhfsStartOptions options;
|
||||
options.java_home = wxFileConfig::Get()->Read(kJavaHomeSettingsKey);
|
||||
options.xmx = "512m";
|
||||
options.mount_path = wxFileConfig::Get()->Read(kMountPointSettingsKey);
|
||||
options.data_path = wxFileConfig::Get()->Read(kDataDirSettingsKey);
|
||||
std::string bundlePath = wxGetenv("DHFS_BUNDLE_PATH");
|
||||
options.jar_path = bundlePath + "/app/Server/quarkus-run.jar";
|
||||
options.webui_path = bundlePath + "/app/Webui";
|
||||
options.jar_path = getBundlePath() + "/app/Server/quarkus-run.jar";
|
||||
options.webui_path = getBundlePath() + "/app/Webui";
|
||||
|
||||
_dhfsInstance.start(options);
|
||||
getDhfsInstance().start(options);
|
||||
break;
|
||||
}
|
||||
case DhfsInstanceState::STOPPING: {
|
||||
// TODO:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -88,14 +137,14 @@ void LauncherAppMainFrame::onNewLineOutput(wxCommandEvent& event) {
|
||||
}
|
||||
|
||||
void LauncherAppMainFrame::OnNotebookPageChanged(wxBookCtrlEvent& event) {
|
||||
}
|
||||
|
||||
void LauncherAppMainFrame::OnNotebookPageChanging(wxBookCtrlEvent& event) {
|
||||
if (event.GetSelection() == 4) prepareWebview();
|
||||
else unloadWebview();
|
||||
}
|
||||
|
||||
void LauncherAppMainFrame::onShutdown(wxCommandEvent& event) {
|
||||
void LauncherAppMainFrame::OnNotebookPageChanging(wxBookCtrlEvent& event) {
|
||||
}
|
||||
|
||||
void LauncherAppMainFrame::onDhfsInstanceStateChange(wxCommandEvent& event) {
|
||||
updateState();
|
||||
}
|
||||
|
||||
@@ -113,3 +162,20 @@ void LauncherAppMainFrame::prepareWebview() {
|
||||
m_webView->LoadURL("http://localhost:8080");
|
||||
m_panel5->Layout();
|
||||
}
|
||||
|
||||
|
||||
void LauncherAppMainFrame::OnActivate(wxActivateEvent& event) {
|
||||
MainFrame::OnActivate(event);
|
||||
}
|
||||
|
||||
void LauncherAppMainFrame::OnActivateApp(wxActivateEvent& event) {
|
||||
MainFrame::OnActivateApp(event);
|
||||
}
|
||||
|
||||
void LauncherAppMainFrame::OnClose(wxCloseEvent& event) {
|
||||
#ifdef __APPLE__
|
||||
SetAppAsAccessory();
|
||||
#endif
|
||||
wxGetApp().OnTopFrameClose(event);
|
||||
MainFrame::OnClose(event);
|
||||
}
|
||||
|
||||
@@ -18,9 +18,6 @@ static constexpr auto kJavaHomeSettingsKey = "DHFS/JavaHome";
|
||||
static constexpr auto kMountPointSettingsKey = "DHFS/MountDir";
|
||||
static constexpr auto kDataDirSettingsKey = "DHFS/DataDir";
|
||||
|
||||
wxDECLARE_EVENT(NEW_LINE_OUTPUT_EVENT, wxCommandEvent);
|
||||
wxDECLARE_EVENT(SHUTDOWN_EVENT, wxCommandEvent);
|
||||
|
||||
/** Implementing MainFrame */
|
||||
class LauncherAppMainFrame : public MainFrame {
|
||||
protected:
|
||||
@@ -39,13 +36,20 @@ protected:
|
||||
|
||||
void onNewLineOutput(wxCommandEvent& event);
|
||||
|
||||
void onShutdown(wxCommandEvent& event);
|
||||
void onDhfsInstanceStateChange(wxCommandEvent& event);
|
||||
|
||||
void updateState();
|
||||
|
||||
void unloadWebview();
|
||||
|
||||
void prepareWebview();
|
||||
|
||||
void OnActivate(wxActivateEvent& event) override;
|
||||
|
||||
void OnActivateApp(wxActivateEvent& event) override;
|
||||
|
||||
void OnClose(wxCloseEvent& event) override;
|
||||
|
||||
public:
|
||||
/** Constructor */
|
||||
LauncherAppMainFrame(wxWindow* parent);
|
||||
@@ -55,8 +59,6 @@ public:
|
||||
private:
|
||||
wxWebView* m_webView = nullptr;
|
||||
wxGridSizer* m_webViewSizer;
|
||||
|
||||
DhfsGuiInstance _dhfsInstance{*this};
|
||||
};
|
||||
|
||||
#endif // __LauncherAppMainFrame__
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
<property name="window_name">DHFS</property>
|
||||
<property name="window_style">wxTAB_TRAVERSAL</property>
|
||||
<property name="xrc_skip_sizer">1</property>
|
||||
<event name="OnActivate">OnActivate</event>
|
||||
<event name="OnActivateApp">OnActivateApp</event>
|
||||
<event name="OnClose">OnClose</event>
|
||||
<object class="wxStatusBar" expanded="true">
|
||||
<property name="bg"></property>
|
||||
<property name="context_help"></property>
|
||||
@@ -91,7 +94,7 @@
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="flag">wxBOTTOM|wxEXPAND|wxTOP</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxNotebook" expanded="true">
|
||||
<property name="BottomDockable">1</property>
|
||||
@@ -1211,7 +1214,7 @@
|
||||
</object>
|
||||
<object class="notebookpage" expanded="true">
|
||||
<property name="bitmap"></property>
|
||||
<property name="label">a page</property>
|
||||
<property name="label">Web UI</property>
|
||||
<property name="select">0</property>
|
||||
<object class="wxPanel" expanded="true">
|
||||
<property name="BottomDockable">1</property>
|
||||
|
||||
20
launcher/gui/src/macos/utils.h
Normal file
20
launcher/gui/src/macos/utils.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 29.06.2025.
|
||||
//
|
||||
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void SetAppAsRegular(void);
|
||||
|
||||
void SetAppAsAccessory(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //UTILS_H
|
||||
11
launcher/gui/src/macos/utils.m
Normal file
11
launcher/gui/src/macos/utils.m
Normal file
@@ -0,0 +1,11 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "utils.h"
|
||||
|
||||
void SetAppAsRegular(void) {
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
}
|
||||
|
||||
void SetAppAsAccessory(void) {
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user