From 6534a2d62e3670ed51649cd0a9bbacebb755ee66 Mon Sep 17 00:00:00 2001 From: decodism Date: Tue, 7 Mar 2023 22:22:24 +0100 Subject: [PATCH] feat: add option to preview selected window (closes #967) --- alt-tab-macos.xcodeproj/project.pbxproj | 4 ++ docs/Contributors.md | 1 + resources/l10n/Localizable.strings | 3 ++ resources/l10n/ar.lproj/Localizable.strings | 3 ++ resources/l10n/bg.lproj/Localizable.strings | 3 ++ resources/l10n/bn.lproj/Localizable.strings | 3 ++ resources/l10n/ca.lproj/Localizable.strings | 3 ++ resources/l10n/cs.lproj/Localizable.strings | 3 ++ resources/l10n/da.lproj/Localizable.strings | 3 ++ resources/l10n/de.lproj/Localizable.strings | 3 ++ resources/l10n/el.lproj/Localizable.strings | 3 ++ resources/l10n/en.lproj/Localizable.strings | 3 ++ resources/l10n/es.lproj/Localizable.strings | 3 ++ resources/l10n/et.lproj/Localizable.strings | 3 ++ resources/l10n/fa.lproj/Localizable.strings | 3 ++ resources/l10n/fi.lproj/Localizable.strings | 3 ++ resources/l10n/fr.lproj/Localizable.strings | 3 ++ resources/l10n/gl.lproj/Localizable.strings | 3 ++ resources/l10n/he.lproj/Localizable.strings | 3 ++ resources/l10n/hi.lproj/Localizable.strings | 3 ++ resources/l10n/hu.lproj/Localizable.strings | 3 ++ resources/l10n/id.lproj/Localizable.strings | 3 ++ resources/l10n/it.lproj/Localizable.strings | 3 ++ resources/l10n/ja.lproj/Localizable.strings | 3 ++ resources/l10n/ko.lproj/Localizable.strings | 3 ++ resources/l10n/ku.lproj/Localizable.strings | 3 ++ resources/l10n/lb.lproj/Localizable.strings | 3 ++ resources/l10n/nl.lproj/Localizable.strings | 3 ++ resources/l10n/no.lproj/Localizable.strings | 3 ++ resources/l10n/pl.lproj/Localizable.strings | 3 ++ .../l10n/pt-BR.lproj/Localizable.strings | 3 ++ resources/l10n/pt.lproj/Localizable.strings | 3 ++ resources/l10n/ro.lproj/Localizable.strings | 3 ++ resources/l10n/ru.lproj/Localizable.strings | 3 ++ resources/l10n/sk.lproj/Localizable.strings | 3 ++ resources/l10n/sl.lproj/Localizable.strings | 3 ++ resources/l10n/sq.lproj/Localizable.strings | 3 ++ resources/l10n/sr.lproj/Localizable.strings | 3 ++ resources/l10n/sv.lproj/Localizable.strings | 3 ++ resources/l10n/tr.lproj/Localizable.strings | 3 ++ resources/l10n/uk.lproj/Localizable.strings | 3 ++ resources/l10n/vi.lproj/Localizable.strings | 3 ++ .../l10n/zh-CN.lproj/Localizable.strings | 3 ++ .../l10n/zh-TW.lproj/Localizable.strings | 3 ++ src/api-wrappers/CGWindowID.swift | 4 +- src/logic/Preferences.swift | 2 + src/logic/Window.swift | 18 +++++-- src/logic/Windows.swift | 28 +++++++++-- src/ui/App.swift | 4 ++ src/ui/main-window/PreviewPanel.swift | 47 +++++++++++++++++++ src/ui/main-window/ThumbnailView.swift | 2 +- src/ui/main-window/ThumbnailsView.swift | 2 +- .../tabs/AppearanceTab.swift | 1 + 53 files changed, 228 insertions(+), 11 deletions(-) create mode 100644 src/ui/main-window/PreviewPanel.swift diff --git a/alt-tab-macos.xcodeproj/project.pbxproj b/alt-tab-macos.xcodeproj/project.pbxproj index 59cc2a36..b4d57b8a 100644 --- a/alt-tab-macos.xcodeproj/project.pbxproj +++ b/alt-tab-macos.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 4807A6C623A9CD190052A53E /* SkyLight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4807A6C523A9CD190052A53E /* SkyLight.framework */; }; 48F3E16224EC0D8800A1C64B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BABDA79F8EF76E3ACDD5F /* Localizable.strings */; }; 76D02BB22BFE7C9E0056008D /* Pods_alt_tab_macos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0712B3BEA2B3780398C0999 /* Pods_alt_tab_macos.framework */; }; + AA974BA929B7D84C0099A29E /* PreviewPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA974BA829B7D84C0099A29E /* PreviewPanel.swift */; }; BF0C8052AE41B1B10E42BFCE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C875C983226CB16DBD90F /* InfoPlist.strings */; }; BF0C807D26E465F467B066F7 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C849EBA5A547912BD8BB9 /* Localizable.strings */; }; BF0C812C068CD751CE9BFB67 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C8D5993267A74D4875C1A /* Localizable.strings */; }; @@ -173,6 +174,7 @@ 481FE54624D2D387001032F1 /* alt-tab-macos-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "alt-tab-macos-Bridging-Header.h"; sourceTree = ""; }; 59DD4BE63D42EEFF1182BA7F /* Pods-alt-tab-macos.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-alt-tab-macos.release.xcconfig"; path = "Target Support Files/Pods-alt-tab-macos/Pods-alt-tab-macos.release.xcconfig"; sourceTree = ""; }; 672F94799CC7C90282AEB3EA /* Pods-alt-tab-macos.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-alt-tab-macos.debug.xcconfig"; path = "Target Support Files/Pods-alt-tab-macos/Pods-alt-tab-macos.debug.xcconfig"; sourceTree = ""; }; + AA974BA829B7D84C0099A29E /* PreviewPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewPanel.swift; sourceTree = ""; }; BF0C80A05C11C8ADC366EC4A /* lb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = lb; path = InfoPlist.strings; sourceTree = ""; }; BF0C8113492C0FFCB4454BC9 /* sl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = sl; path = Localizable.strings; sourceTree = ""; }; BF0C8118F91A00A04AD4DE26 /* bg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = bg; path = InfoPlist.strings; sourceTree = ""; }; @@ -994,6 +996,7 @@ D04BA1DF8CAB2FAB7FE9244B /* ThumbnailFontIconView.swift */, D04BA258B56193958D60978A /* ThumbnailView.swift */, D04BAA998119CAA8B70A2B67 /* ThumbnailsView.swift */, + AA974BA829B7D84C0099A29E /* PreviewPanel.swift */, ); path = "main-window"; sourceTree = ""; @@ -1618,6 +1621,7 @@ D04BA6187A91A847844B6ABB /* Window.swift in Sources */, D04BA737008AA2CD4E230A21 /* Application.swift in Sources */, D04BA2A6FF9DDDC5A1A68E36 /* Applications.swift in Sources */, + AA974BA929B7D84C0099A29E /* PreviewPanel.swift in Sources */, D04BA3CF766857381519B892 /* BackgroundWork.swift in Sources */, D04BA48B00B4211A465C7337 /* DebugProfile.swift in Sources */, D04BAB68B7B8D1B548BC3AD5 /* App.swift in Sources */, diff --git a/docs/Contributors.md b/docs/Contributors.md index bebdb929..bac2cc4f 100644 --- a/docs/Contributors.md +++ b/docs/Contributors.md @@ -180,3 +180,4 @@ They helped [localize the app](https://poeditor.com/join/project/8AOEZ0eAZE): * Yukai * yumechan * Yusuf Caliskan +* Ивайло diff --git a/resources/l10n/Localizable.strings b/resources/l10n/Localizable.strings index 9244c9c9..aa91b49a 100644 --- a/resources/l10n/Localizable.strings +++ b/resources/l10n/Localizable.strings @@ -232,6 +232,9 @@ /* Menubar option */ "Preferences…" = "Preferences…"; +/* No comment provided by engineer. */ +"Preview selected window:" = "Preview selected window:"; + /* No comment provided by engineer. */ "Quit" = "Quit"; diff --git a/resources/l10n/ar.lproj/Localizable.strings b/resources/l10n/ar.lproj/Localizable.strings index 8dd643cc..41ef0e3d 100644 --- a/resources/l10n/ar.lproj/Localizable.strings +++ b/resources/l10n/ar.lproj/Localizable.strings @@ -250,6 +250,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "التفضيلات…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "إغلاق"; diff --git a/resources/l10n/bg.lproj/Localizable.strings b/resources/l10n/bg.lproj/Localizable.strings index 0b4b3339..4b991026 100644 --- a/resources/l10n/bg.lproj/Localizable.strings +++ b/resources/l10n/bg.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Настройки..."; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Излез"; diff --git a/resources/l10n/bn.lproj/Localizable.strings b/resources/l10n/bn.lproj/Localizable.strings index 1b70a73c..2f80cf0f 100644 --- a/resources/l10n/bn.lproj/Localizable.strings +++ b/resources/l10n/bn.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "পছন্দ…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "প্রস্থান করুন"; diff --git a/resources/l10n/ca.lproj/Localizable.strings b/resources/l10n/ca.lproj/Localizable.strings index f4f3055c..c5f71de0 100644 --- a/resources/l10n/ca.lproj/Localizable.strings +++ b/resources/l10n/ca.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferències..."; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Sortir"; diff --git a/resources/l10n/cs.lproj/Localizable.strings b/resources/l10n/cs.lproj/Localizable.strings index 8fb66567..3c3f97af 100644 --- a/resources/l10n/cs.lproj/Localizable.strings +++ b/resources/l10n/cs.lproj/Localizable.strings @@ -253,6 +253,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Nastavení..."; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Zavřít"; diff --git a/resources/l10n/da.lproj/Localizable.strings b/resources/l10n/da.lproj/Localizable.strings index cc59604b..ea3d550e 100644 --- a/resources/l10n/da.lproj/Localizable.strings +++ b/resources/l10n/da.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferences…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Quit"; diff --git a/resources/l10n/de.lproj/Localizable.strings b/resources/l10n/de.lproj/Localizable.strings index 961269fe..3d70cb04 100644 --- a/resources/l10n/de.lproj/Localizable.strings +++ b/resources/l10n/de.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Einstellungen…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Beenden"; diff --git a/resources/l10n/el.lproj/Localizable.strings b/resources/l10n/el.lproj/Localizable.strings index bae1399e..dfd1b688 100644 --- a/resources/l10n/el.lproj/Localizable.strings +++ b/resources/l10n/el.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Προτιμήσεις..."; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Εγκατάλειψη"; diff --git a/resources/l10n/en.lproj/Localizable.strings b/resources/l10n/en.lproj/Localizable.strings index 85a1c8cf..c5a7338d 100644 --- a/resources/l10n/en.lproj/Localizable.strings +++ b/resources/l10n/en.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferences…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Quit"; diff --git a/resources/l10n/es.lproj/Localizable.strings b/resources/l10n/es.lproj/Localizable.strings index 86e90b09..b47c4bfa 100644 --- a/resources/l10n/es.lproj/Localizable.strings +++ b/resources/l10n/es.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferencias…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Salir"; diff --git a/resources/l10n/et.lproj/Localizable.strings b/resources/l10n/et.lproj/Localizable.strings index 93f90be5..3d6c52a5 100644 --- a/resources/l10n/et.lproj/Localizable.strings +++ b/resources/l10n/et.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferences…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Quit"; diff --git a/resources/l10n/fa.lproj/Localizable.strings b/resources/l10n/fa.lproj/Localizable.strings index 559b6b39..a2f371c1 100644 --- a/resources/l10n/fa.lproj/Localizable.strings +++ b/resources/l10n/fa.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "ترجیحات..."; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Quit"; diff --git a/resources/l10n/fi.lproj/Localizable.strings b/resources/l10n/fi.lproj/Localizable.strings index e13b26ee..2bfff190 100644 --- a/resources/l10n/fi.lproj/Localizable.strings +++ b/resources/l10n/fi.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Asetukset…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Lopeta"; diff --git a/resources/l10n/fr.lproj/Localizable.strings b/resources/l10n/fr.lproj/Localizable.strings index 154f4207..e6c37e46 100644 --- a/resources/l10n/fr.lproj/Localizable.strings +++ b/resources/l10n/fr.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Préférences…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Quitter"; diff --git a/resources/l10n/gl.lproj/Localizable.strings b/resources/l10n/gl.lproj/Localizable.strings index e13d1e1b..ac68ec0a 100644 --- a/resources/l10n/gl.lproj/Localizable.strings +++ b/resources/l10n/gl.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferencias..."; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Saír"; diff --git a/resources/l10n/he.lproj/Localizable.strings b/resources/l10n/he.lproj/Localizable.strings index 71e96bb3..3b7bb716 100644 --- a/resources/l10n/he.lproj/Localizable.strings +++ b/resources/l10n/he.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "העדפות"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "צא"; diff --git a/resources/l10n/hi.lproj/Localizable.strings b/resources/l10n/hi.lproj/Localizable.strings index d6eed3d6..043033bc 100644 --- a/resources/l10n/hi.lproj/Localizable.strings +++ b/resources/l10n/hi.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "पसंद"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "बंद करो"; diff --git a/resources/l10n/hu.lproj/Localizable.strings b/resources/l10n/hu.lproj/Localizable.strings index 212703e1..480b780a 100644 --- a/resources/l10n/hu.lproj/Localizable.strings +++ b/resources/l10n/hu.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Beállítások…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Kilépés"; diff --git a/resources/l10n/id.lproj/Localizable.strings b/resources/l10n/id.lproj/Localizable.strings index 98a90d64..b8c136d6 100644 --- a/resources/l10n/id.lproj/Localizable.strings +++ b/resources/l10n/id.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferensi…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Keluar"; diff --git a/resources/l10n/it.lproj/Localizable.strings b/resources/l10n/it.lproj/Localizable.strings index 76144979..1fe53f15 100644 --- a/resources/l10n/it.lproj/Localizable.strings +++ b/resources/l10n/it.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferenze…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Esci"; diff --git a/resources/l10n/ja.lproj/Localizable.strings b/resources/l10n/ja.lproj/Localizable.strings index 052735f0..a952d554 100644 --- a/resources/l10n/ja.lproj/Localizable.strings +++ b/resources/l10n/ja.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "環境設定…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "終了"; diff --git a/resources/l10n/ko.lproj/Localizable.strings b/resources/l10n/ko.lproj/Localizable.strings index 9a502552..03224743 100644 --- a/resources/l10n/ko.lproj/Localizable.strings +++ b/resources/l10n/ko.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "설정…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "종료"; diff --git a/resources/l10n/ku.lproj/Localizable.strings b/resources/l10n/ku.lproj/Localizable.strings index d39544de..fbf69772 100644 --- a/resources/l10n/ku.lproj/Localizable.strings +++ b/resources/l10n/ku.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Taybetmendî"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Jêderkeve"; diff --git a/resources/l10n/lb.lproj/Localizable.strings b/resources/l10n/lb.lproj/Localizable.strings index 7435f550..047c32d1 100644 --- a/resources/l10n/lb.lproj/Localizable.strings +++ b/resources/l10n/lb.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Astellung…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Quit"; diff --git a/resources/l10n/nl.lproj/Localizable.strings b/resources/l10n/nl.lproj/Localizable.strings index f5629ab4..2fe005bf 100644 --- a/resources/l10n/nl.lproj/Localizable.strings +++ b/resources/l10n/nl.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Voorkeuren…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Stop"; diff --git a/resources/l10n/no.lproj/Localizable.strings b/resources/l10n/no.lproj/Localizable.strings index 20f58c9a..6ddecfb0 100644 --- a/resources/l10n/no.lproj/Localizable.strings +++ b/resources/l10n/no.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Valg…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Avslutt"; diff --git a/resources/l10n/pl.lproj/Localizable.strings b/resources/l10n/pl.lproj/Localizable.strings index 65524590..68a23341 100644 --- a/resources/l10n/pl.lproj/Localizable.strings +++ b/resources/l10n/pl.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferencje…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Wyjdź"; diff --git a/resources/l10n/pt-BR.lproj/Localizable.strings b/resources/l10n/pt-BR.lproj/Localizable.strings index 7b405055..2e05bc45 100644 --- a/resources/l10n/pt-BR.lproj/Localizable.strings +++ b/resources/l10n/pt-BR.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferências…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Encerrar"; diff --git a/resources/l10n/pt.lproj/Localizable.strings b/resources/l10n/pt.lproj/Localizable.strings index 29fc3beb..608f7324 100644 --- a/resources/l10n/pt.lproj/Localizable.strings +++ b/resources/l10n/pt.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferências…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Sair"; diff --git a/resources/l10n/ro.lproj/Localizable.strings b/resources/l10n/ro.lproj/Localizable.strings index 98106da1..b5483ce5 100644 --- a/resources/l10n/ro.lproj/Localizable.strings +++ b/resources/l10n/ro.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferințe…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Ieșire"; diff --git a/resources/l10n/ru.lproj/Localizable.strings b/resources/l10n/ru.lproj/Localizable.strings index e5e95d19..ebd8b6ad 100644 --- a/resources/l10n/ru.lproj/Localizable.strings +++ b/resources/l10n/ru.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Настройки…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Выход"; diff --git a/resources/l10n/sk.lproj/Localizable.strings b/resources/l10n/sk.lproj/Localizable.strings index c6b3a520..07171131 100644 --- a/resources/l10n/sk.lproj/Localizable.strings +++ b/resources/l10n/sk.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Nastavenia…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Ukončiť"; diff --git a/resources/l10n/sl.lproj/Localizable.strings b/resources/l10n/sl.lproj/Localizable.strings index 3f936958..4503fb01 100644 --- a/resources/l10n/sl.lproj/Localizable.strings +++ b/resources/l10n/sl.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Nastavitve…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Quit"; diff --git a/resources/l10n/sq.lproj/Localizable.strings b/resources/l10n/sq.lproj/Localizable.strings index cc845a25..e6996b79 100644 --- a/resources/l10n/sq.lproj/Localizable.strings +++ b/resources/l10n/sq.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Preferencat"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Dil"; diff --git a/resources/l10n/sr.lproj/Localizable.strings b/resources/l10n/sr.lproj/Localizable.strings index c7909f40..33b3614a 100644 --- a/resources/l10n/sr.lproj/Localizable.strings +++ b/resources/l10n/sr.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Podešavanja…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Zatvori"; diff --git a/resources/l10n/sv.lproj/Localizable.strings b/resources/l10n/sv.lproj/Localizable.strings index 3608f0d5..23b31063 100644 --- a/resources/l10n/sv.lproj/Localizable.strings +++ b/resources/l10n/sv.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Inställningar..."; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Avsluta"; diff --git a/resources/l10n/tr.lproj/Localizable.strings b/resources/l10n/tr.lproj/Localizable.strings index ff21121e..4c807188 100644 --- a/resources/l10n/tr.lproj/Localizable.strings +++ b/resources/l10n/tr.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Tercihler…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Çıkış"; diff --git a/resources/l10n/uk.lproj/Localizable.strings b/resources/l10n/uk.lproj/Localizable.strings index 7eba71db..ae83aca7 100644 --- a/resources/l10n/uk.lproj/Localizable.strings +++ b/resources/l10n/uk.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Налаштування..."; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Вийти"; diff --git a/resources/l10n/vi.lproj/Localizable.strings b/resources/l10n/vi.lproj/Localizable.strings index 9d354a90..64423e3d 100644 --- a/resources/l10n/vi.lproj/Localizable.strings +++ b/resources/l10n/vi.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "Tuỳ chỉnh"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "Thoát"; diff --git a/resources/l10n/zh-CN.lproj/Localizable.strings b/resources/l10n/zh-CN.lproj/Localizable.strings index 867f822e..9b3da315 100644 --- a/resources/l10n/zh-CN.lproj/Localizable.strings +++ b/resources/l10n/zh-CN.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "偏好设置…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "退出"; diff --git a/resources/l10n/zh-TW.lproj/Localizable.strings b/resources/l10n/zh-TW.lproj/Localizable.strings index 783b5fb2..6c0ec5fd 100644 --- a/resources/l10n/zh-TW.lproj/Localizable.strings +++ b/resources/l10n/zh-TW.lproj/Localizable.strings @@ -248,6 +248,9 @@ /*No comment provided by engineer.*/ "Preferences…" = "偏好設定…"; +/*No comment provided by engineer.*/ +"Preview selected window:" = "Preview selected window:"; + /*No comment provided by engineer.*/ "Quit" = "離開"; diff --git a/src/api-wrappers/CGWindowID.swift b/src/api-wrappers/CGWindowID.swift index 14faf0dc..2ae09a35 100644 --- a/src/api-wrappers/CGWindowID.swift +++ b/src/api-wrappers/CGWindowID.swift @@ -19,10 +19,10 @@ extension CGWindowID { return CGSCopySpacesForWindows(cgsMainConnectionId, CGSSpaceMask.all.rawValue, [self] as CFArray) as! [CGSSpaceID] } - func screenshot() -> CGImage? { + func screenshot(_ bestResolution: Bool = false) -> CGImage? { // CGSHWCaptureWindowList var windowId_ = self - let list = CGSHWCaptureWindowList(cgsMainConnectionId, &windowId_, 1, [.ignoreGlobalClipShape, .nominalResolution]).takeRetainedValue() as! [CGImage] + let list = CGSHWCaptureWindowList(cgsMainConnectionId, &windowId_, 1, [.ignoreGlobalClipShape, bestResolution ? .bestResolution : .nominalResolution]).takeRetainedValue() as! [CGImage] return list.first // // CGWindowListCreateImage diff --git a/src/logic/Preferences.swift b/src/logic/Preferences.swift index 39badecd..36be926d 100644 --- a/src/logic/Preferences.swift +++ b/src/logic/Preferences.swift @@ -87,6 +87,7 @@ class Preferences { "hideAppBadges": "false", "hideWindowlessApps": "false", "hideThumbnails": "false", + "previewFocusedWindow": "false", ] // system preferences @@ -130,6 +131,7 @@ class Preferences { static var hideThumbnails: Bool { defaults.bool("hideThumbnails") } static var startAtLogin: Bool { defaults.bool("startAtLogin") } static var blacklist: [BlacklistEntry] { jsonDecode([BlacklistEntry].self, defaults.string("blacklist")) } + static var previewFocusedWindow: Bool { defaults.bool("previewFocusedWindow") } // macro values static var theme: ThemePreference { defaults.macroPref("theme", ThemePreference.allCases) } diff --git a/src/logic/Window.swift b/src/logic/Window.swift index f300301a..5a6668e5 100644 --- a/src/logic/Window.swift +++ b/src/logic/Window.swift @@ -93,12 +93,24 @@ class Window { } CFRunLoopAddSource(BackgroundWork.accessibilityEventsThread.runLoop, AXObserverGetRunLoopSource(axObserver), .defaultMode) } + + private func screenshot(_ bestResolution: Bool = false) -> NSImage? { + guard !isWindowlessApp, let cgWindowId = cgWindowId, cgWindowId != -1, let cgImage = cgWindowId.screenshot(bestResolution) else { + return nil + } + return NSImage(cgImage: cgImage, size: NSSize(width: cgImage.width, height: cgImage.height)) + } func refreshThumbnail() { - if !isWindowlessApp, let cgWindowId = cgWindowId, cgWindowId != -1, let cgImage = cgWindowId.screenshot() { - thumbnail = NSImage(cgImage: cgImage, size: NSSize(width: cgImage.width, height: cgImage.height)) - thumbnailFullSize = thumbnail!.size + guard let screenshot = screenshot() else { + return } + thumbnail = screenshot + thumbnailFullSize = thumbnail!.size + } + + func getPreview() -> NSImage? { + return screenshot(true) } func canBeClosed() -> Bool { diff --git a/src/logic/Windows.swift b/src/logic/Windows.swift index 0675658d..a95246a1 100644 --- a/src/logic/Windows.swift +++ b/src/logic/Windows.swift @@ -36,11 +36,11 @@ class Windows { if let app = Applications.find(NSWorkspace.shared.frontmostApplication?.processIdentifier), app.focusedWindow == nil, let lastFocusedWindowIndex = getLastFocusedWindowIndex() { - updateHoveredAndFocusedWindowIndexes(lastFocusedWindowIndex) + updateFocusedAndHoveredWindowIndex(lastFocusedWindowIndex) } else { cycleFocusedWindowIndex(1) if focusedWindowIndex == 0 { - updateHoveredAndFocusedWindowIndexes(0) + updateFocusedAndHoveredWindowIndex(0) } } } @@ -99,7 +99,7 @@ class Windows { return nil } - static func updateHoveredAndFocusedWindowIndexes(_ newIndex: Int, _ fromMouse: Bool = false) { + static func updateFocusedAndHoveredWindowIndex(_ newIndex: Int, _ fromMouse: Bool = false) { var index: Int? if fromMouse && newIndex != hoveredWindowIndex { let oldIndex = hoveredWindowIndex @@ -113,6 +113,7 @@ class Windows { let oldIndex = focusedWindowIndex focusedWindowIndex = newIndex ThumbnailsView.highlight(oldIndex) + previewFocusedWindowIfNeeded() index = focusedWindowIndex } guard let index = index else { return } @@ -121,6 +122,25 @@ class Windows { App.app.thumbnailsPanel.thumbnailsView.scrollView.contentView.scrollToVisible(focusedView.frame) voiceOverWindow(index) } + + static func previewFocusedWindowIfNeeded() { + guard + Preferences.previewFocusedWindow, + App.app.appIsBeingUsed && App.app.thumbnailsPanel.isKeyWindow, + let window = focusedWindow(), + let preview = window.getPreview(), + let position = window.position, + let size = window.size + else { + App.app.previewPanel.orderOut(nil) + return + } + App.app.previewPanel.setPreview(preview) + var frame = NSRect(origin: position, size: size) + frame.origin.y = NSScreen.screens[0].frame.maxY - frame.maxY + App.app.previewPanel.setFrame(frame, display: false) + App.app.previewPanel.order(.below, relativeTo: App.app.thumbnailsPanel.windowNumber) + } static func voiceOverWindow(_ windowIndex: Int = focusedWindowIndex) { guard App.app.appIsBeingUsed && App.app.thumbnailsPanel.isKeyWindow else { return } @@ -144,7 +164,7 @@ class Windows { (KeyRepeatTimer.isARepeat || KeyRepeatTimer.timer?.isValid ?? false) { return } - updateHoveredAndFocusedWindowIndexes(nextIndex) + updateFocusedAndHoveredWindowIndex(nextIndex) } static func windowIndexAfterCycling(_ step: Int) -> Int { diff --git a/src/ui/App.swift b/src/ui/App.swift index 676a9b5c..8c950c1c 100644 --- a/src/ui/App.swift +++ b/src/ui/App.swift @@ -17,6 +17,7 @@ class App: AppCenterApplication, NSApplicationDelegate { static let repository = "https://github.com/lwouis/alt-tab-macos" static var app: App! var thumbnailsPanel: ThumbnailsPanel! + var previewPanel: PreviewPanel! var preferencesWindow: PreferencesWindow! var feedbackWindow: FeedbackWindow! var isFirstSummon = true @@ -55,6 +56,7 @@ class App: AppCenterApplication, NSApplicationDelegate { Menubar.initialize() self.loadMainMenuXib() self.thumbnailsPanel = ThumbnailsPanel() + self.previewPanel = PreviewPanel() Spaces.initialDiscovery() Applications.initialDiscovery() self.preferencesWindow = PreferencesWindow() @@ -113,6 +115,7 @@ class App: AppCenterApplication, NSApplicationDelegate { isFirstSummon = true MouseEvents.toggle(false) hideThumbnailPanelWithoutChangingKeyWindow() + previewPanel.orderOut(nil) hideAllTooltips() } @@ -295,6 +298,7 @@ class App: AppCenterApplication, NSApplicationDelegate { refreshOpenUi() guard appIsBeingUsed else { return } thumbnailsPanel.show() + Windows.previewFocusedWindowIfNeeded() guard appIsBeingUsed else { return } Windows.refreshThumbnailsAsync(screen) guard appIsBeingUsed else { return } diff --git a/src/ui/main-window/PreviewPanel.swift b/src/ui/main-window/PreviewPanel.swift new file mode 100644 index 00000000..ee13d386 --- /dev/null +++ b/src/ui/main-window/PreviewPanel.swift @@ -0,0 +1,47 @@ +import Cocoa + +class PreviewPanel: NSPanel { + private let previewView = NSImageView() + private let borderView = BorderView() + + convenience init() { + self.init(contentRect: .zero, styleMask: [.nonactivatingPanel, .titled, .fullSizeContentView], backing: .buffered, defer: false) + isFloatingPanel = true + animationBehavior = .none + hidesOnDeactivate = false + titleVisibility = .hidden + titlebarAppearsTransparent = true + backgroundColor = .clear + contentView = previewView + borderView.autoresizingMask = [.width, .height] + previewView.addSubview(borderView) + // triggering AltTab before or during Space transition animation brings the window on the Space post-transition + collectionBehavior = .canJoinAllSpaces + // 2nd highest level possible; this allows the app to go on top of context menus + // highest level is .screenSaver but makes drag and drop on top the main window impossible + level = .popUpMenu + // helps filter out this window from the thumbnails + setAccessibilitySubrole(.unknown) + } + + func setPreview(_ preview: NSImage) { + previewView.image = preview + } +} + +private class BorderView: NSView { + override func draw(_ dirtyRect: NSRect) { + let path = NSBezierPath(rect: bounds) + path.append(NSBezierPath(roundedRect: bounds.insetBy(dx: 5, dy: 5), xRadius: 5, yRadius: 5).reversed) + systemAccentColor().withAlphaComponent(0.5).setFill() + path.fill() + } +} + +func systemAccentColor() -> NSColor { + if #available(OSX 10.14, *) { + // dynamically adapts to changes in System Default; no need to listen to notifications + return NSColor.controlAccentColor + } + return NSColor(srgbRed: 0, green: 0.47843137254901963, blue: 1, alpha: 1) +} diff --git a/src/ui/main-window/ThumbnailView.swift b/src/ui/main-window/ThumbnailView.swift index 3d2a4848..2d3d9209 100644 --- a/src/ui/main-window/ThumbnailView.swift +++ b/src/ui/main-window/ThumbnailView.swift @@ -187,7 +187,7 @@ class ThumbnailView: NSStackView { windowlessIcon.needsDisplay = true } self.mouseUpCallback = { () -> Void in App.app.focusSelectedWindow(element) } - self.mouseMovedCallback = { () -> Void in Windows.updateHoveredAndFocusedWindowIndexes(index, true) } + self.mouseMovedCallback = { () -> Void in Windows.updateFocusedAndHoveredWindowIndex(index, true) } [quitIcon, closeIcon, minimizeIcon, maximizeIcon].forEach { $0.window_ = element } showOrHideWindowControls(false) // force a display to avoid flickering; see https://github.com/lwouis/alt-tab-macos/issues/197 diff --git a/src/ui/main-window/ThumbnailsView.swift b/src/ui/main-window/ThumbnailsView.swift index ac2355c7..2d51a18f 100644 --- a/src/ui/main-window/ThumbnailsView.swift +++ b/src/ui/main-window/ThumbnailsView.swift @@ -71,7 +71,7 @@ class ThumbnailsView: NSVisualEffectView { return leadingSide ? NSMinX($0.frame) < originCenter : NSMaxX($0.frame) > originCenter } ?? iterable.last! let targetIndex = ThumbnailsView.recycledViews.firstIndex(of: targetView)! - Windows.updateHoveredAndFocusedWindowIndexes(targetIndex) + Windows.updateFocusedAndHoveredWindowIndex(targetIndex) } } diff --git a/src/ui/preferences-window/tabs/AppearanceTab.swift b/src/ui/preferences-window/tabs/AppearanceTab.swift index 3c92753e..aafc1122 100644 --- a/src/ui/preferences-window/tabs/AppearanceTab.swift +++ b/src/ui/preferences-window/tabs/AppearanceTab.swift @@ -31,6 +31,7 @@ class AppearanceTab { LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide colored circles on mouse hover:", comment: ""), "hideColoredCircles"), LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide app badges:", comment: ""), "hideAppBadges"), LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide apps with no open window:", comment: ""), "hideWindowlessApps"), + LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Preview selected window:", comment: ""), "previewFocusedWindow"), ]) grid.column(at: 0).xPlacement = .trailing grid.fit()