diff --git a/ModuleKit/module.swift b/ModuleKit/module.swift index b507b980..002da0f4 100644 --- a/ModuleKit/module.swift +++ b/ModuleKit/module.swift @@ -104,6 +104,7 @@ open class Module: Module_p { NotificationCenter.default.addObserver(self, selector: #selector(listenForWidgetSwitch), name: .switchWidget, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(listenForMouseDownInSettings), name: .clickInSettings, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(listenForModuleToggle), name: .toggleModule, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(listenChangingPopupSize), name: .updatePopupSize, object: nil) if self.config.widgetsConfig.count != 0 { self.setWidget() @@ -255,24 +256,25 @@ open class Module: Module_p { self.settings?.setActiveWidget(self.widget) } - @objc private func togglePopup(_ sender: NSStatusBarButton) { + @objc private func togglePopup(_ sender: Any) { let openedWindows = NSApplication.shared.windows.filter{ $0 is NSPanel } openedWindows.forEach{ $0.setIsVisible(false) } if self.popup.occlusionState.rawValue == 8192 { NSApplication.shared.activate(ignoringOtherApps: true) + self.popup.contentView?.invalidateIntrinsicContentSize() + let buttonOrigin = self.menuBarItem.button?.window?.frame.origin let buttonCenter = (self.menuBarItem.button?.window?.frame.width)! / 2 - let windowCenter = self.popup.frame.width / 2 - self.popup.contentView?.invalidateIntrinsicContentSize() + let windowCenter = self.popup.contentView!.intrinsicContentSize.width / 2 var x = buttonOrigin!.x - windowCenter + buttonCenter let y = buttonOrigin!.y - self.popup.contentView!.intrinsicContentSize.height - 3 let maxWidth = NSScreen.screens.map{ $0.frame.width }.reduce(0, +) - if x + self.popup.frame.width > maxWidth { - x = maxWidth - self.popup.frame.width - 3 + if x + self.popup.contentView!.intrinsicContentSize.width > maxWidth { + x = maxWidth - self.popup.contentView!.intrinsicContentSize.width - 3 } self.popup.setFrameOrigin(NSPoint(x: x, y: y)) @@ -314,4 +316,12 @@ open class Module: Module_p { self.popup.setIsVisible(false) } } + + @objc private func listenChangingPopupSize(_ notification: Notification) { + if let moduleName = notification.userInfo?["module"] as? String, moduleName == self.config.name { + if self.popup.isVisible { + self.popup.setIsVisible(false) + } + } + } } diff --git a/ModuleKit/popup.swift b/ModuleKit/popup.swift index 99c65402..21fa0826 100644 --- a/ModuleKit/popup.swift +++ b/ModuleKit/popup.swift @@ -69,6 +69,7 @@ internal class PopupViewController: NSViewController { public func setup(title: String, view: NSView?) { self.title = title + self.popup.title = title self.popup.headerView?.titleView?.stringValue = title self.popup.setView(view) } @@ -76,6 +77,7 @@ internal class PopupViewController: NSViewController { internal class PopupView: NSView { public var headerView: HeaderView? = nil + public var title: String? = nil private var mainView: NSView? = nil override var intrinsicContentSize: CGSize { @@ -92,6 +94,7 @@ internal class PopupView: NSView { self.canDrawConcurrently = true self.layer!.cornerRadius = 3 + NotificationCenter.default.addObserver(self, selector: #selector(listenChangingPopupSize), name: .updatePopupSize, object: nil) self.headerView = HeaderView(frame: NSRect(x: 0, y: frame.height - Constants.Popup.headerHeight, width: frame.width, height: Constants.Popup.headerHeight)) let mainView: NSView = NSView(frame: NSRect(x: Constants.Popup.margins, y: Constants.Popup.margins, width: frame.width - (Constants.Popup.margins*2), height: 0)) @@ -143,6 +146,13 @@ internal class PopupView: NSView { self.mainView?.subviews.first{ !($0 is HeaderView) }?.display() } internal func disappear() {} + + + @objc private func listenChangingPopupSize(_ notification: Notification) { + if let moduleName = notification.userInfo?["module"] as? String, moduleName == self.title { + self.updateLayer() + } + } } internal class HeaderView: NSView { diff --git a/Modules/Disk/main.swift b/Modules/Disk/main.swift index 604264d5..f1fe790e 100644 --- a/Modules/Disk/main.swift +++ b/Modules/Disk/main.swift @@ -25,6 +25,8 @@ struct diskInfo { var mediaBSDName: String = "" var root: Bool = false + + var removable: Bool = false } struct DiskList: value_t { @@ -78,6 +80,7 @@ public class Disk: Module { guard self.available else { return } self.capacityReader = CapacityReader() + self.capacityReader?.store = store self.selectedDisk = store!.pointee.string(key: "\(self.config.name)_disk", defaultValue: self.selectedDisk) self.capacityReader?.readyCallback = { [unowned self] in @@ -91,6 +94,9 @@ public class Disk: Module { self.selectedDisk = value self.capacityReader?.read() } + self.settingsView.callback = { [unowned self] in + self.capacityReader?.read() + } if let reader = self.capacityReader { self.addReader(reader) diff --git a/Modules/Disk/popup.swift b/Modules/Disk/popup.swift index f422ca59..e76d8c7e 100644 --- a/Modules/Disk/popup.swift +++ b/Modules/Disk/popup.swift @@ -26,6 +26,11 @@ internal class Popup: NSView { } internal func usageCallback(_ value: DiskList) { + if self.list.count != value.list.count { + self.subviews.forEach{ $0.removeFromSuperview() } + self.list = [:] + } + value.list.reversed().forEach { (d: diskInfo) in if self.list[d.name] == nil { DispatchQueue.main.async(execute: { @@ -37,13 +42,19 @@ internal class Popup: NSView { path: d.path ) self.addSubview(self.list[d.name]!) - - self.setFrameSize(NSSize(width: self.frame.width, height: ((self.diskFullHeight + Constants.Popup.margins) * CGFloat(self.list.count)) - Constants.Popup.margins)) }) } else { self.list[d.name]?.update(free: d.freeSize) } } + + DispatchQueue.main.async(execute: { + let h: CGFloat = ((self.diskFullHeight + Constants.Popup.margins) * CGFloat(self.list.count)) - Constants.Popup.margins + if self.frame.size.height != h { + self.setFrameSize(NSSize(width: self.frame.width, height: h)) + NotificationCenter.default.post(name: .updatePopupSize, object: nil, userInfo: ["module": "Disk"]) + } + }) } } diff --git a/Modules/Disk/readers.swift b/Modules/Disk/readers.swift index 7a77fb6d..abb4da0d 100644 --- a/Modules/Disk/readers.swift +++ b/Modules/Disk/readers.swift @@ -11,9 +11,11 @@ import Cocoa import ModuleKit +import StatsKit internal class CapacityReader: Reader { private var disks: DiskList = DiskList() + public var store: UnsafePointer? = nil public override func setup() { self.interval = 10000 @@ -21,7 +23,9 @@ internal class CapacityReader: Reader { public override func read() { let keys: [URLResourceKey] = [.volumeNameKey] + let removableState = store?.pointee.bool(key: "Disk_removable", defaultValue: false) ?? false let paths = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: keys)! + if let session = DASessionCreate(kCFAllocatorDefault) { for url in paths { if url.pathComponents.count == 1 || (url.pathComponents.count > 1 && url.pathComponents[1] == "Volumes") { @@ -29,8 +33,13 @@ internal class CapacityReader: Reader { if let diskName = DADiskGetBSDName(disk) { let BSDName: String = String(cString: diskName) - if let _: diskInfo = self.disks.getDiskByBSDName(BSDName) { + if let d: diskInfo = self.disks.getDiskByBSDName(BSDName) { if let idx = self.disks.list.firstIndex(where: { $0.mediaBSDName == BSDName }) { + if d.removable && !removableState { + self.disks.list.remove(at: idx) + continue + } + if let path = self.disks.list[idx].path { self.disks.list[idx].freeSize = freeDiskSpaceInBytes(path.absoluteString) } @@ -38,8 +47,9 @@ internal class CapacityReader: Reader { continue } - if let d = getDisk(disk) { + if let d = getDisk(disk, removableState: removableState) { self.disks.list.append(d) + self.disks.list.sort{ $1.removable } } } } @@ -50,7 +60,7 @@ internal class CapacityReader: Reader { self.callback(self.disks) } - private func getDisk(_ disk: DADisk) -> diskInfo? { + private func getDisk(_ disk: DADisk, removableState: Bool) -> diskInfo? { var d: diskInfo = diskInfo() if let bsdName = DADiskGetBSDName(disk) { @@ -61,7 +71,10 @@ internal class CapacityReader: Reader { if let dict = diskDescription as? [String: AnyObject] { if let removable = dict[kDADiskDescriptionMediaRemovableKey as String] { if removable as! Bool { - return nil + if !removableState { + return nil + } + d.removable = true } } diff --git a/Modules/Disk/settings.swift b/Modules/Disk/settings.swift index c2429f65..e221972c 100644 --- a/Modules/Disk/settings.swift +++ b/Modules/Disk/settings.swift @@ -22,10 +22,13 @@ internal class Settings: NSView, Settings_v { private var selectedDisk: String private var button: NSPopUpButton? + private var removableState: Bool = false + public init(_ title: String, store: UnsafePointer) { self.title = title self.store = store self.selectedDisk = store.pointee.string(key: "\(self.title)_disk", defaultValue: "") + self.removableState = store.pointee.bool(key: "\(self.title)_removable", defaultValue: self.removableState) super.init(frame: CGRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: Constants.Settings.width - (Constants.Settings.margin*2), height: 0)) self.wantsLayer = true self.canDrawConcurrently = true @@ -38,13 +41,21 @@ internal class Settings: NSView, Settings_v { public func load(widget: widget_t) { self.subviews.forEach{ $0.removeFromSuperview() } + let rowHeight: CGFloat = 30 self.addDiskSelector() - self.setFrameSize(NSSize(width: self.frame.width, height: 30 + (Constants.Settings.margin*2))) + self.addSubview(ToggleTitleRow( + frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 0, width: self.frame.width - (Constants.Settings.margin*2), height: rowHeight), + title: "Show removable disks", + action: #selector(toggleRemovable), + state: self.removableState + )) + + self.setFrameSize(NSSize(width: self.frame.width, height: rowHeight*2 + (Constants.Settings.margin*3))) } private func addDiskSelector() { - let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: self.frame.width, height: 29)) + let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin*2 + 30, width: self.frame.width, height: 29)) let rowTitle: NSTextField = LabelField(frame: NSRect(x: 0, y: (view.frame.height - 16)/2, width: view.frame.width - 52, height: 17), "Disk to show") rowTitle.font = NSFont.systemFont(ofSize: 13, weight: .light) @@ -63,6 +74,10 @@ internal class Settings: NSView, Settings_v { internal func setList(_ list: DiskList) { let disks = list.list.map{ $0.name } DispatchQueue.main.async(execute: { + if self.button?.itemTitles.count != disks.count { + self.button?.removeAllItems() + } + if disks != self.button?.itemTitles { self.button?.addItems(withTitles: disks) if self.selectedDisk != "" { @@ -72,10 +87,23 @@ internal class Settings: NSView, Settings_v { }) } - @objc func handleSelection(_ sender: NSPopUpButton) { + @objc private func handleSelection(_ sender: NSPopUpButton) { guard let item = sender.selectedItem else { return } self.selectedDisk = item.title self.store.pointee.set(key: "\(self.title)_disk", value: item.title) self.selectedDiskHandler(item.title) } + + @objc private func toggleRemovable(_ sender: NSControl) { + var state: NSControl.StateValue? = nil + if #available(OSX 10.15, *) { + state = sender is NSSwitch ? (sender as! NSSwitch).state: nil + } else { + state = sender is NSButton ? (sender as! NSButton).state: nil + } + + self.removableState = state! == .on ? true : false + self.store.pointee.set(key: "\(self.title)_removable", value: self.removableState) + self.callback() + } } diff --git a/StatsKit/extensions.swift b/StatsKit/extensions.swift index 6d9836c6..bbd9f6c4 100644 --- a/StatsKit/extensions.swift +++ b/StatsKit/extensions.swift @@ -375,6 +375,7 @@ public extension Notification.Name { static let switchWidget = Notification.Name("switchWidget") static let checkForUpdates = Notification.Name("checkForUpdates") static let clickInSettings = Notification.Name("clickInSettings") + static let updatePopupSize = Notification.Name("updatePopupSize") } public class NSButtonWithPadding: NSButton {