mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 03:07:04 +02:00
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [X] **Closes:** #30352 - [X] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [X] **Tests:** Added/updated and all pass - [X] **Localization:** All end user facing strings can be localized - [ ] **Dev docs:** Added/updated - [X] **New binaries:** Added on the required places - [X] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [X] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments   <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed - Close PowerToys if installed in your machine - Full build the solution: PowerToys.sln - Start PowerToys from PowerToys\x64\Debug\PowerToys.exe or PowerToys\x64\Release\PowerToys.exe - Toggle the "Binary G-code thumbnail previewer" setting to enable - Open HelperFiles folder on the tests and check if the icon changes to an image - Check explorer preview to see if image is also shown there --------- Co-authored-by: leileizhang <leilzh@microsoft.com>
287 lines
13 KiB
C++
287 lines
13 KiB
C++
#include "pch.h"
|
|
#include <common/SettingsAPI/settings_objects.h>
|
|
#include "powerpreview.h"
|
|
#include "trace.h"
|
|
#include "Generated Files/resource.h"
|
|
#include <common/notifications/dont_show_again.h>
|
|
#include <common/notifications/notifications.h>
|
|
|
|
#include <common/utils/resources.h>
|
|
#include <common/utils/os-detect.h>
|
|
#include <common/utils/process_path.h>
|
|
|
|
#include <SettingsAPI/settings_helpers.h>
|
|
|
|
// Constructor
|
|
PowerPreviewModule::PowerPreviewModule() :
|
|
m_moduleName(GET_RESOURCE_STRING(IDS_MODULE_NAME)),
|
|
app_key(powerpreviewConstants::ModuleKey)
|
|
{
|
|
const std::wstring installationDir = get_module_folderpath();
|
|
|
|
std::filesystem::path logFilePath(PTSettingsHelper::get_module_save_folder_location(this->app_key));
|
|
logFilePath.append(LogSettings::fileExplorerLogPath);
|
|
Logger::init(LogSettings::fileExplorerLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
|
|
|
|
Logger::info("Initializing PowerPreviewModule");
|
|
const bool installPerUser = true;
|
|
m_fileExplorerModules.push_back({ .settingName = L"svg-previewer-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_SVG_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredSvgPreviewEnabledValue,
|
|
.registryChanges = getSvgPreviewHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"md-previewer-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_MD_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredMarkdownPreviewEnabledValue,
|
|
.registryChanges = getMdPreviewHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"monaco-previewer-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_MONACO_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredMonacoPreviewEnabledValue,
|
|
.registryChanges = getMonacoPreviewHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"pdf-previewer-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_PDF_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredPdfPreviewEnabledValue,
|
|
.registryChanges = getPdfPreviewHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"gcode-previewer-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_GCODE_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredGcodePreviewEnabledValue,
|
|
.registryChanges = getGcodePreviewHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"bgcode-previewer-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_BGCODE_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredBgcodePreviewEnabledValue,
|
|
.registryChanges = getBgcodePreviewHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"svg-thumbnail-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_SVG_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredSvgThumbnailsEnabledValue,
|
|
.registryChanges = getSvgThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"pdf-thumbnail-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_PDF_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredPdfThumbnailsEnabledValue,
|
|
.registryChanges = getPdfThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"gcode-thumbnail-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_GCODE_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredGcodeThumbnailsEnabledValue,
|
|
.registryChanges = getGcodeThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"bgcode-thumbnail-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_BGCODE_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredBgcodeThumbnailsEnabledValue,
|
|
.registryChanges = getBgcodeThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"stl-thumbnail-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_STL_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredStlThumbnailsEnabledValue,
|
|
.registryChanges = getStlThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"qoi-previewer-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_QOI_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredQoiPreviewEnabledValue,
|
|
.registryChanges = getQoiPreviewHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
m_fileExplorerModules.push_back({ .settingName = L"qoi-thumbnail-toggle-setting",
|
|
.settingDescription = GET_RESOURCE_STRING(IDS_QOI_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
|
.checkModuleGPOEnabledRuleFunction = powertoys_gpo::getConfiguredQoiThumbnailsEnabledValue,
|
|
.registryChanges = getQoiThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
|
|
|
try
|
|
{
|
|
PowerToysSettings::PowerToyValues settings =
|
|
PowerToysSettings::PowerToyValues::load_from_settings_file(PowerPreviewModule::get_key());
|
|
|
|
apply_settings(settings);
|
|
}
|
|
catch (std::exception const& e)
|
|
{
|
|
Trace::InitSetErrorLoadingFile(e.what());
|
|
}
|
|
}
|
|
|
|
// Destroy the powertoy and free memory.
|
|
void PowerPreviewModule::destroy()
|
|
{
|
|
Trace::Destroyed();
|
|
delete this;
|
|
}
|
|
|
|
// Return the localized display name of the powertoy
|
|
const wchar_t* PowerPreviewModule::get_name()
|
|
{
|
|
return m_moduleName.c_str();
|
|
}
|
|
|
|
// Return the non localized key of the powertoy, this will be cached by the runner
|
|
const wchar_t* PowerPreviewModule::get_key()
|
|
{
|
|
return app_key.c_str();
|
|
}
|
|
|
|
// Return JSON with the configuration options.
|
|
bool PowerPreviewModule::get_config(_Out_ wchar_t* buffer, _Out_ int* buffer_size)
|
|
{
|
|
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
|
|
|
// Create a Settings object.
|
|
PowerToysSettings::Settings settings(hinstance, get_name());
|
|
|
|
// General Settings.
|
|
settings.set_description(GET_RESOURCE_STRING(IDS_GENERAL_DESCRIPTION));
|
|
settings.set_icon_key(GET_RESOURCE_STRING(IDS_ICON_KEY_NAME));
|
|
settings.set_overview_link(L"https://aka.ms/PowerToysOverview_FileExplorerAddOns");
|
|
|
|
// Preview Pane: Settings Group Header.
|
|
settings.add_header_szLarge(
|
|
GET_RESOURCE_STRING(IDS_PRVPANE_FILE_PREV_STTNGS_GROUP_HEADER_ID),
|
|
GET_RESOURCE_STRING(IDS_PRVPANE_FILE_PREV_STTNGS_GROUP_DESC),
|
|
GET_RESOURCE_STRING(IDS_PRVPANE_FILE_PREV_STTNGS_GROUP_TEXT));
|
|
|
|
for (auto& fileExplorerModule : m_fileExplorerModules)
|
|
{
|
|
settings.add_bool_toggle(
|
|
fileExplorerModule.settingName,
|
|
fileExplorerModule.settingDescription,
|
|
fileExplorerModule.registryChanges.isApplied());
|
|
}
|
|
|
|
return settings.serialize_to_buffer(buffer, buffer_size);
|
|
}
|
|
|
|
// Called by the runner to pass the updated settings values as a serialized JSON.
|
|
void PowerPreviewModule::set_config(const wchar_t* config)
|
|
{
|
|
try
|
|
{
|
|
auto settings = PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
|
apply_settings(settings);
|
|
settings.save_to_settings_file();
|
|
}
|
|
catch (std::exception const& e)
|
|
{
|
|
Trace::SetConfigInvalidJSON(e.what());
|
|
}
|
|
}
|
|
|
|
void PowerPreviewModule::enable()
|
|
{
|
|
if (!m_enabled)
|
|
{
|
|
Trace::EnabledPowerPreview(true);
|
|
}
|
|
|
|
m_enabled = true;
|
|
}
|
|
|
|
// Disable active preview handlers.
|
|
void PowerPreviewModule::disable()
|
|
{
|
|
for (auto& fileExplorerModule : m_fileExplorerModules)
|
|
{
|
|
if (!fileExplorerModule.registryChanges.unApply())
|
|
{
|
|
Logger::error(L"Couldn't disable file explorer module {} during module disable() call", fileExplorerModule.settingName);
|
|
}
|
|
}
|
|
|
|
if (m_enabled)
|
|
{
|
|
Trace::EnabledPowerPreview(false);
|
|
}
|
|
|
|
m_enabled = false;
|
|
}
|
|
|
|
// Returns if the powertoys is enabled
|
|
bool PowerPreviewModule::is_enabled()
|
|
{
|
|
return m_enabled;
|
|
}
|
|
|
|
// Function to warn the user that PowerToys needs to run as administrator for changes to take effect
|
|
void PowerPreviewModule::show_update_warning_message()
|
|
{
|
|
using namespace notifications;
|
|
if (is_toast_disabled(PreviewModulesDontShowAgainRegistryPath, PreviewModulesDisableIntervalInDays))
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::vector<action_t> actions = {
|
|
link_button{ GET_RESOURCE_STRING(IDS_FILEEXPLORER_ADMIN_RESTART_WARNING_OPEN_SETTINGS),
|
|
L"powertoys://open_settings/" },
|
|
link_button{ GET_RESOURCE_STRING(IDS_FILEEXPLORER_ADMIN_RESTART_WARNING_DONT_SHOW_AGAIN),
|
|
L"powertoys://couldnt_toggle_powerpreview_modules_disable/" }
|
|
};
|
|
show_toast_with_activations(GET_RESOURCE_STRING(IDS_FILEEXPLORER_ADMIN_RESTART_WARNING_DESCRIPTION),
|
|
GET_RESOURCE_STRING(IDS_FILEEXPLORER_ADMIN_RESTART_WARNING_TITLE),
|
|
{},
|
|
std::move(actions));
|
|
}
|
|
|
|
void PowerPreviewModule::apply_settings(const PowerToysSettings::PowerToyValues& settings)
|
|
{
|
|
bool notifyShell = false;
|
|
|
|
for (auto& fileExplorerModule : m_fileExplorerModules)
|
|
{
|
|
const auto toggle = settings.get_bool_value(fileExplorerModule.settingName);
|
|
const auto gpo_rule = fileExplorerModule.checkModuleGPOEnabledRuleFunction();
|
|
const auto gpo_is_configured = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled;
|
|
|
|
if (gpo_rule == powertoys_gpo::gpo_rule_configured_unavailable)
|
|
{
|
|
Logger::warn(L"Couldn't read the gpo rule for Power Preview module {}", fileExplorerModule.settingName);
|
|
}
|
|
if (gpo_rule == powertoys_gpo::gpo_rule_configured_wrong_value)
|
|
{
|
|
Logger::warn(L"gpo rule for Power Preview module {} is set to an unknown value", fileExplorerModule.settingName);
|
|
}
|
|
|
|
// Skip if no need to update
|
|
if (!toggle.has_value() && !gpo_is_configured)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bool module_new_state = false;
|
|
if (toggle.has_value())
|
|
{
|
|
module_new_state = *toggle;
|
|
}
|
|
if (gpo_is_configured)
|
|
{
|
|
// gpo rule overrides settings state
|
|
module_new_state = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled;
|
|
}
|
|
|
|
// Skip if no need to update
|
|
if (module_new_state == fileExplorerModule.registryChanges.isApplied())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// (Un)Apply registry changes depending on the new setting value
|
|
const bool updated = module_new_state ? fileExplorerModule.registryChanges.apply() : fileExplorerModule.registryChanges.unApply();
|
|
|
|
if (updated)
|
|
{
|
|
notifyShell = true;
|
|
Trace::PowerPreviewSettingsUpdated(fileExplorerModule.settingName.c_str(), !*toggle, *toggle, true);
|
|
}
|
|
else
|
|
{
|
|
Logger::error(L"Couldn't {} file explorer module {} during apply_settings", *toggle ? L"enable " : L"disable", fileExplorerModule.settingName);
|
|
Trace::PowerPreviewSettingsUpdateFailed(fileExplorerModule.settingName.c_str(), !*toggle, *toggle, true);
|
|
}
|
|
}
|
|
if (notifyShell)
|
|
{
|
|
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
|
|
}
|
|
}
|