mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-27 14:25:34 +00:00
Compare commits
15
Commits
@@ -72,6 +72,7 @@ target_sources(applib PRIVATE
|
||||
storage_property_repository.cpp
|
||||
storage_property_repository.h
|
||||
storage_settings.h
|
||||
warning_colors.cpp
|
||||
warning_colors.h
|
||||
warning_level.h
|
||||
window_instance_manager.h
|
||||
|
||||
@@ -165,6 +165,29 @@ bool gui_show_text_entry_dialog(const std::string& title, const std::string& mes
|
||||
|
||||
|
||||
|
||||
bool gui_is_dark_theme_active()
|
||||
{
|
||||
// Try to get the GTK settings to check for dark theme preference.
|
||||
// If GTK is not available or not initialized, get_default() will return null.
|
||||
const Glib::RefPtr<Gtk::Settings> settings = Gtk::Settings::get_default();
|
||||
if (settings) {
|
||||
// Check if the application prefers dark theme
|
||||
if (settings->property_gtk_application_prefer_dark_theme().get_value()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check theme name for common dark theme identifiers
|
||||
Glib::ustring theme_name;
|
||||
settings->get_property("gtk-theme-name", theme_name);
|
||||
const std::string theme_str = theme_name.lowercase();
|
||||
if (theme_str.find("dark") != std::string::npos ||
|
||||
theme_str.find("black") != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -58,8 +58,8 @@ bool gui_show_text_entry_dialog(const std::string& title, const std::string& mes
|
||||
std::string& result, const std::string& default_str, Gtk::Window* parent = nullptr, bool sec_msg_markup = false);
|
||||
|
||||
|
||||
|
||||
|
||||
/// Check if a dark GTK theme is currently active
|
||||
bool gui_is_dark_theme_active();
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/******************************************************************************
|
||||
License: GNU General Public License v3.0 only
|
||||
Copyright:
|
||||
(C) 2008 - 2026 Alexander Shaduri <ashaduri@gmail.com>
|
||||
******************************************************************************/
|
||||
/// \file
|
||||
/// \author Alexander Shaduri
|
||||
/// \ingroup applib
|
||||
/// \weakgroup applib
|
||||
/// @{
|
||||
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "warning_colors.h"
|
||||
#include "gui_utils.h"
|
||||
|
||||
|
||||
bool app_property_get_row_highlight_colors(bool dark_mode, WarningLevel warning, std::string& fg, std::string& bg)
|
||||
{
|
||||
// Note: we're setting both fg and bg, to avoid theme conflicts.
|
||||
if (warning == WarningLevel::Notice) {
|
||||
fg = dark_mode ? "#FFFFFF" : "#000000"; // white for dark themes, black for light themes
|
||||
bg = dark_mode ? "#6B2050" : "#FFD5EE"; // dark pinkish for dark themes, pinkish for light themes
|
||||
|
||||
} else if (warning == WarningLevel::Warning) {
|
||||
fg = dark_mode ? "#FFFFFF" : "#000000"; // white for dark themes, black for light themes
|
||||
bg = dark_mode ? "#802020" : "#FFA0A0"; // dark red for dark themes, light red for light themes
|
||||
|
||||
} else if (warning == WarningLevel::Alert) {
|
||||
fg = dark_mode ? "#FFFFFF" : "#000000"; // white for dark themes, black for light themes
|
||||
bg = dark_mode ? "#AA0000" : "#FF0000"; // darker red for dark themes, bright red for light themes
|
||||
}
|
||||
|
||||
return !(fg.empty());
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool app_property_get_label_highlight_color(bool dark_mode, WarningLevel warning, std::string& fg)
|
||||
{
|
||||
if (warning == WarningLevel::None) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (warning == WarningLevel::Notice) {
|
||||
fg = dark_mode ? "#FF9999" : "#770000"; // lighter red for dark themes, very dark red for light themes
|
||||
|
||||
} else if (warning == WarningLevel::Warning) {
|
||||
fg = dark_mode ? "#FF6666" : "#C00000"; // lighter red for dark themes, dark red for light themes
|
||||
|
||||
} else if (warning == WarningLevel::Alert) {
|
||||
fg = dark_mode ? "#FF4444" : "#FF0000"; // lighter/pink red for dark themes, bright red for light themes
|
||||
}
|
||||
|
||||
return !(fg.empty());
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string storage_property_get_warning_reason(const StorageProperty& p)
|
||||
{
|
||||
std::string fg, start = "<b>", stop = "</b>";
|
||||
if (app_property_get_label_highlight_color(gui_is_dark_theme_active(), p.warning_level, fg)) {
|
||||
start += "<span color=\"" + fg + "\">";
|
||||
stop = "</span>" + stop;
|
||||
}
|
||||
|
||||
switch (p.warning_level) {
|
||||
case WarningLevel::None:
|
||||
// nothing
|
||||
break;
|
||||
case WarningLevel::Notice:
|
||||
/// Translators: %1 and %2 are HTML tags, %3 is a message.
|
||||
return Glib::ustring::compose(_("%1Notice:%2 %3"), start, stop, Glib::Markup::escape_text(p.warning_reason));
|
||||
case WarningLevel::Warning:
|
||||
/// Translators: %1 and %2 are HTML tags, %3 is a message.
|
||||
return Glib::ustring::compose(_("%1Warning:%2 %3"), start, stop, Glib::Markup::escape_text(p.warning_reason));
|
||||
case WarningLevel::Alert:
|
||||
/// Translators: %1 and %2 are HTML tags, %3 is a message.
|
||||
return Glib::ustring::compose(_("%1ALERT:%2 %3"), start, stop, Glib::Markup::escape_text(p.warning_reason));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @}
|
||||
@@ -1,7 +1,7 @@
|
||||
/******************************************************************************
|
||||
License: GNU General Public License v3.0 only
|
||||
Copyright:
|
||||
(C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
|
||||
(C) 2008 - 2026 Alexander Shaduri <ashaduri@gmail.com>
|
||||
******************************************************************************/
|
||||
/// \file
|
||||
/// \author Alexander Shaduri
|
||||
@@ -12,83 +12,24 @@ Copyright:
|
||||
#ifndef WARNING_COLORS_H
|
||||
#define WARNING_COLORS_H
|
||||
|
||||
#include <glibmm.h>
|
||||
#include <string>
|
||||
|
||||
#include "storage_property.h"
|
||||
|
||||
#include "warning_level.h"
|
||||
|
||||
|
||||
/// Get colors for tree rows according to warning severity.
|
||||
/// \return true if the colors were changed.
|
||||
inline bool app_property_get_row_highlight_colors(WarningLevel warning, std::string& fg, std::string& bg)
|
||||
{
|
||||
// Note: we're setting both fg and bg, to avoid theme conflicts.
|
||||
if (warning == WarningLevel::Notice) {
|
||||
fg = "#000000"; // black
|
||||
bg = "#FFD5EE"; // pinkish
|
||||
|
||||
} else if (warning == WarningLevel::Warning) {
|
||||
fg = "#000000"; // black
|
||||
bg = "#FFA0A0"; // even more pinkish
|
||||
|
||||
} else if (warning == WarningLevel::Alert) {
|
||||
fg = "#000000"; // black
|
||||
bg = "#FF0000"; // red
|
||||
}
|
||||
|
||||
return !(fg.empty());
|
||||
}
|
||||
|
||||
bool app_property_get_row_highlight_colors(bool dark_mode, WarningLevel warning, std::string& fg, std::string& bg);
|
||||
|
||||
|
||||
/// Get color for labels according to warning severity.
|
||||
/// \return true if the color was changed.
|
||||
inline bool app_property_get_label_highlight_color(WarningLevel warning, std::string& fg)
|
||||
{
|
||||
if (warning == WarningLevel::Notice) {
|
||||
fg = "#770000"; // very dark red
|
||||
|
||||
} else if (warning == WarningLevel::Warning) {
|
||||
fg = "#C00000"; // dark red
|
||||
|
||||
} else if (warning == WarningLevel::Alert) {
|
||||
fg = "#FF0000"; // red
|
||||
}
|
||||
|
||||
return !(fg.empty());
|
||||
}
|
||||
|
||||
|
||||
bool app_property_get_label_highlight_color(bool dark_mode, WarningLevel warning, std::string& fg);
|
||||
|
||||
|
||||
/// Format warning text, but without description
|
||||
inline std::string storage_property_get_warning_reason(const StorageProperty& p)
|
||||
{
|
||||
std::string fg, start = "<b>", stop = "</b>";
|
||||
if (app_property_get_label_highlight_color(p.warning_level, fg)) {
|
||||
start += "<span color=\"" + fg + "\">";
|
||||
stop = "</span>" + stop;
|
||||
}
|
||||
|
||||
switch (p.warning_level) {
|
||||
case WarningLevel::None:
|
||||
// nothing
|
||||
break;
|
||||
case WarningLevel::Notice:
|
||||
/// Translators: %1 and %2 are HTML tags, %3 is a message.
|
||||
return Glib::ustring::compose(_("%1Notice:%2 %3"), start, stop, Glib::Markup::escape_text(p.warning_reason));
|
||||
case WarningLevel::Warning:
|
||||
/// Translators: %1 and %2 are HTML tags, %3 is a message.
|
||||
return Glib::ustring::compose(_("%1Warning:%2 %3"), start, stop, Glib::Markup::escape_text(p.warning_reason));
|
||||
case WarningLevel::Alert:
|
||||
/// Translators: %1 and %2 are HTML tags, %3 is a message.
|
||||
return Glib::ustring::compose(_("%1ALERT:%2 %3"), start, stop, Glib::Markup::escape_text(p.warning_reason));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
std::string storage_property_get_warning_reason(const StorageProperty& p);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace {
|
||||
// vbox->pack_start(*label, false, false);
|
||||
|
||||
} else {
|
||||
const bool dark_mode = gui_is_dark_theme_active();
|
||||
|
||||
// add one label per element
|
||||
for (const auto& label_string : label_strings) {
|
||||
@@ -95,7 +96,7 @@ namespace {
|
||||
label->set_can_focus(false);
|
||||
|
||||
std::string fg;
|
||||
if (app_property_get_label_highlight_color(label_string.property->warning_level, fg)) {
|
||||
if (app_property_get_label_highlight_color(dark_mode, label_string.property->warning_level, fg)) {
|
||||
label->set_markup(
|
||||
std::string("<span color=\"").append(fg).append("\">")
|
||||
.append(label_text).append("</span>") );
|
||||
@@ -129,7 +130,7 @@ namespace {
|
||||
}
|
||||
|
||||
std::string fg;
|
||||
if (app_property_get_label_highlight_color(warning, fg))
|
||||
if (app_property_get_label_highlight_color(gui_is_dark_theme_active(), warning, fg))
|
||||
label->set_markup_with_mnemonic("<span color=\"" + fg + "\">" + original_label + "</span>");
|
||||
}
|
||||
|
||||
@@ -1038,6 +1039,7 @@ void GscInfoWindow::fill_ui_general(const StoragePropertyRepository& property_re
|
||||
identity_table->hide();
|
||||
|
||||
WarningLevel max_tab_warning = WarningLevel::None;
|
||||
const bool dark_mode = gui_is_dark_theme_active();
|
||||
int row = 0;
|
||||
|
||||
for (auto&& p : general_props) {
|
||||
@@ -1070,7 +1072,7 @@ void GscInfoWindow::fill_ui_general(const StoragePropertyRepository& property_re
|
||||
value->set_markup(Glib::Markup::escape_text(p.format_value()));
|
||||
|
||||
std::string fg;
|
||||
if (app_property_get_label_highlight_color(p.warning_level, fg)) {
|
||||
if (app_property_get_label_highlight_color(dark_mode, p.warning_level, fg)) {
|
||||
name->set_markup("<span color=\"" + fg + "\">" + name->get_label() + "</span>");
|
||||
value->set_markup("<span color=\"" + fg + "\">" + value->get_label() + "</span>");
|
||||
}
|
||||
@@ -2067,7 +2069,7 @@ WarningLevel GscInfoWindow::fill_ui_directory(const StoragePropertyRepository& p
|
||||
inline void cell_renderer_set_warning_fg_bg(Gtk::CellRendererText* crt, const StorageProperty& p)
|
||||
{
|
||||
std::string fg, bg;
|
||||
if (app_property_get_row_highlight_colors(p.warning_level, fg, bg)) {
|
||||
if (app_property_get_row_highlight_colors(gui_is_dark_theme_active(), p.warning_level, fg, bg)) {
|
||||
// Note: property_cell_background makes horizontal tree lines disappear around it,
|
||||
// but property_background doesn't play nice with sorted column color.
|
||||
crt->property_cell_background() = bg;
|
||||
@@ -2444,7 +2446,11 @@ gboolean GscInfoWindow::test_idle_callback(void* data)
|
||||
break;
|
||||
case SelfTestStatusSeverity::Error:
|
||||
if (!result_main_msg.empty()) { // Highlight in red
|
||||
result_main_msg = "<span color=\"#FF0000\">"s + result_main_msg + "</span>";
|
||||
std::string alert_color;
|
||||
// Use the same color as Alert level warnings for consistency
|
||||
if (app_property_get_label_highlight_color(WarningLevel::Alert, alert_color) && !alert_color.empty()) {
|
||||
result_main_msg = "<span color=\"" + alert_color + "\">"s + result_main_msg + "</span>";
|
||||
}
|
||||
}
|
||||
result_details_msg += "\n"s + _("Check the Self-Test Log for more information.");
|
||||
break;
|
||||
|
||||
@@ -505,6 +505,32 @@ bool app_init_and_loop(int& argc, char**& argv)
|
||||
}
|
||||
*/
|
||||
|
||||
// Detect Windows dark mode and set GTK theme preference accordingly
|
||||
if constexpr(BuildEnv::is_kernel_family_windows()) {
|
||||
Glib::RefPtr<Gtk::Settings> gtk_settings = Gtk::Settings::get_default();
|
||||
if (gtk_settings) {
|
||||
bool use_dark_theme = false;
|
||||
#ifdef _WIN32
|
||||
// Check Windows registry for dark mode preference
|
||||
// HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize
|
||||
// AppsUseLightTheme = 0 means dark mode, 1 means light mode
|
||||
DWORD apps_use_light_theme = 1; // Default to light mode
|
||||
if (hz::win32_get_registry_value_dword(HKEY_CURRENT_USER,
|
||||
R"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)",
|
||||
"AppsUseLightTheme", apps_use_light_theme)) {
|
||||
use_dark_theme = (apps_use_light_theme == 0);
|
||||
debug_out_dump("app", "Windows theme detected: " << (use_dark_theme ? "dark" : "light") << "\n");
|
||||
} else {
|
||||
debug_out_dump("app", "Could not read Windows theme preference, defaulting to light mode.\n");
|
||||
}
|
||||
#endif
|
||||
// Apply the dark theme preference to GTK
|
||||
gtk_settings->property_gtk_application_prefer_dark_theme().set_value(use_dark_theme);
|
||||
debug_out_dump("app", "GTK dark theme preference set to: " << (use_dark_theme ? "dark" : "light") << "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The application is dpi-aware in Windows.
|
||||
// However, Gtk3 does not support fractional scaling, so at 250% scaling in system settings, the UI will use 200%.
|
||||
//
|
||||
|
||||
@@ -774,7 +774,7 @@ void GscMainWindow::update_status_widgets()
|
||||
if (health_prop.generic_name == "smart_status/passed") {
|
||||
health_label_->set_text(health_prop.format_value());
|
||||
std::string fg;
|
||||
if (app_property_get_label_highlight_color(health_prop.warning_level, fg)) {
|
||||
if (app_property_get_label_highlight_color(gui_is_dark_theme_active(), health_prop.warning_level, fg)) {
|
||||
health_label_->set_markup("<span color=\"" + fg + "\">"+ Glib::Markup::escape_text(health_label_->get_text()) + "</span>");
|
||||
}
|
||||
// don't set description tooltip - we already have the basic one.
|
||||
|
||||
@@ -120,7 +120,7 @@ bool GscMainWindowIconView::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
|
||||
return true;
|
||||
}
|
||||
if (empty_view_message_ != Message::None && this->num_icons_ == 0) { // no icons
|
||||
Glib::RefPtr<Pango::Layout> layout = this->create_pango_layout("");
|
||||
const Glib::RefPtr<Pango::Layout> layout = this->create_pango_layout("");
|
||||
layout->set_alignment(Pango::ALIGN_CENTER);
|
||||
layout->set_markup(get_message_string(empty_view_message_));
|
||||
|
||||
@@ -131,6 +131,12 @@ bool GscMainWindowIconView::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
|
||||
const int pos_y = (get_allocation().get_height() - layout_h) / 2;
|
||||
cr->move_to(pos_x, pos_y);
|
||||
|
||||
// Use the foreground color from the widget's style context so
|
||||
// the text is visible in both light and dark themes.
|
||||
const auto style_context = get_style_context();
|
||||
const Gdk::RGBA fg_color = style_context->get_color(style_context->get_state());
|
||||
cr->set_source_rgba(fg_color.get_red(), fg_color.get_green(), fg_color.get_blue(), fg_color.get_alpha());
|
||||
|
||||
layout->show_in_cairo_context(cr);
|
||||
|
||||
return true;
|
||||
|
||||
+3
-116
@@ -21,11 +21,6 @@ Copyright:
|
||||
#include "win32_tools.h" // hz::win32_utf8_to_utf16
|
||||
#else
|
||||
#include <memory>
|
||||
#include <unistd.h> // geteuid, fork, execvp, setuid, setgid
|
||||
#include <sys/types.h> // uid_t, gid_t
|
||||
#include <sys/wait.h> // waitpid
|
||||
#include <pwd.h> // getpwuid
|
||||
#include "env_tools.h" // hz::env_get_value
|
||||
#endif
|
||||
|
||||
|
||||
@@ -34,89 +29,6 @@ Copyright:
|
||||
namespace hz {
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/// Launch URL as the original user when running as root.
|
||||
/// This is needed because gtk_show_uri_on_window() doesn't work when running as root
|
||||
/// (D-Bus session is not accessible).
|
||||
/// \return error message on error, empty string on success.
|
||||
inline std::string launch_url_as_original_user(const std::string& link)
|
||||
{
|
||||
// Get the original user's UID from environment variables
|
||||
// SUDO_UID is set by sudo, PKEXEC_UID is set by pkexec
|
||||
std::string uid_str;
|
||||
uid_t original_uid = 0;
|
||||
gid_t original_gid = 0;
|
||||
|
||||
if (hz::env_get_value("SUDO_UID", uid_str) || hz::env_get_value("PKEXEC_UID", uid_str)) {
|
||||
try {
|
||||
original_uid = static_cast<uid_t>(std::stoul(uid_str));
|
||||
} catch (...) {
|
||||
return "Cannot parse original user UID";
|
||||
}
|
||||
|
||||
// Get the original user's GID
|
||||
struct passwd* pw = getpwuid(original_uid);
|
||||
if (pw) {
|
||||
original_gid = pw->pw_gid;
|
||||
} else {
|
||||
return "Cannot get original user information";
|
||||
}
|
||||
} else {
|
||||
return "Cannot determine original user UID";
|
||||
}
|
||||
|
||||
// Fork and execute xdg-open as the original user
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
return "Cannot fork process";
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
// Child process
|
||||
|
||||
// Restore HOME environment variable if available
|
||||
// This helps xdg-open find the correct configuration
|
||||
std::string sudo_user;
|
||||
if (hz::env_get_value("SUDO_USER", sudo_user)) {
|
||||
struct passwd* pw = getpwnam(sudo_user.c_str());
|
||||
if (pw && pw->pw_dir) {
|
||||
setenv("HOME", pw->pw_dir, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Drop privileges to original user
|
||||
// Set GID first, then UID (order matters for security)
|
||||
if (setgid(original_gid) != 0) {
|
||||
_exit(1);
|
||||
}
|
||||
if (setuid(original_uid) != 0) {
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
// Execute xdg-open with the URL
|
||||
const char* argv[] = {"xdg-open", link.c_str(), nullptr};
|
||||
execvp("xdg-open", const_cast<char* const*>(argv));
|
||||
|
||||
// If execvp returns, it failed
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
// Parent process - wait for child
|
||||
int status = 0;
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
return "Cannot wait for child process";
|
||||
}
|
||||
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
|
||||
return {}; // Success
|
||||
}
|
||||
|
||||
return "xdg-open failed to launch URL";
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
/// Open URL in browser or mailto: link in mail client.
|
||||
/// Return error message on error, empty string otherwise.
|
||||
@@ -138,41 +50,16 @@ inline std::string launch_url([[maybe_unused]] GtkWindow* window, const std::str
|
||||
#else
|
||||
|
||||
GError* error = nullptr;
|
||||
bool status = false;
|
||||
|
||||
// Check if running as root
|
||||
bool is_root = (geteuid() == 0);
|
||||
|
||||
// If running as root, try to launch as the original user first
|
||||
if (is_root) {
|
||||
std::string result = launch_url_as_original_user(link);
|
||||
if (result.empty()) {
|
||||
return {}; // Success
|
||||
}
|
||||
// If launching as original user failed, fall through to try GTK method
|
||||
}
|
||||
|
||||
// Try the standard GTK method
|
||||
#if GTK_CHECK_VERSION(3, 22, 0)
|
||||
status = static_cast<bool>(gtk_show_uri_on_window(window, link.c_str(), GDK_CURRENT_TIME, &error));
|
||||
bool status = static_cast<bool>(gtk_show_uri_on_window(window, link.c_str(), GDK_CURRENT_TIME, &error));
|
||||
#else
|
||||
GdkScreen* screen = (window ? gtk_window_get_screen(window) : nullptr);
|
||||
status = static_cast<bool>(gtk_show_uri(screen, link.c_str(), GDK_CURRENT_TIME, &error));
|
||||
bool status = static_cast<bool>(gtk_show_uri(screen, link.c_str(), GDK_CURRENT_TIME, &error));
|
||||
#endif
|
||||
std::unique_ptr<GError, decltype(&g_error_free)> uerror(error, &g_error_free);
|
||||
|
||||
if (!status) {
|
||||
// GTK method failed. If running as root, we already tried the fallback.
|
||||
// Otherwise, try the fallback now.
|
||||
if (!is_root) {
|
||||
std::string result = launch_url_as_original_user(link);
|
||||
if (result.empty()) {
|
||||
return {}; // Success
|
||||
}
|
||||
}
|
||||
|
||||
// Both methods failed, return error
|
||||
return std::string("Cannot open URL")
|
||||
return std::string("Cannot open URL: ")
|
||||
+ ((error && error->message) ? (std::string(": ") + error->message) : ".");
|
||||
}
|
||||
return {};
|
||||
|
||||
@@ -79,6 +79,14 @@ inline bool win32_set_registry_value_string(HKEY base,
|
||||
const std::string& keydir, const std::string& key, const std::string& value);
|
||||
|
||||
|
||||
/// Get registry value as a DWORD.
|
||||
/// Base may be e.g. HKEY_CURRENT_USER.
|
||||
/// Note that this works only with REG_DWORD types.
|
||||
/// False is returned for all other types.
|
||||
inline bool win32_get_registry_value_dword(HKEY base,
|
||||
const std::string& keydir, const std::string& key, DWORD& put_here);
|
||||
|
||||
|
||||
/// Redirect stdout and stderr to console window (if open). Requires winxp (at compile-time).
|
||||
/// \param create_if_none if true, create a new console if none was found and attach to it.
|
||||
/// \return false if failed or unsupported.
|
||||
@@ -340,6 +348,49 @@ inline bool win32_set_registry_value_string(HKEY base,
|
||||
|
||||
|
||||
|
||||
// Get registry value as a DWORD.
|
||||
// Note that this works only with REG_DWORD types.
|
||||
inline bool win32_get_registry_value_dword(HKEY base,
|
||||
const std::string& keydir, const std::string& key, DWORD& put_here)
|
||||
{
|
||||
std::wstring wkeydir = win32_utf8_to_utf16(keydir);
|
||||
if (wkeydir.empty())
|
||||
return false;
|
||||
|
||||
HKEY reg_key = nullptr;
|
||||
bool open_status = (RegOpenKeyExW(base, wkeydir.c_str(), 0, KEY_QUERY_VALUE, ®_key) == ERROR_SUCCESS);
|
||||
|
||||
if (!open_status)
|
||||
return false;
|
||||
|
||||
bool ok = false;
|
||||
std::wstring wkey = win32_utf8_to_utf16(key, &ok);
|
||||
if (!ok) { // conversion error. Note that an empty string is not an error.
|
||||
if (reg_key)
|
||||
RegCloseKey(reg_key);
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD type = 0;
|
||||
DWORD value = 0;
|
||||
DWORD nbytes = sizeof(DWORD);
|
||||
bool status = (RegQueryValueExW(reg_key, wkey.c_str(), nullptr, &type,
|
||||
reinterpret_cast<BYTE*>(&value), &nbytes) == ERROR_SUCCESS);
|
||||
|
||||
if (status && type == REG_DWORD) {
|
||||
put_here = value;
|
||||
} else {
|
||||
status = false;
|
||||
}
|
||||
|
||||
if (reg_key)
|
||||
RegCloseKey(reg_key);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Redirect stdout and stderr to console window (if open).
|
||||
inline bool win32_redirect_stdio_to_console(bool create_if_none)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user