diff --git a/entry/src/main/cpp/src/exe/Xournalpp-wrapper.cpp b/entry/src/main/cpp/src/exe/Xournalpp-wrapper.cpp deleted file mode 100644 index 32fd8a5..0000000 --- a/entry/src/main/cpp/src/exe/Xournalpp-wrapper.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Xournal++ - * - * The main application - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 - */ - -#include -#include -#include -#include - -#include -#include - -#ifdef _WIN32 -// clang-format off -#include -#include -// clang-format on -#endif - -#include "util/PathUtil.h" -#include "util/VersionInfo.h" -#include "util/XojMsgBox.h" -#include "util/glib_casts.h" -#include "util/gtk4_helper.h" -#include "util/raii/CStringWrapper.h" -#include "util/raii/GObjectSPtr.h" - -#include "config.h" -#include "filesystem.h" - -static constexpr const char* UI_RESOURCE = "/org/xournalpp/wrapper/ui/crashDialog.glade"; - -// See CrashHandler::emergencySave() -static constexpr const char* EMERGENCY_SAVE_MSG_REGEX = "Successfully saved document to \"(.*)\""; - -static auto escape(const std::string& str) { - return xoj::util::OwnedCString::assumeOwnership(g_uri_escape_string(str.c_str(), nullptr, true)); -} - -/// Create a URL which opens a crash report on github, pre-filled with the data we can get -static std::string makeCrashReportURL() { - // See .github/ISSUE_TEMPLATE/crash_report.yml for the keywords (id) - std::stringstream str; - str.imbue(std::locale::classic()); - - str << PROJECT_CRASHREPORT; - str << "&os=" << escape(xoj::util::getOsInfo()).get(); - -#ifdef __linux__ - auto getEnvTruncated = [](const char* var) { - if (auto* value = std::getenv(var); value) { - auto d = std::string(value); - if (d.length() > 20) { - // No control over the environment variable: limit the length - d.resize(20); - } - return d; - } else { - return std::string("unknown"); - } - }; - str << "&desktop=" << escape(getEnvTruncated("DESKTOP_SESSION") + " " + getEnvTruncated("XDG_SESSION_TYPE")).get(); - str << "&displayserver=" << escape(xoj::util::getGdkBackend()).get(); -#endif - - str << "&version=" << escape(xoj::util::getXournalppVersion()).get(); - str << ">k=" << gtk_major_version << "." << gtk_minor_version << "." << gtk_micro_version; - - return str.str(); -} - -static void activate(GtkApplication* app, std::string* str) { - xoj::util::GObjectSPtr builder(gtk_builder_new_from_resource(UI_RESOURCE), xoj::util::adopt); - auto* window = GTK_WIDGET(gtk_builder_get_object(builder.get(), "crashDialog")); - gtk_application_add_window(app, GTK_WINDOW(window)); - auto* view = GTK_TEXT_VIEW(gtk_builder_get_object(builder.get(), "textViewLog")); - gtk_text_buffer_set_text(gtk_text_view_get_buffer(view), str->data(), -1); - - auto* entry = GTK_ENTRY(gtk_builder_get_object(builder.get(), "entryPathEmergencySave")); - std::smatch res; - std::regex_search(*str, res, std::regex(EMERGENCY_SAVE_MSG_REGEX)); - if (res.empty()) { - gtk_editable_set_text(GTK_EDITABLE(entry), "FAILED"); - gtk_widget_add_css_class(GTK_WIDGET(entry), "error"); - } else { - gtk_editable_set_text(GTK_EDITABLE(entry), res[1].str().c_str()); - } - - g_signal_connect_object(gtk_builder_get_object(builder.get(), "closeBtn"), "clicked", - G_CALLBACK(+[](GtkButton* btn, gpointer w) { gtk_window_close(GTK_WINDOW(w)); }), window, - GConnectFlags(0)); - g_signal_connect_object(gtk_builder_get_object(builder.get(), "reportBtn"), "clicked", - G_CALLBACK(+[](GtkButton* btn, gpointer w) { - XojMsgBox::openURL(GTK_WINDOW(w), makeCrashReportURL().c_str()); - }), - window, GConnectFlags(0)); - gtk_window_present(GTK_WINDOW(window)); -} - -auto main(int argc, char* argv[]) -> int { - GError* err = nullptr; - std::stringstream errorlog; - errorlog.imbue(std::locale::classic()); - - auto p = [&]() { - static constexpr auto FLAGS = GSubprocessFlags(G_SUBPROCESS_FLAGS_STDOUT_PIPE -#ifdef _WIN32 // On Windows, STDERR_MERGE does not work. See https://gitlab.gnome.org/GNOME/glib/-/issues/3723 - | G_SUBPROCESS_FLAGS_STDERR_PIPE -#else - | G_SUBPROCESS_FLAGS_STDERR_MERGE -#endif - ); - - std::vector subargv; - std::cout << Util::getExePath() << std::endl; - - const std::u8string path = (Util::getExePath() / "xournalpp").u8string(); - subargv.emplace_back(char_cast(path.c_str())); // Data is owned by `path` - Do not delete it - errorlog << "Executing \"" << char_cast(path); - -#ifdef _WIN32 - std::vector utf8_args; - - LPWSTR* szArglist; - int nArgs; - szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs); - - if (szArglist != nullptr) { - // Start from 1 to skip program name - for (int i = 1; i < nArgs; i++) { - // Calculate required buffer size for UTF-8 - int size_needed = WideCharToMultiByte(CP_UTF8, 0, szArglist[i], -1, nullptr, 0, nullptr, nullptr); - if (size_needed > 0) { - std::string utf8_arg(size_needed - 1, 0); // -1 to exclude null terminator - WideCharToMultiByte(CP_UTF8, 0, szArglist[i], -1, &utf8_arg[0], size_needed, nullptr, nullptr); - utf8_args.push_back(std::move(utf8_arg)); - } - } - LocalFree(szArglist); - - // Add UTF-8 encoded arguments - for (const auto& arg: utf8_args) { - subargv.emplace_back(arg.c_str()); - errorlog << " " << arg; - } - } else { - // Fallback to original argv if CommandLineToArgvW fails - for (int i = 1; i < argc; i++) { - subargv.emplace_back(argv[i]); - errorlog << " " << argv[i]; - } - } -#else - for (int i = 1; i < argc; i++) { - subargv.emplace_back(argv[i]); - errorlog << " " << argv[i]; - } -#endif - subargv.emplace_back(nullptr); - errorlog << "\"" << std::endl; - - xoj::util::GObjectSPtr launcher(g_subprocess_launcher_new(FLAGS), xoj::util::adopt); - g_subprocess_launcher_set_environ(launcher.get(), nullptr); // Copies the host's environment - g_subprocess_launcher_setenv(launcher.get(), "G_MESSAGES_DEBUG", G_LOG_DOMAIN, false); // Print xopp debug - - return xoj::util::GObjectSPtr(g_subprocess_launcher_spawnv(launcher.get(), subargv.data(), &err), - xoj::util::adopt); - }(); - - int exitstatus = -1; - - if (err) { - printf("Failed to start\n"); - errorlog << "Failed to start: " << err->message << std::endl; - g_error_free(err); - err = nullptr; - } else { - xoj::util::OwnedCString stdoutBuffer; -#ifdef _WIN32 // On Windows, STDERR_MERGE does not work. See https://gitlab.gnome.org/GNOME/glib/-/issues/3723 - xoj::util::OwnedCString stderrBuffer; -#endif - - std::cout << "Xournal++ started with PID: " << g_subprocess_get_identifier(p.get()) << std::endl; - errorlog << "Xournal++ started with PID: " << g_subprocess_get_identifier(p.get()) << std::endl; - - g_subprocess_communicate_utf8(p.get(), nullptr, nullptr, stdoutBuffer.contentReplacer(), -#ifdef _WIN32 // On Windows, STDERR_MERGE does not work. See https://gitlab.gnome.org/GNOME/glib/-/issues/3723 - stderrBuffer.contentReplacer(), -#else - nullptr, -#endif - &err); - - if (g_subprocess_get_if_exited(p.get())) { - exitstatus = g_subprocess_get_exit_status(p.get()); - if (exitstatus == 0) [[likely]] { - std::cout << "Execution completed normally" << std::endl; - return 0; - } else { - std::cout << "Exited with error status: " << exitstatus << std::endl; - errorlog << "Exited with error status: " << exitstatus << std::endl; - } - } - if (g_subprocess_get_if_signaled(p.get())) { - auto sig = g_subprocess_get_term_sig(p.get()); - std::cout << "Crashed with signal: " << sig << std::endl; - errorlog << "Crashed with signal: " << sig << std::endl; - } - - if (err) { - errorlog << " Error: " << err->message << std::endl; - g_error_free(err); - err = nullptr; - } - - time_t lt = time(nullptr); - errorlog << " Date: " << ctime(<) << std::endl; - - errorlog << xoj::util::getVersionInfo(); - errorlog << " (The GDK backend is probably printed out below)\n"; - - errorlog << "\n*** Output: ***\n\n" << stdoutBuffer.get(); - -#ifdef _WIN32 - errorlog << "\n\n*** Cerr: ***\n\n" << stderrBuffer.get(); -#endif - } - - GtkApplication* app = gtk_application_new("com.github.xournalpp.xournalpp", G_APPLICATION_FLAGS_NONE); - g_signal_connect_data(app, "activate", xoj::util::wrap_for_g_callback_v, new std::string(errorlog.str()), - xoj::util::closure_notify_cb, GConnectFlags(0)); - - g_application_run(G_APPLICATION(app), 0, nullptr); - g_object_unref(app); - - return exitstatus; -} diff --git a/entry/src/main/cpp/src/exe/Xournalpp.cpp b/entry/src/main/cpp/src/exe/Xournalpp.cpp deleted file mode 100644 index e593fd7..0000000 --- a/entry/src/main/cpp/src/exe/Xournalpp.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Xournal++ - * - * The main application - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 - */ - -#include "control/CrashHandler.h" // for installCrashHandlers -#include "control/XournalMain.h" // for run - -#ifdef __APPLE__ -#include "osx/setup-env.h" -#endif - -#ifdef _WIN32 -#include - -#include "win32/console.h" -#endif - -auto main(int argc, char* argv[]) -> int { -#ifdef _WIN32 - // Attach to the console here. Otherwise, gspawn-win32-helper will create annoying console popups, - // e.g. in the LaTeX tool after every change in the formula - attachConsole(); -#endif - - // init crash handler - installCrashHandlers(); - -#ifdef DEV_CALL_LOG - Log::initlog(); -#endif - -#ifdef _WIN32 - // Switch to the FontConfig backend for Pango - See #3371 - _putenv_s("PANGOCAIRO_BACKEND", "fc"); -#endif - -#ifdef __APPLE__ - // Setup the environment variables, in particular so that the pixbuf loaders are found - setupEnvironment(); -#endif - - // Use this two line to test the crash handler... - // int* crash = nullptr; - // *crash = 0; - - int result = XournalMain::run(argc, argv); - -#ifdef DEV_CALL_LOG - Log::closelog(); -#endif - - return result; -} diff --git a/entry/src/main/cpp/src/exe/osx/setup-env.cpp b/entry/src/main/cpp/src/exe/osx/setup-env.cpp deleted file mode 100644 index 52fda9b..0000000 --- a/entry/src/main/cpp/src/exe/osx/setup-env.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "setup-env.h" - -#include - -#include -#include -#include - -#include "util/PathUtil.h" - -#include "filesystem.h" - -namespace { -void prependPathToEnvVar(const char* name, fs::path const& path) { - const char* currentVal = g_getenv(name); - std::string newVar; - if (currentVal == nullptr || strlen(currentVal) == 0) { - newVar = path.string(); - } else { - newVar = path.string() + ":" + currentVal; - } - g_setenv(name, newVar.c_str(), 1); -} - -void prependPathToLua(const char* name, const std::string& path) { - const char* currentVal = g_getenv(name); - std::string newVar; - if (currentVal == nullptr || strlen(currentVal) == 0) { - newVar = std::string(Util::toGFilename(path).c_str()) + ";;"; - } else { - newVar = std::string(Util::toGFilename(path).c_str()) + ";" + currentVal; - } - g_setenv(name, newVar.c_str(), true); -} -} // end namespace - -void setupEnvironment() { - /** - * see https://gitlab.gnome.org/GNOME/gtk-mac-bundler/-/blob/master/examples/gtk3-launcher.sh - * and https://gitlab.gnome.org/GNOME/gtk-mac-bundler/-/issues/12 - */ - auto base = Util::getExePath().parent_path(); // Xournal++.app/Contents or $HOME/gtk/inst or e.g. build/inst (via - // Homebrew or MacPorts) - - std::error_code err; - bool isAppBundle = fs::exists(base / "Resources", err); - if (err) { - g_warning("Failed to determine if the app runs as an app bundle: %s", err.message().c_str()); - } - bool underJHBuild = g_strcmp0(g_getenv("UNDER_JHBUILD"), "true") == 0; - - if (isAppBundle) { - base = base / "Resources"; // Now base is Xournal++.app/Contents/Resources - } - - auto libPath = base / "lib"; - auto dataPath = base / "share"; - - if (isAppBundle) { - // Set poppler data directory for (relocatable) app bundles. Otherwise a compile time value is used. - auto popplerDataDir = dataPath / "poppler"; - poppler::set_data_dir(popplerDataDir.string().c_str()); - - auto imModuleFile = libPath / "gtk-3.0" / "3.0.0" / "immodules.cache"; - auto pixbufModuleFile = libPath / "gdk-pixbuf-2.0" / "2.10.0" / "loaders.cache"; - - auto typelibPath = libPath / "girepository-1.0"; - auto xdgPath = base / "etc" / "xdg"; - - prependPathToEnvVar("XDG_CONFIG_DIRS", xdgPath); - prependPathToEnvVar("XDG_DATA_DIRS", dataPath); - g_setenv("GTK_DATA_PREFIX", Util::toGFilename(base).c_str(), 1); - g_setenv("GTK_EXE_PREFIX", Util::toGFilename(base).c_str(), 1); - g_setenv("GTK_PATH", Util::toGFilename(base).c_str(), 1); - - g_setenv("GTK_IM_MODULE_FILE", Util::toGFilename(imModuleFile).c_str(), 0); - g_setenv("GDK_PIXBUF_MODULE_FILE", Util::toGFilename(pixbufModuleFile).c_str(), 0); - - g_setenv("GI_TYPELIB_PATH", Util::toGFilename(typelibPath).c_str(), 0); - } - - if (isAppBundle || underJHBuild) { // in both cases we have non-standard paths for Lua - std::string luaPath = std::string(Util::toGFilename(dataPath).c_str()) + "/lua/5.4/?.lua"; - std::string luaCPath = std::string(Util::toGFilename(libPath).c_str()) + "/lua/5.4/?.so"; - - prependPathToLua("LUA_PATH", luaPath); - prependPathToLua("LUA_CPATH", luaCPath); - } - - const char* usedPixbufModuleFile = g_getenv("GDK_PIXBUF_MODULE_FILE"); - const char* usedXDGDataDirs = g_getenv("XDG_DATA_DIRS"); - const char* usedTypelibPath = g_getenv("GI_TYPELIB_PATH"); - // The DYLD_LIBRARY_PATH is only read when the process is started, so it can't be set here. It is set in - // the Info.plist therefore, which only takes effect when running the App from Finder or using the "open" command. - const char* usedDYLDLibraryPath = g_getenv("DYLD_LIBRARY_PATH"); - const char* usedLuaPath = g_getenv("LUA_PATH"); - const char* usedLuaCPath = g_getenv("LUA_CPATH"); - g_debug("Continue with:\n" - "GDK_PIXBUF_MODULE_FILE = %s\n" - "XDG_DATA_DIRS = %s\n" - "GI_TYPELIB_PATH = %s\n" - "DYLD_LIBRARY_PATH = %s\n" - "LUA_PATH = %s\n" - "LUA_CPATH = %s", - usedPixbufModuleFile, usedXDGDataDirs, usedTypelibPath, usedDYLDLibraryPath, usedLuaPath, usedLuaCPath); - - /** - * set LANG and LC_MESSAGES in order to detect the default language - * Use the equivalent of 'defaults read -g "AppleLanguages"' executed in the terminal, also visible in System - * settings -> Language and Region - */ - CFArrayRef languages = - (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); - if (languages && CFArrayGetCount(languages)) { - CFStringRef langCode = (CFStringRef)CFArrayGetValueAtIndex(languages, 0); - if (langCode) { - char buffer[128]; - if (CFStringGetCString(langCode, buffer, sizeof(buffer), kCFStringEncodingUTF8)) { - std::string lang = buffer; // e.g. "de-DE" - if (auto pos = lang.find("-"); pos != std::string::npos) { - lang.replace(pos, 1, "_"); // e.g. "de_DE" - } - lang += ".UTF-8"; // e.g. "de_DE.UTF-8" - g_message("Setting LANG and LC_MESSAGES to %s", lang.c_str()); - g_setenv("LANG", lang.c_str(), 0); - g_setenv("LC_MESSAGES", lang.c_str(), 0); - } - } - } -} diff --git a/entry/src/main/cpp/src/exe/osx/setup-env.h b/entry/src/main/cpp/src/exe/osx/setup-env.h deleted file mode 100644 index f2a897c..0000000 --- a/entry/src/main/cpp/src/exe/osx/setup-env.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -/** - * Sets up all environment variables. - */ -void setupEnvironment(); diff --git a/entry/src/main/cpp/src/exe/win32/console.cpp b/entry/src/main/cpp/src/exe/win32/console.cpp deleted file mode 100644 index 620d6e1..0000000 --- a/entry/src/main/cpp/src/exe/win32/console.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "console.h" - -#include - -void attachConsole() { - if (GetConsoleWindow() != NULL) { - // Console is already attached. - return; - } - - // Make sure the console starts hidden. - STARTUPINFOW startupInfo = {0}; - startupInfo.dwFlags = STARTF_USESHOWWINDOW; - startupInfo.wShowWindow = SW_HIDE; - startupInfo.cb = sizeof(startupInfo); - - PROCESS_INFORMATION processInformation = {0}; - - bool consoleAttached = false; - - if (CreateProcessW(L"C:\\Windows\\System32\\cmd.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, - &processInformation)) { - HANDLE job = CreateJobObject(NULL, NULL); - - if (job != NULL) { - // Terminate the console process automatically when Xournal++ exits. - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInformation = {0}; - jobInformation.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - - if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &jobInformation, - sizeof(jobInformation)) || - !AssignProcessToJobObject(job, processInformation.hProcess)) { - TerminateProcess(processInformation.hProcess, 0); - CloseHandle(processInformation.hProcess); - CloseHandle(processInformation.hThread); - CloseHandle(job); - processInformation.hProcess = processInformation.hThread = job = NULL; - } else { - // It takes a short time before the console becomes ready to be attached, unfortunately - // there is no API that would let us wait for it. - for (unsigned short i = 0; i < 20; i++) { - if (AttachConsole(processInformation.dwProcessId)) { - consoleAttached = true; - break; - } - Sleep(50); - } - } - } else { - TerminateProcess(processInformation.hProcess, 0); - CloseHandle(processInformation.hProcess); - CloseHandle(processInformation.hThread); - processInformation.hProcess = processInformation.hThread = NULL; - } - - if (processInformation.hProcess != NULL) { - if (!consoleAttached) { - TerminateProcess(processInformation.hProcess, 0); - CloseHandle(job); - } - - CloseHandle(processInformation.hProcess); - CloseHandle(processInformation.hThread); - } - } - - if (!consoleAttached) { - // Could not attach to the manually created console process, request one from the system instead. - // This will make the console window flash briefly before we hide it. - AllocConsole(); - ShowWindow(GetConsoleWindow(), SW_HIDE); - } -} diff --git a/entry/src/main/cpp/src/exe/win32/console.h b/entry/src/main/cpp/src/exe/win32/console.h deleted file mode 100644 index 83b7601..0000000 --- a/entry/src/main/cpp/src/exe/win32/console.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -/** - * Allocates a new (hidden) console and associates the standard input and output handles with it. - */ -void attachConsole(); diff --git a/entry/src/main/cpp/src/exe/win32/gui_main.cpp b/entry/src/main/cpp/src/exe/win32/gui_main.cpp deleted file mode 100644 index 668c257..0000000 --- a/entry/src/main/cpp/src/exe/win32/gui_main.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Only for Windows GUI applications, compiled with MSVC. -#ifdef _MSC_VER - -#include - -#include -#include - -auto main(int argc, char* argv[]) -> int; - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) { - // Call main: - return main(__argc, __argv); -} - -#endif diff --git a/entry/src/main/cpp/src/exe/win32/xpp.rc.in b/entry/src/main/cpp/src/exe/win32/xpp.rc.in deleted file mode 100644 index f8667bf..0000000 --- a/entry/src/main/cpp/src/exe/win32/xpp.rc.in +++ /dev/null @@ -1,31 +0,0 @@ -#include "winver.h" - -0 ICON "xournalpp.ico" - -VS_VERSION_INFO VERSIONINFO -FILEVERSION ${PROJECT_VERSION_MAJOR}, ${PROJECT_VERSION_MINOR}, ${PROJECT_VERSION_PATCH}, 0 -PRODUCTVERSION ${PROJECT_VERSION_MAJOR}, ${PROJECT_VERSION_MINOR}, ${PROJECT_VERSION_PATCH}, 0 -FILEOS VOS__WINDOWS32 -FILETYPE VFT_APP -BEGIN - BLOCK "StringFileInfo" - BEGIN - /* Lang = US English, Charset = Multilingual */ - BLOCK "040904E4" - BEGIN - VALUE "CompanyName", "The Xournal++ Team\0" - VALUE "FileDescription", "Xournal++\0" - VALUE "FileVersion", "${PROJECT_VERSION}\0" - VALUE "ProductVersion", "${PROJECT_VERSION}\0" - VALUE "ProductName", "Xournal++\0" - VALUE "LegalCopyright", "\0" - VALUE "LegalTrademarks", "\0" - VALUE "Comments", "\0" - END - END - - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END \ No newline at end of file diff --git a/entry/src/main/cpp/src/exe/xournalpp-wrapper.gresource.xml b/entry/src/main/cpp/src/exe/xournalpp-wrapper.gresource.xml deleted file mode 100644 index 749fe97..0000000 --- a/entry/src/main/cpp/src/exe/xournalpp-wrapper.gresource.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - ui/crashDialog.glade - -