feat: show notification badges on top of app icons (closes #523)
This commit is contained in:
1 parent
d3253ba4e1
commit
fb628341d1
32 files changed
+141
-36
No files matched your search
Binary file not shown.
@@ -127,6 +127,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Hidden" = "Hidden";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "مخفي";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Versteckt";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Bunte Kreise beim Markieren mit Maus verbergen:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Hidden";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Ocultas";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Piilossa";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Cachées";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Rejtett";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Tersembunyi";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Nascosto";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "ウィンドウをしまう";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "숨겨진 화면";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "마우스를 올릴 때 색칠된 원들 숨기기:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Verstoppen";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Verborgen";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Escondido";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Esconder círculos coloridos onde o rato passar:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Скрытые";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Скрыть цветные круги при наведении мышью:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "Gizli";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "隐藏";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "鼠标悬停时隐藏彩色圆圈:";
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/*No comment provided by engineer.*/
|
||||
"Hidden" = "隱藏";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide app badges:" = "Hide app badges:";
|
||||
|
||||
/*No comment provided by engineer.*/
|
||||
"Hide colored circles on mouse hover:" = "Hide colored circles on mouse hover:";
|
||||
|
||||
|
||||
@@ -4,4 +4,4 @@ set -exu
|
||||
|
||||
"$(pipenv --venv)"/bin/pyftsubset resources/SF-Pro-Text-Regular-Full.otf \
|
||||
--output-file=resources/SF-Pro-Text-Regular.otf \
|
||||
--text=""
|
||||
--text=""
|
||||
@@ -116,6 +116,10 @@ extension AXUIElement {
|
||||
return try attribute(kAXParentAttribute, AXUIElement.self)
|
||||
}
|
||||
|
||||
func children() throws -> [AXUIElement]? {
|
||||
return try attribute(kAXChildrenAttribute, [AXUIElement].self)
|
||||
}
|
||||
|
||||
func windows() throws -> [AXUIElement]? {
|
||||
return try attribute(kAXWindowsAttribute, [AXUIElement].self)
|
||||
}
|
||||
@@ -140,6 +144,10 @@ extension AXUIElement {
|
||||
return try attribute(kAXSubroleAttribute, String.self)
|
||||
}
|
||||
|
||||
func appIsRunning() throws -> Bool? {
|
||||
return try attribute(kAXIsApplicationRunningAttribute, Bool.self)
|
||||
}
|
||||
|
||||
func closeButton() throws -> AXUIElement? {
|
||||
return try attribute(kAXCloseButtonAttribute, AXUIElement.self)
|
||||
}
|
||||
|
||||
@@ -121,8 +121,9 @@ func CGSGetWindowLevel(_ cid: CGSConnectionID, _ wid: CGWindowID, _ level: inout
|
||||
@_silgen_name("SLSRequestScreenCaptureAccess") @discardableResult
|
||||
func SLSRequestScreenCaptureAccess() -> UInt8
|
||||
|
||||
// for some reason, this attribute is missing from AXAttributeConstants
|
||||
// for some reason, these attributes are missing from AXAttributeConstants
|
||||
let kAXFullscreenAttribute = "AXFullScreen"
|
||||
let kAXStatusLabelAttribute = "AXStatusLabel"
|
||||
|
||||
// enables/disables a symbolic hotkeys. These are system shortcuts such as command+tab or Spotlight
|
||||
// it is possible to find all the existing hotkey IDs by using CGSGetSymbolicHotKeyValue on the first few hundred numbers
|
||||
|
||||
@@ -7,6 +7,7 @@ class Application: NSObject {
|
||||
var axUiElement: AXUIElement?
|
||||
var axObserver: AXObserver?
|
||||
var isReallyFinishedLaunching = false
|
||||
var dockLabel: String?
|
||||
|
||||
static func notifications(_ app: NSRunningApplication) -> [String] {
|
||||
var n = [
|
||||
|
||||
@@ -73,6 +73,21 @@ class Applications {
|
||||
App.app.refreshOpenUi()
|
||||
}
|
||||
|
||||
static func refreshBadges() {
|
||||
retryAxCallUntilTimeout {
|
||||
let axDock = AXUIElementCreateApplication(Applications.list.first { $0.runningApplication.bundleIdentifier == "com.apple.dock" }!.runningApplication.processIdentifier)
|
||||
let axList = try axDock.children()!.first { try $0.role() == "AXList" }!
|
||||
let axAppDockItem = try axList.children()!.filter { try $0.subrole() == "AXApplicationDockItem" && ($0.appIsRunning() ?? false) }
|
||||
try Applications.list.forEach { app in
|
||||
if app.runningApplication.activationPolicy == .regular,
|
||||
let bundleId = app.runningApplication.bundleIdentifier,
|
||||
let url = NSWorkspace.shared.urlForApplication(withBundleIdentifier: bundleId) {
|
||||
app.dockLabel = try axAppDockItem.first { try $0.attribute(kAXURLAttribute, URL.self) == url }?.attribute(kAXStatusLabelAttribute, String.self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static func isActualApplication(_ app: NSRunningApplication) -> Bool {
|
||||
return (app.activationPolicy != .prohibited || isNotXpc(app)) && notAltTab(app)
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ class Preferences {
|
||||
"minCellsPerRow": defaultsDependingOnScreenRatio_["minCellsPerRow"]!,
|
||||
"maxCellsPerRow": defaultsDependingOnScreenRatio_["maxCellsPerRow"]!,
|
||||
"shortcutStyle": "0",
|
||||
"hideAppBadges": "false",
|
||||
]
|
||||
|
||||
// constant values
|
||||
@@ -96,6 +97,7 @@ class Preferences {
|
||||
static var fadeOutAnimation: Bool { defaults.bool("fadeOutAnimation") }
|
||||
static var hideSpaceNumberLabels: Bool { defaults.bool("hideSpaceNumberLabels") }
|
||||
static var hideStatusIcons: Bool { defaults.bool("hideStatusIcons") }
|
||||
static var hideAppBadges: Bool { defaults.bool("hideAppBadges") }
|
||||
static var startAtLogin: Bool { defaults.bool("startAtLogin") }
|
||||
static var dontShowBlacklist: [String] { blacklistStringToArray(defaults.string("dontShowBlacklist")) }
|
||||
static var disableShortcutsBlacklist: [String] { blacklistStringToArray(defaults.string("disableShortcutsBlacklist")) }
|
||||
|
||||
@@ -4,10 +4,11 @@ class Window {
|
||||
var cgWindowId: CGWindowID
|
||||
var title: String!
|
||||
var thumbnail: NSImage?
|
||||
var icon: NSImage?
|
||||
var icon: NSImage? { get { application.runningApplication.icon } }
|
||||
var shouldShowTheUser = true
|
||||
var isTabbed: Bool = false
|
||||
var isHidden: Bool
|
||||
var isHidden: Bool { get { application.runningApplication.isHidden } }
|
||||
var dockLabel: Int? { get { application.dockLabel.flatMap { Int($0) } } }
|
||||
var isFullscreen: Bool
|
||||
var isMinimized: Bool
|
||||
var isOnAllSpaces: Bool
|
||||
@@ -35,8 +36,6 @@ class Window {
|
||||
self.cgWindowId = wid
|
||||
self.spaceId = Spaces.currentSpaceId
|
||||
self.spaceIndex = Spaces.currentSpaceIndex
|
||||
self.icon = application.runningApplication.icon
|
||||
self.isHidden = application.runningApplication.isHidden
|
||||
self.isFullscreen = isFullscreen
|
||||
self.isMinimized = isMinimized
|
||||
self.isOnAllSpaces = false
|
||||
|
||||
@@ -86,11 +86,7 @@ private func applicationHiddenOrShown(_ element: AXUIElement, _ pid: pid_t, _ ty
|
||||
DispatchQueue.main.async {
|
||||
let windows = Windows.list.filter {
|
||||
// for AXUIElement of apps, CFEqual or == don't work; looks like a Cocoa bug
|
||||
let isFromApp = $0.application.runningApplication.processIdentifier == pid
|
||||
if isFromApp {
|
||||
$0.isHidden = type == kAXApplicationHiddenNotification
|
||||
}
|
||||
return isFromApp
|
||||
return $0.application.runningApplication.processIdentifier == pid
|
||||
}
|
||||
App.app.refreshOpenUi(windows)
|
||||
}
|
||||
|
||||
@@ -270,6 +270,8 @@ class App: AppCenterApplication, NSApplicationDelegate {
|
||||
guard appIsBeingUsed else { return }
|
||||
Windows.refreshAllThumbnails()
|
||||
guard appIsBeingUsed else { return }
|
||||
Applications.refreshBadges()
|
||||
guard appIsBeingUsed else { return }
|
||||
refreshOpenUi()
|
||||
guard appIsBeingUsed else { return }
|
||||
thumbnailsPanel.show()
|
||||
|
||||
@@ -7,22 +7,21 @@ enum Symbols: String {
|
||||
case circledNumber0 = ""
|
||||
case circledNumber10 = ""
|
||||
case circledStar = ""
|
||||
case filledCircledStar = ""
|
||||
case filledCircled = ""
|
||||
case filledCircledMultiplySign = ""
|
||||
case filledCircledMinusSign = ""
|
||||
case filledCircledPlusSign = ""
|
||||
case filledCircledNumber0 = ""
|
||||
case filledCircledNumber10 = ""
|
||||
}
|
||||
|
||||
// Font icon using SF Symbols from the SF Pro font from Apple
|
||||
// see https://developer.apple.com/design/human-interface-guidelines/sf-symbols/overview/
|
||||
class ThumbnailFontIconView: ThumbnailTitleView {
|
||||
convenience init(_ symbol: Symbols, _ size: CGFloat = Preferences.fontIconSize, _ color: NSColor = .white, _ isBackground: Bool = false) {
|
||||
convenience init(_ symbol: Symbols, _ size: CGFloat = Preferences.fontIconSize, _ color: NSColor = .white, _ shadow: NSShadow? = ThumbnailView.makeShadow(.darkGray)) {
|
||||
// This helps SF symbols display vertically centered and not clipped at the bottom
|
||||
if isBackground {
|
||||
self.init(size, 3, shadow: nil)
|
||||
} else {
|
||||
self.init(size, 3)
|
||||
}
|
||||
self.init(size, 3, shadow: shadow)
|
||||
string = symbol.rawValue
|
||||
font = NSFont(name: "SF Pro Text", size: size)
|
||||
textColor = color
|
||||
@@ -31,32 +30,39 @@ class ThumbnailFontIconView: ThumbnailTitleView {
|
||||
}
|
||||
|
||||
// number should be in the interval [0-50]
|
||||
func setNumber(_ number: UInt32) {
|
||||
let (baseCharacter, offset) = baseCharacterAndOffset(number)
|
||||
assignIfDifferent(&string, String(UnicodeScalar(baseCharacter.unicodeScalars.first!.value + offset)!))
|
||||
func setNumber(_ number: Int, _ filled: Bool) {
|
||||
let (baseCharacter, offset) = baseCharacterAndOffset(number, filled)
|
||||
assignIfDifferent(&string, String(UnicodeScalar(Int(baseCharacter.unicodeScalars.first!.value) + offset)!))
|
||||
}
|
||||
|
||||
private func baseCharacterAndOffset(_ number: Int, _ filled: Bool) -> (String, Int) {
|
||||
if number <= 9 {
|
||||
// numbers alternate between empty and full circles; we skip the full circles
|
||||
return ((filled ? Symbols.filledCircledNumber0 : Symbols.circledNumber0).rawValue, number * 2)
|
||||
} else {
|
||||
return ((filled ? Symbols.filledCircledNumber10 : Symbols.circledNumber10).rawValue, number - 10)
|
||||
}
|
||||
}
|
||||
|
||||
func setStar() {
|
||||
assignIfDifferent(&string, Symbols.circledStar.rawValue)
|
||||
}
|
||||
|
||||
private func baseCharacterAndOffset(_ number: UInt32) -> (String, UInt32) {
|
||||
if number <= 9 {
|
||||
// numbers alternate between empty and full circles; we skip the full circles
|
||||
return (Symbols.circledNumber0.rawValue, number * UInt32(2))
|
||||
} else {
|
||||
return (Symbols.circledNumber10.rawValue, number - 10)
|
||||
}
|
||||
func setFilledStar() {
|
||||
assignIfDifferent(&string, Symbols.filledCircledStar.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
class ThumbnailFilledFontIconView: NSView {
|
||||
convenience init(_ thumbnailFontIconView: ThumbnailFontIconView, _ backgroundColor: NSColor) {
|
||||
convenience init(_ thumbnailFontIconView: ThumbnailFontIconView, _ backgroundColor: NSColor, _ offset: Bool = false) {
|
||||
self.init(frame: .zero)
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
let backgroundView = ThumbnailFontIconView(.filledCircled, thumbnailFontIconView.font!.pointSize, backgroundColor, true)
|
||||
let backgroundView = ThumbnailFontIconView(.filledCircled, thumbnailFontIconView.font!.pointSize - (offset ? 2 : 0), backgroundColor)
|
||||
addSubview(backgroundView)
|
||||
addSubview(thumbnailFontIconView, positioned: .above, relativeTo: nil)
|
||||
fit(backgroundView.fittingSize.width, backgroundView.fittingSize.height)
|
||||
if offset {
|
||||
backgroundView.leftAnchor.constraint(equalTo: backgroundView.superview!.leftAnchor, constant: 1).isActive = true
|
||||
}
|
||||
fit(thumbnailFontIconView.fittingSize.width, thumbnailFontIconView.fittingSize.height)
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,10 @@ class ThumbnailView: NSStackView {
|
||||
var minimizedIcon = ThumbnailFontIconView(.circledMinusSign)
|
||||
var hiddenIcon = ThumbnailFontIconView(.circledSlashSign)
|
||||
var spaceIcon = ThumbnailFontIconView(.circledNumber0)
|
||||
var closeIcon = ThumbnailFilledFontIconView(ThumbnailFontIconView(.filledCircledMultiplySign, Preferences.fontIconSize, NSColor(srgbRed: 1, green: 0.35, blue: 0.32, alpha: 1)), NSColor(srgbRed: 0.64, green: 0.03, blue: 0.02, alpha: 1))
|
||||
var minimizeIcon = ThumbnailFilledFontIconView(ThumbnailFontIconView(.filledCircledMinusSign, Preferences.fontIconSize, NSColor(srgbRed: 0.91, green: 0.75, blue: 0.16, alpha: 1)), NSColor(srgbRed: 0.71, green: 0.55, blue: 0.09, alpha: 1))
|
||||
var maximizeIcon = ThumbnailFilledFontIconView(ThumbnailFontIconView(.filledCircledPlusSign, Preferences.fontIconSize, NSColor(srgbRed: 0.32, green: 0.76, blue: 0.17, alpha: 1)), NSColor(srgbRed: 0.04, green: 0.39, blue: 0.02, alpha: 1))
|
||||
var dockLabelIcon = ThumbnailFilledFontIconView(ThumbnailFontIconView(.filledCircledNumber0, (Preferences.fontIconSize * 0.7).rounded(), NSColor(srgbRed: 1, green: 0.30, blue: 0.25, alpha: 1), nil), NSColor.white, true)
|
||||
var closeIcon = ThumbnailFilledFontIconView(ThumbnailFontIconView(.filledCircledMultiplySign, Preferences.fontIconSize, NSColor(srgbRed: 1, green: 0.35, blue: 0.32, alpha: 1), nil), NSColor(srgbRed: 0.64, green: 0.03, blue: 0.02, alpha: 1))
|
||||
var minimizeIcon = ThumbnailFilledFontIconView(ThumbnailFontIconView(.filledCircledMinusSign, Preferences.fontIconSize, NSColor(srgbRed: 0.91, green: 0.75, blue: 0.16, alpha: 1), nil), NSColor(srgbRed: 0.71, green: 0.55, blue: 0.09, alpha: 1))
|
||||
var maximizeIcon = ThumbnailFilledFontIconView(ThumbnailFontIconView(.filledCircledPlusSign, Preferences.fontIconSize, NSColor(srgbRed: 0.32, green: 0.76, blue: 0.17, alpha: 1), nil), NSColor(srgbRed: 0.04, green: 0.39, blue: 0.02, alpha: 1))
|
||||
var hStackView: NSStackView!
|
||||
var mouseUpCallback: (() -> Void)!
|
||||
var mouseMovedCallback: (() -> Void)!
|
||||
@@ -42,9 +43,16 @@ class ThumbnailView: NSStackView {
|
||||
hStackView.spacing = Preferences.intraCellPadding
|
||||
setViews([hStackView, thumbnail], in: .leading)
|
||||
addWindowControls()
|
||||
addDockLabelIcon()
|
||||
}
|
||||
|
||||
func addWindowControls() {
|
||||
private func addDockLabelIcon() {
|
||||
appIcon.addSubview(dockLabelIcon, positioned: .above, relativeTo: nil)
|
||||
dockLabelIcon.topAnchor.constraint(equalTo: appIcon.topAnchor, constant: -4).isActive = true
|
||||
dockLabelIcon.rightAnchor.constraint(equalTo: appIcon.rightAnchor, constant: 1).isActive = true
|
||||
}
|
||||
|
||||
private func addWindowControls() {
|
||||
thumbnail.addSubview(closeIcon, positioned: .above, relativeTo: nil)
|
||||
thumbnail.addSubview(minimizeIcon, positioned: .above, relativeTo: nil)
|
||||
thumbnail.addSubview(maximizeIcon, positioned: .above, relativeTo: nil)
|
||||
@@ -117,10 +125,19 @@ class ThumbnailView: NSStackView {
|
||||
assignIfDifferent(&minimizedIcon.isHidden, !element.isMinimized || Preferences.hideStatusIcons)
|
||||
assignIfDifferent(&spaceIcon.isHidden, Spaces.isSingleSpace || Preferences.hideSpaceNumberLabels)
|
||||
if !spaceIcon.isHidden {
|
||||
if element.isOnAllSpaces {
|
||||
if element.spaceIndex > 30 || element.isOnAllSpaces {
|
||||
spaceIcon.setStar()
|
||||
} else {
|
||||
spaceIcon.setNumber(UInt32(element.spaceIndex))
|
||||
spaceIcon.setNumber(element.spaceIndex, false)
|
||||
}
|
||||
}
|
||||
assignIfDifferent(&dockLabelIcon.isHidden, element.dockLabel == nil || Preferences.hideAppBadges || Preferences.iconSize == 0)
|
||||
if !dockLabelIcon.isHidden, let dockLabel = element.dockLabel {
|
||||
let view = dockLabelIcon.subviews[1] as! ThumbnailFontIconView
|
||||
if dockLabel > 30 {
|
||||
view.setFilledStar()
|
||||
} else {
|
||||
view.setNumber(dockLabel, true)
|
||||
}
|
||||
}
|
||||
assignIfDifferent(&frame.size.width, max(thumbnail.frame.size.width + Preferences.intraCellPadding * 2, ThumbnailView.widthMin(screen)))
|
||||
|
||||
@@ -24,6 +24,7 @@ class AppearanceTab: NSViewController, PreferencePane {
|
||||
LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide status icons:", comment: ""), "hideStatusIcons"),
|
||||
LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Show standard tabs as windows:", comment: ""), "showTabsAsWindows"),
|
||||
LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide colored circles on mouse hover:", comment: ""), "hideColoredCircles"),
|
||||
LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide app badges:", comment: ""), "hideAppBadges"),
|
||||
])
|
||||
grid.column(at: 0).xPlacement = .trailing
|
||||
grid.rowAlignment = .lastBaseline
|
||||
|
||||
Reference in new issue
Block a user