2021-01-20 20:16:24 +01:00
|
|
|
#include <hex/api/imhex_api.hpp>
|
|
|
|
|
2023-11-18 14:50:43 +01:00
|
|
|
#include <hex/api/event_manager.hpp>
|
|
|
|
#include <hex/api/task_manager.hpp>
|
2023-06-20 11:55:56 +02:00
|
|
|
#include <hex/helpers/fmt.hpp>
|
2023-10-21 20:40:24 +02:00
|
|
|
#include <hex/helpers/utils.hpp>
|
2024-01-30 11:21:34 +01:00
|
|
|
#include <hex/helpers/auto_reset.hpp>
|
2024-02-25 14:30:56 +01:00
|
|
|
#include <hex/providers/provider_data.hpp>
|
|
|
|
#include <hex/providers/provider.hpp>
|
2023-06-20 11:55:56 +02:00
|
|
|
|
2023-10-21 20:40:24 +02:00
|
|
|
#include <wolv/utils/string.hpp>
|
2021-01-20 20:16:24 +01:00
|
|
|
|
2022-07-02 16:22:38 +02:00
|
|
|
#include <utility>
|
2021-08-21 15:03:44 +02:00
|
|
|
|
2022-02-17 11:42:56 +01:00
|
|
|
#include <imgui.h>
|
2023-11-28 13:52:26 +01:00
|
|
|
#include <imgui_internal.h>
|
2024-05-17 21:56:43 +02:00
|
|
|
#include <set>
|
2024-06-03 10:02:29 +02:00
|
|
|
#include <algorithm>
|
2024-01-21 18:39:51 +01:00
|
|
|
#include <GLFW/glfw3.h>
|
2022-02-17 11:42:56 +01:00
|
|
|
|
2022-10-07 10:14:24 +02:00
|
|
|
#if defined(OS_WINDOWS)
|
|
|
|
#include <windows.h>
|
2023-06-20 11:55:56 +02:00
|
|
|
#else
|
|
|
|
#include <sys/utsname.h>
|
2024-01-30 11:21:34 +01:00
|
|
|
#include <unistd.h>
|
2022-10-07 10:14:24 +02:00
|
|
|
#endif
|
|
|
|
|
2021-01-20 20:16:24 +01:00
|
|
|
namespace hex {
|
|
|
|
|
2021-08-21 13:55:21 +02:00
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
namespace ImHexApi::HexEditor {
|
2021-01-20 20:16:24 +01:00
|
|
|
|
2022-05-27 20:42:07 +02:00
|
|
|
Highlighting::Highlighting(Region region, color_t color)
|
|
|
|
: m_region(region), m_color(color) {
|
|
|
|
}
|
|
|
|
|
|
|
|
Tooltip::Tooltip(Region region, std::string value, color_t color) : m_region(region), m_value(std::move(value)), m_color(color) {
|
|
|
|
|
2022-02-16 14:57:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace impl {
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::map<u32, Highlighting>> s_backgroundHighlights;
|
|
|
|
const std::map<u32, Highlighting>& getBackgroundHighlights() {
|
|
|
|
return *s_backgroundHighlights;
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::map<u32, HighlightingFunction>> s_backgroundHighlightingFunctions;
|
|
|
|
const std::map<u32, HighlightingFunction>& getBackgroundHighlightingFunctions() {
|
|
|
|
return *s_backgroundHighlightingFunctions;
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::map<u32, Highlighting>> s_foregroundHighlights;
|
|
|
|
const std::map<u32, Highlighting>& getForegroundHighlights() {
|
|
|
|
return *s_foregroundHighlights;
|
2022-02-16 14:57:13 +01:00
|
|
|
}
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::map<u32, HighlightingFunction>> s_foregroundHighlightingFunctions;
|
|
|
|
const std::map<u32, HighlightingFunction>& getForegroundHighlightingFunctions() {
|
|
|
|
return *s_foregroundHighlightingFunctions;
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::map<u32, Tooltip>> s_tooltips;
|
|
|
|
const std::map<u32, Tooltip>& getTooltips() {
|
|
|
|
return *s_tooltips;
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::map<u32, TooltipFunction>> s_tooltipFunctions;
|
|
|
|
const std::map<u32, TooltipFunction>& getTooltipFunctions() {
|
|
|
|
return *s_tooltipFunctions;
|
2022-02-16 14:57:13 +01:00
|
|
|
}
|
2021-01-20 20:16:24 +01:00
|
|
|
|
2024-02-25 14:30:56 +01:00
|
|
|
static AutoReset<std::map<u32, HoveringFunction>> s_hoveringFunctions;
|
|
|
|
const std::map<u32, HoveringFunction>& getHoveringFunctions() {
|
|
|
|
return *s_hoveringFunctions;
|
|
|
|
}
|
|
|
|
|
2024-01-30 11:21:34 +01:00
|
|
|
static AutoReset<std::optional<ProviderRegion>> s_currentSelection;
|
2023-11-10 21:03:31 +01:00
|
|
|
void setCurrentSelection(const std::optional<ProviderRegion> ®ion) {
|
2024-03-21 23:50:34 +01:00
|
|
|
if (region == Region::Invalid()) {
|
|
|
|
clearSelection();
|
|
|
|
} else {
|
|
|
|
*s_currentSelection = region;
|
|
|
|
}
|
2022-11-08 21:43:22 +01:00
|
|
|
}
|
|
|
|
|
2024-02-25 14:30:56 +01:00
|
|
|
static PerProvider<std::optional<Region>> s_hoveredRegion;
|
|
|
|
void setHoveredRegion(const prv::Provider *provider, const Region ®ion) {
|
|
|
|
if (region == Region::Invalid())
|
|
|
|
s_hoveredRegion.get(provider).reset();
|
|
|
|
else
|
|
|
|
s_hoveredRegion.get(provider) = region;
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
2021-01-20 20:16:24 +01:00
|
|
|
|
2022-05-27 20:42:07 +02:00
|
|
|
u32 addBackgroundHighlight(const Region ®ion, color_t color) {
|
|
|
|
static u32 id = 0;
|
2022-03-26 16:54:15 +01:00
|
|
|
|
|
|
|
id++;
|
2021-01-20 20:16:24 +01:00
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_backgroundHighlights->insert({
|
|
|
|
id, Highlighting { region, color }
|
2022-02-01 22:09:44 +01:00
|
|
|
});
|
2021-01-20 20:16:24 +01:00
|
|
|
|
2024-02-23 17:47:59 +01:00
|
|
|
TaskManager::doLaterOnce([]{ EventHighlightingChanged::post(); });
|
2022-02-04 00:29:47 +01:00
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2022-05-27 20:42:07 +02:00
|
|
|
void removeBackgroundHighlight(u32 id) {
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_backgroundHighlights->erase(id);
|
2022-02-16 14:57:13 +01:00
|
|
|
|
2024-02-23 17:47:59 +01:00
|
|
|
TaskManager::doLaterOnce([]{ EventHighlightingChanged::post(); });
|
2022-02-16 14:57:13 +01:00
|
|
|
}
|
|
|
|
|
2022-05-27 20:42:07 +02:00
|
|
|
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function) {
|
|
|
|
static u32 id = 0;
|
2022-02-16 14:57:13 +01:00
|
|
|
|
2022-05-27 20:42:07 +02:00
|
|
|
id++;
|
2022-02-16 14:57:13 +01:00
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_backgroundHighlightingFunctions->insert({ id, function });
|
2022-02-04 00:29:47 +01:00
|
|
|
|
2024-02-23 17:47:59 +01:00
|
|
|
TaskManager::doLaterOnce([]{ EventHighlightingChanged::post(); });
|
2022-02-16 14:57:13 +01:00
|
|
|
|
|
|
|
return id;
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
2022-05-27 20:42:07 +02:00
|
|
|
void removeBackgroundHighlightingProvider(u32 id) {
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_backgroundHighlightingFunctions->erase(id);
|
2022-02-16 14:57:13 +01:00
|
|
|
|
2024-02-23 17:47:59 +01:00
|
|
|
TaskManager::doLaterOnce([]{ EventHighlightingChanged::post(); });
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
2021-01-20 20:16:24 +01:00
|
|
|
|
2022-05-27 20:42:07 +02:00
|
|
|
u32 addForegroundHighlight(const Region ®ion, color_t color) {
|
|
|
|
static u32 id = 0;
|
|
|
|
|
|
|
|
id++;
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_foregroundHighlights->insert({
|
|
|
|
id, Highlighting { region, color }
|
2022-02-08 18:38:54 +01:00
|
|
|
});
|
|
|
|
|
2024-02-23 17:47:59 +01:00
|
|
|
TaskManager::doLaterOnce([]{ EventHighlightingChanged::post(); });
|
2022-05-27 20:42:07 +02:00
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void removeForegroundHighlight(u32 id) {
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_foregroundHighlights->erase(id);
|
2022-05-27 20:42:07 +02:00
|
|
|
|
2024-02-23 17:47:59 +01:00
|
|
|
TaskManager::doLaterOnce([]{ EventHighlightingChanged::post(); });
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function) {
|
|
|
|
static u32 id = 0;
|
|
|
|
|
|
|
|
id++;
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_foregroundHighlightingFunctions->insert({ id, function });
|
2022-05-27 20:42:07 +02:00
|
|
|
|
2024-02-23 17:47:59 +01:00
|
|
|
TaskManager::doLaterOnce([]{ EventHighlightingChanged::post(); });
|
2022-05-27 20:42:07 +02:00
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void removeForegroundHighlightingProvider(u32 id) {
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_foregroundHighlightingFunctions->erase(id);
|
2022-05-27 20:42:07 +02:00
|
|
|
|
2024-02-23 17:47:59 +01:00
|
|
|
TaskManager::doLaterOnce([]{ EventHighlightingChanged::post(); });
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
2024-02-25 14:30:56 +01:00
|
|
|
u32 addHoverHighlightProvider(const impl::HoveringFunction &function) {
|
|
|
|
static u32 id = 0;
|
|
|
|
|
|
|
|
id++;
|
|
|
|
|
|
|
|
impl::s_hoveringFunctions->insert({ id, function });
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void removeHoverHighlightProvider(u32 id) {
|
|
|
|
impl::s_hoveringFunctions->erase(id);
|
|
|
|
}
|
|
|
|
|
2024-06-05 23:02:38 +02:00
|
|
|
static u32 s_tooltipId = 0;
|
2022-05-27 20:42:07 +02:00
|
|
|
u32 addTooltip(Region region, std::string value, color_t color) {
|
2024-06-05 23:02:38 +02:00
|
|
|
s_tooltipId++;
|
|
|
|
impl::s_tooltips->insert({ s_tooltipId, { region, std::move(value), color } });
|
2022-05-27 20:42:07 +02:00
|
|
|
|
2024-06-05 23:02:38 +02:00
|
|
|
return s_tooltipId;
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void removeTooltip(u32 id) {
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_tooltips->erase(id);
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
2024-06-05 23:02:38 +02:00
|
|
|
static u32 s_tooltipFunctionId;
|
2022-05-27 20:42:07 +02:00
|
|
|
u32 addTooltipProvider(TooltipFunction function) {
|
2024-06-05 23:02:38 +02:00
|
|
|
s_tooltipFunctionId++;
|
|
|
|
impl::s_tooltipFunctions->insert({ s_tooltipFunctionId, std::move(function) });
|
2022-05-27 20:42:07 +02:00
|
|
|
|
2024-06-05 23:02:38 +02:00
|
|
|
return s_tooltipFunctionId;
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void removeTooltipProvider(u32 id) {
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_tooltipFunctions->erase(id);
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool isSelectionValid() {
|
2024-01-31 15:31:51 +01:00
|
|
|
auto selection = getSelection();
|
|
|
|
return selection.has_value() && selection->provider != nullptr;
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
2022-11-08 21:43:22 +01:00
|
|
|
std::optional<ProviderRegion> getSelection() {
|
|
|
|
return impl::s_currentSelection;
|
|
|
|
}
|
2022-05-27 20:42:07 +02:00
|
|
|
|
2023-05-12 08:38:07 +02:00
|
|
|
void clearSelection() {
|
2024-05-16 19:00:31 +02:00
|
|
|
impl::s_currentSelection->reset();
|
2023-05-12 08:38:07 +02:00
|
|
|
}
|
|
|
|
|
2022-11-08 21:43:22 +01:00
|
|
|
void setSelection(const Region ®ion, prv::Provider *provider) {
|
|
|
|
setSelection(ProviderRegion { region, provider == nullptr ? Provider::get() : provider });
|
2022-02-08 18:38:54 +01:00
|
|
|
}
|
|
|
|
|
2022-11-08 21:43:22 +01:00
|
|
|
void setSelection(const ProviderRegion ®ion) {
|
2024-01-31 11:26:22 +01:00
|
|
|
RequestHexEditorSelectionChange::post(region);
|
2022-02-08 18:38:54 +01:00
|
|
|
}
|
|
|
|
|
2022-11-08 21:43:22 +01:00
|
|
|
void setSelection(u64 address, size_t size, prv::Provider *provider) {
|
|
|
|
setSelection({ { address, size }, provider == nullptr ? Provider::get() : provider });
|
2022-02-08 18:38:54 +01:00
|
|
|
}
|
|
|
|
|
2024-01-11 20:11:22 +01:00
|
|
|
void addVirtualFile(const std::fs::path &path, std::vector<u8> data, Region region) {
|
|
|
|
RequestAddVirtualFile::post(path, std::move(data), region);
|
|
|
|
}
|
2024-02-25 14:30:56 +01:00
|
|
|
|
|
|
|
const std::optional<Region>& getHoveredRegion(const prv::Provider *provider) {
|
|
|
|
return impl::s_hoveredRegion.get(provider);
|
|
|
|
}
|
|
|
|
|
2021-01-20 20:16:24 +01:00
|
|
|
}
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
namespace ImHexApi::Bookmarks {
|
2021-09-21 02:29:54 +02:00
|
|
|
|
2023-11-25 12:43:48 +01:00
|
|
|
u64 add(Region region, const std::string &name, const std::string &comment, u32 color) {
|
|
|
|
u64 id = 0;
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestAddBookmark::post(region, name, comment, color, &id);
|
2023-11-25 12:43:48 +01:00
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 add(u64 address, size_t size, const std::string &name, const std::string &comment, u32 color) {
|
|
|
|
return add(Region { address, size }, name, comment, color);
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
2021-09-21 02:29:54 +02:00
|
|
|
|
2023-11-25 12:43:48 +01:00
|
|
|
void remove(u64 id) {
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestRemoveBookmark::post(id);
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
2021-09-21 02:29:54 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-12-12 00:41:44 +01:00
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
namespace ImHexApi::Provider {
|
|
|
|
|
2022-09-05 14:16:31 +02:00
|
|
|
static i64 s_currentProvider = -1;
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::vector<std::unique_ptr<prv::Provider>>> s_providers;
|
2024-06-05 23:02:38 +02:00
|
|
|
static AutoReset<std::list<std::unique_ptr<prv::Provider>>> s_providersToRemove;
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2022-08-08 21:23:52 +02:00
|
|
|
namespace impl {
|
|
|
|
|
2024-05-17 21:56:43 +02:00
|
|
|
static std::set<prv::Provider*> s_closingProviders;
|
2022-08-08 21:23:52 +02:00
|
|
|
void resetClosingProvider() {
|
2023-11-07 15:31:54 +01:00
|
|
|
s_closingProviders.clear();
|
2022-08-08 21:23:52 +02:00
|
|
|
}
|
|
|
|
|
2024-06-16 14:48:31 +02:00
|
|
|
std::set<prv::Provider*> getClosingProviders() {
|
2023-11-07 15:31:54 +01:00
|
|
|
return s_closingProviders;
|
2022-08-08 21:23:52 +02:00
|
|
|
}
|
|
|
|
|
2024-05-17 21:56:43 +02:00
|
|
|
static std::recursive_mutex s_providerMutex;
|
2022-08-08 21:23:52 +02:00
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
prv::Provider *get() {
|
|
|
|
if (!ImHexApi::Provider::isValid())
|
|
|
|
return nullptr;
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
return (*s_providers)[s_currentProvider].get();
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
std::vector<prv::Provider*> getProviders() {
|
|
|
|
std::vector<prv::Provider*> result;
|
|
|
|
result.reserve(s_providers->size());
|
|
|
|
for (const auto &provider : *s_providers)
|
|
|
|
result.push_back(provider.get());
|
|
|
|
|
|
|
|
return result;
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
2024-02-24 12:06:06 +01:00
|
|
|
void setCurrentProvider(i64 index) {
|
2024-05-17 21:56:43 +02:00
|
|
|
std::scoped_lock lock(impl::s_providerMutex);
|
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
if (TaskManager::getRunningTaskCount() > 0)
|
2022-07-29 11:35:29 +02:00
|
|
|
return;
|
|
|
|
|
2024-02-24 12:06:06 +01:00
|
|
|
if (std::cmp_less(index, s_providers->size()) && s_currentProvider != index) {
|
2022-02-01 22:09:44 +01:00
|
|
|
auto oldProvider = get();
|
2022-02-01 18:09:40 +01:00
|
|
|
s_currentProvider = index;
|
2023-12-08 10:29:44 +01:00
|
|
|
EventProviderChanged::post(oldProvider, get());
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
2024-02-24 12:06:06 +01:00
|
|
|
|
|
|
|
RequestUpdateWindowTitle::post();
|
|
|
|
}
|
|
|
|
|
|
|
|
void setCurrentProvider(NonNull<prv::Provider*> provider) {
|
2024-05-17 21:56:43 +02:00
|
|
|
std::scoped_lock lock(impl::s_providerMutex);
|
|
|
|
|
2024-02-24 12:06:06 +01:00
|
|
|
if (TaskManager::getRunningTaskCount() > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const auto providers = getProviders();
|
|
|
|
auto it = std::ranges::find(providers, provider.get());
|
|
|
|
|
|
|
|
auto index = std::distance(providers.begin(), it);
|
|
|
|
setCurrentProvider(index);
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
2023-09-24 18:04:14 +02:00
|
|
|
i64 getCurrentProviderIndex() {
|
|
|
|
return s_currentProvider;
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
bool isValid() {
|
2024-01-30 11:21:34 +01:00
|
|
|
return !s_providers->empty() && s_currentProvider >= 0 && s_currentProvider < i64(s_providers->size());
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
2022-08-08 21:23:52 +02:00
|
|
|
void markDirty() {
|
|
|
|
get()->markDirty();
|
2024-06-12 19:51:12 +02:00
|
|
|
EventProviderDirtied::post(get());
|
2022-08-08 21:23:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void resetDirty() {
|
2024-01-30 11:21:34 +01:00
|
|
|
for (const auto &provider : *s_providers)
|
2022-08-08 21:23:52 +02:00
|
|
|
provider->markDirty(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDirty() {
|
2024-01-30 11:21:34 +01:00
|
|
|
return std::ranges::any_of(*s_providers, [](const auto &provider) {
|
2022-08-08 21:23:52 +02:00
|
|
|
return provider->isDirty();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface, bool select) {
|
2024-05-17 21:56:43 +02:00
|
|
|
std::scoped_lock lock(impl::s_providerMutex);
|
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
if (TaskManager::getRunningTaskCount() > 0)
|
2022-07-29 11:35:29 +02:00
|
|
|
return;
|
|
|
|
|
2022-08-14 10:07:45 +02:00
|
|
|
if (skipLoadInterface)
|
|
|
|
provider->skipLoadInterface();
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
EventProviderCreated::post(provider.get());
|
|
|
|
s_providers->emplace_back(std::move(provider));
|
2022-07-31 11:09:20 +02:00
|
|
|
|
2024-01-30 11:21:34 +01:00
|
|
|
if (select || s_providers->size() == 1)
|
|
|
|
setCurrentProvider(s_providers->size() - 1);
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
2022-08-08 21:23:52 +02:00
|
|
|
void remove(prv::Provider *provider, bool noQuestions) {
|
2024-05-17 21:56:43 +02:00
|
|
|
std::scoped_lock lock(impl::s_providerMutex);
|
|
|
|
|
2022-07-30 22:01:49 +02:00
|
|
|
if (provider == nullptr)
|
|
|
|
return;
|
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
if (TaskManager::getRunningTaskCount() > 0)
|
2022-07-29 11:35:29 +02:00
|
|
|
return;
|
2022-07-30 22:01:49 +02:00
|
|
|
|
2022-08-08 21:23:52 +02:00
|
|
|
if (!noQuestions) {
|
2024-05-17 21:56:43 +02:00
|
|
|
impl::s_closingProviders.insert(provider);
|
2022-08-08 21:23:52 +02:00
|
|
|
|
|
|
|
bool shouldClose = true;
|
2023-12-08 10:29:44 +01:00
|
|
|
EventProviderClosing::post(provider, &shouldClose);
|
2022-08-08 21:23:52 +02:00
|
|
|
if (!shouldClose)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
const auto it = std::ranges::find_if(*s_providers, [provider](const auto &p) {
|
|
|
|
return p.get() == provider;
|
|
|
|
});
|
|
|
|
|
2024-01-30 11:21:34 +01:00
|
|
|
if (it == s_providers->end())
|
2022-07-30 22:01:49 +02:00
|
|
|
return;
|
|
|
|
|
2024-01-30 11:21:34 +01:00
|
|
|
if (!s_providers->empty()) {
|
|
|
|
if (it == s_providers->begin()) {
|
2023-10-01 20:56:25 +02:00
|
|
|
// If the first provider is being closed, select the one that's the first one now
|
2023-10-01 20:18:26 +02:00
|
|
|
setCurrentProvider(0);
|
2023-12-14 20:46:53 +01:00
|
|
|
|
2024-01-30 11:21:34 +01:00
|
|
|
if (s_providers->size() > 1)
|
2024-02-10 23:31:05 +01:00
|
|
|
EventProviderChanged::post(s_providers->at(0).get(), s_providers->at(1).get());
|
2023-10-01 20:56:25 +02:00
|
|
|
}
|
2024-01-30 11:21:34 +01:00
|
|
|
else if (std::distance(s_providers->begin(), it) == s_currentProvider) {
|
2023-10-01 20:56:25 +02:00
|
|
|
// If the current provider is being closed, select the one that's before it
|
2023-10-01 20:18:26 +02:00
|
|
|
setCurrentProvider(s_currentProvider - 1);
|
2023-10-01 20:56:25 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// If any other provider is being closed, find the current provider in the list again and select it again
|
2024-01-30 11:21:34 +01:00
|
|
|
const auto currentProvider = get();
|
2024-02-10 23:31:05 +01:00
|
|
|
const auto currentIt = std::ranges::find_if(*s_providers, [currentProvider](const auto &p) {
|
|
|
|
return p.get() == currentProvider;
|
|
|
|
});
|
2023-10-01 20:56:25 +02:00
|
|
|
|
2024-01-30 11:21:34 +01:00
|
|
|
if (currentIt != s_providers->end()) {
|
|
|
|
auto newIndex = std::distance(s_providers->begin(), currentIt);
|
2023-10-01 20:56:25 +02:00
|
|
|
|
2024-02-24 12:06:06 +01:00
|
|
|
if (s_currentProvider == newIndex && newIndex != 0)
|
2023-10-01 20:56:25 +02:00
|
|
|
newIndex -= 1;
|
|
|
|
|
|
|
|
setCurrentProvider(newIndex);
|
|
|
|
} else {
|
|
|
|
// If the current provider is not in the list anymore, select the first one
|
|
|
|
setCurrentProvider(0);
|
|
|
|
}
|
|
|
|
}
|
2023-10-01 20:18:26 +02:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2024-06-05 23:02:38 +02:00
|
|
|
static std::mutex eraseMutex;
|
2022-09-04 11:16:20 +02:00
|
|
|
|
2024-06-05 23:02:38 +02:00
|
|
|
// Move provider over to a list of providers to delete
|
|
|
|
eraseMutex.lock();
|
|
|
|
auto removeIt = s_providersToRemove->emplace(s_providersToRemove->end(), std::move(*it));
|
|
|
|
eraseMutex.unlock();
|
2024-02-10 23:31:05 +01:00
|
|
|
|
2024-06-05 23:02:38 +02:00
|
|
|
// Remove left over references from the main provider list
|
|
|
|
s_providers->erase(it);
|
|
|
|
impl::s_closingProviders.erase(provider);
|
|
|
|
|
2024-06-05 23:21:15 +02:00
|
|
|
if (s_currentProvider >= i64(s_providers->size()) && !s_providers->empty())
|
|
|
|
setCurrentProvider(s_providers->size() - 1);
|
2024-06-05 23:02:38 +02:00
|
|
|
|
|
|
|
if (s_providers->empty())
|
|
|
|
EventProviderChanged::post(provider, nullptr);
|
|
|
|
|
|
|
|
EventProviderClosed::post(removeIt->get());
|
|
|
|
RequestUpdateWindowTitle::post();
|
2024-02-10 23:31:05 +01:00
|
|
|
|
2024-06-05 23:02:38 +02:00
|
|
|
// Do the destruction of the provider in the background once all tasks have finished
|
|
|
|
TaskManager::runWhenTasksFinished([removeIt] {
|
|
|
|
EventProviderDeleted::post(removeIt->get());
|
|
|
|
TaskManager::createBackgroundTask("Closing Provider", [removeIt](Task &) {
|
|
|
|
eraseMutex.lock();
|
|
|
|
auto provider = std::move(*removeIt);
|
|
|
|
s_providersToRemove->erase(removeIt);
|
|
|
|
eraseMutex.unlock();
|
|
|
|
|
|
|
|
provider->close();
|
|
|
|
});
|
2022-12-27 11:35:20 +01:00
|
|
|
});
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
2023-12-19 12:22:28 +01:00
|
|
|
prv::Provider* createProvider(const UnlocalizedString &unlocalizedName, bool skipLoadInterface, bool select) {
|
2022-08-06 22:29:59 +02:00
|
|
|
prv::Provider* result = nullptr;
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestCreateProvider::post(unlocalizedName, skipLoadInterface, select, &result);
|
2022-08-06 22:29:59 +02:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
namespace ImHexApi::System {
|
|
|
|
|
|
|
|
namespace impl {
|
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
// Default to true means we forward to ourselves by default
|
2023-07-13 14:08:23 +02:00
|
|
|
static bool s_isMainInstance = true;
|
|
|
|
void setMainInstanceStatus(bool status) {
|
|
|
|
s_isMainInstance = status;
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
static ImVec2 s_mainWindowPos;
|
|
|
|
static ImVec2 s_mainWindowSize;
|
2023-06-10 15:15:38 +02:00
|
|
|
void setMainWindowPosition(i32 x, i32 y) {
|
2024-01-30 11:21:34 +01:00
|
|
|
s_mainWindowPos = ImVec2(float(x), float(y));
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void setMainWindowSize(u32 width, u32 height) {
|
2024-01-30 11:21:34 +01:00
|
|
|
s_mainWindowSize = ImVec2(float(width), float(height));
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static ImGuiID s_mainDockSpaceId;
|
|
|
|
void setMainDockSpaceId(ImGuiID id) {
|
|
|
|
s_mainDockSpaceId = id;
|
|
|
|
}
|
|
|
|
|
2024-01-15 20:52:08 +01:00
|
|
|
static GLFWwindow *s_mainWindowHandle;
|
|
|
|
void setMainWindowHandle(GLFWwindow *window) {
|
|
|
|
s_mainWindowHandle = window;
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2022-05-27 20:42:07 +02:00
|
|
|
static float s_globalScale = 1.0;
|
2022-02-01 18:09:40 +01:00
|
|
|
void setGlobalScale(float scale) {
|
|
|
|
s_globalScale = scale;
|
|
|
|
}
|
|
|
|
|
2022-07-29 17:37:30 +02:00
|
|
|
static float s_nativeScale = 1.0;
|
|
|
|
void setNativeScale(float scale) {
|
|
|
|
s_nativeScale = scale;
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2022-02-15 23:07:48 +01:00
|
|
|
static bool s_borderlessWindowMode;
|
|
|
|
void setBorderlessWindowMode(bool enabled) {
|
|
|
|
s_borderlessWindowMode = enabled;
|
|
|
|
}
|
|
|
|
|
2024-01-28 22:14:59 +01:00
|
|
|
static bool s_multiWindowMode = false;
|
|
|
|
void setMultiWindowMode(bool enabled) {
|
|
|
|
s_multiWindowMode = enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::optional<InitialWindowProperties> s_initialWindowProperties;
|
|
|
|
void setInitialWindowProperties(InitialWindowProperties properties) {
|
|
|
|
s_initialWindowProperties = properties;
|
|
|
|
}
|
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
|
2024-01-30 11:21:34 +01:00
|
|
|
static AutoReset<std::string> s_gpuVendor;
|
2022-07-02 17:53:13 +02:00
|
|
|
void setGPUVendor(const std::string &vendor) {
|
|
|
|
s_gpuVendor = vendor;
|
|
|
|
}
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::map<std::string, std::string>> s_initArguments;
|
2022-09-19 16:54:19 +02:00
|
|
|
void addInitArgument(const std::string &key, const std::string &value) {
|
|
|
|
static std::mutex initArgumentsMutex;
|
|
|
|
std::scoped_lock lock(initArgumentsMutex);
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
(*s_initArguments)[key] = value;
|
2022-09-19 16:54:19 +02:00
|
|
|
}
|
|
|
|
|
2023-12-20 13:42:42 +01:00
|
|
|
static double s_lastFrameTime;
|
|
|
|
void setLastFrameTime(double time) {
|
|
|
|
s_lastFrameTime = time;
|
|
|
|
}
|
|
|
|
|
2024-01-21 18:39:51 +01:00
|
|
|
static bool s_windowResizable = true;
|
|
|
|
bool isWindowResizable() {
|
|
|
|
return s_windowResizable;
|
|
|
|
}
|
|
|
|
|
2024-02-21 00:06:52 +01:00
|
|
|
static std::vector<hex::impl::AutoResetBase*> s_autoResetObjects;
|
|
|
|
void addAutoResetObject(hex::impl::AutoResetBase *object) {
|
2024-02-19 22:06:46 +01:00
|
|
|
s_autoResetObjects.emplace_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cleanup() {
|
|
|
|
for (const auto &object : s_autoResetObjects)
|
|
|
|
object->reset();
|
|
|
|
}
|
|
|
|
|
2023-12-20 13:42:42 +01:00
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
2023-07-13 14:08:23 +02:00
|
|
|
bool isMainInstance() {
|
|
|
|
return impl::s_isMainInstance;
|
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
void closeImHex(bool noQuestions) {
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestCloseImHex::post(noQuestions);
|
2023-03-21 15:33:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void restartImHex() {
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestRestartImHex::post();
|
|
|
|
RequestCloseImHex::post(false);
|
2023-03-21 15:33:43 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-01-14 14:21:16 +01:00
|
|
|
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress) {
|
2023-12-08 10:29:44 +01:00
|
|
|
EventSetTaskBarIconState::post(u32(state), u32(type), progress);
|
2023-01-14 14:21:16 +01:00
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-04-13 17:12:40 +02:00
|
|
|
static float s_targetFPS = 14.0F;
|
2022-02-01 18:09:40 +01:00
|
|
|
|
|
|
|
float getTargetFPS() {
|
|
|
|
return s_targetFPS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setTargetFPS(float fps) {
|
|
|
|
s_targetFPS = fps;
|
|
|
|
}
|
|
|
|
|
|
|
|
float getGlobalScale() {
|
|
|
|
return impl::s_globalScale;
|
|
|
|
}
|
|
|
|
|
2022-07-29 17:37:30 +02:00
|
|
|
float getNativeScale() {
|
|
|
|
return impl::s_nativeScale;
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
|
|
|
|
ImVec2 getMainWindowPosition() {
|
2023-11-23 09:33:47 +01:00
|
|
|
if ((ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) != ImGuiConfigFlags_None)
|
|
|
|
return impl::s_mainWindowPos;
|
|
|
|
else
|
|
|
|
return { 0, 0 };
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImVec2 getMainWindowSize() {
|
|
|
|
return impl::s_mainWindowSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ImGuiID getMainDockSpaceId() {
|
|
|
|
return impl::s_mainDockSpaceId;
|
|
|
|
}
|
|
|
|
|
2024-01-15 20:52:08 +01:00
|
|
|
GLFWwindow* getMainWindowHandle() {
|
|
|
|
return impl::s_mainWindowHandle;
|
|
|
|
}
|
|
|
|
|
2022-02-15 23:07:48 +01:00
|
|
|
bool isBorderlessWindowModeEnabled() {
|
|
|
|
return impl::s_borderlessWindowMode;
|
|
|
|
}
|
|
|
|
|
2024-01-28 22:14:59 +01:00
|
|
|
bool isMutliWindowModeEnabled() {
|
|
|
|
return impl::s_multiWindowMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<InitialWindowProperties> getInitialWindowProperties() {
|
|
|
|
return impl::s_initialWindowProperties;
|
|
|
|
}
|
|
|
|
|
2024-03-12 23:17:49 +01:00
|
|
|
void* getLibImHexModuleHandle() {
|
2024-06-05 23:02:38 +02:00
|
|
|
return hex::getContainingModule(reinterpret_cast<void*>(&getLibImHexModuleHandle));
|
2024-03-12 23:17:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
const std::map<std::string, std::string>& getInitArguments() {
|
|
|
|
return *impl::s_initArguments;
|
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
std::string getInitArgument(const std::string &key) {
|
|
|
|
if (impl::s_initArguments->contains(key))
|
|
|
|
return impl::s_initArguments->at(key);
|
|
|
|
else
|
|
|
|
return "";
|
2022-02-01 18:09:40 +01:00
|
|
|
}
|
2022-07-02 16:22:38 +02:00
|
|
|
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
|
2022-07-02 16:22:38 +02:00
|
|
|
static bool s_systemThemeDetection;
|
|
|
|
void enableSystemThemeDetection(bool enabled) {
|
|
|
|
s_systemThemeDetection = enabled;
|
|
|
|
|
2023-12-08 10:29:44 +01:00
|
|
|
EventOSThemeChanged::post();
|
2022-07-02 16:22:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool usesSystemThemeDetection() {
|
|
|
|
return s_systemThemeDetection;
|
|
|
|
}
|
2022-07-02 17:53:13 +02:00
|
|
|
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::vector<std::fs::path>> s_additionalFolderPaths;
|
|
|
|
const std::vector<std::fs::path>& getAdditionalFolderPaths() {
|
|
|
|
return *s_additionalFolderPaths;
|
2022-07-02 17:53:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void setAdditionalFolderPaths(const std::vector<std::fs::path> &paths) {
|
2024-02-10 23:31:05 +01:00
|
|
|
s_additionalFolderPaths = paths;
|
2022-07-02 17:53:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const std::string &getGPUVendor() {
|
|
|
|
return impl::s_gpuVendor;
|
|
|
|
}
|
2022-08-01 14:51:08 +02:00
|
|
|
|
|
|
|
bool isPortableVersion() {
|
2024-02-11 13:46:06 +01:00
|
|
|
static std::optional<bool> portable;
|
|
|
|
if (portable.has_value())
|
|
|
|
return portable.value();
|
|
|
|
|
|
|
|
if (const auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) {
|
|
|
|
const auto flagFile = executablePath->parent_path() / "PORTABLE";
|
|
|
|
|
|
|
|
portable = wolv::io::fs::exists(flagFile) && wolv::io::fs::isRegularFile(flagFile);
|
|
|
|
} else {
|
|
|
|
portable = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return portable.value();
|
2022-08-01 14:51:08 +02:00
|
|
|
}
|
2023-06-20 11:55:56 +02:00
|
|
|
|
|
|
|
std::string getOSName() {
|
|
|
|
#if defined(OS_WINDOWS)
|
|
|
|
return "Windows";
|
|
|
|
#elif defined(OS_LINUX)
|
2024-03-21 21:31:17 +01:00
|
|
|
#if defined(OS_FREEBSD)
|
|
|
|
return "FreeBSD";
|
|
|
|
#else
|
|
|
|
return "Linux";
|
|
|
|
#endif
|
2023-06-20 11:55:56 +02:00
|
|
|
#elif defined(OS_MACOS)
|
|
|
|
return "macOS";
|
2023-10-04 12:00:32 +02:00
|
|
|
#elif defined(OS_WEB)
|
|
|
|
return "Web";
|
2023-06-20 11:55:56 +02:00
|
|
|
#else
|
|
|
|
return "Unknown";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getOSVersion() {
|
|
|
|
#if defined(OS_WINDOWS)
|
|
|
|
OSVERSIONINFOA info;
|
|
|
|
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
|
|
|
::GetVersionExA(&info);
|
|
|
|
|
|
|
|
return hex::format("{}.{}.{}", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber);
|
2023-10-04 12:00:32 +02:00
|
|
|
#elif defined(OS_LINUX) || defined(OS_MACOS) || defined(OS_WEB)
|
2024-01-30 11:21:34 +01:00
|
|
|
struct utsname details = { };
|
2023-06-20 11:55:56 +02:00
|
|
|
|
|
|
|
if (uname(&details) != 0) {
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::string(details.release) + " " + std::string(details.version);
|
|
|
|
#else
|
|
|
|
return "Unknown";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getArchitecture() {
|
|
|
|
#if defined(OS_WINDOWS)
|
|
|
|
SYSTEM_INFO info;
|
|
|
|
::GetNativeSystemInfo(&info);
|
|
|
|
|
|
|
|
switch (info.wProcessorArchitecture) {
|
|
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
|
|
return "x86_64";
|
|
|
|
case PROCESSOR_ARCHITECTURE_ARM:
|
|
|
|
return "ARM";
|
|
|
|
case PROCESSOR_ARCHITECTURE_ARM64:
|
|
|
|
return "ARM64";
|
|
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
|
|
return "IA64";
|
|
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
|
|
return "x86";
|
|
|
|
default:
|
|
|
|
return "Unknown";
|
|
|
|
}
|
2023-10-04 12:00:32 +02:00
|
|
|
#elif defined(OS_LINUX) || defined(OS_MACOS) || defined(OS_WEB)
|
2024-01-30 11:21:34 +01:00
|
|
|
struct utsname details = { };
|
2023-06-20 11:55:56 +02:00
|
|
|
|
|
|
|
if (uname(&details) != 0) {
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
2024-01-30 11:21:34 +01:00
|
|
|
return { details.machine };
|
2023-06-20 11:55:56 +02:00
|
|
|
#else
|
|
|
|
return "Unknown";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-06-03 10:02:29 +02:00
|
|
|
std::optional<LinuxDistro> getLinuxDistro() {
|
2024-06-05 23:02:38 +02:00
|
|
|
wolv::io::File file("/etc/os-release", wolv::io::File::Mode::Read);
|
2024-06-03 10:02:29 +02:00
|
|
|
std::string name;
|
|
|
|
std::string version;
|
|
|
|
|
2024-06-05 23:02:38 +02:00
|
|
|
auto fileContent = file.readString();
|
|
|
|
for (const auto &line : wolv::util::splitString(fileContent, "\n")) {
|
2024-06-03 10:02:29 +02:00
|
|
|
if (line.find("PRETTY_NAME=") != std::string::npos) {
|
|
|
|
name = line.substr(line.find("=") + 1);
|
2024-06-05 23:02:38 +02:00
|
|
|
std::erase(name, '\"');
|
2024-06-03 10:02:29 +02:00
|
|
|
} else if (line.find("VERSION_ID=") != std::string::npos) {
|
|
|
|
version = line.substr(line.find("=") + 1);
|
2024-06-05 23:02:38 +02:00
|
|
|
std::erase(version, '\"');
|
2024-06-03 10:02:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-05 23:02:38 +02:00
|
|
|
return { { name, version } };
|
2024-06-03 10:02:29 +02:00
|
|
|
}
|
|
|
|
|
2023-11-05 19:57:29 +01:00
|
|
|
std::string getImHexVersion(bool withBuildType) {
|
2023-06-26 14:01:45 +02:00
|
|
|
#if defined IMHEX_VERSION
|
2023-12-27 16:33:49 +01:00
|
|
|
if (withBuildType) {
|
2023-11-05 19:57:29 +01:00
|
|
|
return IMHEX_VERSION;
|
2023-12-27 16:33:49 +01:00
|
|
|
} else {
|
2023-11-05 19:57:29 +01:00
|
|
|
auto version = std::string(IMHEX_VERSION);
|
|
|
|
return version.substr(0, version.find('-'));
|
|
|
|
}
|
2023-06-26 14:01:45 +02:00
|
|
|
#else
|
|
|
|
return "Unknown";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getCommitHash(bool longHash) {
|
2024-02-10 02:40:33 +01:00
|
|
|
#if defined GIT_COMMIT_HASH_LONG
|
|
|
|
if (longHash) {
|
2023-06-26 14:01:45 +02:00
|
|
|
return GIT_COMMIT_HASH_LONG;
|
2024-02-10 02:40:33 +01:00
|
|
|
} else {
|
|
|
|
return std::string(GIT_COMMIT_HASH_LONG).substr(0, 7);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
hex::unused(longHash);
|
|
|
|
return "Unknown";
|
|
|
|
#endif
|
2023-06-26 14:01:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string getCommitBranch() {
|
|
|
|
#if defined GIT_BRANCH
|
|
|
|
return GIT_BRANCH;
|
|
|
|
#else
|
|
|
|
return "Unknown";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-10-22 23:39:14 +02:00
|
|
|
bool isDebugBuild() {
|
|
|
|
#if defined DEBUG
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-06-05 22:23:43 +02:00
|
|
|
bool isNightlyBuild() {
|
2024-06-05 20:59:48 +02:00
|
|
|
return getImHexVersion(false).ends_with("WIP");
|
|
|
|
}
|
|
|
|
|
2023-10-21 20:40:24 +02:00
|
|
|
bool updateImHex(UpdateType updateType) {
|
|
|
|
// Get the path of the updater executable
|
|
|
|
std::fs::path executablePath;
|
|
|
|
|
|
|
|
for (const auto &entry : std::fs::directory_iterator(wolv::io::fs::getExecutablePath()->parent_path())) {
|
|
|
|
if (entry.path().filename().string().starts_with("imhex-updater")) {
|
|
|
|
executablePath = entry.path();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (executablePath.empty() || !wolv::io::fs::exists(executablePath))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::string updateTypeString;
|
|
|
|
switch (updateType) {
|
|
|
|
case UpdateType::Stable:
|
|
|
|
updateTypeString = "latest";
|
|
|
|
break;
|
|
|
|
case UpdateType::Nightly:
|
|
|
|
updateTypeString = "nightly";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-12-08 10:29:44 +01:00
|
|
|
EventImHexClosing::subscribe([executablePath, updateTypeString] {
|
2023-10-21 20:40:24 +02:00
|
|
|
hex::executeCommand(
|
|
|
|
hex::format("{} {}",
|
|
|
|
wolv::util::toUTF8String(executablePath),
|
|
|
|
updateTypeString
|
|
|
|
)
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
ImHexApi::System::closeImHex();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-11-28 00:19:42 +01:00
|
|
|
void addStartupTask(const std::string &name, bool async, const std::function<bool()> &function) {
|
2023-12-08 10:29:44 +01:00
|
|
|
RequestAddInitTask::post(name, async, function);
|
2023-11-28 00:19:42 +01:00
|
|
|
}
|
|
|
|
|
2023-12-20 13:42:42 +01:00
|
|
|
double getLastFrameTime() {
|
|
|
|
return impl::s_lastFrameTime;
|
|
|
|
}
|
|
|
|
|
2024-01-21 18:39:51 +01:00
|
|
|
void setWindowResizable(bool resizable) {
|
2024-01-30 11:21:34 +01:00
|
|
|
glfwSetWindowAttrib(impl::s_mainWindowHandle, GLFW_RESIZABLE, int(resizable));
|
2024-01-21 18:39:51 +01:00
|
|
|
impl::s_windowResizable = resizable;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-12-20 13:42:42 +01:00
|
|
|
|
2021-12-16 23:48:52 +01:00
|
|
|
}
|
|
|
|
|
2023-07-13 14:08:23 +02:00
|
|
|
namespace ImHexApi::Messaging {
|
|
|
|
|
|
|
|
namespace impl {
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::map<std::string, MessagingHandler>> s_handlers;
|
|
|
|
const std::map<std::string, MessagingHandler>& getHandlers() {
|
|
|
|
return *s_handlers;
|
2023-07-13 14:08:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void runHandler(const std::string &eventName, const std::vector<u8> &args) {
|
2024-02-10 23:31:05 +01:00
|
|
|
const auto& handlers = getHandlers();
|
2024-01-30 11:21:34 +01:00
|
|
|
const auto matchHandler = handlers.find(eventName);
|
2023-07-13 14:08:23 +02:00
|
|
|
|
|
|
|
if (matchHandler == handlers.end()) {
|
|
|
|
log::error("Forward event handler {} not found", eventName);
|
|
|
|
} else {
|
|
|
|
matchHandler->second(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void registerHandler(const std::string &eventName, const impl::MessagingHandler &handler) {
|
|
|
|
log::debug("Registered new forward event handler: {}", eventName);
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_handlers->insert({ eventName, handler });
|
2023-07-13 14:08:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-11-28 01:55:41 +01:00
|
|
|
namespace ImHexApi::Fonts {
|
|
|
|
|
|
|
|
namespace impl {
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
static AutoReset<std::vector<Font>> s_fonts;
|
|
|
|
const std::vector<Font>& getFonts() {
|
|
|
|
return *s_fonts;
|
2023-11-28 01:55:41 +01:00
|
|
|
}
|
|
|
|
|
2024-01-30 11:21:34 +01:00
|
|
|
static AutoReset<std::fs::path> s_customFontPath;
|
2023-11-29 23:47:37 +01:00
|
|
|
void setCustomFontPath(const std::fs::path &path) {
|
|
|
|
s_customFontPath = path;
|
|
|
|
}
|
|
|
|
|
|
|
|
static float s_fontSize = DefaultFontSize;
|
|
|
|
void setFontSize(float size) {
|
|
|
|
s_fontSize = size;
|
|
|
|
}
|
|
|
|
|
2024-03-26 19:48:38 +01:00
|
|
|
static AutoReset<std::shared_ptr<ImFontAtlas>> s_fontAtlas;
|
2023-11-29 23:47:37 +01:00
|
|
|
void setFontAtlas(ImFontAtlas* fontAtlas) {
|
2024-03-26 19:48:38 +01:00
|
|
|
s_fontAtlas = std::unique_ptr<ImFontAtlas, void(*)(ImFontAtlas*)>(fontAtlas, IM_DELETE);
|
2023-11-29 23:47:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static ImFont *s_boldFont = nullptr;
|
|
|
|
static ImFont *s_italicFont = nullptr;
|
|
|
|
void setFonts(ImFont *bold, ImFont *italic) {
|
|
|
|
s_boldFont = bold;
|
|
|
|
s_italicFont = italic;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-11-28 01:55:41 +01:00
|
|
|
}
|
|
|
|
|
2023-11-28 13:52:26 +01:00
|
|
|
GlyphRange glyph(const char *glyph) {
|
|
|
|
u32 codepoint;
|
|
|
|
ImTextCharFromUtf8(&codepoint, glyph, nullptr);
|
|
|
|
|
|
|
|
return {
|
|
|
|
.begin = u16(codepoint),
|
|
|
|
.end = u16(codepoint)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
GlyphRange glyph(u32 codepoint) {
|
|
|
|
return {
|
|
|
|
.begin = u16(codepoint),
|
|
|
|
.end = u16(codepoint)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
GlyphRange range(const char *glyphBegin, const char *glyphEnd) {
|
|
|
|
u32 codepointBegin, codepointEnd;
|
|
|
|
ImTextCharFromUtf8(&codepointBegin, glyphBegin, nullptr);
|
|
|
|
ImTextCharFromUtf8(&codepointEnd, glyphEnd, nullptr);
|
|
|
|
|
|
|
|
return {
|
|
|
|
.begin = u16(codepointBegin),
|
|
|
|
.end = u16(codepointEnd)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
GlyphRange range(u32 codepointBegin, u32 codepointEnd) {
|
|
|
|
return {
|
|
|
|
.begin = u16(codepointBegin),
|
|
|
|
.end = u16(codepointEnd)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-03-21 21:27:50 +01:00
|
|
|
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags, std::optional<u32> defaultSize) {
|
2023-11-28 01:55:41 +01:00
|
|
|
wolv::io::File fontFile(path, wolv::io::File::Mode::Read);
|
|
|
|
if (!fontFile.isValid()) {
|
|
|
|
log::error("Failed to load font from file '{}'", wolv::util::toUTF8String(path));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_fonts->emplace_back(Font {
|
2023-11-28 01:55:41 +01:00
|
|
|
wolv::util::toUTF8String(path.filename()),
|
|
|
|
fontFile.readVector(),
|
|
|
|
glyphRanges,
|
2023-11-28 13:52:26 +01:00
|
|
|
offset,
|
2024-03-21 21:27:50 +01:00
|
|
|
flags,
|
|
|
|
defaultSize
|
2023-11-28 01:55:41 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-03-21 21:27:50 +01:00
|
|
|
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags, std::optional<u32> defaultSize) {
|
2024-02-10 23:31:05 +01:00
|
|
|
impl::s_fonts->emplace_back(Font {
|
2023-11-28 01:55:41 +01:00
|
|
|
name,
|
|
|
|
{ data.begin(), data.end() },
|
|
|
|
glyphRanges,
|
2023-11-28 13:52:26 +01:00
|
|
|
offset,
|
2024-03-21 21:27:50 +01:00
|
|
|
flags,
|
|
|
|
defaultSize
|
2023-11-28 01:55:41 +01:00
|
|
|
});
|
|
|
|
}
|
2023-11-29 23:47:37 +01:00
|
|
|
|
2024-02-10 23:31:05 +01:00
|
|
|
const std::fs::path& getCustomFontPath() {
|
2023-11-29 23:47:37 +01:00
|
|
|
return impl::s_customFontPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
float getFontSize() {
|
|
|
|
return impl::s_fontSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImFontAtlas* getFontAtlas() {
|
2024-01-30 11:21:34 +01:00
|
|
|
return impl::s_fontAtlas->get();
|
2023-11-29 23:47:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImFont* Bold() {
|
|
|
|
return impl::s_boldFont;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImFont* Italic() {
|
|
|
|
return impl::s_italicFont;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-11-28 01:55:41 +01:00
|
|
|
}
|
|
|
|
|
2021-12-22 13:16:51 +01:00
|
|
|
}
|