mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
Merge Master Latest: 4/15/20
This commit is contained in:
100
NOTICE.md
100
NOTICE.md
@@ -18,11 +18,12 @@ Notwithstanding any other terms, you may reverse engineer this software to the
|
||||
extent required to debug changes to any libraries licensed under the GNU Lesser
|
||||
General Public License.
|
||||
|
||||
## ImageResizer
|
||||
## PowerToy: ImageResizer
|
||||
|
||||
### Brice Lams's Image Resizer License
|
||||
|
||||
**Source**: https://github.com/bricelam/ImageResizer/
|
||||
|
||||
### License
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Brice Lambson. All rights reserved.
|
||||
@@ -44,3 +45,98 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
## PowerToy: Launcher
|
||||
|
||||
### Wox License
|
||||
|
||||
**Source**: https://github.com/Wox-launcher/Wox
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Wox
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
### Beta Tadele's Window Walker License
|
||||
|
||||
**Source**: https://github.com/betsegaw/windowwalker
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2020 Betsegaw Tadele
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
### Squirrel.Windows License
|
||||
|
||||
**Source**: https://github.com/Squirrel/Squirrel.Windows/
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012 GitHub, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## PowerToy: PowerRename
|
||||
|
||||
### Chris Davis's SmartRename License
|
||||
|
||||
**Source**: https://github.com/chrdavis/SmartRename
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Chris Davis
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
<![CDATA[(WINDOWSBUILDNUMBER >= 17134)]]>
|
||||
</Condition>
|
||||
|
||||
<Icon Id="powertoys.ico" SourceFile="$(var.BinX64Dir)\svgs\icon.ico"/>
|
||||
<Property Id="ARPPRODUCTICON" Value="powertoys.ico" />
|
||||
<Icon Id="powertoys.exe" SourceFile="$(var.BinX64Dir)\svgs\icon.ico"/>
|
||||
<Property Id="ARPPRODUCTICON" Value="powertoys.exe" />
|
||||
<Feature Id="CoreFeature" Title="PowerToys" AllowAdvertise="no" Absent="disallow" TypicalDefault="install"
|
||||
Description="Contains the Shortcut Guide and Fancy Zones features.">
|
||||
<ComponentGroupRef Id="CoreComponents" />
|
||||
@@ -228,7 +228,7 @@
|
||||
Description="PowerToys - Windows system utilities to maximize productivity"
|
||||
Directory="ApplicationProgramsFolder"
|
||||
WorkingDirectory="INSTALLFOLDER"
|
||||
Icon="powertoys.ico"
|
||||
Icon="powertoys.exe"
|
||||
IconIndex="0"
|
||||
Advertise="yes">
|
||||
<ShortcutProperty Key="System.AppUserModel.ID" Value="Microsoft.PowerToysWin32"/>
|
||||
@@ -500,7 +500,7 @@
|
||||
Description="PowerToys - Windows system utilities to maximize productivity"
|
||||
Target="[!PowerToys.exe]"
|
||||
WorkingDirectory="INSTALLFOLDER"
|
||||
Icon="powertoys.ico"
|
||||
Icon="powertoys.exe"
|
||||
Directory="DesktopFolder"/>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
@@ -30,7 +30,8 @@ const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
|
||||
// The path of the executable to run should be passed as the CustomActionData (Value).
|
||||
// Based on the Task Scheduler Logon Trigger Example:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/taskschd/logon-trigger-example--c---/
|
||||
UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) {
|
||||
UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
@@ -39,13 +40,13 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) {
|
||||
|
||||
std::wstring wstrTaskName;
|
||||
|
||||
ITaskService *pService = NULL;
|
||||
ITaskFolder *pTaskFolder = NULL;
|
||||
ITaskDefinition *pTask = NULL;
|
||||
IRegistrationInfo *pRegInfo = NULL;
|
||||
ITaskSettings *pSettings = NULL;
|
||||
ITriggerCollection *pTriggerCollection = NULL;
|
||||
IRegisteredTask *pRegisteredTask = NULL;
|
||||
ITaskService* pService = NULL;
|
||||
ITaskFolder* pTaskFolder = NULL;
|
||||
ITaskDefinition* pTask = NULL;
|
||||
IRegistrationInfo* pRegInfo = NULL;
|
||||
ITaskSettings* pSettings = NULL;
|
||||
ITriggerCollection* pTriggerCollection = NULL;
|
||||
IRegisteredTask* pRegisteredTask = NULL;
|
||||
|
||||
hr = WcaInitialize(hInstall, "CreateScheduledTaskCA");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
@@ -58,10 +59,12 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) {
|
||||
// This action needs to run as the system to get elevated privileges from the installation,
|
||||
// so GetUserNameEx can't be used to get the current user details.
|
||||
// The USERNAME and USERDOMAIN environment variables are used instead.
|
||||
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
|
||||
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
|
||||
{
|
||||
ExitWithLastError(hr, "Getting username failed: %x", hr);
|
||||
}
|
||||
if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN)) {
|
||||
if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN))
|
||||
{
|
||||
ExitWithLastError(hr, "Getting the user's domain failed: %x", hr);
|
||||
}
|
||||
wcscat_s(username_domain, L"\\");
|
||||
@@ -90,20 +93,21 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) {
|
||||
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
|
||||
|
||||
// Connect to the task service.
|
||||
hr = pService->Connect(_variant_t(), _variant_t(),
|
||||
_variant_t(), _variant_t());
|
||||
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
|
||||
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Get the PowerToys task folder. Creates it if it doesn't exist.
|
||||
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// Folder doesn't exist. Get the Root folder and create the PowerToys subfolder.
|
||||
ITaskFolder *pRootFolder = NULL;
|
||||
ITaskFolder* pRootFolder = NULL;
|
||||
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
|
||||
ExitOnFailure(hr, "Cannot get Root Folder pointer: %x", hr);
|
||||
hr = pRootFolder->CreateFolder(_bstr_t(L"\\PowerToys"), _variant_t(L""), &pTaskFolder);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
pRootFolder->Release();
|
||||
ExitOnFailure(hr, "Cannot create PowerToys task folder: %x", hr);
|
||||
}
|
||||
@@ -144,25 +148,27 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) {
|
||||
ExitOnFailure(hr, "Cannot get trigger collection: %x", hr);
|
||||
|
||||
// Add the logon trigger to the task.
|
||||
ITrigger *pTrigger = NULL;
|
||||
ITrigger* pTrigger = NULL;
|
||||
hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
|
||||
ExitOnFailure(hr, "Cannot create the trigger: %x", hr);
|
||||
|
||||
ILogonTrigger *pLogonTrigger = NULL;
|
||||
ILogonTrigger* pLogonTrigger = NULL;
|
||||
hr = pTrigger->QueryInterface(
|
||||
IID_ILogonTrigger, (void**)&pLogonTrigger);
|
||||
pTrigger->Release();
|
||||
ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: %x", hr);
|
||||
|
||||
hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1"));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WcaLogError(hr, "Cannot put the trigger ID: %x", hr);
|
||||
}
|
||||
|
||||
// Timing issues may make explorer not be started when the task runs.
|
||||
// Add a little delay to mitigate this.
|
||||
hr = pLogonTrigger->put_Delay(_bstr_t(L"PT03S"));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WcaLogError(hr, "Cannot put the trigger delay: %x", hr);
|
||||
}
|
||||
|
||||
@@ -174,19 +180,19 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) {
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Add an Action to the task. This task will execute the path passed to this custom action.
|
||||
IActionCollection *pActionCollection = NULL;
|
||||
IActionCollection* pActionCollection = NULL;
|
||||
|
||||
// Get the task action collection pointer.
|
||||
hr = pTask->get_Actions(&pActionCollection);
|
||||
ExitOnFailure(hr, "Cannot get Task collection pointer: %x", hr);
|
||||
|
||||
// Create the action, specifying that it is an executable action.
|
||||
IAction *pAction = NULL;
|
||||
IAction* pAction = NULL;
|
||||
hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
|
||||
pActionCollection->Release();
|
||||
ExitOnFailure(hr, "Cannot create the action: %x", hr);
|
||||
|
||||
IExecAction *pExecAction = NULL;
|
||||
IExecAction* pExecAction = NULL;
|
||||
// QI for the executable task pointer.
|
||||
hr = pAction->QueryInterface(
|
||||
IID_IExecAction, (void**)&pExecAction);
|
||||
@@ -200,23 +206,26 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) {
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Create the principal for the task
|
||||
IPrincipal *pPrincipal = NULL;
|
||||
IPrincipal* pPrincipal = NULL;
|
||||
hr = pTask->get_Principal(&pPrincipal);
|
||||
ExitOnFailure(hr, "Cannot get principal pointer: %x", hr);
|
||||
|
||||
// Set up principal information:
|
||||
hr = pPrincipal->put_Id(_bstr_t(L"Principal1"));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WcaLogError(hr, "Cannot put the principal ID: %x", hr);
|
||||
}
|
||||
|
||||
hr = pPrincipal->put_UserId(_bstr_t(username_domain));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WcaLogError(hr, "Cannot put principal user Id: %x", hr);
|
||||
}
|
||||
|
||||
hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WcaLogError(hr, "Cannot put principal logon type: %x", hr);
|
||||
}
|
||||
|
||||
@@ -245,15 +254,37 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) {
|
||||
|
||||
LExit:
|
||||
ReleaseStr(wszExecutablePath);
|
||||
if (pService) pService->Release();
|
||||
if (pTaskFolder) pTaskFolder->Release();
|
||||
if (pTask) pTask->Release();
|
||||
if (pRegInfo) pRegInfo->Release();
|
||||
if (pSettings) pSettings->Release();
|
||||
if (pTriggerCollection) pTriggerCollection->Release();
|
||||
if (pRegisteredTask) pRegisteredTask->Release();
|
||||
if (pService)
|
||||
{
|
||||
pService->Release();
|
||||
}
|
||||
if (pTaskFolder)
|
||||
{
|
||||
pTaskFolder->Release();
|
||||
}
|
||||
if (pTask)
|
||||
{
|
||||
pTask->Release();
|
||||
}
|
||||
if (pRegInfo)
|
||||
{
|
||||
pRegInfo->Release();
|
||||
}
|
||||
if (pSettings)
|
||||
{
|
||||
pSettings->Release();
|
||||
}
|
||||
if (pTriggerCollection)
|
||||
{
|
||||
pTriggerCollection->Release();
|
||||
}
|
||||
if (pRegisteredTask)
|
||||
{
|
||||
pRegisteredTask->Release();
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
PMSIHANDLE hRecord = MsiCreateRecord(0);
|
||||
MsiRecordSetString(hRecord, 0, TEXT("Failed to create a scheduled task to start PowerToys at user login. You can re-try to create the scheduled task using the PowerToys settings."));
|
||||
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
|
||||
@@ -266,12 +297,13 @@ LExit:
|
||||
// Removes all Scheduled Tasks in the PowerToys folder and deletes the folder afterwards.
|
||||
// Based on the Task Scheduler Displaying Task Names and State example:
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/TaskSchd/displaying-task-names-and-state--c---/
|
||||
UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall) {
|
||||
UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
ITaskService *pService = NULL;
|
||||
ITaskFolder *pTaskFolder = NULL;
|
||||
ITaskService* pService = NULL;
|
||||
ITaskFolder* pTaskFolder = NULL;
|
||||
IRegisteredTaskCollection* pTaskCollection = NULL;
|
||||
|
||||
hr = WcaInitialize(hInstall, "RemoveScheduledTasksCA");
|
||||
@@ -291,14 +323,14 @@ UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall) {
|
||||
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
|
||||
|
||||
// Connect to the task service.
|
||||
hr = pService->Connect(_variant_t(), _variant_t(),
|
||||
_variant_t(), _variant_t());
|
||||
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
|
||||
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Get the PowerToys task folder.
|
||||
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// Folder doesn't exist. No need to delete anything.
|
||||
WcaLog(LOGMSG_STANDARD, "The PowerToys scheduled task folder wasn't found. Nothing to delete.");
|
||||
hr = S_OK;
|
||||
@@ -312,32 +344,40 @@ UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall) {
|
||||
|
||||
LONG numTasks = 0;
|
||||
hr = pTaskCollection->get_Count(&numTasks);
|
||||
for (LONG i = 0; i < numTasks; i++) {
|
||||
for (LONG i = 0; i < numTasks; i++)
|
||||
{
|
||||
// Delete all the tasks found.
|
||||
// If some tasks can't be deleted, the folder won't be deleted later and the user will still be notified.
|
||||
IRegisteredTask* pRegisteredTask = NULL;
|
||||
hr = pTaskCollection->get_Item(_variant_t(i + 1), &pRegisteredTask);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
BSTR taskName = NULL;
|
||||
hr = pRegisteredTask->get_Name(&taskName);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pTaskFolder->DeleteTask(taskName, NULL);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WcaLogError(hr, "Cannot delete the '%S' task: %x", taskName, hr);
|
||||
}
|
||||
SysFreeString(taskName);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
WcaLogError(hr, "Cannot get the registered task name: %x", hr);
|
||||
}
|
||||
pRegisteredTask->Release();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
WcaLogError(hr, "Cannot get the registered task item at index=%d: %x", i + 1, hr);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Get the pointer to the root task folder and delete the PowerToys subfolder.
|
||||
ITaskFolder *pRootFolder = NULL;
|
||||
ITaskFolder* pRootFolder = NULL;
|
||||
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
|
||||
ExitOnFailure(hr, "Cannot get Root Folder pointer: %x", hr);
|
||||
hr = pRootFolder->DeleteFolder(_bstr_t(L"PowerToys"), NULL);
|
||||
@@ -347,11 +387,21 @@ UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall) {
|
||||
WcaLog(LOGMSG_STANDARD, "Deleted the PowerToys Task Scheduler folder.");
|
||||
|
||||
LExit:
|
||||
if (pService) pService->Release();
|
||||
if (pTaskFolder) pTaskFolder->Release();
|
||||
if (pTaskCollection) pTaskCollection->Release();
|
||||
if (pService)
|
||||
{
|
||||
pService->Release();
|
||||
}
|
||||
if (pTaskFolder)
|
||||
{
|
||||
pTaskFolder->Release();
|
||||
}
|
||||
if (pTaskCollection)
|
||||
{
|
||||
pTaskCollection->Release();
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
PMSIHANDLE hRecord = MsiCreateRecord(0);
|
||||
MsiRecordSetString(hRecord, 0, TEXT("Failed to remove the PowerToys folder from the scheduled task. These can be removed manually later."));
|
||||
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
|
||||
@@ -361,7 +411,8 @@ LExit:
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TelemetryLogInstallSuccessCA(MSIHANDLE hInstall) {
|
||||
UINT __stdcall TelemetryLogInstallSuccessCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
@@ -380,7 +431,8 @@ LExit:
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TelemetryLogInstallCancelCA(MSIHANDLE hInstall) {
|
||||
UINT __stdcall TelemetryLogInstallCancelCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
@@ -399,7 +451,8 @@ LExit:
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TelemetryLogInstallFailCA(MSIHANDLE hInstall) {
|
||||
UINT __stdcall TelemetryLogInstallFailCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
@@ -418,7 +471,8 @@ LExit:
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TelemetryLogUninstallSuccessCA(MSIHANDLE hInstall) {
|
||||
UINT __stdcall TelemetryLogUninstallSuccessCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
@@ -437,7 +491,8 @@ LExit:
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TelemetryLogUninstallCancelCA(MSIHANDLE hInstall) {
|
||||
UINT __stdcall TelemetryLogUninstallCancelCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
@@ -456,7 +511,8 @@ LExit:
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TelemetryLogUninstallFailCA(MSIHANDLE hInstall) {
|
||||
UINT __stdcall TelemetryLogUninstallFailCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
@@ -475,7 +531,8 @@ LExit:
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TelemetryLogRepairCancelCA(MSIHANDLE hInstall) {
|
||||
UINT __stdcall TelemetryLogRepairCancelCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
@@ -494,7 +551,8 @@ LExit:
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TelemetryLogRepairFailCA(MSIHANDLE hInstall) {
|
||||
UINT __stdcall TelemetryLogRepairFailCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
@@ -514,8 +572,10 @@ LExit:
|
||||
}
|
||||
|
||||
// DllMain - Initialize and cleanup WiX custom action utils.
|
||||
extern "C" BOOL WINAPI DllMain(__in HINSTANCE hInst, __in ULONG ulReason, __in LPVOID) {
|
||||
switch (ulReason) {
|
||||
extern "C" BOOL WINAPI DllMain(__in HINSTANCE hInst, __in ULONG ulReason, __in LPVOID)
|
||||
{
|
||||
switch (ulReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
WcaGlobalInitialize(hInst);
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
|
||||
@@ -364,8 +364,9 @@ WindowState get_window_state(HWND hwnd)
|
||||
return RESTORED;
|
||||
}
|
||||
|
||||
bool is_process_elevated()
|
||||
bool is_process_elevated(const bool use_cached_value)
|
||||
{
|
||||
auto detection_func = []() {
|
||||
HANDLE token = nullptr;
|
||||
bool elevated = false;
|
||||
|
||||
@@ -385,6 +386,9 @@ bool is_process_elevated()
|
||||
}
|
||||
|
||||
return elevated;
|
||||
};
|
||||
static const bool cached_value = detection_func();
|
||||
return use_cached_value ? cached_value : detection_func();
|
||||
}
|
||||
|
||||
bool drop_elevated_privileges()
|
||||
|
||||
@@ -61,7 +61,7 @@ enum WindowState
|
||||
WindowState get_window_state(HWND hwnd);
|
||||
|
||||
// Returns true if the current process is running with elevated privileges
|
||||
bool is_process_elevated();
|
||||
bool is_process_elevated(const bool use_cached_value = true);
|
||||
|
||||
// Drops the elevated privilages if present
|
||||
bool drop_elevated_privileges();
|
||||
@@ -78,7 +78,7 @@ bool run_same_elevation(const std::wstring& file, const std::wstring& params);
|
||||
// Returns true if the current process is running from administrator account
|
||||
bool check_user_is_admin();
|
||||
|
||||
//Returns true when one or more strings from vector found in string
|
||||
// Returns true when one or more strings from vector found in string
|
||||
bool find_app_name_in_path(const std::wstring& where, const std::vector<std::wstring>& what);
|
||||
|
||||
// Get the executable path or module name for modern apps
|
||||
|
||||
@@ -38,6 +38,11 @@ std::vector<MonitorInfo> MonitorInfo::GetMonitors(bool include_toolbar)
|
||||
return monitors;
|
||||
}
|
||||
|
||||
int MonitorInfo::GetMonitorsCount()
|
||||
{
|
||||
return GetMonitors(true).size();
|
||||
}
|
||||
|
||||
static BOOL CALLBACK get_primary_display_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
|
||||
{
|
||||
MONITORINFOEX monitor_info;
|
||||
|
||||
@@ -32,6 +32,7 @@ struct MonitorInfo : ScreenSize
|
||||
|
||||
// Returns monitor rects ordered from left to right
|
||||
static std::vector<MonitorInfo> GetMonitors(bool include_toolbar);
|
||||
static int GetMonitorsCount();
|
||||
// Return primary display
|
||||
static MonitorInfo GetPrimaryMonitor();
|
||||
// Return monitor on which hwnd window is displayed
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
<!-- Accent and AppTheme setting -->
|
||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<SolidColorBrush x:Key="CanvasZoneBackgroundBrush" Color="#BF333333"/>
|
||||
<SolidColorBrush x:Key="GridZoneBackgroundBrush" Color="#FF1a1a1a"/>
|
||||
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -5,14 +5,73 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:FancyZonesEditor"
|
||||
mc:Ignorable="d"
|
||||
Background="LightGray"
|
||||
Opacity="0.75"
|
||||
Background="Transparent"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
|
||||
<UserControl.Resources>
|
||||
<Style x:Key="CanvasZoneThumbStyle" TargetType="{x:Type Thumb}">
|
||||
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Thumb}">
|
||||
<Border x:Name="ThumbBorder" Opacity="0" BorderBrush="{Binding Source={x:Static SystemParameters.WindowGlassBrush}}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates" >
|
||||
<VisualStateGroup.Transitions>
|
||||
<VisualTransition GeneratedDuration="0:0:0.15">
|
||||
<VisualTransition.GeneratedEasingFunction>
|
||||
<ExponentialEase EasingMode="EaseInOut"/>
|
||||
</VisualTransition.GeneratedEasingFunction>
|
||||
</VisualTransition>
|
||||
</VisualStateGroup.Transitions>
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="MouseOver">
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="ThumbBorder" Duration="0:0:0.15" Storyboard.TargetProperty="Opacity" To="1"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CloseButtonStyle" TargetType="{x:Type Button}">
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Padding" Value="1"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
|
||||
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsDefaulted" Value="true">
|
||||
<Setter Property="BorderBrush" TargetName="border" Value="{Binding Source={x:Static SystemParameters.WindowGlassBrush}}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Opacity" TargetName="contentPresenter" Value="0.6"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="true">
|
||||
<Setter Property="Opacity" TargetName="contentPresenter" Value="0.4"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border BorderBrush="{Binding Source={x:Static SystemParameters.WindowGlassBrush}}" Background="{StaticResource CanvasZoneBackgroundBrush}" BorderThickness="1">
|
||||
<Grid x:Name="Frame">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="8"/>
|
||||
<RowDefinition Height="16"/>
|
||||
<RowDefinition Height="24"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="16"/>
|
||||
<RowDefinition Height="8"/>
|
||||
@@ -24,32 +83,35 @@
|
||||
<ColumnDefinition Width="16"/>
|
||||
<ColumnDefinition Width="8"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Thumb x:Name="NWResize" Cursor="SizeNWSE" Background="Black" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="NWResize_DragStarted"/>
|
||||
<Thumb x:Name="NEResize" Cursor="SizeNESW" Background="Black" Grid.Row="0" Grid.Column="3" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="NEResize_DragStarted"/>
|
||||
<Thumb x:Name="SWResize" Cursor="SizeNESW" Background="Black" Grid.Row="4" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="SWResize_DragStarted"/>
|
||||
<Thumb x:Name="SEResize" Cursor="SizeNWSE" Background="Black" Grid.Row="4" Grid.Column="3" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="SEResize_DragStarted"/>
|
||||
<Thumb x:Name="NResize" Cursor="SizeNS" Background="Black" Margin="1,0,1,0" Grid.Row="0" Grid.Column="2" DragDelta="UniversalDragDelta" DragStarted="NResize_DragStarted"/>
|
||||
<Thumb x:Name="SResize" Cursor="SizeNS" Background="Black" Margin="1,0,1,0" Grid.Row="5" Grid.Column="2" DragDelta="UniversalDragDelta" DragStarted="SResize_DragStarted"/>
|
||||
<Thumb x:Name="WResize" Cursor="SizeWE" Background="Black" Margin="0,1,0,1" Grid.Row="2" Grid.Column="0" Grid.RowSpan="2" DragDelta="UniversalDragDelta" DragStarted="WResize_DragStarted"/>
|
||||
<Thumb x:Name="EResize" Cursor="SizeWE" Background="Black" Margin="0,1,0,1" Grid.Row="2" Grid.Column="4" Grid.RowSpan="2" DragDelta="UniversalDragDelta" DragStarted="EResize_DragStarted"/>
|
||||
<DockPanel Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" Grid.ColumnSpan="3">
|
||||
<Button DockPanel.Dock="Right" Padding="8,0" Click="OnClose">
|
||||
<Image Source="images/ChromeClose.png" Height="24" Width="24" />
|
||||
</Button>
|
||||
<Thumb x:Name="Caption" Cursor="SizeAll" Background="DarkGray" DragDelta="UniversalDragDelta" DragStarted="Caption_DragStarted"/>
|
||||
</DockPanel>
|
||||
<Rectangle Fill="LightGray" Grid.Row="3" Grid.Column="1" Grid.RowSpan="2" Grid.ColumnSpan="3"/>
|
||||
<Canvas x:Name="Body" />
|
||||
|
||||
<Label Name="LabelID"
|
||||
Content="ID"
|
||||
Canvas.Left="10"
|
||||
Canvas.Bottom="10"
|
||||
FontSize="80"
|
||||
FontFamily="Segoe UI"
|
||||
Foreground="Black"
|
||||
FontSize="64"
|
||||
FontFamily="Segoe UI Light"
|
||||
Foreground="White"
|
||||
Grid.Column="2"
|
||||
Grid.Row="3"
|
||||
Grid.Row="2"
|
||||
VerticalContentAlignment="Center"
|
||||
HorizontalContentAlignment="Center" />
|
||||
|
||||
<Thumb x:Name="Caption" Cursor="SizeAll" Background="Transparent" BorderThickness="3" Padding="4" Grid.Column="0" Grid.ColumnSpan="5" Grid.Row="0" Grid.RowSpan="5" DragDelta="UniversalDragDelta" DragStarted="Caption_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
|
||||
<Thumb x:Name="NResize" Cursor="SizeNS" BorderThickness="0,3,0,0" Grid.ColumnSpan="5" DragDelta="UniversalDragDelta" DragStarted="NResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="SResize" Cursor="SizeNS" BorderThickness="0,0,0,3" Grid.Row="4" Grid.ColumnSpan="5" DragDelta="UniversalDragDelta" DragStarted="SResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="WResize" Cursor="SizeWE" BorderThickness="3,0,0,0" Grid.RowSpan="5" DragDelta="UniversalDragDelta" DragStarted="WResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="EResize" Cursor="SizeWE" BorderThickness="0,0,3,0" Grid.Column="4" Grid.RowSpan="5" DragDelta="UniversalDragDelta" DragStarted="EResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
|
||||
<Thumb x:Name="NWResize" Cursor="SizeNWSE" BorderThickness="3,3,0,0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="NWResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="NEResize" Cursor="SizeNESW" BorderThickness="0,3,3,0" Grid.Row="0" Grid.Column="3" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="NEResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="SWResize" Cursor="SizeNESW" BorderThickness="3,0,0,3" Grid.Row="3" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="SWResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="SEResize" Cursor="SizeNWSE" BorderThickness="0,0,3,3" Grid.Row="3" Grid.Column="3" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="SEResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
|
||||
<Button Content="" BorderThickness="0" ToolTip="Delete zone" Background="Transparent" Foreground="White" FontSize="16" Padding="4" Click="OnClose" Grid.Row="2" Grid.Column="2" FontFamily="Segoe MDL2 Assets" HorizontalAlignment="Right" VerticalAlignment="Top" Style="{DynamicResource CloseButtonStyle}"/>
|
||||
|
||||
<Canvas x:Name="Body" />
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
</UserControl>
|
||||
|
||||
@@ -76,6 +76,9 @@
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
<CodeAnalysisRuleSet>..\..\..\..\codeAnalysis\Rules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>images\FancyZonesEditor.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
@@ -248,5 +251,8 @@
|
||||
<ItemGroup>
|
||||
<Resource Include="images\Merge.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="images\FancyZonesEditor.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -9,10 +9,16 @@
|
||||
<Thumb.Template>
|
||||
<ControlTemplate>
|
||||
<StackPanel x:Name="Body" Grid.Column="0" Width="48" Height="48">
|
||||
<Ellipse Height="48" Width="48" Fill="#0078D7" />
|
||||
|
||||
<Ellipse x:Name="BackgroundEllipse" Height="48" Width="48" Fill="{Binding Source={x:Static SystemParameters.WindowGlassBrush}}" />
|
||||
<Rectangle Height="20" Width="2" Fill="White" Margin="5,-48,0,0"/>
|
||||
<Rectangle Height="20" Width="2" Fill="White" Margin="-5,-48,0,0"/>
|
||||
</StackPanel>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Opacity" TargetName="BackgroundEllipse" Value="0.6"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Thumb.Template>
|
||||
</Thumb>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
Background="LightGray"
|
||||
BorderBrush="DarkGray"
|
||||
Background="{StaticResource GridZoneBackgroundBrush}"
|
||||
BorderBrush="{Binding Source={x:Static SystemParameters.WindowGlassBrush}}"
|
||||
BorderThickness="1"
|
||||
Opacity="0.5"
|
||||
Opacity="0.8"
|
||||
mc:Ignorable="d">
|
||||
<Grid x:Name="Frame">
|
||||
<Canvas x:Name="Body" />
|
||||
@@ -23,9 +23,9 @@
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
Content="ID"
|
||||
FontFamily="Segoe UI"
|
||||
FontSize="80"
|
||||
Foreground="Black" />
|
||||
FontFamily="Segoe UI Light"
|
||||
FontSize="64"
|
||||
Foreground="White" />
|
||||
<!--<TextBlock Margin="2" Text="Shift Key switches direction Ctrl Key repeats"/>-->
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace FancyZonesEditor
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
Background = IsSelected ? Brushes.SteelBlue : Brushes.LightGray;
|
||||
Background = IsSelected ? SystemParameters.WindowGlassBrush : App.Current.Resources["GridZoneBackgroundBrush"] as SolidColorBrush;
|
||||
}
|
||||
|
||||
public bool IsSelected
|
||||
@@ -60,7 +60,7 @@ namespace FancyZonesEditor
|
||||
OnSelectionChanged();
|
||||
_splitter = new Rectangle
|
||||
{
|
||||
Fill = Brushes.DarkGray,
|
||||
Fill = SystemParameters.WindowGlassBrush,
|
||||
};
|
||||
Body.Children.Add(_splitter);
|
||||
|
||||
@@ -101,7 +101,16 @@ namespace FancyZonesEditor
|
||||
|
||||
private int SplitterThickness
|
||||
{
|
||||
get { return Math.Max(((App)Application.Current).ZoneSettings.Spacing, 5); }
|
||||
get
|
||||
{
|
||||
Settings settings = ((App)Application.Current).ZoneSettings;
|
||||
if (!settings.ShowSpacing)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return Math.Max(settings.Spacing, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSplitter()
|
||||
@@ -146,7 +155,7 @@ namespace FancyZonesEditor
|
||||
|
||||
protected override void OnMouseEnter(MouseEventArgs e)
|
||||
{
|
||||
_splitter.Fill = Brushes.DarkGray;
|
||||
_splitter.Fill = SystemParameters.WindowGlassBrush; // Active Accent color
|
||||
base.OnMouseEnter(e);
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
@@ -150,6 +150,7 @@ public:
|
||||
void AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept;
|
||||
|
||||
void MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index) noexcept;
|
||||
void MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet) noexcept;
|
||||
|
||||
protected:
|
||||
static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
|
||||
@@ -180,6 +181,7 @@ private:
|
||||
};
|
||||
|
||||
bool IsInterestingWindow(HWND window) noexcept;
|
||||
bool IsCursorTypeIndicatingSizeEvent();
|
||||
void UpdateZoneWindows() noexcept;
|
||||
void MoveWindowsOnDisplayChange() noexcept;
|
||||
void UpdateDragState(HWND window, require_write_lock) noexcept;
|
||||
@@ -679,7 +681,7 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
|
||||
//const bool flash = m_settings->GetSettings()->zoneSetChange_flashZones && newWorkArea;
|
||||
const bool flash = false;
|
||||
|
||||
auto zoneWindow = MakeZoneWindow(this, m_hinstance, monitor, uniqueId, flash);
|
||||
auto zoneWindow = MakeZoneWindow(this, m_hinstance, monitor, uniqueId, flash, newWorkArea);
|
||||
if (zoneWindow)
|
||||
{
|
||||
m_zoneWindowMap[monitor] = std::move(zoneWindow);
|
||||
@@ -694,6 +696,12 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
|
||||
}
|
||||
|
||||
void FancyZones::MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index) noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
MoveWindowIntoZoneByIndexSet(window, monitor, { index });
|
||||
}
|
||||
|
||||
void FancyZones::MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet) noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
if (window != m_windowMoveSize)
|
||||
@@ -705,7 +713,7 @@ void FancyZones::MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int in
|
||||
if (zoneWindow != m_zoneWindowMap.end())
|
||||
{
|
||||
const auto& zoneWindowPtr = zoneWindow->second;
|
||||
zoneWindowPtr->MoveWindowIntoZoneByIndex(window, index);
|
||||
zoneWindowPtr->MoveWindowIntoZoneByIndexSet(window, indexSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -745,6 +753,33 @@ bool FancyZones::IsInterestingWindow(HWND window) noexcept
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FancyZones::IsCursorTypeIndicatingSizeEvent()
|
||||
{
|
||||
CURSORINFO cursorInfo = { 0 };
|
||||
cursorInfo.cbSize = sizeof(cursorInfo);
|
||||
|
||||
if (::GetCursorInfo(&cursorInfo))
|
||||
{
|
||||
if (::LoadCursor(NULL, IDC_SIZENS) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (::LoadCursor(NULL, IDC_SIZEWE) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (::LoadCursor(NULL, IDC_SIZENESW) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (::LoadCursor(NULL, IDC_SIZENWSE) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FancyZones::UpdateZoneWindows() noexcept
|
||||
{
|
||||
auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM data) -> BOOL {
|
||||
@@ -832,10 +867,8 @@ void FancyZones::UpdateDragState(HWND window, require_write_lock) noexcept
|
||||
m_dragEnabled = !(shift | mouse);
|
||||
}
|
||||
|
||||
const bool windowElevated = IsProcessOfWindowElevated(window);
|
||||
static const bool meElevated = is_process_elevated();
|
||||
static bool warning_shown = false;
|
||||
if (windowElevated && !meElevated)
|
||||
if (!is_process_elevated() && IsProcessOfWindowElevated(window))
|
||||
{
|
||||
m_dragEnabled = false;
|
||||
if (!warning_shown && !is_cant_drag_elevated_warning_disabled())
|
||||
@@ -920,23 +953,10 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
|
||||
|
||||
void FancyZones::MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT const& ptScreen, require_write_lock writeLock) noexcept
|
||||
{
|
||||
// Only enter move/size if the cursor is inside the window rect by a certain padding.
|
||||
// This prevents resize from triggering zones.
|
||||
RECT windowRect{};
|
||||
::GetWindowRect(window, &windowRect);
|
||||
|
||||
const auto padding_x = 8;
|
||||
const auto padding_y = 6;
|
||||
windowRect.top += padding_y;
|
||||
windowRect.left += padding_x;
|
||||
windowRect.right -= padding_x;
|
||||
windowRect.bottom -= padding_y;
|
||||
|
||||
if (PtInRect(&windowRect, ptScreen) == FALSE)
|
||||
if (IsCursorTypeIndicatingSizeEvent())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_inMoveSize = true;
|
||||
|
||||
auto iter = m_zoneWindowMap.find(monitor);
|
||||
|
||||
@@ -604,9 +604,6 @@ namespace JSONHelpers
|
||||
|
||||
if (!std::filesystem::exists(jsonFilePath))
|
||||
{
|
||||
TmpMigrateAppliedZoneSetsFromRegistry();
|
||||
|
||||
// Custom zone sets have to be migrated after applied zone sets!
|
||||
MigrateCustomZoneSetsFromRegistry();
|
||||
|
||||
SaveFancyZonesData();
|
||||
@@ -639,56 +636,6 @@ namespace JSONHelpers
|
||||
json::to_file(jsonFilePath, root);
|
||||
}
|
||||
|
||||
void FancyZonesData::TmpMigrateAppliedZoneSetsFromRegistry()
|
||||
{
|
||||
std::wregex ex(L"^[0-9]{3,4}_[0-9]{3,4}$");
|
||||
|
||||
std::scoped_lock lock{ dataLock };
|
||||
wchar_t key[256];
|
||||
StringCchPrintf(key, ARRAYSIZE(key), L"%s", RegistryHelpers::REG_SETTINGS);
|
||||
HKEY hkey;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS)
|
||||
{
|
||||
wchar_t resolutionKey[256]{};
|
||||
DWORD resolutionKeyLength = ARRAYSIZE(resolutionKey);
|
||||
DWORD i = 0;
|
||||
while (RegEnumKeyW(hkey, i++, resolutionKey, resolutionKeyLength) == ERROR_SUCCESS)
|
||||
{
|
||||
std::wstring resolution{ resolutionKey };
|
||||
wchar_t appliedZoneSetskey[256];
|
||||
StringCchPrintf(appliedZoneSetskey, ARRAYSIZE(appliedZoneSetskey), L"%s\\%s", RegistryHelpers::REG_SETTINGS, resolutionKey);
|
||||
HKEY appliedZoneSetsHkey;
|
||||
if (std::regex_match(resolution, ex) && RegOpenKeyExW(HKEY_CURRENT_USER, appliedZoneSetskey, 0, KEY_ALL_ACCESS, &appliedZoneSetsHkey) == ERROR_SUCCESS)
|
||||
{
|
||||
ZoneSetPersistedDataOLD data;
|
||||
DWORD dataSize = sizeof(data);
|
||||
wchar_t value[256]{};
|
||||
DWORD valueLength = ARRAYSIZE(value);
|
||||
DWORD i = 0;
|
||||
|
||||
while (RegEnumValueW(appliedZoneSetsHkey, i++, value, &valueLength, nullptr, nullptr, reinterpret_cast<BYTE*>(&data), &dataSize) == ERROR_SUCCESS)
|
||||
{
|
||||
ZoneSetData appliedZoneSetData;
|
||||
appliedZoneSetData.type = TypeFromLayoutId(data.LayoutId);
|
||||
if (appliedZoneSetData.type != ZoneSetLayoutType::Custom)
|
||||
{
|
||||
appliedZoneSetData.uuid = std::wstring{ value };
|
||||
}
|
||||
else
|
||||
{
|
||||
// uuid is changed later to actual uuid when migrating custom zone sets
|
||||
appliedZoneSetData.uuid = std::to_wstring(data.LayoutId);
|
||||
}
|
||||
appliedZoneSetsMap[value] = appliedZoneSetData;
|
||||
dataSize = sizeof(data);
|
||||
valueLength = ARRAYSIZE(value);
|
||||
}
|
||||
}
|
||||
resolutionKeyLength = ARRAYSIZE(resolutionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesData::MigrateCustomZoneSetsFromRegistry()
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
@@ -709,30 +656,20 @@ namespace JSONHelpers
|
||||
zoneSetData.type = static_cast<CustomLayoutType>(data[2]);
|
||||
// int version = data[0] * 256 + data[1]; - Not used anymore
|
||||
|
||||
std::wstring uuid = std::to_wstring(data[3] * 256 + data[4]);
|
||||
auto it = std::find_if(appliedZoneSetsMap.cbegin(), appliedZoneSetsMap.cend(), [&uuid](std::pair<std::wstring, ZoneSetData> zoneSetMap) {
|
||||
return zoneSetMap.second.uuid.compare(uuid) == 0;
|
||||
});
|
||||
|
||||
if (it != appliedZoneSetsMap.cend())
|
||||
{
|
||||
uuid = it->first;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUID guid;
|
||||
auto result = CoCreateGuid(&guid);
|
||||
if (result != S_OK)
|
||||
{
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
if (SUCCEEDED_LOG(StringFromCLSID(guid, &guidString)))
|
||||
if (!SUCCEEDED_LOG(StringFromCLSID(guid, &guidString)))
|
||||
{
|
||||
uuid = guidString.get();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
std::wstring uuid = guidString.get();
|
||||
|
||||
switch (zoneSetData.type)
|
||||
{
|
||||
case CustomLayoutType::Grid: {
|
||||
|
||||
@@ -207,12 +207,16 @@ namespace JSONHelpers
|
||||
#if defined(UNIT_TESTS)
|
||||
inline void clear_data()
|
||||
{
|
||||
appliedZoneSetsMap.clear();
|
||||
appZoneHistoryMap.clear();
|
||||
deviceInfoMap.clear();
|
||||
customZoneSetsMap.clear();
|
||||
activeDeviceId.clear();
|
||||
}
|
||||
|
||||
inline void SetDeviceInfo(const std::wstring& deviceId, DeviceInfoData data)
|
||||
{
|
||||
deviceInfoMap[deviceId] = data;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void SetActiveDeviceId(const std::wstring& deviceId)
|
||||
@@ -254,10 +258,8 @@ namespace JSONHelpers
|
||||
void SaveFancyZonesData() const;
|
||||
|
||||
private:
|
||||
void TmpMigrateAppliedZoneSetsFromRegistry();
|
||||
void MigrateCustomZoneSetsFromRegistry();
|
||||
|
||||
std::unordered_map<std::wstring, ZoneSetData> appliedZoneSetsMap{};
|
||||
std::unordered_map<std::wstring, AppZoneHistoryData> appZoneHistoryMap{};
|
||||
std::unordered_map<std::wstring, DeviceInfoData> deviceInfoMap{};
|
||||
std::unordered_map<std::wstring, CustomZoneSetData> customZoneSetsMap{};
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <common/monitors.h>
|
||||
#include "Zone.h"
|
||||
#include "Settings.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "common/monitors.h"
|
||||
|
||||
struct Zone : winrt::implements<Zone, IZone>
|
||||
{
|
||||
@@ -20,6 +23,7 @@ public:
|
||||
IFACEMETHODIMP_(void) RemoveWindowFromZone(HWND window, bool restoreSize) noexcept;
|
||||
IFACEMETHODIMP_(void) SetId(size_t id) noexcept { m_id = id; }
|
||||
IFACEMETHODIMP_(size_t) Id() noexcept { return m_id; }
|
||||
IFACEMETHODIMP_(RECT) ComputeActualZoneRect(HWND window, HWND zoneWindow) noexcept;
|
||||
|
||||
private:
|
||||
void SizeWindowToZone(HWND window, HWND zoneWindow) noexcept;
|
||||
@@ -61,14 +65,13 @@ IFACEMETHODIMP_(void) Zone::RemoveWindowFromZone(HWND window, bool restoreSize)
|
||||
|
||||
void Zone::SizeWindowToZone(HWND window, HWND zoneWindow) noexcept
|
||||
{
|
||||
// Skip invisible windows
|
||||
if (!IsWindowVisible(window))
|
||||
{
|
||||
return;
|
||||
}
|
||||
SizeWindowToRect(window, ComputeActualZoneRect(window, zoneWindow));
|
||||
}
|
||||
|
||||
RECT Zone::ComputeActualZoneRect(HWND window, HWND zoneWindow) noexcept
|
||||
{
|
||||
// Take care of 1px border
|
||||
RECT zoneRect = m_zoneRect;
|
||||
RECT newWindowRect = m_zoneRect;
|
||||
|
||||
RECT windowRect{};
|
||||
::GetWindowRect(window, &windowRect);
|
||||
@@ -77,57 +80,43 @@ void Zone::SizeWindowToZone(HWND window, HWND zoneWindow) noexcept
|
||||
|
||||
const auto level = DPIAware::GetAwarenessLevel(GetWindowDpiAwarenessContext(window));
|
||||
const bool accountForUnawareness = level < DPIAware::PER_MONITOR_AWARE;
|
||||
|
||||
if (SUCCEEDED(DwmGetWindowAttribute(window, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRect, sizeof(frameRect))))
|
||||
{
|
||||
const auto left_margin = frameRect.left - windowRect.left;
|
||||
const auto right_margin = frameRect.right - windowRect.right;
|
||||
const auto bottom_margin = frameRect.bottom - windowRect.bottom;
|
||||
zoneRect.left -= left_margin;
|
||||
zoneRect.right -= right_margin;
|
||||
zoneRect.bottom -= bottom_margin;
|
||||
LONG leftMargin = frameRect.left - windowRect.left;
|
||||
LONG rightMargin = frameRect.right - windowRect.right;
|
||||
LONG bottomMargin = frameRect.bottom - windowRect.bottom;
|
||||
newWindowRect.left -= leftMargin;
|
||||
newWindowRect.right -= rightMargin;
|
||||
newWindowRect.bottom -= bottomMargin;
|
||||
}
|
||||
|
||||
// Map to screen coords
|
||||
MapWindowRect(zoneWindow, nullptr, &zoneRect);
|
||||
MapWindowRect(zoneWindow, nullptr, &newWindowRect);
|
||||
|
||||
MONITORINFO mi{sizeof(mi)};
|
||||
MONITORINFO mi{ sizeof(mi) };
|
||||
if (GetMonitorInfoW(MonitorFromWindow(zoneWindow, MONITOR_DEFAULTTONEAREST), &mi))
|
||||
{
|
||||
const auto taskbar_left_size = std::abs(mi.rcMonitor.left - mi.rcWork.left);
|
||||
const auto taskbar_top_size = std::abs(mi.rcMonitor.top - mi.rcWork.top);
|
||||
OffsetRect(&zoneRect, -taskbar_left_size, -taskbar_top_size);
|
||||
if (accountForUnawareness)
|
||||
OffsetRect(&newWindowRect, -taskbar_left_size, -taskbar_top_size);
|
||||
|
||||
if (accountForUnawareness && MonitorInfo::GetMonitorsCount() > 1)
|
||||
{
|
||||
zoneRect.left = max(mi.rcMonitor.left, zoneRect.left);
|
||||
zoneRect.right = min(mi.rcMonitor.right - taskbar_left_size, zoneRect.right);
|
||||
zoneRect.top = max(mi.rcMonitor.top, zoneRect.top);
|
||||
zoneRect.bottom = min(mi.rcMonitor.bottom - taskbar_top_size, zoneRect.bottom);
|
||||
newWindowRect.left = max(mi.rcMonitor.left, newWindowRect.left);
|
||||
newWindowRect.right = min(mi.rcMonitor.right - taskbar_left_size, newWindowRect.right);
|
||||
newWindowRect.top = max(mi.rcMonitor.top, newWindowRect.top);
|
||||
newWindowRect.bottom = min(mi.rcMonitor.bottom - taskbar_top_size, newWindowRect.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
WINDOWPLACEMENT placement{};
|
||||
::GetWindowPlacement(window, &placement);
|
||||
|
||||
//wait if SW_SHOWMINIMIZED would be removed from window (Issue #1685)
|
||||
for (int i = 0; i < 5 && (placement.showCmd & SW_SHOWMINIMIZED) != 0; i++)
|
||||
if ((::GetWindowLong(window, GWL_STYLE) & WS_SIZEBOX) == 0)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
::GetWindowPlacement(window, &placement);
|
||||
newWindowRect.right = newWindowRect.left + (windowRect.right - windowRect.left);
|
||||
newWindowRect.bottom = newWindowRect.top + (windowRect.bottom - windowRect.top);
|
||||
}
|
||||
|
||||
// Do not restore minimized windows. We change their placement though so they restore to the correct zone.
|
||||
if ((placement.showCmd & SW_SHOWMINIMIZED) == 0)
|
||||
{
|
||||
placement.showCmd = SW_RESTORE | SW_SHOWNA;
|
||||
}
|
||||
|
||||
placement.rcNormalPosition = zoneRect;
|
||||
placement.flags |= WPF_ASYNCWINDOWPLACEMENT;
|
||||
|
||||
::SetWindowPlacement(window, &placement);
|
||||
// Do it again, allowing Windows to resize the window and set correct scaling
|
||||
// This fixes Issue #365
|
||||
::SetWindowPlacement(window, &placement);
|
||||
return newWindowRect;
|
||||
}
|
||||
|
||||
void Zone::StampZone(HWND window, bool stamp) noexcept
|
||||
|
||||
@@ -42,9 +42,20 @@ interface __declspec(uuid("{8228E934-B6EF-402A-9892-15A1441BF8B0}")) IZone : pub
|
||||
*/
|
||||
IFACEMETHOD_(void, SetId)(size_t id) = 0;
|
||||
/**
|
||||
* @retirns Zone identifier.
|
||||
* @returns Zone identifier.
|
||||
*/
|
||||
IFACEMETHOD_(size_t, Id)() = 0;
|
||||
|
||||
/**
|
||||
* Compute the coordinates of the rectangle to which a window should be resized.
|
||||
*
|
||||
* @param window Handle of window which should be assigned to zone.
|
||||
* @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the
|
||||
* current monitor desktop work area.
|
||||
* @returns a RECT structure, describing global coordinates to which a window should be resized
|
||||
*/
|
||||
IFACEMETHOD_(RECT, ComputeActualZoneRect)(HWND window, HWND zoneWindow) = 0;
|
||||
|
||||
};
|
||||
|
||||
winrt::com_ptr<IZone> MakeZone(const RECT& zoneRect) noexcept;
|
||||
|
||||
@@ -122,14 +122,16 @@ public:
|
||||
IFACEMETHODIMP_(JSONHelpers::ZoneSetLayoutType)
|
||||
LayoutType() noexcept { return m_config.LayoutType; }
|
||||
IFACEMETHODIMP AddZone(winrt::com_ptr<IZone> zone) noexcept;
|
||||
IFACEMETHODIMP_(winrt::com_ptr<IZone>)
|
||||
ZoneFromPoint(POINT pt) noexcept;
|
||||
IFACEMETHODIMP_(std::vector<int>)
|
||||
ZonesFromPoint(POINT pt) noexcept;
|
||||
IFACEMETHODIMP_(int)
|
||||
GetZoneIndexFromWindow(HWND window) noexcept;
|
||||
IFACEMETHODIMP_(std::vector<winrt::com_ptr<IZone>>)
|
||||
GetZones() noexcept { return m_zones; }
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveWindowIntoZoneByIndex(HWND window, HWND zoneWindow, int index) noexcept;
|
||||
MoveWindowIntoZoneByIndex(HWND window, HWND zoneWindow, int index, bool stampZone) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveWindowIntoZoneByIndexSet(HWND window, HWND windowZone, const std::vector<int>& indexSet, bool stampZone) noexcept;
|
||||
IFACEMETHODIMP_(bool)
|
||||
MoveWindowIntoZoneByDirection(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
@@ -162,41 +164,79 @@ IFACEMETHODIMP ZoneSet::AddZone(winrt::com_ptr<IZone> zone) noexcept
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(winrt::com_ptr<IZone>)
|
||||
ZoneSet::ZoneFromPoint(POINT pt) noexcept
|
||||
IFACEMETHODIMP_(std::vector<int>)
|
||||
ZoneSet::ZonesFromPoint(POINT pt) noexcept
|
||||
{
|
||||
winrt::com_ptr<IZone> smallestKnownZone = nullptr;
|
||||
// To reduce redundant calculations, we will store the last known zones area.
|
||||
int smallestKnownZoneArea = INT32_MAX;
|
||||
for (auto iter = m_zones.rbegin(); iter != m_zones.rend(); iter++)
|
||||
const int SENSITIVITY_RADIUS = 20;
|
||||
std::vector<int> capturedZones;
|
||||
std::vector<int> strictlyCapturedZones;
|
||||
for (size_t i = 0; i < m_zones.size(); i++)
|
||||
{
|
||||
if (winrt::com_ptr<IZone> zone = iter->try_as<IZone>())
|
||||
auto zone = m_zones[i];
|
||||
RECT newZoneRect = zone->GetZoneRect();
|
||||
if (newZoneRect.left < newZoneRect.right && newZoneRect.top < newZoneRect.bottom) // proper zone
|
||||
{
|
||||
RECT* newZoneRect = &zone->GetZoneRect();
|
||||
if (PtInRect(newZoneRect, pt))
|
||||
if (newZoneRect.left - SENSITIVITY_RADIUS <= pt.x && pt.x <= newZoneRect.right + SENSITIVITY_RADIUS &&
|
||||
newZoneRect.top - SENSITIVITY_RADIUS <= pt.y && pt.y <= newZoneRect.bottom + SENSITIVITY_RADIUS)
|
||||
{
|
||||
if (smallestKnownZone == nullptr)
|
||||
{
|
||||
smallestKnownZone = zone;
|
||||
capturedZones.emplace_back(static_cast<int>(i));
|
||||
}
|
||||
|
||||
RECT* r = &smallestKnownZone->GetZoneRect();
|
||||
smallestKnownZoneArea = (r->right - r->left) * (r->bottom - r->top);
|
||||
}
|
||||
else
|
||||
if (newZoneRect.left <= pt.x && pt.x < newZoneRect.right &&
|
||||
newZoneRect.top <= pt.y && pt.y < newZoneRect.bottom)
|
||||
{
|
||||
int newZoneArea = (newZoneRect->right - newZoneRect->left) * (newZoneRect->bottom - newZoneRect->top);
|
||||
|
||||
if (newZoneArea < smallestKnownZoneArea)
|
||||
{
|
||||
smallestKnownZone = zone;
|
||||
smallestKnownZoneArea = newZoneArea;
|
||||
}
|
||||
}
|
||||
strictlyCapturedZones.emplace_back(static_cast<int>(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return smallestKnownZone;
|
||||
// If only one zone is captured, but it's not strictly captured
|
||||
// don't consider it as captured
|
||||
if (capturedZones.size() == 1 && strictlyCapturedZones.size() == 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// If captured zones do not overlap, return all of them
|
||||
// Otherwise, return the smallest one
|
||||
|
||||
bool overlap = false;
|
||||
for (size_t i = 0; i < capturedZones.size(); ++i)
|
||||
{
|
||||
for (size_t j = i + 1; j < capturedZones.size(); ++j)
|
||||
{
|
||||
auto rectI = m_zones[capturedZones[i]]->GetZoneRect();
|
||||
auto rectJ = m_zones[capturedZones[j]]->GetZoneRect();
|
||||
if (max(rectI.top, rectJ.top) < min(rectI.bottom, rectJ.bottom) &&
|
||||
max(rectI.left, rectJ.left) < min(rectI.right, rectJ.right))
|
||||
{
|
||||
overlap = true;
|
||||
i = capturedZones.size() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (overlap)
|
||||
{
|
||||
size_t smallestIdx = 0;
|
||||
for (size_t i = 1; i < capturedZones.size(); ++i)
|
||||
{
|
||||
auto rectS = m_zones[capturedZones[smallestIdx]]->GetZoneRect();
|
||||
auto rectI = m_zones[capturedZones[i]]->GetZoneRect();
|
||||
int smallestSize = (rectS.bottom - rectS.top) * (rectS.right - rectS.left);
|
||||
int iSize = (rectI.bottom - rectI.top) * (rectI.right - rectI.left);
|
||||
|
||||
if (iSize <= smallestSize)
|
||||
{
|
||||
smallestIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
capturedZones = { capturedZones[smallestIdx] };
|
||||
}
|
||||
|
||||
return capturedZones;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(int)
|
||||
@@ -217,7 +257,7 @@ ZoneSet::GetZoneIndexFromWindow(HWND window) noexcept
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneSet::MoveWindowIntoZoneByIndex(HWND window, HWND windowZone, int index) noexcept
|
||||
ZoneSet::MoveWindowIntoZoneByIndex(HWND window, HWND windowZone, int index, bool stampZone) noexcept
|
||||
{
|
||||
if (m_zones.empty())
|
||||
{
|
||||
@@ -236,7 +276,55 @@ ZoneSet::MoveWindowIntoZoneByIndex(HWND window, HWND windowZone, int index) noex
|
||||
|
||||
if (auto zone = m_zones.at(index))
|
||||
{
|
||||
zone->AddWindowToZone(window, windowZone, false);
|
||||
zone->AddWindowToZone(window, windowZone, stampZone);
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND windowZone, const std::vector<int>& indexSet, bool stampZone) noexcept
|
||||
{
|
||||
if (m_zones.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (auto zoneDrop = ZoneFromWindow(window))
|
||||
{
|
||||
zoneDrop->RemoveWindowFromZone(window, !IsZoomed(window));
|
||||
}
|
||||
|
||||
if (indexSet.size() == 1)
|
||||
{
|
||||
MoveWindowIntoZoneByIndex(window, windowZone, indexSet[0], stampZone);
|
||||
return;
|
||||
}
|
||||
|
||||
RECT size;
|
||||
bool sizeEmpty = true;
|
||||
|
||||
for (int index : indexSet)
|
||||
{
|
||||
if (index < static_cast<int>(m_zones.size()))
|
||||
{
|
||||
RECT newSize = m_zones.at(index)->ComputeActualZoneRect(window, windowZone);
|
||||
if (!sizeEmpty)
|
||||
{
|
||||
size.left = min(size.left, newSize.left);
|
||||
size.top = min(size.top, newSize.top);
|
||||
size.right = max(size.right, newSize.right);
|
||||
size.bottom = max(size.bottom, newSize.bottom);
|
||||
}
|
||||
else
|
||||
{
|
||||
size = newSize;
|
||||
sizeEmpty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sizeEmpty)
|
||||
{
|
||||
SizeWindowToRect(window, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,10 +394,8 @@ ZoneSet::MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient)
|
||||
zoneDrop->RemoveWindowFromZone(window, !IsZoomed(window));
|
||||
}
|
||||
|
||||
if (auto zone = ZoneFromPoint(ptClient))
|
||||
{
|
||||
zone->AddWindowToZone(window, zoneWindow, true);
|
||||
}
|
||||
auto zones = ZonesFromPoint(ptClient);
|
||||
MoveWindowIntoZoneByIndexSet(window, zoneWindow, zones, true);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
|
||||
@@ -24,12 +24,12 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
|
||||
*/
|
||||
IFACEMETHOD(AddZone)(winrt::com_ptr<IZone> zone) = 0;
|
||||
/**
|
||||
* Get zone from cursor coordinates.
|
||||
* Get zones from cursor coordinates.
|
||||
*
|
||||
* @param pt Cursor coordinates.
|
||||
* @returns Zone object (defining coordinates of the zone).
|
||||
* @returns Vector of indices, corresponding to the current set of zones - the zones considered active.
|
||||
*/
|
||||
IFACEMETHOD_(winrt::com_ptr<IZone>, ZoneFromPoint)(POINT pt) = 0;
|
||||
IFACEMETHOD_(std::vector<int>, ZonesFromPoint)(POINT pt) = 0;
|
||||
/**
|
||||
* Get index of the zone inside zone layout by window assigned to it.
|
||||
*
|
||||
@@ -48,8 +48,20 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
|
||||
* @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the
|
||||
* current monitor desktop work area.
|
||||
* @param index Zone index within zone layout.
|
||||
* @param stampZone Whether the window being added to the zone should be stamped.
|
||||
*/
|
||||
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(HWND window, HWND zoneWindow, int index) = 0;
|
||||
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(HWND window, HWND zoneWindow, int index, bool stampZone) = 0;
|
||||
/**
|
||||
* Assign window to the zones based on the set of zone indices inside zone layout.
|
||||
*
|
||||
* @param window Handle of window which should be assigned to zone.
|
||||
* @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the
|
||||
* current monitor desktop work area.
|
||||
* @param indexSet The set of zone indices within zone layout.
|
||||
* @param stampZone Whether the window being added to the zone should be stamped,
|
||||
in case a single window is to be added.
|
||||
*/
|
||||
IFACEMETHOD_(void, MoveWindowIntoZoneByIndexSet)(HWND window, HWND zoneWindow, const std::vector<int>& indexSet, bool stampZone) = 0;
|
||||
/**
|
||||
* Assign window to the zone based on direction (using WIN + LEFT/RIGHT arrow).
|
||||
*
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace ZoneWindowDrawUtils
|
||||
Gdiplus::Color fillColor(colorSetting.fillAlpha, GetRValue(colorSetting.fill), GetGValue(colorSetting.fill), GetBValue(colorSetting.fill));
|
||||
Gdiplus::Color borderColor(colorSetting.borderAlpha, GetRValue(colorSetting.border), GetGValue(colorSetting.border), GetBValue(colorSetting.border));
|
||||
|
||||
Gdiplus::Rect rectangle(zoneRect.left, zoneRect.top, zoneRect.right - zoneRect.left, zoneRect.bottom - zoneRect.top);
|
||||
Gdiplus::Rect rectangle(zoneRect.left, zoneRect.top, zoneRect.right - zoneRect.left - 1, zoneRect.bottom - zoneRect.top - 1);
|
||||
|
||||
Gdiplus::Pen pen(borderColor, static_cast<Gdiplus::REAL>(colorSetting.thickness));
|
||||
g.FillRectangle(new Gdiplus::SolidBrush(fillColor), rectangle);
|
||||
@@ -148,7 +148,7 @@ namespace ZoneWindowDrawUtils
|
||||
COLORREF highlightColor,
|
||||
int zoneOpacity,
|
||||
const std::vector<winrt::com_ptr<IZone>>& zones,
|
||||
const winrt::com_ptr<IZone>& highlightZone,
|
||||
const std::vector<int>& highlightZones,
|
||||
bool flashMode,
|
||||
bool drawHints) noexcept
|
||||
{
|
||||
@@ -158,15 +158,22 @@ namespace ZoneWindowDrawUtils
|
||||
ColorSetting colorHighlight{ OpacitySettingToAlpha(zoneOpacity), 0, 255, 0, -2 };
|
||||
ColorSetting const colorFlash{ OpacitySettingToAlpha(zoneOpacity), RGB(81, 92, 107), 200, RGB(104, 118, 138), -2 };
|
||||
|
||||
std::vector<bool> isHighlighted(zones.size(), false);
|
||||
for (int x : highlightZones)
|
||||
{
|
||||
isHighlighted[x] = true;
|
||||
}
|
||||
|
||||
for (auto iter = zones.begin(); iter != zones.end(); iter++)
|
||||
{
|
||||
int zoneId = static_cast<int>(iter - zones.begin());
|
||||
winrt::com_ptr<IZone> zone = iter->try_as<IZone>();
|
||||
if (!zone)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zone != highlightZone)
|
||||
if (!isHighlighted[zoneId])
|
||||
{
|
||||
if (flashMode)
|
||||
{
|
||||
@@ -182,13 +189,12 @@ namespace ZoneWindowDrawUtils
|
||||
DrawZone(hdc, colorViewer, zone, zones, flashMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (highlightZone)
|
||||
else
|
||||
{
|
||||
colorHighlight.fill = highlightColor;
|
||||
colorHighlight.border = zoneBorderColor;
|
||||
DrawZone(hdc, colorHighlight, highlightZone, zones, flashMode);
|
||||
DrawZone(hdc, colorHighlight, zone, zones, flashMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,7 +205,7 @@ public:
|
||||
ZoneWindow(HINSTANCE hinstance);
|
||||
~ZoneWindow();
|
||||
|
||||
bool Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, bool flashZones);
|
||||
bool Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, bool flashZones, bool newWorkArea);
|
||||
|
||||
IFACEMETHODIMP MoveSizeEnter(HWND window, bool dragEnabled) noexcept;
|
||||
IFACEMETHODIMP MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled) noexcept;
|
||||
@@ -210,6 +216,8 @@ public:
|
||||
IsDragEnabled() noexcept { return m_dragEnabled; }
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveWindowIntoZoneByIndex(HWND window, int index) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<int>& indexSet) noexcept;
|
||||
IFACEMETHODIMP_(bool)
|
||||
MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode, bool cycle) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
@@ -232,13 +240,13 @@ protected:
|
||||
|
||||
private:
|
||||
void LoadSettings() noexcept;
|
||||
void InitializeZoneSets(MONITORINFO const& mi) noexcept;
|
||||
void InitializeZoneSets(bool newWorkArea) noexcept;
|
||||
void CalculateZoneSet() noexcept;
|
||||
void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept;
|
||||
LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept;
|
||||
void OnPaint(wil::unique_hdc& hdc) noexcept;
|
||||
void OnKeyUp(WPARAM wparam) noexcept;
|
||||
winrt::com_ptr<IZone> ZoneFromPoint(POINT pt) noexcept;
|
||||
std::vector<int> ZonesFromPoint(POINT pt) noexcept;
|
||||
void CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept;
|
||||
void FlashZones() noexcept;
|
||||
|
||||
@@ -253,7 +261,7 @@ private:
|
||||
bool m_dragEnabled{};
|
||||
winrt::com_ptr<IZoneSet> m_activeZoneSet;
|
||||
std::vector<winrt::com_ptr<IZoneSet>> m_zoneSets;
|
||||
winrt::com_ptr<IZone> m_highlightZone;
|
||||
std::vector<int> m_highlightZone;
|
||||
WPARAM m_keyLast{};
|
||||
size_t m_keyCycle{};
|
||||
static const UINT m_showAnimationDuration = 200; // ms
|
||||
@@ -289,7 +297,7 @@ ZoneWindow::~ZoneWindow()
|
||||
Gdiplus::GdiplusShutdown(gdiplusToken);
|
||||
}
|
||||
|
||||
bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, bool flashZones)
|
||||
bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, bool flashZones, bool newWorkArea)
|
||||
{
|
||||
m_host.copy_from(host);
|
||||
|
||||
@@ -308,7 +316,7 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
|
||||
|
||||
m_uniqueId = uniqueId;
|
||||
LoadSettings();
|
||||
InitializeZoneSets(mi);
|
||||
InitializeZoneSets(newWorkArea);
|
||||
|
||||
m_window = wil::unique_hwnd{
|
||||
CreateWindowExW(WS_EX_TOOLWINDOW, L"SuperFancyZones_ZoneWindow", L"", WS_POPUP, workAreaRect.left(), workAreaRect.top(), workAreaRect.width(), workAreaRect.height(), nullptr, nullptr, hinstance, this)
|
||||
@@ -363,7 +371,7 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnter(HWND window, bool dragEnabled) noexcept
|
||||
m_dragEnabled = dragEnabled;
|
||||
m_windowMoveSize = window;
|
||||
m_drawHints = true;
|
||||
m_highlightZone = nullptr;
|
||||
m_highlightZone = {};
|
||||
ShowZoneWindow();
|
||||
return S_OK;
|
||||
}
|
||||
@@ -378,13 +386,13 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable
|
||||
|
||||
if (dragEnabled)
|
||||
{
|
||||
auto highlightZone = ZoneFromPoint(ptClient);
|
||||
auto highlightZone = ZonesFromPoint(ptClient);
|
||||
redraw = (highlightZone != m_highlightZone);
|
||||
m_highlightZone = std::move(highlightZone);
|
||||
}
|
||||
else if (m_highlightZone)
|
||||
else if (m_highlightZone.size())
|
||||
{
|
||||
m_highlightZone = nullptr;
|
||||
m_highlightZone = {};
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
@@ -432,10 +440,16 @@ ZoneWindow::RestoreOrginalTransparency() noexcept
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::MoveWindowIntoZoneByIndex(HWND window, int index) noexcept
|
||||
{
|
||||
MoveWindowIntoZoneByIndexSet(window, { index });
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<int>& indexSet) noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
m_activeZoneSet->MoveWindowIntoZoneByIndex(window, m_window.get(), index);
|
||||
m_activeZoneSet->MoveWindowIntoZoneByIndexSet(window, m_window.get(), indexSet, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,7 +532,7 @@ ZoneWindow::HideZoneWindow() noexcept
|
||||
m_keyLast = 0;
|
||||
m_windowMoveSize = nullptr;
|
||||
m_drawHints = false;
|
||||
m_highlightZone = nullptr;
|
||||
m_highlightZone = {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,10 +543,10 @@ void ZoneWindow::LoadSettings() noexcept
|
||||
JSONHelpers::FancyZonesDataInstance().AddDevice(m_uniqueId);
|
||||
}
|
||||
|
||||
void ZoneWindow::InitializeZoneSets(MONITORINFO const& mi) noexcept
|
||||
void ZoneWindow::InitializeZoneSets(bool newWorkArea) noexcept
|
||||
{
|
||||
auto parent = m_host->GetParentZoneWindow(m_monitor);
|
||||
if (parent)
|
||||
if (newWorkArea && parent)
|
||||
{
|
||||
// Update device info with device info from parent virtual desktop (if empty).
|
||||
JSONHelpers::FancyZonesDataInstance().CloneDeviceInfo(parent->UniqueId(), m_uniqueId);
|
||||
@@ -685,13 +699,13 @@ void ZoneWindow::OnKeyUp(WPARAM wparam) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
winrt::com_ptr<IZone> ZoneWindow::ZoneFromPoint(POINT pt) noexcept
|
||||
std::vector<int> ZoneWindow::ZonesFromPoint(POINT pt) noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
return m_activeZoneSet->ZoneFromPoint(pt);
|
||||
return m_activeZoneSet->ZonesFromPoint(pt);
|
||||
}
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
void ZoneWindow::CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept
|
||||
@@ -739,7 +753,7 @@ void ZoneWindow::CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::Inp
|
||||
{
|
||||
m_host->MoveWindowsOnActiveZoneSetChange();
|
||||
}
|
||||
m_highlightZone = nullptr;
|
||||
m_highlightZone = {};
|
||||
}
|
||||
|
||||
void ZoneWindow::FlashZones() noexcept
|
||||
@@ -773,10 +787,10 @@ LRESULT CALLBACK ZoneWindow::s_WndProc(HWND window, UINT message, WPARAM wparam,
|
||||
DefWindowProc(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, bool flashZones) noexcept
|
||||
winrt::com_ptr<IZoneWindow> MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, bool flashZones, bool newWorkArea) noexcept
|
||||
{
|
||||
auto self = winrt::make_self<ZoneWindow>(hinstance);
|
||||
if (self->Init(host, hinstance, monitor, uniqueId, flashZones))
|
||||
if (self->Init(host, hinstance, monitor, uniqueId, flashZones, newWorkArea))
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,13 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow
|
||||
* @param index Zone index within zone layout.
|
||||
*/
|
||||
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(HWND window, int index) = 0;
|
||||
/**
|
||||
* Assign window to the zones based on the set of zone indices inside zone layout.
|
||||
*
|
||||
* @param window Handle of window which should be assigned to zone.
|
||||
* @param indexSet The set of zone indices within zone layout.
|
||||
*/
|
||||
IFACEMETHOD_(void, MoveWindowIntoZoneByIndexSet)(HWND window, const std::vector<int>& indexSet) = 0;
|
||||
/**
|
||||
* Assign window to the zone based on direction (using WIN + LEFT/RIGHT arrow).
|
||||
*
|
||||
@@ -98,4 +105,4 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow
|
||||
};
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor,
|
||||
const std::wstring& uniqueId, bool flashZones) noexcept;
|
||||
const std::wstring& uniqueId, bool flashZones, bool newWorkArea) noexcept;
|
||||
|
||||
@@ -108,3 +108,30 @@ void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo)
|
||||
|
||||
monitorInfo = std::move(sortedMonitorInfo);
|
||||
}
|
||||
|
||||
void SizeWindowToRect(HWND window, RECT rect) noexcept
|
||||
{
|
||||
WINDOWPLACEMENT placement{};
|
||||
::GetWindowPlacement(window, &placement);
|
||||
|
||||
//wait if SW_SHOWMINIMIZED would be removed from window (Issue #1685)
|
||||
for (int i = 0; i < 5 && (placement.showCmd & SW_SHOWMINIMIZED) != 0; i++)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
::GetWindowPlacement(window, &placement);
|
||||
}
|
||||
|
||||
// Do not restore minimized windows. We change their placement though so they restore to the correct zone.
|
||||
if ((placement.showCmd & SW_SHOWMINIMIZED) == 0)
|
||||
{
|
||||
placement.showCmd = SW_RESTORE | SW_SHOWNA;
|
||||
}
|
||||
|
||||
placement.rcNormalPosition = rect;
|
||||
placement.flags |= WPF_ASYNCWINDOWPLACEMENT;
|
||||
|
||||
::SetWindowPlacement(window, &placement);
|
||||
// Do it again, allowing Windows to resize the window and set correct scaling
|
||||
// This fixes Issue #365
|
||||
::SetWindowPlacement(window, &placement);
|
||||
}
|
||||
|
||||
@@ -118,3 +118,4 @@ inline BYTE OpacitySettingToAlpha(int opacity)
|
||||
|
||||
UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
|
||||
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
|
||||
void SizeWindowToRect(HWND window, RECT rect) noexcept;
|
||||
|
||||
@@ -132,8 +132,8 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (ZoneFromPointEmpty)
|
||||
{
|
||||
auto actual = m_set->ZoneFromPoint(POINT{ 0, 0 });
|
||||
Assert::IsTrue(nullptr == actual);
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ 0, 0 });
|
||||
Assert::IsTrue(actual.size() == 0);
|
||||
}
|
||||
|
||||
TEST_METHOD (ZoneFromPointInner)
|
||||
@@ -146,9 +146,9 @@ namespace FancyZonesUnitTests
|
||||
{
|
||||
for (int j = top + 1; j < bottom; j++)
|
||||
{
|
||||
auto actual = m_set->ZoneFromPoint(POINT{ i, j });
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
compareZones(expected, actual);
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ i, j });
|
||||
Assert::IsTrue(actual.size() == 1);
|
||||
compareZones(expected, m_set->GetZones()[actual[0]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,29 +161,29 @@ namespace FancyZonesUnitTests
|
||||
|
||||
for (int i = left; i < right; i++)
|
||||
{
|
||||
auto actual = m_set->ZoneFromPoint(POINT{ i, top });
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
compareZones(expected, actual);
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ i, top });
|
||||
Assert::IsTrue(actual.size() == 1);
|
||||
compareZones(expected, m_set->GetZones()[actual[0]]);
|
||||
}
|
||||
|
||||
for (int i = top; i < bottom; i++)
|
||||
{
|
||||
auto actual = m_set->ZoneFromPoint(POINT{ left, i });
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
compareZones(expected, actual);
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ left, i });
|
||||
Assert::IsTrue(actual.size() == 1);
|
||||
compareZones(expected, m_set->GetZones()[actual[0]]);
|
||||
}
|
||||
|
||||
//bottom and right borders considered to be outside
|
||||
for (int i = left; i < right; i++)
|
||||
{
|
||||
auto actual = m_set->ZoneFromPoint(POINT{ i, bottom });
|
||||
Assert::IsTrue(nullptr == actual);
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ i, bottom });
|
||||
Assert::IsTrue(actual.size() == 0);
|
||||
}
|
||||
|
||||
for (int i = top; i < bottom; i++)
|
||||
{
|
||||
auto actual = m_set->ZoneFromPoint(POINT{ right, i });
|
||||
Assert::IsTrue(nullptr == actual);
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ right, i });
|
||||
Assert::IsTrue(actual.size() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,8 +193,8 @@ namespace FancyZonesUnitTests
|
||||
winrt::com_ptr<IZone> zone = MakeZone({ left, top, right, bottom });
|
||||
m_set->AddZone(zone);
|
||||
|
||||
auto actual = m_set->ZoneFromPoint(POINT{ 101, 101 });
|
||||
Assert::IsTrue(actual == nullptr);
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ 200, 200 });
|
||||
Assert::IsTrue(actual.size() == 0);
|
||||
}
|
||||
|
||||
TEST_METHOD (ZoneFromPointOverlapping)
|
||||
@@ -208,9 +208,65 @@ namespace FancyZonesUnitTests
|
||||
winrt::com_ptr<IZone> zone4 = MakeZone({ 10, 10, 50, 50 });
|
||||
m_set->AddZone(zone4);
|
||||
|
||||
auto actual = m_set->ZoneFromPoint(POINT{ 50, 50 });
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
compareZones(zone2, actual);
|
||||
// zone4 is expected because it's the smallest one, and it's considered to be inside
|
||||
// since Multizones support
|
||||
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ 50, 50 });
|
||||
Assert::IsTrue(actual.size() == 1);
|
||||
compareZones(zone4, m_set->GetZones()[actual[0]]);
|
||||
}
|
||||
|
||||
TEST_METHOD (ZoneFromPointMultizoneHorizontal)
|
||||
{
|
||||
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
|
||||
m_set->AddZone(zone1);
|
||||
winrt::com_ptr<IZone> zone2 = MakeZone({ 100, 0, 200, 100 });
|
||||
m_set->AddZone(zone2);
|
||||
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 100, 100, 200 });
|
||||
m_set->AddZone(zone3);
|
||||
winrt::com_ptr<IZone> zone4 = MakeZone({ 100, 100, 200, 200 });
|
||||
m_set->AddZone(zone4);
|
||||
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ 50, 100 });
|
||||
Assert::IsTrue(actual.size() == 2);
|
||||
compareZones(zone1, m_set->GetZones()[actual[0]]);
|
||||
compareZones(zone3, m_set->GetZones()[actual[1]]);
|
||||
}
|
||||
|
||||
TEST_METHOD (ZoneFromPointMultizoneVertical)
|
||||
{
|
||||
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
|
||||
m_set->AddZone(zone1);
|
||||
winrt::com_ptr<IZone> zone2 = MakeZone({ 100, 0, 200, 100 });
|
||||
m_set->AddZone(zone2);
|
||||
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 100, 100, 200 });
|
||||
m_set->AddZone(zone3);
|
||||
winrt::com_ptr<IZone> zone4 = MakeZone({ 100, 100, 200, 200 });
|
||||
m_set->AddZone(zone4);
|
||||
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ 100, 50 });
|
||||
Assert::IsTrue(actual.size() == 2);
|
||||
compareZones(zone1, m_set->GetZones()[actual[0]]);
|
||||
compareZones(zone2, m_set->GetZones()[actual[1]]);
|
||||
}
|
||||
|
||||
TEST_METHOD(ZoneFromPointMultizoneQuad)
|
||||
{
|
||||
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
|
||||
m_set->AddZone(zone1);
|
||||
winrt::com_ptr<IZone> zone2 = MakeZone({ 100, 0, 200, 100 });
|
||||
m_set->AddZone(zone2);
|
||||
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 100, 100, 200 });
|
||||
m_set->AddZone(zone3);
|
||||
winrt::com_ptr<IZone> zone4 = MakeZone({ 100, 100, 200, 200 });
|
||||
m_set->AddZone(zone4);
|
||||
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ 100, 100 });
|
||||
Assert::IsTrue(actual.size() == 4);
|
||||
compareZones(zone1, m_set->GetZones()[actual[0]]);
|
||||
compareZones(zone2, m_set->GetZones()[actual[1]]);
|
||||
compareZones(zone3, m_set->GetZones()[actual[2]]);
|
||||
compareZones(zone4, m_set->GetZones()[actual[3]]);
|
||||
}
|
||||
|
||||
TEST_METHOD (ZoneFromPointWithNotNormalizedRect)
|
||||
@@ -218,8 +274,8 @@ namespace FancyZonesUnitTests
|
||||
winrt::com_ptr<IZone> zone = MakeZone({ 100, 100, 0, 0 });
|
||||
m_set->AddZone(zone);
|
||||
|
||||
auto actual = m_set->ZoneFromPoint(POINT{ 50, 50 });
|
||||
Assert::IsTrue(actual == nullptr);
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ 50, 50 });
|
||||
Assert::IsTrue(actual.size() == 0);
|
||||
}
|
||||
|
||||
TEST_METHOD (ZoneFromPointWithZeroRect)
|
||||
@@ -227,8 +283,8 @@ namespace FancyZonesUnitTests
|
||||
winrt::com_ptr<IZone> zone = MakeZone({ 0, 0, 0, 0 });
|
||||
m_set->AddZone(zone);
|
||||
|
||||
auto actual = m_set->ZoneFromPoint(POINT{ 0, 0 });
|
||||
Assert::IsTrue(actual == nullptr);
|
||||
auto actual = m_set->ZonesFromPoint(POINT{ 0, 0 });
|
||||
Assert::IsTrue(actual.size() == 0);
|
||||
}
|
||||
|
||||
TEST_METHOD (ZoneIndexFromWindow)
|
||||
@@ -316,7 +372,7 @@ namespace FancyZonesUnitTests
|
||||
m_set->AddZone(zone3);
|
||||
|
||||
HWND window = Mocks::Window();
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1);
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1, false);
|
||||
Assert::IsFalse(zone1->ContainsWindow(window));
|
||||
Assert::IsTrue(zone2->ContainsWindow(window));
|
||||
Assert::IsFalse(zone3->ContainsWindow(window));
|
||||
@@ -325,7 +381,7 @@ namespace FancyZonesUnitTests
|
||||
TEST_METHOD (MoveWindowIntoZoneByIndexWithNoZones)
|
||||
{
|
||||
HWND window = Mocks::Window();
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveWindowIntoZoneByIndexWithInvalidIndex)
|
||||
@@ -338,8 +394,8 @@ namespace FancyZonesUnitTests
|
||||
m_set->AddZone(zone3);
|
||||
|
||||
HWND window = Mocks::Window();
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 100);
|
||||
Assert::IsTrue(zone1->ContainsWindow(window));
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 100, false);
|
||||
Assert::IsFalse(zone1->ContainsWindow(window));
|
||||
Assert::IsFalse(zone2->ContainsWindow(window));
|
||||
Assert::IsFalse(zone3->ContainsWindow(window));
|
||||
}
|
||||
@@ -355,17 +411,17 @@ namespace FancyZonesUnitTests
|
||||
m_set->AddZone(zone3);
|
||||
|
||||
HWND window = Mocks::Window();
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
|
||||
Assert::IsTrue(zone1->ContainsWindow(window));
|
||||
Assert::IsFalse(zone2->ContainsWindow(window));
|
||||
Assert::IsFalse(zone3->ContainsWindow(window));
|
||||
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1);
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1, false);
|
||||
Assert::IsFalse(zone1->ContainsWindow(window));
|
||||
Assert::IsTrue(zone2->ContainsWindow(window));
|
||||
Assert::IsFalse(zone3->ContainsWindow(window));
|
||||
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 2);
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 2, false);
|
||||
Assert::IsFalse(zone1->ContainsWindow(window));
|
||||
Assert::IsFalse(zone2->ContainsWindow(window));
|
||||
Assert::IsTrue(zone3->ContainsWindow(window));
|
||||
@@ -382,9 +438,9 @@ namespace FancyZonesUnitTests
|
||||
m_set->AddZone(zone3);
|
||||
|
||||
HWND window = Mocks::Window();
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
|
||||
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
|
||||
Assert::IsTrue(zone1->ContainsWindow(window));
|
||||
Assert::IsFalse(zone2->ContainsWindow(window));
|
||||
Assert::IsFalse(zone3->ContainsWindow(window));
|
||||
@@ -401,7 +457,7 @@ namespace FancyZonesUnitTests
|
||||
m_set->AddZone(zone1);
|
||||
|
||||
auto window = Mocks::Window();
|
||||
m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 101, 101 });
|
||||
m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 200, 200 });
|
||||
|
||||
Assert::IsFalse(zone1->ContainsWindow(window));
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace FancyZonesUnitTests
|
||||
{
|
||||
const std::wstring m_deviceId = L"\\\\?\\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}";
|
||||
const std::wstring m_virtualDesktopId = L"MyVirtualDesktopId";
|
||||
std::wstringstream m_parentUniqueId;
|
||||
std::wstringstream m_uniqueId;
|
||||
|
||||
HINSTANCE m_hInst{};
|
||||
@@ -75,6 +76,7 @@ namespace FancyZonesUnitTests
|
||||
m_monitorInfo.cbSize = sizeof(m_monitorInfo);
|
||||
Assert::AreNotEqual(0, GetMonitorInfoW(m_monitor, &m_monitorInfo));
|
||||
|
||||
m_parentUniqueId << L"DELA026#5&10a58c63&0&UID16777488_" << m_monitorInfo.rcMonitor.right << "_" << m_monitorInfo.rcMonitor.bottom << "_{61FA9FC0-26A6-4B37-A834-491C148DFC57}";
|
||||
m_uniqueId << L"DELA026#5&10a58c63&0&UID16777488_" << m_monitorInfo.rcMonitor.right << "_" << m_monitorInfo.rcMonitor.bottom << "_{39B25DD2-130D-4B5D-8851-4791D66B1539}";
|
||||
|
||||
Assert::IsFalse(ZoneWindowUtils::GetActiveZoneSetTmpPath().empty());
|
||||
@@ -113,7 +115,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
m_fancyZonesData.ParseDeviceInfoFromTmpFile(activeZoneSetTempPath);
|
||||
|
||||
return MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
return MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
}
|
||||
|
||||
void testZoneWindow(winrt::com_ptr<IZoneWindow> zoneWindow)
|
||||
@@ -129,14 +131,14 @@ namespace FancyZonesUnitTests
|
||||
public:
|
||||
TEST_METHOD(CreateZoneWindow)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
testZoneWindow(m_zoneWindow);
|
||||
Assert::IsNull(m_zoneWindow->ActiveZoneSet());
|
||||
}
|
||||
|
||||
TEST_METHOD(CreateZoneWindowNoHinst)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, {}, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, {}, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
testZoneWindow(m_zoneWindow);
|
||||
Assert::IsNull(m_zoneWindow->ActiveZoneSet());
|
||||
@@ -144,7 +146,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(CreateZoneWindowNoHinstFlashZones)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, {}, m_monitor, m_uniqueId.str(), true);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, {}, m_monitor, m_uniqueId.str(), true, false);
|
||||
|
||||
testZoneWindow(m_zoneWindow);
|
||||
Assert::IsNull(m_zoneWindow->ActiveZoneSet());
|
||||
@@ -152,7 +154,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(CreateZoneWindowNoMonitor)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, {}, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, {}, m_uniqueId.str(), false, false);
|
||||
|
||||
Assert::IsNull(m_zoneWindow.get());
|
||||
Assert::IsNotNull(m_hostPtr);
|
||||
@@ -160,7 +162,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(CreateZoneWindowNoMonitorFlashZones)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, {}, m_uniqueId.str(), true);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, {}, m_uniqueId.str(), true, false);
|
||||
|
||||
Assert::IsNull(m_zoneWindow.get());
|
||||
Assert::IsNotNull(m_hostPtr);
|
||||
@@ -170,7 +172,7 @@ namespace FancyZonesUnitTests
|
||||
{
|
||||
// Generate unique id without device id
|
||||
std::wstring uniqueId = ZoneWindowUtils::GenerateUniqueId(m_monitor, nullptr, m_virtualDesktopId.c_str());
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, uniqueId, false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, uniqueId, false, false);
|
||||
|
||||
const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom);
|
||||
const std::wstring expectedUniqueId = L"FallbackDevice_" + std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom) + L"_" + m_virtualDesktopId;
|
||||
@@ -186,7 +188,7 @@ namespace FancyZonesUnitTests
|
||||
{
|
||||
// Generate unique id without virtual desktop id
|
||||
std::wstring uniqueId = ZoneWindowUtils::GenerateUniqueId(m_monitor, m_deviceId.c_str(), nullptr);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, uniqueId, false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, uniqueId, false, false);
|
||||
|
||||
const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom);
|
||||
Assert::IsNotNull(m_zoneWindow.get());
|
||||
@@ -213,7 +215,7 @@ namespace FancyZonesUnitTests
|
||||
m_fancyZonesData.ParseDeviceInfoFromTmpFile(activeZoneSetTempPath);
|
||||
|
||||
//temp file read on initialization
|
||||
auto actual = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
auto actual = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
testZoneWindow(actual);
|
||||
|
||||
@@ -237,7 +239,7 @@ namespace FancyZonesUnitTests
|
||||
m_fancyZonesData.ParseDeviceInfoFromTmpFile(activeZoneSetTempPath);
|
||||
|
||||
//temp file read on initialization
|
||||
auto actual = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
auto actual = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
testZoneWindow(actual);
|
||||
|
||||
@@ -273,7 +275,7 @@ namespace FancyZonesUnitTests
|
||||
m_fancyZonesData.ParseCustomZoneSetFromTmpFile(appliedZoneSetTempPath);
|
||||
|
||||
//temp file read on initialization
|
||||
auto actual = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
auto actual = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
testZoneWindow(actual);
|
||||
|
||||
@@ -320,7 +322,7 @@ namespace FancyZonesUnitTests
|
||||
m_fancyZonesData.ParseCustomZoneSetFromTmpFile(appliedZoneSetTempPath);
|
||||
|
||||
//temp file read on initialization
|
||||
auto actual = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
auto actual = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
testZoneWindow(actual);
|
||||
|
||||
@@ -367,7 +369,7 @@ namespace FancyZonesUnitTests
|
||||
m_fancyZonesData.ParseCustomZoneSetFromTmpFile(appliedZoneSetTempPath);
|
||||
|
||||
//temp file read on initialization
|
||||
auto actual = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
auto actual = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
testZoneWindow(actual);
|
||||
|
||||
@@ -376,9 +378,68 @@ namespace FancyZonesUnitTests
|
||||
Assert::AreEqual((size_t)1, actualZoneSet.size());
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowClonedFromParent)
|
||||
{
|
||||
using namespace JSONHelpers;
|
||||
|
||||
const ZoneSetLayoutType type = ZoneSetLayoutType::PriorityGrid;
|
||||
const int spacing = 10;
|
||||
const int zoneCount = 5;
|
||||
const auto customSetGuid = Helpers::CreateGuidString();
|
||||
const auto parentZoneSet = ZoneSetData{ customSetGuid, type };
|
||||
const auto parentDeviceInfo = DeviceInfoData{ parentZoneSet, true, spacing, zoneCount };
|
||||
m_fancyZonesData.SetDeviceInfo(m_parentUniqueId.str(), parentDeviceInfo);
|
||||
|
||||
auto parentZoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_parentUniqueId.str(), false, false);
|
||||
m_zoneWindowHost.m_zoneWindow = parentZoneWindow.get();
|
||||
|
||||
// newWorkArea = true - zoneWindow will be cloned from parent
|
||||
auto actualZoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, true);
|
||||
|
||||
Assert::IsNotNull(actualZoneWindow->ActiveZoneSet());
|
||||
const auto actualZoneSet = actualZoneWindow->ActiveZoneSet()->GetZones();
|
||||
Assert::AreEqual((size_t)zoneCount, actualZoneSet.size());
|
||||
|
||||
Assert::IsTrue(m_fancyZonesData.GetDeviceInfoMap().contains(m_uniqueId.str()));
|
||||
auto currentDeviceInfo = m_fancyZonesData.GetDeviceInfoMap().at(m_uniqueId.str());
|
||||
Assert::AreEqual(zoneCount, currentDeviceInfo.zoneCount);
|
||||
Assert::AreEqual(spacing, currentDeviceInfo.spacing);
|
||||
Assert::AreEqual(static_cast<int>(type), static_cast<int>(currentDeviceInfo.activeZoneSet.type));
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowNotClonedFromParent)
|
||||
{
|
||||
using namespace JSONHelpers;
|
||||
|
||||
const ZoneSetLayoutType type = ZoneSetLayoutType::PriorityGrid;
|
||||
const int spacing = 10;
|
||||
const int zoneCount = 5;
|
||||
const auto customSetGuid = Helpers::CreateGuidString();
|
||||
const auto parentZoneSet = ZoneSetData{ customSetGuid, type };
|
||||
const auto parentDeviceInfo = DeviceInfoData{ parentZoneSet, true, spacing, zoneCount };
|
||||
m_fancyZonesData.SetDeviceInfo(m_parentUniqueId.str(), parentDeviceInfo);
|
||||
|
||||
auto parentZoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_parentUniqueId.str(), false, false);
|
||||
m_zoneWindowHost.m_zoneWindow = parentZoneWindow.get();
|
||||
|
||||
// newWorkArea = false - zoneWindow won't be cloned from parent
|
||||
auto actualZoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
Assert::IsNull(actualZoneWindow->ActiveZoneSet());
|
||||
|
||||
Assert::IsTrue(m_fancyZonesData.GetDeviceInfoMap().contains(m_uniqueId.str()));
|
||||
auto currentDeviceInfo = m_fancyZonesData.GetDeviceInfoMap().at(m_uniqueId.str());
|
||||
// default values
|
||||
Assert::AreEqual(false, currentDeviceInfo.showSpacing);
|
||||
Assert::AreEqual(0, currentDeviceInfo.zoneCount);
|
||||
Assert::AreEqual(0, currentDeviceInfo.spacing);
|
||||
Assert::AreEqual(std::wstring{ L"null" }, currentDeviceInfo.activeZoneSet.uuid);
|
||||
Assert::AreEqual(static_cast<int>(ZoneSetLayoutType::Blank), static_cast<int>(currentDeviceInfo.activeZoneSet.type));
|
||||
}
|
||||
|
||||
TEST_METHOD(MoveSizeEnter)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = m_zoneWindow->MoveSizeEnter(Mocks::Window(), true);
|
||||
@@ -389,7 +450,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(MoveSizeEnterTwice)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
const auto expected = E_INVALIDARG;
|
||||
|
||||
@@ -402,7 +463,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(MoveSizeUpdate)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = m_zoneWindow->MoveSizeUpdate(POINT{ 0, 0 }, true);
|
||||
@@ -413,7 +474,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(MoveSizeUpdatePointNegativeCoordinates)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = m_zoneWindow->MoveSizeUpdate(POINT{ -10, -10 }, true);
|
||||
@@ -424,7 +485,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(MoveSizeUpdatePointBigCoordinates)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = m_zoneWindow->MoveSizeUpdate(POINT{ m_monitorInfo.rcMonitor.right + 1, m_monitorInfo.rcMonitor.bottom + 1 }, true);
|
||||
@@ -445,7 +506,7 @@ namespace FancyZonesUnitTests
|
||||
Assert::AreEqual(expected, actual);
|
||||
|
||||
const auto zoneSet = zoneWindow->ActiveZoneSet();
|
||||
zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), false);
|
||||
zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
|
||||
const auto actualZoneIndex = zoneSet->GetZoneIndexFromWindow(window);
|
||||
Assert::AreNotEqual(-1, actualZoneIndex);
|
||||
}
|
||||
@@ -458,7 +519,7 @@ namespace FancyZonesUnitTests
|
||||
zoneWindow->MoveSizeEnter(window, true);
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = zoneWindow->MoveSizeEnd(window, POINT{ 0, 0 });
|
||||
const auto actual = zoneWindow->MoveSizeEnd(window, POINT{ -100, -100 });
|
||||
Assert::AreEqual(expected, actual);
|
||||
|
||||
const auto zoneSet = zoneWindow->ActiveZoneSet();
|
||||
@@ -468,7 +529,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(MoveSizeEndDifferentWindows)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
const auto window = Mocks::Window();
|
||||
m_zoneWindow->MoveSizeEnter(window, true);
|
||||
@@ -481,7 +542,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(MoveSizeEndWindowNotSet)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
|
||||
const auto expected = E_INVALIDARG;
|
||||
const auto actual = m_zoneWindow->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 });
|
||||
@@ -501,14 +562,14 @@ namespace FancyZonesUnitTests
|
||||
Assert::AreEqual(expected, actual);
|
||||
|
||||
const auto zoneSet = zoneWindow->ActiveZoneSet();
|
||||
zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), false);
|
||||
zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
|
||||
const auto actualZoneIndex = zoneSet->GetZoneIndexFromWindow(window);
|
||||
Assert::AreNotEqual(-1, actualZoneIndex); //with invalid point zone remains the same
|
||||
}
|
||||
|
||||
TEST_METHOD(MoveWindowIntoZoneByIndexNoActiveZoneSet)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
Assert::IsNull(m_zoneWindow->ActiveZoneSet());
|
||||
|
||||
m_zoneWindow->MoveWindowIntoZoneByIndex(Mocks::Window(), 0);
|
||||
@@ -526,7 +587,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(MoveWindowIntoZoneByDirectionNoActiveZoneSet)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
Assert::IsNull(m_zoneWindow->ActiveZoneSet());
|
||||
|
||||
m_zoneWindow->MoveWindowIntoZoneByIndex(Mocks::Window(), 0);
|
||||
@@ -564,7 +625,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD(SaveWindowProcessToZoneIndexNoActiveZoneSet)
|
||||
{
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false);
|
||||
m_zoneWindow = MakeZoneWindow(m_hostPtr, m_hInst, m_monitor, m_uniqueId.str(), false, false);
|
||||
Assert::IsNull(m_zoneWindow->ActiveZoneSet());
|
||||
|
||||
m_zoneWindow->SaveWindowProcessToZoneIndex(Mocks::Window());
|
||||
@@ -650,5 +711,29 @@ namespace FancyZonesUnitTests
|
||||
const auto actual = m_fancyZonesData.GetAppZoneHistoryMap().at(processPath).zoneIndex;
|
||||
Assert::AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt)
|
||||
{
|
||||
m_zoneWindow = InitZoneWindowWithActiveZoneSet();
|
||||
Assert::IsNotNull(m_zoneWindow->ActiveZoneSet());
|
||||
|
||||
auto window = Mocks::WindowCreate(m_hInst);
|
||||
|
||||
int orginalWidth = 450;
|
||||
int orginalHeight = 550;
|
||||
|
||||
SetWindowPos(window, nullptr, 150, 150, orginalWidth, orginalHeight, SWP_SHOWWINDOW);
|
||||
SetWindowLong(window, GWL_STYLE, GetWindowLong(window, GWL_STYLE) & ~WS_SIZEBOX);
|
||||
|
||||
auto zone = MakeZone(RECT{ 50, 50, 300, 300 });
|
||||
m_zoneWindow->ActiveZoneSet()->AddZone(zone);
|
||||
|
||||
m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_LEFT, true);
|
||||
|
||||
RECT inZoneRect;
|
||||
GetWindowRect(window, &inZoneRect);
|
||||
Assert::AreEqual(orginalWidth, (int)inZoneRect.right - (int) inZoneRect.left);
|
||||
Assert::AreEqual(orginalHeight, (int)inZoneRect.bottom - (int)inZoneRect.top);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -147,6 +147,7 @@ HRESULT CContextMenuHandler::QueryContextMenu(_In_ HMENU hmenu, UINT indexMenu,
|
||||
if (!InsertMenuItem(hmenu, indexMenu, TRUE, &mii))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
Trace::QueryContextMenuError(hr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -220,12 +221,12 @@ HRESULT CContextMenuHandler::ResizePictures(CMINVOKECOMMANDINFO* pici, IShellIte
|
||||
HRESULT hr = E_FAIL;
|
||||
if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0))
|
||||
{
|
||||
Trace::InvokedRet(hr);
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hr;
|
||||
}
|
||||
if (!SetHandleInformation(hWritePipe, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
Trace::InvokedRet(hr);
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hr;
|
||||
}
|
||||
CAtlFile writePipe(hWritePipe);
|
||||
@@ -277,12 +278,12 @@ HRESULT CContextMenuHandler::ResizePictures(CMINVOKECOMMANDINFO* pici, IShellIte
|
||||
delete[] lpszCommandLine;
|
||||
if (!CloseHandle(processInformation.hProcess))
|
||||
{
|
||||
Trace::InvokedRet(hr);
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hr;
|
||||
}
|
||||
if (!CloseHandle(processInformation.hThread))
|
||||
{
|
||||
Trace::InvokedRet(hr);
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hr;
|
||||
}
|
||||
|
||||
@@ -322,7 +323,6 @@ HRESULT CContextMenuHandler::ResizePictures(CMINVOKECOMMANDINFO* pici, IShellIte
|
||||
|
||||
writePipe.Close();
|
||||
hr = S_OK;
|
||||
Trace::InvokedRet(hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,3 +47,13 @@ void Trace::InvokedRet(_In_ HRESULT hr) noexcept
|
||||
TraceLoggingHResult(hr),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
void Trace::QueryContextMenuError(_In_ HRESULT hr) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"ImageResizer_QueryContextMenuError",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingHResult(hr),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
@@ -8,4 +8,5 @@ public:
|
||||
static void EnableImageResizer(_In_ bool enabled) noexcept;
|
||||
static void Invoked() noexcept;
|
||||
static void InvokedRet(_In_ HRESULT hr) noexcept;
|
||||
static void QueryContextMenuError(_In_ HRESULT hr) noexcept;
|
||||
};
|
||||
@@ -48,7 +48,7 @@ HRESULT CPowerRenameMenu::s_CreateInstance(_In_opt_ IUnknown*, _In_ REFIID riid,
|
||||
HRESULT CPowerRenameMenu::Initialize(_In_opt_ PCIDLIST_ABSOLUTE, _In_ IDataObject* pdtobj, HKEY)
|
||||
{
|
||||
// Check if we have disabled ourselves
|
||||
if (!CSettings::GetEnabled())
|
||||
if (!CSettingsInstance().GetEnabled())
|
||||
return E_FAIL;
|
||||
|
||||
// Cache the data object to be used later
|
||||
@@ -60,11 +60,11 @@ HRESULT CPowerRenameMenu::Initialize(_In_opt_ PCIDLIST_ABSOLUTE, _In_ IDataObjec
|
||||
HRESULT CPowerRenameMenu::QueryContextMenu(HMENU hMenu, UINT index, UINT uIDFirst, UINT, UINT uFlags)
|
||||
{
|
||||
// Check if we have disabled ourselves
|
||||
if (!CSettings::GetEnabled())
|
||||
if (!CSettingsInstance().GetEnabled())
|
||||
return E_FAIL;
|
||||
|
||||
// Check if we should only be on the extended context menu
|
||||
if (CSettings::GetExtendedContextMenuOnly() && (!(uFlags & CMF_EXTENDEDVERBS)))
|
||||
if (CSettingsInstance().GetExtendedContextMenuOnly() && (!(uFlags & CMF_EXTENDEDVERBS)))
|
||||
return E_FAIL;
|
||||
|
||||
HRESULT hr = E_UNEXPECTED;
|
||||
@@ -81,7 +81,7 @@ HRESULT CPowerRenameMenu::QueryContextMenu(HMENU hMenu, UINT index, UINT uIDFirs
|
||||
mii.dwTypeData = (PWSTR)menuName;
|
||||
mii.fState = MFS_ENABLED;
|
||||
|
||||
if (CSettings::GetShowIconOnMenu())
|
||||
if (CSettingsInstance().GetShowIconOnMenu())
|
||||
{
|
||||
HICON hIcon = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_RENAME), IMAGE_ICON, 16, 16, 0);
|
||||
if (hIcon)
|
||||
@@ -113,7 +113,7 @@ HRESULT CPowerRenameMenu::InvokeCommand(_In_ LPCMINVOKECOMMANDINFO pici)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
if (CSettings::GetEnabled() &&
|
||||
if (CSettingsInstance().GetEnabled() &&
|
||||
(IS_INTRESOURCE(pici->lpVerb)) &&
|
||||
(LOWORD(pici->lpVerb) == 0))
|
||||
{
|
||||
@@ -203,7 +203,7 @@ HRESULT __stdcall CPowerRenameMenu::GetTitle(IShellItemArray* /*psiItemArray*/,
|
||||
|
||||
HRESULT __stdcall CPowerRenameMenu::GetIcon(IShellItemArray* /*psiItemArray*/, LPWSTR* ppszIcon)
|
||||
{
|
||||
if (!CSettings::GetShowIconOnMenu())
|
||||
if (!CSettingsInstance().GetShowIconOnMenu())
|
||||
{
|
||||
*ppszIcon = nullptr;
|
||||
return E_NOTIMPL;
|
||||
@@ -229,7 +229,7 @@ HRESULT __stdcall CPowerRenameMenu::GetCanonicalName(GUID* pguidCommandName)
|
||||
|
||||
HRESULT __stdcall CPowerRenameMenu::GetState(IShellItemArray* psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE* pCmdState)
|
||||
{
|
||||
*pCmdState = CSettings::GetEnabled() ? ECS_ENABLED : ECS_HIDDEN;
|
||||
*pCmdState = CSettingsInstance().GetEnabled() ? ECS_ENABLED : ECS_HIDDEN;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\obj\PowerRenameUI\PowerRenameUI.res;shcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
|
||||
<DelayLoadDLLs>gdi32.dll;advapi32.dll;shell32.dll;ole32.dll;shlwapi.dll;oleaut32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<DelayLoadDLLs>gdi32.dll;shell32.dll;ole32.dll;shlwapi.dll;oleaut32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -207,17 +207,17 @@ public:
|
||||
settings.add_bool_toogle(
|
||||
L"bool_persist_input",
|
||||
GET_RESOURCE_STRING(IDS_RESTORE_SEARCH),
|
||||
CSettings::GetPersistState());
|
||||
CSettingsInstance().GetPersistState());
|
||||
|
||||
settings.add_bool_toogle(
|
||||
L"bool_mru_enabled",
|
||||
GET_RESOURCE_STRING(IDS_ENABLE_AUTO),
|
||||
CSettings::GetMRUEnabled());
|
||||
CSettingsInstance().GetMRUEnabled());
|
||||
|
||||
settings.add_int_spinner(
|
||||
L"int_max_mru_size",
|
||||
GET_RESOURCE_STRING(IDS_MAX_ITEMS),
|
||||
CSettings::GetMaxMRUSize(),
|
||||
CSettingsInstance().GetMaxMRUSize(),
|
||||
0,
|
||||
20,
|
||||
1);
|
||||
@@ -225,12 +225,12 @@ public:
|
||||
settings.add_bool_toogle(
|
||||
L"bool_show_icon_on_menu",
|
||||
GET_RESOURCE_STRING(IDS_ICON_CONTEXT_MENU),
|
||||
CSettings::GetShowIconOnMenu());
|
||||
CSettingsInstance().GetShowIconOnMenu());
|
||||
|
||||
settings.add_bool_toogle(
|
||||
L"bool_show_extended_menu",
|
||||
GET_RESOURCE_STRING(IDS_EXTENDED_MENU_INFO),
|
||||
CSettings::GetExtendedContextMenuOnly());
|
||||
CSettingsInstance().GetExtendedContextMenuOnly());
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
@@ -245,13 +245,12 @@ public:
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config);
|
||||
|
||||
CSettings::SetPersistState(values.get_bool_value(L"bool_persist_input").value());
|
||||
CSettings::SetMRUEnabled(values.get_bool_value(L"bool_mru_enabled").value());
|
||||
CSettings::SetMaxMRUSize(values.get_int_value(L"int_max_mru_size").value());
|
||||
CSettings::SetShowIconOnMenu(values.get_bool_value(L"bool_show_icon_on_menu").value());
|
||||
CSettings::SetExtendedContextMenuOnly(values.get_bool_value(L"bool_show_extended_menu").value());
|
||||
|
||||
values.save_to_settings_file();
|
||||
CSettingsInstance().SetPersistState(values.get_bool_value(L"bool_persist_input").value());
|
||||
CSettingsInstance().SetMRUEnabled(values.get_bool_value(L"bool_mru_enabled").value());
|
||||
CSettingsInstance().SetMaxMRUSize(values.get_int_value(L"int_max_mru_size").value());
|
||||
CSettingsInstance().SetShowIconOnMenu(values.get_bool_value(L"bool_show_icon_on_menu").value());
|
||||
CSettingsInstance().SetExtendedContextMenuOnly(values.get_bool_value(L"bool_show_extended_menu").value());
|
||||
CSettingsInstance().SavePowerRenameData();
|
||||
|
||||
Trace::SettingsChanged();
|
||||
}
|
||||
@@ -284,13 +283,15 @@ public:
|
||||
|
||||
void init_settings()
|
||||
{
|
||||
m_enabled = CSettings::GetEnabled();
|
||||
CSettingsInstance().LoadPowerRenameData();
|
||||
m_enabled = CSettingsInstance().GetEnabled();
|
||||
Trace::EnablePowerRename(m_enabled);
|
||||
}
|
||||
|
||||
void save_settings()
|
||||
{
|
||||
CSettings::SetEnabled(m_enabled);
|
||||
CSettingsInstance().SetEnabled(m_enabled);
|
||||
CSettingsInstance().SavePowerRenameData();
|
||||
Trace::EnablePowerRename(m_enabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,13 +85,14 @@
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -99,7 +100,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
@@ -107,6 +108,7 @@
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -116,7 +118,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
@@ -124,6 +126,7 @@
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -134,7 +137,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
@@ -143,6 +146,7 @@
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
||||
@@ -1,171 +1,70 @@
|
||||
#include "stdafx.h"
|
||||
#include <commctrl.h>
|
||||
#include "Settings.h"
|
||||
#include "PowerRenameInterfaces.h"
|
||||
#include "settings_helpers.h"
|
||||
|
||||
const wchar_t c_rootRegPath[] = L"Software\\Microsoft\\PowerRename";
|
||||
const wchar_t c_mruSearchRegPath[] = L"SearchMRU";
|
||||
const wchar_t c_mruReplaceRegPath[] = L"ReplaceMRU";
|
||||
#include <filesystem>
|
||||
#include <commctrl.h>
|
||||
|
||||
const wchar_t c_enabled[] = L"Enabled";
|
||||
const wchar_t c_showIconOnMenu[] = L"ShowIcon";
|
||||
const wchar_t c_extendedContextMenuOnly[] = L"ExtendedContextMenuOnly";
|
||||
const wchar_t c_persistState[] = L"PersistState";
|
||||
const wchar_t c_maxMRUSize[] = L"MaxMRUSize";
|
||||
const wchar_t c_flags[] = L"Flags";
|
||||
const wchar_t c_searchText[] = L"SearchText";
|
||||
const wchar_t c_replaceText[] = L"ReplaceText";
|
||||
const wchar_t c_mruEnabled[] = L"MRUEnabled";
|
||||
|
||||
const bool c_enabledDefault = true;
|
||||
const bool c_showIconOnMenuDefault = true;
|
||||
const bool c_extendedContextMenuOnlyDefaut = false;
|
||||
const bool c_persistStateDefault = true;
|
||||
const bool c_mruEnabledDefault = true;
|
||||
|
||||
const DWORD c_maxMRUSizeDefault = 10;
|
||||
const DWORD c_flagsDefault = 0;
|
||||
|
||||
bool CSettings::GetEnabled()
|
||||
namespace
|
||||
{
|
||||
return GetRegBoolValue(c_enabled, c_enabledDefault);
|
||||
}
|
||||
const wchar_t c_powerRenameDataFilePath[] = L"power-rename-settings.json";
|
||||
|
||||
bool CSettings::SetEnabled(_In_ bool enabled)
|
||||
{
|
||||
return SetRegBoolValue(c_enabled, enabled);
|
||||
}
|
||||
const wchar_t c_rootRegPath[] = L"Software\\Microsoft\\PowerRename";
|
||||
const wchar_t c_mruSearchRegPath[] = L"SearchMRU";
|
||||
const wchar_t c_mruReplaceRegPath[] = L"ReplaceMRU";
|
||||
|
||||
bool CSettings::GetShowIconOnMenu()
|
||||
{
|
||||
return GetRegBoolValue(c_showIconOnMenu, c_showIconOnMenuDefault);
|
||||
}
|
||||
const wchar_t c_enabled[] = L"Enabled";
|
||||
const wchar_t c_showIconOnMenu[] = L"ShowIcon";
|
||||
const wchar_t c_extendedContextMenuOnly[] = L"ExtendedContextMenuOnly";
|
||||
const wchar_t c_persistState[] = L"PersistState";
|
||||
const wchar_t c_maxMRUSize[] = L"MaxMRUSize";
|
||||
const wchar_t c_flags[] = L"Flags";
|
||||
const wchar_t c_searchText[] = L"SearchText";
|
||||
const wchar_t c_replaceText[] = L"ReplaceText";
|
||||
const wchar_t c_mruEnabled[] = L"MRUEnabled";
|
||||
|
||||
bool CSettings::SetShowIconOnMenu(_In_ bool show)
|
||||
{
|
||||
return SetRegBoolValue(c_showIconOnMenu, show);
|
||||
}
|
||||
|
||||
bool CSettings::GetExtendedContextMenuOnly()
|
||||
{
|
||||
return GetRegBoolValue(c_extendedContextMenuOnly, c_extendedContextMenuOnlyDefaut);
|
||||
}
|
||||
|
||||
bool CSettings::SetExtendedContextMenuOnly(_In_ bool extendedOnly)
|
||||
{
|
||||
return SetRegBoolValue(c_extendedContextMenuOnly, extendedOnly);
|
||||
}
|
||||
|
||||
bool CSettings::GetPersistState()
|
||||
{
|
||||
return GetRegBoolValue(c_persistState, c_persistStateDefault);
|
||||
}
|
||||
|
||||
bool CSettings::SetPersistState(_In_ bool persistState)
|
||||
{
|
||||
return SetRegBoolValue(c_persistState, persistState);
|
||||
}
|
||||
|
||||
bool CSettings::GetMRUEnabled()
|
||||
{
|
||||
return GetRegBoolValue(c_mruEnabled, c_mruEnabledDefault);
|
||||
}
|
||||
|
||||
bool CSettings::SetMRUEnabled(_In_ bool enabled)
|
||||
{
|
||||
return SetRegBoolValue(c_mruEnabled, enabled);
|
||||
}
|
||||
|
||||
DWORD CSettings::GetMaxMRUSize()
|
||||
{
|
||||
return GetRegDWORDValue(c_maxMRUSize, c_maxMRUSizeDefault);
|
||||
}
|
||||
|
||||
bool CSettings::SetMaxMRUSize(_In_ DWORD maxMRUSize)
|
||||
{
|
||||
return SetRegDWORDValue(c_maxMRUSize, maxMRUSize);
|
||||
}
|
||||
|
||||
DWORD CSettings::GetFlags()
|
||||
{
|
||||
return GetRegDWORDValue(c_flags, c_flagsDefault);
|
||||
}
|
||||
|
||||
bool CSettings::SetFlags(_In_ DWORD flags)
|
||||
{
|
||||
return SetRegDWORDValue(c_flags, flags);
|
||||
}
|
||||
|
||||
bool CSettings::GetSearchText(__out_ecount(cchBuf) PWSTR text, DWORD cchBuf)
|
||||
{
|
||||
return GetRegStringValue(c_searchText, text, cchBuf);
|
||||
}
|
||||
|
||||
bool CSettings::SetSearchText(_In_ PCWSTR text)
|
||||
{
|
||||
return SetRegStringValue(c_searchText, text);
|
||||
}
|
||||
|
||||
bool CSettings::GetReplaceText(__out_ecount(cchBuf) PWSTR text, DWORD cchBuf)
|
||||
{
|
||||
return GetRegStringValue(c_replaceText, text, cchBuf);
|
||||
}
|
||||
|
||||
bool CSettings::SetReplaceText(_In_ PCWSTR text)
|
||||
{
|
||||
return SetRegStringValue(c_replaceText, text);
|
||||
}
|
||||
|
||||
bool CSettings::SetRegBoolValue(_In_ PCWSTR valueName, _In_ bool value)
|
||||
{
|
||||
DWORD dwValue = value ? 1 : 0;
|
||||
return SetRegDWORDValue(valueName, dwValue);
|
||||
}
|
||||
|
||||
bool CSettings::GetRegBoolValue(_In_ PCWSTR valueName, _In_ bool defaultValue)
|
||||
{
|
||||
DWORD value = GetRegDWORDValue(valueName, (defaultValue == 0) ? false : true);
|
||||
return (value == 0) ? false : true;
|
||||
}
|
||||
|
||||
bool CSettings::SetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD value)
|
||||
{
|
||||
return (SUCCEEDED(HRESULT_FROM_WIN32(SHSetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, REG_DWORD, &value, sizeof(value)))));
|
||||
}
|
||||
|
||||
DWORD CSettings::GetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD defaultValue)
|
||||
{
|
||||
DWORD retVal = defaultValue;
|
||||
long GetRegNumber(const std::wstring& valueName, long defaultValue)
|
||||
{
|
||||
DWORD type = REG_DWORD;
|
||||
DWORD dwEnabled = 0;
|
||||
DWORD cb = sizeof(dwEnabled);
|
||||
if (SHGetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, &type, &dwEnabled, &cb) == ERROR_SUCCESS)
|
||||
DWORD data = 0;
|
||||
DWORD size = sizeof(DWORD);
|
||||
if (SHGetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName.c_str(), &type, &data, &size) == ERROR_SUCCESS)
|
||||
{
|
||||
retVal = dwEnabled;
|
||||
return data;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool CSettings::SetRegStringValue(_In_ PCWSTR valueName, _In_ PCWSTR value)
|
||||
{
|
||||
ULONG cb = (DWORD)((wcslen(value) + 1) * sizeof(*value));
|
||||
return (SUCCEEDED(HRESULT_FROM_WIN32(SHSetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, REG_SZ, (const BYTE*)value, cb))));
|
||||
}
|
||||
|
||||
bool CSettings::GetRegStringValue(_In_ PCWSTR valueName, __out_ecount(cchBuf) PWSTR value, DWORD cchBuf)
|
||||
{
|
||||
if (cchBuf > 0)
|
||||
void SetRegNumber(const std::wstring& valueName, long value)
|
||||
{
|
||||
SHSetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName.c_str(), REG_DWORD, &value, sizeof(value));
|
||||
}
|
||||
|
||||
bool GetRegBoolean(const std::wstring& valueName, bool defaultValue)
|
||||
{
|
||||
DWORD value = GetRegNumber(valueName.c_str(), defaultValue ? 1 : 0);
|
||||
return (value == 0) ? false : true;
|
||||
}
|
||||
|
||||
void SetRegBoolean(const std::wstring& valueName, bool value)
|
||||
{
|
||||
SetRegNumber(valueName, value ? 1 : 0);
|
||||
}
|
||||
|
||||
std::wstring GetRegString(const std::wstring& valueName) {
|
||||
wchar_t value[CSettings::MAX_INPUT_STRING_LEN];
|
||||
value[0] = L'\0';
|
||||
}
|
||||
|
||||
DWORD type = REG_SZ;
|
||||
ULONG cb = cchBuf * sizeof(*value);
|
||||
return (SUCCEEDED(HRESULT_FROM_WIN32(SHGetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, &type, value, &cb) == ERROR_SUCCESS)));
|
||||
DWORD size = CSettings::MAX_INPUT_STRING_LEN * sizeof(wchar_t);
|
||||
if (SUCCEEDED(HRESULT_FROM_WIN32(SHGetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName.c_str(), &type, value, &size) == ERROR_SUCCESS)))
|
||||
{
|
||||
return std::wstring(value);
|
||||
}
|
||||
return std::wstring{};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef int (CALLBACK* MRUCMPPROC)(LPCWSTR, LPCWSTR);
|
||||
|
||||
typedef struct {
|
||||
@@ -470,12 +369,121 @@ void CRenameMRU::_FreeMRUList()
|
||||
}
|
||||
}
|
||||
|
||||
CSettings::CSettings()
|
||||
{
|
||||
std::wstring result = PTSettingsHelper::get_module_save_folder_location(L"PowerRename");
|
||||
jsonFilePath = result + L"\\" + std::wstring(c_powerRenameDataFilePath);
|
||||
}
|
||||
|
||||
bool CSettings::GetEnabled()
|
||||
{
|
||||
return GetRegBoolean(c_enabled, true);
|
||||
}
|
||||
|
||||
void CSettings::SetEnabled(bool enabled)
|
||||
{
|
||||
SetRegBoolean(c_enabled, enabled);
|
||||
}
|
||||
|
||||
void CSettings::LoadPowerRenameData()
|
||||
{
|
||||
if (!std::filesystem::exists(jsonFilePath))
|
||||
{
|
||||
MigrateSettingsFromRegistry();
|
||||
|
||||
SavePowerRenameData();
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseJsonSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void CSettings::SavePowerRenameData() const
|
||||
{
|
||||
json::JsonObject jsonData;
|
||||
|
||||
jsonData.SetNamedValue(c_showIconOnMenu, json::value(settings.showIconOnMenu));
|
||||
jsonData.SetNamedValue(c_extendedContextMenuOnly, json::value(settings.extendedContextMenuOnly));
|
||||
jsonData.SetNamedValue(c_persistState, json::value(settings.persistState));
|
||||
jsonData.SetNamedValue(c_mruEnabled, json::value(settings.MRUEnabled));
|
||||
jsonData.SetNamedValue(c_maxMRUSize, json::value(settings.maxMRUSize));
|
||||
jsonData.SetNamedValue(c_flags, json::value(settings.flags));
|
||||
jsonData.SetNamedValue(c_searchText, json::value(settings.searchText));
|
||||
jsonData.SetNamedValue(c_replaceText, json::value(settings.replaceText));
|
||||
|
||||
json::to_file(jsonFilePath, jsonData);
|
||||
}
|
||||
|
||||
void CSettings::MigrateSettingsFromRegistry()
|
||||
{
|
||||
settings.showIconOnMenu = GetRegBoolean(c_showIconOnMenu, true);
|
||||
settings.extendedContextMenuOnly = GetRegBoolean(c_extendedContextMenuOnly, false); // Disabled by default.
|
||||
settings.persistState = GetRegBoolean(c_persistState, true);
|
||||
settings.MRUEnabled = GetRegBoolean(c_mruEnabled, true);
|
||||
settings.maxMRUSize = GetRegNumber(c_maxMRUSize, 10);
|
||||
settings.flags = GetRegNumber(c_flags, 0);
|
||||
settings.searchText = GetRegString(c_searchText);
|
||||
settings.replaceText = GetRegString(c_replaceText);
|
||||
}
|
||||
|
||||
void CSettings::ParseJsonSettings()
|
||||
{
|
||||
auto json = json::from_file(jsonFilePath);
|
||||
if (json)
|
||||
{
|
||||
const json::JsonObject& jsonSettings = json.value();
|
||||
try
|
||||
{
|
||||
if (json::has(jsonSettings, c_showIconOnMenu, json::JsonValueType::Boolean))
|
||||
{
|
||||
settings.showIconOnMenu = jsonSettings.GetNamedBoolean(c_showIconOnMenu);
|
||||
}
|
||||
if (json::has(jsonSettings, c_extendedContextMenuOnly, json::JsonValueType::Boolean))
|
||||
{
|
||||
settings.extendedContextMenuOnly = jsonSettings.GetNamedBoolean(c_extendedContextMenuOnly);
|
||||
}
|
||||
if (json::has(jsonSettings, c_persistState, json::JsonValueType::Boolean))
|
||||
{
|
||||
settings.persistState = jsonSettings.GetNamedBoolean(c_persistState);
|
||||
}
|
||||
if (json::has(jsonSettings, c_mruEnabled, json::JsonValueType::Boolean))
|
||||
{
|
||||
settings.MRUEnabled = jsonSettings.GetNamedBoolean(c_mruEnabled);
|
||||
}
|
||||
if (json::has(jsonSettings, c_maxMRUSize, json::JsonValueType::Number))
|
||||
{
|
||||
settings.maxMRUSize = (long)jsonSettings.GetNamedNumber(c_maxMRUSize);
|
||||
}
|
||||
if (json::has(jsonSettings, c_flags, json::JsonValueType::Number))
|
||||
{
|
||||
settings.flags = (long)jsonSettings.GetNamedNumber(c_flags);
|
||||
}
|
||||
if (json::has(jsonSettings, c_searchText, json::JsonValueType::String))
|
||||
{
|
||||
settings.searchText = jsonSettings.GetNamedString(c_searchText);
|
||||
}
|
||||
if (json::has(jsonSettings, c_replaceText, json::JsonValueType::String))
|
||||
{
|
||||
settings.replaceText = jsonSettings.GetNamedString(c_replaceText);
|
||||
}
|
||||
}
|
||||
catch (const winrt::hresult_error&) { }
|
||||
}
|
||||
}
|
||||
|
||||
CSettings& CSettingsInstance()
|
||||
{
|
||||
static CSettings instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
HRESULT CRenameMRUSearch_CreateInstance(_Outptr_ IUnknown** ppUnk)
|
||||
{
|
||||
return CRenameMRU::CreateInstance(c_mruSearchRegPath, CSettings::GetMaxMRUSize(), ppUnk);
|
||||
return CRenameMRU::CreateInstance(c_mruSearchRegPath, CSettingsInstance().GetMaxMRUSize(), ppUnk);
|
||||
}
|
||||
|
||||
HRESULT CRenameMRUReplace_CreateInstance(_Outptr_ IUnknown** ppUnk)
|
||||
{
|
||||
return CRenameMRU::CreateInstance(c_mruReplaceRegPath, CSettings::GetMaxMRUSize(), ppUnk);
|
||||
return CRenameMRU::CreateInstance(c_mruReplaceRegPath, CSettingsInstance().GetMaxMRUSize(), ppUnk);
|
||||
}
|
||||
|
||||
@@ -1,45 +1,124 @@
|
||||
#pragma once
|
||||
|
||||
#include "json.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CSettings
|
||||
{
|
||||
public:
|
||||
static const int MAX_INPUT_STRING_LEN = 1024;
|
||||
|
||||
static bool GetEnabled();
|
||||
static bool SetEnabled(_In_ bool enabled);
|
||||
CSettings();
|
||||
|
||||
static bool GetShowIconOnMenu();
|
||||
static bool SetShowIconOnMenu(_In_ bool show);
|
||||
bool GetEnabled();
|
||||
|
||||
static bool GetExtendedContextMenuOnly();
|
||||
static bool SetExtendedContextMenuOnly(_In_ bool extendedOnly);
|
||||
void SetEnabled(bool enabled);
|
||||
|
||||
static bool GetPersistState();
|
||||
static bool SetPersistState(_In_ bool extendedOnly);
|
||||
inline bool GetShowIconOnMenu() const
|
||||
{
|
||||
return settings.showIconOnMenu;
|
||||
}
|
||||
|
||||
static bool GetMRUEnabled();
|
||||
static bool SetMRUEnabled(_In_ bool enabled);
|
||||
inline void SetShowIconOnMenu(bool show)
|
||||
{
|
||||
settings.showIconOnMenu = show;
|
||||
}
|
||||
|
||||
static DWORD GetMaxMRUSize();
|
||||
static bool SetMaxMRUSize(_In_ DWORD maxMRUSize);
|
||||
inline bool GetExtendedContextMenuOnly() const
|
||||
{
|
||||
return settings.extendedContextMenuOnly;
|
||||
}
|
||||
|
||||
static DWORD GetFlags();
|
||||
static bool SetFlags(_In_ DWORD flags);
|
||||
inline void SetExtendedContextMenuOnly(bool extendedOnly)
|
||||
{
|
||||
settings.extendedContextMenuOnly = extendedOnly;
|
||||
}
|
||||
|
||||
static bool GetSearchText(__out_ecount(cchBuf) PWSTR text, DWORD cchBuf);
|
||||
static bool SetSearchText(_In_ PCWSTR text);
|
||||
inline bool GetPersistState() const
|
||||
{
|
||||
return settings.persistState;
|
||||
}
|
||||
|
||||
static bool GetReplaceText(__out_ecount(cchBuf) PWSTR text, DWORD cchBuf);
|
||||
static bool SetReplaceText(_In_ PCWSTR text);
|
||||
inline void SetPersistState(bool persistState)
|
||||
{
|
||||
settings.persistState = persistState;
|
||||
}
|
||||
|
||||
inline bool GetMRUEnabled() const
|
||||
{
|
||||
return settings.MRUEnabled;
|
||||
}
|
||||
|
||||
inline void SetMRUEnabled(bool MRUEnabled)
|
||||
{
|
||||
settings.MRUEnabled = MRUEnabled;
|
||||
}
|
||||
|
||||
inline long GetMaxMRUSize() const
|
||||
{
|
||||
return settings.maxMRUSize;
|
||||
}
|
||||
|
||||
inline void SetMaxMRUSize(long maxMRUSize)
|
||||
{
|
||||
settings.maxMRUSize = maxMRUSize;
|
||||
}
|
||||
|
||||
inline long GetFlags() const
|
||||
{
|
||||
return settings.flags;
|
||||
}
|
||||
|
||||
inline void SetFlags(long flags)
|
||||
{
|
||||
settings.flags = flags;
|
||||
}
|
||||
|
||||
inline const std::wstring& GetSearchText() const
|
||||
{
|
||||
return settings.searchText;
|
||||
}
|
||||
|
||||
inline void SetSearchText(const std::wstring& text)
|
||||
{
|
||||
settings.searchText = text;
|
||||
}
|
||||
|
||||
inline const std::wstring& GetReplaceText() const
|
||||
{
|
||||
return settings.replaceText;
|
||||
}
|
||||
|
||||
inline void SetReplaceText(const std::wstring& text)
|
||||
{
|
||||
settings.replaceText = text;
|
||||
}
|
||||
|
||||
void LoadPowerRenameData();
|
||||
void SavePowerRenameData() const;
|
||||
|
||||
private:
|
||||
static bool GetRegBoolValue(_In_ PCWSTR valueName, _In_ bool defaultValue);
|
||||
static bool SetRegBoolValue(_In_ PCWSTR valueName, _In_ bool value);
|
||||
static bool SetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD value);
|
||||
static DWORD GetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD defaultValue);
|
||||
static bool SetRegStringValue(_In_ PCWSTR valueName, _In_ PCWSTR value);
|
||||
static bool GetRegStringValue(_In_ PCWSTR valueName, __out_ecount(cchBuf) PWSTR value, DWORD cchBuf);
|
||||
struct Settings
|
||||
{
|
||||
bool showIconOnMenu{ true };
|
||||
bool extendedContextMenuOnly{ false }; // Disabled by default.
|
||||
bool persistState{ true };
|
||||
bool MRUEnabled{ true };
|
||||
long maxMRUSize{ 10 };
|
||||
long flags{ 0 };
|
||||
std::wstring searchText{};
|
||||
std::wstring replaceText{};
|
||||
};
|
||||
|
||||
void MigrateSettingsFromRegistry();
|
||||
void ParseJsonSettings();
|
||||
|
||||
Settings settings;
|
||||
std::wstring jsonFilePath;
|
||||
};
|
||||
|
||||
CSettings& CSettingsInstance();
|
||||
|
||||
HRESULT CRenameMRUSearch_CreateInstance(_Outptr_ IUnknown** ppUnk);
|
||||
HRESULT CRenameMRUReplace_CreateInstance(_Outptr_ IUnknown** ppUnk);
|
||||
@@ -19,3 +19,5 @@
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include <ProjectTelemetry.h>
|
||||
|
||||
#pragma comment(lib, "windowsapp")
|
||||
|
||||
@@ -79,11 +79,11 @@ void Trace::SettingsChanged() noexcept
|
||||
"PowerRename_SettingsChanged",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(CSettings::GetEnabled(), "IsEnabled"),
|
||||
TraceLoggingBoolean(CSettings::GetShowIconOnMenu(), "ShowIconOnMenu"),
|
||||
TraceLoggingBoolean(CSettings::GetExtendedContextMenuOnly(), "ExtendedContextMenuOnly"),
|
||||
TraceLoggingBoolean(CSettings::GetPersistState(), "PersistState"),
|
||||
TraceLoggingBoolean(CSettings::GetMRUEnabled(), "IsMRUEnabled"),
|
||||
TraceLoggingUInt64(CSettings::GetMaxMRUSize(), "MaxMRUSize"),
|
||||
TraceLoggingUInt64(CSettings::GetFlags(), "Flags"));
|
||||
TraceLoggingBoolean(CSettingsInstance().GetEnabled(), "IsEnabled"),
|
||||
TraceLoggingBoolean(CSettingsInstance().GetShowIconOnMenu(), "ShowIconOnMenu"),
|
||||
TraceLoggingBoolean(CSettingsInstance().GetExtendedContextMenuOnly(), "ExtendedContextMenuOnly"),
|
||||
TraceLoggingBoolean(CSettingsInstance().GetPersistState(), "PersistState"),
|
||||
TraceLoggingBoolean(CSettingsInstance().GetMRUEnabled(), "IsMRUEnabled"),
|
||||
TraceLoggingUInt64(CSettingsInstance().GetMaxMRUSize(), "MaxMRUSize"),
|
||||
TraceLoggingUInt64(CSettingsInstance().GetFlags(), "Flags"));
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ HRESULT CPowerRenameUI::_Initialize(_In_ IPowerRenameManager* psrm, _In_opt_ IUn
|
||||
HRESULT CPowerRenameUI::_InitAutoComplete()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
if (CSettings::GetMRUEnabled())
|
||||
if (CSettingsInstance().GetMRUEnabled())
|
||||
{
|
||||
hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&m_spSearchAC));
|
||||
if (SUCCEEDED(hr))
|
||||
@@ -387,19 +387,13 @@ HRESULT CPowerRenameUI::_ReadSettings()
|
||||
// Check if we should read flags from settings
|
||||
// or the defaults from the manager.
|
||||
DWORD flags = 0;
|
||||
if (CSettings::GetPersistState())
|
||||
if (CSettingsInstance().GetPersistState())
|
||||
{
|
||||
flags = CSettings::GetFlags();
|
||||
flags = CSettingsInstance().GetFlags();
|
||||
m_spsrm->put_flags(flags);
|
||||
|
||||
wchar_t buffer[CSettings::MAX_INPUT_STRING_LEN];
|
||||
buffer[0] = L'\0';
|
||||
CSettings::GetSearchText(buffer, ARRAYSIZE(buffer));
|
||||
SetDlgItemText(m_hwnd, IDC_EDIT_SEARCHFOR, buffer);
|
||||
|
||||
buffer[0] = L'\0';
|
||||
CSettings::GetReplaceText(buffer, ARRAYSIZE(buffer));
|
||||
SetDlgItemText(m_hwnd, IDC_EDIT_REPLACEWITH, buffer);
|
||||
SetDlgItemText(m_hwnd, IDC_EDIT_SEARCHFOR, CSettingsInstance().GetSearchText().c_str());
|
||||
SetDlgItemText(m_hwnd, IDC_EDIT_REPLACEWITH, CSettingsInstance().GetReplaceText().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -414,18 +408,18 @@ HRESULT CPowerRenameUI::_ReadSettings()
|
||||
HRESULT CPowerRenameUI::_WriteSettings()
|
||||
{
|
||||
// Check if we should store our settings
|
||||
if (CSettings::GetPersistState())
|
||||
if (CSettingsInstance().GetPersistState())
|
||||
{
|
||||
DWORD flags = 0;
|
||||
m_spsrm->get_flags(&flags);
|
||||
CSettings::SetFlags(flags);
|
||||
CSettingsInstance().SetFlags(flags);
|
||||
|
||||
wchar_t buffer[CSettings::MAX_INPUT_STRING_LEN];
|
||||
buffer[0] = L'\0';
|
||||
GetDlgItemText(m_hwnd, IDC_EDIT_SEARCHFOR, buffer, ARRAYSIZE(buffer));
|
||||
CSettings::SetSearchText(buffer);
|
||||
CSettingsInstance().SetSearchText(buffer);
|
||||
|
||||
if (CSettings::GetMRUEnabled() && m_spSearchACL)
|
||||
if (CSettingsInstance().GetMRUEnabled() && m_spSearchACL)
|
||||
{
|
||||
CComPtr<IPowerRenameMRU> spSearchMRU;
|
||||
if (SUCCEEDED(m_spSearchACL->QueryInterface(IID_PPV_ARGS(&spSearchMRU))))
|
||||
@@ -436,9 +430,9 @@ HRESULT CPowerRenameUI::_WriteSettings()
|
||||
|
||||
buffer[0] = L'\0';
|
||||
GetDlgItemText(m_hwnd, IDC_EDIT_REPLACEWITH, buffer, ARRAYSIZE(buffer));
|
||||
CSettings::SetReplaceText(buffer);
|
||||
CSettingsInstance().SetReplaceText(buffer);
|
||||
|
||||
if (CSettings::GetMRUEnabled() && m_spReplaceACL)
|
||||
if (CSettingsInstance().GetMRUEnabled() && m_spReplaceACL)
|
||||
{
|
||||
CComPtr<IPowerRenameMRU> spReplaceMRU;
|
||||
if (SUCCEEDED(m_spReplaceACL->QueryInterface(IID_PPV_ARGS(&spReplaceMRU))))
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>..\lib\;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
|
||||
@@ -87,7 +87,6 @@
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information. Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/
|
||||
|
||||
@@ -594,9 +594,223 @@ namespace WindowWalker.Components
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetWindow relationship between the specified window and the window whose handle is to be retrieved.
|
||||
/// </summary>
|
||||
public enum GetWindowCmd : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// The retrieved handle identifies the window of the same type that is highest in the Z order.
|
||||
/// </summary>
|
||||
GW_HWNDFIRST = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The retrieved handle identifies the window of the same type that is lowest in the Z order.
|
||||
/// </summary>
|
||||
GW_HWNDLAST = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The retrieved handle identifies the window below the specified window in the Z order.
|
||||
/// </summary>
|
||||
GW_HWNDNEXT = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The retrieved handle identifies the window above the specified window in the Z order.
|
||||
/// </summary>
|
||||
GW_HWNDPREV = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The retrieved handle identifies the specified window's owner window, if any.
|
||||
/// </summary>
|
||||
GW_OWNER = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The retrieved handle identifies the child window at the top of the Z order, if the specified window
|
||||
/// is a parent window.
|
||||
/// </summary>
|
||||
GW_CHILD = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The retrieved handle identifies the enabled popup window owned by the specified window.
|
||||
/// </summary>
|
||||
GW_ENABLEDPOPUP = 6,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetWindowLong index to retrieves the extended window styles.
|
||||
/// </summary>
|
||||
#pragma warning disable SA1310 // Field names should not contain underscore
|
||||
public const int GWL_EXSTYLE = -20;
|
||||
#pragma warning restore SA1310 // Field names should not contain underscore
|
||||
|
||||
/// <summary>
|
||||
/// The following are the extended window styles
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ExtendedWindowStyles : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// The window has a double border; the window can, optionally, be created with a title bar by specifying
|
||||
/// the WS_CAPTION style in the dwStyle parameter.
|
||||
/// </summary>
|
||||
WS_EX_DLGMODALFRAME = 0X0001,
|
||||
|
||||
/// <summary>
|
||||
/// The child window created with this style does not send the WM_PARENTNOTIFY message to its parent window
|
||||
/// when it is created or destroyed.
|
||||
/// </summary>
|
||||
WS_EX_NOPARENTNOTIFY = 0X0004,
|
||||
|
||||
/// <summary>
|
||||
/// The window should be placed above all non-topmost windows and should stay above all non-topmost windows
|
||||
/// and should stay above them, even when the window is deactivated.
|
||||
/// </summary>
|
||||
WS_EX_TOPMOST = 0X0008,
|
||||
|
||||
/// <summary>
|
||||
/// The window accepts drag-drop files.
|
||||
/// </summary>
|
||||
WS_EX_ACCEPTFILES = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// The window should not be painted until siblings beneath the window (that were created by the same thread)
|
||||
/// have been painted.
|
||||
/// </summary>
|
||||
WS_EX_TRANSPARENT = 0x0020,
|
||||
|
||||
/// <summary>
|
||||
/// The window is a MDI child window.
|
||||
/// </summary>
|
||||
WS_EX_MDICHILD = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// The window is intended to be used as a floating toolbar. A tool window has a title bar that is shorter
|
||||
/// than a normal title bar, and the window title is drawn using a smaller font. A tool window does not
|
||||
/// appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
|
||||
/// </summary>
|
||||
WS_EX_TOOLWINDOW = 0x0080,
|
||||
|
||||
/// <summary>
|
||||
/// The window has a border with a raised edge.
|
||||
/// </summary>
|
||||
WS_EX_WINDOWEDGE = 0x0100,
|
||||
|
||||
/// <summary>
|
||||
/// The window has a border with a sunken edge.
|
||||
/// </summary>
|
||||
WS_EX_CLIENTEDGE = 0x0200,
|
||||
|
||||
/// <summary>
|
||||
/// The title bar of the window includes a question mark.
|
||||
/// </summary>
|
||||
WS_EX_CONTEXTHELP = 0x0400,
|
||||
|
||||
/// <summary>
|
||||
/// The window has generic "right-aligned" properties. This depends on the window class. This style has
|
||||
/// an effect only if the shell language supports reading-order alignment, otherwise is ignored.
|
||||
/// </summary>
|
||||
WS_EX_RIGHT = 0x1000,
|
||||
|
||||
/// <summary>
|
||||
/// The window has generic left-aligned properties. This is the default.
|
||||
/// </summary>
|
||||
WS_EX_LEFT = 0x0,
|
||||
|
||||
/// <summary>
|
||||
/// If the shell language supports reading-order alignment, the window text is displayed using right-to-left
|
||||
/// reading-order properties. For other languages, the styles is ignored.
|
||||
/// </summary>
|
||||
WS_EX_RTLREADING = 0x2000,
|
||||
|
||||
/// <summary>
|
||||
/// The window text is displayed using left-to-right reading-order properties. This is the default.
|
||||
/// </summary>
|
||||
WS_EX_LTRREADING = 0x0,
|
||||
|
||||
/// <summary>
|
||||
/// If the shell language supports reading order alignment, the vertical scroll bar (if present) is to
|
||||
/// the left of the client area. For other languages, the style is ignored.
|
||||
/// </summary>
|
||||
WS_EX_LEFTSCROLLBAR = 0x4000,
|
||||
|
||||
/// <summary>
|
||||
/// The vertical scroll bar (if present) is to the right of the client area. This is the default.
|
||||
/// </summary>
|
||||
WS_EX_RIGHTSCROLLBAR = 0x0,
|
||||
|
||||
/// <summary>
|
||||
/// The window itself contains child windows that should take part in dialog box, navigation. If this
|
||||
/// style is specified, the dialog manager recurses into children of this window when performing
|
||||
/// navigation operations such as handling tha TAB key, an arrow key, or a keyboard mnemonic.
|
||||
/// </summary>
|
||||
WS_EX_CONTROLPARENT = 0x10000,
|
||||
|
||||
/// <summary>
|
||||
/// The window has a three-dimensional border style intended to be used for items that do not accept
|
||||
/// user input.
|
||||
/// </summary>
|
||||
WS_EX_STATICEDGE = 0x20000,
|
||||
|
||||
/// <summary>
|
||||
/// Forces a top-level window onto the taskbar when the window is visible.
|
||||
/// </summary>
|
||||
WS_EX_APPWINDOW = 0x40000,
|
||||
|
||||
/// <summary>
|
||||
/// The window is an overlapped window.
|
||||
/// </summary>
|
||||
WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
|
||||
|
||||
/// <summary>
|
||||
/// The window is palette window, which is a modeless dialog box that presents an array of commands.
|
||||
/// </summary>
|
||||
WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
|
||||
|
||||
/// <summary>
|
||||
/// The window is a layered window. This style cannot be used if the window has a class style of either
|
||||
/// CS_OWNDC or CS_CLASSDC. Only for top level window before Windows 8, and child windows from Windows 8.
|
||||
/// </summary>
|
||||
WS_EX_LAYERED = 0x80000,
|
||||
|
||||
/// <summary>
|
||||
/// The window does not pass its window layout to its child windows.
|
||||
/// </summary>
|
||||
WS_EX_NOINHERITLAYOUT = 0x100000,
|
||||
|
||||
/// <summary>
|
||||
/// If the shell language supports reading order alignment, the horizontal origin of the window is on the
|
||||
/// right edge. Increasing horizontal values advance to the left.
|
||||
/// </summary>
|
||||
WS_EX_LAYOUTRTL = 0x400000,
|
||||
|
||||
/// <summary>
|
||||
/// Paints all descendants of a window in bottom-to-top painting order using double-buffering.
|
||||
/// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and
|
||||
/// transparency (color-key) effects, but only if the descendent window also has the WS_EX_TRANSPARENT
|
||||
/// bit set. Double-buffering allows the window and its descendents to be painted without flicker.
|
||||
/// </summary>
|
||||
WS_EX_COMPOSITED = 0x2000000,
|
||||
|
||||
/// <summary>
|
||||
/// A top-level window created with this style does not become the foreground window when the user
|
||||
/// clicks it. The system does not bring this window to the foreground when the user minimizes or closes
|
||||
/// the foreground window.
|
||||
/// </summary>
|
||||
WS_EX_NOACTIVATE = 0x8000000,
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int EnumWindows(CallBackPtr callPtr, int lPar);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowCmd uCmd);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int EnumChildWindows(IntPtr hWnd, CallBackPtr callPtr, int lPar);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
|
||||
|
||||
@@ -606,6 +820,9 @@ namespace WindowWalker.Components
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool IsWindowVisible(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool IsWindow(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SetWindowPosFlags uFlags);
|
||||
@@ -633,6 +850,9 @@ namespace WindowWalker.Components
|
||||
[DllImport("psapi.dll")]
|
||||
public static extern uint GetProcessImageFileName(IntPtr hProcess, [Out] StringBuilder lpImageFileName, [In] [MarshalAs(UnmanagedType.U4)] int nSize);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern IntPtr GetProp(IntPtr hWnd, string lpString);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
|
||||
|
||||
@@ -642,6 +862,9 @@ namespace WindowWalker.Components
|
||||
[DllImport("dwmapi.dll", PreserveSig = false)]
|
||||
public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
|
||||
|
||||
[DllImport("dwmapi.dll", PreserveSig = false)]
|
||||
public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out int pvAttribute, int cbAttribute);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WindowWalker.Components
|
||||
@@ -19,11 +18,15 @@ namespace WindowWalker.Components
|
||||
/// </summary>
|
||||
public delegate void OpenWindowsUpdateHandler(object sender, SearchController.SearchResultUpdateEventArgs e);
|
||||
|
||||
#pragma warning disable 0067 // suppress false positive
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when there is an update to the list of open windows
|
||||
/// </summary>
|
||||
public event OpenWindowsUpdateHandler OnOpenWindowsUpdate;
|
||||
|
||||
#pragma warning restore 0067
|
||||
|
||||
/// <summary>
|
||||
/// List of all the open windows
|
||||
/// </summary>
|
||||
@@ -94,22 +97,11 @@ namespace WindowWalker.Components
|
||||
{
|
||||
Window newWindow = new Window(hwnd);
|
||||
|
||||
if (windows.Select(x => x.Title).Contains(newWindow.Title))
|
||||
{
|
||||
if (newWindow.ProcessName.ToLower().Equals("applicationframehost.exe"))
|
||||
{
|
||||
windows.Remove(windows.Where(x => x.Title == newWindow.Title).First());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((newWindow.Visible && !newWindow.ProcessName.ToLower().Equals("iexplore.exe")) ||
|
||||
(newWindow.ProcessName.ToLower().Equals("iexplore.exe") && newWindow.ClassName == "TabThumbnailWindow"))
|
||||
if (newWindow.IsWindow && newWindow.Visible && newWindow.IsOwner &&
|
||||
(!newWindow.IsToolWindow || newWindow.IsAppWindow ) && !newWindow.TaskListDeleted &&
|
||||
newWindow.ClassName != "Windows.UI.Core.CoreWindow")
|
||||
{
|
||||
windows.Add(newWindow);
|
||||
|
||||
OnOpenWindowsUpdate?.Invoke(this, new SearchController.SearchResultUpdateEventArgs());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
@@ -71,6 +72,8 @@ namespace WindowWalker.Components
|
||||
get { return hwnd; }
|
||||
}
|
||||
|
||||
public uint ProcessID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets returns the name of the process
|
||||
/// </summary>
|
||||
@@ -88,11 +91,9 @@ namespace WindowWalker.Components
|
||||
|
||||
if (!_handlesToProcessCache.ContainsKey(Hwnd))
|
||||
{
|
||||
InteropAndHelpers.GetWindowThreadProcessId(Hwnd, out uint processId);
|
||||
IntPtr processHandle = InteropAndHelpers.OpenProcess(InteropAndHelpers.ProcessAccessFlags.AllAccess, true, (int)processId);
|
||||
StringBuilder processName = new StringBuilder(MaximumFileNameLength);
|
||||
var processName = GetProcessNameFromWindowHandle(Hwnd);
|
||||
|
||||
if (InteropAndHelpers.GetProcessImageFileName(processHandle, processName, MaximumFileNameLength) != 0)
|
||||
if (processName.Length != 0)
|
||||
{
|
||||
_handlesToProcessCache.Add(
|
||||
Hwnd,
|
||||
@@ -104,6 +105,27 @@ namespace WindowWalker.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (_handlesToProcessCache[hwnd].ToLower() == "applicationframehost.exe")
|
||||
{
|
||||
new Task(() =>
|
||||
{
|
||||
InteropAndHelpers.CallBackPtr callbackptr = new InteropAndHelpers.CallBackPtr((IntPtr hwnd, IntPtr lParam) =>
|
||||
{
|
||||
var childProcessId = GetProcessIDFromWindowHandle(hwnd);
|
||||
if (childProcessId != ProcessID)
|
||||
{
|
||||
_handlesToProcessCache[Hwnd] = GetProcessNameFromWindowHandle(hwnd);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
});
|
||||
InteropAndHelpers.EnumChildWindows(Hwnd, callbackptr, 0);
|
||||
}).Start();
|
||||
}
|
||||
|
||||
return _handlesToProcessCache[hwnd];
|
||||
}
|
||||
}
|
||||
@@ -168,6 +190,87 @@ namespace WindowWalker.Components
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the specified window handle identifies an existing window.
|
||||
/// </summary>
|
||||
public bool IsWindow
|
||||
{
|
||||
get
|
||||
{
|
||||
return InteropAndHelpers.IsWindow(Hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a value is the window GWL_EX_STYLE is a toolwindow
|
||||
/// </summary>
|
||||
public bool IsToolWindow
|
||||
{
|
||||
get
|
||||
{
|
||||
return (InteropAndHelpers.GetWindowLong(Hwnd, InteropAndHelpers.GWL_EXSTYLE) &
|
||||
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_TOOLWINDOW) ==
|
||||
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_TOOLWINDOW;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the window GWL_EX_STYLE is an appwindow
|
||||
/// </summary>
|
||||
public bool IsAppWindow
|
||||
{
|
||||
get
|
||||
{
|
||||
return (InteropAndHelpers.GetWindowLong(Hwnd, InteropAndHelpers.GWL_EXSTYLE) &
|
||||
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_APPWINDOW) ==
|
||||
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_APPWINDOW;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the window has ITaskList_Deleted property
|
||||
/// </summary>
|
||||
public bool TaskListDeleted
|
||||
{
|
||||
get
|
||||
{
|
||||
return InteropAndHelpers.GetProp(Hwnd, "ITaskList_Deleted") != IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the app is a cloaked UWP app
|
||||
/// </summary>
|
||||
public bool IsUWPCloaked
|
||||
{
|
||||
get
|
||||
{
|
||||
return IsWindowCloaked() && ClassName == "ApplicationFrameWindow";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the specified windows is the owner
|
||||
/// </summary>
|
||||
public bool IsOwner
|
||||
{
|
||||
get
|
||||
{
|
||||
return InteropAndHelpers.GetWindow(Hwnd, InteropAndHelpers.GetWindowCmd.GW_OWNER) != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether is the window cloaked. To detect UWP apps in background or win32 apps running in another virtual desktop
|
||||
/// </summary>
|
||||
public bool IsWindowCloaked()
|
||||
{
|
||||
int isCloaked = 0;
|
||||
const int DWMWA_CLOAKED = 14;
|
||||
InteropAndHelpers.DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, out isCloaked, sizeof(int));
|
||||
return isCloaked != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether returns true if the window is minimized
|
||||
/// </summary>
|
||||
@@ -261,5 +364,38 @@ namespace WindowWalker.Components
|
||||
Maximized,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the process using the window handle
|
||||
/// </summary>
|
||||
/// <param name="hwnd">The handle to the window</param>
|
||||
/// <returns>A string representing the process name or an empty string if the function fails</returns>
|
||||
private string GetProcessNameFromWindowHandle(IntPtr hwnd)
|
||||
{
|
||||
uint processId = GetProcessIDFromWindowHandle(hwnd);
|
||||
ProcessID = processId;
|
||||
IntPtr processHandle = InteropAndHelpers.OpenProcess(InteropAndHelpers.ProcessAccessFlags.AllAccess, true, (int)processId);
|
||||
StringBuilder processName = new StringBuilder(MaximumFileNameLength);
|
||||
|
||||
if (InteropAndHelpers.GetProcessImageFileName(processHandle, processName, MaximumFileNameLength) != 0)
|
||||
{
|
||||
return processName.ToString().Split('\\').Reverse().ToArray()[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the process ID for the Window handle
|
||||
/// </summary>
|
||||
/// <param name="hwnd">The handle to the window</param>
|
||||
/// <returns>The process ID</returns>
|
||||
private uint GetProcessIDFromWindowHandle(IntPtr hwnd)
|
||||
{
|
||||
InteropAndHelpers.GetWindowThreadProcessId(hwnd, out uint processId);
|
||||
return processId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace WindowWalker
|
||||
|
||||
private void Window_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.searchBox.Focus();
|
||||
searchBox.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Interop;
|
||||
using Microsoft.Win32;
|
||||
|
||||
using WindowWalker.Components;
|
||||
using WindowWalker.MVVMHelpers;
|
||||
|
||||
@@ -18,8 +18,6 @@ namespace WindowWalker.ViewModels
|
||||
private readonly List<string> _hints = new List<string>()
|
||||
{
|
||||
"search for running processes or windows...",
|
||||
|
||||
// "you can reinvoke this app using CTRL + WIN",
|
||||
};
|
||||
|
||||
private string _searchText = string.Empty;
|
||||
|
||||
453
src/settings-web/package-lock.json
generated
453
src/settings-web/package-lock.json
generated
@@ -2437,6 +2437,16 @@
|
||||
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
|
||||
"dev": true
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"block-stream": {
|
||||
"version": "0.0.9",
|
||||
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
|
||||
@@ -2760,6 +2770,21 @@
|
||||
"y18n": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
@@ -3272,6 +3297,21 @@
|
||||
"run-queue": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
@@ -4477,6 +4517,15 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
@@ -4552,6 +4601,13 @@
|
||||
"schema-utils": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"filesize": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz",
|
||||
@@ -4810,14 +4866,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "1.2.9",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
|
||||
"integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
|
||||
"version": "1.2.12",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz",
|
||||
"integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"bindings": "^1.5.0",
|
||||
"nan": "^2.12.1",
|
||||
"node-pre-gyp": "^0.12.0"
|
||||
"node-pre-gyp": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"abbrev": {
|
||||
@@ -4865,7 +4922,7 @@
|
||||
}
|
||||
},
|
||||
"chownr": {
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
@@ -4895,7 +4952,7 @@
|
||||
"optional": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"version": "3.2.6",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -4922,12 +4979,12 @@
|
||||
"optional": true
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "1.2.5",
|
||||
"version": "1.2.7",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minipass": "^2.2.1"
|
||||
"minipass": "^2.6.0"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
@@ -4953,7 +5010,7 @@
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.3",
|
||||
"version": "7.1.6",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -4982,7 +5039,7 @@
|
||||
}
|
||||
},
|
||||
"ignore-walk": {
|
||||
"version": "3.0.1",
|
||||
"version": "3.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -5001,7 +5058,7 @@
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
@@ -5037,13 +5094,11 @@
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"version": "1.2.5",
|
||||
"bundled": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"version": "2.9.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -5053,48 +5108,47 @@
|
||||
}
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "1.2.1",
|
||||
"version": "1.3.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minipass": "^2.2.1"
|
||||
"minipass": "^2.9.0"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"version": "2.1.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"needle": {
|
||||
"version": "2.3.0",
|
||||
"version": "2.3.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"debug": "^4.1.0",
|
||||
"debug": "^3.2.6",
|
||||
"iconv-lite": "^0.4.4",
|
||||
"sax": "^1.2.4"
|
||||
}
|
||||
},
|
||||
"node-pre-gyp": {
|
||||
"version": "0.12.0",
|
||||
"version": "0.14.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"detect-libc": "^1.0.2",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mkdirp": "0.5.5",
|
||||
"needle": "^2.2.1",
|
||||
"nopt": "^4.0.1",
|
||||
"npm-packlist": "^1.1.6",
|
||||
@@ -5102,11 +5156,23 @@
|
||||
"rc": "^1.2.7",
|
||||
"rimraf": "^2.6.1",
|
||||
"semver": "^5.3.0",
|
||||
"tar": "^4"
|
||||
"tar": "^4.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"nopt": {
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -5116,19 +5182,29 @@
|
||||
}
|
||||
},
|
||||
"npm-bundled": {
|
||||
"version": "1.0.6",
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"npm-normalize-package-bin": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"npm-normalize-package-bin": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"npm-packlist": {
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.8",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ignore-walk": "^3.0.1",
|
||||
"npm-bundled": "^1.0.1"
|
||||
"npm-bundled": "^1.0.1",
|
||||
"npm-normalize-package-bin": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"npmlog": {
|
||||
@@ -5193,7 +5269,7 @@
|
||||
"optional": true
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
@@ -5208,18 +5284,10 @@
|
||||
"ini": "~1.3.0",
|
||||
"minimist": "^1.2.0",
|
||||
"strip-json-comments": "~2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"version": "2.3.7",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -5234,7 +5302,7 @@
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.3",
|
||||
"version": "2.7.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -5261,7 +5329,7 @@
|
||||
"optional": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"version": "5.7.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
@@ -5314,18 +5382,30 @@
|
||||
"optional": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "4.4.8",
|
||||
"version": "4.4.13",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chownr": "^1.1.1",
|
||||
"fs-minipass": "^1.2.5",
|
||||
"minipass": "^2.3.4",
|
||||
"minizlib": "^1.1.1",
|
||||
"mkdirp": "^0.5.0",
|
||||
"minipass": "^2.8.6",
|
||||
"minizlib": "^1.2.1",
|
||||
"mkdirp": "0.5.5",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.2"
|
||||
"yallist": "^3.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
@@ -5350,7 +5430,7 @@
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"version": "3.1.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
@@ -5369,6 +5449,21 @@
|
||||
"rimraf": "2"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
@@ -5609,15 +5704,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.5.3",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
|
||||
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
|
||||
"version": "4.7.6",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
|
||||
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5",
|
||||
"neo-async": "^2.6.0",
|
||||
"optimist": "^0.6.1",
|
||||
"source-map": "^0.6.1",
|
||||
"uglify-js": "^3.1.4"
|
||||
"uglify-js": "^3.1.4",
|
||||
"wordwrap": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"har-schema": {
|
||||
@@ -7098,6 +7194,21 @@
|
||||
"semver": "^6.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
@@ -7124,6 +7235,23 @@
|
||||
"mkdirp": "^0.5.1",
|
||||
"slash": "^2.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"jest-validate": {
|
||||
@@ -8052,9 +8180,9 @@
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"minipass": {
|
||||
@@ -8131,21 +8259,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||
}
|
||||
}
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@@ -8160,6 +8273,21 @@
|
||||
"run-queue": "^1.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
@@ -8312,6 +8440,21 @@
|
||||
"which": "1"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
@@ -8482,6 +8625,21 @@
|
||||
"yallist": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
@@ -8813,16 +8971,6 @@
|
||||
"is-wsl": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"optimist": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "~0.0.1",
|
||||
"wordwrap": "~0.0.2"
|
||||
}
|
||||
},
|
||||
"optionator": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
|
||||
@@ -9184,6 +9332,21 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
@@ -9782,6 +9945,28 @@
|
||||
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==",
|
||||
"dev": true
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
@@ -11415,6 +11600,19 @@
|
||||
"dom-serializer": "0",
|
||||
"domelementtype": "1"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11443,6 +11641,23 @@
|
||||
"mkdirp": "^0.5.0",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"terser": {
|
||||
@@ -11494,7 +11709,24 @@
|
||||
"ssri": "^6.0.1",
|
||||
"unique-filename": "^1.1.1",
|
||||
"y18n": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
@@ -11727,6 +11959,21 @@
|
||||
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
|
||||
"dev": true
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
|
||||
@@ -11815,23 +12062,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.7.3",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.3.tgz",
|
||||
"integrity": "sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==",
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.8.1.tgz",
|
||||
"integrity": "sha512-W7KxyzeaQmZvUFbGj4+YFshhVrMBGSg2IbcYAjGWGvx8DHvJMclbTDMpffdxFUGPBHjIytk7KJUR/KUXstUGDw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"commander": "~2.20.3",
|
||||
"source-map": "~0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"undertaker": {
|
||||
@@ -12207,6 +12445,23 @@
|
||||
"terser-webpack-plugin": "^1.1.0",
|
||||
"watchpack": "^1.5.0",
|
||||
"webpack-sources": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"webpack-cli": {
|
||||
@@ -12537,9 +12792,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
||||
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
|
||||
"dev": true
|
||||
},
|
||||
"worker-farm": {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"typings": "lib/index.d.ts",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"preinstall": "npx npm-force-resolutions",
|
||||
"just": "just-scripts",
|
||||
"clean": "rimraf build lib lib-commonjs && just-scripts clean",
|
||||
"build": "rimraf build && just-scripts build --min --production && copy *.html build && react-snap && xcopy build\\* ..\\settings\\settings-html /sy",
|
||||
@@ -46,5 +47,8 @@
|
||||
},
|
||||
"just": {
|
||||
"stack": "just-stack-uifabric"
|
||||
},
|
||||
"resolutions": {
|
||||
"mkdirp": "0.5.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,7 +567,7 @@ int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _
|
||||
Trace::RegisterProvider();
|
||||
CoInitialize(nullptr);
|
||||
|
||||
const bool should_try_drop_privileges = !initialize_com_security_policy_for_webview() && is_process_elevated();
|
||||
const bool should_try_drop_privileges = !initialize_com_security_policy_for_webview() && is_process_elevated(false);
|
||||
|
||||
if (should_try_drop_privileges)
|
||||
{
|
||||
|
||||
@@ -26,13 +26,18 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(topBorder);
|
||||
Assert.IsNotNull(bottomBorder);
|
||||
|
||||
int height = bottomBorder.Rect.Y - topBorder.Rect.Y;
|
||||
|
||||
//up
|
||||
new Actions(session).MoveToElement(topBorder).ClickAndHold().MoveByOffset(0, -5000).Release().Perform();
|
||||
Assert.IsTrue(topBorder.Rect.Y >= 0);
|
||||
Assert.IsTrue(height < bottomBorder.Rect.Y - topBorder.Rect.Y);
|
||||
height = bottomBorder.Rect.Y - topBorder.Rect.Y;
|
||||
|
||||
//down
|
||||
new Actions(session).MoveToElement(topBorder).ClickAndHold().MoveByOffset(0, 5000).Release().Perform();
|
||||
Assert.IsTrue(topBorder.Rect.Y <= bottomBorder.Rect.Y);
|
||||
Assert.IsTrue(height > bottomBorder.Rect.Y - topBorder.Rect.Y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -43,13 +48,18 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(topBorder);
|
||||
Assert.IsNotNull(bottomBorder);
|
||||
|
||||
int height = bottomBorder.Rect.Y - topBorder.Rect.Y;
|
||||
|
||||
//up
|
||||
new Actions(session).MoveToElement(bottomBorder).ClickAndHold().MoveByOffset(0, -5000).Release().Perform();
|
||||
Assert.IsTrue(topBorder.Rect.Y <= bottomBorder.Rect.Y);
|
||||
Assert.IsTrue(height > bottomBorder.Rect.Y - topBorder.Rect.Y);
|
||||
height = bottomBorder.Rect.Y - topBorder.Rect.Y;
|
||||
|
||||
//down
|
||||
new Actions(session).MoveToElement(bottomBorder).ClickAndHold().MoveByOffset(0, 5000).Release().Perform();
|
||||
Assert.IsTrue(bottomBorder.Rect.Y <= Screen.PrimaryScreen.WorkingArea.Bottom);
|
||||
Assert.IsTrue(height < bottomBorder.Rect.Y - topBorder.Rect.Y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -60,13 +70,18 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(leftBorder);
|
||||
Assert.IsNotNull(rightBorder);
|
||||
|
||||
int width = rightBorder.Rect.X - leftBorder.Rect.X;
|
||||
|
||||
//to the left
|
||||
new Actions(session).MoveToElement(leftBorder).ClickAndHold().MoveByOffset(-5000, 0).Release().Perform();
|
||||
Assert.IsTrue(leftBorder.Rect.Y <= Screen.PrimaryScreen.WorkingArea.Bottom);
|
||||
Assert.IsTrue(width < rightBorder.Rect.X - leftBorder.Rect.X);
|
||||
width = rightBorder.Rect.X - leftBorder.Rect.X;
|
||||
|
||||
//to the right
|
||||
new Actions(session).MoveToElement(leftBorder).ClickAndHold().MoveByOffset(5000, 0).Release().Perform();
|
||||
Assert.IsTrue(leftBorder.Rect.X <= rightBorder.Rect.X);
|
||||
Assert.IsTrue(width > rightBorder.Rect.X - leftBorder.Rect.X);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -77,13 +92,18 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(leftBorder);
|
||||
Assert.IsNotNull(rightBorder);
|
||||
|
||||
int width = rightBorder.Rect.X - leftBorder.Rect.X;
|
||||
|
||||
//to the left
|
||||
new Actions(session).MoveToElement(rightBorder).ClickAndHold().MoveByOffset(-5000, 0).Release().Perform();
|
||||
Assert.IsTrue(leftBorder.Rect.X <= rightBorder.Rect.X);
|
||||
Assert.IsTrue(width > rightBorder.Rect.X - leftBorder.Rect.X);
|
||||
width = rightBorder.Rect.X - leftBorder.Rect.X;
|
||||
|
||||
//to the right
|
||||
new Actions(session).MoveToElement(rightBorder).ClickAndHold().MoveByOffset(5000, 0).Release().Perform();
|
||||
Assert.IsTrue(leftBorder.Rect.X <= Screen.PrimaryScreen.WorkingArea.Right);
|
||||
Assert.IsTrue(width < rightBorder.Rect.X - leftBorder.Rect.X);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -96,41 +116,32 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(bottomBorder);
|
||||
Assert.IsNotNull(rightBorder);
|
||||
|
||||
//up
|
||||
MoveCorner(topLeftCorner, true, true, 0, -5000);
|
||||
Assert.IsTrue(topLeftCorner.Rect.Y >= 0);
|
||||
|
||||
//down
|
||||
MoveCorner(topLeftCorner, true, true, 0, 5000);
|
||||
Assert.IsTrue(topLeftCorner.Rect.Y <= bottomBorder.Rect.Y);
|
||||
int expectedWidth = rightBorder.Rect.X - topLeftCorner.Rect.X;
|
||||
int expectedHeight = bottomBorder.Rect.Y - topLeftCorner.Rect.Y;
|
||||
int actualWidth, actualHeight;
|
||||
|
||||
//up-left
|
||||
MoveCorner(topLeftCorner, true, true, -5000, -5000);
|
||||
actualHeight = bottomBorder.Rect.Y - topLeftCorner.Rect.Y;
|
||||
actualWidth = rightBorder.Rect.X - topLeftCorner.Rect.X;
|
||||
|
||||
Assert.IsTrue(topLeftCorner.Rect.Y >= 0);
|
||||
Assert.IsTrue(topLeftCorner.Rect.X >= 0);
|
||||
Assert.IsTrue(actualHeight > expectedHeight);
|
||||
Assert.IsTrue(actualWidth > expectedWidth);
|
||||
|
||||
//up-right
|
||||
MoveCorner(topLeftCorner, true, true, 5000, -5000);
|
||||
Assert.IsTrue(topLeftCorner.Rect.Y >= 0);
|
||||
Assert.IsTrue(topLeftCorner.Rect.X <= rightBorder.Rect.X);
|
||||
|
||||
//to the left
|
||||
MoveCorner(topLeftCorner, true, true, -5000, 0);
|
||||
Assert.IsTrue(topLeftCorner.Rect.X >= 0);
|
||||
|
||||
//to the right
|
||||
MoveCorner(topLeftCorner, true, true, 5000, 0);
|
||||
Assert.IsTrue(topLeftCorner.Rect.X <= rightBorder.Rect.X);
|
||||
|
||||
//down-left
|
||||
MoveCorner(topLeftCorner, true, true, -5000, 5000);
|
||||
Assert.IsTrue(topLeftCorner.Rect.Y <= bottomBorder.Rect.Y);
|
||||
Assert.IsTrue(topLeftCorner.Rect.X >= 0);
|
||||
expectedHeight = actualHeight;
|
||||
expectedWidth = actualWidth;
|
||||
|
||||
//down-right
|
||||
MoveCorner(topLeftCorner, true, true, 5000, 5000);
|
||||
actualHeight = bottomBorder.Rect.Y - topLeftCorner.Rect.Y;
|
||||
actualWidth = rightBorder.Rect.X - topLeftCorner.Rect.X;
|
||||
|
||||
Assert.IsTrue(topLeftCorner.Rect.Y <= bottomBorder.Rect.Y);
|
||||
Assert.IsTrue(topLeftCorner.Rect.X <= rightBorder.Rect.X);
|
||||
Assert.IsTrue(actualHeight < expectedHeight);
|
||||
Assert.IsTrue(actualWidth < expectedWidth);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -143,41 +154,32 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(bottomBorder);
|
||||
Assert.IsNotNull(leftBorder);
|
||||
|
||||
//up
|
||||
MoveCorner(topRightCorner, false, true, 0, -5000);
|
||||
Assert.IsTrue(topRightCorner.Rect.Y >= 0);
|
||||
|
||||
//down
|
||||
MoveCorner(topRightCorner, false, true, 0, 5000);
|
||||
Assert.IsTrue(topRightCorner.Rect.Y <= bottomBorder.Rect.Y);
|
||||
|
||||
//up-left
|
||||
MoveCorner(topRightCorner, false, true, -5000, -5000);
|
||||
Assert.IsTrue(topRightCorner.Rect.Y >= 0);
|
||||
Assert.IsTrue(topRightCorner.Rect.X >= leftBorder.Rect.X);
|
||||
int expectedWidth = topRightCorner.Rect.X - leftBorder.Rect.X;
|
||||
int expectedHeight = bottomBorder.Rect.Y - topRightCorner.Rect.Y;
|
||||
int actualWidth, actualHeight;
|
||||
|
||||
//up-right
|
||||
MoveCorner(topRightCorner, false, true, 5000, -5000);
|
||||
actualHeight = bottomBorder.Rect.Y - topRightCorner.Rect.Y;
|
||||
actualWidth = topRightCorner.Rect.X - leftBorder.Rect.X;
|
||||
|
||||
Assert.IsTrue(topRightCorner.Rect.Y >= 0);
|
||||
Assert.IsTrue(leftBorder.Rect.X <= Screen.PrimaryScreen.WorkingArea.Right);
|
||||
Assert.IsTrue(actualHeight > expectedHeight);
|
||||
Assert.IsTrue(actualWidth > expectedWidth);
|
||||
|
||||
//to the left
|
||||
MoveCorner(topRightCorner, false, true, -5000, 0);
|
||||
Assert.IsTrue(topRightCorner.Rect.X >= leftBorder.Rect.X);
|
||||
|
||||
//to the right
|
||||
MoveCorner(topRightCorner, false, true, 5000, 0);
|
||||
Assert.IsTrue(leftBorder.Rect.X <= Screen.PrimaryScreen.WorkingArea.Right);
|
||||
|
||||
//down-right
|
||||
MoveCorner(topRightCorner, false, true, 5000, 5000);
|
||||
Assert.IsTrue(topRightCorner.Rect.Y <= bottomBorder.Rect.Y);
|
||||
Assert.IsTrue(leftBorder.Rect.X <= Screen.PrimaryScreen.WorkingArea.Right);
|
||||
expectedHeight = actualHeight;
|
||||
expectedWidth = actualWidth;
|
||||
|
||||
//down-left
|
||||
MoveCorner(topRightCorner, false, true, -5000, 5000);
|
||||
actualHeight = bottomBorder.Rect.Y - topRightCorner.Rect.Y;
|
||||
actualWidth = topRightCorner.Rect.X - leftBorder.Rect.X;
|
||||
|
||||
Assert.IsTrue(topRightCorner.Rect.Y <= bottomBorder.Rect.Y);
|
||||
Assert.IsTrue(topRightCorner.Rect.X >= leftBorder.Rect.X);
|
||||
Assert.IsTrue(actualHeight < expectedHeight);
|
||||
Assert.IsTrue(actualWidth < expectedWidth);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -190,41 +192,32 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(topBorder);
|
||||
Assert.IsNotNull(rightBorder);
|
||||
|
||||
//down
|
||||
MoveCorner(bottomLeftCorner, true, false, 0, 5000);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.Y <= Screen.PrimaryScreen.WorkingArea.Bottom);
|
||||
|
||||
//up
|
||||
MoveCorner(bottomLeftCorner, true, false, 0, -5000);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.Y >= topBorder.Rect.Y);
|
||||
|
||||
//down-right
|
||||
MoveCorner(bottomLeftCorner, true, false, 5000, 5000);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.Y <= Screen.PrimaryScreen.WorkingArea.Bottom);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.X <= rightBorder.Rect.X);
|
||||
|
||||
//down-left
|
||||
MoveCorner(bottomLeftCorner, true, false, -5000, 5000);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.Y <= Screen.PrimaryScreen.WorkingArea.Bottom);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.X >= 0);
|
||||
|
||||
//to the right
|
||||
MoveCorner(bottomLeftCorner, true, false, 5000, 0);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.X <= rightBorder.Rect.X);
|
||||
|
||||
//to the left
|
||||
MoveCorner(bottomLeftCorner, true, false, -5000, 0);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.X >= 0);
|
||||
int expectedWidth = rightBorder.Rect.X - bottomLeftCorner.Rect.X;
|
||||
int expectedHeight = bottomLeftCorner.Rect.Y - topBorder.Rect.Y;
|
||||
int actualWidth, actualHeight;
|
||||
|
||||
//up-left
|
||||
MoveCorner(bottomLeftCorner, true, false, -5000, -5000);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.Y >= topBorder.Rect.Y);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.X >= 0);
|
||||
|
||||
//up-right
|
||||
MoveCorner(bottomLeftCorner, true, false, 5000, -5000);
|
||||
actualHeight = bottomLeftCorner.Rect.Y - topBorder.Rect.Y;
|
||||
actualWidth = rightBorder.Rect.X - bottomLeftCorner.Rect.X;
|
||||
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.Y >= topBorder.Rect.Y);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.X <= rightBorder.Rect.X);
|
||||
Assert.IsTrue(actualHeight < expectedHeight);
|
||||
Assert.IsTrue(actualWidth < expectedWidth);
|
||||
|
||||
expectedHeight = actualHeight;
|
||||
expectedWidth = actualWidth;
|
||||
|
||||
//down-right
|
||||
MoveCorner(bottomLeftCorner, true, false, -5000, 5000);
|
||||
actualHeight = bottomLeftCorner.Rect.Y - topBorder.Rect.Y;
|
||||
actualWidth = rightBorder.Rect.X - bottomLeftCorner.Rect.X;
|
||||
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.Y <= Screen.PrimaryScreen.WorkingArea.Bottom);
|
||||
Assert.IsTrue(bottomLeftCorner.Rect.X >= 0);
|
||||
Assert.IsTrue(actualHeight > expectedHeight);
|
||||
Assert.IsTrue(actualWidth > expectedWidth);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -237,41 +230,31 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(topBorder);
|
||||
Assert.IsNotNull(leftBorder);
|
||||
|
||||
//to the right
|
||||
MoveCorner(bottomRightCorner, false, false, 5000, 0);
|
||||
Assert.IsTrue(bottomRightCorner.Rect.X <= Screen.PrimaryScreen.WorkingArea.Right);
|
||||
|
||||
//to the left
|
||||
MoveCorner(bottomRightCorner, false, false, -5000, 0);
|
||||
Assert.IsTrue(bottomRightCorner.Rect.X >= leftBorder.Rect.X);
|
||||
|
||||
//down
|
||||
MoveCorner(bottomRightCorner, false, false, 0, 5000);
|
||||
Assert.IsTrue(bottomRightCorner.Rect.Y <= Screen.PrimaryScreen.WorkingArea.Bottom);
|
||||
|
||||
//up
|
||||
MoveCorner(bottomRightCorner, false, false, 0, -5000);
|
||||
Assert.IsTrue(bottomRightCorner.Rect.Y >= topBorder.Rect.Y);
|
||||
int expectedWidth = bottomRightCorner.Rect.X - leftBorder.Rect.X;
|
||||
int expectedHeight = bottomRightCorner.Rect.Y - topBorder.Rect.Y;
|
||||
int actualWidth, actualHeight;
|
||||
|
||||
//up-left
|
||||
MoveCorner(bottomRightCorner, false, false, -5000, -5000);
|
||||
actualHeight = bottomRightCorner.Rect.Y - topBorder.Rect.Y;
|
||||
actualWidth = bottomRightCorner.Rect.X - leftBorder.Rect.X;
|
||||
|
||||
Assert.IsTrue(bottomRightCorner.Rect.Y >= topBorder.Rect.Y);
|
||||
Assert.IsTrue(bottomRightCorner.Rect.X >= leftBorder.Rect.X);
|
||||
Assert.IsTrue(actualHeight < expectedHeight);
|
||||
Assert.IsTrue(actualWidth < expectedWidth);
|
||||
|
||||
//up-right
|
||||
MoveCorner(bottomRightCorner, false, false, 5000, -5000);
|
||||
Assert.IsTrue(bottomRightCorner.Rect.Y >= topBorder.Rect.Y);
|
||||
Assert.IsTrue(bottomRightCorner.Rect.X <= Screen.PrimaryScreen.WorkingArea.Right);
|
||||
expectedHeight = actualHeight;
|
||||
expectedWidth = actualWidth;
|
||||
|
||||
//down-right
|
||||
MoveCorner(bottomRightCorner, false, false, 5000, 5000);
|
||||
actualHeight = bottomRightCorner.Rect.Y - topBorder.Rect.Y;
|
||||
actualWidth = bottomRightCorner.Rect.X - leftBorder.Rect.X;
|
||||
|
||||
Assert.IsTrue(bottomRightCorner.Rect.Y <= Screen.PrimaryScreen.WorkingArea.Bottom);
|
||||
Assert.IsTrue(bottomRightCorner.Rect.X <= Screen.PrimaryScreen.WorkingArea.Right);
|
||||
|
||||
//down-left
|
||||
MoveCorner(bottomRightCorner, false, false, -5000, 5000);
|
||||
Assert.IsTrue(bottomRightCorner.Rect.Y <= Screen.PrimaryScreen.WorkingArea.Bottom);
|
||||
Assert.IsTrue(bottomRightCorner.Rect.X >= leftBorder.Rect.X);
|
||||
Assert.IsTrue(actualHeight > expectedHeight);
|
||||
}
|
||||
|
||||
[ClassInitialize]
|
||||
@@ -286,16 +269,11 @@ namespace PowerToysTests
|
||||
}
|
||||
OpenEditor();
|
||||
OpenCustomLayouts();
|
||||
|
||||
//create canvas zone
|
||||
OpenCreatorWindow("Create new custom", "Custom layout creator");
|
||||
session.FindElementByAccessibilityId("newZoneButton").Click();
|
||||
}
|
||||
|
||||
[ClassCleanup]
|
||||
public static void ClassCleanup()
|
||||
{
|
||||
new Actions(session).MoveToElement(session.FindElementByXPath("//Button[@Name=\"Cancel\"]")).Click().Perform();
|
||||
CloseEditor();
|
||||
TearDown();
|
||||
}
|
||||
@@ -303,13 +281,15 @@ namespace PowerToysTests
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
|
||||
//create canvas zone
|
||||
OpenCreatorWindow("Create new custom", "Custom layout creator");
|
||||
session.FindElementByAccessibilityId("newZoneButton").Click();
|
||||
}
|
||||
|
||||
[TestCleanup]
|
||||
public void TestCleanup()
|
||||
{
|
||||
|
||||
new Actions(session).MoveToElement(session.FindElementByXPath("//Button[@Name=\"Cancel\"]")).Click().Perform();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ namespace PowerToysTests
|
||||
{
|
||||
WindowsElement cancelButton = session.FindElementByXPath("//Window[@Name=\"FancyZones Editor\"]/Window/Button[@Name=\"Cancel\"]");
|
||||
new Actions(session).MoveToElement(cancelButton).Click().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
Assert.AreEqual(_initialZoneSettings, File.ReadAllText(_zoneSettingsPath), "Settings were changed");
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace PowerToysTests
|
||||
private void SaveTest(string type, string name, int zoneCount)
|
||||
{
|
||||
new Actions(session).MoveToElement(session.FindElementByName("Save and apply")).Click().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
JObject settings = JObject.Parse(File.ReadAllText(_zoneSettingsPath));
|
||||
Assert.AreEqual(name, settings["custom-zone-sets"][0]["name"]);
|
||||
@@ -149,7 +149,7 @@ namespace PowerToysTests
|
||||
string name = "My custom zone layout name";
|
||||
SetLayoutName(name);
|
||||
SaveTest("canvas", name, 0);
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
//rename layout
|
||||
OpenEditor();
|
||||
@@ -168,7 +168,7 @@ namespace PowerToysTests
|
||||
string name = "Name";
|
||||
SetLayoutName(name);
|
||||
SaveTest("canvas", name, 0);
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
//save layout id
|
||||
JObject settings = JObject.Parse(File.ReadAllText(_zoneSettingsPath));
|
||||
@@ -183,7 +183,7 @@ namespace PowerToysTests
|
||||
|
||||
//settings are saved on window closing
|
||||
new Actions(session).MoveToElement(session.FindElementByAccessibilityId("PART_Close")).Click().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
//check settings
|
||||
settings = JObject.Parse(File.ReadAllText(_zoneSettingsPath));
|
||||
@@ -206,7 +206,7 @@ namespace PowerToysTests
|
||||
SetLayoutName(name);
|
||||
|
||||
new Actions(session).MoveToElement(session.FindElementByName("Save and apply")).Click().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
//remove layout
|
||||
OpenEditor();
|
||||
@@ -217,7 +217,7 @@ namespace PowerToysTests
|
||||
|
||||
//settings are saved on window closing
|
||||
new Actions(session).MoveToElement(session.FindElementByAccessibilityId("PART_Close")).Click().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
//check settings
|
||||
JObject settings = JObject.Parse(File.ReadAllText(_zoneSettingsPath));
|
||||
@@ -236,7 +236,6 @@ namespace PowerToysTests
|
||||
SetLayoutName(name);
|
||||
|
||||
new Actions(session).MoveToElement(session.FindElementByName("Save and apply")).Click().Perform();
|
||||
ShortWait();
|
||||
|
||||
//remove layout
|
||||
OpenEditor();
|
||||
@@ -247,7 +246,7 @@ namespace PowerToysTests
|
||||
|
||||
//settings are saved on window closing
|
||||
new Actions(session).MoveToElement(session.FindElementByAccessibilityId("PART_Close")).Click().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
//check settings
|
||||
JObject settings = JObject.Parse(File.ReadAllText(_zoneSettingsPath));
|
||||
@@ -263,7 +262,7 @@ namespace PowerToysTests
|
||||
OpenCreatorWindow("Create new custom", "Custom layout creator");
|
||||
SetLayoutName(name);
|
||||
new Actions(session).MoveToElement(session.FindElementByName("Save and apply")).Click().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
//save layout id
|
||||
JObject settings = JObject.Parse(File.ReadAllText(_zoneSettingsPath));
|
||||
@@ -278,7 +277,7 @@ namespace PowerToysTests
|
||||
|
||||
//apply
|
||||
new Actions(session).MoveToElement(session.FindElementByName("Apply")).Click().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
//check settings
|
||||
settings = JObject.Parse(File.ReadAllText(_zoneSettingsPath));
|
||||
|
||||
@@ -59,11 +59,10 @@ namespace PowerToysTests
|
||||
WindowsElement errorMessage = null;
|
||||
try
|
||||
{
|
||||
errorMessage = session.FindElementByName("FancyZones Editor Exception Handler");
|
||||
errorMessage = WaitElementByName("FancyZones Editor Exception Handler");
|
||||
if (errorMessage != null)
|
||||
{
|
||||
errorMessage.FindElementByName("OK").Click();
|
||||
ShortWait();
|
||||
}
|
||||
}
|
||||
catch (OpenQA.Selenium.WebDriverException)
|
||||
@@ -92,16 +91,12 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(editorButton);
|
||||
|
||||
editorButton.Click();
|
||||
ShortWait();
|
||||
|
||||
TestEditorOpened();
|
||||
}
|
||||
|
||||
void OpenEditorByHotkey()
|
||||
{
|
||||
new Actions(session).KeyDown(OpenQA.Selenium.Keys.Command).SendKeys("`").KeyUp(OpenQA.Selenium.Keys.Command).Perform();
|
||||
ShortWait();
|
||||
|
||||
TestEditorOpened();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OpenQA.Selenium;
|
||||
@@ -8,71 +9,177 @@ using OpenQA.Selenium.Appium.Windows;
|
||||
namespace PowerToysTests
|
||||
{
|
||||
[TestClass]
|
||||
public class FancyZonesEditorSettingsTests : PowerToysSession
|
||||
public class FancyZonesEditorSettingsTests : FancyZonesEditor
|
||||
{
|
||||
private const string editorZoneCount = "editor-zone-count";
|
||||
private const string editorShowSpacing = "editor-show-spacing";
|
||||
private const string editorSpacing = "editor-spacing";
|
||||
|
||||
[TestMethod]
|
||||
public void ZoneCount()
|
||||
{
|
||||
ShortWait();
|
||||
OpenFancyZonesSettings();
|
||||
OpenEditor();
|
||||
|
||||
WindowsElement editorButton = WaitElementByXPath("//Button[@Name=\"Edit zones\"]");
|
||||
editorButton.Click();
|
||||
WindowsElement minusButton = session.FindElementByAccessibilityId("decrementZones");
|
||||
WindowsElement zoneCount = session.FindElementByAccessibilityId("zoneCount");
|
||||
|
||||
WindowsElement minusButton = WaitElementByAccessibilityId("decrementZones");
|
||||
WindowsElement zoneCount = WaitElementByAccessibilityId("zoneCount");
|
||||
WindowsElement applyButton;
|
||||
int editorZoneCountValue;
|
||||
Assert.IsTrue(Int32.TryParse(zoneCount.Text, out editorZoneCountValue));
|
||||
|
||||
int zoneCountQty;
|
||||
Assert.IsTrue(Int32.TryParse(zoneCount.Text, out zoneCountQty));
|
||||
|
||||
for (int i = zoneCountQty - 1, j = 0; i > -5; --i, ++j)
|
||||
for (int i = editorZoneCountValue - 1, j = 0; i > -5; --i, ++j)
|
||||
{
|
||||
minusButton.Click();
|
||||
|
||||
Assert.IsTrue(Int32.TryParse(zoneCount.Text, out zoneCountQty));
|
||||
Assert.AreEqual(Math.Max(i, 1), zoneCountQty);
|
||||
Assert.IsTrue(Int32.TryParse(zoneCount.Text, out editorZoneCountValue));
|
||||
Assert.AreEqual(Math.Max(i, 1), editorZoneCountValue);
|
||||
|
||||
if (j == 0 || i == -4)
|
||||
{
|
||||
applyButton = WaitElementByAccessibilityId("ApplyTemplateButton");
|
||||
applyButton.Click();
|
||||
ShortWait();
|
||||
Assert.AreEqual(zoneCountQty, getSavedZoneCount());
|
||||
editorButton.Click();
|
||||
minusButton = WaitElementByAccessibilityId("decrementZones");
|
||||
zoneCount = WaitElementByAccessibilityId("zoneCount");
|
||||
session.FindElementByAccessibilityId("ApplyTemplateButton").Click();
|
||||
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual(editorZoneCountValue, GetEditZonesSetting<int>(editorZoneCount));
|
||||
OpenEditor();
|
||||
|
||||
minusButton = session.FindElementByAccessibilityId("decrementZones");
|
||||
zoneCount = session.FindElementByAccessibilityId("zoneCount");
|
||||
}
|
||||
}
|
||||
|
||||
WindowsElement plusButton = WaitElementByAccessibilityId("incrementZones");
|
||||
WindowsElement plusButton = session.FindElementByAccessibilityId("incrementZones");
|
||||
|
||||
for (int i = 2; i < 45; ++i)
|
||||
{
|
||||
plusButton.Click();
|
||||
|
||||
Assert.IsTrue(Int32.TryParse(zoneCount.Text, out zoneCountQty));
|
||||
Assert.AreEqual(Math.Min(i, 40), zoneCountQty);
|
||||
Assert.IsTrue(Int32.TryParse(zoneCount.Text, out editorZoneCountValue));
|
||||
Assert.AreEqual(Math.Min(i, 40), editorZoneCountValue);
|
||||
}
|
||||
|
||||
applyButton = WaitElementByAccessibilityId("ApplyTemplateButton");
|
||||
applyButton.Click();
|
||||
ShortWait();
|
||||
Assert.AreEqual(zoneCountQty, getSavedZoneCount());
|
||||
session.FindElementByAccessibilityId("ApplyTemplateButton").Click();
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual(editorZoneCountValue, GetEditZonesSetting<int>(editorZoneCount));
|
||||
}
|
||||
|
||||
private int getSavedZoneCount()
|
||||
[TestMethod]
|
||||
public void ShowSpacingTest()
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
OpenEditor();
|
||||
|
||||
WindowsElement spaceAroundSetting = session.FindElementByAccessibilityId("spaceAroundSetting");
|
||||
bool spaceAroundSettingValue = spaceAroundSetting.Selected;
|
||||
spaceAroundSetting.Click();
|
||||
|
||||
session.FindElementByAccessibilityId("ApplyTemplateButton").Click();
|
||||
|
||||
WaitSeconds(1);
|
||||
|
||||
Assert.AreNotEqual(spaceAroundSettingValue, GetEditZonesSetting<bool>(editorShowSpacing));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpacingTestsValid()
|
||||
{
|
||||
OpenEditor();
|
||||
|
||||
WindowsElement spaceAroundSetting = session.FindElementByAccessibilityId("spaceAroundSetting");
|
||||
bool editorShowSpacingValue = spaceAroundSetting.Selected;
|
||||
|
||||
session.FindElementByAccessibilityId("ApplyTemplateButton").Click();
|
||||
WaitSeconds(1);
|
||||
|
||||
string[] validValues = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
|
||||
foreach (string editorSpacingValue in validValues)
|
||||
{
|
||||
OpenEditor();
|
||||
|
||||
WindowsElement paddingValue = WaitElementByAccessibilityId("paddingValue");
|
||||
ClearText(paddingValue);
|
||||
paddingValue.SendKeys(editorSpacingValue);
|
||||
|
||||
session.FindElementByAccessibilityId("ApplyTemplateButton").Click();
|
||||
WaitSeconds(1);
|
||||
|
||||
Assert.AreEqual(editorShowSpacingValue, GetEditZonesSetting<bool>(editorShowSpacing));
|
||||
Assert.AreEqual(editorSpacingValue, GetEditZonesSetting<string>(editorSpacing));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpacingTestsInvalid()
|
||||
{
|
||||
OpenEditor();
|
||||
|
||||
WindowsElement spaceAroundSetting = session.FindElementByAccessibilityId("spaceAroundSetting");
|
||||
bool editorShowSpacingValue = spaceAroundSetting.Selected;
|
||||
|
||||
session.FindElementByAccessibilityId("ApplyTemplateButton").Click();
|
||||
WaitSeconds(1);
|
||||
|
||||
string[] invalidValues = { "!", "/", "<", "?", "D", "Z", "]", "m", "}", "1.5", "2,5" };
|
||||
|
||||
string editorSpacingValue = GetEditZonesSetting<string>(editorSpacing);
|
||||
|
||||
foreach (string value in invalidValues)
|
||||
{
|
||||
OpenEditor();
|
||||
|
||||
WindowsElement paddingValue = WaitElementByAccessibilityId("paddingValue");
|
||||
ClearText(paddingValue);
|
||||
paddingValue.SendKeys(value);
|
||||
|
||||
session.FindElementByAccessibilityId("ApplyTemplateButton").Click();
|
||||
WaitSeconds(1);
|
||||
|
||||
Assert.AreEqual(editorShowSpacingValue, GetEditZonesSetting<bool>(editorShowSpacing));
|
||||
Assert.AreEqual(editorSpacingValue, GetEditZonesSetting<string>(editorSpacing));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SpacingTestLargeValue()
|
||||
{
|
||||
OpenEditor();
|
||||
session.FindElementByXPath("//Text[@Name=\"Grid\"]").Click();
|
||||
|
||||
WindowsElement paddingValue = session.FindElementByAccessibilityId("paddingValue");
|
||||
ClearText(paddingValue);
|
||||
paddingValue.SendKeys("1000");
|
||||
|
||||
session.FindElementByAccessibilityId("ApplyTemplateButton").Click();
|
||||
|
||||
editorWindow = null;
|
||||
try
|
||||
{
|
||||
OpenEditor();
|
||||
}
|
||||
catch { }
|
||||
|
||||
Assert.AreNotEqual(editorWindow, null, "Editor Zones Window is not starting after setting large padding value");
|
||||
}
|
||||
|
||||
private T GetEditZonesSetting<T>(string value)
|
||||
{
|
||||
JObject zoneSettings = JObject.Parse(File.ReadAllText(_zoneSettingsPath));
|
||||
int editorZoneCount = (int)zoneSettings["devices"][0]["editor-zone-count"];
|
||||
return editorZoneCount;
|
||||
T result = zoneSettings["devices"][0][value].ToObject<T>();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ClearText(WindowsElement windowsElement)
|
||||
{
|
||||
windowsElement.SendKeys(Keys.Home);
|
||||
windowsElement.SendKeys(Keys.Control + Keys.Delete);
|
||||
}
|
||||
|
||||
[ClassInitialize]
|
||||
public static void ClassInitialize(TestContext context)
|
||||
{
|
||||
Setup(context);
|
||||
OpenSettings();
|
||||
Setup(context, false);
|
||||
ResetSettings();
|
||||
}
|
||||
|
||||
[ClassCleanup]
|
||||
@@ -91,7 +198,7 @@ namespace PowerToysTests
|
||||
[TestCleanup]
|
||||
public void TestCleanup()
|
||||
{
|
||||
|
||||
ResetSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace PowerToysTests
|
||||
{
|
||||
WindowsElement cancelButton = session.FindElementByXPath("//Window[@Name=\"FancyZones Editor\"]/Window/Button[@Name=\"Cancel\"]");
|
||||
new Actions(session).MoveToElement(cancelButton).Click().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
Assert.AreEqual(_defaultZoneSettings, File.ReadAllText(_zoneSettingsPath), "Settings were changed");
|
||||
}
|
||||
@@ -26,7 +26,7 @@ namespace PowerToysTests
|
||||
private void SaveTest()
|
||||
{
|
||||
new Actions(session).MoveToElement(session.FindElementByName("Save and apply")).Click().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
JObject settings = JObject.Parse(File.ReadAllText(_zoneSettingsPath));
|
||||
Assert.AreEqual("Custom Layout 1", settings["custom-zone-sets"][0]["name"]);
|
||||
@@ -188,7 +188,6 @@ namespace PowerToysTests
|
||||
if (editorWindow != null)
|
||||
{
|
||||
editorWindow.SendKeys(OpenQA.Selenium.Keys.Alt + OpenQA.Selenium.Keys.F4);
|
||||
ShortWait();
|
||||
}
|
||||
}
|
||||
catch(OpenQA.Selenium.WebDriverException)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OpenQA.Selenium.Appium.Windows;
|
||||
using OpenQA.Selenium.Interactions;
|
||||
|
||||
@@ -17,8 +17,10 @@ namespace PowerToysTests
|
||||
protected static void OpenEditor()
|
||||
{
|
||||
new Actions(session).KeyDown(OpenQA.Selenium.Keys.Command).SendKeys("`").KeyUp(OpenQA.Selenium.Keys.Command).Perform();
|
||||
ShortWait();
|
||||
editorWindow = session.FindElementByXPath("//Window[@Name=\"FancyZones Editor\"]");
|
||||
//editorWindow = WaitElementByXPath("//Window[@Name=\"FancyZones Editor\"]");
|
||||
//may not find editor by name in 0.16.1
|
||||
editorWindow = WaitElementByAccessibilityId("MainWindow1");
|
||||
Assert.IsNotNull(editorWindow, "Couldn't find editor window");
|
||||
}
|
||||
|
||||
protected static void CloseEditor()
|
||||
@@ -28,7 +30,6 @@ namespace PowerToysTests
|
||||
if (editorWindow != null)
|
||||
{
|
||||
editorWindow.SendKeys(OpenQA.Selenium.Keys.Alt + OpenQA.Selenium.Keys.F4);
|
||||
ShortWait();
|
||||
}
|
||||
}
|
||||
catch (OpenQA.Selenium.WebDriverException)
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace PowerToysTests
|
||||
private static void Init()
|
||||
{
|
||||
OpenSettings();
|
||||
ShortWait();
|
||||
|
||||
OpenFancyZonesSettings();
|
||||
|
||||
_saveButton = session.FindElementByName("Save");
|
||||
@@ -94,7 +92,7 @@ namespace PowerToysTests
|
||||
Assert.AreEqual(expected.ToString() + "\r\n", editor.Text);
|
||||
|
||||
SaveChanges();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
int value = GetPropertyValue<int>("fancyzones_highlight_opacity");
|
||||
Assert.AreEqual(expected, value);
|
||||
@@ -215,7 +213,7 @@ namespace PowerToysTests
|
||||
action.Perform();
|
||||
|
||||
SaveChanges();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
//Assert.AreEqual(expectedText, input.Text);
|
||||
|
||||
@@ -235,7 +233,7 @@ namespace PowerToysTests
|
||||
|
||||
//black on the bottom
|
||||
new Actions(session).MoveToElement(saturationAndBrightness).ClickAndHold().MoveByOffset(0, satRect.Height).Release().Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
Assert.AreEqual("0\r\n", red.Text);
|
||||
Assert.AreEqual("0\r\n", green.Text);
|
||||
@@ -243,7 +241,7 @@ namespace PowerToysTests
|
||||
Assert.AreEqual("000000\r\n", hex.Text);
|
||||
|
||||
SaveChanges();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual("#000000", GetPropertyValue<string>(propertyName));
|
||||
|
||||
//white in left corner
|
||||
@@ -254,7 +252,7 @@ namespace PowerToysTests
|
||||
Assert.AreEqual("ffffff\r\n", hex.Text);
|
||||
|
||||
SaveChanges();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual("#ffffff", GetPropertyValue<string>(propertyName));
|
||||
|
||||
//color in right corner
|
||||
@@ -266,7 +264,7 @@ namespace PowerToysTests
|
||||
Assert.AreEqual("ff0000\r\n", hex.Text);
|
||||
|
||||
SaveChanges();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual("#ff0000", GetPropertyValue<string>(propertyName));
|
||||
}
|
||||
|
||||
@@ -299,9 +297,10 @@ namespace PowerToysTests
|
||||
toggle.Click();
|
||||
|
||||
SaveChanges();
|
||||
ShortWait();
|
||||
}
|
||||
|
||||
WaitSeconds(1);
|
||||
|
||||
//check saved settings
|
||||
JObject savedProps = GetProperties();
|
||||
Assert.AreNotEqual(toggleValues[0], GetPropertyValue<bool>(savedProps, "fancyzones_shiftDrag"));
|
||||
@@ -339,7 +338,7 @@ namespace PowerToysTests
|
||||
}
|
||||
|
||||
SaveChanges();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
JObject savedProps = GetProperties();
|
||||
Assert.AreEqual(toggleValues[0], GetPropertyValue<bool>(savedProps, "fancyzones_shiftDrag"));
|
||||
@@ -396,7 +395,7 @@ namespace PowerToysTests
|
||||
|
||||
Actions action = new Actions(session);
|
||||
action.MoveToElement(editor).MoveByOffset(editorRect.Width / 2 + 10, -editorRect.Height / 4).Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
action.Click().Perform();
|
||||
Assert.AreEqual("100\r\n", editor.Text);
|
||||
@@ -421,7 +420,7 @@ namespace PowerToysTests
|
||||
|
||||
Actions action = new Actions(session);
|
||||
action.MoveToElement(editor).MoveByOffset(editorRect.Width / 2 + 10, editorRect.Height / 4).Perform();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
|
||||
action.Click().Perform();
|
||||
Assert.AreEqual("0\r\n", editor.Text);
|
||||
@@ -494,7 +493,7 @@ namespace PowerToysTests
|
||||
Assert.AreEqual("152", hue.Text);
|
||||
|
||||
SaveChanges();
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual("#63c99a", GetPropertyValue<string>("fancyzones_zoneHighlightColor"));
|
||||
}
|
||||
|
||||
@@ -565,7 +564,7 @@ namespace PowerToysTests
|
||||
input.SendKeys(inputValue);
|
||||
SaveChanges();
|
||||
ClearInput(input);
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual(inputValue, GetPropertyValue<string>("fancyzones_excluded_apps"));
|
||||
|
||||
//invalid
|
||||
@@ -573,28 +572,28 @@ namespace PowerToysTests
|
||||
input.SendKeys(inputValue);
|
||||
SaveChanges();
|
||||
ClearInput(input);
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual(inputValue, GetPropertyValue<string>("fancyzones_excluded_apps"));
|
||||
|
||||
inputValue = "Notepad,Chrome";
|
||||
input.SendKeys(inputValue);
|
||||
SaveChanges();
|
||||
ClearInput(input);
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual(inputValue, GetPropertyValue<string>("fancyzones_excluded_apps"));
|
||||
|
||||
inputValue = "Note*";
|
||||
input.SendKeys(inputValue);
|
||||
SaveChanges();
|
||||
ClearInput(input);
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual(inputValue, GetPropertyValue<string>("fancyzones_excluded_apps"));
|
||||
|
||||
inputValue = "Кириллица";
|
||||
input.SendKeys(inputValue);
|
||||
SaveChanges();
|
||||
ClearInput(input);
|
||||
ShortWait();
|
||||
WaitSeconds(1);
|
||||
Assert.AreEqual(inputValue, GetPropertyValue<string>("fancyzones_excluded_apps"));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace PowerToysTests
|
||||
public class PowerToysSession
|
||||
{
|
||||
protected const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
|
||||
protected const string AppPath = "C:\\Program Files\\PowerToys\\PowerToys.exe";
|
||||
|
||||
protected static WindowsDriver<WindowsElement> session;
|
||||
protected static bool isPowerToysLaunched = false;
|
||||
protected static WindowsElement trayButton;
|
||||
@@ -67,13 +69,26 @@ namespace PowerToysTests
|
||||
Thread.Sleep(TimeSpan.FromSeconds(seconds));
|
||||
}
|
||||
|
||||
public static void ShortWait()
|
||||
//Trying to find element by XPath
|
||||
protected static WindowsElement WaitElementByName(string name, double maxTime = 10)
|
||||
{
|
||||
Thread.Sleep(TimeSpan.FromSeconds(0.5));
|
||||
WindowsElement result = null;
|
||||
Stopwatch timer = new Stopwatch();
|
||||
timer.Start();
|
||||
while (timer.Elapsed < TimeSpan.FromSeconds(maxTime))
|
||||
{
|
||||
try
|
||||
{
|
||||
result = session.FindElementByName(name);
|
||||
}
|
||||
catch { }
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Trying to find element by XPath
|
||||
protected WindowsElement WaitElementByXPath(string xPath, double maxTime = 10)
|
||||
protected static WindowsElement WaitElementByXPath(string xPath, double maxTime = 10)
|
||||
{
|
||||
WindowsElement result = null;
|
||||
Stopwatch timer = new Stopwatch();
|
||||
@@ -85,17 +100,13 @@ namespace PowerToysTests
|
||||
result = session.FindElementByXPath(xPath);
|
||||
}
|
||||
catch { }
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Assert.IsNotNull(result);
|
||||
return null;
|
||||
}
|
||||
|
||||
//Trying to find element by AccessibilityId
|
||||
protected WindowsElement WaitElementByAccessibilityId(string accessibilityId, double maxTime = 10)
|
||||
protected static WindowsElement WaitElementByAccessibilityId(string accessibilityId, double maxTime = 10)
|
||||
{
|
||||
WindowsElement result = null;
|
||||
Stopwatch timer = new Stopwatch();
|
||||
@@ -107,12 +118,8 @@ namespace PowerToysTests
|
||||
result = session.FindElementByAccessibilityId(accessibilityId);
|
||||
}
|
||||
catch { }
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Assert.IsNotNull(result);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -125,13 +132,11 @@ namespace PowerToysTests
|
||||
|
||||
public static void OpenFancyZonesSettings()
|
||||
{
|
||||
WindowsElement fzNavigationButton = session.FindElementByXPath("//Button[@Name=\"FancyZones\"]");
|
||||
WindowsElement fzNavigationButton = WaitElementByXPath("//Button[@Name=\"FancyZones\"]");
|
||||
Assert.IsNotNull(fzNavigationButton);
|
||||
|
||||
fzNavigationButton.Click();
|
||||
fzNavigationButton.Click();
|
||||
|
||||
ShortWait();
|
||||
}
|
||||
|
||||
public static void CloseSettings()
|
||||
@@ -157,7 +162,7 @@ namespace PowerToysTests
|
||||
|
||||
try
|
||||
{
|
||||
WindowsElement pt = session.FindElementByXPath("//Button[@Name=\"PowerToys\"]");
|
||||
WindowsElement pt = WaitElementByXPath("//Button[@Name=\"PowerToys\"]");
|
||||
isLaunched = (pt != null);
|
||||
}
|
||||
catch(OpenQA.Selenium.WebDriverException)
|
||||
@@ -175,9 +180,7 @@ namespace PowerToysTests
|
||||
{
|
||||
AppiumOptions opts = new AppiumOptions();
|
||||
opts.PlatformName = "Windows";
|
||||
opts.AddAdditionalCapability("platformVersion", "10");
|
||||
opts.AddAdditionalCapability("deviceName", "WindowsPC");
|
||||
opts.AddAdditionalCapability("app", "C:/Program Files/PowerToys/PowerToys.exe");
|
||||
opts.AddAdditionalCapability("app", AppPath);
|
||||
|
||||
WindowsDriver<WindowsElement> driver = new WindowsDriver<WindowsElement>(new Uri(WindowsApplicationDriverUrl), opts);
|
||||
Assert.IsNotNull(driver);
|
||||
@@ -195,13 +198,12 @@ namespace PowerToysTests
|
||||
public static void ExitPowerToys()
|
||||
{
|
||||
trayButton.Click();
|
||||
ShortWait();
|
||||
|
||||
WindowsElement pt = session.FindElementByXPath("//Button[@Name=\"PowerToys\"]");
|
||||
WindowsElement pt = WaitElementByXPath("//Button[@Name=\"PowerToys\"]");
|
||||
Assert.IsNotNull(pt, "Couldn't find \'PowerToys\' button");
|
||||
new Actions(session).MoveToElement(pt).ContextClick().Perform();
|
||||
ShortWait();
|
||||
|
||||
session.FindElementByXPath("//MenuItem[@Name=\"Exit\"]").Click();
|
||||
WaitElementByXPath("//MenuItem[@Name=\"Exit\"]").Click();
|
||||
trayButton.Click(); //close tray
|
||||
isPowerToysLaunched = false;
|
||||
}
|
||||
|
||||
@@ -15,10 +15,9 @@ namespace PowerToysTests
|
||||
public void SettingsOpen()
|
||||
{
|
||||
OpenSettings();
|
||||
ShortWait();
|
||||
|
||||
//check settings window opened
|
||||
WindowsElement settingsWindow = session.FindElementByName("PowerToys Settings");
|
||||
WindowsElement settingsWindow = WaitElementByName("PowerToys Settings");
|
||||
Assert.IsNotNull(settingsWindow);
|
||||
|
||||
isSettingsOpened = true;
|
||||
@@ -36,14 +35,12 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(pt);
|
||||
|
||||
new Actions(session).MoveToElement(pt).ContextClick().Perform();
|
||||
ShortWait();
|
||||
|
||||
//open settings
|
||||
session.FindElementByXPath("//MenuItem[@Name=\"Settings\"]").Click();
|
||||
ShortWait();
|
||||
WaitElementByXPath("//MenuItem[@Name=\"Settings\"]").Click();
|
||||
|
||||
//check settings window opened
|
||||
WindowsElement settingsWindow = session.FindElementByName("PowerToys Settings");
|
||||
WindowsElement settingsWindow = WaitElementByName("PowerToys Settings");
|
||||
Assert.IsNotNull(settingsWindow);
|
||||
|
||||
isSettingsOpened = true;
|
||||
@@ -62,11 +59,9 @@ namespace PowerToysTests
|
||||
Assert.IsNotNull(powerToys);
|
||||
|
||||
new Actions(session).MoveToElement(powerToys).ContextClick().Perform();
|
||||
ShortWait();
|
||||
|
||||
//exit
|
||||
session.FindElementByXPath("//MenuItem[@Name=\"Exit\"]").Click();
|
||||
ShortWait();
|
||||
WaitElementByXPath("//MenuItem[@Name=\"Exit\"]").Click();
|
||||
|
||||
//check PowerToys exited
|
||||
powerToys = null;
|
||||
@@ -82,8 +77,6 @@ namespace PowerToysTests
|
||||
}
|
||||
|
||||
LaunchPowerToys();
|
||||
ShortWait();
|
||||
|
||||
Assert.IsNull(powerToys);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user