Skip to content

Commit

Permalink
feat: new preference to hide thumbnails (closes #384)
Browse files Browse the repository at this point in the history
  • Loading branch information
lwouis committed Sep 4, 2020
1 parent df3010a commit 877c93c
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 37 deletions.
6 changes: 3 additions & 3 deletions src/logic/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ class Application: NSObject {

func addAndObserveWindows() {
if runningApplication.isFinishedLaunching && runningApplication.activationPolicy != .prohibited && axUiElement == nil {
axUiElement = AXUIElementCreateApplication(runningApplication.processIdentifier)
AXObserverCreate(runningApplication.processIdentifier, axObserverCallback, &axObserver)
debugPrint("Adding app", runningApplication.processIdentifier, runningApplication.bundleIdentifier ?? "nil")
axUiElement = AXUIElementCreateApplication(pid)
AXObserverCreate(pid, axObserverCallback, &axObserver)
debugPrint("Adding app", pid, runningApplication.bundleIdentifier ?? "nil")
observeEvents()
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/logic/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Preferences {
"shortcutStyle": "0",
"hideAppBadges": "false",
"hideWindowlessApps": "false",
"hideThumbnails": "false",
]

// constant values
Expand All @@ -69,7 +70,6 @@ class Preferences {
static var windowPadding: CGFloat { 18 }
static var interCellPadding: CGFloat { 5 }
static var intraCellPadding: CGFloat { 5 }
static var fontIconSize: CGFloat { 20 }

// persisted values
static var maxScreenUsage: CGFloat { defaults.cgfloat("maxScreenUsage") / CGFloat(100) }
Expand Down Expand Up @@ -100,6 +100,7 @@ class Preferences {
static var hideStatusIcons: Bool { defaults.bool("hideStatusIcons") }
static var hideAppBadges: Bool { defaults.bool("hideAppBadges") }
static var hideWindowlessApps: Bool { defaults.bool("hideWindowlessApps") }
static var hideThumbnails: Bool { defaults.bool("hideThumbnails") }
static var startAtLogin: Bool { defaults.bool("startAtLogin") }
static var dontShowBlacklist: [String] { blacklistStringToArray(defaults.string("dontShowBlacklist")) }
static var disableShortcutsBlacklist: [String] { blacklistStringToArray(defaults.string("disableShortcutsBlacklist")) }
Expand Down
2 changes: 1 addition & 1 deletion src/logic/Window.swift
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class Window {
}

func focus() {
if application.runningApplication.processIdentifier == ProcessInfo.processInfo.processIdentifier {
if application.pid == ProcessInfo.processInfo.processIdentifier {
App.app.showSecondaryWindow(App.app.window(withWindowNumber: Int(cgWindowId)))
} else if isWindowlessApp {
if let bundleID = application.runningApplication.bundleIdentifier {
Expand Down
2 changes: 2 additions & 0 deletions src/logic/Windows.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,15 @@ class Windows {
}

static func refreshFirstFewThumbnailsSync() {
if Preferences.hideThumbnails { return }
list.filter { $0.shouldShowTheUser }
.prefix(criticalFirstThumbnails)
.forEachAsync { window in window.refreshThumbnail() }
}

static func refreshThumbnailsAsync(_ screen: NSScreen, _ currentIndex: Int = criticalFirstThumbnails) {
guard App.app.appIsBeingUsed else { return }
if Preferences.hideThumbnails { return }
BackgroundWork.mainQueueConcurrentWorkQueue.async {
if currentIndex < list.count {
let window = list[currentIndex]
Expand Down
16 changes: 7 additions & 9 deletions src/ui/main-window/ThumbnailFontIconView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ class FontIcon: BaseLabel {
// 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, _ shadow: NSShadow? = ThumbnailView.makeShadow(.darkGray)) {
// This helps SF symbols display vertically centered and not clipped at the bottom
self.init(size, 3, shadow: shadow)
convenience init(_ symbol: Symbols, _ size: CGFloat = Preferences.fontHeight, _ color: NSColor = .white, _ shadow: NSShadow? = ThumbnailView.makeShadow(.darkGray)) {
self.init(size, shadow)
string = symbol.rawValue
font = NSFont(name: "SF Pro Text", size: size)
// This helps SF symbols display vertically centered and not clipped at the top
font = NSFont(name: "SF Pro Text", size: (size * 0.85).rounded())
textColor = color
// This helps SF symbols not be clipped on the right
widthAnchor.constraint(equalToConstant: size * 1.15).isActive = true
Expand Down Expand Up @@ -62,15 +62,13 @@ class ThumbnailFontIconView: ThumbnailTitleView {
}

class ThumbnailFilledFontIconView: NSView {
convenience init(_ thumbnailFontIconView: ThumbnailFontIconView, _ backgroundColor: NSColor, _ offset: Bool = false) {
convenience init(_ thumbnailFontIconView: ThumbnailFontIconView, _ backgroundColor: NSColor) {
self.init(frame: .zero)
translatesAutoresizingMaskIntoConstraints = false
let backgroundView = ThumbnailFontIconView(.filledCircled, thumbnailFontIconView.font!.pointSize - (offset ? 2 : 0), backgroundColor)
let backgroundView = ThumbnailFontIconView(.filledCircled, 14 - 2, backgroundColor, nil)
addSubview(backgroundView)
addSubview(thumbnailFontIconView, positioned: .above, relativeTo: nil)
if offset {
backgroundView.leftAnchor.constraint(equalTo: backgroundView.superview!.leftAnchor, constant: 1).isActive = true
}
backgroundView.frame.origin = CGPoint(x: backgroundView.frame.origin.x + 1, y: backgroundView.frame.origin.y + 1)
fit(thumbnailFontIconView.fittingSize.width, thumbnailFontIconView.fittingSize.height)
}
}
11 changes: 4 additions & 7 deletions src/ui/main-window/ThumbnailTitleView.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import Cocoa

class ThumbnailTitleView: BaseLabel {
var magicOffset = CGFloat(0)

convenience init(_ size: CGFloat, _ magicOffset: CGFloat = 0, shadow: NSShadow? = ThumbnailView.makeShadow(.darkGray)) {
convenience init(_ size: CGFloat, _ shadow: NSShadow? = ThumbnailView.makeShadow(.darkGray)) {
let textStorage = NSTextStorage()
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
Expand All @@ -13,18 +11,17 @@ class ThumbnailTitleView: BaseLabel {
layoutManager.addTextContainer(textContainer)
self.init(NSRect.zero, textContainer)
font = Preferences.font
self.magicOffset = magicOffset
textColor = Preferences.fontColor
self.shadow = shadow
defaultParagraphStyle = makeParagraphStyle(size)
heightAnchor.constraint(equalToConstant: size + magicOffset).isActive = true
heightAnchor.constraint(equalToConstant: size).isActive = true
}

private func makeParagraphStyle(_ size: CGFloat) -> NSMutableParagraphStyle {
let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
paragraphStyle.lineBreakMode = getTruncationMode()
paragraphStyle.maximumLineHeight = size + magicOffset
paragraphStyle.minimumLineHeight = size + magicOffset
paragraphStyle.maximumLineHeight = size
paragraphStyle.minimumLineHeight = size
paragraphStyle.allowsDefaultTighteningForTruncation = false
return paragraphStyle
}
Expand Down
31 changes: 17 additions & 14 deletions src/ui/main-window/ThumbnailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class ThumbnailView: NSStackView {
var minimizedIcon = ThumbnailFontIconView(.circledMinusSign)
var hiddenIcon = ThumbnailFontIconView(.circledSlashSign)
var spaceIcon = ThumbnailFontIconView(.circledNumber0)
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 dockLabelIcon = ThumbnailFilledFontIconView(ThumbnailFontIconView(.filledCircledNumber0, 14, NSColor(srgbRed: 1, green: 0.30, blue: 0.25, alpha: 1), nil), NSColor.white)
var closeIcon = WindowControlView("close", 16)
var minimizeIcon = WindowControlView("minimize", 16)
var maximizeIcon = WindowControlView("fullscreen", 16)
Expand All @@ -36,12 +36,10 @@ class ThumbnailView: NSStackView {
layer!.borderWidth = Preferences.cellBorderWidth
edgeInsets = NSEdgeInsets(top: Preferences.intraCellPadding, left: Preferences.intraCellPadding, bottom: Preferences.intraCellPadding, right: Preferences.intraCellPadding)
orientation = .vertical
spacing = Preferences.intraCellPadding
let shadow = ThumbnailView.makeShadow(.gray)
thumbnail.shadow = shadow
appIcon.shadow = shadow
hStackView = NSStackView(views: [appIcon, label, hiddenIcon, fullscreenIcon, minimizedIcon, spaceIcon])
hStackView.spacing = Preferences.intraCellPadding
setViews([hStackView, thumbnail], in: .leading)
addWindowControls()
addDockLabelIcon()
Expand Down Expand Up @@ -70,7 +68,7 @@ class ThumbnailView: NSStackView {
if let shouldShowWindowControls = shouldShowWindowControls_ {
self.shouldShowWindowControls = shouldShowWindowControls
}
let shouldShow = shouldShowWindowControls && isHighlighted && !Preferences.hideColoredCircles && !window_!.isWindowlessApp
let shouldShow = shouldShowWindowControls && isHighlighted && !Preferences.hideColoredCircles && !window_!.isWindowlessApp && !Preferences.hideThumbnails
if isShowingWindowControls != shouldShow {
isShowingWindowControls = shouldShow
[closeIcon, minimizeIcon, maximizeIcon].forEach { $0.isHidden = !shouldShow }
Expand Down Expand Up @@ -101,14 +99,19 @@ class ThumbnailView: NSStackView {

func updateRecycledCellWithNewContent(_ element: Window, _ index: Int, _ newHeight: CGFloat, _ screen: NSScreen) {
window_ = element
thumbnail.image = element.thumbnail
if let image = thumbnail.image {
image.size = element.thumbnailFullSize!
assignIfDifferent(&thumbnail.isHidden, Preferences.hideThumbnails)
if !Preferences.hideThumbnails {
thumbnail.image = element.thumbnail
if let image = thumbnail.image {
image.size = element.thumbnailFullSize!
}
let (thumbnailWidth, thumbnailHeight) = ThumbnailView.thumbnailSize(element.thumbnail, screen)
let thumbnailSize = NSSize(width: thumbnailWidth.rounded(), height: thumbnailHeight.rounded())
thumbnail.image?.size = thumbnailSize
thumbnail.frame.size = thumbnailSize
}
let (thumbnailWidth, thumbnailHeight) = ThumbnailView.thumbnailSize(element.thumbnail, screen)
let thumbnailSize = NSSize(width: thumbnailWidth.rounded(), height: thumbnailHeight.rounded())
thumbnail.image?.size = thumbnailSize
thumbnail.frame.size = thumbnailSize
assignIfDifferent(&spacing, Preferences.hideThumbnails ? 0 : Preferences.intraCellPadding)
assignIfDifferent(&hStackView.spacing, Preferences.fontHeight == 0 ? 0 : Preferences.intraCellPadding)
if appIcon.image != element.icon {
appIcon.image = element.icon
let appIconSize = NSSize(width: Preferences.iconSize, height: Preferences.iconSize)
Expand Down Expand Up @@ -142,11 +145,11 @@ class ThumbnailView: NSStackView {
}
dockLabelIcon.setFrameOrigin(NSPoint(x: appIcon.frame.maxX - dockLabelIcon.fittingSize.width - 1, y: appIcon.frame.maxY - dockLabelIcon.fittingSize.height + 4))
}
assignIfDifferent(&frame.size.width, max(thumbnail.frame.size.width + Preferences.intraCellPadding * 2, ThumbnailView.widthMin(screen)))
assignIfDifferent(&frame.size.width, max((Preferences.hideThumbnails ? hStackView.fittingSize.width : thumbnail.frame.size.width) + Preferences.intraCellPadding * 2, ThumbnailView.widthMin(screen)))
assignIfDifferent(&frame.size.height, newHeight)
let fontIconWidth = CGFloat([fullscreenIcon, minimizedIcon, hiddenIcon, spaceIcon].filter { !$0.isHidden }.count) * (Preferences.fontIconSize + Preferences.intraCellPadding)
let fontIconWidth = CGFloat([fullscreenIcon, minimizedIcon, hiddenIcon, spaceIcon].filter { !$0.isHidden }.count) * (Preferences.fontHeight + Preferences.intraCellPadding)
assignIfDifferent(&label.textContainer!.size.width, frame.width - Preferences.iconSize - Preferences.intraCellPadding * 3 - fontIconWidth)
assignIfDifferent(&windowlessIcon.isHidden, !element.isWindowlessApp)
assignIfDifferent(&windowlessIcon.isHidden, !element.isWindowlessApp || Preferences.hideThumbnails)
if element.isWindowlessApp {
let maxWidth = (ThumbnailView.widthMin(screen) - Preferences.intraCellPadding * 2).rounded()
let maxHeight = ((ThumbnailView.height(screen) - hStackView.fittingSize.height) - Preferences.intraCellPadding * 2).rounded()
Expand Down
9 changes: 8 additions & 1 deletion src/ui/main-window/ThumbnailsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,15 @@ class ThumbnailsView: NSVisualEffectView {
}
}

func rowHeight(_ screen: NSScreen) -> CGFloat {
if Preferences.hideThumbnails {
return max(Preferences.iconSize, Preferences.fontHeight + 3) + Preferences.intraCellPadding * 2
}
return ThumbnailView.height(screen).rounded(.down)
}

private func layoutThumbnailViews(_ screen: NSScreen, _ widthMax: CGFloat) -> (CGFloat, CGFloat)? {
let height = ThumbnailView.height(screen).rounded(.down)
let height = rowHeight(screen)
let isLeftToRight = App.shared.userInterfaceLayoutDirection == .leftToRight
let startingX = isLeftToRight ? Preferences.interCellPadding : widthMax - Preferences.interCellPadding
var currentX = startingX
Expand Down
3 changes: 2 additions & 1 deletion src/ui/preferences-window/tabs/AppearanceTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class AppearanceTab {
LabelAndControl.makeLabelWithSlider(NSLocalizedString("Rows of windows:", comment: ""), "rowsCount", 1, 20, 20, true),
LabelAndControl.makeLabelWithSlider(NSLocalizedString("Min windows per row:", comment: ""), "minCellsPerRow", 1, 20, 20, true),
LabelAndControl.makeLabelWithSlider(NSLocalizedString("Max windows per row:", comment: ""), "maxCellsPerRow", 1, 40, 20, true),
LabelAndControl.makeLabelWithSlider(NSLocalizedString("Window app icon size:", comment: ""), "iconSize", 0, 64, 11, false, "px"),
LabelAndControl.makeLabelWithSlider(NSLocalizedString("Window app icon size:", comment: ""), "iconSize", 0, 128, 11, false, "px"),
LabelAndControl.makeLabelWithSlider(NSLocalizedString("Window title font size:", comment: ""), "fontHeight", 0, 64, 11, false, "px"),
LabelAndControl.makeLabelWithDropdown(NSLocalizedString("Window title truncation:", comment: ""), "titleTruncation", TitleTruncationPreference.allCases),
LabelAndControl.makeLabelWithDropdown(NSLocalizedString("Show on:", comment: ""), "showOnScreen", ShowOnScreenPreference.allCases),
Expand All @@ -21,6 +21,7 @@ class AppearanceTab {
LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide colored circles on mouse hover:", comment: ""), "hideColoredCircles"),
LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide app badges:", comment: ""), "hideAppBadges"),
LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide apps with no open window:", comment: ""), "hideWindowlessApps"),
LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide window thumbnails:", comment: ""), "hideThumbnails"),
])
grid.column(at: 0).xPlacement = .trailing
grid.rowAlignment = .lastBaseline
Expand Down

0 comments on commit 877c93c

Please sign in to comment.