Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ jobs:
sudo apt-get install -y --no-install-recommends build-essential libcurl4-openssl-dev libgl1-mesa-dev libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev

- name: Configure CMake
run: cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCOREDECK_BUILD_TESTS=ON
env:
COREDECK_SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
run: cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCOREDECK_BUILD_TESTS=ON -DCOREDECK_SENTRY_DSN=$COREDECK_SENTRY_DSN
shell: bash

- name: Build
run: cmake --build build --config ${{ matrix.build_type }} --parallel
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ jobs:
sudo apt-get install -y --no-install-recommends build-essential libcurl4-openssl-dev libgl1-mesa-dev libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev

- name: Configure CMake
run: cmake -B build -DCMAKE_BUILD_TYPE=Release
env:
COREDECK_SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
run: cmake -B build -DCMAKE_BUILD_TYPE=Release -DCOREDECK_SENTRY_DSN=$COREDECK_SENTRY_DSN
shell: bash

- name: Build
run: cmake --build build --config Release --parallel
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@
[submodule "extern/catch2"]
path = extern/catch2
url = https://github.com/catchorg/Catch2.git
[submodule "extern/sentry-native"]
path = extern/sentry-native
url = https://github.com/getsentry/sentry-native.git
43 changes: 42 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ set(TINYFD_DIR ${CMAKE_SOURCE_DIR}/extern/tinyfiledialogs)
add_library(tinyfiledialogs STATIC ${TINYFD_DIR}/tinyfiledialogs.c)
target_include_directories(tinyfiledialogs PUBLIC ${TINYFD_DIR})

