mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 17:26:09 +03:00
Move unzoom button logic into TerminalWindow
This fixed some bugs with keeping the correct button state when reordering tabs
This commit is contained in:
@ -55,8 +55,6 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
|||||||
/// For example, terminals executing custom scripts are not restorable.
|
/// For example, terminals executing custom scripts are not restorable.
|
||||||
private var restorable: Bool = true
|
private var restorable: Bool = true
|
||||||
|
|
||||||
private var surfaceIsZoomed: Bool = false
|
|
||||||
|
|
||||||
init(_ ghostty: Ghostty.App,
|
init(_ ghostty: Ghostty.App,
|
||||||
withBaseConfig base: Ghostty.SurfaceConfiguration? = nil,
|
withBaseConfig base: Ghostty.SurfaceConfiguration? = nil,
|
||||||
withSurfaceTree tree: Ghostty.SplitNode? = nil
|
withSurfaceTree tree: Ghostty.SplitNode? = nil
|
||||||
@ -123,7 +121,7 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
|||||||
// Reset this to false. It'll be set back to true later.
|
// Reset this to false. It'll be set back to true later.
|
||||||
tabListenForFrame = false
|
tabListenForFrame = false
|
||||||
|
|
||||||
guard let windows = self.window?.tabbedWindows else { return }
|
guard let windows = self.window?.tabbedWindows as? [TerminalWindow] else { return }
|
||||||
|
|
||||||
// We only listen for frame changes if we have more than 1 window,
|
// We only listen for frame changes if we have more than 1 window,
|
||||||
// otherwise the accessory view doesn't matter.
|
// otherwise the accessory view doesn't matter.
|
||||||
@ -135,24 +133,7 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let attributes: [NSAttributedString.Key: Any] = [
|
window.keyEquivalent = "\(equiv)"
|
||||||
.font: NSFont.labelFont(ofSize: 0),
|
|
||||||
.foregroundColor: window.isKeyWindow ? NSColor.labelColor : NSColor.secondaryLabelColor,
|
|
||||||
]
|
|
||||||
let attributedString = NSAttributedString(string: " \(equiv) ", attributes: attributes)
|
|
||||||
let text = NSTextField(labelWithAttributedString: attributedString)
|
|
||||||
text.setContentCompressionResistancePriority(.windowSizeStayPut, for: .horizontal)
|
|
||||||
text.postsFrameChangedNotifications = true
|
|
||||||
|
|
||||||
window.tab.accessoryView = NSStackView(views: [text])
|
|
||||||
}
|
|
||||||
|
|
||||||
if surfaceIsZoomed {
|
|
||||||
guard let stackView = window?.tabGroup?.selectedWindow?.tab.accessoryView as? NSStackView,
|
|
||||||
let buttonView = window?.toolbar?.items.first(where: { $0.itemIdentifier == .unZoom })?.view
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
stackView.addArrangedSubview(buttonView)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,12 +193,6 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateToolbarUnZoomButton() {
|
|
||||||
guard let buttonView = window?.toolbar?.items.first(where: { $0.itemIdentifier == .unZoom })?.view else { return }
|
|
||||||
|
|
||||||
buttonView.isHidden = !surfaceIsZoomed
|
|
||||||
}
|
|
||||||
|
|
||||||
//MARK: - NSWindowController
|
//MARK: - NSWindowController
|
||||||
|
|
||||||
override func windowWillLoad() {
|
override func windowWillLoad() {
|
||||||
@ -290,13 +265,6 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set a toolbar that is used with toolbar tabs
|
|
||||||
let toolbar = TerminalToolbar(identifier: "Toolbar")
|
|
||||||
toolbar.hasTitle = ghostty.config.macosTitlebarTabs
|
|
||||||
|
|
||||||
window.toolbar = toolbar
|
|
||||||
window.toolbarStyle = .unifiedCompact
|
|
||||||
|
|
||||||
// Initialize our content view to the SwiftUI root
|
// Initialize our content view to the SwiftUI root
|
||||||
window.contentView = NSHostingView(rootView: TerminalView(
|
window.contentView = NSHostingView(rootView: TerminalView(
|
||||||
ghostty: self.ghostty,
|
ghostty: self.ghostty,
|
||||||
@ -412,10 +380,6 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func windowDidUpdate(_ notification: Notification) {
|
|
||||||
updateToolbarUnZoomButton()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called when the window will be encoded. We handle the data encoding here in the
|
// Called when the window will be encoded. We handle the data encoding here in the
|
||||||
// window controller.
|
// window controller.
|
||||||
func window(_ window: NSWindow, willEncodeRestorableState state: NSCoder) {
|
func window(_ window: NSWindow, willEncodeRestorableState state: NSCoder) {
|
||||||
@ -618,9 +582,8 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func zoomStateDidChange(to: Bool) {
|
func zoomStateDidChange(to: Bool) {
|
||||||
self.surfaceIsZoomed = to
|
guard let window = window as? TerminalWindow else { return }
|
||||||
updateToolbarUnZoomButton()
|
window.surfaceIsZoomed = to
|
||||||
relabelTabs()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: - Clipboard Confirmation
|
//MARK: - Clipboard Confirmation
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class TerminalWindow: NSWindow {
|
class TerminalWindow: NSWindow {
|
||||||
|
@objc dynamic var surfaceIsZoomed: Bool = false
|
||||||
|
@objc dynamic var keyEquivalent: String = ""
|
||||||
|
|
||||||
var titlebarOpacity: CGFloat = 1 {
|
var titlebarOpacity: CGFloat = 1 {
|
||||||
didSet {
|
didSet {
|
||||||
guard let titlebarContainer = contentView?.superview?.subviews.first(where: {
|
guard let titlebarContainer = contentView?.superview?.subviews.first(where: {
|
||||||
@ -12,15 +15,97 @@ class TerminalWindow: NSWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var unZoomToolbarButton: NSButton? {
|
||||||
|
guard let button = toolbar?.items.first(where: { $0.itemIdentifier == .unZoom })?.view?.subviews.first as? NSButton
|
||||||
|
else { return nil }
|
||||||
|
|
||||||
|
return button
|
||||||
|
}
|
||||||
|
|
||||||
|
private let unZoomTabButton: NSButton = {
|
||||||
|
let button = NSButton()
|
||||||
|
button.target = nil
|
||||||
|
button.action = #selector(TerminalController.splitZoom(_:))
|
||||||
|
button.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
button.widthAnchor.constraint(equalToConstant: 20).isActive = true
|
||||||
|
button.heightAnchor.constraint(equalToConstant: 20).isActive = true
|
||||||
|
button.isBordered = false
|
||||||
|
button.contentTintColor = .controlAccentColor
|
||||||
|
button.state = .on
|
||||||
|
button.image = NSImage(systemSymbolName: "arrow.down.right.and.arrow.up.left.square.fill", accessibilityDescription: nil)!
|
||||||
|
.withSymbolConfiguration(NSImage.SymbolConfiguration(scale: .large))
|
||||||
|
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var keyEquivalentLabel: NSTextField = {
|
||||||
|
let label = NSTextField(labelWithAttributedString: NSAttributedString())
|
||||||
|
label.setContentCompressionResistancePriority(.windowSizeStayPut, for: .horizontal)
|
||||||
|
label.postsFrameChangedNotifications = true
|
||||||
|
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var bindings = [
|
||||||
|
observe(\.surfaceIsZoomed, options: [.initial, .new]) { [weak self] window, _ in
|
||||||
|
guard let unZoomToolbarButton = self?.unZoomToolbarButton, let tabGroup = self?.tabGroup else { return }
|
||||||
|
|
||||||
|
self?.unZoomTabButton.isHidden = !window.surfaceIsZoomed
|
||||||
|
self?.updateUnZoomToolbarButtonVisibility()
|
||||||
|
},
|
||||||
|
|
||||||
|
observe(\.keyEquivalent, options: [.initial, .new]) { [weak self] window, _ in
|
||||||
|
let attributes: [NSAttributedString.Key: Any] = [
|
||||||
|
.font: NSFont.systemFont(ofSize: NSFont.smallSystemFontSize),
|
||||||
|
.foregroundColor: window.isKeyWindow ? NSColor.labelColor : NSColor.secondaryLabelColor,
|
||||||
|
]
|
||||||
|
let attributedString = NSAttributedString(string: " \(window.keyEquivalent) ", attributes: attributes)
|
||||||
|
|
||||||
|
self?.keyEquivalentLabel.attributedStringValue = attributedString
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
// Both of these must be true for windows without decorations to be able to
|
// Both of these must be true for windows without decorations to be able to
|
||||||
// still become key/main and receive events.
|
// still become key/main and receive events.
|
||||||
override var canBecomeKey: Bool { return true }
|
override var canBecomeKey: Bool { return true }
|
||||||
override var canBecomeMain: Bool { return true }
|
override var canBecomeMain: Bool { return true }
|
||||||
|
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
|
||||||
|
override func awakeFromNib() {
|
||||||
|
super.awakeFromNib()
|
||||||
|
|
||||||
|
// By hiding the visual effect view, we allow the window's (or titlebar's in this case)
|
||||||
|
// background color to show through. If we were to set `titlebarAppearsTransparent` to true
|
||||||
|
// the selected tab would look fine, but the unselected ones and new tab button backgrounds
|
||||||
|
// would be an opaque color. When the titlebar isn't transparent, however, the system applies
|
||||||
|
// a compositing effect to the unselected tab backgrounds, which makes them blend with the
|
||||||
|
// titlebar's/window's background.
|
||||||
|
if let titlebarContainer = contentView?.superview?.subviews.first(where: {
|
||||||
|
$0.className == "NSTitlebarContainerView"
|
||||||
|
}), let effectView = titlebarContainer.descendants(withClassName: "NSVisualEffectView").first {
|
||||||
|
effectView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the tab accessory view that houses the key-equivalent label and optional un-zoom button
|
||||||
|
let stackView = NSStackView(views: [keyEquivalentLabel, unZoomTabButton])
|
||||||
|
stackView.setHuggingPriority(.defaultHigh, for: .horizontal)
|
||||||
|
stackView.spacing = 3
|
||||||
|
tab.accessoryView = stackView
|
||||||
|
|
||||||
|
generateToolbar()
|
||||||
|
|
||||||
|
_ = bindings
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
bindings.forEach() { $0.invalidate() }
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - NSWindow
|
// MARK: - NSWindow
|
||||||
|
|
||||||
override func becomeKey() {
|
override func becomeKey() {
|
||||||
// This is required because the removeTitlebarAccessoryViewControlle hook does not
|
// This is required because the removeTitlebarAccessoryViewController hook does not
|
||||||
// catch the creation of a new window by "tearing off" a tab from a tabbed window.
|
// catch the creation of a new window by "tearing off" a tab from a tabbed window.
|
||||||
if let tabGroup = self.tabGroup, tabGroup.windows.count < 2 {
|
if let tabGroup = self.tabGroup, tabGroup.windows.count < 2 {
|
||||||
hideCustomTabBarViews()
|
hideCustomTabBarViews()
|
||||||
@ -28,17 +113,99 @@ class TerminalWindow: NSWindow {
|
|||||||
|
|
||||||
super.becomeKey()
|
super.becomeKey()
|
||||||
|
|
||||||
if titlebarTabs {
|
|
||||||
updateNewTabButtonOpacity()
|
updateNewTabButtonOpacity()
|
||||||
}
|
unZoomTabButton.isEnabled = true
|
||||||
|
unZoomTabButton.contentTintColor = .controlAccentColor
|
||||||
|
unZoomToolbarButton?.contentTintColor = .controlAccentColor
|
||||||
}
|
}
|
||||||
|
|
||||||
override func resignKey() {
|
override func resignKey() {
|
||||||
super.resignKey()
|
super.resignKey()
|
||||||
|
|
||||||
if titlebarTabs {
|
|
||||||
updateNewTabButtonOpacity()
|
updateNewTabButtonOpacity()
|
||||||
|
unZoomTabButton.isEnabled = false
|
||||||
|
unZoomTabButton.contentTintColor = .labelColor
|
||||||
|
unZoomToolbarButton?.contentTintColor = .tertiaryLabelColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func update() {
|
||||||
|
super.update()
|
||||||
|
|
||||||
|
updateUnZoomToolbarButtonVisibility()
|
||||||
|
|
||||||
|
titlebarSeparatorStyle = tabbedWindows != nil && !titlebarTabs ? .line : .none
|
||||||
|
|
||||||
|
// This is called when we open, close, switch, and reorder tabs, at which point we determine if the
|
||||||
|
// first tab in the tab bar is selected. If it is, we make the `windowButtonsBackdrop` color the same
|
||||||
|
// as that of the active tab (i.e. the titlebar's background color), otherwise we make it the same
|
||||||
|
// color as the background of unselected tabs.
|
||||||
|
if let index = windowController?.window?.tabbedWindows?.firstIndex(of: self), titlebarTabs {
|
||||||
|
windowButtonsBackdrop?.isHighlighted = index == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Color the new tab button's image to match the color of the tab title/keyboard shortcut labels,
|
||||||
|
// just as it does in the stock tab bar.
|
||||||
|
updateNewTabButtonOpacity()
|
||||||
|
|
||||||
|
guard let titlebarContainer = contentView?.superview?.subviews.first(where: {
|
||||||
|
$0.className == "NSTitlebarContainerView"
|
||||||
|
}) else { return }
|
||||||
|
guard let newTabButton: NSButton = titlebarContainer.firstDescendant(withClassName: "NSTabBarNewTabButton") as? NSButton else { return }
|
||||||
|
guard let newTabButtonImageView: NSImageView = newTabButton.subviews.first(where: {
|
||||||
|
$0 as? NSImageView != nil
|
||||||
|
}) as? NSImageView else { return }
|
||||||
|
guard let newTabButtonImage = newTabButtonImageView.image else { return }
|
||||||
|
|
||||||
|
let isLightTheme = backgroundColor.isLightColor
|
||||||
|
|
||||||
|
if newTabButtonImageLayer == nil {
|
||||||
|
let fillColor: NSColor = isLightTheme ? .black.withAlphaComponent(0.85) : .white.withAlphaComponent(0.85)
|
||||||
|
let newImage = NSImage(size: newTabButtonImage.size, flipped: false) { rect in
|
||||||
|
newTabButtonImage.draw(in: rect)
|
||||||
|
fillColor.setFill()
|
||||||
|
rect.fill(using: .sourceAtop)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
let imageLayer = VibrantLayer(forAppearance: isLightTheme ? .light : .dark)!
|
||||||
|
imageLayer.frame = NSRect(origin: NSPoint(x: newTabButton.bounds.midX - newTabButtonImage.size.width/2, y: newTabButton.bounds.midY - newTabButtonImage.size.height/2), size: newTabButtonImage.size)
|
||||||
|
imageLayer.contentsGravity = .resizeAspect
|
||||||
|
imageLayer.contents = newImage
|
||||||
|
imageLayer.opacity = 0.5
|
||||||
|
|
||||||
|
newTabButtonImageLayer = imageLayer
|
||||||
|
}
|
||||||
|
|
||||||
|
newTabButtonImageView.layer?.sublayers?.first(where: { $0.className == "VibrantLayer" })?.removeFromSuperlayer()
|
||||||
|
newTabButtonImageView.layer?.addSublayer(newTabButtonImageLayer!)
|
||||||
|
newTabButtonImageView.image = nil
|
||||||
|
// When we nil out the original image, the image view's frame resizes and repositions
|
||||||
|
// slightly, so we need to reset it to make sure our new image doesn't shift quickly.
|
||||||
|
newTabButtonImageView.frame = newTabButton.bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
|
private func updateUnZoomToolbarButtonVisibility() {
|
||||||
|
guard let unZoomToolbarButton = unZoomToolbarButton, let tabGroup else { return }
|
||||||
|
|
||||||
|
if tabGroup.isTabBarVisible {
|
||||||
|
unZoomToolbarButton.isHidden = true
|
||||||
|
} else {
|
||||||
|
unZoomToolbarButton.isHidden = !surfaceIsZoomed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to regenerate a toolbar when the titlebar tabs setting changes since our
|
||||||
|
// custom toolbar conditionally generates the items based on this setting. I tried to
|
||||||
|
// invalidate the toolbar items and force a refresh, but as far as I can tell that
|
||||||
|
// isn't possible.
|
||||||
|
private func generateToolbar() {
|
||||||
|
let terminalToolbar = TerminalToolbar(identifier: "Toolbar")
|
||||||
|
terminalToolbar.hasTitle = titlebarTabs
|
||||||
|
|
||||||
|
toolbar = terminalToolbar
|
||||||
|
toolbarStyle = .unifiedCompact
|
||||||
|
updateUnZoomToolbarButtonVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Titlebar Tabs
|
// MARK: - Titlebar Tabs
|
||||||
@ -47,6 +214,7 @@ class TerminalWindow: NSWindow {
|
|||||||
var titlebarTabs = false {
|
var titlebarTabs = false {
|
||||||
didSet {
|
didSet {
|
||||||
self.titleVisibility = titlebarTabs ? .hidden : .visible
|
self.titleVisibility = titlebarTabs ? .hidden : .visible
|
||||||
|
generateToolbar()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,22 +244,6 @@ class TerminalWindow: NSWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func awakeFromNib() {
|
|
||||||
super.awakeFromNib()
|
|
||||||
|
|
||||||
// By hiding the visual effect view, we allow the window's (or titlebar's in this case)
|
|
||||||
// background color to show through. If we were to set `titlebarAppearsTransparent` to true
|
|
||||||
// the selected tab would look fine, but the unselected ones and new tab button backgrounds
|
|
||||||
// would be an opaque color. When the titlebar isn't transparent, however, the system applies
|
|
||||||
// a compositing effect to the unselected tab backgrounds, which makes them blend with the
|
|
||||||
// titlebar's/window's background.
|
|
||||||
if let titlebarContainer = contentView?.superview?.subviews.first(where: {
|
|
||||||
$0.className == "NSTitlebarContainerView"
|
|
||||||
}), let effectView = titlebarContainer.descendants(withClassName: "NSVisualEffectView").first {
|
|
||||||
effectView.isHidden = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is called by macOS for native tabbing in order to add the tab bar. We hook into
|
// This is called by macOS for native tabbing in order to add the tab bar. We hook into
|
||||||
// this, detect the tab bar being added, and override its behavior.
|
// this, detect the tab bar being added, and override its behavior.
|
||||||
override func addTitlebarAccessoryViewController(_ childViewController: NSTitlebarAccessoryViewController) {
|
override func addTitlebarAccessoryViewController(_ childViewController: NSTitlebarAccessoryViewController) {
|
||||||
@ -174,59 +326,6 @@ class TerminalWindow: NSWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func update() {
|
|
||||||
super.update()
|
|
||||||
|
|
||||||
titlebarSeparatorStyle = tabbedWindows != nil && !titlebarTabs ? .line : .none
|
|
||||||
|
|
||||||
// This is called when we open, close, switch, and reorder tabs, at which point we determine if the
|
|
||||||
// first tab in the tab bar is selected. If it is, we make the `windowButtonsBackdrop` color the same
|
|
||||||
// as that of the active tab (i.e. the titlebar's background color), otherwise we make it the same
|
|
||||||
// color as the background of unselected tabs.
|
|
||||||
if let index = windowController?.window?.tabbedWindows?.firstIndex(of: self), titlebarTabs {
|
|
||||||
windowButtonsBackdrop?.isHighlighted = index == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Color the new tab button's image to match the color of the tab title/keyboard shortcut labels,
|
|
||||||
// just as it does in the stock tab bar.
|
|
||||||
updateNewTabButtonOpacity()
|
|
||||||
|
|
||||||
guard let titlebarContainer = contentView?.superview?.subviews.first(where: {
|
|
||||||
$0.className == "NSTitlebarContainerView"
|
|
||||||
}) else { return }
|
|
||||||
guard let newTabButton: NSButton = titlebarContainer.firstDescendant(withClassName: "NSTabBarNewTabButton") as? NSButton else { return }
|
|
||||||
guard let newTabButtonImageView: NSImageView = newTabButton.subviews.first(where: {
|
|
||||||
$0 as? NSImageView != nil
|
|
||||||
}) as? NSImageView else { return }
|
|
||||||
guard let newTabButtonImage = newTabButtonImageView.image else { return }
|
|
||||||
|
|
||||||
let isLightTheme = backgroundColor.isLightColor
|
|
||||||
|
|
||||||
if newTabButtonImageLayer == nil {
|
|
||||||
let fillColor: NSColor = isLightTheme ? .black.withAlphaComponent(0.85) : .white.withAlphaComponent(0.85)
|
|
||||||
let newImage = NSImage(size: newTabButtonImage.size, flipped: false) { rect in
|
|
||||||
newTabButtonImage.draw(in: rect)
|
|
||||||
fillColor.setFill()
|
|
||||||
rect.fill(using: .sourceAtop)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
let imageLayer = VibrantLayer(forAppearance: isLightTheme ? .light : .dark)!
|
|
||||||
imageLayer.frame = NSRect(origin: NSPoint(x: newTabButton.bounds.midX - newTabButtonImage.size.width/2, y: newTabButton.bounds.midY - newTabButtonImage.size.height/2), size: newTabButtonImage.size)
|
|
||||||
imageLayer.contentsGravity = .resizeAspect
|
|
||||||
imageLayer.contents = newImage
|
|
||||||
imageLayer.opacity = 0.5
|
|
||||||
|
|
||||||
newTabButtonImageLayer = imageLayer
|
|
||||||
}
|
|
||||||
|
|
||||||
newTabButtonImageView.layer?.sublayers?.first(where: { $0.className == "VibrantLayer" })?.removeFromSuperlayer()
|
|
||||||
newTabButtonImageView.layer?.addSublayer(newTabButtonImageLayer!)
|
|
||||||
newTabButtonImageView.image = nil
|
|
||||||
// When we nil out the original image, the image view's frame resizes and repositions
|
|
||||||
// slightly, so we need to reset it to make sure our new image doesn't shift quickly.
|
|
||||||
newTabButtonImageView.frame = newTabButton.bounds
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we are coloring the new tab button's image, it doesn't respond to the
|
// Since we are coloring the new tab button's image, it doesn't respond to the
|
||||||
// window's key status changes in terms of becoming less prominent visually,
|
// window's key status changes in terms of becoming less prominent visually,
|
||||||
// so we need to do it manually.
|
// so we need to do it manually.
|
||||||
|
Reference in New Issue
Block a user