From 1041a9609b2f63950b61620ace92867c2bf38576 Mon Sep 17 00:00:00 2001 From: Nikita Bobko Date: Sun, 4 Feb 2024 05:40:31 +0100 Subject: [PATCH] 2/n Implement macos-native-fullscreen command https://github.com/nikitabobko/AeroSpace/issues/18 --- AeroSpace.xcodeproj/project.pbxproj | 20 ++++++++++++---- .../Cli/subcommandDescriptionsGenerated.swift | 1 + .../cmdArgs/MacosNativeFullscreen.swift | 4 ++++ .../Common/cmdArgs/{ => other}/CmdKind.swift | 1 + .../cmdArgs/{ => other}/parseCmdArgs.swift | 2 ++ .../{ => other}/parseCmdArgsUtils.swift | 0 docs/aerospace-macos-native-fullscreen.adoc | 24 +++++++++++++++++++ docs/commands.adoc | 7 ++++++ .../MacosNativeFullscreenCommand.swift | 17 +++++++++++++ src/command/{ => other}/parseCommand.swift | 2 ++ src/util/accessibility.swift | 5 ++-- 11 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 LocalPackage/Sources/Common/cmdArgs/MacosNativeFullscreen.swift rename LocalPackage/Sources/Common/cmdArgs/{ => other}/CmdKind.swift (93%) rename LocalPackage/Sources/Common/cmdArgs/{ => other}/parseCmdArgs.swift (97%) rename LocalPackage/Sources/Common/cmdArgs/{ => other}/parseCmdArgsUtils.swift (100%) create mode 100644 docs/aerospace-macos-native-fullscreen.adoc create mode 100644 src/command/MacosNativeFullscreenCommand.swift rename src/command/{ => other}/parseCommand.swift (95%) diff --git a/AeroSpace.xcodeproj/project.pbxproj b/AeroSpace.xcodeproj/project.pbxproj index f0eed6c5..fc95cd3f 100644 --- a/AeroSpace.xcodeproj/project.pbxproj +++ b/AeroSpace.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 45AA5FD4A023AF751922BC22 /* BundleEx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B7A2DF0D1F72B80B1F04240 /* BundleEx.swift */; }; 45EA2D1C90430C432E123B51 /* keysMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0D40CBD65704BA9595C2FA /* keysMap.swift */; }; 4CC374136F60299FB672662D /* DebugWindowsCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71908440CD1ADBE13AD58E26 /* DebugWindowsCommand.swift */; }; + 4E0BC093AD1FBCCA718A26EC /* parseCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07ADCBFC2E29A2AD5C1B7984 /* parseCommand.swift */; }; 51AB4C0992703B2E9D0F55E2 /* MonitorDescriptionEx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C1D626244E63437F1CA24C3 /* MonitorDescriptionEx.swift */; }; 56E72B24303F5F337B31B776 /* TrayMenuModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5F52E346D024960EAF5938 /* TrayMenuModel.swift */; }; 5BA537EABFE48178D6BD2544 /* parseGaps.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCDFB9D7321F08B5CCEF6AFB /* parseGaps.swift */; }; @@ -69,7 +70,6 @@ A07FCBE4D69DBA4D6990E143 /* FocusSourceOfTruth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826EA316AB62F913D1A94466 /* FocusSourceOfTruth.swift */; }; A249B6511A9BD20A298C0DE7 /* SplitCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65F0D298D61D85CEB29CE77 /* SplitCommand.swift */; }; A2CBF9674964F9083BB198D2 /* ArrayEx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 883D7F7F87FBE7D0BDE4E87F /* ArrayEx.swift */; }; - A5BFF75CF8021A585BC1F9D5 /* parseCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB03A4736BC3F6D19E4E69F3 /* parseCommand.swift */; }; AC47DF43EFF42358F033C87C /* WorkspaceBackAndForthCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED7EE20910D7BE4D0150CED /* WorkspaceBackAndForthCommand.swift */; }; B04363E8C28CEC76F39977F2 /* MonitorDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244190F3707EF2BB3CC7FA5A /* MonitorDescription.swift */; }; B0D0C37BAE7E7F0D0FF1E9FC /* GlobalObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C2E5977331398421A4FC168 /* GlobalObserver.swift */; }; @@ -89,6 +89,7 @@ D24D02B1FD87424B908986AF /* ResizeCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB371951459F8CB0137788C2 /* ResizeCommand.swift */; }; DA43825BE8B903C7AAA00D92 /* HotkeyBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69CB1289E3FA51A35F839238 /* HotkeyBinding.swift */; }; DCCC05496BDAAFB745E99624 /* SplitCommandTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D96FF3675C63A83DC8B8969 /* SplitCommandTest.swift */; }; + DEE74487CFB70CEC10D9D3D7 /* MacosNativeFullscreenCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3D87FF4D8238F07870F2F6 /* MacosNativeFullscreenCommand.swift */; }; DFEB9F168281870D09BD1C2C /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 4227A8D8CDB02646B1E1313D /* Common */; }; E1E35DC5D9D74D54E92AB5F3 /* ExecCommandTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A6EF465EF4129BCB10FE247 /* ExecCommandTest.swift */; }; E22ACB36C90695FBAC78226E /* TestWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F1905935B0C61590A96EFEF /* TestWindow.swift */; }; @@ -116,6 +117,7 @@ /* Begin PBXFileReference section */ 00ECDFE176777828D560A737 /* TilingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TilingContainer.swift; sourceTree = ""; }; + 07ADCBFC2E29A2AD5C1B7984 /* parseCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = parseCommand.swift; sourceTree = ""; }; 09685297933511208058F7CF /* AeroSpace.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AeroSpace.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0A9DFF8980BB3F90A3793BE9 /* parseOnWindowDetected.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = parseOnWindowDetected.swift; sourceTree = ""; }; 0AEE5470AF418906B180A593 /* mouse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = mouse.swift; sourceTree = ""; }; @@ -186,10 +188,10 @@ B65F0D298D61D85CEB29CE77 /* SplitCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitCommand.swift; sourceTree = ""; }; B7DB782C527ABE0CF31740EB /* MacApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacApp.swift; sourceTree = ""; }; BEF353340822CD20E9DAB3EC /* AeroSpace.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AeroSpace.entitlements; sourceTree = ""; }; + BF3D87FF4D8238F07870F2F6 /* MacosNativeFullscreenCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacosNativeFullscreenCommand.swift; sourceTree = ""; }; C3F068BCC50ED846DCBFDE57 /* Workspace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Workspace.swift; sourceTree = ""; }; C704028F402C0DE83EDEABB9 /* normalizeContainers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = normalizeContainers.swift; sourceTree = ""; }; C848D6E57FDF22AAF0FB45E6 /* TilingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TilingContainer.swift; sourceTree = ""; }; - CB03A4736BC3F6D19E4E69F3 /* parseCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = parseCommand.swift; sourceTree = ""; }; CB371951459F8CB0137788C2 /* ResizeCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResizeCommand.swift; sourceTree = ""; }; CC4A8803D3A23C26287D449E /* ListMonitorsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListMonitorsTest.swift; sourceTree = ""; }; CCDFB9D7321F08B5CCEF6AFB /* parseGaps.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = parseGaps.swift; sourceTree = ""; }; @@ -416,16 +418,17 @@ 9ECC990B6C2D66D343216A12 /* FullscreenCommand.swift */, D27A7AF7E9A049700BDE276B /* JoinWithCommand.swift */, 1A2B673C67B00DBFCC27FFE7 /* LayoutCommand.swift */, + BF3D87FF4D8238F07870F2F6 /* MacosNativeFullscreenCommand.swift */, 4B0CD3C2A0E86CDB9DF312AB /* ModeCommand.swift */, 1376845BAB666880919B9AA2 /* MoveCommand.swift */, 25AC44D0E9450867215FCBEC /* MoveNodeToWorkspaceCommand.swift */, 51CC651BEB897CB7A555D230 /* MoveWorkspaceToMonitorCommand.swift */, - CB03A4736BC3F6D19E4E69F3 /* parseCommand.swift */, CF3C9038C846369FDD71D1D2 /* ReloadConfigCommand.swift */, CB371951459F8CB0137788C2 /* ResizeCommand.swift */, B65F0D298D61D85CEB29CE77 /* SplitCommand.swift */, EED7EE20910D7BE4D0150CED /* WorkspaceBackAndForthCommand.swift */, 43DD32B1711B8EFCC834B68E /* WorkspaceCommand.swift */, + BC4C93837A34DB0968E73833 /* other */, 9797FA095A9BE84428C5E2C0 /* query */, ); path = command; @@ -442,6 +445,14 @@ path = tree; sourceTree = ""; }; + BC4C93837A34DB0968E73833 /* other */ = { + isa = PBXGroup; + children = ( + 07ADCBFC2E29A2AD5C1B7984 /* parseCommand.swift */, + ); + path = other; + sourceTree = ""; + }; C136937AA077E63558E9707C /* util */ = { isa = PBXGroup; children = ( @@ -609,6 +620,7 @@ 3AFD7EE961B97F38C0914A0C /* ListWorkspacesCommand.swift in Sources */, BD6301B2CFC16FDE4223ACB8 /* MacApp.swift in Sources */, EECC59858691B99A95542D72 /* MacWindow.swift in Sources */, + DEE74487CFB70CEC10D9D3D7 /* MacosNativeFullscreenCommand.swift in Sources */, 6E4E235FDA41307B19F16182 /* ModeCommand.swift in Sources */, C76E421FB0D0F0EB1C93A06C /* Monitor.swift in Sources */, B04363E8C28CEC76F39977F2 /* MonitorDescription.swift in Sources */, @@ -641,7 +653,7 @@ 045D4B46ABACA9E8167EF356 /* mouse.swift in Sources */, 78622D72C0CCE8D69B080D29 /* moveWithMouse.swift in Sources */, B19980B36D066FD4947D2F92 /* normalizeContainers.swift in Sources */, - A5BFF75CF8021A585BC1F9D5 /* parseCommand.swift in Sources */, + 4E0BC093AD1FBCCA718A26EC /* parseCommand.swift in Sources */, A0765C31043BCFB0420BF1C9 /* parseConfig.swift in Sources */, 5BA537EABFE48178D6BD2544 /* parseGaps.swift in Sources */, 21D0512B48E0E3C28F8CA42A /* parseOnWindowDetected.swift in Sources */, diff --git a/LocalPackage/Sources/Cli/subcommandDescriptionsGenerated.swift b/LocalPackage/Sources/Cli/subcommandDescriptionsGenerated.swift index 2669d3b0..c49432a7 100644 --- a/LocalPackage/Sources/Cli/subcommandDescriptionsGenerated.swift +++ b/LocalPackage/Sources/Cli/subcommandDescriptionsGenerated.swift @@ -13,6 +13,7 @@ let subcommandDescriptions = [ [" list-monitors", "Prints monitors that satisfy conditions"], [" list-windows", "Prints windows that satisfy conditions"], [" list-workspaces", "Prints workspaces that satisfy conditions"], + [" macos-native-fullscreen", "Toggle macOS fullscreen for the currently focused window"], [" mode", "Activates the specified binding modes"], [" move-node-to-workspace", "Moves currently focused window to the specified workspace"], [" move-workspace-to-monitor", "Moves currently focused workspace to the next or previous monitor"], diff --git a/LocalPackage/Sources/Common/cmdArgs/MacosNativeFullscreen.swift b/LocalPackage/Sources/Common/cmdArgs/MacosNativeFullscreen.swift new file mode 100644 index 00000000..f636b973 --- /dev/null +++ b/LocalPackage/Sources/Common/cmdArgs/MacosNativeFullscreen.swift @@ -0,0 +1,4 @@ +public struct MacosNativeFullscreenCmdArgs: RawCmdArgs, CmdArgs { + public init() {} + public static let parser: CmdParser = noArgsParser(.macosNativeFullscreen, allowInConfig: true) +} diff --git a/LocalPackage/Sources/Common/cmdArgs/CmdKind.swift b/LocalPackage/Sources/Common/cmdArgs/other/CmdKind.swift similarity index 93% rename from LocalPackage/Sources/Common/cmdArgs/CmdKind.swift rename to LocalPackage/Sources/Common/cmdArgs/other/CmdKind.swift index e107b470..7a98b896 100644 --- a/LocalPackage/Sources/Common/cmdArgs/CmdKind.swift +++ b/LocalPackage/Sources/Common/cmdArgs/other/CmdKind.swift @@ -13,6 +13,7 @@ public enum CmdKind: String, CaseIterable, Equatable { case listMonitors = "list-monitors" case listWindows = "list-windows" case listWorkspaces = "list-workspaces" + case macosNativeFullscreen = "macos-native-fullscreen" case mode case move = "move" case moveNodeToWorkspace = "move-node-to-workspace" diff --git a/LocalPackage/Sources/Common/cmdArgs/parseCmdArgs.swift b/LocalPackage/Sources/Common/cmdArgs/other/parseCmdArgs.swift similarity index 97% rename from LocalPackage/Sources/Common/cmdArgs/parseCmdArgs.swift rename to LocalPackage/Sources/Common/cmdArgs/other/parseCmdArgs.swift index ae34f291..bca02ce9 100644 --- a/LocalPackage/Sources/Common/cmdArgs/parseCmdArgs.swift +++ b/LocalPackage/Sources/Common/cmdArgs/other/parseCmdArgs.swift @@ -46,6 +46,8 @@ private func initSubcommands() -> [String: any SubCommandParserProtocol] { result[kind.rawValue] = SubCommandParser(parseListWindowsCmdArgs) case .listWorkspaces: result[kind.rawValue] = SubCommandParser(parseListWorkspacesCmdArgs) + case .macosNativeFullscreen: + result[kind.rawValue] = defaultSubCommandParser(MacosNativeFullscreenCmdArgs()) case .mode: result[kind.rawValue] = defaultSubCommandParser(ModeCmdArgs()) case .moveNodeToWorkspace: diff --git a/LocalPackage/Sources/Common/cmdArgs/parseCmdArgsUtils.swift b/LocalPackage/Sources/Common/cmdArgs/other/parseCmdArgsUtils.swift similarity index 100% rename from LocalPackage/Sources/Common/cmdArgs/parseCmdArgsUtils.swift rename to LocalPackage/Sources/Common/cmdArgs/other/parseCmdArgsUtils.swift diff --git a/docs/aerospace-macos-native-fullscreen.adoc b/docs/aerospace-macos-native-fullscreen.adoc new file mode 100644 index 00000000..e0c14425 --- /dev/null +++ b/docs/aerospace-macos-native-fullscreen.adoc @@ -0,0 +1,24 @@ += aerospace-macos-native-fullscreen(1) +include::util/man-attributes.adoc[] +:manname: aerospace-macos-native-fullscreen +// tag::purpose[] +:manpurpose: Toggle macOS fullscreen for the currently focused window +// end::purpose[] + +== Synopsis +// tag::synopsis[] +macos-native-fullscreen [-h|--help] +// end::synopsis[] + +== Description + +// tag::body[] +{manpurpose} + +// end::body[] + +include::util/conditional-options-header.adoc[] + +-h, --help:: Print help + +include::util/man-footer.adoc[] diff --git a/docs/commands.adoc b/docs/commands.adoc index 7df00418..09ee4211 100644 --- a/docs/commands.adoc +++ b/docs/commands.adoc @@ -95,6 +95,13 @@ include::aerospace-layout.adoc[tags=synopsis] include::aerospace-layout.adoc[tags=purpose] include::aerospace-layout.adoc[tags=body] +== macos-native-fullscreen +---- +include::aerospace-macos-native-fullscreen.adoc[tags=synopsis] +---- +include::aerospace-macos-native-fullscreen.adoc[tags=purpose] +include::aerospace-macos-native-fullscreen.adoc[tags=body] + == mode ---- include::aerospace-mode.adoc[tags=synopsis] diff --git a/src/command/MacosNativeFullscreenCommand.swift b/src/command/MacosNativeFullscreenCommand.swift new file mode 100644 index 00000000..e320906d --- /dev/null +++ b/src/command/MacosNativeFullscreenCommand.swift @@ -0,0 +1,17 @@ +import Common + +struct MacosNativeFullscreenCommand: Command { + let args: MacosNativeFullscreenCmdArgs + + func _run(_ state: CommandMutableState, stdin: String) -> Bool { + check(Thread.current.isMainThread) + guard let window = state.subject.windowOrNil else { + state.stderr.append("No window in focus") + return false + } + let axWindow = window.asMacWindow().axWindow + let success = axWindow.set(Ax.isFullscreenAttr, !window.isMacosFullscreen) + if !success { state.stderr.append("Failed") } + return success + } +} diff --git a/src/command/parseCommand.swift b/src/command/other/parseCommand.swift similarity index 95% rename from src/command/parseCommand.swift rename to src/command/other/parseCommand.swift index 0c3c942f..fb48960b 100644 --- a/src/command/parseCommand.swift +++ b/src/command/other/parseCommand.swift @@ -37,6 +37,8 @@ extension CmdArgs { command = ListWindowsCommand(args: self as! ListWindowsCmdArgs) case .listWorkspaces: command = ListWorkspacesCommand(args: self as! ListWorkspacesCmdArgs) + case .macosNativeFullscreen: + command = MacosNativeFullscreenCommand(args: self as! MacosNativeFullscreenCmdArgs) case .mode: command = ModeCommand(args: self as! ModeCmdArgs) case .moveNodeToWorkspace: diff --git a/src/util/accessibility.swift b/src/util/accessibility.swift index 59ed525e..e13d6ba7 100644 --- a/src/util/accessibility.swift +++ b/src/util/accessibility.swift @@ -215,9 +215,10 @@ enum Ax { // key: kAXMinimizedAttribute, // getter: { $0 as? Bool } //) - static let isFullscreenAttr = ReadableAttrImpl( + static let isFullscreenAttr = WritableAttrImpl( key: "AXFullScreen", - getter: { $0 as? Bool } + getter: { $0 as? Bool }, + setter: { $0 as CFTypeRef } ) //static let axMainAttr = ReadableAttrImpl( // key: kAXMainAttribute,