Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
c35cee0
Move (some) menu command handling to NotifyIcon
res2k Jun 23, 2024
1cca574
Internally rename 'autostart' to 'login startup'
res2k Jun 23, 2024
da98d47
Move 'login startup' config into separate class
res2k Jun 23, 2024
7312f43
HDRCmd: Add ability to change 'startup when logging in'
res2k Jun 23, 2024
65a5e20
Add docs for new 'status' HDRCmd command
res2k Jun 23, 2024
60f0800
Rename hdr::Display to hdr::DisplayInfo
res2k Jun 23, 2024
418f074
Add & use hdr::DisplayID internal type
res2k Jun 30, 2024
7f0331f
Make hdr::DisplayID public
res2k Jun 30, 2024
4cd40ae
Change hdr::DisplayInfo to lazily return status, name
res2k Jun 30, 2024
6bb79cd
Implement hdr::GetWindowsHDRStatus() using GetDisplays()
res2k Jun 30, 2024
aaf61eb
Add hdr::DisplayInfo::GetID()
res2k Jun 30, 2024
3c97dd6
Implement hdr::SetWindowsHDRStatus() using GetDisplays()
res2k Jun 30, 2024
10d2679
Change HDR functions to take explicit displays list
res2k Jun 30, 2024
e8e7204
Store DisplayInfo errors as HRESULT
res2k Jun 30, 2024
517f0f5
Add DisplayInfo::GetStableID()
res2k Jun 30, 2024
13678f1
Statically allocate LoginStartupConfig
res2k Jul 7, 2024
f2d5cb2
Add RegistryKey move ctors, assignment
res2k Jul 7, 2024
3a2bf8f
Add RegistryKey::GetValue()
res2k Jul 7, 2024
470481e
Add DisplayConfig class
res2k Jul 7, 2024
14c8116
HDRCmd: Move some status functions to separate source
res2k Jul 7, 2024
08ac810
Print whether a display is 'selected' or not in long status
res2k Jul 7, 2024
f90b976
Add 'index' to DisplayInfo
res2k Jul 7, 2024
1d619f3
HDRCmd: Implement 'select' subcommand to toggle which displays to inc…
res2k Jul 7, 2024
6b2ba6c
Add hdr::GetEnabledDisplays()
res2k Aug 11, 2024
e3ad745
HDRCmd: Add subcommand base class for those involving displays
res2k Aug 11, 2024
d7c84d7
Add DisplayID::operator==
res2k Aug 11, 2024
240ec4e
HDRCmd: Add displays argument to on, off commands
res2k Aug 11, 2024
66ed2f0
HDRCmd: Only consider selected displays for short, exitcode status
res2k Aug 11, 2024
28a2d9e
HDRTray: Only consider selected displays for notification icon
res2k Aug 11, 2024
34772c0
common: Expose registry path used by DisplayConfig
res2k Aug 11, 2024
9acd3c6
HDRTray: Add watcher for display config changes
res2k Aug 11, 2024
51865bb
common: Add RegistryKey::Open()
res2k Aug 11, 2024
97a218d
common: Only 'open' registry key when querying enabled flag
res2k Aug 11, 2024
dc333d0
Add documentation on display selection
res2k Aug 11, 2024
88bc75c
Bump minimum required Windows to 10 1809
res2k Aug 11, 2024
e50499a
Add winui3_cmake as a submodule
res2k Dec 14, 2024
5e58680
Add mock-up HDRTrayConfig
res2k Dec 14, 2024
368e256
Move version.h to common
res2k Dec 20, 2024
ac6955e
Add some more fields to version.h
res2k Dec 20, 2024
c6dc916
Add actual version number to HDRTrayConfig About
res2k Dec 20, 2024
0179021
Add IsOn property to ToggleCard
res2k Dec 20, 2024
a194576
Expose Toggled event from ToggleCard
res2k Dec 21, 2024
b7bed6c
Use generated winrt headers for common
res2k Dec 21, 2024
0bc466d
Fix warning when using 'common' in HDRTrayConfig
res2k Dec 21, 2024
b118cbe
Add HDRViewModel class, use as member of App
res2k Dec 21, 2024
b99f051
Update HDR status on display change
res2k Dec 21, 2024
3664d4c
Hook up HDR toggling to HDRPage
res2k Dec 22, 2024
8da67b6
Programmatically get list of displays
res2k Dec 24, 2024
fb5afb7
Add & use HDRViewModel::IsHDRAvailable()
res2k Dec 25, 2024
616c5fc
Move DisplayConfigWatcher to common
res2k Dec 25, 2024
53cdb1f
Update HDRViewModel on display config change
res2k Dec 25, 2024
0d4c3e4
Add spaceship operator to DisplayID
res2k Dec 25, 2024
4dfc4bc
Reuse HDRDisplay objects
res2k Dec 25, 2024
f18d310
Add more fields to HDRDisplay
res2k Dec 25, 2024
917678b
Always store use display config from wow64_64 keys
res2k Dec 25, 2024
b06be77
Hook up display selection toggling
res2k Dec 25, 2024
100bcb3
Factor out RegistryWatcher
res2k Dec 26, 2024
c8bfdcf
Add LoginStartupConfigWatcher
res2k Dec 26, 2024
438f3bb
Provide plumbing to make 'Start when logging in' toggle do something
res2k Dec 26, 2024
dc82cbf
Switch to two-way HDRViewModel::IsHDREnabled property
res2k Dec 26, 2024
2d25227
Switch to two-way HDRDisplay::IsSelected property
res2k Dec 27, 2024
f00b10a
Switch to two-way SettingsViewModel::IsLoginStartupEnabled
res2k Dec 27, 2024
80142e2
Launch HDRTrayConfig from notification icon context menu
res2k Dec 27, 2024
3182859
Add resource file to HDRTrayConfig
res2k Dec 27, 2024
da04f03
Add window icon to HDRTrayConfig
res2k Dec 27, 2024
7c6bcb5
Add custom title bar to HDRTrayConfig
res2k Dec 27, 2024
340d025
Make AboutPage links work
res2k Dec 28, 2024
c2e3d39
Tweak MainWindow navigation behavior
res2k Dec 28, 2024
b0b0510
Also install HDRTrayConfig
res2k Dec 28, 2024
c39a23b
Add resource_common.h
res2k Dec 31, 2024
4cf5d17
Customize 'App Runtime not found' dialog
res2k Jan 1, 2025
be8591e
Update copyright
res2k Jan 1, 2025
14b76d3
Handle display changes in HDRTrayConfig
res2k Jan 1, 2025
1679e01
Always update HDR status after displays changed
res2k Jan 1, 2025
637f7df
Fix show argument for HDRTrayConfig
res2k Mar 25, 2025
2f9ba7f
Update to stable WinUI3 1.7
res2k Mar 25, 2025
f66f37f
Add function to get description string for error code
res2k Jul 3, 2025
3ba3c60
Move NotifyIcon balloon tip to separate method
res2k Jul 3, 2025
786eb48
Show a balloon tip when toggling 'Start when logging in' failed
res2k Jul 3, 2025
dab79db
Also add periodic HDR status re-check to HDRTrayConfig
res2k Aug 21, 2025
6d68736
workflows: Switch to upstream fbactions, also installer older Windows…
res2k May 7, 2026
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
7 changes: 6 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ jobs:
- name: Install marko
run: python -m pip install marko

- uses: res2k/setup-winsdk@support-sdk-26100 # TEMPORARY until upstream fbactions/setup-winsdk works w/ 26100
- uses: fbactions/setup-winsdk@v2
with:
winsdk-build-version: 17763
name: Install Windows 10 SDK 17763

- uses: fbactions/setup-winsdk@v2
with:
winsdk-build-version: 26100
name: Install Windows 11 SDK 26100
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "ext/CLI11"]
path = ext/CLI11
url = https://github.com/CLIUtils/CLI11
[submodule "ext/winui3_cmake"]
path = ext/winui3_cmake
url = https://github.com/res2k/winui3_cmake
27 changes: 25 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ set(VERSION_MINOR ${GITVERSIONDETECT_VERSION_MINOR})
set(VERSION_REVISION ${GITVERSIONDETECT_VERSION_PATCH})
set(VERSION_BUILD ${GITVERSIONDETECT_VERSION_COMMIT_NUM})
set(VERSION_FULL ${GITVERSIONDETECT_VERSION})
set(VERSION_COMMIT ${GITVERSIONDETECT_VERSION_COMMIT_SHA})
set(COPYRIGHT_STR "Copyright (c) 2022-2025 Frank Richter")

set(CMAKE_CXX_STANDARD 23)
Expand Down Expand Up @@ -62,11 +63,29 @@ endif()
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)

add_subdirectory(ext)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/ext/winui3_cmake/cmake")

# We need to use the same CppWinRT version for common and HDRTrayConfig,
# so generate headers from the nuget packages
include(nuget)
nuget_install()

set(WINSDK_VERSION 10.0.17763.0)

include(find_platform_winmds)
include(run_cppwinrt)
find_platform_winmds(PATHS_VAR PLATFORM_WINMD_PATHS WINSDK_VERSION ${WINSDK_VERSION})
run_cppwinrt(TARGET platform_cppwinrt
OUT "${CMAKE_CURRENT_BINARY_DIR}/generated"
IN ${PLATFORM_WINMD_PATHS})
include_directories("${CMAKE_CURRENT_BINARY_DIR}/generated")

add_subdirectory(common)
add_dependencies(common platform_cppwinrt)

add_subdirectory(HDRTray)
add_subdirectory(HDRCmd)
add_subdirectory(HDRTray)
add_subdirectory(HDRTrayConfig)

if(MARKO_AVAILABLE)
set(MD2HTML "${CMAKE_CURRENT_SOURCE_DIR}/build/md2html.py")
Expand All @@ -85,9 +104,13 @@ if(MARKO_AVAILABLE)
add_custom_target(ConvertMD ALL DEPENDS ${GENERATED_HTML_FILES})
endif()

install(TARGETS HDRTray HDRCmd
install(TARGETS HDRTray HDRCmd HDRTrayConfig
RUNTIME
DESTINATION ".")
install(FILES
"$<TARGET_FILE_DIR:HDRTrayConfig>/Microsoft.WindowsAppRuntime.Bootstrap.dll"
"$<TARGET_FILE_DIR:HDRTrayConfig>/HDRTrayConfig.pri"
DESTINATION ".")
if(MARKO_AVAILABLE)
foreach(md_file LICENSE README)
install(FILES "${MD_OUTPUT_DIR}/${md_file}.html"
Expand Down
11 changes: 10 additions & 1 deletion HDRCmd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
configure_file(version.h.in "${CMAKE_CURRENT_BINARY_DIR}/generated/version.h")
configure_file(version.rc.in "${CMAKE_CURRENT_BINARY_DIR}/generated/version.rc")

add_executable(HDRCmd)
target_sources(HDRCmd PRIVATE
"HDRCmd.cpp"
"HDRCmd.manifest"
"HDRCmd.rc"
"subcommand/display_status.hpp"
"subcommand/display_status.cpp"
"subcommand/resolve_display.hpp"
"subcommand/resolve_display.cpp"
"subcommand/Base.hpp"
"subcommand/Disable.hpp"
"subcommand/Disable.cpp"
"subcommand/DisplayUsing.hpp"
"subcommand/DisplayUsing.cpp"
"subcommand/Enable.hpp"
"subcommand/Enable.cpp"
"subcommand/LoginStartup.hpp"
"subcommand/LoginStartup.cpp"
"subcommand/Select.hpp"
"subcommand/Select.cpp"
"subcommand/Status.hpp"
"subcommand/Status.cpp"
"subcommand/Toggle.hpp"
Expand Down
16 changes: 13 additions & 3 deletions HDRCmd/HDRCmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@

#include "subcommand/Disable.hpp"
#include "subcommand/Enable.hpp"
#include "subcommand/LoginStartup.hpp"
#include "subcommand/Select.hpp"
#include "subcommand/Status.hpp"
#include "subcommand/Toggle.hpp"
#include "version.h"
#include "WinVerCheck.hpp"

#include <format>

#include <winrt/Windows.Foundation.h>

static std::string failure_message(const CLI::App *app, const CLI::Error &e) {
return std::format("Invalid command line arguments: {}\n\n{}", e.what(), app->help());
}
Expand All @@ -35,12 +39,16 @@ int wmain(int argc, const wchar_t* const argv[])
{
CLI::App app{"HDRCmd " VERSION_FULL " - turn \"Use HDR\" on or off from command line"};

// if Windows 10 < version 1803 refuse to start
if (!IsWindows10_1803OrGreater()) {
std::cerr << "Sorry, HDRCmd only works on Windows 10, version 1803 and above" << std::endl;
// if Windows 10 < version 1809 refuse to start
if (!IsWindows10_1809OrGreater()) {
std::cerr << "Sorry, HDRCmd only works on Windows 10, version 1809 and above" << std::endl;
return -2;
}

// Init WinRT. For monitor stable ID.
// FIXME: Obtain lazily?
winrt::init_apartment();

app.allow_windows_style_options();
app.ignore_case();
app.require_subcommand(1);
Expand All @@ -50,6 +58,8 @@ int wmain(int argc, const wchar_t* const argv[])
subcommand::Enable::add(app);
subcommand::Disable::add(app);
subcommand::Toggle::add(app);
subcommand::Select::add(app);
subcommand::LoginStartup::add(app);

CLI11_PARSE(app, argc, argv);
const auto* subcmd = app.get_subcommands()[0];
Expand Down
7 changes: 5 additions & 2 deletions HDRCmd/subcommand/Disable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@

namespace subcommand {

Disable::Disable(CLI::App* parent) : Base("Turn HDR off", "off", parent) { }
Disable::Disable(CLI::App* parent) : DisplayUsing("Turn HDR off", "off", parent)
{
add_displays_option(this, default_displays_option_name, "Displays to consider");
}

int Disable::run() const
{
auto result = hdr::SetWindowsHDRStatus(false);
auto result = hdr::SetWindowsHDRStatus(GetSelectedDisplays(), false);
if (!result)
return -1;
return *result == hdr::Status::Off ? 0 : 1;
Expand Down
4 changes: 2 additions & 2 deletions HDRCmd/subcommand/Disable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
#ifndef SUBCOMMAND_DISABLE_HPP_
#define SUBCOMMAND_DISABLE_HPP_

#include "Base.hpp"
#include "DisplayUsing.hpp"

namespace subcommand {
class Disable : public Base
class Disable : public DisplayUsing
{
protected:
Disable(CLI::App* parent);
Expand Down
52 changes: 52 additions & 0 deletions HDRCmd/subcommand/DisplayUsing.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
HDRCmd - enable/disable "Use HDR" from command line
Copyright (C) 2024 Frank Richter

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include "DisplayUsing.hpp"

#include "resolve_display.hpp"

namespace subcommand {

const char* DisplayUsing::default_displays_option_name = "-d,--displays";

CLI::Option* DisplayUsing::add_displays_option(CLI::App* app, std::string option_name, std::string option_description)
{
return app->add_option(option_name, display_ids, option_description)->type_name("# or NAME");
}

hdr::DisplayInfo_vec DisplayUsing::GetSelectedDisplays() const
{
if (display_ids.empty())
return hdr::GetEnabledDisplays();

auto all_displays = hdr::GetDisplays();
hdr::DisplayInfo_vec selected_displays;
for(const auto& disp_id : display_ids) {
if (const auto* disp = resolve_display(all_displays, disp_id)) {
if (std::find_if(selected_displays.begin(), selected_displays.end(),
[disp](const hdr::DisplayInfo& already_selected) {
return already_selected.GetID() == disp->GetID();
}) != selected_displays.end())
continue;
selected_displays.push_back(*disp);
}
}
return selected_displays;
}

}
50 changes: 50 additions & 0 deletions HDRCmd/subcommand/DisplayUsing.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
HDRCmd - enable/disable "Use HDR" from command line
Copyright (C) 2024 Frank Richter

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef SUBCOMMAND_DISPLAYUSING_HPP_
#define SUBCOMMAND_DISPLAYUSING_HPP_

#include "Base.hpp"

#include "HDR.h"

namespace subcommand {

class DisplayUsing : public Base
{
protected:
/// Default name for "optional" display specification
static const char* default_displays_option_name;
/// Display IDs given on command line
std::vector<std::string> display_ids;

/// Add an option for explicit display selection. Fills display_ids
CLI::Option* add_displays_option(CLI::App* app, std::string option_name, std::string option_description);

/// Return selected displays, from command line, if explicitly given, or configuration by default
hdr::DisplayInfo_vec GetSelectedDisplays() const;

template<typename... Arg>
DisplayUsing(Arg&&... arg) : Base(std::forward<Arg>(arg)...)
{
}
};

} // namespace subcommand

#endif // SUBCOMMAND_DISPLAYUSING_HPP_
7 changes: 5 additions & 2 deletions HDRCmd/subcommand/Enable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@

namespace subcommand {

Enable::Enable(CLI::App* parent) : Base("Turn HDR on", "on", parent) { }
Enable::Enable(CLI::App* parent) : DisplayUsing("Turn HDR on", "on", parent)
{
add_displays_option(this, default_displays_option_name, "Displays to consider");
}

int Enable::run() const
{
auto result = hdr::SetWindowsHDRStatus(true);
auto result = hdr::SetWindowsHDRStatus(GetSelectedDisplays(), true);
if (!result)
return -1;
return *result == hdr::Status::On ? 0 : 1;
Expand Down
4 changes: 2 additions & 2 deletions HDRCmd/subcommand/Enable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
#ifndef SUBCOMMAND_ENABLE_HPP_
#define SUBCOMMAND_ENABLE_HPP_

#include "Base.hpp"
#include "DisplayUsing.hpp"

namespace subcommand {
class Enable : public Base
class Enable : public DisplayUsing
{
protected:
Enable(CLI::App* parent);
Expand Down
78 changes: 78 additions & 0 deletions HDRCmd/subcommand/LoginStartup.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
HDRCmd - enable/disable "Use HDR" from command line
Copyright (C) 2024 Frank Richter

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include "LoginStartup.hpp"

#include "LoginStartupConfig.hpp"

#include <array>
#include <format>
#include <print>

namespace subcommand {

LoginStartup::LoginStartup(CLI::App* parent) : Base("Change 'Start when logging in'", "startup", parent)
{
add_subcommand("status", "Print current status of option");
add_subcommand("on", "Turn 'Start when logging in' on");
add_subcommand("off", "Turn 'Start when logging in' off");
}

int LoginStartup::print_status(bool active)
{
auto status_result = LoginStartupConfig::instance().IsEnabled();
if (!status_result) {
std::println("Could not get login startup state, error {}", status_result.error());
return status_result.error();
}

auto status_str = *status_result ? "ON" : "OFF";
if (active)
std::println("'Start when logging in' is now {}", status_str);
else
std::println("'Start when logging in' is {}", status_str);
return 0;
}

int LoginStartup::run() const
{
bool has_status = got_subcommand("status");
bool has_on = got_subcommand("on");
bool has_off = got_subcommand("off");

if (has_on || has_off) {
auto enable_result = LoginStartupConfig::instance().SetEnabled(has_on);
if (!enable_result) {
std::println("Could not change login startup state, error {}", enable_result.error());
return enable_result.error();
}
}

if (!has_status && !has_on && !has_off) {
// No explicit command given: also include help text
std::cout << help() << std::endl;
}
return print_status(has_on || has_off);
}

CLI::App* LoginStartup::add(CLI::App& app)
{
return app.add_subcommand(std::shared_ptr<LoginStartup>(new LoginStartup(&app)));
}

} // namespace subcommand
Loading
Loading