set(COREDECK_SENTRY_DSN "" CACHE STRING "Sentry DSN for crash reporting")
if (COREDECK_SENTRY_DSN)
set(SENTRY_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(SENTRY_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(SENTRY_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(SENTRY_BACKEND "crashpad" CACHE STRING "" FORCE)
add_subdirectory(extern/sentry-native)
message(STATUS "Sentry: Enabled")
else ()
message(STATUS "Sentry: Disabled")
endif ()

find_package(OpenGL REQUIRED)
find_package(Threads REQUIRED)

Expand All @@ -96,7 +108,9 @@ endif ()
add_library(coredeck_core STATIC
src/core/app_settings.cpp
src/core/avd.cpp
src/core/crash_reporter.cpp
src/core/emulator.cpp
src/core/emulator_console.cpp
src/core/file_dialog.cpp
src/core/log_buffer.cpp
src/core/options.cpp
Expand All @@ -113,6 +127,7 @@ target_precompile_headers(coredeck_core PRIVATE src/pch.h)
target_link_libraries(coredeck_core PUBLIC reflectcpp tinyfiledialogs)

target_compile_definitions(coredeck_core PUBLIC
COREDECK_TITLE="CoreDeck"
COREDECK_VERSION="${PROJECT_VERSION_FULL}"
COREDECK_BUILD_NUMBER="${PROJECT_BUILD_NUMBER}"
COREDECK_VENDOR="${APP_VENDOR}"
Expand All @@ -125,9 +140,14 @@ target_compile_definitions(coredeck_core PUBLIC
COREDECK_COPYRIGHT="${APP_COPYRIGHT}"
)

if (COREDECK_SENTRY_DSN)
target_compile_definitions(coredeck_core PUBLIC COREDECK_SENTRY_DSN="${COREDECK_SENTRY_DSN}")
target_link_libraries(coredeck_core PUBLIC sentry)
endif ()

if (WIN32)
target_compile_definitions(coredeck_core PUBLIC WIN32_LEAN_AND_MEAN NOMINMAX)
target_link_libraries(coredeck_core PUBLIC shell32 comdlg32 ole32 winhttp)
target_link_libraries(coredeck_core PUBLIC shell32 comdlg32 ole32 winhttp ws2_32)
elseif (UNIX AND NOT APPLE)
target_link_libraries(coredeck_core PUBLIC ${CMAKE_DL_LIBS} Threads::Threads CURL::libcurl)
else ()
Expand Down Expand Up @@ -191,6 +211,23 @@ if (UNIX AND NOT APPLE)
)
endif ()

if (COREDECK_SENTRY_DSN)
if (APPLE)
target_link_options(${PROJECT_NAME} PRIVATE "-Wl,-no_warn_duplicate_libraries")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:crashpad_handler>
$<TARGET_BUNDLE_CONTENT_DIR:${PROJECT_NAME}>/MacOS/crashpad_handler
)
else ()
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:crashpad_handler>
$<TARGET_FILE_DIR:${PROJECT_NAME}>/$<TARGET_FILE_NAME:crashpad_handler>
)
endif ()
endif ()

if (WIN32)
configure_file(${CMAKE_SOURCE_DIR}/resources.rc.in ${CMAKE_BINARY_DIR}/resources.rc @ONLY)
target_link_options(${PROJECT_NAME} PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
Expand Down Expand Up @@ -237,6 +274,10 @@ install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION .
)

if (COREDECK_SENTRY_DSN AND NOT APPLE)
install(PROGRAMS $<TARGET_FILE:crashpad_handler> DESTINATION .)
endif ()

if (NOT APPLE)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/assets/fonts DESTINATION assets)
endif ()
Expand Down
1 change: 1 addition & 0 deletions extern/sentry-native
Submodule sentry-native added at 197e12
6 changes: 4 additions & 2 deletions resources.rc.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma code_page(65001)
#include <windows.h>

IDI_ICON1 ICON "@CMAKE_SOURCE_DIR@/assets/icons/icon.ico"
1 ICON "@CMAKE_SOURCE_DIR@/assets/icons/icon.ico"

VS_VERSION_INFO VERSIONINFO
FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@PROJECT_BUILD_NUMBER@
Expand All @@ -16,12 +17,13 @@ BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "@APP_VENDOR@"
VALUE "FileDescription", "@APP_DESCRIPTION_SHORT@"
VALUE "FileDescription", "@PROJECT_NAME@"
VALUE "FileVersion", "@PROJECT_VERSION@.@PROJECT_BUILD_NUMBER@"
VALUE "ProductName", "@PROJECT_NAME@"
VALUE "ProductVersion", "@PROJECT_VERSION@"
VALUE "LegalCopyright", "@APP_COPYRIGHT@"
VALUE "OriginalFilename", "@PROJECT_NAME@.exe"
VALUE "Comments", "@APP_DESCRIPTION_SHORT@"
END
END
BLOCK "VarFileInfo"
Expand Down
37 changes: 11 additions & 26 deletions src/core/avd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include "avd.h"
#include "paths.h"
#include "process.h"
#include "utilities.h"

namespace CoreDeck {
static std::unordered_map<std::string, std::string> ParseConfigFile(const std::string &path) {
Expand Down Expand Up @@ -129,8 +128,7 @@ namespace CoreDeck {
std::vector<std::string> avds;
if (!sdk.IsFound) return avds;

const std::string cmd = StrConcat("\"", sdk.EmulatorPath, "\" -list-avds");
const std::string output = RunCommand(cmd);
const std::string output = RunCommandArgs(sdk.EmulatorPath, {"-list-avds"});
std::istringstream stream(output);
std::string line;
while (std::getline(stream, line)) {
Expand All @@ -144,13 +142,14 @@ namespace CoreDeck {
if (sdk.AvdManagerPath.empty()) return false;
if (data.Name.empty() || data.SystemImagePackagePath.empty()) return false;

std::string cmd = StrConcat(
"echo no | \"", sdk.AvdManagerPath, "\" create avd -n \"", data.Name, "\" -k \"",
data.SystemImagePackagePath, "\""
);

if (!data.DeviceId.empty()) cmd = StrConcat(cmd, " -d \"", data.DeviceId, "\"");
RunCommand(cmd);
std::vector<std::string> args = {
"create", "avd", "-n", data.Name, "-k", data.SystemImagePackagePath
};
if (!data.DeviceId.empty()) {
args.emplace_back("-d");
args.push_back(data.DeviceId);
}
RunCommandArgs(sdk.AvdManagerPath, args, "no\n");

const std::string avdDir = Paths::GetAvdDirectory();
const std::string configPath = Paths::JoinPaths({avdDir, data.Name + ".avd", "config.ini"});
Expand Down Expand Up @@ -179,23 +178,9 @@ namespace CoreDeck {
}

bool DeleteAvd(const SdkInfo &sdk, const std::string &avdName) {
if (!sdk.AvdManagerPath.empty()) {
const std::string cmd = StrConcat("\"", sdk.AvdManagerPath, "\" delete avd -n ", avdName);
RunCommand(cmd);
} else {
// Fallback: manually delete the AVD files
const std::string avdDir = Paths::GetAvdDirectory();
if (avdDir.empty()) return false;

const std::string avdFolder = Paths::JoinPaths({avdDir, avdName + ".avd"});
const std::string avdIni = Paths::JoinPaths({avdDir, avdName + ".ini"});

std::error_code ec;
std::filesystem::remove_all(avdFolder, ec);
if (ec) return false;
if (sdk.AvdManagerPath.empty()) return false;

std::filesystem::remove(avdIni, ec);
}
RunCommandArgs(sdk.AvdManagerPath, {"delete", "avd", "-n", avdName});

const std::string avdDir = Paths::GetAvdDirectory();
const std::string avdFolder = Paths::JoinPaths({avdDir, avdName + ".avd"});
Expand Down
107 changes: 107 additions & 0 deletions src/core/crash_reporter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//
// Created by AbdulMuaz Aqeel on 27/04/2026.
//

#include "crash_reporter.h"

#ifdef COREDECK_SENTRY_DSN

#include <sentry.h>
#include <string>

#include "paths.h"

namespace CoreDeck::CrashReporter {
static sentry_level_t ToSentryLevel(const Level level) {
switch (level) {
case Level::Debug: return SENTRY_LEVEL_DEBUG;
case Level::Info: return SENTRY_LEVEL_INFO;
case Level::Warning: return SENTRY_LEVEL_WARNING;
case Level::Error: return SENTRY_LEVEL_ERROR;
case Level::Fatal: return SENTRY_LEVEL_FATAL;
}
return SENTRY_LEVEL_INFO;
}

static std::string ToString(const std::string_view sv) {
return std::string(sv);
}

bool Init() {
sentry_options_t *opts = sentry_options_new();
sentry_options_set_dsn(opts, COREDECK_SENTRY_DSN);
sentry_options_set_release(opts, "coredeck@" COREDECK_VERSION);
sentry_options_set_dist(opts, COREDECK_BUILD_NUMBER);
sentry_options_set_database_path(opts, Paths::GetAppConfigPath("sentry-db").c_str());

const char *handlerName =
#ifdef _WIN32
"crashpad_handler.exe";
#else
"crashpad_handler";
#endif
const std::string handlerPath = Paths::JoinPaths(
{Paths::GetExecutableDirectory(), handlerName}
);
sentry_options_set_handler_path(opts, handlerPath.c_str());

return sentry_init(opts) == 0;
}

void Shutdown() {
sentry_close();
}

bool IsEnabled() { return true; }

void CaptureMessage(const Level level, const std::string_view message) {
sentry_capture_event(sentry_value_new_message_event(
ToSentryLevel(level),
nullptr,
ToString(message).c_str()
)
);
}

void CaptureException(const std::string_view type, const std::string_view message) {
const sentry_value_t event = sentry_value_new_event();
const sentry_value_t exc = sentry_value_new_exception(
ToString(type).c_str(),
ToString(message).c_str()
);
sentry_value_set_stacktrace(exc, nullptr, 0);
sentry_event_add_exception(event, exc);
sentry_capture_event(event);
}

void AddBreadcrumb(const std::string_view category, const std::string_view message) {
const sentry_value_t crumb = sentry_value_new_breadcrumb(
nullptr,
ToString(message).c_str()
);
sentry_value_set_by_key(crumb, "category", sentry_value_new_string(ToString(category).c_str()));
sentry_add_breadcrumb(crumb);
}
}

#else

namespace CoreDeck::CrashReporter {
bool Init() { return false; }

void Shutdown() {
}

bool IsEnabled() { return false; }

void CaptureMessage(Level, std::string_view) {
}

void CaptureException(std::string_view, std::string_view) {
}

void AddBreadcrumb(std::string_view, std::string_view) {
}
}

#endif
32 changes: 32 additions & 0 deletions src/core/crash_reporter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Created by AbdulMuaz Aqeel on 27/04/2026.
//

#ifndef COREDECK_CRASH_REPORTER_H
#define COREDECK_CRASH_REPORTER_H

#include <string_view>

namespace CoreDeck::CrashReporter {
enum class Level {
Debug,
Info,
Warning,
Error,
Fatal
};

bool Init();

void Shutdown();

bool IsEnabled();

void CaptureMessage(Level level, std::string_view message);

void CaptureException(std::string_view type, std::string_view message);

void AddBreadcrumb(std::string_view category, std::string_view message);
}

#endif //COREDECK_CRASH_REPORTER_H
Loading
Loading