Skip to content

Commit

Permalink
Adding a configuration screen
Browse files Browse the repository at this point in the history
  • Loading branch information
xiamaz committed Jan 1, 2022
1 parent 2ec3c77 commit 5b31a60
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 40 deletions.
12 changes: 10 additions & 2 deletions YabaiIndicator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

/* Begin PBXBuildFile section */
500F41362780826500C6BC9B /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500F41352780826500C6BC9B /* SettingsView.swift */; };
5051A4692780C02700614C85 /* YabaiClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5051A4682780C02700614C85 /* YabaiClient.swift */; };
5051A46B2780DC9B00614C85 /* defaults.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5051A46A2780DC9B00614C85 /* defaults.plist */; };
5061206C2779212000E8F192 /* YabaiIndicatorApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5061206B2779212000E8F192 /* YabaiIndicatorApp.swift */; };
5061206E2779212000E8F192 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5061206D2779212000E8F192 /* ContentView.swift */; };
506120702779212200E8F192 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5061206F2779212200E8F192 /* Assets.xcassets */; };
Expand Down Expand Up @@ -44,6 +46,8 @@

/* Begin PBXFileReference section */
500F41352780826500C6BC9B /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
5051A4682780C02700614C85 /* YabaiClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YabaiClient.swift; sourceTree = "<group>"; };
5051A46A2780DC9B00614C85 /* defaults.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = defaults.plist; sourceTree = "<group>"; };
506120682779212000E8F192 /* YabaiIndicator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YabaiIndicator.app; sourceTree = BUILT_PRODUCTS_DIR; };
5061206B2779212000E8F192 /* YabaiIndicatorApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YabaiIndicatorApp.swift; sourceTree = "<group>"; };
5061206D2779212000E8F192 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -123,6 +127,7 @@
5061206A2779212000E8F192 /* YabaiIndicator */ = {
isa = PBXGroup;
children = (
5051A46A2780DC9B00614C85 /* defaults.plist */,
506120962779231000E8F192 /* Info.plist */,
5061206B2779212000E8F192 /* YabaiIndicatorApp.swift */,
5061206D2779212000E8F192 /* ContentView.swift */,
Expand All @@ -135,6 +140,7 @@
5061209F277A195C00E8F192 /* YabaiIndicator-Bridging-Header.h */,
506120AE277A7BF800E8F192 /* SpacesModel.swift */,
500F41352780826500C6BC9B /* SettingsView.swift */,
5051A4682780C02700614C85 /* YabaiClient.swift */,
);
path = YabaiIndicator;
sourceTree = "<group>";
Expand Down Expand Up @@ -287,6 +293,7 @@
buildActionMask = 2147483647;
files = (
506120732779212200E8F192 /* Preview Assets.xcassets in Resources */,
5051A46B2780DC9B00614C85 /* defaults.plist in Resources */,
506120702779212200E8F192 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -318,6 +325,7 @@
500F41362780826500C6BC9B /* SettingsView.swift in Sources */,
5061206E2779212000E8F192 /* ContentView.swift in Sources */,
5061206C2779212000E8F192 /* YabaiIndicatorApp.swift in Sources */,
5051A4692780C02700614C85 /* YabaiClient.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -490,7 +498,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 0.1.0;
MARKETING_VERSION = 0.2.0;
PRODUCT_BUNDLE_IDENTIFIER = de.arsbrevis.YabaiIndicator;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down Expand Up @@ -525,7 +533,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 0.1.0;
MARKETING_VERSION = 0.2.0;
PRODUCT_BUNDLE_IDENTIFIER = de.arsbrevis.YabaiIndicator;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
filePath = "YabaiIndicator/YabaiAppDelegate.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "141"
endingLineNumber = "141"
startingLineNumber = "189"
endingLineNumber = "189"
landmarkName = "applicationDidFinishLaunching(_:)"
landmarkType = "7">
</BreakpointContent>
Expand Down
18 changes: 4 additions & 14 deletions YabaiIndicator/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,6 @@

import SwiftUI

@discardableResult
func shell(_ args: String...) -> Int32 {
let task = Process()
task.launchPath = "/usr/local/bin/yabai"
task.arguments = args
task.launch()
task.waitUntilExit()
return task.terminationStatus
}

struct SpaceButton : View {
var space: Space

Expand All @@ -32,8 +22,7 @@ struct SpaceButton : View {

func switchSpace() {
if !space.active && space.yabaiIndex > 0 {
shell(
"-m", "space", "--focus", "\(space.yabaiIndex)")
focusSpace(index: space.yabaiIndex)
}

}
Expand All @@ -52,11 +41,12 @@ struct SpaceButton : View {
struct ContentView: View {

@EnvironmentObject var spaces: Spaces

@AppStorage("showDisplaySeparator") private var showDisplaySeparator = true
@AppStorage("showCurrentSpaceOnly") private var showCurrentSpaceOnly = false

var body: some View {
HStack (spacing: 4) {
ForEach(spaces.spaceElems) {space in
ForEach(spaces.spaceElems.filter{($0.type >= 0) || showDisplaySeparator}.filter{$0.visible || !showCurrentSpaceOnly}) {space in
SpaceButton(space: space)
}
}.padding(2)
Expand Down
46 changes: 35 additions & 11 deletions YabaiIndicator/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,43 @@ import SwiftUI
struct SettingsView : View {
@AppStorage("showDisplaySeparator") private var showDisplaySeparator = true
@AppStorage("showCurrentSpaceOnly") private var showCurrentSpaceOnly = false
@AppStorage("yabaiPath") private var yabaiPath = "/usr/local/bin/yabai"
@AppStorage("yabaiPath") private var yabaiPath = ""

@State private var validPath = false
@State private var editedPath = false

private enum Tabs: Hashable {
case general, advanced
}

private func checkYabaiPath() {
validPath = checkYabai()
editedPath = true
}

var body: some View {
Form {
Toggle("Show Display Separator", isOn: $showDisplaySeparator)
Toggle("Show Current Space Only", isOn: $showCurrentSpaceOnly)
VStack {
TextField("Yabai Path", text: $yabaiPath).textFieldStyle(.plain)
Divider()
}.padding(5).disabled(false)

TabView {
Form {
Toggle("Show Display Separator", isOn: $showDisplaySeparator)
Toggle("Show Current Space Only", isOn: $showCurrentSpaceOnly)
VStack{
HStack {
Text("Yabai Path")
TextField("Yabai Path", text: $yabaiPath)
Button("Check", action: checkYabaiPath)
}
if (editedPath) {
Text(validPath ? "Valid yabai binary" : "Invalid path").foregroundColor(validPath ? Color.green : Color.red)
}
Spacer()
}
}.padding(10)
.tabItem {
Label("General", systemImage: "gear")
}
.tag(Tabs.general)

}.padding(20)

}
.frame(width: 375, height: 120)
}
}
2 changes: 2 additions & 0 deletions YabaiIndicator/SpacesModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import Foundation

class Spaces: ObservableObject {
@Published var spaceElems:[Space] = []
@Published var totalSpaces:Int = 0
@Published var totalDisplays:Int = 0

init(spaces: [Space]) {
spaceElems = spaces
Expand Down
70 changes: 59 additions & 11 deletions YabaiIndicator/YabaiAppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@

import SwiftUI
import Socket
import Combine

extension UserDefaults {
@objc dynamic var showDisplaySeparator: Bool {
return bool(forKey: "showDisplaySeparator")
}

@objc dynamic var showCurrentSpaceOnly: Bool {
return bool(forKey: "showCurrentSpaceOnly")
}
}

class YabaiAppDelegate: NSObject, NSApplicationDelegate {
var statusBarItem: NSStatusItem?
Expand All @@ -16,6 +27,11 @@ class YabaiAppDelegate: NSObject, NSApplicationDelegate {
let g_connection = SLSMainConnectionID()
let statusBarHeight = 22
let itemWidth:CGFloat = 30

var refreshSink: AnyCancellable?
var separatorSink: AnyCancellable?
var displaySink: AnyCancellable?


@objc
func onSpaceChanged(_ notification: Notification) {
Expand All @@ -32,7 +48,7 @@ class YabaiAppDelegate: NSObject, NSApplicationDelegate {
let activeDisplayUUID = SLSCopyActiveMenuBarDisplayIdentifier(g_connection).takeRetainedValue() as String

let displays = SLSCopyManagedDisplaySpaces(g_connection).takeRetainedValue() as [AnyObject]

var spaceIncr = 0
var totalSpaces = 0
var spaces:[Space] = []
Expand All @@ -45,7 +61,7 @@ class YabaiAppDelegate: NSObject, NSApplicationDelegate {
let activeDisplay = activeDisplayUUID == displayUUID

if (totalSpaces > 0) {
spaces.append(Space(id: 0, uuid: "", visible: false, active: false, displayUUID: "", index: 0, yabaiIndex: totalSpaces, type: -1))
spaces.append(Space(id: 0, uuid: "", visible: true, active: false, displayUUID: "", index: 0, yabaiIndex: totalSpaces, type: -1))
}

for nsSpace:NSDictionary in displaySpaces {
Expand All @@ -66,10 +82,23 @@ class YabaiAppDelegate: NSObject, NSApplicationDelegate {
}
}
self.spaces.spaceElems = spaces

let newWidth = CGFloat(totalSpaces) * itemWidth
self.spaces.totalSpaces = totalSpaces
self.spaces.totalDisplays = displays.count
}

func refreshBar() {
let showDisplaySeparator = UserDefaults.standard.bool(forKey: "showDisplaySeparator")
let showCurrentSpaceOnly = UserDefaults.standard.bool(forKey: "showCurrentSpaceOnly")

let numButtons = showCurrentSpaceOnly ? spaces.totalDisplays : spaces.totalSpaces

var newWidth = CGFloat(numButtons) * itemWidth
if !showDisplaySeparator {
newWidth -= CGFloat((spaces.totalDisplays - 1) * 10)
}
statusBarItem?.button?.frame.size.width = newWidth
statusBarItem?.button?.subviews[0].frame.size.width = newWidth
statusBarItem?.button?.subviews[0].frame.size.width = newWidth

}

func socketServer() async {
Expand Down Expand Up @@ -100,6 +129,12 @@ class YabaiAppDelegate: NSObject, NSApplicationDelegate {
NSApp.terminate(self)
}

@objc
func openPreferences() {
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: nil, from: nil)
NSApp.activate(ignoringOtherApps: true)
}

func createStatusItemView() -> NSView {
let view = NSHostingView(
rootView: ContentView().environmentObject(spaces)
Expand All @@ -109,13 +144,13 @@ class YabaiAppDelegate: NSObject, NSApplicationDelegate {
}

func createMenu() -> NSMenu {
let statusBarMenu = NSMenu(title: "Yabai Indicator Menu")
let settingsView = NSHostingView(rootView: SettingsView())
let menuItem = NSMenuItem()
settingsView.setFrameSize(NSSize(width: 300, height: 100))
menuItem.view = settingsView
statusBarMenu.addItem(menuItem)
let statusBarMenu = NSMenu()
statusBarMenu.addItem(
withTitle: "Preferences",
action: #selector(openPreferences),
keyEquivalent: "")
statusBarMenu.addItem(NSMenuItem.separator())

statusBarMenu.addItem(
withTitle: "Quit",
action: #selector(quit),
Expand All @@ -129,6 +164,16 @@ class YabaiAppDelegate: NSObject, NSApplicationDelegate {
}

func applicationDidFinishLaunching(_ notification: Notification) {
if let prefs = Bundle.main.path(forResource: "defaults", ofType: "plist"),
let dict = NSDictionary(contentsOfFile: prefs) as? [String : Any] {
UserDefaults.standard.register(defaults: dict)
}

refreshSink = spaces.objectWillChange.sink{_ in self.refreshBar()}
separatorSink = UserDefaults.standard.publisher(for: \.showDisplaySeparator).sink {_ in self.refreshBar()}
displaySink = UserDefaults.standard.publisher(for: \.showCurrentSpaceOnly).sink {_ in self.refreshBar()}


Task {
await self.socketServer()
}
Expand All @@ -138,5 +183,8 @@ class YabaiAppDelegate: NSObject, NSApplicationDelegate {
statusBarItem?.menu = createMenu()

refreshData()

registerObservers()

}
}
35 changes: 35 additions & 0 deletions YabaiIndicator/YabaiClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// YabaiClient.swift
// YabaiIndicator
//
// Created by Max Zhao on 01/01/2022.
//

import SwiftUI

@discardableResult
func yabai(_ args: String...) -> Int32 {
let task = Process()
let yabaiPath = UserDefaults.standard.string(forKey: "yabaiPath")
task.launchPath = yabaiPath
task.arguments = args
do {
try task.run()
} catch {
print(error)
return 1
}
task.waitUntilExit()
let status = task.terminationStatus
return status
}

func focusSpace(index: Int) {
yabai(
"-m", "space", "--focus", "\(index)")
}

func checkYabai() -> Bool {
let valid = yabai("-v") == 0
return valid
}
12 changes: 12 additions & 0 deletions YabaiIndicator/defaults.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>showDisplaySeparator</key>
<true/>
<key>yabaiPath</key>
<string>/usr/local/bin/yabai</string>
<key>showCurrentSpaceOnly</key>
<false/>
</dict>
</plist>

0 comments on commit 5b31a60

Please sign in to comment.