mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: start work on SlideTerminal, slides in window from top
This commit is contained in:
@ -62,6 +62,9 @@
|
||||
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0572C9F30860017A1AE /* Cursor.swift */; };
|
||||
A5CBD0592C9F37B10017A1AE /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CEAFFE29C2410700646FDA /* Backport.swift */; };
|
||||
A5CBD06B2CA322430017A1AE /* GlobalEventTap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD06A2CA322320017A1AE /* GlobalEventTap.swift */; };
|
||||
A5CBD05C2CA0C5C70017A1AE /* SlideTerminal.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5CBD05B2CA0C5C70017A1AE /* SlideTerminal.xib */; };
|
||||
A5CBD05E2CA0C5EC0017A1AE /* SlideTerminalController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD05D2CA0C5E70017A1AE /* SlideTerminalController.swift */; };
|
||||
A5CBD0602CA0C90A0017A1AE /* SlideTerminalWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD05F2CA0C9080017A1AE /* SlideTerminalWindow.swift */; };
|
||||
A5CC36132C9CD72D004D6760 /* SecureInputOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CC36122C9CD729004D6760 /* SecureInputOverlay.swift */; };
|
||||
A5CC36152C9CDA06004D6760 /* View+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CC36142C9CDA03004D6760 /* View+Extension.swift */; };
|
||||
A5CDF1912AAF9A5800513312 /* ConfigurationErrors.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5CDF1902AAF9A5800513312 /* ConfigurationErrors.xib */; };
|
||||
@ -133,6 +136,9 @@
|
||||
A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableWindowView.swift; sourceTree = "<group>"; };
|
||||
A5CBD0572C9F30860017A1AE /* Cursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cursor.swift; sourceTree = "<group>"; };
|
||||
A5CBD06A2CA322320017A1AE /* GlobalEventTap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalEventTap.swift; sourceTree = "<group>"; };
|
||||
A5CBD05B2CA0C5C70017A1AE /* SlideTerminal.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SlideTerminal.xib; sourceTree = "<group>"; };
|
||||
A5CBD05D2CA0C5E70017A1AE /* SlideTerminalController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SlideTerminalController.swift; sourceTree = "<group>"; };
|
||||
A5CBD05F2CA0C9080017A1AE /* SlideTerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SlideTerminalWindow.swift; sourceTree = "<group>"; };
|
||||
A5CC36122C9CD729004D6760 /* SecureInputOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInputOverlay.swift; sourceTree = "<group>"; };
|
||||
A5CC36142C9CDA03004D6760 /* View+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extension.swift"; sourceTree = "<group>"; };
|
||||
A5CDF1902AAF9A5800513312 /* ConfigurationErrors.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConfigurationErrors.xib; sourceTree = "<group>"; };
|
||||
@ -204,6 +210,7 @@
|
||||
A5CBD0672CA2704E0017A1AE /* Global Keybinds */,
|
||||
A56D58872ACDE6BE00508D2C /* Services */,
|
||||
A59630982AEE1C4400D64628 /* Terminal */,
|
||||
A5CBD05A2CA0C5910017A1AE /* SlideTerminal */,
|
||||
A5E112912AF73E4D00C6E0C2 /* ClipboardConfirmation */,
|
||||
A57D79252C9C8782001D522E /* Secure Input */,
|
||||
A534263E2A7DCC5800EBB7A2 /* Settings */,
|
||||
@ -381,6 +388,16 @@
|
||||
path = "Global Keybinds";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A5CBD05A2CA0C5910017A1AE /* SlideTerminal */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A5CBD05B2CA0C5C70017A1AE /* SlideTerminal.xib */,
|
||||
A5CBD05D2CA0C5E70017A1AE /* SlideTerminalController.swift */,
|
||||
A5CBD05F2CA0C9080017A1AE /* SlideTerminalWindow.swift */,
|
||||
);
|
||||
path = SlideTerminal;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A5CEAFDA29B8005900646FDA /* SplitView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -506,6 +523,7 @@
|
||||
A5985CE62C33060F00C57AD3 /* man in Resources */,
|
||||
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */,
|
||||
552964E62B34A9B400030505 /* vim in Resources */,
|
||||
A5CBD05C2CA0C5C70017A1AE /* SlideTerminal.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -533,6 +551,8 @@
|
||||
A596309C2AEE1C9E00D64628 /* TerminalController.swift in Sources */,
|
||||
A5CC36152C9CDA06004D6760 /* View+Extension.swift in Sources */,
|
||||
A56D58892ACDE6CA00508D2C /* ServiceProvider.swift in Sources */,
|
||||
A5CBD0602CA0C90A0017A1AE /* SlideTerminalWindow.swift in Sources */,
|
||||
A5CBD05E2CA0C5EC0017A1AE /* SlideTerminalController.swift in Sources */,
|
||||
A51BFC222B2FB6B400E92F16 /* AboutView.swift in Sources */,
|
||||
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
|
||||
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */,
|
||||
|
@ -156,6 +156,8 @@ class AppDelegate: NSObject,
|
||||
center.delegate = self
|
||||
}
|
||||
|
||||
var foo: SlideTerminalController? = nil
|
||||
|
||||
func applicationDidBecomeActive(_ notification: Notification) {
|
||||
guard !applicationHasBecomeActive else { return }
|
||||
applicationHasBecomeActive = true
|
||||
@ -165,8 +167,11 @@ class AppDelegate: NSObject,
|
||||
// - if we're opening a URL since `application(_:openFile:)` is called before this.
|
||||
// - if we're restoring from persisted state
|
||||
if terminalManager.windows.count == 0 {
|
||||
terminalManager.newWindow()
|
||||
//terminalManager.newWindow()
|
||||
}
|
||||
|
||||
foo = SlideTerminalController(window: nil)
|
||||
foo?.showWindow(self)
|
||||
}
|
||||
|
||||
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||
|
31
macos/Sources/Features/SlideTerminal/SlideTerminal.xib
Normal file
31
macos/Sources/Features/SlideTerminal/SlideTerminal.xib
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23094" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23094"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="SlideTerminalController" customModule="Ghostty" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="window" destination="QvC-M9-y7g" id="JMU-zX-9Ie"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<window title="👻 Ghostty" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="SlideTerminalWindow" customModule="Ghostty" customModuleProvider="target">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="3008" height="1667"/>
|
||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="-2" id="u5f-FR-jJw"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="132" y="-82"/>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
@ -0,0 +1,62 @@
|
||||
import Foundation
|
||||
import Cocoa
|
||||
import SwiftUI
|
||||
import GhosttyKit
|
||||
|
||||
/// Controller for the slide-style terminal.
|
||||
class SlideTerminalController: NSWindowController {
|
||||
override var windowNibName: NSNib.Name? { "SlideTerminal" }
|
||||
|
||||
override func windowDidLoad() {
|
||||
guard let window = self.window else { return }
|
||||
|
||||
// Make the window full width
|
||||
let screenFrame = NSScreen.main?.frame ?? .zero
|
||||
window.setFrame(NSRect(
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: screenFrame.size.width,
|
||||
height: window.frame.size.height
|
||||
), display: false)
|
||||
|
||||
slideWindowIn(window: window)
|
||||
}
|
||||
|
||||
private func slideWindowIn(window: NSWindow) {
|
||||
guard let screen = NSScreen.main else { return }
|
||||
|
||||
// Determine our final position. Our final position is exactly
|
||||
// pinned against the top menu bar.
|
||||
let windowFrame = window.frame
|
||||
let finalY = screen.visibleFrame.maxY - windowFrame.height
|
||||
|
||||
// Move our window off screen to the top
|
||||
window.setFrameOrigin(.init(
|
||||
x: windowFrame.origin.x,
|
||||
y: screen.frame.maxY))
|
||||
|
||||
// Set the window invisible
|
||||
window.alphaValue = 0
|
||||
|
||||
// Move it to the visible position since animation requires this
|
||||
window.makeKeyAndOrderFront(nil)
|
||||
|
||||
// Run the animation that moves our window into the proper place and makes
|
||||
// it visible.
|
||||
NSAnimationContext.runAnimationGroup { context in
|
||||
context.duration = 0.3
|
||||
context.timingFunction = .init(name: .easeIn)
|
||||
|
||||
let animator = window.animator()
|
||||
animator.setFrame(.init(
|
||||
origin: .init(x: windowFrame.origin.x, y: finalY),
|
||||
size: windowFrame.size
|
||||
), display: true)
|
||||
animator.alphaValue = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum SlideTerminalLocation {
|
||||
case top
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import Cocoa
|
||||
|
||||
class SlideTerminalWindow: NSWindow {
|
||||
// Both of these must be true for windows without decorations to be able to
|
||||
// still become key/main and receive events.
|
||||
override var canBecomeKey: Bool { return true }
|
||||
override var canBecomeMain: Bool { return true }
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
// Note: almost all of this stuff can be done in the nib/xib directly
|
||||
// but I prefer to do it programmatically because the properties we
|
||||
// care about are less hidden.
|
||||
|
||||
// Remove the title completely. This will make the window square. One
|
||||
// downside is it also hides the cursor indications of resize but the
|
||||
// window remains resizable.
|
||||
self.styleMask.remove(.titled)
|
||||
|
||||
// We need to set our window level to a high value. In testing, only
|
||||
// popUpMenu and above do what we want. This gets it above the menu bar
|
||||
// and lets us render off screen.
|
||||
self.level = .popUpMenu
|
||||
|
||||
self.isMovableByWindowBackground = true
|
||||
self.isMovable = true
|
||||
|
||||
self.collectionBehavior = [
|
||||
// We want this to be part of every space because it is a singleton.
|
||||
.canJoinAllSpaces,
|
||||
|
||||
// We don't want to be part of command-tilde
|
||||
.ignoresCycle,
|
||||
|
||||
// We never support fullscreen
|
||||
.fullScreenNone]
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user