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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends build-essential libgl1-mesa-dev libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev
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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends build-essential libgl1-mesa-dev libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev
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
Expand Down
10 changes: 8 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ target_include_directories(tinyfiledialogs PUBLIC ${TINYFD_DIR})
find_package(OpenGL REQUIRED)
find_package(Threads REQUIRED)

if (NOT WIN32)
find_package(CURL REQUIRED)
endif ()

add_library(coredeck_core STATIC
src/core/app_settings.cpp
src/core/avd.cpp
Expand Down Expand Up @@ -123,9 +127,11 @@ target_compile_definitions(coredeck_core PUBLIC

if (WIN32)
target_compile_definitions(coredeck_core PUBLIC WIN32_LEAN_AND_MEAN NOMINMAX)
target_link_libraries(coredeck_core PUBLIC shell32 comdlg32 ole32)
target_link_libraries(coredeck_core PUBLIC shell32 comdlg32 ole32 winhttp)
elseif (UNIX AND NOT APPLE)
target_link_libraries(coredeck_core PUBLIC ${CMAKE_DL_LIBS} Threads::Threads)
target_link_libraries(coredeck_core PUBLIC ${CMAKE_DL_LIBS} Threads::Threads CURL::libcurl)
else ()
target_link_libraries(coredeck_core PUBLIC CURL::libcurl)
endif ()

add_executable(${PROJECT_NAME}
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ Grab the latest release for your platform from the [Releases](https://github.com

**Linux dependencies (Ubuntu/Debian):**

`build-essential` does not include CMake, so it's listed separately:

```bash
sudo apt-get install build-essential libgl1-mesa-dev libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev
sudo apt-get install build-essential cmake libcurl4-openssl-dev libgl1-mesa-dev libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev
```

**Build:**
Expand Down
3 changes: 2 additions & 1 deletion src/core/avd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ namespace CoreDeck {
const std::string path = Paths::JoinPaths({avdRoot, avdName + ".avd"});

avd.Name = avdName;
avd.DisplayName = avdName;
avd.Path = path;

std::string configPath = Paths::JoinPaths({avd.Path, "config.ini"});
Expand All @@ -61,7 +62,7 @@ namespace CoreDeck {
avd.Device = it->second;
}

if (auto it = config.find("avd.ini.displayname"); it != config.end()) {
if (auto it = config.find("avd.ini.displayname"); it != config.end() && !it->second.empty()) {
avd.DisplayName = it->second;
}

Expand Down
40 changes: 40 additions & 0 deletions src/core/paths.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h>
#elif defined(__APPLE__)
#include <mach-o/dyld.h>
#include <climits>
#elif defined(__linux__)
#include <unistd.h>
#include <climits>
#endif

#include "log.h"
Expand Down Expand Up @@ -151,6 +157,40 @@ namespace CoreDeck::Paths {
}
}

std::string GetExecutableDirectory() {
#ifdef _WIN32
char buffer[MAX_PATH];
const DWORD len = GetModuleFileNameA(nullptr, buffer, MAX_PATH);
if (len == 0) return {};
return std::filesystem::path(std::string(buffer, len)).parent_path().string();
#elif defined(__APPLE__)
char buffer[PATH_MAX];
uint32_t size = sizeof(buffer);
if (_NSGetExecutablePath(buffer, &size) != 0) return {};
return std::filesystem::canonical(buffer).parent_path().string();
#elif defined(__linux__)
char buffer[PATH_MAX];
const ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
if (len <= 0) return {};
buffer[len] = '\0';
return std::filesystem::path(buffer).parent_path().string();
#else
return {};
#endif
}

std::string GetResourcesDirectory() {
std::string exeDir = GetExecutableDirectory();
if (exeDir.empty()) return {};
#ifdef __APPLE__
const std::filesystem::path p(exeDir);
if (p.filename() == "MacOS" && p.parent_path().filename() == "Contents") {
return (p.parent_path() / "Resources").string();
}
#endif
return std::move(exeDir);
}

std::string JoinPaths(const std::vector<std::string> &components) {
if (components.empty()) return "";

Expand Down
4 changes: 4 additions & 0 deletions src/core/paths.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ namespace CoreDeck::Paths {

std::string GetExecutableExtension();

std::string GetExecutableDirectory();

std::string GetResourcesDirectory();

std::string JoinPaths(const std::vector<std::string> &components);

std::string NormalizePath(const std::string &path);
Expand Down
129 changes: 113 additions & 16 deletions src/core/version_check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@
#include <rfl/json.hpp>

#include "version_check.h"
#include "process.h"
#include "utilities.h"

#if defined(_WIN32)
#include <windows.h>
#include <winhttp.h>
#pragma comment(lib, "winhttp.lib")
#else
#include <curl/curl.h>
#endif

namespace CoreDeck {
struct GitHubLatestRelease {
std::string tag_name;
Expand Down Expand Up @@ -87,25 +94,115 @@ namespace CoreDeck {
}
}

namespace {
#if defined(_WIN32)
std::optional<std::string> HttpGet(const wchar_t *host, const wchar_t *path, const std::wstring &userAgent) {
HINTERNET session = WinHttpOpen(
userAgent.c_str(),
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0
);
if (!session) return std::nullopt;

WinHttpSetTimeouts(session, 15000, 15000, 15000, 15000);

HINTERNET connect = WinHttpConnect(session, host, INTERNET_DEFAULT_HTTPS_PORT, 0);
if (!connect) {
WinHttpCloseHandle(session);
return std::nullopt;
}

HINTERNET request = WinHttpOpenRequest(
connect, L"GET", path, nullptr,
WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE
);
if (!request) {
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
return std::nullopt;
}

const wchar_t *headers = L"Accept: application/vnd.github+json\r\n";
BOOL sent = WinHttpSendRequest(request, headers, static_cast<DWORD>(-1L), WINHTTP_NO_REQUEST_DATA, 0, 0, 0)
&& WinHttpReceiveResponse(request, nullptr);

std::optional<std::string> result;
if (sent) {
DWORD status = 0;
DWORD statusSize = sizeof(status);
WinHttpQueryHeaders(request,
WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
WINHTTP_HEADER_NAME_BY_INDEX, &status, &statusSize,
WINHTTP_NO_HEADER_INDEX);
if (status >= 200 && status < 300) {
std::string body;
DWORD available = 0;
while (WinHttpQueryDataAvailable(request, &available) && available > 0) {
std::string chunk(available, '\0');
DWORD read = 0;
if (!WinHttpReadData(request, chunk.data(), available, &read)) break;
chunk.resize(read);
body.append(chunk);
}
result = std::move(body);
}
}

WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
return result;
}
#else
size_t CurlWriteCallback(const char *ptr, const size_t size, size_t nmemb, void *userdata) {
auto *buf = static_cast<std::string *>(userdata);
buf->append(ptr, size * nmemb);
return size * nmemb;
}

std::optional<std::string> HttpGet(const std::string &url, const std::string &userAgent) {
CURL *curl = curl_easy_init();
if (!curl) return std::nullopt;

std::string body;
curl_slist *headers = curl_slist_append(nullptr, "Accept: application/vnd.github+json");

curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15L);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &body);

const CURLcode rc = curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);

if (rc != CURLE_OK) return std::nullopt;
return body;
}
#endif
}

std::optional<std::string> QueryRemoteNewerVersion() {
#if defined(_WIN32)
const std::string cmd = StrConcat(
"curl -sfL --max-time 15 -H \"Accept: application/vnd.github+json\" -A \"CoreDeck/",
COREDECK_VERSION,
"\" \"",
COREDECK_GITHUB_API,
"\""
);
const std::string ua = StrConcat("CoreDeck/", COREDECK_VERSION);
std::wstring userAgent(ua.begin(), ua.end());
auto fetched = HttpGet(L"api.github.com", L"/repos/devmuaz/CoreDeck/releases/latest", userAgent);
#else
const std::string cmd = StrConcat(
"curl -sfL --max-time 15 -H 'Accept: application/vnd.github+json' -A 'CoreDeck/",
COREDECK_VERSION,
"' '",
COREDECK_GITHUB_API,
"'"
);
const std::string userAgent = StrConcat("CoreDeck/", COREDECK_VERSION);
auto fetched = HttpGet(COREDECK_GITHUB_API, userAgent);
#endif
std::string body = RunCommand(cmd);
if (!fetched) {
return std::nullopt;
}
std::string body = std::move(fetched.value());
TrimInPlace(body);
if (body.empty()) {
return std::nullopt;
Expand Down
2 changes: 2 additions & 0 deletions src/gui/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ namespace CoreDeck {
int SelectedSystemImage = 0;
int SelectedDevice = 0;
int SelectedGpuMode = 0;
bool NameAutoFilled = true;
bool DisplayNameAutoFilled = true;

struct {
std::atomic<bool> Loading{false};
Expand Down
31 changes: 31 additions & 0 deletions src/gui/icons.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// Created by AbdulMuaz Aqeel on 24/04/2026.
//

#ifndef COREDECK_ICONS_H
#define COREDECK_ICONS_H

namespace CoreDeck::Icons {
constexpr const char *Play = "\xef\x81\x8b"; // fa-play (f04b)
constexpr const char *Stop = "\xef\x81\x8d"; // fa-stop (f04d)
constexpr const char *Refresh = "\xef\x80\xa1"; // fa-arrows-rotate (f021)
constexpr const char *Trash = "\xef\x87\xb8"; // fa-trash-can (f1f8)
constexpr const char *Circle = "\xef\x84\x91"; // fa-circle (f111)
constexpr const char *Desktop = "\xef\x84\x88"; // fa-desktop (f108)
constexpr const char *Gear = "\xef\x80\x93"; // fa-gear (f013)
constexpr const char *Terminal = "\xef\x84\xa0"; // fa-terminal (f120)
constexpr const char *Info = "\xef\x81\x9a"; // fa-circle-info (f05a)
constexpr const char *Search = "\xef\x80\x82"; // fa-magnifying-glass (f002)
constexpr const char *Plus = "\xef\x81\xa7"; // fa-plus (f067)
constexpr const char *SortUp = "\xef\x83\x9e"; // fa-sort-up (f0de)
constexpr const char *SortDown = "\xef\x83\x9d"; // fa-sort-down (f0dd)
constexpr const char *Sort = "\xef\x83\x9c"; // fa-sort (f0dc)
constexpr const char *Times = "\xef\x80\x8d"; // fa-xmark (f00d)
constexpr const char *Mobile = "\xef\x8f\x8d"; // fa-mobile-screen-button (f3cd)
constexpr const char *Tablet = "\xef\x8f\xba"; // fa-tablet-screen-button (f3fa)
constexpr const char *Tv = "\xef\x89\xac"; // fa-tv (f26c)
constexpr const char *Watch = "\xef\x80\x97"; // fa-clock (f017) — used for Wear OS
constexpr const char *Car = "\xef\x86\xb9"; // fa-car (f1b9) — used for Automotive
}

#endif //COREDECK_ICONS_H
21 changes: 0 additions & 21 deletions src/gui/theme.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,6 @@ namespace CoreDeck {
alpha
};
}

namespace Icons {
constexpr const char *Play = "\xef\x81\x8b";
constexpr const char *Stop = "\xef\x81\x8d";
constexpr const char *Refresh = "\xef\x80\xa1";
constexpr const char *Trash = "\xef\x87\xb8";
constexpr const char *Circle = "\xef\x84\x91";
constexpr const char *Desktop = "\xef\x84\x88";
constexpr const char *Gear = "\xef\x80\x93";
constexpr const char *Terminal = "\xef\x84\xa0";
constexpr const char *Info = "\xef\x81\x9a";
constexpr const char *Search = "\xef\x80\x82";
constexpr const char *Plus = "\xef\x81\xa7";
constexpr const char *SortUp = "\xef\x83\x9e"; // fa-sort-up (f0de)
constexpr const char *SortDown = "\xef\x83\x9d"; // fa-sort-down (f0dd)
constexpr const char *Sort = "\xef\x83\x9c"; // fa-sort (f0dc)
constexpr const char *Times = "\xef\x80\x8d"; // fa-xmark (f00d)
}

namespace Colors {
}
}

#endif //COREDECK_THEME_H
Loading
Loading