Skip to content

Instantly share code, notes, and snippets.

@JuniperPhoton
Last active March 31, 2025 08:47
Show Gist options
  • Save JuniperPhoton/b8e130159541803d71531c7d9320d5d3 to your computer and use it in GitHub Desktop.
Save JuniperPhoton/b8e130159541803d71531c7d9320d5d3 to your computer and use it in GitHub Desktop.
A simple application to show a black, resizable, title-less, always-on-top NSWindow on Mac.
//
// FloatingOverlayApp.swift
// FloatingOverlay
//
// Created by JuniperPhoton on 2025/3/12.
//
import SwiftUI
// Dependency: https://github.com/sindresorhus/KeyboardShortcuts
import KeyboardShortcuts
extension KeyboardShortcuts.Name {
static let toggleWindow = Self("ToggleWindow", default: .init(.l, modifiers: [.command, .option]))
}
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
guard let window = NSApplication.shared.windows.first else {
return
}
window.configureWindow()
// If users maximum a NSWindow to the fullscreen mode, we need to activate it using keyboard shortcuts.
// This [library](https://github.com/sindresorhus/KeyboardShortcuts) can help us implement this feature.
// Also, make sure to set "Application is agent (UIElement)" to true in Info.plist.
KeyboardShortcuts.onKeyUp(for: .toggleWindow) {
if let window = NSApplication.shared.windows.first {
// Make sure to reconfigure the window first.
window.configureWindow()
NSApplication.shared.activate()
}
}
}
}
extension NSWindow {
func configureWindow() {
self.titleVisibility = .hidden
self.titlebarAppearsTransparent = true
self.isMovableByWindowBackground = true
self.level = .screenSaver
self.styleMask = [.borderless, .resizable]
self.collectionBehavior = [
.fullScreenAuxiliary,
.stationary,
.moveToActiveSpace
]
}
}
@main
struct FloatingOverlayApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView().preferredColorScheme(.dark)
}
}
}
struct ContentView: View {
var body: some View {
VStack {
// empty
}
.padding()
.background {
Rectangle().fill(.clear)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment