From 1f9d9c619ee4134e1f3adec28fccb09e12bccb72 Mon Sep 17 00:00:00 2001 From: Seraphima Zykova Date: Thu, 9 Apr 2020 16:47:25 +0300 Subject: [PATCH 01/14] FZ editor: splitter thickness set to 1px when space around zones is zero (#2020) --- .../editor/FancyZonesEditor/GridZone.xaml.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/GridZone.xaml.cs b/src/modules/fancyzones/editor/FancyZonesEditor/GridZone.xaml.cs index cb37c20650..5a8e330010 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/GridZone.xaml.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/GridZone.xaml.cs @@ -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() From 6419c6b1baea251e34df24ac5e7845edbca6bade Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Thu, 9 Apr 2020 16:20:17 +0100 Subject: [PATCH 02/14] settings: fix minimist package vulnerable version (#2021) Updates nested dependencies so that a vulnerable version of minimist is not being used. --- src/settings-web/package-lock.json | 453 ++++++++++++++++++++++------- src/settings-web/package.json | 4 + 2 files changed, 358 insertions(+), 99 deletions(-) diff --git a/src/settings-web/package-lock.json b/src/settings-web/package-lock.json index a02ec1495b..c2efd9eab8 100644 --- a/src/settings-web/package-lock.json +++ b/src/settings-web/package-lock.json @@ -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,8 +11709,25 @@ "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", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -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": { diff --git a/src/settings-web/package.json b/src/settings-web/package.json index 983ff89f97..52a306aa72 100644 --- a/src/settings-web/package.json +++ b/src/settings-web/package.json @@ -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" } } From b92a127200181ef322c6823be8ae013ffdce6d04 Mon Sep 17 00:00:00 2001 From: Yevhenii Holovachov <55396981+yevhenii44@users.noreply.github.com> Date: Fri, 10 Apr 2020 12:15:59 +0300 Subject: [PATCH 03/14] Added icon for FZEditor (#1388) * Added icon for FZEditor --- .../FancyZonesEditor/FancyZonesEditor.csproj | 6 ++++++ .../images/FancyZonesEditor.ico | Bin 0 -> 55183 bytes 2 files changed, 6 insertions(+) create mode 100644 src/modules/fancyzones/editor/FancyZonesEditor/images/FancyZonesEditor.ico diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj b/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj index 9c450afcff..1eef754925 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj +++ b/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj @@ -84,6 +84,9 @@ false ..\..\..\..\codeAnalysis\Rules.ruleset + + images\FancyZonesEditor.ico + @@ -256,5 +259,8 @@ + + + \ No newline at end of file diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/images/FancyZonesEditor.ico b/src/modules/fancyzones/editor/FancyZonesEditor/images/FancyZonesEditor.ico new file mode 100644 index 0000000000000000000000000000000000000000..e82442c2643edd754a5dcece07d0a1ecb79c438b GIT binary patch literal 55183 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 literal 0 HcmV?d00001 From e896e1b3dd800cee820d2e18fb93856b2c60e461 Mon Sep 17 00:00:00 2001 From: Clint Rutkas Date: Fri, 10 Apr 2020 06:41:19 -0700 Subject: [PATCH 04/14] fixing a bunch of warnings from Window Walker (#2014) * first set of warning fixes * Since this is a Interop item, it should have a _ * Update Window.cs * Update InteropAndHelpers.cs looks like there was a space a the top * Update Window.cs --- .../Components/InteropAndHelpers.cs | 47 ++++++++++++++++--- .../Window Walker/Components/OpenWindows.cs | 1 - .../app/Window Walker/Components/Window.cs | 18 +++---- .../app/Window Walker/MainWindow.xaml.cs | 2 +- .../ViewModels/WindowWalkerViewModel.cs | 3 +- 5 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/modules/windowwalker/app/Window Walker/Components/InteropAndHelpers.cs b/src/modules/windowwalker/app/Window Walker/Components/InteropAndHelpers.cs index 1f90405c0b..946729e8db 100644 --- a/src/modules/windowwalker/app/Window Walker/Components/InteropAndHelpers.cs +++ b/src/modules/windowwalker/app/Window Walker/Components/InteropAndHelpers.cs @@ -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/ @@ -603,167 +603,200 @@ namespace WindowWalker.Components /// The retrieved handle identifies the window of the same type that is highest in the Z order. /// GW_HWNDFIRST = 0, + /// /// The retrieved handle identifies the window of the same type that is lowest in the Z order. /// GW_HWNDLAST = 1, + /// /// The retrieved handle identifies the window below the specified window in the Z order. /// GW_HWNDNEXT = 2, + /// /// The retrieved handle identifies the window above the specified window in the Z order. /// GW_HWNDPREV = 3, + /// /// The retrieved handle identifies the specified window's owner window, if any. /// GW_OWNER = 4, + /// /// The retrieved handle identifies the child window at the top of the Z order, if the specified window /// is a parent window. /// GW_CHILD = 5, + /// /// The retrieved handle identifies the enabled popup window owned by the specified window. /// - GW_ENABLEDPOPUP = 6 + GW_ENABLEDPOPUP = 6, } /// /// GetWindowLong index to retrieves the extended window styles. /// +#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 /// /// The following are the extended window styles /// [Flags] - public enum ExtendedWindowStyles : UInt32 + public enum ExtendedWindowStyles : uint { /// /// 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. /// WS_EX_DLGMODALFRAME = 0X0001, + /// /// The child window created with this style does not send the WM_PARENTNOTIFY message to its parent window /// when it is created or destroyed. /// WS_EX_NOPARENTNOTIFY = 0X0004, + /// /// 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. /// WS_EX_TOPMOST = 0X0008, + /// /// The window accepts drag-drop files. /// WS_EX_ACCEPTFILES = 0x0010, + /// /// The window should not be painted until siblings beneath the window (that were created by the same thread) - /// have been painted. + /// have been painted. /// WS_EX_TRANSPARENT = 0x0020, + /// /// The window is a MDI child window. /// WS_EX_MDICHILD = 0x0040, + /// /// 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. /// WS_EX_TOOLWINDOW = 0x0080, + /// /// The window has a border with a raised edge. /// WS_EX_WINDOWEDGE = 0x0100, + /// /// The window has a border with a sunken edge. /// WS_EX_CLIENTEDGE = 0x0200, + /// /// The title bar of the window includes a question mark. /// WS_EX_CONTEXTHELP = 0x0400, + /// /// 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. /// WS_EX_RIGHT = 0x1000, + /// /// The window has generic left-aligned properties. This is the default. /// WS_EX_LEFT = 0x0, + /// /// 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. /// WS_EX_RTLREADING = 0x2000, + /// /// The window text is displayed using left-to-right reading-order properties. This is the default. /// WS_EX_LTRREADING = 0x0, + /// /// 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. /// WS_EX_LEFTSCROLLBAR = 0x4000, + /// /// The vertical scroll bar (if present) is to the right of the client area. This is the default. /// WS_EX_RIGHTSCROLLBAR = 0x0, + /// - /// The window itself contains child windows that should take part in dialog box, navigation. If this + /// 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. /// WS_EX_CONTROLPARENT = 0x10000, + /// /// The window has a three-dimensional border style intended to be used for items that do not accept /// user input. /// WS_EX_STATICEDGE = 0x20000, + /// /// Forces a top-level window onto the taskbar when the window is visible. /// WS_EX_APPWINDOW = 0x40000, + /// /// The window is an overlapped window. /// WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE, + /// /// The window is palette window, which is a modeless dialog box that presents an array of commands. /// WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST, + /// /// 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. /// WS_EX_LAYERED = 0x80000, + /// /// The window does not pass its window layout to its child windows. /// WS_EX_NOINHERITLAYOUT = 0x100000, + /// /// 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. /// WS_EX_LAYOUTRTL = 0x400000, + /// /// 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 + /// 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. /// WS_EX_COMPOSITED = 0x2000000, + /// /// 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. /// - WS_EX_NOACTIVATE = 0x8000000 + WS_EX_NOACTIVATE = 0x8000000, } [DllImport("user32.dll", CharSet = CharSet.Unicode)] diff --git a/src/modules/windowwalker/app/Window Walker/Components/OpenWindows.cs b/src/modules/windowwalker/app/Window Walker/Components/OpenWindows.cs index e65dd2913a..4450fa546a 100644 --- a/src/modules/windowwalker/app/Window Walker/Components/OpenWindows.cs +++ b/src/modules/windowwalker/app/Window Walker/Components/OpenWindows.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace WindowWalker.Components diff --git a/src/modules/windowwalker/app/Window Walker/Components/Window.cs b/src/modules/windowwalker/app/Window Walker/Components/Window.cs index 0aa84eafdb..a767145ecb 100644 --- a/src/modules/windowwalker/app/Window Walker/Components/Window.cs +++ b/src/modules/windowwalker/app/Window Walker/Components/Window.cs @@ -112,7 +112,7 @@ namespace WindowWalker.Components InteropAndHelpers.CallBackPtr callbackptr = new InteropAndHelpers.CallBackPtr((IntPtr hwnd, IntPtr lParam) => { var childProcessId = GetProcessIDFromWindowHandle(hwnd); - if (childProcessId != this.ProcessID) + if (childProcessId != ProcessID) { _handlesToProcessCache[Hwnd] = GetProcessNameFromWindowHandle(hwnd); return false; @@ -191,7 +191,7 @@ namespace WindowWalker.Components } /// - /// Determines whether the specified window handle identifies an existing window. + /// Gets a value indicating whether the specified window handle identifies an existing window. /// public bool IsWindow { @@ -202,7 +202,7 @@ namespace WindowWalker.Components } /// - /// Get a value indicating whether is the window GWL_EX_STYLE is a toolwindow + /// Gets a value indicating whether a value is the window GWL_EX_STYLE is a toolwindow /// public bool IsToolWindow { @@ -215,7 +215,7 @@ namespace WindowWalker.Components } /// - /// Get a value indicating whether the window GWL_EX_STYLE is an appwindow + /// Gets a value indicating whether the window GWL_EX_STYLE is an appwindow /// public bool IsAppWindow { @@ -228,7 +228,7 @@ namespace WindowWalker.Components } /// - /// Get a value indicating whether the window has ITaskList_Deleted property + /// Gets a value indicating whether the window has ITaskList_Deleted property /// public bool TaskListDeleted { @@ -239,18 +239,18 @@ namespace WindowWalker.Components } /// - /// Get a value indicating whether the app is a cloaked UWP app + /// Gets a value indicating whether the app is a cloaked UWP app /// public bool IsUWPCloaked { get { - return (this.IsWindowCloaked() && this.ClassName == "ApplicationFrameWindow"); + return IsWindowCloaked() && ClassName == "ApplicationFrameWindow"; } } /// - /// Determines whether the specified windows is the owner + /// Gets a value indicating whether the specified windows is the owner /// public bool IsOwner { @@ -267,7 +267,7 @@ namespace WindowWalker.Components { int isCloaked = 0; const int DWMWA_CLOAKED = 14; - InteropAndHelpers.DwmGetWindowAttribute(this.hwnd, DWMWA_CLOAKED, out isCloaked, sizeof(int)); + InteropAndHelpers.DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, out isCloaked, sizeof(int)); return isCloaked != 0; } diff --git a/src/modules/windowwalker/app/Window Walker/MainWindow.xaml.cs b/src/modules/windowwalker/app/Window Walker/MainWindow.xaml.cs index ac20d27302..f1acd6c687 100644 --- a/src/modules/windowwalker/app/Window Walker/MainWindow.xaml.cs +++ b/src/modules/windowwalker/app/Window Walker/MainWindow.xaml.cs @@ -117,7 +117,7 @@ namespace WindowWalker private void Window_GotFocus(object sender, RoutedEventArgs e) { - this.searchBox.Focus(); + searchBox.Focus(); } } } diff --git a/src/modules/windowwalker/app/Window Walker/ViewModels/WindowWalkerViewModel.cs b/src/modules/windowwalker/app/Window Walker/ViewModels/WindowWalkerViewModel.cs index 2b5fd6dcad..8f57747b38 100644 --- a/src/modules/windowwalker/app/Window Walker/ViewModels/WindowWalkerViewModel.cs +++ b/src/modules/windowwalker/app/Window Walker/ViewModels/WindowWalkerViewModel.cs @@ -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,7 +18,6 @@ namespace WindowWalker.ViewModels private readonly List _hints = new List() { "search for running processes or windows...", - // "you can reinvoke this app using CTRL + WIN", }; private string _searchText = string.Empty; From 629ba763d7172338355a9547163d6448bd34cc14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Sto=C5=A1i=C4=87?= Date: Fri, 10 Apr 2020 16:09:08 +0200 Subject: [PATCH 05/14] Basic support for snapping to multiple zones (#1955) * Refactor a method which resizes windows * Completed initial work for MultiZones Without changing any test, they all pass! * Implemented a basic version of Multizones, updated some tests * Reduced the sensitivity radius * Added a few must-have unit tests for Multizones * Some fixups * Took care of the conflict between this and #1938 * Improved how zones are detected, reverted a change in one unit test * Resolved another merge conflict * Fixed bugs related to stamping --- src/modules/fancyzones/lib/FancyZones.cpp | 9 +- src/modules/fancyzones/lib/Zone.cpp | 35 +--- src/modules/fancyzones/lib/Zone.h | 13 +- src/modules/fancyzones/lib/ZoneSet.cpp | 158 ++++++++++++++---- src/modules/fancyzones/lib/ZoneSet.h | 20 ++- src/modules/fancyzones/lib/ZoneWindow.cpp | 56 ++++--- src/modules/fancyzones/lib/ZoneWindow.h | 7 + src/modules/fancyzones/lib/util.cpp | 27 +++ src/modules/fancyzones/lib/util.h | 1 + .../tests/UnitTests/ZoneSet.Spec.cpp | 124 ++++++++++---- .../tests/UnitTests/ZoneWindow.Spec.cpp | 6 +- 11 files changed, 328 insertions(+), 128 deletions(-) diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index 4ea6c7b6db..15eda418d5 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -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& indexSet) noexcept; protected: static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept; @@ -695,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& indexSet) noexcept { std::shared_lock readLock(m_lock); if (window != m_windowMoveSize) @@ -706,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); } } } diff --git a/src/modules/fancyzones/lib/Zone.cpp b/src/modules/fancyzones/lib/Zone.cpp index 6b3347f390..ad6207e7e1 100644 --- a/src/modules/fancyzones/lib/Zone.cpp +++ b/src/modules/fancyzones/lib/Zone.cpp @@ -4,6 +4,7 @@ #include #include "Zone.h" #include "Settings.h" +#include "util.h" struct Zone : winrt::implements { @@ -20,6 +21,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,12 +63,11 @@ 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 newWindowRect = m_zoneRect; @@ -111,29 +112,7 @@ void Zone::SizeWindowToZone(HWND window, HWND zoneWindow) noexcept newWindowRect.bottom = newWindowRect.top + (windowRect.bottom - windowRect.top); } - 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 = newWindowRect; - 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 diff --git a/src/modules/fancyzones/lib/Zone.h b/src/modules/fancyzones/lib/Zone.h index 6e283d9607..8cad96647d 100644 --- a/src/modules/fancyzones/lib/Zone.h +++ b/src/modules/fancyzones/lib/Zone.h @@ -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 MakeZone(const RECT& zoneRect) noexcept; diff --git a/src/modules/fancyzones/lib/ZoneSet.cpp b/src/modules/fancyzones/lib/ZoneSet.cpp index 80fd36b119..269632727b 100644 --- a/src/modules/fancyzones/lib/ZoneSet.cpp +++ b/src/modules/fancyzones/lib/ZoneSet.cpp @@ -122,14 +122,16 @@ public: IFACEMETHODIMP_(JSONHelpers::ZoneSetLayoutType) LayoutType() noexcept { return m_config.LayoutType; } IFACEMETHODIMP AddZone(winrt::com_ptr zone) noexcept; - IFACEMETHODIMP_(winrt::com_ptr) - ZoneFromPoint(POINT pt) noexcept; + IFACEMETHODIMP_(std::vector) + ZonesFromPoint(POINT pt) noexcept; IFACEMETHODIMP_(int) GetZoneIndexFromWindow(HWND window) noexcept; IFACEMETHODIMP_(std::vector>) 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& 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 zone) noexcept return S_OK; } -IFACEMETHODIMP_(winrt::com_ptr) -ZoneSet::ZoneFromPoint(POINT pt) noexcept +IFACEMETHODIMP_(std::vector) +ZoneSet::ZonesFromPoint(POINT pt) noexcept { - winrt::com_ptr 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 capturedZones; + std::vector strictlyCapturedZones; + for (size_t i = 0; i < m_zones.size(); i++) { - if (winrt::com_ptr zone = iter->try_as()) + 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; - - RECT* r = &smallestKnownZone->GetZoneRect(); - smallestKnownZoneArea = (r->right - r->left) * (r->bottom - r->top); - } - else - { - int newZoneArea = (newZoneRect->right - newZoneRect->left) * (newZoneRect->bottom - newZoneRect->top); - - if (newZoneArea < smallestKnownZoneArea) - { - smallestKnownZone = zone; - smallestKnownZoneArea = newZoneArea; - } - } + capturedZones.emplace_back(static_cast(i)); + } + + if (newZoneRect.left <= pt.x && pt.x < newZoneRect.right && + newZoneRect.top <= pt.y && pt.y < newZoneRect.bottom) + { + strictlyCapturedZones.emplace_back(static_cast(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& 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(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) diff --git a/src/modules/fancyzones/lib/ZoneSet.h b/src/modules/fancyzones/lib/ZoneSet.h index 94a7ff6c8b..41564f83aa 100644 --- a/src/modules/fancyzones/lib/ZoneSet.h +++ b/src/modules/fancyzones/lib/ZoneSet.h @@ -24,12 +24,12 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : */ IFACEMETHOD(AddZone)(winrt::com_ptr 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, ZoneFromPoint)(POINT pt) = 0; + IFACEMETHOD_(std::vector, 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& indexSet, bool stampZone) = 0; /** * Assign window to the zone based on direction (using WIN + LEFT/RIGHT arrow). * diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index b2c3bab992..3e75c8d5a1 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -148,7 +148,7 @@ namespace ZoneWindowDrawUtils COLORREF highlightColor, int zoneOpacity, const std::vector>& zones, - const winrt::com_ptr& highlightZone, + const std::vector& 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 isHighlighted(zones.size(), false); + for (int x : highlightZones) + { + isHighlighted[x] = true; + } + for (auto iter = zones.begin(); iter != zones.end(); iter++) { + int zoneId = static_cast(iter - zones.begin()); winrt::com_ptr zone = iter->try_as(); 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) - { - colorHighlight.fill = highlightColor; - colorHighlight.border = zoneBorderColor; - DrawZone(hdc, colorHighlight, highlightZone, zones, flashMode); + else + { + colorHighlight.fill = highlightColor; + colorHighlight.border = zoneBorderColor; + DrawZone(hdc, colorHighlight, zone, zones, flashMode); + } } } } @@ -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& indexSet) noexcept; IFACEMETHODIMP_(bool) MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode, bool cycle) noexcept; IFACEMETHODIMP_(void) @@ -238,7 +246,7 @@ private: LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept; void OnPaint(wil::unique_hdc& hdc) noexcept; void OnKeyUp(WPARAM wparam) noexcept; - winrt::com_ptr ZoneFromPoint(POINT pt) noexcept; + std::vector 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 m_activeZoneSet; std::vector> m_zoneSets; - winrt::com_ptr m_highlightZone; + std::vector m_highlightZone; WPARAM m_keyLast{}; size_t m_keyCycle{}; static const UINT m_showAnimationDuration = 200; // ms @@ -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& 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 = {}; } } @@ -685,13 +699,13 @@ void ZoneWindow::OnKeyUp(WPARAM wparam) noexcept } } -winrt::com_ptr ZoneWindow::ZoneFromPoint(POINT pt) noexcept +std::vector 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 diff --git a/src/modules/fancyzones/lib/ZoneWindow.h b/src/modules/fancyzones/lib/ZoneWindow.h index df5b199486..0961163752 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.h +++ b/src/modules/fancyzones/lib/ZoneWindow.h @@ -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& indexSet) = 0; /** * Assign window to the zone based on direction (using WIN + LEFT/RIGHT arrow). * diff --git a/src/modules/fancyzones/lib/util.cpp b/src/modules/fancyzones/lib/util.cpp index 631af7e528..675b9f67e1 100644 --- a/src/modules/fancyzones/lib/util.cpp +++ b/src/modules/fancyzones/lib/util.cpp @@ -108,3 +108,30 @@ void OrderMonitors(std::vector>& 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); +} diff --git a/src/modules/fancyzones/lib/util.h b/src/modules/fancyzones/lib/util.h index f4b29934f7..be654c8555 100644 --- a/src/modules/fancyzones/lib/util.h +++ b/src/modules/fancyzones/lib/util.h @@ -118,3 +118,4 @@ inline BYTE OpacitySettingToAlpha(int opacity) UINT GetDpiForMonitor(HMONITOR monitor) noexcept; void OrderMonitors(std::vector>& monitorInfo); +void SizeWindowToRect(HWND window, RECT rect) noexcept; diff --git a/src/modules/fancyzones/tests/UnitTests/ZoneSet.Spec.cpp b/src/modules/fancyzones/tests/UnitTests/ZoneSet.Spec.cpp index 5562743e77..bbd32f4834 100644 --- a/src/modules/fancyzones/tests/UnitTests/ZoneSet.Spec.cpp +++ b/src/modules/fancyzones/tests/UnitTests/ZoneSet.Spec.cpp @@ -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 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 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 zone1 = MakeZone({ 0, 0, 100, 100 }); + m_set->AddZone(zone1); + winrt::com_ptr zone2 = MakeZone({ 100, 0, 200, 100 }); + m_set->AddZone(zone2); + winrt::com_ptr zone3 = MakeZone({ 0, 100, 100, 200 }); + m_set->AddZone(zone3); + winrt::com_ptr 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 zone1 = MakeZone({ 0, 0, 100, 100 }); + m_set->AddZone(zone1); + winrt::com_ptr zone2 = MakeZone({ 100, 0, 200, 100 }); + m_set->AddZone(zone2); + winrt::com_ptr zone3 = MakeZone({ 0, 100, 100, 200 }); + m_set->AddZone(zone3); + winrt::com_ptr 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 zone1 = MakeZone({ 0, 0, 100, 100 }); + m_set->AddZone(zone1); + winrt::com_ptr zone2 = MakeZone({ 100, 0, 200, 100 }); + m_set->AddZone(zone2); + winrt::com_ptr zone3 = MakeZone({ 0, 100, 100, 200 }); + m_set->AddZone(zone3); + winrt::com_ptr 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 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 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,7 +394,7 @@ namespace FancyZonesUnitTests m_set->AddZone(zone3); HWND window = Mocks::Window(); - m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 100); + 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)); } diff --git a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp index bece6fd65a..9be58b22ec 100644 --- a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp +++ b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp @@ -445,7 +445,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 +458,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(); @@ -501,7 +501,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); //with invalid point zone remains the same } From f589dd2f266f5f5e437739f5d2398475b62c1620 Mon Sep 17 00:00:00 2001 From: stefansjfw <57057282+stefansjfw@users.noreply.github.com> Date: Fri, 10 Apr 2020 16:29:18 +0200 Subject: [PATCH 06/14] Only clone layout from parent desktop when creating new virtual desktop (#1904) * Fix issue #1343 * Add Unit Tests * Revert non intended rename * Address PR comments --- src/modules/fancyzones/lib/FancyZones.cpp | 2 +- src/modules/fancyzones/lib/JsonHelpers.h | 5 + src/modules/fancyzones/lib/ZoneWindow.cpp | 16 +-- src/modules/fancyzones/lib/ZoneWindow.h | 2 +- .../tests/UnitTests/ZoneWindow.Spec.cpp | 107 ++++++++++++++---- 5 files changed, 99 insertions(+), 33 deletions(-) diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index 15eda418d5..ce05da6464 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -681,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); diff --git a/src/modules/fancyzones/lib/JsonHelpers.h b/src/modules/fancyzones/lib/JsonHelpers.h index 9917209bb1..3b5ecd27f0 100644 --- a/src/modules/fancyzones/lib/JsonHelpers.h +++ b/src/modules/fancyzones/lib/JsonHelpers.h @@ -212,6 +212,11 @@ namespace JSONHelpers customZoneSetsMap.clear(); activeDeviceId.clear(); } + + inline void SetDeviceInfo(const std::wstring& deviceId, DeviceInfoData data) + { + deviceInfoMap[deviceId] = data; + } #endif inline void SetActiveDeviceId(const std::wstring& deviceId) diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index 3e75c8d5a1..81cd60ac22 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -205,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; @@ -240,7 +240,7 @@ 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; @@ -297,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); @@ -316,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) @@ -543,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); @@ -787,10 +787,10 @@ LRESULT CALLBACK ZoneWindow::s_WndProc(HWND window, UINT message, WPARAM wparam, DefWindowProc(window, message, wparam, lparam); } -winrt::com_ptr MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, bool flashZones) noexcept +winrt::com_ptr MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, bool flashZones, bool newWorkArea) noexcept { auto self = winrt::make_self(hinstance); - if (self->Init(host, hinstance, monitor, uniqueId, flashZones)) + if (self->Init(host, hinstance, monitor, uniqueId, flashZones, newWorkArea)) { return self; } diff --git a/src/modules/fancyzones/lib/ZoneWindow.h b/src/modules/fancyzones/lib/ZoneWindow.h index 0961163752..e66c6f0b49 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.h +++ b/src/modules/fancyzones/lib/ZoneWindow.h @@ -105,4 +105,4 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow }; winrt::com_ptr MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, - const std::wstring& uniqueId, bool flashZones) noexcept; + const std::wstring& uniqueId, bool flashZones, bool newWorkArea) noexcept; diff --git a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp index 9be58b22ec..3460894f32 100644 --- a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp +++ b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp @@ -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 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(type), static_cast(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(ZoneSetLayoutType::Blank), static_cast(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); @@ -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 }); @@ -508,7 +569,7 @@ namespace FancyZonesUnitTests 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()); From 14441ec144b1e8307fd748734fe6ed82c15f9797 Mon Sep 17 00:00:00 2001 From: Seraphima Zykova Date: Fri, 10 Apr 2020 18:52:16 +0300 Subject: [PATCH 07/14] WinAppDriver tests fix (#2006) * updated wait methods and launch * canvas zone resize tests updated * updated editor opening --- .../EditorCanvasZoneResizeTests.cs | 204 ++++++++---------- .../EditorCustomLayoutsTests.cs | 23 +- .../FancyZonesTests/EditorOpeningTests.cs | 7 +- .../FancyZonesTests/EditorSettingsTests.cs | 14 +- .../EditorTemplatesEditTests.cs | 5 +- .../FancyZonesTests/FancyZonesEditor.cs | 9 +- .../FancyZonesSettingsTests.cs | 37 ++-- src/tests/win-app-driver/PowerToysSession.cs | 62 +++--- .../win-app-driver/PowerToysTrayTests.cs | 23 +- 9 files changed, 176 insertions(+), 208 deletions(-) diff --git a/src/tests/win-app-driver/FancyZonesTests/EditorCanvasZoneResizeTests.cs b/src/tests/win-app-driver/FancyZonesTests/EditorCanvasZoneResizeTests.cs index 955e6abb8a..f43b329f07 100644 --- a/src/tests/win-app-driver/FancyZonesTests/EditorCanvasZoneResizeTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/EditorCanvasZoneResizeTests.cs @@ -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(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] @@ -285,17 +268,12 @@ namespace PowerToysTests LaunchPowerToys(); } OpenEditor(); - OpenCustomLayouts(); - - //create canvas zone - OpenCreatorWindow("Create new custom", "Custom layout creator"); - session.FindElementByAccessibilityId("newZoneButton").Click(); + OpenCustomLayouts(); } [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(); } } } \ No newline at end of file diff --git a/src/tests/win-app-driver/FancyZonesTests/EditorCustomLayoutsTests.cs b/src/tests/win-app-driver/FancyZonesTests/EditorCustomLayoutsTests.cs index 49b184c8cc..3e2927e295 100644 --- a/src/tests/win-app-driver/FancyZonesTests/EditorCustomLayoutsTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/EditorCustomLayoutsTests.cs @@ -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,8 +236,7 @@ namespace PowerToysTests SetLayoutName(name); new Actions(session).MoveToElement(session.FindElementByName("Save and apply")).Click().Perform(); - ShortWait(); - + //remove layout OpenEditor(); OpenCustomLayouts(); @@ -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)); diff --git a/src/tests/win-app-driver/FancyZonesTests/EditorOpeningTests.cs b/src/tests/win-app-driver/FancyZonesTests/EditorOpeningTests.cs index 62bb3cccee..b9f4866841 100644 --- a/src/tests/win-app-driver/FancyZonesTests/EditorOpeningTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/EditorOpeningTests.cs @@ -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(); } diff --git a/src/tests/win-app-driver/FancyZonesTests/EditorSettingsTests.cs b/src/tests/win-app-driver/FancyZonesTests/EditorSettingsTests.cs index bc781ffcfa..009862b297 100644 --- a/src/tests/win-app-driver/FancyZonesTests/EditorSettingsTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/EditorSettingsTests.cs @@ -37,7 +37,7 @@ namespace PowerToysTests { session.FindElementByAccessibilityId("ApplyTemplateButton").Click(); - ShortWait(); + WaitSeconds(1); Assert.AreEqual(editorZoneCountValue, GetEditZonesSetting(editorZoneCount)); OpenEditor(); @@ -57,7 +57,7 @@ namespace PowerToysTests } session.FindElementByAccessibilityId("ApplyTemplateButton").Click(); - ShortWait(); + WaitSeconds(1); Assert.AreEqual(editorZoneCountValue, GetEditZonesSetting(editorZoneCount)); } @@ -74,7 +74,7 @@ namespace PowerToysTests session.FindElementByAccessibilityId("ApplyTemplateButton").Click(); - ShortWait(); + WaitSeconds(1); Assert.AreNotEqual(spaceAroundSettingValue, GetEditZonesSetting(editorShowSpacing)); } @@ -89,7 +89,7 @@ namespace PowerToysTests bool editorShowSpacingValue = spaceAroundSetting.Selected; session.FindElementByAccessibilityId("ApplyTemplateButton").Click(); - ShortWait(); + WaitSeconds(1); string[] validValues = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; @@ -102,7 +102,7 @@ namespace PowerToysTests paddingValue.SendKeys(editorSpacingValue); session.FindElementByAccessibilityId("ApplyTemplateButton").Click(); - ShortWait(); + WaitSeconds(1); Assert.AreEqual(editorShowSpacingValue, GetEditZonesSetting(editorShowSpacing)); Assert.AreEqual(editorSpacingValue, GetEditZonesSetting(editorSpacing)); @@ -118,7 +118,7 @@ namespace PowerToysTests bool editorShowSpacingValue = spaceAroundSetting.Selected; session.FindElementByAccessibilityId("ApplyTemplateButton").Click(); - ShortWait(); + WaitSeconds(1); string[] invalidValues = { "!", "/", "<", "?", "D", "Z", "]", "m", "}", "1.5", "2,5" }; @@ -133,7 +133,7 @@ namespace PowerToysTests paddingValue.SendKeys(value); session.FindElementByAccessibilityId("ApplyTemplateButton").Click(); - ShortWait(); + WaitSeconds(1); Assert.AreEqual(editorShowSpacingValue, GetEditZonesSetting(editorShowSpacing)); Assert.AreEqual(editorSpacingValue, GetEditZonesSetting(editorSpacing)); diff --git a/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesEditTests.cs b/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesEditTests.cs index b772bd7b8b..a74b1d43bc 100644 --- a/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesEditTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesEditTests.cs @@ -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) diff --git a/src/tests/win-app-driver/FancyZonesTests/FancyZonesEditor.cs b/src/tests/win-app-driver/FancyZonesTests/FancyZonesEditor.cs index 5d0cbbb745..ba98f1a991 100644 --- a/src/tests/win-app-driver/FancyZonesTests/FancyZonesEditor.cs +++ b/src/tests/win-app-driver/FancyZonesTests/FancyZonesEditor.cs @@ -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) diff --git a/src/tests/win-app-driver/FancyZonesTests/FancyZonesSettingsTests.cs b/src/tests/win-app-driver/FancyZonesTests/FancyZonesSettingsTests.cs index 70f7edf67f..d655b7960b 100644 --- a/src/tests/win-app-driver/FancyZonesTests/FancyZonesSettingsTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/FancyZonesSettingsTests.cs @@ -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("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(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(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(propertyName)); } @@ -299,9 +297,10 @@ namespace PowerToysTests toggle.Click(); SaveChanges(); - ShortWait(); } - + + WaitSeconds(1); + //check saved settings JObject savedProps = GetProperties(); Assert.AreNotEqual(toggleValues[0], GetPropertyValue(savedProps, "fancyzones_shiftDrag")); @@ -339,7 +338,7 @@ namespace PowerToysTests } SaveChanges(); - ShortWait(); + WaitSeconds(1); JObject savedProps = GetProperties(); Assert.AreEqual(toggleValues[0], GetPropertyValue(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("fancyzones_zoneHighlightColor")); } @@ -565,7 +564,7 @@ namespace PowerToysTests input.SendKeys(inputValue); SaveChanges(); ClearInput(input); - ShortWait(); + WaitSeconds(1); Assert.AreEqual(inputValue, GetPropertyValue("fancyzones_excluded_apps")); //invalid @@ -573,28 +572,28 @@ namespace PowerToysTests input.SendKeys(inputValue); SaveChanges(); ClearInput(input); - ShortWait(); + WaitSeconds(1); Assert.AreEqual(inputValue, GetPropertyValue("fancyzones_excluded_apps")); inputValue = "Notepad,Chrome"; input.SendKeys(inputValue); SaveChanges(); ClearInput(input); - ShortWait(); + WaitSeconds(1); Assert.AreEqual(inputValue, GetPropertyValue("fancyzones_excluded_apps")); inputValue = "Note*"; input.SendKeys(inputValue); SaveChanges(); ClearInput(input); - ShortWait(); + WaitSeconds(1); Assert.AreEqual(inputValue, GetPropertyValue("fancyzones_excluded_apps")); inputValue = "Кириллица"; input.SendKeys(inputValue); SaveChanges(); ClearInput(input); - ShortWait(); + WaitSeconds(1); Assert.AreEqual(inputValue, GetPropertyValue("fancyzones_excluded_apps")); } diff --git a/src/tests/win-app-driver/PowerToysSession.cs b/src/tests/win-app-driver/PowerToysSession.cs index 490e2bf39e..150938367f 100644 --- a/src/tests/win-app-driver/PowerToysSession.cs +++ b/src/tests/win-app-driver/PowerToysSession.cs @@ -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 session; protected static bool isPowerToysLaunched = false; protected static WindowsElement trayButton; @@ -66,14 +68,27 @@ namespace PowerToysTests { Thread.Sleep(TimeSpan.FromSeconds(seconds)); } - - public static void ShortWait() - { - Thread.Sleep(TimeSpan.FromSeconds(0.5)); + + //Trying to find element by XPath + protected static WindowsElement WaitElementByName(string name, double maxTime = 10) + { + 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; - } + 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; - } + 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) @@ -174,11 +179,9 @@ namespace PowerToysTests try { 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.PlatformName = "Windows"; + opts.AddAdditionalCapability("app", AppPath); + WindowsDriver driver = new WindowsDriver(new Uri(WindowsApplicationDriverUrl), opts); Assert.IsNotNull(driver); driver.LaunchApp(); @@ -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; } diff --git a/src/tests/win-app-driver/PowerToysTrayTests.cs b/src/tests/win-app-driver/PowerToysTrayTests.cs index 40be624014..304cb8e0bf 100644 --- a/src/tests/win-app-driver/PowerToysTrayTests.cs +++ b/src/tests/win-app-driver/PowerToysTrayTests.cs @@ -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,12 +59,10 @@ 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; try @@ -82,8 +77,6 @@ namespace PowerToysTests } LaunchPowerToys(); - ShortWait(); - Assert.IsNull(powerToys); } From 41ab94fe13d4e1184b21f59588b9bc19a5995a7a Mon Sep 17 00:00:00 2001 From: Clint Rutkas Date: Fri, 10 Apr 2020 12:39:25 -0700 Subject: [PATCH 08/14] updated notice (#2075) --- NOTICE.md | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/NOTICE.md b/NOTICE.md index 02bba477c4..19e326b54e 100644 --- a/NOTICE.md +++ b/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. + +### 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. \ No newline at end of file From 4e18c67ec5be9d284d68013f48fbf307275465c9 Mon Sep 17 00:00:00 2001 From: yuyoyuppe Date: Fri, 10 Apr 2020 20:58:49 +0300 Subject: [PATCH 09/14] chore: fix linking warnings --- src/modules/powerrename/dll/PowerRenameExt.vcxproj | 2 +- .../powerrename/unittests/PowerRenameLibUnitTests.vcxproj | 2 +- .../previewpane/powerpreviewTest/powerpreviewTest.vcxproj | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modules/powerrename/dll/PowerRenameExt.vcxproj b/src/modules/powerrename/dll/PowerRenameExt.vcxproj index 0ad2a49d20..152bbeba49 100644 --- a/src/modules/powerrename/dll/PowerRenameExt.vcxproj +++ b/src/modules/powerrename/dll/PowerRenameExt.vcxproj @@ -162,7 +162,7 @@ true Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\obj\PowerRenameUI\PowerRenameUI.res;shcore.lib;%(AdditionalDependencies) PowerRenameExt.def - gdi32.dll;advapi32.dll;shell32.dll;ole32.dll;shlwapi.dll;oleaut32.dll;%(DelayLoadDLLs) + gdi32.dll;shell32.dll;ole32.dll;shlwapi.dll;oleaut32.dll;%(DelayLoadDLLs) diff --git a/src/modules/powerrename/unittests/PowerRenameLibUnitTests.vcxproj b/src/modules/powerrename/unittests/PowerRenameLibUnitTests.vcxproj index 15cdf98324..795d47a53f 100644 --- a/src/modules/powerrename/unittests/PowerRenameLibUnitTests.vcxproj +++ b/src/modules/powerrename/unittests/PowerRenameLibUnitTests.vcxproj @@ -81,7 +81,7 @@ $(Platform)\$(Configuration)\ - false + true ..\lib\;$(IncludePath) $(SolutionDir)$(Platform)\$(Configuration)\modules\ $(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\ diff --git a/src/modules/previewpane/powerpreviewTest/powerpreviewTest.vcxproj b/src/modules/previewpane/powerpreviewTest/powerpreviewTest.vcxproj index 9673f02e4f..b95e2fe4bc 100644 --- a/src/modules/previewpane/powerpreviewTest/powerpreviewTest.vcxproj +++ b/src/modules/previewpane/powerpreviewTest/powerpreviewTest.vcxproj @@ -87,7 +87,6 @@ false - true $(SolutionDir)$(Platform)\$(Configuration)\modules\ $(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\ From 77e49844683fb66d99114b2af5311ab3051a4eff Mon Sep 17 00:00:00 2001 From: yuyoyuppe Date: Fri, 10 Apr 2020 21:41:01 +0300 Subject: [PATCH 10/14] chore: fix window walker warning --- .../windowwalker/app/Window Walker/Components/OpenWindows.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/windowwalker/app/Window Walker/Components/OpenWindows.cs b/src/modules/windowwalker/app/Window Walker/Components/OpenWindows.cs index 4450fa546a..21fffc284a 100644 --- a/src/modules/windowwalker/app/Window Walker/Components/OpenWindows.cs +++ b/src/modules/windowwalker/app/Window Walker/Components/OpenWindows.cs @@ -18,11 +18,15 @@ namespace WindowWalker.Components /// public delegate void OpenWindowsUpdateHandler(object sender, SearchController.SearchResultUpdateEventArgs e); +#pragma warning disable 0067 // suppress false positive + /// /// Event raised when there is an update to the list of open windows /// public event OpenWindowsUpdateHandler OnOpenWindowsUpdate; +#pragma warning restore 0067 + /// /// List of all the open windows /// From 6bb0f18d53a20970070c06449e6b4c8f61015243 Mon Sep 17 00:00:00 2001 From: Andrey Nekrasov Date: Mon, 13 Apr 2020 16:00:51 +0300 Subject: [PATCH 11/14] chore: format PowerToys custom actions (#2104) * chore: format PowerToys custom actions * add curly braces --- .../CustomAction.cpp | 856 ++++++++++-------- 1 file changed, 458 insertions(+), 398 deletions(-) diff --git a/installer/PowerToysSetupCustomActions/CustomAction.cpp b/installer/PowerToysSetupCustomActions/CustomAction.cpp index cf932f901b..a27a22581c 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.cpp +++ b/installer/PowerToysSetupCustomActions/CustomAction.cpp @@ -17,11 +17,11 @@ using namespace std; TRACELOGGING_DEFINE_PROVIDER( - g_hProvider, - "Microsoft.PowerToysInstaller", - // {e1d8165d-5cb6-5c74-3b51-bdfbfe4f7a3b} - (0xe1d8165d, 0x5cb6, 0x5c74, 0x3b, 0x51, 0xbd, 0xfb, 0xfe, 0x4f, 0x7a, 0x3b), - TraceLoggingOptionProjectTelemetry()); + g_hProvider, + "Microsoft.PowerToysInstaller", + // {e1d8165d-5cb6-5c74-3b51-bdfbfe4f7a3b} + (0xe1d8165d, 0x5cb6, 0x5c74, 0x3b, 0x51, 0xbd, 0xfb, 0xfe, 0x4f, 0x7a, 0x3b), + TraceLoggingOptionProjectTelemetry()); const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0' const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0' @@ -30,502 +30,562 @@ 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) { - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; +UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; - TCHAR username_domain[USERNAME_DOMAIN_LEN]; - TCHAR username[USERNAME_LEN]; + TCHAR username_domain[USERNAME_DOMAIN_LEN]; + TCHAR username[USERNAME_LEN]; - std::wstring wstrTaskName; + 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"); + hr = WcaInitialize(hInstall, "CreateScheduledTaskCA"); + ExitOnFailure(hr, "Failed to initialize"); - WcaLog(LOGMSG_STANDARD, "Initialized."); + WcaLog(LOGMSG_STANDARD, "Initialized."); - // ------------------------------------------------------ - // Get the Domain/Username for the trigger. - // - // 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)) { - ExitWithLastError(hr, "Getting username failed: %x", hr); - } - if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN)) { - ExitWithLastError(hr, "Getting the user's domain failed: %x", hr); - } - wcscat_s(username_domain, L"\\"); - wcscat_s(username_domain, username); - - WcaLog(LOGMSG_STANDARD, "Current user detected: %ls", username_domain); - - // Task Name. - wstrTaskName = L"Autorun for "; - wstrTaskName += username; - - // Get the executable path passed to the custom action. - LPWSTR wszExecutablePath = NULL; - hr = WcaGetProperty(L"CustomActionData", &wszExecutablePath); - ExitOnFailure(hr, "Failed to get the executable path from CustomActionData."); - - // COM and Security Initialization is expected to have been done by the MSI. - // It couldn't be done in the DLL, anyway. - // ------------------------------------------------------ - // Create an instance of the Task Service. - hr = CoCreateInstance(CLSID_TaskScheduler, - NULL, - CLSCTX_INPROC_SERVER, - IID_ITaskService, - (void**)&pService); - 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()); - 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)) { - // Folder doesn't exist. Get the Root folder and create the PowerToys subfolder. - 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)) { - pRootFolder->Release(); - ExitOnFailure(hr, "Cannot create PowerToys task folder: %x", hr); + // ------------------------------------------------------ + // Get the Domain/Username for the trigger. + // + // 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)) + { + ExitWithLastError(hr, "Getting username failed: %x", hr); } - WcaLog(LOGMSG_STANDARD, "PowerToys task folder created."); - } + if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN)) + { + ExitWithLastError(hr, "Getting the user's domain failed: %x", hr); + } + wcscat_s(username_domain, L"\\"); + wcscat_s(username_domain, username); - // If the same task exists, remove it. - pTaskFolder->DeleteTask(_bstr_t(wstrTaskName.c_str()), 0); + WcaLog(LOGMSG_STANDARD, "Current user detected: %ls", username_domain); - // Create the task builder object to create the task. - hr = pService->NewTask(0, &pTask); - ExitOnFailure(hr, "Failed to create a task definition: %x", hr); + // Task Name. + wstrTaskName = L"Autorun for "; + wstrTaskName += username; - // ------------------------------------------------------ - // Get the registration info for setting the identification. - hr = pTask->get_RegistrationInfo(&pRegInfo); - ExitOnFailure(hr, "Cannot get identification pointer: %x", hr); - hr = pRegInfo->put_Author(_bstr_t(username_domain)); - ExitOnFailure(hr, "Cannot put identification info: %x", hr); + // Get the executable path passed to the custom action. + LPWSTR wszExecutablePath = NULL; + hr = WcaGetProperty(L"CustomActionData", &wszExecutablePath); + ExitOnFailure(hr, "Failed to get the executable path from CustomActionData."); - // ------------------------------------------------------ - // Create the settings for the task - hr = pTask->get_Settings(&pSettings); - ExitOnFailure(hr, "Cannot get settings pointer: %x", hr); + // COM and Security Initialization is expected to have been done by the MSI. + // It couldn't be done in the DLL, anyway. + // ------------------------------------------------------ + // Create an instance of the Task Service. + hr = CoCreateInstance(CLSID_TaskScheduler, + NULL, + CLSCTX_INPROC_SERVER, + IID_ITaskService, + (void**)&pService); + ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr); - hr = pSettings->put_StartWhenAvailable(VARIANT_FALSE); - ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: %x", hr); - hr = pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE); - ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: %x", hr); - hr = pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S")); //Unlimited - ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: %x", hr); - hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE); - ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: %x", hr); + // Connect to the task service. + hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); + ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr); - // ------------------------------------------------------ - // Get the trigger collection to insert the logon trigger. - hr = pTask->get_Triggers(&pTriggerCollection); - ExitOnFailure(hr, "Cannot get trigger collection: %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)) + { + // Folder doesn't exist. Get the Root folder and create the PowerToys subfolder. + 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)) + { + pRootFolder->Release(); + ExitOnFailure(hr, "Cannot create PowerToys task folder: %x", hr); + } + WcaLog(LOGMSG_STANDARD, "PowerToys task folder created."); + } - // Add the logon trigger to the task. - ITrigger *pTrigger = NULL; - hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger); - ExitOnFailure(hr, "Cannot create the trigger: %x", hr); + // If the same task exists, remove it. + pTaskFolder->DeleteTask(_bstr_t(wstrTaskName.c_str()), 0); - ILogonTrigger *pLogonTrigger = NULL; - hr = pTrigger->QueryInterface( - IID_ILogonTrigger, (void**)&pLogonTrigger); - pTrigger->Release(); - ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: %x", hr); + // Create the task builder object to create the task. + hr = pService->NewTask(0, &pTask); + ExitOnFailure(hr, "Failed to create a task definition: %x", hr); - hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1")); - if (FAILED(hr)) { - WcaLogError(hr, "Cannot put the trigger ID: %x", hr); - } + // ------------------------------------------------------ + // Get the registration info for setting the identification. + hr = pTask->get_RegistrationInfo(&pRegInfo); + ExitOnFailure(hr, "Cannot get identification pointer: %x", hr); + hr = pRegInfo->put_Author(_bstr_t(username_domain)); + ExitOnFailure(hr, "Cannot put identification info: %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)) { - WcaLogError(hr, "Cannot put the trigger delay: %x", hr); - } + // ------------------------------------------------------ + // Create the settings for the task + hr = pTask->get_Settings(&pSettings); + ExitOnFailure(hr, "Cannot get settings pointer: %x", hr); - // Define the user. The task will execute when the user logs on. - // The specified user must be a user on this computer. - hr = pLogonTrigger->put_UserId(_bstr_t(username_domain)); - pLogonTrigger->Release(); - ExitOnFailure(hr, "Cannot add user ID to logon trigger: %x", hr); + hr = pSettings->put_StartWhenAvailable(VARIANT_FALSE); + ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: %x", hr); + hr = pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE); + ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: %x", hr); + hr = pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S")); //Unlimited + ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: %x", hr); + hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE); + ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: %x", hr); - // ------------------------------------------------------ - // Add an Action to the task. This task will execute the path passed to this custom action. - IActionCollection *pActionCollection = NULL; + // ------------------------------------------------------ + // Get the trigger collection to insert the logon trigger. + hr = pTask->get_Triggers(&pTriggerCollection); + ExitOnFailure(hr, "Cannot get trigger collection: %x", hr); - // Get the task action collection pointer. - hr = pTask->get_Actions(&pActionCollection); - ExitOnFailure(hr, "Cannot get Task collection pointer: %x", hr); + // Add the logon trigger to the task. + ITrigger* pTrigger = NULL; + hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger); + ExitOnFailure(hr, "Cannot create the trigger: %x", hr); - // Create the action, specifying that it is an executable action. - IAction *pAction = NULL; - hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction); - pActionCollection->Release(); - ExitOnFailure(hr, "Cannot create the action: %x", hr); + ILogonTrigger* pLogonTrigger = NULL; + hr = pTrigger->QueryInterface( + IID_ILogonTrigger, (void**)&pLogonTrigger); + pTrigger->Release(); + ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: %x", hr); - IExecAction *pExecAction = NULL; - // QI for the executable task pointer. - hr = pAction->QueryInterface( - IID_IExecAction, (void**)&pExecAction); - pAction->Release(); - ExitOnFailure(hr, "QueryInterface call failed for IExecAction: %x", hr); + hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1")); + if (FAILED(hr)) + { + WcaLogError(hr, "Cannot put the trigger ID: %x", hr); + } - // Set the path of the executable to PowerToys (passed as CustomActionData). - hr = pExecAction->put_Path(_bstr_t(wszExecutablePath)); - pExecAction->Release(); - ExitOnFailure(hr, "Cannot set path of executable: %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)) + { + WcaLogError(hr, "Cannot put the trigger delay: %x", hr); + } - // ------------------------------------------------------ - // Create the principal for the task - IPrincipal *pPrincipal = NULL; - hr = pTask->get_Principal(&pPrincipal); - ExitOnFailure(hr, "Cannot get principal pointer: %x", hr); + // Define the user. The task will execute when the user logs on. + // The specified user must be a user on this computer. + hr = pLogonTrigger->put_UserId(_bstr_t(username_domain)); + pLogonTrigger->Release(); + ExitOnFailure(hr, "Cannot add user ID to logon trigger: %x", hr); - // Set up principal information: - hr = pPrincipal->put_Id(_bstr_t(L"Principal1")); - if (FAILED(hr)) { - WcaLogError(hr, "Cannot put the principal ID: %x", hr); - } + // ------------------------------------------------------ + // Add an Action to the task. This task will execute the path passed to this custom action. + IActionCollection* pActionCollection = NULL; - hr = pPrincipal->put_UserId(_bstr_t(username_domain)); - if (FAILED(hr)) { - WcaLogError(hr, "Cannot put principal user Id: %x", hr); - } + // Get the task action collection pointer. + hr = pTask->get_Actions(&pActionCollection); + ExitOnFailure(hr, "Cannot get Task collection pointer: %x", hr); - hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN); - if (FAILED(hr)) { - WcaLogError(hr, "Cannot put principal logon type: %x", hr); - } + // Create the action, specifying that it is an executable action. + IAction* pAction = NULL; + hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction); + pActionCollection->Release(); + ExitOnFailure(hr, "Cannot create the action: %x", hr); - // Run the task with the highest available privileges. - hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_LUA); - pPrincipal->Release(); - ExitOnFailure(hr, "Cannot put principal run level: %x", hr); + IExecAction* pExecAction = NULL; + // QI for the executable task pointer. + hr = pAction->QueryInterface( + IID_IExecAction, (void**)&pExecAction); + pAction->Release(); + ExitOnFailure(hr, "QueryInterface call failed for IExecAction: %x", hr); - // ------------------------------------------------------ - // Save the task in the PowerToys folder. - { - _variant_t SDDL_FULL_ACCESS_FOR_EVERYONE = L"D:(A;;FA;;;WD)"; - hr = pTaskFolder->RegisterTaskDefinition( - _bstr_t(wstrTaskName.c_str()), - pTask, - TASK_CREATE_OR_UPDATE, - _variant_t(username_domain), - _variant_t(), - TASK_LOGON_INTERACTIVE_TOKEN, - SDDL_FULL_ACCESS_FOR_EVERYONE, - &pRegisteredTask); - ExitOnFailure(hr, "Error saving the Task : %x", hr); - } + // Set the path of the executable to PowerToys (passed as CustomActionData). + hr = pExecAction->put_Path(_bstr_t(wszExecutablePath)); + pExecAction->Release(); + ExitOnFailure(hr, "Cannot set path of executable: %x", hr); - WcaLog(LOGMSG_STANDARD, "Scheduled task created for the current user."); + // ------------------------------------------------------ + // Create the principal for the task + 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)) + { + WcaLogError(hr, "Cannot put the principal ID: %x", hr); + } + + hr = pPrincipal->put_UserId(_bstr_t(username_domain)); + if (FAILED(hr)) + { + WcaLogError(hr, "Cannot put principal user Id: %x", hr); + } + + hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN); + if (FAILED(hr)) + { + WcaLogError(hr, "Cannot put principal logon type: %x", hr); + } + + // Run the task with the highest available privileges. + hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_LUA); + pPrincipal->Release(); + ExitOnFailure(hr, "Cannot put principal run level: %x", hr); + + // ------------------------------------------------------ + // Save the task in the PowerToys folder. + { + _variant_t SDDL_FULL_ACCESS_FOR_EVERYONE = L"D:(A;;FA;;;WD)"; + hr = pTaskFolder->RegisterTaskDefinition( + _bstr_t(wstrTaskName.c_str()), + pTask, + TASK_CREATE_OR_UPDATE, + _variant_t(username_domain), + _variant_t(), + TASK_LOGON_INTERACTIVE_TOKEN, + SDDL_FULL_ACCESS_FOR_EVERYONE, + &pRegisteredTask); + ExitOnFailure(hr, "Error saving the Task : %x", hr); + } + + WcaLog(LOGMSG_STANDARD, "Scheduled task created for the current user."); 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(); + 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 (!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); - } + 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); + } - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); } // 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) { - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; +UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; - ITaskService *pService = NULL; - ITaskFolder *pTaskFolder = NULL; - IRegisteredTaskCollection* pTaskCollection = NULL; + ITaskService* pService = NULL; + ITaskFolder* pTaskFolder = NULL; + IRegisteredTaskCollection* pTaskCollection = NULL; - hr = WcaInitialize(hInstall, "RemoveScheduledTasksCA"); - ExitOnFailure(hr, "Failed to initialize"); + hr = WcaInitialize(hInstall, "RemoveScheduledTasksCA"); + ExitOnFailure(hr, "Failed to initialize"); - WcaLog(LOGMSG_STANDARD, "Initialized."); + WcaLog(LOGMSG_STANDARD, "Initialized."); - // COM and Security Initialization is expected to have been done by the MSI. - // It couldn't be done in the DLL, anyway. - // ------------------------------------------------------ - // Create an instance of the Task Service. - hr = CoCreateInstance(CLSID_TaskScheduler, - NULL, - CLSCTX_INPROC_SERVER, - IID_ITaskService, - (void**)&pService); - ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr); + // COM and Security Initialization is expected to have been done by the MSI. + // It couldn't be done in the DLL, anyway. + // ------------------------------------------------------ + // Create an instance of the Task Service. + hr = CoCreateInstance(CLSID_TaskScheduler, + NULL, + CLSCTX_INPROC_SERVER, + IID_ITaskService, + (void**)&pService); + 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()); - ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr); + // Connect to the task service. + 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)) { - // 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; - ExitFunction(); - } - - // ------------------------------------------------------- - // Get the registered tasks in the folder. - hr = pTaskFolder->GetTasks(TASK_ENUM_HIDDEN, &pTaskCollection); - ExitOnFailure(hr, "Cannot get the registered tasks: %x", hr); - - LONG numTasks = 0; - hr = pTaskCollection->get_Count(&numTasks); - 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)) { - BSTR taskName = NULL; - hr = pRegisteredTask->get_Name(&taskName); - if (SUCCEEDED(hr)) { - hr = pTaskFolder->DeleteTask(taskName, NULL); - if (FAILED(hr)) { - WcaLogError(hr, "Cannot delete the '%S' task: %x", taskName, hr); - } - SysFreeString(taskName); - } else { - WcaLogError(hr, "Cannot get the registered task name: %x", hr); - } - pRegisteredTask->Release(); - } else { - WcaLogError(hr, "Cannot get the registered task item at index=%d: %x", i + 1, hr); + // ------------------------------------------------------ + // Get the PowerToys task folder. + hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder); + 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; + ExitFunction(); } - } - // ------------------------------------------------------ - // Get the pointer to the root task folder and delete the PowerToys subfolder. - 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); - pRootFolder->Release(); - ExitOnFailure(hr, "Cannot delete the PowerToys folder: %x", hr); + // ------------------------------------------------------- + // Get the registered tasks in the folder. + hr = pTaskFolder->GetTasks(TASK_ENUM_HIDDEN, &pTaskCollection); + ExitOnFailure(hr, "Cannot get the registered tasks: %x", hr); - WcaLog(LOGMSG_STANDARD, "Deleted the PowerToys Task Scheduler folder."); + LONG numTasks = 0; + hr = pTaskCollection->get_Count(&numTasks); + 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)) + { + BSTR taskName = NULL; + hr = pRegisteredTask->get_Name(&taskName); + if (SUCCEEDED(hr)) + { + hr = pTaskFolder->DeleteTask(taskName, NULL); + if (FAILED(hr)) + { + WcaLogError(hr, "Cannot delete the '%S' task: %x", taskName, hr); + } + SysFreeString(taskName); + } + else + { + WcaLogError(hr, "Cannot get the registered task name: %x", hr); + } + pRegisteredTask->Release(); + } + 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; + hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder); + ExitOnFailure(hr, "Cannot get Root Folder pointer: %x", hr); + hr = pRootFolder->DeleteFolder(_bstr_t(L"PowerToys"), NULL); + pRootFolder->Release(); + ExitOnFailure(hr, "Cannot delete the PowerToys folder: %x", hr); + + 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)) { - 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); - } + 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); + } - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); } -UINT __stdcall TelemetryLogInstallSuccessCA(MSIHANDLE hInstall) { - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; +UINT __stdcall TelemetryLogInstallSuccessCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; - hr = WcaInitialize(hInstall, "TelemetryLogInstallSuccessCA"); - ExitOnFailure(hr, "Failed to initialize"); + hr = WcaInitialize(hInstall, "TelemetryLogInstallSuccessCA"); + ExitOnFailure(hr, "Failed to initialize"); - TraceLoggingWrite( - g_hProvider, - "Install_Success", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); + TraceLoggingWrite( + g_hProvider, + "Install_Success", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); } -UINT __stdcall TelemetryLogInstallCancelCA(MSIHANDLE hInstall) { - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; +UINT __stdcall TelemetryLogInstallCancelCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; - hr = WcaInitialize(hInstall, "TelemetryLogInstallCancelCA"); - ExitOnFailure(hr, "Failed to initialize"); + hr = WcaInitialize(hInstall, "TelemetryLogInstallCancelCA"); + ExitOnFailure(hr, "Failed to initialize"); - TraceLoggingWrite( - g_hProvider, - "Install_Cancel", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); + TraceLoggingWrite( + g_hProvider, + "Install_Cancel", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); } -UINT __stdcall TelemetryLogInstallFailCA(MSIHANDLE hInstall) { - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; +UINT __stdcall TelemetryLogInstallFailCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; - hr = WcaInitialize(hInstall, "TelemetryLogInstallFailCA"); - ExitOnFailure(hr, "Failed to initialize"); + hr = WcaInitialize(hInstall, "TelemetryLogInstallFailCA"); + ExitOnFailure(hr, "Failed to initialize"); - TraceLoggingWrite( - g_hProvider, - "Install_Fail", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); + TraceLoggingWrite( + g_hProvider, + "Install_Fail", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); } -UINT __stdcall TelemetryLogUninstallSuccessCA(MSIHANDLE hInstall) { - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; +UINT __stdcall TelemetryLogUninstallSuccessCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; - hr = WcaInitialize(hInstall, "TelemetryLogUninstallSuccessCA"); - ExitOnFailure(hr, "Failed to initialize"); + hr = WcaInitialize(hInstall, "TelemetryLogUninstallSuccessCA"); + ExitOnFailure(hr, "Failed to initialize"); - TraceLoggingWrite( - g_hProvider, - "UnInstall_Success", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); + TraceLoggingWrite( + g_hProvider, + "UnInstall_Success", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); } -UINT __stdcall TelemetryLogUninstallCancelCA(MSIHANDLE hInstall) { - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; +UINT __stdcall TelemetryLogUninstallCancelCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; - hr = WcaInitialize(hInstall, "TelemetryLogUninstallCancelCA"); - ExitOnFailure(hr, "Failed to initialize"); + hr = WcaInitialize(hInstall, "TelemetryLogUninstallCancelCA"); + ExitOnFailure(hr, "Failed to initialize"); - TraceLoggingWrite( - g_hProvider, - "UnInstall_Cancel", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); + TraceLoggingWrite( + g_hProvider, + "UnInstall_Cancel", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); } -UINT __stdcall TelemetryLogUninstallFailCA(MSIHANDLE hInstall) { - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; +UINT __stdcall TelemetryLogUninstallFailCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; - hr = WcaInitialize(hInstall, "TelemetryLogUninstallFailCA"); - ExitOnFailure(hr, "Failed to initialize"); + hr = WcaInitialize(hInstall, "TelemetryLogUninstallFailCA"); + ExitOnFailure(hr, "Failed to initialize"); - TraceLoggingWrite( - g_hProvider, - "UnInstall_Fail", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); + TraceLoggingWrite( + g_hProvider, + "UnInstall_Fail", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); } -UINT __stdcall TelemetryLogRepairCancelCA(MSIHANDLE hInstall) { - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; +UINT __stdcall TelemetryLogRepairCancelCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; - hr = WcaInitialize(hInstall, "TelemetryLogRepairCancelCA"); - ExitOnFailure(hr, "Failed to initialize"); + hr = WcaInitialize(hInstall, "TelemetryLogRepairCancelCA"); + ExitOnFailure(hr, "Failed to initialize"); - TraceLoggingWrite( - g_hProvider, - "Repair_Cancel", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); + TraceLoggingWrite( + g_hProvider, + "Repair_Cancel", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); } -UINT __stdcall TelemetryLogRepairFailCA(MSIHANDLE hInstall) { - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; +UINT __stdcall TelemetryLogRepairFailCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; - hr = WcaInitialize(hInstall, "TelemetryLogRepairFailCA"); - ExitOnFailure(hr, "Failed to initialize"); + hr = WcaInitialize(hInstall, "TelemetryLogRepairFailCA"); + ExitOnFailure(hr, "Failed to initialize"); - TraceLoggingWrite( - g_hProvider, - "Repair_Fail", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); + TraceLoggingWrite( + g_hProvider, + "Repair_Fail", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); } // DllMain - Initialize and cleanup WiX custom action utils. -extern "C" BOOL WINAPI DllMain(__in HINSTANCE hInst, __in ULONG ulReason, __in LPVOID) { - switch (ulReason) { - case DLL_PROCESS_ATTACH: - WcaGlobalInitialize(hInst); - TraceLoggingRegister(g_hProvider); - break; +extern "C" BOOL WINAPI DllMain(__in HINSTANCE hInst, __in ULONG ulReason, __in LPVOID) +{ + switch (ulReason) + { + case DLL_PROCESS_ATTACH: + WcaGlobalInitialize(hInst); + TraceLoggingRegister(g_hProvider); + break; - case DLL_PROCESS_DETACH: - TraceLoggingUnregister(g_hProvider); - WcaGlobalFinalize(); - break; - } + case DLL_PROCESS_DETACH: + TraceLoggingUnregister(g_hProvider); + WcaGlobalFinalize(); + break; + } - return TRUE; + return TRUE; } From 86704efcec94ed8c3de84b502dd8677a1206bd0e Mon Sep 17 00:00:00 2001 From: Andrey Nekrasov Date: Mon, 13 Apr 2020 18:22:37 +0300 Subject: [PATCH 12/14] FancyZones: optimize elevation detection logic (#2103) --- src/common/common.cpp | 34 +++++++++++++---------- src/common/common.h | 4 +-- src/modules/fancyzones/lib/FancyZones.cpp | 4 +-- src/settings/main.cpp | 2 +- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/common/common.cpp b/src/common/common.cpp index 7e379b2976..c64c7178cb 100644 --- a/src/common/common.cpp +++ b/src/common/common.cpp @@ -364,27 +364,31 @@ WindowState get_window_state(HWND hwnd) return RESTORED; } -bool is_process_elevated() +bool is_process_elevated(const bool use_cached_value) { - HANDLE token = nullptr; - bool elevated = false; + auto detection_func = []() { + HANDLE token = nullptr; + bool elevated = false; - if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) - { - TOKEN_ELEVATION elevation; - DWORD size; - if (GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &size)) + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { - elevated = (elevation.TokenIsElevated != 0); + TOKEN_ELEVATION elevation; + DWORD size; + if (GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &size)) + { + elevated = (elevation.TokenIsElevated != 0); + } } - } - if (token) - { - CloseHandle(token); - } + if (token) + { + CloseHandle(token); + } - return elevated; + return elevated; + }; + static const bool cached_value = detection_func(); + return use_cached_value ? cached_value : detection_func(); } bool drop_elevated_privileges() diff --git a/src/common/common.h b/src/common/common.h index e99327a021..17cd475993 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -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& what); // Get the executable path or module name for modern apps diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index ce05da6464..e932f4a57e 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -867,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()) diff --git a/src/settings/main.cpp b/src/settings/main.cpp index 68411bd187..7f24e26b1f 100644 --- a/src/settings/main.cpp +++ b/src/settings/main.cpp @@ -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) { From d584dc5632ef9fb26538051b62bcb8b071a43745 Mon Sep 17 00:00:00 2001 From: Clint Rutkas Date: Mon, 13 Apr 2020 10:48:05 -0700 Subject: [PATCH 13/14] Update NOTICE.md --- NOTICE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NOTICE.md b/NOTICE.md index 19e326b54e..ee6bf9c456 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -73,7 +73,7 @@ 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. -### Window Walker License +### Beta Tadele's Window Walker License **Source**: https://github.com/betsegaw/windowwalker @@ -139,4 +139,4 @@ 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. \ No newline at end of file +SOFTWARE. From 87fb6fc3d1f5073729717a6b16b6f12b79cea280 Mon Sep 17 00:00:00 2001 From: PrzemyslawTusinski <61138537+PrzemyslawTusinski@users.noreply.github.com> Date: Tue, 14 Apr 2020 10:40:30 +0200 Subject: [PATCH 14/14] Added unit test for non-resizable window placement (#2017) --- .../tests/UnitTests/ZoneWindow.Spec.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp index 3460894f32..96cdf6365b 100644 --- a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp +++ b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp @@ -711,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); + } }; }