├── .github └── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_suggestion.yml ├── LICENSE ├── README.md ├── Resources ├── get-windows.swift ├── raise-window │ ├── raise-window.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ ├── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── xcuserdata │ │ │ │ └── vitor.xcuserdatad │ │ │ │ └── UserInterfaceState.xcuserstate │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ └── raise-window.xcscheme │ │ └── xcuserdata │ │ │ └── vitor.xcuserdatad │ │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── raise-window │ │ ├── main.swift │ │ └── raise-window-Bridging-Header.h └── request-recording.swift └── Workflow ├── get-windows ├── icon.png ├── images └── about │ └── win.png ├── info.plist ├── raise-window └── request-recording /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | body: 4 | - type: input 5 | attributes: 6 | label: Workflow version 7 | description: Open the Workflow in Alfred Preferences and find it at the top, near the description 8 | validations: 9 | required: true 10 | - type: input 11 | attributes: 12 | label: Alfred version 13 | description: In the top left corner of Alfred Preferences → General 14 | validations: 15 | required: true 16 | - type: input 17 | attributes: 18 | label: macOS version 19 | description: Click  on the menubar → About This Mac 20 | validations: 21 | required: true 22 | - type: textarea 23 | attributes: 24 | label: Debugger output 25 | description: Perform the failing action with [the debugger](https://www.alfredapp.com/help/workflows/advanced/debugger/) open 26 | render: alfred_debugger 27 | validations: 28 | required: true 29 | - type: textarea 30 | attributes: 31 | label: More details 32 | description: Explain what you did, what happened, and what you expected to happen 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_suggestion.yml: -------------------------------------------------------------------------------- 1 | name: Feature Suggestion 2 | description: Suggest a new feature 3 | body: 4 | - type: textarea 5 | attributes: 6 | label: Feature details 7 | description: Explain the feature idea 8 | validations: 9 | required: true 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Running with Crayons Ltd 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # icon Window Switcher Alfred Workflow 2 | 3 | Switch to a specific window of an app in the current Desktop Space 4 | 5 | [⤓ Install on the Alfred Gallery](https://alfred.app/workflows/alfredapp/window-switcher) 6 | 7 | ## Usage 8 | 9 | Search app windows in the current Desktop Space via the `win` keyword. 10 | 11 | ![Alfred search for win](Workflow/images/about/win.png) 12 | 13 | * ↩︎ Bring window to the front. 14 | * ↩︎ Quit app. 15 | 16 | Configure the [Hotkey](https://www.alfredapp.com/help/workflows/triggers/hotkey/) for faster triggering. 17 | -------------------------------------------------------------------------------- /Resources/get-windows.swift: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env swift 2 | 3 | import AppKit 4 | 5 | // Helpers 6 | struct ScriptFilterItem: Codable { 7 | let variables: [String: String] 8 | let title: String 9 | let subtitle: String 10 | let arg: [Int32] 11 | let icon: [String: String] 12 | let match: String 13 | } 14 | 15 | // Grab windows 16 | let windowList: CFArray? = CGWindowListCopyWindowInfo( 17 | [.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) 18 | 19 | guard let windows = windowList as? [[String: Any]] else { fatalError("Unable to get window list") } 20 | 21 | // Populate items 22 | let sfItems: [ScriptFilterItem] = windows.compactMap { dict in 23 | guard 24 | dict["kCGWindowLayer"] as? Int == 0, 25 | let appRawName = dict["kCGWindowOwnerName"] as? String, 26 | let appPID = dict["kCGWindowOwnerPID"] as? Int32, 27 | let windowID = dict["kCGWindowNumber"] as? Int32, 28 | let appPath = NSRunningApplication(processIdentifier: appPID)?.bundleURL?.path, 29 | let windowTitle = dict["kCGWindowName"] as? String, 30 | // When using Stage Manager, there are a lot of extra windows from Window Manager 31 | appRawName != "WindowManager", 32 | // Unnamed windows with a low height are generally safe to ignore 33 | // Examples include Safari's 20px status bar and a 68px invisible window present on full screen apps 34 | let windowBounds = dict["kCGWindowBounds"] as? [String: Int32], 35 | let windowHeight = windowBounds["Height"], 36 | !windowTitle.isEmpty || windowHeight > 70 37 | else { return nil } 38 | 39 | // Some apps (e.g. Reeder) have the ".app" extension in "kCGWindowOwnerName" 40 | let appName = URL(fileURLWithPath: appRawName).deletingPathExtension().lastPathComponent 41 | 42 | // Some apps (e.g. Reeder) have legitimate windows without a name 43 | let windowName = windowTitle.isEmpty ? appName : windowTitle 44 | 45 | return ScriptFilterItem( 46 | variables: ["app_name": appName], 47 | title: windowName, 48 | subtitle: appName, 49 | arg: [appPID, windowID], 50 | icon: ["type": "fileicon", "path": appPath], 51 | match: "\(windowName) \(appName)" 52 | ) 53 | } 54 | 55 | // Fallback if no valid items 56 | guard !sfItems.isEmpty else { 57 | let subtitle = CGPreflightScreenCaptureAccess() ? 58 | "Make sure there are unminimised windows in the current Desktop Space" : 59 | "Press ↩ to request Screen Recording permissions, necessary to get window information" 60 | 61 | let notFound = [ 62 | "title": "No Windows Found", 63 | "subtitle": subtitle, 64 | "arg": "request_permissions" 65 | ] 66 | 67 | let jsonData: Data = try JSONSerialization.data(withJSONObject: ["items": [notFound]]) 68 | let jsonString: String = String(data: jsonData, encoding: .utf8)! 69 | 70 | print(jsonString) 71 | exit(0) 72 | } 73 | 74 | // Output JSON 75 | let jsonData = try JSONEncoder().encode(["items": sfItems]) 76 | print(String(data: jsonData, encoding: .utf8)!) 77 | -------------------------------------------------------------------------------- /Resources/raise-window/raise-window.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4E88074D299AED81005D7098 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E88074C299AED81005D7098 /* main.swift */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 4E880747299AED81005D7098 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = /usr/share/man/man1/; 18 | dstSubfolderSpec = 0; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 1; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 4E880749299AED81005D7098 /* raise-window */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "raise-window"; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 4E88074C299AED81005D7098 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 28 | 4E880756299AEF6C005D7098 /* raise-window-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "raise-window-Bridging-Header.h"; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 4E880746299AED81005D7098 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 4E880740299AED81005D7098 = { 43 | isa = PBXGroup; 44 | children = ( 45 | 4E88074B299AED81005D7098 /* raise-window */, 46 | 4E88074A299AED81005D7098 /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | 4E88074A299AED81005D7098 /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | 4E880749299AED81005D7098 /* raise-window */, 54 | ); 55 | name = Products; 56 | sourceTree = ""; 57 | }; 58 | 4E88074B299AED81005D7098 /* raise-window */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 4E88074C299AED81005D7098 /* main.swift */, 62 | 4E880756299AEF6C005D7098 /* raise-window-Bridging-Header.h */, 63 | ); 64 | path = "raise-window"; 65 | sourceTree = ""; 66 | }; 67 | /* End PBXGroup section */ 68 | 69 | /* Begin PBXNativeTarget section */ 70 | 4E880748299AED81005D7098 /* raise-window */ = { 71 | isa = PBXNativeTarget; 72 | buildConfigurationList = 4E880750299AED81005D7098 /* Build configuration list for PBXNativeTarget "raise-window" */; 73 | buildPhases = ( 74 | 4E880745299AED81005D7098 /* Sources */, 75 | 4E880746299AED81005D7098 /* Frameworks */, 76 | 4E880747299AED81005D7098 /* CopyFiles */, 77 | ); 78 | buildRules = ( 79 | ); 80 | dependencies = ( 81 | ); 82 | name = "raise-window"; 83 | productName = "raise-window"; 84 | productReference = 4E880749299AED81005D7098 /* raise-window */; 85 | productType = "com.apple.product-type.tool"; 86 | }; 87 | /* End PBXNativeTarget section */ 88 | 89 | /* Begin PBXProject section */ 90 | 4E880741299AED81005D7098 /* Project object */ = { 91 | isa = PBXProject; 92 | attributes = { 93 | BuildIndependentTargetsInParallel = 1; 94 | LastSwiftUpdateCheck = 1420; 95 | LastUpgradeCheck = 1420; 96 | TargetAttributes = { 97 | 4E880748299AED81005D7098 = { 98 | CreatedOnToolsVersion = 14.2; 99 | }; 100 | }; 101 | }; 102 | buildConfigurationList = 4E880744299AED81005D7098 /* Build configuration list for PBXProject "raise-window" */; 103 | compatibilityVersion = "Xcode 14.0"; 104 | developmentRegion = en; 105 | hasScannedForEncodings = 0; 106 | knownRegions = ( 107 | en, 108 | Base, 109 | ); 110 | mainGroup = 4E880740299AED81005D7098; 111 | productRefGroup = 4E88074A299AED81005D7098 /* Products */; 112 | projectDirPath = ""; 113 | projectRoot = ""; 114 | targets = ( 115 | 4E880748299AED81005D7098 /* raise-window */, 116 | ); 117 | }; 118 | /* End PBXProject section */ 119 | 120 | /* Begin PBXSourcesBuildPhase section */ 121 | 4E880745299AED81005D7098 /* Sources */ = { 122 | isa = PBXSourcesBuildPhase; 123 | buildActionMask = 2147483647; 124 | files = ( 125 | 4E88074D299AED81005D7098 /* main.swift in Sources */, 126 | ); 127 | runOnlyForDeploymentPostprocessing = 0; 128 | }; 129 | /* End PBXSourcesBuildPhase section */ 130 | 131 | /* Begin XCBuildConfiguration section */ 132 | 4E88074E299AED81005D7098 /* Debug */ = { 133 | isa = XCBuildConfiguration; 134 | buildSettings = { 135 | ALWAYS_SEARCH_USER_PATHS = NO; 136 | CLANG_ANALYZER_NONNULL = YES; 137 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 138 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 139 | CLANG_ENABLE_MODULES = YES; 140 | CLANG_ENABLE_OBJC_ARC = YES; 141 | CLANG_ENABLE_OBJC_WEAK = YES; 142 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 143 | CLANG_WARN_BOOL_CONVERSION = YES; 144 | CLANG_WARN_COMMA = YES; 145 | CLANG_WARN_CONSTANT_CONVERSION = YES; 146 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 147 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 148 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 149 | CLANG_WARN_EMPTY_BODY = YES; 150 | CLANG_WARN_ENUM_CONVERSION = YES; 151 | CLANG_WARN_INFINITE_RECURSION = YES; 152 | CLANG_WARN_INT_CONVERSION = YES; 153 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 154 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 155 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 156 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 157 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 158 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 159 | CLANG_WARN_STRICT_PROTOTYPES = YES; 160 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 161 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 162 | CLANG_WARN_UNREACHABLE_CODE = YES; 163 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 164 | COPY_PHASE_STRIP = NO; 165 | DEBUG_INFORMATION_FORMAT = dwarf; 166 | ENABLE_STRICT_OBJC_MSGSEND = YES; 167 | ENABLE_TESTABILITY = YES; 168 | GCC_C_LANGUAGE_STANDARD = gnu11; 169 | GCC_DYNAMIC_NO_PIC = NO; 170 | GCC_NO_COMMON_BLOCKS = YES; 171 | GCC_OPTIMIZATION_LEVEL = 0; 172 | GCC_PREPROCESSOR_DEFINITIONS = ( 173 | "DEBUG=1", 174 | "$(inherited)", 175 | ); 176 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 177 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 178 | GCC_WARN_UNDECLARED_SELECTOR = YES; 179 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 180 | GCC_WARN_UNUSED_FUNCTION = YES; 181 | GCC_WARN_UNUSED_VARIABLE = YES; 182 | MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; 183 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 184 | MTL_FAST_MATH = YES; 185 | ONLY_ACTIVE_ARCH = YES; 186 | SDKROOT = macosx; 187 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 188 | "SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = "raise-window/raise-window-Bridging-Header.h"; 189 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 190 | }; 191 | name = Debug; 192 | }; 193 | 4E88074F299AED81005D7098 /* Release */ = { 194 | isa = XCBuildConfiguration; 195 | buildSettings = { 196 | ALWAYS_SEARCH_USER_PATHS = NO; 197 | CLANG_ANALYZER_NONNULL = YES; 198 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 199 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 200 | CLANG_ENABLE_MODULES = YES; 201 | CLANG_ENABLE_OBJC_ARC = YES; 202 | CLANG_ENABLE_OBJC_WEAK = YES; 203 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 204 | CLANG_WARN_BOOL_CONVERSION = YES; 205 | CLANG_WARN_COMMA = YES; 206 | CLANG_WARN_CONSTANT_CONVERSION = YES; 207 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 208 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 209 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 210 | CLANG_WARN_EMPTY_BODY = YES; 211 | CLANG_WARN_ENUM_CONVERSION = YES; 212 | CLANG_WARN_INFINITE_RECURSION = YES; 213 | CLANG_WARN_INT_CONVERSION = YES; 214 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 215 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 216 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 217 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 218 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 219 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 220 | CLANG_WARN_STRICT_PROTOTYPES = YES; 221 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 222 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 223 | CLANG_WARN_UNREACHABLE_CODE = YES; 224 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 225 | COPY_PHASE_STRIP = NO; 226 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 227 | ENABLE_NS_ASSERTIONS = NO; 228 | ENABLE_STRICT_OBJC_MSGSEND = YES; 229 | GCC_C_LANGUAGE_STANDARD = gnu11; 230 | GCC_NO_COMMON_BLOCKS = YES; 231 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 232 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 233 | GCC_WARN_UNDECLARED_SELECTOR = YES; 234 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 235 | GCC_WARN_UNUSED_FUNCTION = YES; 236 | GCC_WARN_UNUSED_VARIABLE = YES; 237 | MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; 238 | MTL_ENABLE_DEBUG_INFO = NO; 239 | MTL_FAST_MATH = YES; 240 | SDKROOT = macosx; 241 | SWIFT_COMPILATION_MODE = wholemodule; 242 | "SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = "raise-window/raise-window-Bridging-Header.h"; 243 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 244 | }; 245 | name = Release; 246 | }; 247 | 4E880751299AED81005D7098 /* Debug */ = { 248 | isa = XCBuildConfiguration; 249 | buildSettings = { 250 | CODE_SIGN_STYLE = Automatic; 251 | DEVELOPMENT_TEAM = WL898W6Y89; 252 | ENABLE_HARDENED_RUNTIME = YES; 253 | PRODUCT_NAME = "$(TARGET_NAME)"; 254 | SWIFT_VERSION = 5.0; 255 | }; 256 | name = Debug; 257 | }; 258 | 4E880752299AED81005D7098 /* Release */ = { 259 | isa = XCBuildConfiguration; 260 | buildSettings = { 261 | CODE_SIGN_STYLE = Automatic; 262 | DEVELOPMENT_TEAM = WL898W6Y89; 263 | ENABLE_HARDENED_RUNTIME = YES; 264 | PRODUCT_NAME = "$(TARGET_NAME)"; 265 | SWIFT_VERSION = 5.0; 266 | }; 267 | name = Release; 268 | }; 269 | /* End XCBuildConfiguration section */ 270 | 271 | /* Begin XCConfigurationList section */ 272 | 4E880744299AED81005D7098 /* Build configuration list for PBXProject "raise-window" */ = { 273 | isa = XCConfigurationList; 274 | buildConfigurations = ( 275 | 4E88074E299AED81005D7098 /* Debug */, 276 | 4E88074F299AED81005D7098 /* Release */, 277 | ); 278 | defaultConfigurationIsVisible = 0; 279 | defaultConfigurationName = Release; 280 | }; 281 | 4E880750299AED81005D7098 /* Build configuration list for PBXNativeTarget "raise-window" */ = { 282 | isa = XCConfigurationList; 283 | buildConfigurations = ( 284 | 4E880751299AED81005D7098 /* Debug */, 285 | 4E880752299AED81005D7098 /* Release */, 286 | ); 287 | defaultConfigurationIsVisible = 0; 288 | defaultConfigurationName = Release; 289 | }; 290 | /* End XCConfigurationList section */ 291 | }; 292 | rootObject = 4E880741299AED81005D7098 /* Project object */; 293 | } 294 | -------------------------------------------------------------------------------- /Resources/raise-window/raise-window.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Resources/raise-window/raise-window.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Resources/raise-window/raise-window.xcodeproj/project.xcworkspace/xcuserdata/vitor.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfredapp/window-switcher-workflow/298be15358c813d7eaf4aa1bd8351d04265405d0/Resources/raise-window/raise-window.xcodeproj/project.xcworkspace/xcuserdata/vitor.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Resources/raise-window/raise-window.xcodeproj/xcshareddata/xcschemes/raise-window.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 44 | 46 | 52 | 53 | 54 | 55 | 61 | 63 | 69 | 70 | 71 | 72 | 74 | 75 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /Resources/raise-window/raise-window.xcodeproj/xcuserdata/vitor.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | raise-window.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 4E880748299AED81005D7098 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Resources/raise-window/raise-window/main.swift: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env swift 2 | 3 | guard 4 | let appPID = Int(CommandLine.arguments[1]), 5 | let windowNumber = Int(CommandLine.arguments[2]) 6 | else { fatalError("Requires two arguments: app PID and window number") } 7 | 8 | let axApp = AXUIElementCreateApplication(pid_t(appPID)) 9 | var axWindows: AnyObject? 10 | AXUIElementCopyAttributeValue(axApp, kAXWindowsAttribute as CFString, &axWindows) 11 | 12 | (axWindows as! [AXUIElement]).forEach { axWindow in 13 | var axWindowNumber: CGWindowID = 0 14 | _AXUIElementGetWindow(axWindow, &axWindowNumber) 15 | 16 | guard axWindowNumber == windowNumber else { return } 17 | 18 | let app = NSRunningApplication(processIdentifier: pid_t(appPID)) 19 | app?.activate(options: .activateIgnoringOtherApps) 20 | AXUIElementPerformAction(axWindow, kAXRaiseAction as CFString) 21 | } 22 | -------------------------------------------------------------------------------- /Resources/raise-window/raise-window/raise-window-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | AXError _AXUIElementGetWindow(AXUIElementRef element, uint32_t *identifier); 4 | -------------------------------------------------------------------------------- /Resources/request-recording.swift: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env swift 2 | 3 | import AppKit 4 | 5 | CGRequestScreenCaptureAccess() 6 | -------------------------------------------------------------------------------- /Workflow/get-windows: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfredapp/window-switcher-workflow/298be15358c813d7eaf4aa1bd8351d04265405d0/Workflow/get-windows -------------------------------------------------------------------------------- /Workflow/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfredapp/window-switcher-workflow/298be15358c813d7eaf4aa1bd8351d04265405d0/Workflow/icon.png -------------------------------------------------------------------------------- /Workflow/images/about/win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfredapp/window-switcher-workflow/298be15358c813d7eaf4aa1bd8351d04265405d0/Workflow/images/about/win.png -------------------------------------------------------------------------------- /Workflow/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | com.alfredapp.vitor.windowswitcher 7 | connections 8 | 9 | 4324CC66-57F4-4183-9061-3D94423292FA 10 | 11 | 12 | destinationuid 13 | 82CDD910-A6C3-4F66-8394-90150AF91668 14 | modifiers 15 | 0 16 | modifiersubtext 17 | 18 | vitoclose 19 | 20 | 21 | 22 | destinationuid 23 | E3CE2174-60F6-4DDA-9D12-84B0CA5C4271 24 | modifiers 25 | 1048576 26 | modifiersubtext 27 | Quit {var:app_name} 28 | vitoclose 29 | 30 | 31 | 32 | 463DA12A-D0C4-437F-BD05-B512C4FF5DCA 33 | 34 | 6ADF26CF-C74E-42F5-9267-FBAF87960576 35 | 36 | 37 | destinationuid 38 | 4324CC66-57F4-4183-9061-3D94423292FA 39 | modifiers 40 | 0 41 | modifiersubtext 42 | 43 | vitoclose 44 | 45 | 46 | 47 | 82CDD910-A6C3-4F66-8394-90150AF91668 48 | 49 | 50 | destinationuid 51 | BD68FEF5-ECE3-4AAE-8460-2066D5AD1C70 52 | modifiers 53 | 0 54 | modifiersubtext 55 | 56 | sourceoutputuid 57 | C95ACB3C-10F8-4759-909F-525F6F31008A 58 | vitoclose 59 | 60 | 61 | 62 | destinationuid 63 | 463DA12A-D0C4-437F-BD05-B512C4FF5DCA 64 | modifiers 65 | 0 66 | modifiersubtext 67 | 68 | vitoclose 69 | 70 | 71 | 72 | D7455512-A831-4586-8692-E2D2F4B0B802 73 | 74 | 75 | destinationuid 76 | 4324CC66-57F4-4183-9061-3D94423292FA 77 | modifiers 78 | 0 79 | modifiersubtext 80 | 81 | vitoclose 82 | 83 | 84 | 85 | E3CE2174-60F6-4DDA-9D12-84B0CA5C4271 86 | 87 | 88 | destinationuid 89 | 635BD118-84F5-4946-9311-7AA82F846279 90 | modifiers 91 | 0 92 | modifiersubtext 93 | 94 | vitoclose 95 | 96 | 97 | 98 | 99 | createdby 100 | Vítor Galvão 101 | description 102 | Switch to a specific window of an app in the current Desktop Space 103 | disabled 104 | 105 | name 106 | Window Switcher 107 | objects 108 | 109 | 110 | config 111 | 112 | alfredfiltersresults 113 | 114 | alfredfiltersresultsmatchmode 115 | 2 116 | argumenttreatemptyqueryasnil 117 | 118 | argumenttrimmode 119 | 0 120 | argumenttype 121 | 1 122 | escaping 123 | 68 124 | keyword 125 | {var:windows_keyword} 126 | queuedelaycustom 127 | 3 128 | queuedelayimmediatelyinitially 129 | 130 | queuedelaymode 131 | 0 132 | queuemode 133 | 1 134 | runningsubtext 135 | Gathering windows… 136 | script 137 | 138 | scriptargtype 139 | 1 140 | scriptfile 141 | get-windows 142 | skipuniversalaction 143 | 144 | subtext 145 | {const:alfred_workflow_description} 146 | title 147 | {const:alfred_workflow_name} 148 | type 149 | 8 150 | withspace 151 | 152 | 153 | type 154 | alfred.workflow.input.scriptfilter 155 | uid 156 | 4324CC66-57F4-4183-9061-3D94423292FA 157 | version 158 | 3 159 | 160 | 161 | config 162 | 163 | action 164 | 0 165 | argument 166 | 0 167 | focusedappvariable 168 | 169 | focusedappvariablename 170 | 171 | hotkey 172 | 46 173 | hotmod 174 | 1572864 175 | hotstring 176 | M 177 | leftcursor 178 | 179 | modsmode 180 | 0 181 | relatedAppsMode 182 | 0 183 | 184 | type 185 | alfred.workflow.trigger.hotkey 186 | uid 187 | 6ADF26CF-C74E-42F5-9267-FBAF87960576 188 | version 189 | 2 190 | 191 | 192 | config 193 | 194 | concurrently 195 | 196 | escaping 197 | 0 198 | script 199 | 200 | scriptargtype 201 | 1 202 | scriptfile 203 | request-recording 204 | type 205 | 8 206 | 207 | type 208 | alfred.workflow.action.script 209 | uid 210 | BD68FEF5-ECE3-4AAE-8460-2066D5AD1C70 211 | version 212 | 2 213 | 214 | 215 | config 216 | 217 | conditions 218 | 219 | 220 | inputstring 221 | 222 | matchcasesensitive 223 | 224 | matchmode 225 | 0 226 | matchstring 227 | request_permissions 228 | outputlabel 229 | Request Permissions 230 | uid 231 | C95ACB3C-10F8-4759-909F-525F6F31008A 232 | 233 | 234 | elselabel 235 | Raise Window 236 | hideelse 237 | 238 | 239 | type 240 | alfred.workflow.utility.conditional 241 | uid 242 | 82CDD910-A6C3-4F66-8394-90150AF91668 243 | version 244 | 1 245 | 246 | 247 | config 248 | 249 | concurrently 250 | 251 | escaping 252 | 0 253 | script 254 | 255 | scriptargtype 256 | 1 257 | scriptfile 258 | raise-window 259 | type 260 | 8 261 | 262 | type 263 | alfred.workflow.action.script 264 | uid 265 | 463DA12A-D0C4-437F-BD05-B512C4FF5DCA 266 | version 267 | 2 268 | 269 | 270 | config 271 | 272 | availableviaurlhandler 273 | 274 | triggerid 275 | list_windows 276 | 277 | type 278 | alfred.workflow.trigger.external 279 | uid 280 | D7455512-A831-4586-8692-E2D2F4B0B802 281 | version 282 | 1 283 | 284 | 285 | config 286 | 287 | tasksettings 288 | 289 | app_list 290 | {var:app_name} 291 | 292 | taskuid 293 | com.alfredapp.automation.core/macOS/app.quit 294 | 295 | type 296 | alfred.workflow.automation.task 297 | uid 298 | 635BD118-84F5-4946-9311-7AA82F846279 299 | version 300 | 1 301 | 302 | 303 | type 304 | alfred.workflow.utility.junction 305 | uid 306 | E3CE2174-60F6-4DDA-9D12-84B0CA5C4271 307 | version 308 | 1 309 | 310 | 311 | readme 312 | ## Usage 313 | 314 | Search app windows in the current Desktop Space via the `win` keyword. 315 | 316 | ![Alfred search for win](images/about/win.png) 317 | 318 | * <kbd>↩</kbd> Bring window to the front. 319 | * <kbd>⌘</kbd><kbd>↩</kbd> Quit app. 320 | 321 | Configure the [Hotkey](https://www.alfredapp.com/help/workflows/triggers/hotkey/) for faster triggering. 322 | uidata 323 | 324 | 4324CC66-57F4-4183-9061-3D94423292FA 325 | 326 | note 327 | Show window selection 328 | xpos 329 | 235 330 | ypos 331 | 40 332 | 333 | 463DA12A-D0C4-437F-BD05-B512C4FF5DCA 334 | 335 | xpos 336 | 590 337 | ypos 338 | 200 339 | 340 | 635BD118-84F5-4946-9311-7AA82F846279 341 | 342 | xpos 343 | 590 344 | ypos 345 | 335 346 | 347 | 6ADF26CF-C74E-42F5-9267-FBAF87960576 348 | 349 | note 350 | Optional Hotkey to invoke window selection 351 | xpos 352 | 45 353 | ypos 354 | 40 355 | 356 | 82CDD910-A6C3-4F66-8394-90150AF91668 357 | 358 | xpos 359 | 410 360 | ypos 361 | 60 362 | 363 | BD68FEF5-ECE3-4AAE-8460-2066D5AD1C70 364 | 365 | xpos 366 | 590 367 | ypos 368 | 40 369 | 370 | D7455512-A831-4586-8692-E2D2F4B0B802 371 | 372 | xpos 373 | 45 374 | ypos 375 | 200 376 | 377 | E3CE2174-60F6-4DDA-9D12-84B0CA5C4271 378 | 379 | xpos 380 | 455 381 | ypos 382 | 365 383 | 384 | 385 | userconfigurationconfig 386 | 387 | 388 | config 389 | 390 | default 391 | win 392 | placeholder 393 | 394 | required 395 | 396 | trim 397 | 398 | 399 | description 400 | 401 | label 402 | Windows Keyword 403 | type 404 | textfield 405 | variable 406 | windows_keyword 407 | 408 | 409 | variablesdontexport 410 | 411 | version 412 | 2024.2 413 | webaddress 414 | https://github.com/alfredapp/window-switcher-workflow/ 415 | 416 | 417 | -------------------------------------------------------------------------------- /Workflow/raise-window: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfredapp/window-switcher-workflow/298be15358c813d7eaf4aa1bd8351d04265405d0/Workflow/raise-window -------------------------------------------------------------------------------- /Workflow/request-recording: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alfredapp/window-switcher-workflow/298be15358c813d7eaf4aa1bd8351d04265405d0/Workflow/request-recording --------------------------------------------------------------------------------