#include <wx/wxprec.h>
#include <wx/wx.h>
#include <wx/cmdline.h>
#include "../include/wxdragon.h"
#include <wx/app.h>
#include <wx/image.h>
#include <cstdlib>
#include <wx/private/safecall.h>
#include <wx/scopeguard.h>
#include <vector>
#include <utility>
static wxd_OnInitCallback g_OnInitCallback = nullptr;
static void* g_OnInitUserData = nullptr;
extern "C" int
process_rust_callbacks();
class WxdApp : public wxApp {
public:
virtual bool
OnInit() override;
virtual void
OnInitCmdLine(wxCmdLineParser& parser) override;
virtual bool
OnCmdLineParsed(wxCmdLineParser& parser) override;
void
OnIdle(wxIdleEvent& event);
virtual int OnExit() override;
#ifdef __WXOSX__
virtual void
MacOpenFiles(const wxArrayString& fileNames) override;
virtual void
MacOpenURL(const wxString& url) override;
virtual void
MacNewFile() override;
virtual void
MacReopenApp() override;
virtual void
MacPrintFiles(const wxArrayString& fileNames) override;
struct MacCallbackList {
std::vector<std::pair<wxd_MacOpenFilesCallback, void*>> openFiles;
std::vector<std::pair<wxd_MacOpenURLCallback, void*>> openURL;
std::vector<std::pair<wxd_MacNewFileCallback, void*>> newFile;
std::vector<std::pair<wxd_MacReopenAppCallback, void*>> reopenApp;
std::vector<std::pair<wxd_MacPrintFilesCallback, void*>> printFiles;
} m_macCallbacks;
#endif
};
bool
WxdApp::OnInit()
{
if (!wxApp::OnInit()) {
return false;
}
#ifdef __WXMSW__
SetUseBestVisual(true);
#endif
wxInitializeStockLists();
Bind(wxEVT_IDLE, &WxdApp::OnIdle, this);
if (g_OnInitCallback) {
bool success = g_OnInitCallback(g_OnInitUserData);
return success;
}
else {
WXD_LOG_ERROR("wxDragon: No OnInit callback provided to wxd_Main.");
return false;
}
}
void
WxdApp::OnIdle(wxIdleEvent& event)
{
int callbacks_processed = process_rust_callbacks();
if (callbacks_processed > 0) {
event.RequestMore();
}
}
int
WxdApp::OnExit()
{
wxd_IPC_CleanupAll();
return wxApp::OnExit();
}
void
WxdApp::OnInitCmdLine(wxCmdLineParser& parser)
{
wxApp::OnInitCmdLine(parser);
parser.EnableLongOptions(false);
parser.SetSwitchChars("");
static const wxCmdLineEntryDesc cmdLineDesc[] = {
{ wxCMD_LINE_PARAM, nullptr, nullptr, "arg", wxCMD_LINE_VAL_STRING,
wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
};
parser.SetDesc(cmdLineDesc);
}
bool
WxdApp::OnCmdLineParsed(wxCmdLineParser& parser)
{
return true;
}
wxDECLARE_APP(WxdApp);
wxIMPLEMENT_APP_NO_MAIN(WxdApp);
int
wxd_Main(int argc, char** argv, wxd_OnInitCallback on_init_cb, void* userData)
{
if (!on_init_cb) {
fprintf(stderr, "wxDragon Error: No OnInit callback provided to wxd_Main.\n");
return 1;
}
g_OnInitCallback = on_init_cb;
g_OnInitUserData = userData;
if (!wxEntryStart(argc, argv)) {
fprintf(stderr, "wxDragon Error: Failed to initialize wxWidgets (wxEntryStart failed).\n");
return 1;
}
wxInitAllImageHandlers();
int result = wxSafeCall<int>(
[]() {
if (wxTheApp == nullptr) {
fprintf(stderr, "wxDragon Error: wxTheApp is null after wxEntryStart.\n");
return wxApp::GetFatalErrorExitCode();
}
if (!wxTheApp->CallOnInit()) {
return wxTheApp->GetErrorExitCode();
}
wxON_BLOCK_EXIT_OBJ0(*wxTheApp, wxApp::OnExit);
return wxTheApp->OnRun();
},
[]() {
wxApp::CallOnUnhandledException();
return wxApp::GetFatalErrorExitCode();
});
wxEntryCleanup();
g_OnInitCallback = nullptr;
g_OnInitUserData = nullptr;
return result;
}
wxd_App_t*
wxd_GetApp()
{
return reinterpret_cast<wxd_App_t*>(wxTheApp);
}
void
wxd_App_SetTopWindow(wxd_App_t* app, wxd_Window_t* window)
{
if (!app || !window)
return;
WxdApp* wx_app = reinterpret_cast<WxdApp*>(app);
wxWindow* wx_window = reinterpret_cast<wxWindow*>(window);
wx_app->SetTopWindow(wx_window);
}
wxd_Window_t*
wxd_App_GetTopWindow(wxd_App_t* app)
{
if (!app)
return nullptr;
wxApp* wx_app = reinterpret_cast<wxApp*>(app);
return reinterpret_cast<wxd_Window_t*>(wx_app->GetTopWindow());
}
bool
wxd_App_IsMainLoopRunning(wxd_App_t* app)
{
if (!app)
return false;
return wxApp::IsMainLoopRunning();
}
void
wxd_App_ExitMainLoop(wxd_App_t* app)
{
if (!app)
return;
wxApp* wx_app = reinterpret_cast<wxApp*>(app);
wx_app->ExitMainLoop();
}
bool
wxd_App_GetExitOnFrameDelete(wxd_App_t* app)
{
if (!app)
return true;
wxApp* wx_app = reinterpret_cast<wxApp*>(app);
return wx_app->GetExitOnFrameDelete();
}
void
wxd_App_SetExitOnFrameDelete(wxd_App_t* app, bool exitOnFrameDelete)
{
if (!app)
return;
wxApp* wx_app = reinterpret_cast<wxApp*>(app);
wx_app->SetExitOnFrameDelete(exitOnFrameDelete);
}
void
wxd_App_SetAppName(wxd_App_t* app, const char* name)
{
if (!app || !name)
return;
wxApp* wx_app = reinterpret_cast<wxApp*>(app);
wx_app->SetAppName(wxString::FromUTF8(name));
}
int
wxd_App_GetAppName(const wxd_App_t* app, char* out, size_t out_len)
{
if (!app)
return -1;
const wxApp* wx_app = reinterpret_cast<const wxApp*>(app);
return static_cast<int>(wxd_cpp_utils::copy_wxstring_to_buffer(wx_app->GetAppName(), out, out_len));
}
void
wxd_App_SetAppDisplayName(wxd_App_t* app, const char* name)
{
if (!app || !name)
return;
wxApp* wx_app = reinterpret_cast<wxApp*>(app);
wx_app->SetAppDisplayName(wxString::FromUTF8(name));
}
int
wxd_App_GetAppDisplayName(const wxd_App_t* app, char* out, size_t out_len)
{
if (!app)
return -1;
const wxApp* wx_app = reinterpret_cast<const wxApp*>(app);
return static_cast<int>(wxd_cpp_utils::copy_wxstring_to_buffer(wx_app->GetAppDisplayName(), out, out_len));
}
void
wxd_App_SetVendorName(wxd_App_t* app, const char* name)
{
if (!app || !name)
return;
wxApp* wx_app = reinterpret_cast<wxApp*>(app);
wx_app->SetVendorName(wxString::FromUTF8(name));
}
int
wxd_App_GetVendorName(const wxd_App_t* app, char* out, size_t out_len)
{
if (!app)
return -1;
const wxApp* wx_app = reinterpret_cast<const wxApp*>(app);
return static_cast<int>(wxd_cpp_utils::copy_wxstring_to_buffer(wx_app->GetVendorName(), out, out_len));
}
void
wxd_App_SetVendorDisplayName(wxd_App_t* app, const char* name)
{
if (!app || !name)
return;
wxApp* wx_app = reinterpret_cast<wxApp*>(app);
wx_app->SetVendorDisplayName(wxString::FromUTF8(name));
}
int
wxd_App_GetVendorDisplayName(const wxd_App_t* app, char* out, size_t out_len)
{
if (!app)
return -1;
const wxApp* wx_app = reinterpret_cast<const wxApp*>(app);
return static_cast<int>(wxd_cpp_utils::copy_wxstring_to_buffer(wx_app->GetVendorDisplayName(), out, out_len));
}
void
wxd_App_ProcessCallbacks()
{
process_rust_callbacks();
}
void
wxd_free_int_array(int* ptr)
{
if (ptr) {
free(ptr);
}
}
#if wxCHECK_VERSION(3, 3, 0)
#include <wx/settings.h>
#include <wx/systhemectrl.h>
#endif
wxd_AppearanceResult
wxd_App_SetAppearance(wxd_App_t* app, wxd_Appearance appearance)
{
if (!app)
return WXD_APPEARANCE_RESULT_FAILURE;
#if wxCHECK_VERSION(3, 3, 0)
wxApp* wx_app = reinterpret_cast<wxApp*>(app);
wxApp::Appearance wx_appearance;
switch (appearance) {
case WXD_APPEARANCE_LIGHT:
wx_appearance = wxApp::Appearance::Light;
break;
case WXD_APPEARANCE_DARK:
wx_appearance = wxApp::Appearance::Dark;
break;
case WXD_APPEARANCE_SYSTEM:
default:
wx_appearance = wxApp::Appearance::System;
break;
}
wxApp::AppearanceResult result = wx_app->SetAppearance(wx_appearance);
switch (result) {
case wxApp::AppearanceResult::Ok:
return WXD_APPEARANCE_RESULT_OK;
case wxApp::AppearanceResult::Failure:
return WXD_APPEARANCE_RESULT_FAILURE;
case wxApp::AppearanceResult::CannotChange:
return WXD_APPEARANCE_RESULT_CANNOT_CHANGE;
}
return WXD_APPEARANCE_RESULT_FAILURE;
#else
return WXD_APPEARANCE_RESULT_FAILURE;
#endif
}
wxd_SystemAppearance_t*
wxd_SystemSettings_GetAppearance()
{
#if wxCHECK_VERSION(3, 3, 0)
wxSystemAppearance appearance = wxSystemSettings::GetAppearance();
wxSystemAppearance* heap_appearance = new wxSystemAppearance(appearance);
return reinterpret_cast<wxd_SystemAppearance_t*>(heap_appearance);
#else
return nullptr;
#endif
}
bool
wxd_SystemAppearance_IsDark(wxd_SystemAppearance_t* appearance)
{
if (!appearance)
return false;
#if wxCHECK_VERSION(3, 3, 0)
wxSystemAppearance* wx_appearance = reinterpret_cast<wxSystemAppearance*>(appearance);
return wx_appearance->IsDark();
#else
return false;
#endif
}
bool
wxd_SystemAppearance_IsUsingDarkBackground(wxd_SystemAppearance_t* appearance)
{
if (!appearance)
return false;
#if wxCHECK_VERSION(3, 3, 0)
wxSystemAppearance* wx_appearance = reinterpret_cast<wxSystemAppearance*>(appearance);
return wx_appearance->IsUsingDarkBackground();
#else
return false;
#endif
}
WXD_EXPORTED int
wxd_SystemAppearance_GetName(const wxd_SystemAppearance_t* appearance, char* out, size_t out_len)
{
if (!appearance)
return -1;
#if wxCHECK_VERSION(3, 3, 0)
const wxSystemAppearance* a = reinterpret_cast<const wxSystemAppearance*>(appearance);
wxString name = a->GetName();
return (int)wxd_cpp_utils::copy_wxstring_to_buffer(name, out, out_len);
#endif
return -1;
}
void
wxd_SystemAppearance_Destroy(wxd_SystemAppearance_t* appearance)
{
if (!appearance)
return;
#if wxCHECK_VERSION(3, 3, 0)
wxSystemAppearance* wx_appearance = reinterpret_cast<wxSystemAppearance*>(appearance);
delete wx_appearance;
#endif
}
#ifdef __WXOSX__
void
WxdApp::MacOpenFiles(const wxArrayString& fileNames)
{
if (m_macCallbacks.openFiles.empty()) {
wxApp::MacOpenFiles(fileNames);
return;
}
size_t count = fileNames.GetCount();
std::vector<std::string> strings;
std::vector<const char*> cStrings;
strings.reserve(count);
cStrings.reserve(count);
for (size_t i = 0; i < count; i++) {
strings.push_back(fileNames[i].ToStdString());
cStrings.push_back(strings.back().c_str());
}
for (const auto& pair : m_macCallbacks.openFiles) {
if (pair.first) {
pair.first(pair.second, cStrings.data(), static_cast<int>(count));
}
}
}
void
WxdApp::MacOpenURL(const wxString& url)
{
if (m_macCallbacks.openURL.empty()) {
wxApp::MacOpenURL(url);
return;
}
std::string urlStr = url.ToStdString();
for (const auto& pair : m_macCallbacks.openURL) {
if (pair.first) {
pair.first(pair.second, urlStr.c_str());
}
}
}
void
WxdApp::MacNewFile()
{
if (m_macCallbacks.newFile.empty()) {
wxApp::MacNewFile();
return;
}
for (const auto& pair : m_macCallbacks.newFile) {
if (pair.first) {
pair.first(pair.second);
}
}
}
void
WxdApp::MacReopenApp()
{
if (m_macCallbacks.reopenApp.empty()) {
wxApp::MacReopenApp();
return;
}
for (const auto& pair : m_macCallbacks.reopenApp) {
if (pair.first) {
pair.first(pair.second);
}
}
}
void
WxdApp::MacPrintFiles(const wxArrayString& fileNames)
{
if (m_macCallbacks.printFiles.empty()) {
wxApp::MacPrintFiles(fileNames);
return;
}
size_t count = fileNames.GetCount();
std::vector<std::string> strings;
std::vector<const char*> cStrings;
strings.reserve(count);
cStrings.reserve(count);
for (size_t i = 0; i < count; i++) {
strings.push_back(fileNames[i].ToStdString());
cStrings.push_back(strings.back().c_str());
}
for (const auto& pair : m_macCallbacks.printFiles) {
if (pair.first) {
pair.first(pair.second, cStrings.data(), static_cast<int>(count));
}
}
}
#endif
void
wxd_App_AddMacOpenFilesHandler(wxd_App_t* app, wxd_MacOpenFilesCallback callback, void* userData)
{
#ifdef __WXOSX__
if (!app || !callback)
return;
WxdApp* wx_app = reinterpret_cast<WxdApp*>(app);
wx_app->m_macCallbacks.openFiles.push_back(std::make_pair(callback, userData));
#endif
}
void
wxd_App_AddMacOpenURLHandler(wxd_App_t* app, wxd_MacOpenURLCallback callback, void* userData)
{
#ifdef __WXOSX__
if (!app || !callback)
return;
WxdApp* wx_app = reinterpret_cast<WxdApp*>(app);
wx_app->m_macCallbacks.openURL.push_back(std::make_pair(callback, userData));
#endif
}
void
wxd_App_AddMacNewFileHandler(wxd_App_t* app, wxd_MacNewFileCallback callback, void* userData)
{
#ifdef __WXOSX__
if (!app || !callback)
return;
WxdApp* wx_app = reinterpret_cast<WxdApp*>(app);
wx_app->m_macCallbacks.newFile.push_back(std::make_pair(callback, userData));
#endif
}
void
wxd_App_AddMacReopenAppHandler(wxd_App_t* app, wxd_MacReopenAppCallback callback, void* userData)
{
#ifdef __WXOSX__
if (!app || !callback)
return;
WxdApp* wx_app = reinterpret_cast<WxdApp*>(app);
wx_app->m_macCallbacks.reopenApp.push_back(std::make_pair(callback, userData));
#endif
}
void
wxd_App_AddMacPrintFilesHandler(wxd_App_t* app, wxd_MacPrintFilesCallback callback, void* userData)
{
#ifdef __WXOSX__
if (!app || !callback)
return;
WxdApp* wx_app = reinterpret_cast<WxdApp*>(app);
wx_app->m_macCallbacks.printFiles.push_back(std::make_pair(callback, userData));
#endif
}