mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 10:46:33 +02:00
267 lines
8.6 KiB
C++
267 lines
8.6 KiB
C++
#include "pch.h"
|
|
#include <settings_objects.h>
|
|
#include <common.h>
|
|
#include "powerpreview.h"
|
|
#include "trace.h"
|
|
#include "settings.h"
|
|
#include "Generated Files/resource.h"
|
|
#include <common/notifications.h>
|
|
#include <common/os-detect.h>
|
|
#include <common/toast_dont_show_again.h>
|
|
|
|
// Constructor
|
|
PowerPreviewModule::PowerPreviewModule() :
|
|
m_moduleName(GET_RESOURCE_STRING(IDS_MODULE_NAME)),
|
|
app_key(powerpreviewConstants::ModuleKey)
|
|
{
|
|
// Initialize the toggle states for each module
|
|
init_settings();
|
|
|
|
m_fileExplorerModules.emplace_back(std::make_unique<PreviewHandlerSettings>(
|
|
true,
|
|
L"svg-previewer-toggle-setting",
|
|
GET_RESOURCE_STRING(IDS_PREVPANE_SVG_SETTINGS_DESCRIPTION),
|
|
L"{ddee2b8a-6807-48a6-bb20-2338174ff779}",
|
|
L"Svg Preview Handler",
|
|
std::make_unique<RegistryWrapper>()));
|
|
|
|
m_fileExplorerModules.emplace_back(std::make_unique<PreviewHandlerSettings>(
|
|
true,
|
|
L"md-previewer-toggle-setting",
|
|
GET_RESOURCE_STRING(IDS_PREVPANE_MD_SETTINGS_DESCRIPTION),
|
|
L"{45769bcc-e8fd-42d0-947e-02beef77a1f5}",
|
|
L"Markdown Preview Handler",
|
|
std::make_unique<RegistryWrapper>()));
|
|
|
|
m_fileExplorerModules.emplace_back(std::make_unique<ThumbnailProviderSettings>(
|
|
true,
|
|
L"svg-thumbnail-toggle-setting",
|
|
GET_RESOURCE_STRING(IDS_SVG_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
|
L"{36B27788-A8BB-4698-A756-DF9F11F64F84}",
|
|
L"Svg Thumbnail Provider",
|
|
std::make_unique<RegistryWrapper>(),
|
|
L".svg\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}"));
|
|
|
|
// If the user is on the new settings interface, File Explorer might be disabled if they updated from old to new settings, so initialize the registry state in the constructor as PowerPreviewModule::enable/disable will not be called on startup
|
|
if (UseNewSettings())
|
|
{
|
|
update_registry_to_match_toggles();
|
|
}
|
|
}
|
|
|
|
// 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->GetToggleSettingName(),
|
|
fileExplorerModule->GetToggleSettingDescription(),
|
|
fileExplorerModule->GetToggleSettingState());
|
|
}
|
|
|
|
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
|
|
{
|
|
PowerToysSettings::PowerToyValues settings = PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
|
|
|
bool updateSuccess = true;
|
|
bool isElevated = is_process_elevated(false);
|
|
for (auto& fileExplorerModule : m_fileExplorerModules)
|
|
{
|
|
// If the user is using the new settings interface, as it does not have a toggle to modify enabled consider File Explorer to always be enabled
|
|
updateSuccess = updateSuccess && fileExplorerModule->UpdateState(settings, this->m_enabled || UseNewSettings(), isElevated);
|
|
}
|
|
|
|
if (!updateSuccess)
|
|
{
|
|
show_update_warning_message();
|
|
}
|
|
|
|
settings.save_to_settings_file();
|
|
}
|
|
catch (std::exception const& e)
|
|
{
|
|
Trace::SetConfigInvalidJSON(e.what());
|
|
}
|
|
}
|
|
|
|
// Enable preview handlers.
|
|
void PowerPreviewModule::enable()
|
|
{
|
|
// Should only be done for old settings as it is already done for new settings in the constructor.
|
|
if (!UseNewSettings())
|
|
{
|
|
update_registry_to_match_toggles();
|
|
}
|
|
|
|
if (!this->m_enabled)
|
|
{
|
|
Trace::EnabledPowerPreview(true);
|
|
}
|
|
|
|
this->m_enabled = true;
|
|
}
|
|
|
|
// Disable active preview handlers.
|
|
void PowerPreviewModule::disable()
|
|
{
|
|
elevation_check_wrapper([this]() {
|
|
for (auto& fileExplorerModule : m_fileExplorerModules)
|
|
{
|
|
fileExplorerModule->Disable();
|
|
}
|
|
});
|
|
|
|
if (this->m_enabled)
|
|
{
|
|
Trace::EnabledPowerPreview(false);
|
|
}
|
|
|
|
this->m_enabled = false;
|
|
}
|
|
|
|
// Returns if the powertoys is enabled
|
|
bool PowerPreviewModule::is_enabled()
|
|
{
|
|
return this->m_enabled;
|
|
}
|
|
|
|
// Load the settings file.
|
|
void PowerPreviewModule::init_settings()
|
|
{
|
|
try
|
|
{
|
|
// Load and parse the settings file for this PowerToy.
|
|
PowerToysSettings::PowerToyValues settings =
|
|
PowerToysSettings::PowerToyValues::load_from_settings_file(PowerPreviewModule::get_key());
|
|
|
|
// Load settings states.
|
|
for (auto& fileExplorerModule : m_fileExplorerModules)
|
|
{
|
|
fileExplorerModule->LoadState(settings);
|
|
}
|
|
}
|
|
catch (std::exception const& e)
|
|
{
|
|
Trace::InitSetErrorLoadingFile(e.what());
|
|
}
|
|
}
|
|
|
|
// Function to check if the registry states need to be updated
|
|
bool PowerPreviewModule::is_registry_update_required()
|
|
{
|
|
for (auto& fileExplorerModule : m_fileExplorerModules)
|
|
{
|
|
if (fileExplorerModule->GetToggleSettingState() != fileExplorerModule->CheckRegistryState())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// 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))
|
|
{
|
|
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));
|
|
}
|
|
}
|
|
|
|
// Function that checks if a registry method is required and if so checks if the process is elevated and accordingly executes the method or shows a warning
|
|
void PowerPreviewModule::registry_and_elevation_check_wrapper(std::function<void()> method)
|
|
{
|
|
// Check if a registry update is required
|
|
if (is_registry_update_required())
|
|
{
|
|
elevation_check_wrapper(method);
|
|
}
|
|
}
|
|
|
|
// Function that checks if the process is elevated and accordingly executes the method or shows a warning
|
|
void PowerPreviewModule::elevation_check_wrapper(std::function<void()> method)
|
|
{
|
|
// Check if the process is elevated in order to have permissions to modify HKLM registry
|
|
if (is_process_elevated(false))
|
|
{
|
|
method();
|
|
}
|
|
// Show a warning if it doesn't have permissions
|
|
else
|
|
{
|
|
show_update_warning_message();
|
|
}
|
|
}
|
|
|
|
// Function that updates the registry state to match the toggle states
|
|
void PowerPreviewModule::update_registry_to_match_toggles()
|
|
{
|
|
registry_and_elevation_check_wrapper([this]() {
|
|
for (auto& fileExplorerModule : m_fileExplorerModules)
|
|
{
|
|
if (fileExplorerModule->GetToggleSettingState())
|
|
{
|
|
// Enable all the modules with initial state set as true.
|
|
fileExplorerModule->Enable();
|
|
}
|
|
else
|
|
{
|
|
fileExplorerModule->Disable();
|
|
}
|
|
}
|
|
});
|
|
}
|