├── Hide Icons.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── parker.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── HideIcons ├── AppDelegate.swift ├── Assets.xcassets │ ├── .DS_Store │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AlphaBarButtonImage.imageset │ │ ├── AlphaBarButtonImage@2x.png │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Hide_128x128.png │ │ ├── Hide_128x128@2x.png │ │ ├── Hide_16x16.png │ │ ├── Hide_16x16@2x.png │ │ ├── Hide_256x256.png │ │ ├── Hide_256x256@2x.png │ │ ├── Hide_32x32.png │ │ ├── Hide_32x32@2x.png │ │ ├── Hide_512x512.png │ │ └── Hide_512x512@2x.png │ ├── BBarButtonImage.imageset │ │ ├── BBarButtonImage@2x.png │ │ └── Contents.json │ ├── BBarButtonImageUpdate.imageset │ │ ├── BBarButtonImageUpdate@2x.png │ │ └── Contents.json │ └── Contents.json ├── HideIcons.entitlements ├── Hider.swift ├── Info.plist ├── Resources │ └── HideIcons.help │ │ └── Contents │ │ ├── Info.plist │ │ └── Resources │ │ ├── Hide_256x256.png │ │ └── en.lproj │ │ ├── Contact_and_version_hist.html │ │ ├── HideIcons.helpindex │ │ ├── InfoPlist.strings │ │ ├── Welcome.html │ │ ├── Welcome.jpg │ │ ├── Welcome1.jpg │ │ ├── Welcome2.jpg │ │ ├── Welcome3.jpg │ │ ├── Welcome4.jpg │ │ ├── Welcome5.jpg │ │ ├── basic.css │ │ └── index.html └── main.swift └── README.md /Hide Icons.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2C24C152277A508500F21431 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C24C151277A508500F21431 /* main.swift */; }; 11 | 2C5E23BC26365265008D27BE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C5E23BB26365265008D27BE /* AppDelegate.swift */; }; 12 | 2C5E23D126367747008D27BE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C5E23D026367747008D27BE /* Assets.xcassets */; }; 13 | 2C5E23DC2637814E008D27BE /* Hider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C5E23DB2637814E008D27BE /* Hider.swift */; }; 14 | 2C5E23F4263A0052008D27BE /* HideIcons.help in Resources */ = {isa = PBXBuildFile; fileRef = 2C5E23F3263A0052008D27BE /* HideIcons.help */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 2C24C151277A508500F21431 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 19 | 2C5E23B826365265008D27BE /* Hide Icons.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Hide Icons.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | 2C5E23BB26365265008D27BE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 21 | 2C5E23C426365269008D27BE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 22 | 2C5E23C526365269008D27BE /* HideIcons.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HideIcons.entitlements; sourceTree = ""; }; 23 | 2C5E23D026367747008D27BE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 24 | 2C5E23DB2637814E008D27BE /* Hider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Hider.swift; sourceTree = ""; }; 25 | 2C5E23F3263A0052008D27BE /* HideIcons.help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = HideIcons.help; path = HideIcons/Resources/HideIcons.help; sourceTree = ""; }; 26 | /* End PBXFileReference section */ 27 | 28 | /* Begin PBXFrameworksBuildPhase section */ 29 | 2C5E23B526365265008D27BE /* Frameworks */ = { 30 | isa = PBXFrameworksBuildPhase; 31 | buildActionMask = 2147483647; 32 | files = ( 33 | ); 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXFrameworksBuildPhase section */ 37 | 38 | /* Begin PBXGroup section */ 39 | 2C5E23AF26365265008D27BE = { 40 | isa = PBXGroup; 41 | children = ( 42 | 2C5E23F3263A0052008D27BE /* HideIcons.help */, 43 | 2C5E23BA26365265008D27BE /* HideIcons */, 44 | 2C5E23B926365265008D27BE /* Products */, 45 | ); 46 | sourceTree = ""; 47 | }; 48 | 2C5E23B926365265008D27BE /* Products */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | 2C5E23B826365265008D27BE /* Hide Icons.app */, 52 | ); 53 | name = Products; 54 | sourceTree = ""; 55 | }; 56 | 2C5E23BA26365265008D27BE /* HideIcons */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 2C5E23BB26365265008D27BE /* AppDelegate.swift */, 60 | 2C5E23DB2637814E008D27BE /* Hider.swift */, 61 | 2C24C151277A508500F21431 /* main.swift */, 62 | 2C5E23D026367747008D27BE /* Assets.xcassets */, 63 | 2C5E23C426365269008D27BE /* Info.plist */, 64 | 2C5E23C526365269008D27BE /* HideIcons.entitlements */, 65 | ); 66 | path = HideIcons; 67 | sourceTree = ""; 68 | }; 69 | /* End PBXGroup section */ 70 | 71 | /* Begin PBXNativeTarget section */ 72 | 2C5E23B726365265008D27BE /* Hide Icons */ = { 73 | isa = PBXNativeTarget; 74 | buildConfigurationList = 2C5E23C826365269008D27BE /* Build configuration list for PBXNativeTarget "Hide Icons" */; 75 | buildPhases = ( 76 | 2C5E23B426365265008D27BE /* Sources */, 77 | 2C5E23B526365265008D27BE /* Frameworks */, 78 | 2C5E23B626365265008D27BE /* Resources */, 79 | ); 80 | buildRules = ( 81 | ); 82 | dependencies = ( 83 | ); 84 | name = "Hide Icons"; 85 | productName = HideIcons; 86 | productReference = 2C5E23B826365265008D27BE /* Hide Icons.app */; 87 | productType = "com.apple.product-type.application"; 88 | }; 89 | /* End PBXNativeTarget section */ 90 | 91 | /* Begin PBXProject section */ 92 | 2C5E23B026365265008D27BE /* Project object */ = { 93 | isa = PBXProject; 94 | attributes = { 95 | LastSwiftUpdateCheck = 1240; 96 | LastUpgradeCheck = 1420; 97 | TargetAttributes = { 98 | 2C5E23B726365265008D27BE = { 99 | CreatedOnToolsVersion = 12.4; 100 | }; 101 | }; 102 | }; 103 | buildConfigurationList = 2C5E23B326365265008D27BE /* Build configuration list for PBXProject "Hide Icons" */; 104 | compatibilityVersion = "Xcode 9.3"; 105 | developmentRegion = en; 106 | hasScannedForEncodings = 0; 107 | knownRegions = ( 108 | en, 109 | Base, 110 | ); 111 | mainGroup = 2C5E23AF26365265008D27BE; 112 | productRefGroup = 2C5E23B926365265008D27BE /* Products */; 113 | projectDirPath = ""; 114 | projectRoot = ""; 115 | targets = ( 116 | 2C5E23B726365265008D27BE /* Hide Icons */, 117 | ); 118 | }; 119 | /* End PBXProject section */ 120 | 121 | /* Begin PBXResourcesBuildPhase section */ 122 | 2C5E23B626365265008D27BE /* Resources */ = { 123 | isa = PBXResourcesBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | 2C5E23F4263A0052008D27BE /* HideIcons.help in Resources */, 127 | 2C5E23D126367747008D27BE /* Assets.xcassets in Resources */, 128 | ); 129 | runOnlyForDeploymentPostprocessing = 0; 130 | }; 131 | /* End PBXResourcesBuildPhase section */ 132 | 133 | /* Begin PBXSourcesBuildPhase section */ 134 | 2C5E23B426365265008D27BE /* Sources */ = { 135 | isa = PBXSourcesBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | 2C5E23DC2637814E008D27BE /* Hider.swift in Sources */, 139 | 2C5E23BC26365265008D27BE /* AppDelegate.swift in Sources */, 140 | 2C24C152277A508500F21431 /* main.swift in Sources */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXSourcesBuildPhase section */ 145 | 146 | /* Begin XCBuildConfiguration section */ 147 | 2C5E23C626365269008D27BE /* Debug */ = { 148 | isa = XCBuildConfiguration; 149 | buildSettings = { 150 | ALWAYS_SEARCH_USER_PATHS = NO; 151 | CLANG_ANALYZER_NONNULL = YES; 152 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 153 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 154 | CLANG_CXX_LIBRARY = "libc++"; 155 | CLANG_ENABLE_MODULES = YES; 156 | CLANG_ENABLE_OBJC_ARC = YES; 157 | CLANG_ENABLE_OBJC_WEAK = YES; 158 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 159 | CLANG_WARN_BOOL_CONVERSION = YES; 160 | CLANG_WARN_COMMA = YES; 161 | CLANG_WARN_CONSTANT_CONVERSION = YES; 162 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 163 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 164 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 165 | CLANG_WARN_EMPTY_BODY = YES; 166 | CLANG_WARN_ENUM_CONVERSION = YES; 167 | CLANG_WARN_INFINITE_RECURSION = YES; 168 | CLANG_WARN_INT_CONVERSION = YES; 169 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 170 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 171 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 172 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 173 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 174 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 175 | CLANG_WARN_STRICT_PROTOTYPES = YES; 176 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 177 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 178 | CLANG_WARN_UNREACHABLE_CODE = YES; 179 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 180 | COPY_PHASE_STRIP = NO; 181 | DEAD_CODE_STRIPPING = YES; 182 | DEBUG_INFORMATION_FORMAT = dwarf; 183 | ENABLE_STRICT_OBJC_MSGSEND = YES; 184 | ENABLE_TESTABILITY = YES; 185 | GCC_C_LANGUAGE_STANDARD = gnu11; 186 | GCC_DYNAMIC_NO_PIC = NO; 187 | GCC_NO_COMMON_BLOCKS = YES; 188 | GCC_OPTIMIZATION_LEVEL = 0; 189 | GCC_PREPROCESSOR_DEFINITIONS = ( 190 | "DEBUG=1", 191 | "$(inherited)", 192 | ); 193 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 194 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 195 | GCC_WARN_UNDECLARED_SELECTOR = YES; 196 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 197 | GCC_WARN_UNUSED_FUNCTION = YES; 198 | GCC_WARN_UNUSED_VARIABLE = YES; 199 | MACOSX_DEPLOYMENT_TARGET = 10.13; 200 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 201 | MTL_FAST_MATH = YES; 202 | ONLY_ACTIVE_ARCH = YES; 203 | SDKROOT = macosx; 204 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 205 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 206 | }; 207 | name = Debug; 208 | }; 209 | 2C5E23C726365269008D27BE /* Release */ = { 210 | isa = XCBuildConfiguration; 211 | buildSettings = { 212 | ALWAYS_SEARCH_USER_PATHS = NO; 213 | CLANG_ANALYZER_NONNULL = YES; 214 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 215 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 216 | CLANG_CXX_LIBRARY = "libc++"; 217 | CLANG_ENABLE_MODULES = YES; 218 | CLANG_ENABLE_OBJC_ARC = YES; 219 | CLANG_ENABLE_OBJC_WEAK = YES; 220 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 221 | CLANG_WARN_BOOL_CONVERSION = YES; 222 | CLANG_WARN_COMMA = YES; 223 | CLANG_WARN_CONSTANT_CONVERSION = YES; 224 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 225 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 226 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 227 | CLANG_WARN_EMPTY_BODY = YES; 228 | CLANG_WARN_ENUM_CONVERSION = YES; 229 | CLANG_WARN_INFINITE_RECURSION = YES; 230 | CLANG_WARN_INT_CONVERSION = YES; 231 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 232 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 233 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 234 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 235 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 236 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 237 | CLANG_WARN_STRICT_PROTOTYPES = YES; 238 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 239 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 240 | CLANG_WARN_UNREACHABLE_CODE = YES; 241 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 242 | COPY_PHASE_STRIP = NO; 243 | DEAD_CODE_STRIPPING = YES; 244 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 245 | ENABLE_NS_ASSERTIONS = NO; 246 | ENABLE_STRICT_OBJC_MSGSEND = YES; 247 | GCC_C_LANGUAGE_STANDARD = gnu11; 248 | GCC_NO_COMMON_BLOCKS = YES; 249 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 250 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 251 | GCC_WARN_UNDECLARED_SELECTOR = YES; 252 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 253 | GCC_WARN_UNUSED_FUNCTION = YES; 254 | GCC_WARN_UNUSED_VARIABLE = YES; 255 | MACOSX_DEPLOYMENT_TARGET = 10.13; 256 | MTL_ENABLE_DEBUG_INFO = NO; 257 | MTL_FAST_MATH = YES; 258 | SDKROOT = macosx; 259 | SWIFT_COMPILATION_MODE = wholemodule; 260 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 261 | }; 262 | name = Release; 263 | }; 264 | 2C5E23C926365269008D27BE /* Debug */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 268 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 269 | CODE_SIGN_ENTITLEMENTS = HideIcons/HideIcons.entitlements; 270 | CODE_SIGN_IDENTITY = "Apple Development"; 271 | CODE_SIGN_STYLE = Automatic; 272 | COMBINE_HIDPI_IMAGES = YES; 273 | CURRENT_PROJECT_VERSION = 37; 274 | DEAD_CODE_STRIPPING = YES; 275 | DEVELOPMENT_TEAM = XJ9ZL4KYVN; 276 | ENABLE_HARDENED_RUNTIME = YES; 277 | INFOPLIST_FILE = HideIcons/Info.plist; 278 | INFOPLIST_KEY_CFBundleDisplayName = "Hide Icons"; 279 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; 280 | LD_RUNPATH_SEARCH_PATHS = ( 281 | "$(inherited)", 282 | "@executable_path/../Frameworks", 283 | ); 284 | MACOSX_DEPLOYMENT_TARGET = 10.13; 285 | MARKETING_VERSION = 2.2.1; 286 | PRODUCT_BUNDLE_IDENTIFIER = com.entonos.HideIcons; 287 | PRODUCT_NAME = "$(TARGET_NAME)"; 288 | SWIFT_VERSION = 5.0; 289 | }; 290 | name = Debug; 291 | }; 292 | 2C5E23CA26365269008D27BE /* Release */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 296 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 297 | CODE_SIGN_ENTITLEMENTS = HideIcons/HideIcons.entitlements; 298 | CODE_SIGN_IDENTITY = "Apple Development"; 299 | CODE_SIGN_STYLE = Automatic; 300 | COMBINE_HIDPI_IMAGES = YES; 301 | CURRENT_PROJECT_VERSION = 37; 302 | DEAD_CODE_STRIPPING = YES; 303 | DEVELOPMENT_TEAM = XJ9ZL4KYVN; 304 | ENABLE_HARDENED_RUNTIME = YES; 305 | INFOPLIST_FILE = HideIcons/Info.plist; 306 | INFOPLIST_KEY_CFBundleDisplayName = "Hide Icons"; 307 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; 308 | LD_RUNPATH_SEARCH_PATHS = ( 309 | "$(inherited)", 310 | "@executable_path/../Frameworks", 311 | ); 312 | MACOSX_DEPLOYMENT_TARGET = 10.13; 313 | MARKETING_VERSION = 2.2.1; 314 | PRODUCT_BUNDLE_IDENTIFIER = com.entonos.HideIcons; 315 | PRODUCT_NAME = "$(TARGET_NAME)"; 316 | SWIFT_VERSION = 5.0; 317 | }; 318 | name = Release; 319 | }; 320 | /* End XCBuildConfiguration section */ 321 | 322 | /* Begin XCConfigurationList section */ 323 | 2C5E23B326365265008D27BE /* Build configuration list for PBXProject "Hide Icons" */ = { 324 | isa = XCConfigurationList; 325 | buildConfigurations = ( 326 | 2C5E23C626365269008D27BE /* Debug */, 327 | 2C5E23C726365269008D27BE /* Release */, 328 | ); 329 | defaultConfigurationIsVisible = 0; 330 | defaultConfigurationName = Release; 331 | }; 332 | 2C5E23C826365269008D27BE /* Build configuration list for PBXNativeTarget "Hide Icons" */ = { 333 | isa = XCConfigurationList; 334 | buildConfigurations = ( 335 | 2C5E23C926365269008D27BE /* Debug */, 336 | 2C5E23CA26365269008D27BE /* Release */, 337 | ); 338 | defaultConfigurationIsVisible = 0; 339 | defaultConfigurationName = Release; 340 | }; 341 | /* End XCConfigurationList section */ 342 | }; 343 | rootObject = 2C5E23B026365265008D27BE /* Project object */; 344 | } 345 | -------------------------------------------------------------------------------- /Hide Icons.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Hide Icons.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Hide Icons.xcodeproj/xcuserdata/parker.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Hide Icons.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | HideIcons.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /HideIcons/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // HideIcons 4 | // 5 | // Created by parker on 4/25/21. 6 | // 7 | 8 | import Cocoa 9 | 10 | class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { 11 | 12 | // status bar item 13 | var statusBarItem: NSStatusItem? 14 | 15 | // Hider class which hides/shows icons 16 | var hider: Hider? = Hider() 17 | 18 | // status bar item images 19 | let sbiPicture = NSImage(named: "BBarButtonImage") 20 | let sbiPictureUpdate = NSImage(named: "BBarButtonImageUpdate") 21 | let sbiNoPicture = NSImage(named: "AlphaBarButtonImage") 22 | 23 | // to figure out if Services started the app 24 | var startDate: Date! 25 | 26 | // start out w/ status bar item visible 27 | var sbiHidden = false 28 | 29 | // show menu on left click? 30 | var defaultClick = true 31 | 32 | // type of Desktop 33 | var desktop: DesktopTypes = .allDesktop 34 | var desktopColor : NSColor = .black 35 | var lastDesktopColor : NSColor = .black 36 | 37 | let defaultTimeList = ["Never", "5 seconds", "30 seconds", "1 minute", "5 minutes", "15 minutes", "1 hour"] 38 | let defaultTimes = [315576000.0, 5.0, 30.0, 60.0, 300.0, 900.0, 3600.0] 39 | var defaultTime = "Never" 40 | 41 | var version = "0.0.0" 42 | let appStore = false // this app destined to macOS App Store? 43 | var updateAvailable = [String]() 44 | var updateDownloaded = false 45 | var updateMenuItem = "Check for update..." 46 | 47 | // keep track of NSApp that had focus before us 48 | var previousApp : NSRunningApplication? 49 | 50 | func applicationDidFinishLaunching(_ aNotification: Notification) { 51 | 52 | // get version of this app 53 | version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String 54 | //version = "2.1.1" 55 | 56 | // restore user preferences 57 | if !NSEvent.modifierFlags.contains(.command) { setDefaultValues() } 58 | else { // reset to defaults 59 | UserDefaults.standard.set(defaultTime, forKey: "defaultTime") 60 | UserDefaults.standard.set(sbiHidden, forKey: "sbiHidden") 61 | UserDefaults.standard.set(defaultClick, forKey: "defaultClick") 62 | } 63 | 64 | // construct status bar item (or not!) 65 | statusBarItem = setStatusBarItem(image: sbiHidden ? sbiNoPicture : sbiPicture) 66 | 67 | // create some Services 68 | NSApp.servicesProvider = self 69 | NSUpdateDynamicServices() 70 | 71 | // let's go setup a background timer- lazy way to capture changing desktop backgrounds 72 | NotificationCenter.default.post(name: .timeBG, object: defaultTimes[defaultTimeList.firstIndex(where: {$0 == defaultTime}) ?? 0]) 73 | 74 | // date the app started + 2 second 75 | startDate = Date(timeIntervalSinceNow: TimeInterval(2.0)) 76 | 77 | // keep track of app that had focus before us... 78 | NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.didActivateApplicationNotification, object: nil, queue: .main, using: {_ in 79 | if let app = NSWorkspace.shared.frontmostApplication { 80 | if app.bundleIdentifier != Bundle.main.object(forInfoDictionaryKey: "CFBundleIdentifier") as? String { self.previousApp = app } 81 | } 82 | }) 83 | } 84 | 85 | func applicationWillTerminate(_ aNotification: Notification) { 86 | hider = nil // remove observers 87 | } 88 | 89 | func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool { 90 | if statusBarItem == nil || sbiHidden { 91 | if statusBarItem == nil { statusBarItem = setStatusBarItem(image: sbiPicture) } 92 | sbiHidden = false 93 | } 94 | return false 95 | } 96 | 97 | @objc func powerOff(notification: NSNotification) { // does this catch logoff, restart and shutdown? 98 | NSApplication.shared.terminate(self) 99 | } 100 | // called from Services menu 101 | @objc func toggleService(_ pboard: NSPasteboard, userData: String, error: NSErrorPointer) { 102 | if Date() < startDate { //hack to see if Service started the app 103 | statusBarItem = nil // Services did start the app (therefore icons hidden); just turn off menu 104 | } else { 105 | toggle(nil) // didn't start app, so toggle icons 106 | } 107 | // return controll to last app who had focus otherwise finder otherwise window server otherwise random apple app. 108 | if let app = NSWorkspace.shared.runningApplications.filter({$0 == previousApp}).first { //print("reactivating \(app.bundleIdentifier)"); 109 | app.activate() 110 | } else if let finder = NSWorkspace.shared.runningApplications.filter({$0.bundleIdentifier == "com.apple.finder"}).first { //print("activating finder"); 111 | finder.activate() 112 | } else if let windowServer = NSWorkspace.shared.runningApplications.filter({$0.bundleIdentifier == "com.apple.WindowManager"}).first { 113 | windowServer.activate() 114 | } else { NSWorkspace.shared.runningApplications.filter({$0.bundleIdentifier!.starts(with: "com.apple")}).last?.activate() } 115 | } 116 | // construct status bar item 117 | func setStatusBarItem(image: NSImage? ) -> NSStatusItem? { 118 | let sBI = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) 119 | sBI.button?.image = image 120 | sBI.button?.action = #selector(self.statusBarButtonClicked(sender:)) 121 | sBI.button?.sendAction(on: [.leftMouseDown, .rightMouseDown]) 122 | return sBI 123 | } 124 | // status bar item clicked- do we toggle or do we construct and show menu? 125 | @objc func statusBarButtonClicked(sender: NSStatusBarButton) { 126 | if NSApp.currentEvent!.isRightClick == defaultClick { 127 | toggle(nil) 128 | } else { 129 | statusBarItem!.menu = constructMenu(hider!.hidden) 130 | statusBarItem!.button!.performClick(nil) // pass the click along 131 | } 132 | } 133 | // construct menu 134 | func constructMenu(_ hidden : Bool) -> NSMenu? { 135 | let menu = NSMenu() 136 | menu.delegate = self 137 | 138 | // Show/Hide Desktop Icons 139 | var str = hidden ? "Show Desktop Icons" : "Hide Desktop Icons" 140 | menu.addItem(NSMenuItem(title: str, action: #selector(self.toggle(_:)), keyEquivalent: "")) 141 | 142 | menu.addItem(NSMenuItem.separator()) 143 | 144 | // Right or left click for menu? 145 | let menuClick = NSMenuItem(title: "Right-click to show menu", action: #selector(self.rightClicked(_:)), keyEquivalent: "") 146 | menuClick.state = defaultClick ? NSControl.StateValue.off : NSControl.StateValue.on 147 | menu.addItem(menuClick) 148 | 149 | // timer > submenu of possible times to update 150 | let timeSubMenu = NSMenu() 151 | let timeMenuItem = NSMenuItem() // Change menu > Hid/Show or Remove menu 152 | timeMenuItem.title = "Check for changing Desktop" 153 | menu.addItem(timeMenuItem) 154 | for time in defaultTimeList { 155 | let timeMI = NSMenuItem(title: time, action: #selector(self.selectTime(_:)), keyEquivalent: "") 156 | timeMI.state = defaultTime == time ? NSControl.StateValue.on : NSControl.StateValue.off 157 | timeSubMenu.addItem(timeMI) 158 | } 159 | menu.setSubmenu(timeSubMenu, for: timeMenuItem) 160 | 161 | // menu > submenu of Show/Hide or Remove remove 162 | let subMenu = NSMenu() 163 | let menuItem = NSMenuItem() // Change menu > Hid/Show or Remove menu 164 | menuItem.title = "Change menu" 165 | menu.addItem(menuItem) 166 | str = sbiHidden ? "Show menu" : "Hide menu" 167 | subMenu.addItem(NSMenuItem(title: str, action: #selector(self.sbiPic(_:)), keyEquivalent: "")) 168 | subMenu.addItem(NSMenuItem(title: "Remove menu", action: #selector(self.removeMenu(_:)), keyEquivalent: "")) 169 | menu.setSubmenu(subMenu, for: menuItem) 170 | 171 | // desktop menual > submenu of solid color oractual for just this screen or all 172 | if hidden { 173 | let (currentImage, currentColor, currentlyColored) = hider!.desktopFromPoint(NSEvent.mouseLocation, color: desktopColor) 174 | let previewSize = NSSize(width: 20, height: 20); lastDesktopColor = currentColor 175 | let bgSubMenu = NSMenu() 176 | let bgMenuItem = NSMenuItem() 177 | bgMenuItem.title = "Set Desktop wallpaper" 178 | menu.addItem(bgMenuItem) 179 | let bgT1 = NSMenuItem(title: "This Desktop", action: nil, keyEquivalent: "") 180 | bgSubMenu.addItem(bgT1) 181 | if hider!.numberOfDesktops > 1 { 182 | let bgMI = NSMenuItem(title: "actual", action: #selector(self.selectDesktop(_:)), keyEquivalent: "") 183 | if let desktopImage = currentImage { bgMI.image = NSImage(cgImage: desktopImage, size: previewSize) } 184 | bgMI.state = !currentlyColored && desktop != .allDesktop && desktop != .allSolidColorDesktop ? NSControl.StateValue.on : NSControl.StateValue.off 185 | bgMI.tag = 1 186 | bgSubMenu.addItem(bgMI) 187 | let scMI = NSMenuItem(title: "color", action: #selector(self.selectDesktop(_:)), keyEquivalent: "") 188 | scMI.image = NSImage.swatchWithColor(color: currentColor, size: previewSize) 189 | scMI.state = currentlyColored && desktop != .allDesktop && desktop != .allSolidColorDesktop ? NSControl.StateValue.on : NSControl.StateValue.off 190 | scMI.tag = 2 191 | bgSubMenu.addItem(scMI) 192 | bgSubMenu.addItem(NSMenuItem.separator()) 193 | let bgT2 = NSMenuItem(title: "All Desktops", action: nil, keyEquivalent: "") 194 | bgSubMenu.addItem(bgT2) 195 | } 196 | // note if only one screen (monitor), MenuItem has tags > 2 197 | let abgMI = NSMenuItem(title: "actual", action: #selector(self.selectDesktop(_:)), keyEquivalent: "") 198 | if let desktopImage = currentImage { abgMI.image = NSImage(cgImage: desktopImage, size: previewSize) } 199 | abgMI.state = desktop == .allDesktop ? NSControl.StateValue.on : NSControl.StateValue.off 200 | abgMI.tag = 3 201 | bgSubMenu.addItem(abgMI) 202 | let ascMI = NSMenuItem(title: "color", action: #selector(self.selectDesktop(_:)), keyEquivalent: "") 203 | ascMI.image = NSImage.swatchWithColor(color: currentColor, size: previewSize) 204 | ascMI.state = desktop == .allSolidColorDesktop ? NSControl.StateValue.on : NSControl.StateValue.off 205 | ascMI.tag = 4 206 | bgSubMenu.addItem(ascMI) 207 | menu.setSubmenu(bgSubMenu, for: bgMenuItem) 208 | 209 | menu.addItem(NSMenuItem.separator()) 210 | 211 | menu.addItem(NSMenuItem(title: "Force Desktop refresh", action: #selector(self.refreshDesktops(_:)), keyEquivalent: "")) 212 | } 213 | 214 | menu.addItem(NSMenuItem.separator()) 215 | menu.addItem(NSMenuItem(title: "Help", action: #selector(self.getHelp(_:)), keyEquivalent: "")) 216 | menu.addItem(NSMenuItem(title: "About", action: #selector(self.about(_:)), keyEquivalent: "")) 217 | 218 | if appStore || UserDefaults.standard.string(forKey: "donate") == version { // for App Store 219 | menu.addItem(NSMenuItem(title: "Say \"Hi\" to entonos", action: #selector(self.donateClicked(_:)), keyEquivalent: "")) 220 | } else { 221 | let donateItem = NSMenuItem(title: "Donate...", action: #selector(self.donateClicked(_:)), keyEquivalent: "") 222 | if updateAvailable.count < 1 { donateItem.attributedTitle = NSAttributedString(string: "Donate...", attributes: [NSAttributedString.Key.foregroundColor: NSColor.red]) } 223 | menu.addItem(donateItem) 224 | } 225 | 226 | if !appStore { 227 | menu.addItem(NSMenuItem.separator()) 228 | if updateAvailable.count > 1 { 229 | let downloadItem = NSMenuItem(title: updateMenuItem, action: #selector(self.downloadClicked(_:)), keyEquivalent: "") 230 | downloadItem.attributedTitle = NSAttributedString(string: updateMenuItem, attributes: [NSAttributedString.Key.foregroundColor: NSColor.red]) 231 | menu.addItem(downloadItem) 232 | } else if !updateDownloaded { 233 | menu.addItem(NSMenuItem(title: updateMenuItem, action: #selector(self.checkUpdate(_:)), keyEquivalent: "")) 234 | } else { 235 | let noUpdate = NSMenuItem(title: updateMenuItem, action: nil, keyEquivalent: "") 236 | noUpdate.isEnabled = false 237 | menu.addItem(noUpdate) 238 | Timer.scheduledTimer(withTimeInterval: 5*60, repeats: false) { (timer) in self.updateDownloaded = false; self.updateMenuItem = "Check for update..." } // allow for checking in 15 minutes... 239 | } 240 | } 241 | 242 | menu.addItem(NSMenuItem.separator()) 243 | menu.addItem(NSMenuItem(title: "Quit", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "")) 244 | 245 | return menu 246 | } 247 | @objc func refreshDesktops(_ sender: Any?) { // force refresh of hider 248 | desktop = .allDesktop 249 | NotificationCenter.default.post(name: .createDesktops, object: nil) 250 | NotificationCenter.default.post(name: .desktopType, object: (lastDesktopColor, desktop, NSEvent.mouseLocation)) 251 | } 252 | @objc func menuDidClose(_ menu: NSMenu) { // teardown menu for next time SBI is clicked 253 | statusBarItem?.menu = nil 254 | } 255 | @objc func selectDesktop(_ menu: NSMenuItem) { //print("in selectDesktop, menu.tag=\(menu.tag)") // selecting if desktop or all desktops are solid color or actual 256 | let option = menu.tag as Int 257 | switch option { 258 | case 2 : 259 | desktop = .solidColorDesktop 260 | case 4 : 261 | desktop = .allSolidColorDesktop 262 | case 3 : 263 | desktop = .allDesktop 264 | default: 265 | desktop = .desktop 266 | } 267 | 268 | NotificationCenter.default.post(name: .desktopType, object: (lastDesktopColor, desktop, NSEvent.mouseLocation)) 269 | if option % 2 == 1 { return } // no need for color wheel 270 | // (re)set color wheel 271 | let picker = NSColorPanel.shared 272 | picker.mode = .wheel 273 | picker.showsAlpha = false 274 | picker.hidesOnDeactivate = false 275 | picker.isFloatingPanel = true 276 | picker.setTarget(self) 277 | picker.setAction(#selector(colorChosen(_:))) 278 | picker.color = lastDesktopColor 279 | picker.collectionBehavior = .canJoinAllSpaces 280 | picker.makeKeyAndOrderFront(nil) 281 | } 282 | @objc func colorChosen(_ picker: NSColorPanel) { // we got a color 283 | desktopColor = NSColorPanel.shared.color //; print("in colorChosen \(desktop) \(desktopColor)") 284 | NotificationCenter.default.post(name: .desktopType, object: (desktopColor, desktop, NSEvent.mouseLocation)) 285 | } 286 | // called when icons should hidden or shown 287 | @objc func toggle(_ sender: Any?) { 288 | NotificationCenter.default.post(name: .doHide, object: nil) 289 | } 290 | // check for changing Desktop how often? default is never 291 | @objc func selectTime(_ menu: NSMenuItem) { 292 | defaultTime = menu.title 293 | NotificationCenter.default.post(name: .timeBG, object: defaultTimes[defaultTimeList.firstIndex(where: {$0 == defaultTime}) ?? 0]) 294 | UserDefaults.standard.set(defaultTime, forKey: "defaultTime") 295 | } 296 | // called when status bar item should be hidden or shown 297 | @objc func sbiPic(_ sender: Any?) { 298 | statusBarItem?.button?.image = sbiHidden ? sbiPicture : sbiNoPicture 299 | sbiHidden = !sbiHidden 300 | UserDefaults.standard.set(sbiHidden, forKey: "sbiHidden") // save choice 301 | } 302 | // called when switching left & right clicks 303 | @objc func rightClicked(_ sender: Any?) { 304 | defaultClick = !defaultClick 305 | UserDefaults.standard.set(defaultClick, forKey: "defaultClick") // save choice 306 | } 307 | 308 | @objc func removeMenu(_ sender: Any?) { 309 | statusBarItem = nil 310 | } 311 | 312 | @objc func getHelp(_ sender: Any?) { 313 | if let book = Bundle.main.object(forInfoDictionaryKey: "CFBundleHelpBookName") as? NSHelpManager.BookName { 314 | NSHelpManager.shared.openHelpAnchor("Welcome", inBook: book) 315 | } 316 | } 317 | // say "Hi" 318 | @objc func donateClicked(_ sender: Any?) { 319 | if appStore || UserDefaults.standard.string(forKey: "donate") == version { // for App Store 320 | let url = URL(string: "https://entonos.com/index.php/the-geek-shop/") 321 | //let url = URL(string: "https://entonos.com/") 322 | NSWorkspace.shared.open(url!) 323 | } else { // NO via Apple because of paypal donate link. apple's math is about as good as their physics engine (i.e. 30% of 0 is still 0) 324 | let url = URL(string: "http://www.parker9.com/d") 325 | NSWorkspace.shared.open(url!) 326 | UserDefaults.standard.set(version, forKey: "donate") 327 | } 328 | } 329 | 330 | @objc func about(_ sender: Any?) { 331 | NSApplication.shared.orderFrontStandardAboutPanel(nil) 332 | } 333 | // read in user preferences 334 | func setDefaultValues() { 335 | defaultClick = ( UserDefaults.standard.object(forKey: "defaultClick") == nil) ? defaultClick : UserDefaults.standard.bool(forKey: "defaultClick") 336 | sbiHidden = ( UserDefaults.standard.object(forKey: "sbiHidden") == nil) ? sbiHidden : UserDefaults.standard.bool(forKey: "sbiHidden") 337 | defaultTime = (( UserDefaults.standard.object(forKey: "defaultTime") == nil) ? defaultTime : UserDefaults.standard.string(forKey: "defaultTime")) ?? defaultTime 338 | defaultTime = defaultTimeList[defaultTimeList.firstIndex(where: {$0 == defaultTime}) ?? 0] // make sure defaultTime is a valid string 339 | } 340 | @objc func checkUpdate(_ sender: Any?) { 341 | let prog = Bundle.main.object(forInfoDictionaryKey: "CFBundleIdentifier") as! String 342 | let url = URL(string: "https://www.parker9.com/com.parker9.versions.plist")! 343 | URLCache.shared.removeAllCachedResponses() 344 | let getDB = URLSession.shared.dataTask(with: url) { data, response, error in 345 | if error != nil || data == nil { self.updateDownloaded = true; self.updateMenuItem = "Error connecting to server"; return } 346 | guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else { self.updateDownloaded = true; self.updateMenuItem = "Error from update server"; return } 347 | do { 348 | let database = try PropertyListSerialization.propertyList(from: data!, format: nil) as! [String : [String]] 349 | if let progData = database[prog] { 350 | if self.version != progData[0] { 351 | self.updateAvailable = progData 352 | if let downloadFile = URL(string: self.updateAvailable[1]) { 353 | let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String 354 | let target = (FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask)[0]).appendingPathComponent(downloadFile.lastPathComponent) 355 | //self.updateMenuItem = (!FileManager.default.fileExists(atPath: target.path)) ? "Download " + appName + " version " + self.updateAvailable[0] + "..." : "Locate new " + appName + " version..." 356 | self.updateMenuItem = (!FileManager.default.fileExists(atPath: target.path)) ? "Download " + self.updateAvailable[1] + "..." : "Locate new " + appName + " version..." 357 | DispatchQueue.main.async { self.statusBarItem?.button?.image = self.sbiPictureUpdate } 358 | } 359 | } else { self.updateDownloaded = true; self.updateMenuItem = "No update available"} 360 | } 361 | } catch { self.updateDownloaded = true; self.updateMenuItem = "Error in update data" } 362 | } 363 | getDB.resume() 364 | } 365 | @objc func downloadClicked(_ sender: Any?) { 366 | if let downloadFile = URL(string: updateAvailable[1]) { 367 | let downloads = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask)[0] 368 | let target = downloads.appendingPathComponent(downloadFile.lastPathComponent) 369 | let prog = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String 370 | let app = downloads.appendingPathComponent(prog + ".app") 371 | if !updateDownloaded { 372 | updateMenuItem = "Trying to download latest version..." 373 | URLCache.shared.removeAllCachedResponses() 374 | let getUpdate = URLSession.shared.downloadTask(with: downloadFile) { (tFileUrl, response, error) in 375 | if error != nil || tFileUrl == nil { self.updateAvailable.removeAll(); self.updateDownloaded = true; self.updateMenuItem = "Error connecting for download"; return } 376 | guard let response = response as? HTTPURLResponse, let fileURL = tFileUrl, (200...299).contains(response.statusCode) else { self.updateAvailable.removeAll(); self.updateDownloaded = true; self.updateMenuItem = "Error downloading update"; return } 377 | do { 378 | if FileManager.default.fileExists(atPath: target.path) { try? FileManager.default.trashItem(at: target, resultingItemURL: nil) } 379 | try FileManager.default.moveItem(at: fileURL, to: target) 380 | self.updateMenuItem = "Locate new " + (Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String) + " version..." 381 | if FileManager.default.fileExists(atPath: app.path) { try? FileManager.default.trashItem(at: app, resultingItemURL: nil) } 382 | NSWorkspace.shared.open(target) 383 | self.updateDownloaded = true 384 | DispatchQueue.main.async { 385 | Timer.scheduledTimer(withTimeInterval: 30, repeats: false) { (timer) in 386 | if FileManager.default.fileExists(atPath: app.path) { 387 | timer.invalidate() 388 | try? FileManager.default.trashItem(at: target, resultingItemURL: nil) 389 | } 390 | } 391 | } 392 | } catch { self.updateAvailable.removeAll(); self.updateDownloaded = true; self.updateMenuItem = "Error saving update"; return } 393 | } 394 | getUpdate.resume() 395 | } else { 396 | NSWorkspace.shared.selectFile(app.path, inFileViewerRootedAtPath: downloads.path) } 397 | } 398 | } 399 | } 400 | 401 | extension NSEvent { // so .rightMouseDown does not capture control+.leftMouseDown; fix that. 402 | var isRightClick: Bool { 403 | return (self.type == .rightMouseDown) || (self.type == .leftMouseDown && self.modifierFlags.contains(.control)) 404 | } 405 | } 406 | 407 | extension NSImage { // return an solid color image 408 | class func swatchWithColor(color: NSColor, size: NSSize) -> NSImage { 409 | let image = NSImage(size: size) 410 | image.lockFocus() 411 | color.drawSwatch(in: NSRect(origin: .zero, size: size)) 412 | image.unlockFocus() 413 | return image 414 | } 415 | } 416 | 417 | enum DesktopTypes: Int { // different options for Desktop wallpapers 418 | case allDesktop = 1, desktop, allSolidColorDesktop, solidColorDesktop 419 | } 420 | -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/.DS_Store -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AlphaBarButtonImage.imageset/AlphaBarButtonImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AlphaBarButtonImage.imageset/AlphaBarButtonImage@2x.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AlphaBarButtonImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "AlphaBarButtonImage@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Hide_16x16.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "Hide_16x16@2x.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "Hide_32x32.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "Hide_32x32@2x.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "Hide_128x128.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "Hide_128x128@2x.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "Hide_256x256.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "Hide_256x256@2x.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "Hide_512x512.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "Hide_512x512@2x.png", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_128x128.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_128x128@2x.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_16x16.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_16x16@2x.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_256x256.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_256x256@2x.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_32x32.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_32x32@2x.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_512x512.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/AppIcon.appiconset/Hide_512x512@2x.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/BBarButtonImage.imageset/BBarButtonImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/BBarButtonImage.imageset/BBarButtonImage@2x.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/BBarButtonImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "BBarButtonImage@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | }, 21 | "properties" : { 22 | "template-rendering-intent" : "template" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/BBarButtonImageUpdate.imageset/BBarButtonImageUpdate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Assets.xcassets/BBarButtonImageUpdate.imageset/BBarButtonImageUpdate@2x.png -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/BBarButtonImageUpdate.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "BBarButtonImageUpdate@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /HideIcons/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /HideIcons/HideIcons.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.files.downloads.read-write 6 | 7 | com.apple.security.network.client 8 | 9 | com.apple.security.app-sandbox 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /HideIcons/Hider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Hider.swift 3 | // 4 | // Created by G.J. Parker on 21/04/02. 5 | // Copyright © 2021 G.J. Parker. All rights reserved. 6 | // 7 | 8 | import Cocoa 9 | 10 | extension Notification.Name { 11 | static let doHide = NSNotification.Name("doHide") //toggle hide/show Desktop icons 12 | static let createDesktops = NSNotification.Name("createDesktops") //recreate windows for all Desktops 13 | static let timeBG = NSNotification.Name("timeBG") //change the time interval for background updates 14 | static let desktopType = NSNotification.Name("desktopType") //support for solid color or actual Desktop wallpaper 15 | } 16 | 17 | extension NSWindow.Level { 18 | static let hiddenLayer = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.desktopWindow))-2) 19 | static let floatLayer = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.desktopIconWindow))+1) 20 | static let staticLayer = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.desktopIconWindow))+5) 21 | } 22 | 23 | class Hider { // class that covers Desktop w/ pictures of Desktop- invoked by notifications and/or internal timers 24 | 25 | class MyWindow : NSWindow { // just add some data and methods for NSWindow- this will hold a window w/ a Desktop pic 26 | var color: NSColor? = nil // display solid color instead of actual Desktop? nil means actual, otherwise that color 27 | var beingUsed = false 28 | 29 | init(contentRect: NSRect, hidden: Bool) { 30 | super.init(contentRect: contentRect, styleMask: .borderless, backing: .buffered, defer: false) // create NSWindow 31 | reset(contentRect: contentRect, hidden: hidden) 32 | } 33 | 34 | func reset(contentRect: NSRect, hidden: Bool) { 35 | self.setFrame(contentRect, display: true, animate: false) // force the correct frame for window 36 | //if #available(macOS 13.0, *) { self.collectionBehavior = [.canJoinAllSpaces, .canJoinAllApplications, .fullScreenNone, .ignoresCycle] } else { self.collectionBehavior = [.canJoinAllSpaces, .fullScreenNone, .ignoresCycle] } 37 | self.collectionBehavior = [.canJoinAllSpaces, .fullScreenNone, .ignoresCycle] 38 | self.level = hidden ? .floatLayer : .hiddenLayer 39 | //self.orderFrontRegardless() //place on top of this level 40 | self.beingUsed = true 41 | // rest is to make the window dumb 42 | self.canHide = false; self.isExcludedFromWindowsMenu = true; self.isOpaque = true 43 | self.hasShadow = false; self.hidesOnDeactivate = false; self.discardCursorRects() 44 | self.discardEvents(matching: .any, before: nil); self.ignoresMouseEvents = true; self.isRestorable = false 45 | self.animationBehavior = .none 46 | } 47 | 48 | func setWin(imageView: NSImageView, onScreen: Bool, hidden: Bool) { // update picture and pin if we found the correct Space 49 | self.contentView = nil; self.contentView = imageView 50 | if onScreen && !self.collectionBehavior.contains(.stationary) { 51 | // pin this window to this Space 52 | self.collectionBehavior = [.stationary, .fullScreenNone, .ignoresCycle] 53 | self.level = hidden ? .staticLayer : .hiddenLayer //; print("set") // move to top of this level 54 | } 55 | //print("in setWin, beingUsed=\(self.beingUsed), onScreen=\(onScreen) \(self.isOnActiveSpace), hidden=\(hidden), stationary?=\(self.collectionBehavior.contains(.stationary)), screen.frame==frame?\(self.screen?.frame == self.frame), frame=\(self.frame)") 56 | } 57 | } 58 | 59 | private var myDesktops : [ CGWindowID : MyWindow] = [:] // 60 | private var backupDesktops : [ MyWindow] = [] 61 | private var BGTimer : Timer? // lazy update for Desktop pics 62 | private var BGTime = TimeInterval(730000.0) // time interveral for lazy updates 63 | private var hidden_ = false // are icons hidden? 64 | private var observation: NSKeyValueObservation? // Apple doc- to detect dark/light mode switch 65 | 66 | var hidden: Bool { // are icons currently hidden? 67 | get { return hidden_ } 68 | set (value) { hidden_ = value } 69 | } 70 | // hide or show Desktop icons 71 | func doHide() { //print("in doHide, hidden=\(!hidden), empty myDesktops?\(myDesktops.isEmpty)") 72 | hidden = !hidden // toggle hide/show icons 73 | if hidden { // appears the user want to hide icons 74 | updateDesktops(true) // force all Desktops to be updated 75 | backupDesktops.filter({return $0.beingUsed}).forEach({win in win.level = .floatLayer}) 76 | myDesktops.forEach({_, win in win.level = win.collectionBehavior.contains(.stationary) ? .staticLayer : .floatLayer}) 77 | } else { 78 | BGTimer?.invalidate() // stop timer since icons are not hidden 79 | myDesktops.forEach({ _, win in win.level = .hiddenLayer}) // don't show any of the Desktop windows 80 | backupDesktops.forEach({win in win.level = .hiddenLayer}) 81 | } 82 | } 83 | // start a repeating timer to update all Desktops 84 | func doTimer() { //print("in doTimer, BGTime=\(BGTime), valid?\(BGTime < 720000.0)") 85 | BGTimer?.invalidate() 86 | if BGTime < 720000.0 && hidden { //print("start BGTimer") only start timer if time interval is less than 200 hours 87 | BGTimer = Timer.scheduledTimer(withTimeInterval: BGTime, repeats: true, block: { _ in self.updateDesktops(true) })//; print(BGTimer) }) 88 | } 89 | } 90 | // called when user changes the repeating timer interval 91 | @objc func timerChanged(_ notifier : Notification) { //print("in timerChanged, TimeInterval=\(notifier.object as! TimeInterval)") 92 | if let time = notifier.object as? TimeInterval { 93 | BGTime = time 94 | doTimer() 95 | } 96 | } 97 | 98 | func updateDesktops(_ doAll : Bool = false) { // update pictures of Desktop(s) 99 | BGTimer?.invalidate() // stop any timers 100 | //print("updateDesktops, doAll=\(doAll) number of myDesktops:\(myDesktops.count), screens:\(Set(myDesktops.map({$0.value.screen})).count) (\(myDesktops.reduce(0) {n, w in return n + (w.value.screen != nil ? 1 : 0)})) (\(NSScreen.screens.count)) number of CGDesktop on screen: \(getDesktopArray().reduce(0) { numOnScreen, window in let onScreen = window[kCGWindowIsOnscreen as String] as? Bool ?? false; return numOnScreen + (onScreen ? 1 : 0)}) \(memoryFootprint()) # of backups:\(backupDesktops.count)") 101 | 102 | for (cgWin, onScreen) in getDesktopArray(doAll ? .optionAll : .optionOnScreenOnly).map({ ($0[kCGWindowNumber as String] as! CGWindowID, $0[kCGWindowIsOnscreen as String] as? Bool ?? false)}) { 103 | if let win = myDesktops[cgWin] { //print("cgWin=\(cgWin), onScreen=\(onScreen), stationary?\(myDesktops[cgWin]?.collectionBehavior == .stationary)") 104 | setImageView(cgWin: cgWin, win: win, onScreen: onScreen) //;print(cgWin,myDesktops[cgWin]!.frame,onScreen,myDesktops[cgWin]!.collectionBehavior.contains(.stationary),hidden) 105 | } //else { print(" OOPS- \(cgWin) is not in MyDesktops!") } 106 | } //;print(" ") 107 | doTimer() // restart any timers 108 | //print("number of myDesktops:\(myDesktops.count), screens:\(Set(myDesktops.map({$0.value.screen})).count), NSScreen:\(NSScreen.screens.count) \(memoryFootprint())") 109 | } 110 | 111 | func setImageView(cgWin: CGWindowID, win : MyWindow, onScreen : Bool) { 112 | if let color = win.color { 113 | // let image = NSImage.swatchWithColor(color: color, size: win.frame.size) // this too way too much memory, do 1x1 and the scaleAxesIndependently to fill in full desktop 114 | let image = NSImage.swatchWithColor(color: color, size: NSSize(width: 1, height: 1)) 115 | let imageView = NSImageView(image: image) 116 | imageView.imageScaling = .scaleAxesIndependently 117 | win.setWin(imageView: imageView, onScreen: onScreen, hidden: hidden) 118 | } else { 119 | guard let cgImage = CGWindowListCreateImage(CGRectNull, [.optionIncludingWindow], cgWin, [.nominalResolution]) else { return } 120 | let image = NSImage(cgImage: cgImage, size: NSZeroSize) 121 | let imageView = NSImageView(image: image) 122 | win.setWin(imageView: imageView, onScreen: onScreen, hidden: hidden) 123 | } 124 | //print(cgWin, onScreen, win.isOnActiveSpace, hidden, win == nil, win.level == hiddenLayer, win.level == floatLayer, win.level == staticLayer) 125 | } 126 | 127 | func getDesktopArray(_ option: CGWindowListOption = .optionAll) -> [[String: AnyObject]] { 128 | var nTry = 0 129 | repeat { 130 | // need to find Desktop windows... (let's use apple's approved way so we don't trip up security guards) 131 | let windows = CGWindowListCopyWindowInfo([option], kCGNullWindowID)! as! [[String: AnyObject]] // get (all or onscreen) windows 132 | let desktopWindowLevel = CGWindowLevelForKey(.desktopWindow) - 1 // level of Desktop background image 133 | let desktopWindows = windows.filter { // get array of dictionaries for Desktop CGWindows 134 | let windowLevel = $0[kCGWindowLayer as String] as! CGWindowLevel 135 | return windowLevel == desktopWindowLevel 136 | } 137 | /* 138 | let desktopIconWindowLevel = CGWindowLevelForKey(.desktopIconWindow) //- 1 // level of Desktop background image 139 | let desktopIconWindows = windows.filter { // get array of dictionaries for Desktop CGWindows 140 | let windowLevel = $0[kCGWindowLayer as String] as! CGWindowLevel 141 | return windowLevel == desktopIconWindowLevel 142 | } 143 | print("number of desktopIconWindows: \(desktopIconWindows.count)") 144 | for win in desktopIconWindows { 145 | print(win[kCGWindowBounds as String],win[kCGWindowOwnerPID as String],win[kCGWindowOwnerName as String],win[kCGWindowLayer as String],win[kCGWindowIsOnscreen as String] as? Bool ?? false) 146 | } 147 | for win in backupDesktops { print(win.isOpaque,win.isVisible,win.orderedIndex,win.level)} 148 | print("number of desktops: \(desktopWindows.count)") 149 | */ 150 | var screenRect: [CGRect] = [] 151 | let numOnScreen = desktopWindows.reduce(0) { numOnScreen, window in // find the number of desktops onScreen and also construct array of unique screen CGRects 152 | let rect = CGRect(dictionaryRepresentation: window[kCGWindowBounds as String] as! CFDictionary)! 153 | if !screenRect.contains(rect) { screenRect.append(rect)} 154 | let onScreen = window[kCGWindowIsOnscreen as String] as? Bool ?? false 155 | return numOnScreen + (onScreen ? 1 : 0) 156 | } 157 | let n = screenRect.count 158 | let good = n == NSScreen.screens.count || n == backupDesktops.count || n == backupDesktops.filter({return $0.beingUsed}).count 159 | //print("numOnScreen=\(numOnScreen), screenRect.count=\(screenRect.count), backup.count=\(backupDesktops.filter({return $0.beingUsed}).count), screens.count=\(NSScreen.screens.count), good=\(good), nTry=\(nTry)") 160 | if (numOnScreen == screenRect.count && good) || nTry > 20 { return desktopWindows } 161 | usleep(150_000) 162 | nTry += 1 // FIX ME? 163 | } while true 164 | } 165 | 166 | func createDesktops() { //print("createDesktops, myDesktop.count=\(myDesktops.count)") // make window for each desktop 167 | BGTimer?.invalidate() // stop any timer 168 | 169 | //print("createDesktops, myDesktop.count=\(myDesktops.count) (\(myDesktops.reduce(0) {n, w in return n + (w.value.screen != nil ? 1 : 0)})) number of CGDesktop on screen: \(getDesktopArray().reduce(0) { numOnScreen, window in let onScreen = window[kCGWindowIsOnscreen as String] as? Bool ?? false; return numOnScreen + (onScreen ? 1 : 0)}) number of monitors: \(Set(myDesktops.map({$0.value.screen})).count) \(memoryFootprint())") 170 | //print("number of backupDesktops:\(backupDesktops.count), \(backupDesktops.filter({return $0.beingUsed}).count), \(NSScreen.screens.count)") 171 | createBackups() //;print("number of backupDesktops:\(backupDesktops.count), \(backupDesktops.filter({return $0.beingUsed}).count), \(NSScreen.screens.count)") 172 | 173 | let screens = NSScreen.screens; let h0 = NSHeight(screens[0].frame) // height of Screen that has menu bar 174 | myDesktops.forEach({ _, win in win.beingUsed = false; win.level = .hiddenLayer; win.orderOut(nil) }) // assume window is not going to be used 175 | for (cgID, onScreen, rectCG) in getDesktopArray().map({ ($0[kCGWindowNumber as String] as! CGWindowID, $0[kCGWindowIsOnscreen as String] as? Bool ?? false, CGRect(dictionaryRepresentation: $0[kCGWindowBounds as String] as! CFDictionary)!)}) { 176 | let origin = CGPoint(x: rectCG.origin.x, y: h0 - rectCG.origin.y - rectCG.height) 177 | let rect = CGRect(origin: origin, size: rectCG.size) // CGrect is in Screen coordinate 178 | //print("is cgID not in myDesktops? \(myDesktops[cgID]==nil)") 179 | if let win = myDesktops[cgID] { 180 | win.reset(contentRect: rect, hidden: hidden) 181 | } else { 182 | myDesktops[cgID] = MyWindow(contentRect: rect, hidden: hidden) 183 | } 184 | setImageView(cgWin: cgID, win: myDesktops[cgID]!, onScreen: onScreen) //;print(cgID,myDesktops[cgID]!.frame) 185 | } 186 | //print("number of myDesktops:\(myDesktops.count), \(NSScreen.screens.count)") 187 | for cgID in myDesktops.filter({ return !$0.value.beingUsed}).keys { //print(cgID,myDesktops[cgID]!.frame,myDesktops[cgID]!.beingUsed) // remove any myDesktops that are not being used 188 | myDesktops[cgID]?.orderOut(nil); myDesktops.removeValue(forKey: cgID)//if let myD = myDesktops.removeValue(forKey: cgID) {myD.close()} //?.close() 189 | } //;print("number of myDesktops:\(myDesktops.count), \(NSScreen.screens.count)") 190 | myDesktops.forEach({_, win in win.orderFrontRegardless()}) 191 | 192 | //getDesktopArray().reduce(0,{$1[kCGWindowIsOnscreen as String] as? Bool ?? false}) 193 | //print("createDesktops, myDesktop.count=\(myDesktops.count) (\(myDesktops.reduce(0) {n, w in return n + (w.value.screen != nil ? 1 : 0)})) number of CGDesktop on screen: \(getDesktopArray().reduce(0) { numOnScreen, window in let onScreen = window[kCGWindowIsOnscreen as String] as? Bool ?? false; return numOnScreen + (onScreen ? 1 : 0)}) number of monitors: \(Set(myDesktops.map({$0.value.screen})).count)") 194 | doTimer() 195 | //print("number of myDesktops:\(myDesktops.count), screens:\(Set(myDesktops.map({$0.value.screen})).count) \(memoryFootprint())") 196 | } 197 | func createBackups() { 198 | backupDesktops.forEach({ win in win.beingUsed = false; win.orderOut(nil); win.level = .hiddenLayer }) 199 | while NSScreen.screens.count < 1 { usleep(150_000) } 200 | let screens = NSScreen.screens 201 | for (idx, screen) in screens.enumerated() { 202 | if idx >= backupDesktops.count { 203 | backupDesktops.append(MyWindow(contentRect: screen.frame, hidden: hidden)) 204 | } else { 205 | backupDesktops[idx].reset(contentRect: screen.frame, hidden: hidden) 206 | } 207 | backupDesktops[idx].color = .black 208 | setImageView(cgWin: 0, win: backupDesktops[idx], onScreen: false) 209 | } 210 | backupDesktops.forEach({win in if win.beingUsed {win.orderFrontRegardless()}}) //; backupDesktops.forEach({win in print(win.frame,win.beingUsed)}) 211 | } 212 | // number of Desktops 213 | var numberOfDesktops: Int { 214 | get { return getDesktopArray().count } 215 | } 216 | // given a point on screen, return the Desktop image and color 217 | func desktopFromPoint(_ point : CGPoint, color : NSColor) -> (CGImage?, NSColor, Bool) { 218 | for screen in NSScreen.screens.filter({return $0.frame.contains(point)}) { 219 | for cgID in getDesktopArray(.optionOnScreenOnly).map({ $0[kCGWindowNumber as String] as! CGWindowID}) { 220 | if myDesktops[cgID]?.screen == screen { 221 | guard let cgImage = CGWindowListCreateImage(.null, [.optionIncludingWindow], cgID, [.nominalResolution]) else { continue } 222 | return (cgImage, myDesktops[cgID]!.color ?? color, myDesktops[cgID]!.color != nil) 223 | } 224 | } 225 | } 226 | return (nil, color, false) 227 | } 228 | // want solid color or actual wallpaper for Desktop 229 | @objc func desktopTypeChange(_ notifier: Notification) { 230 | BGTimer?.invalidate() 231 | let (color, desktop, mousePoint ) = notifier.object as? (NSColor, DesktopTypes, CGPoint) ?? (NSColor.black, .allDesktop, CGPoint.zero) 232 | switch desktop { 233 | case .solidColorDesktop, .desktop: // one Desktop is either getting a solid color or the actual Desktop, find it 234 | for screen in NSScreen.screens.filter({$0.frame.contains(mousePoint)}) { // only if the mouse click was on this screen 235 | for cgID in getDesktopArray(.optionOnScreenOnly).map({ $0[kCGWindowNumber as String] as! CGWindowID}) { 236 | if myDesktops[cgID]?.screen == screen { myDesktops[cgID]!.color = (desktop == .solidColorDesktop) ? color : nil } 237 | } 238 | } 239 | default: // all Desktops are actual or solid color 240 | myDesktops.forEach({ _, win in win.color = (desktop == .allSolidColorDesktop) ? color : nil }) 241 | } 242 | updateDesktops(desktop == .allDesktop || desktop == .allSolidColorDesktop) // will also restart timer 243 | } 244 | // set up initial window lists for each screen and observers 245 | init() { 246 | hidden = true 247 | createDesktops() // go grab all the Desktops 248 | 249 | let NCdefault = NotificationCenter.default 250 | NCdefault.addObserver(self, selector: #selector(self.timerChanged(_:)), name: .timeBG, object: nil) // catch background timer interval 251 | NCdefault.addObserver(self, selector: #selector(self.desktopTypeChange(_:)), name: .desktopType, object: nil) // desktops are actual or solid color, for one or all 252 | NCdefault.addObserver(forName: .createDesktops, object: nil, queue: .main, using: { not in self.createDesktops() }) 253 | NCdefault.addObserver(forName: NSApplication.didChangeScreenParametersNotification, object: nil, queue: .main, using: {_ in //print("didChangeScreenParameters \(self.memoryFootprint())"); 254 | self.BGTimer?.invalidate(); usleep(500_000); self.createDesktops()}) //;print("didChangeScreenParameters done \(self.memoryFootprint())")}) 255 | NCdefault.addObserver(forName: .doHide, object: nil, queue: .main, using: {_ in self.doHide() }) 256 | let WSsharedNC = NSWorkspace.shared.notificationCenter 257 | WSsharedNC.addObserver(forName: NSWorkspace.screensDidSleepNotification, object: nil, queue: .main, using: {_ in self.BGTimer?.invalidate() })//; print("didSleep") }) 258 | WSsharedNC.addObserver(forName: NSWorkspace.screensDidWakeNotification, object: nil, queue: .main, using: {_ in //print("didWake \(self.memoryFootprint())") 259 | self.updateDesktops(true)}) //; print("didWake done \(self.memoryFootprint())") }) 260 | WSsharedNC.addObserver(forName: NSWorkspace.activeSpaceDidChangeNotification, object: nil, queue: .main, using: { _ in //print("activeSpaceDidChange \(self.memoryFootprint())") 261 | self.BGTimer?.invalidate(); usleep(150_000); self.updateDesktops(true)}) //;print("activeSpaceDidChange done \(self.memoryFootprint())")}) //ugh! FIXME apple 262 | 263 | // this should capture in/out of Dark Mode 264 | if #available(OSX 10.14, *) { 265 | observation = NSApp.observe(\.effectiveAppearance) { (app, _) in 266 | if self.hidden { // give 3 second delay to make sure the Desktop did in fact update 267 | Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false, block: { _ in self.updateDesktops(true)}) //; print("mode change!") }) 268 | } 269 | } 270 | } 271 | } 272 | // tear down observers (is this really necessary?) 273 | deinit { 274 | observation?.invalidate(); BGTimer?.invalidate() // invalidate any background timers 275 | let WSsharedNC = NSWorkspace.shared.notificationCenter 276 | WSsharedNC.removeObserver(self, name: NSWorkspace.activeSpaceDidChangeNotification, object: nil) 277 | WSsharedNC.removeObserver(self, name: NSWorkspace.screensDidWakeNotification, object: nil) 278 | WSsharedNC.removeObserver(self, name: NSWorkspace.screensDidSleepNotification, object: nil) 279 | let NCdefault = NotificationCenter.default 280 | NCdefault.removeObserver(self, name: .doHide, object: nil) 281 | NCdefault.removeObserver(self, name: .timeBG, object: nil) 282 | NCdefault.removeObserver(self, name: NSApplication.didChangeScreenParametersNotification, object: nil) 283 | NCdefault.removeObserver(self, name: .createDesktops, object: nil) 284 | NCdefault.removeObserver(self, name: .desktopType, object: nil) 285 | myDesktops.removeAll(); backupDesktops.removeAll() // and free up screen/window dictionary 286 | } 287 | 288 | func memoryFootprint() -> String { 289 | // The `TASK_VM_INFO_COUNT` and `TASK_VM_INFO_REV1_COUNT` macros are too 290 | // complex for the Swift C importer, so we have to define them ourselves. 291 | let TASK_VM_INFO_COUNT = mach_msg_type_number_t(MemoryLayout.size / MemoryLayout.size) 292 | guard let offset = MemoryLayout.offset(of: \task_vm_info_data_t.min_address) else {return "memory: NA"} 293 | let TASK_VM_INFO_REV1_COUNT = mach_msg_type_number_t(offset / MemoryLayout.size) 294 | var info = task_vm_info_data_t() 295 | var count = TASK_VM_INFO_COUNT 296 | let kr = withUnsafeMutablePointer(to: &info) { infoPtr in 297 | infoPtr.withMemoryRebound(to: integer_t.self, capacity: Int(count)) { intPtr in 298 | task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), intPtr, &count) 299 | } 300 | } 301 | guard 302 | kr == KERN_SUCCESS, 303 | count >= TASK_VM_INFO_REV1_COUNT 304 | else { return "memory: NA" } 305 | 306 | let usedBytes = Float(info.phys_footprint) 307 | let usedBytesInt: UInt64 = UInt64(usedBytes) 308 | let usedMB = usedBytesInt / 1024 / 1024 309 | let usedMBAsString: String = "memory: \(usedMB) MB" 310 | return usedMBAsString 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /HideIcons/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleHelpBookFolder 10 | HideIcons.help 11 | CFBundleHelpBookName 12 | com.parker9.HideIcons.help 13 | CFBundleIconFile 14 | 15 | CFBundleIdentifier 16 | $(PRODUCT_BUNDLE_IDENTIFIER) 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | $(PRODUCT_NAME) 21 | CFBundlePackageType 22 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 23 | CFBundleShortVersionString 24 | $(MARKETING_VERSION) 25 | CFBundleVersion 26 | $(CURRENT_PROJECT_VERSION) 27 | LSApplicationCategoryType 28 | public.app-category.utilities 29 | LSMinimumSystemVersion 30 | $(MACOSX_DEPLOYMENT_TARGET) 31 | LSUIElement 32 | 33 | LSUIPresentationMode 34 | 0.0 35 | NSDownloadsFolderUsageDescriptionNSDownloadsFolderUsageDescription 36 | So we can download a new version of Hide Icons. 37 | NSHumanReadableCopyright 38 | Copyright © 2024 G.J. Parker (entonos) 39 | NSPrincipalClass 40 | NSApplication 41 | NSServices 42 | 43 | 44 | NSKeyEquivalent 45 | 46 | default 47 | D 48 | 49 | NSMenuItem 50 | 51 | default 52 | Toggle Desktop Icons 53 | 54 | NSMessage 55 | toggleService 56 | NSRequiredContext 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleIdentifier 8 | com.parker9.HideIcons.help 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | BNDL 13 | CFBundleShortVersionString 14 | 4.0 15 | CFBundleSignature 16 | hbwr 17 | CFBundleVersion 18 | 1 19 | HPDBookAccessPath 20 | index.html 21 | HPDBookIconPath 22 | Hide_256x256.png 23 | HPDBookIndexPath 24 | HideIcons.helpindex 25 | HPDBookTitle 26 | Hide Icons Help 27 | HPDBookType 28 | 3 29 | HPDBookUsesExternalViewer 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/Hide_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Resources/HideIcons.help/Contents/Resources/Hide_256x256.png -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Contact_and_version_hist.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Contact and version history 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 | Contact and version history 17 |

18 |

Hide Icons’ home is located at http://www.parker9.com/script.html. Furthermore, email can be sent to HideIcon@parker9.com

19 | 20 |

Version History

21 |

— 25 April 2024, v2.2.1- Fixed a problem when repeated typing of shortcut (via Services) did not work.

22 |

— 17 September 2023, v2.2- Reduced memory useage and for non Mac App store version. Add "Check for update..." to menu and offer to download if available.

23 |

— 19 January 2023, v2.1.1- Fix possible crash when number of connected monitors changes (can happen temporarily during wake from sleep).

24 |

— 6 January 2023, v2.1- In Ventura (13+) the wrong Desktop is flashed when changing spaces (apparently a bug via Apple). Instead of relying on the ordering of windows in a window level, we now construct window levels so we don't depend on ordering within a level.

25 |

— 6 July 2022, v2.0.2- Fixed crash by performing additional checks on CoreGraphics output (thanks to anonymous crash reports!).

26 |

— 25 May 2022, v2.0.1- Workaround for occasional CoreGraphic delay on updating which Desktops are on screen. Workaround for NSScreen.screens not accurately reflecting attached screens. Update all Desktop windows when Space change (not just the new Space). Added floating black backup Desktops in case normal Desktop pictures get pinned to incorrect Space. Memory leak fixed when number of attached screens change. Added FAQ to Help.

27 |

— 12 May 2022, v2.0- Rewrite of Hider class to work around current Apple bugs.

28 |

— 28 Febuary 2022, v1.5.3- New menu option to set Desktop wallpaper- either for all or individual Desktops. Minor bug fixes. Attempted workaround for Apple bug by delaying 0.15 (0.5) sec every Space Change (Screen Wake) notification. No workaround for macOS Mojave (11.6.4) bug resulting in flashing icons during Space Change.

29 |

— 1 January 2022, v1.4.2- New menu option to set time interval to refresh Desktop to allow for changing Desktops. Refactoring of code and support for Monterey.

30 |

— 21 December 2021, v1.3- New menu option to refresh Desktop; bug fix for when a Display sleeps (can return a gray Desktop under Big Sur and later).

31 |

— 12 August 2021, v1.2- Left-click shows menu while right-click toggles icons; option to reverse click behavior; memorize user preferences.

32 |

— 13 May 2021, v1.1.1- Bug fix so we don't forget Desktop and display pairings if icons are shown.

33 |

— 4 May 2021, v1.1- Icons won't flash when entering Exposé; learns which Desktop goes with which Space; add About menu; when started by Service do not display menu.

34 |

— 30 April 2021, v1.0- Initial release.

35 | 36 |

Welcome

37 | 38 |

39 | G.J. Parker- http://www.parker9.com (Entonos) 40 |

41 | 42 | 43 | -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/HideIcons.helpindex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/HideIcons.helpindex -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | "HPDBookTitle" = "Hide Icons Help"; 2 | "CFBundleName" = "Hide Icons Help"; 3 | -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Welcome to Hide Icons 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 | Welcome to Hide Icons 17 |

18 | 19 |

20 | 21 | 

22 | 23 |

Hide Icons effectively hides your Desktop icons. Ideally it should be placed in the Applications folder. It can be specified as a Login Item in your user account as a nice way to have the application run automatically.

24 | 25 |

1) Use

26 |

Hide Icon is used two ways:

27 |
  • ) As a Service
28 |

29 | 30 | 

31 |

Notice the default key combination (this can be changed, see below).

32 |
  • ) As a menu item, 33 | 34 | 
35 |

36 | 37 | 

38 |

Show Desktop icons/Hide Desktop Icons toggles showing or hiding the Desktop icons.

39 |

If Right-click to show menu is enabled, then clicking on the the menu () will toggle Show/Hide Desktop icons and right-click will open the menu. The default is the opposite behavior. 40 |

41 |

If Check for changing Desktop is set to anything other than Never, Hide Icons will update the Desktop every time interval specified. This allows for changing Desktops.

42 |

Change menu allows you to hide the menu item (replaces it with a blank icon) or to completely remove the menu from the menu bar. For the latter case, one can still use Services to toggle showing/hiding icons. To get the menu back, simply re-run Hide Icons.

43 |

Set Desktop wallpaper allows you to use either the actual Desktop wallpaper or to use a custom color wallpaper. Either for all Desktops or for individual Desktops. If you have either more than one display or more than one Space, you have multiple Desktops.

44 |

Refresh Desktop forces an update of all Desktops across all displays and Spaces. This option will also cause Hide Icons to forget which Desktop goes with which Space (see below). This is essentially a restart of Hide Icons.

45 |

Check for update... reaches out (via https) to see if there is a new version of Hide Icons. If there is, this menu item changes to Download. If this is selected, then a new version is downloaded to the Downloads folder (also via https) and then the menu item changes to Locate update. Selecting this will present a Finder window with the update highlighted. It is up to you to quit Hide Icons and repace it with this updated version. Please note, the downloaded zip file will be moved to the trash eventually along with any previous version of Hide Icons.

46 |

47 | 48 |

2) Services

49 |

Hide Icon can be controlled by Services. You may have to got to >System Preferences…>Keyboard, select Shortcuts, select Services on the left and check Toggle Desktop Icons on the right. You can also select your own shortcut.

50 |

51 | 52 | 

53 |

If Toggle Desktop Icons is not present, make sure Hide Icons is in the Applications folder and you will need to logout/login for macOS to see the Service.

54 | 55 |

3) Where is the menu ( 56 | 57 | )?

58 |

Simply run Hide Icon again. The menu is not present if Hide Icon was started as a Service or 59 | 60 | >Change menu>Remove menu was chosen.

61 | 62 |

If command key (⌘) is held when Hide Icons starts, the user defined preferences are overwritten with default preferences- useful if you chose a preference set you don't like.

63 | 64 |

4) Requirements

65 |

Hide Icon was written in Swift with Xcode 14.2. It was compiled to support macOS 10.13 (High Sierra) through 13.x (Ventura). Versions before 10.14 (Mojave) can not detect Dark Mode switching.

66 | 67 |

5) Details

68 |

Hide Icon doesn’t touch the Desktop icons. It simply takes a picture of the Desktop (without the icons) and displays this picture just above the real Desktop giving the illusion that the icons have vanished. THEY HAVE NOT. If you open a Finder window, you can easily navigate to Desktop. From there you can add, remove and manipulate items on the Desktop. You must either Show Desktop Icons or quit Hide Icons to have the usual Desktop back.

69 | 70 |

If Check for changing Desktop is set to anything other than Never, then for every time interval specified the picture of the real Desktop is taken to allow for time varying Desktops. Similary, on macOS 10.14 and above, changes in Appearances (e.g. Dark Mode) are immediately reflected.

71 |

If you are using multiple Spaces (with any number of displays), Hide Icons doesn't actually know which Desktop goes with which Space. However, once you visit that Space, Hide Icons will remember that Desktop goes with that Space. Until it does, switching Spaces may temporarily display the wrong Desktop. Selecting Refresh Desktop will force Hide Icons to forget these correlations.

72 |

Set Desktop wallpaper will determine This Desktop according to where the last mouse click was performed. This may cause some difficulties if Displays have separate Spaces is unchecked in System Preferences...>Mission Control. Simply drag the Color Panel to the Desktop of the Space which does not have a menu bar and then select a custom color for wallpaper. Finally, the menu bar is always tinted according to the actual Desktop. You can turn off tinting by enabling System Settings/Preferences...>Accessibility>Display>Display>Reduce transparency.

73 | 74 |

On macOS 11.6.+ (Big Sur), the Desktop icons will flash when changing Spaces. This is a bug introduced by Apple and currently no workaround is known. Monterey or earlier versions of macOS do not exhibit this behavior.

75 | 76 |

6) FAQ

77 |

The incorrect Desktop is being displayed! As mentioned above, Hide Icons does not know which Space corresponds to which Desktop (there are no public APIs that Apple provides for this information) and therefore it tries to learn which Desktop corresponds to which Space. This learning may go wrong. If it does, you can either quit and restart Hide Icons or you can select Force Desktop refresh from the menu.

78 |

Desktop is black! This is similar to above. Hide Icons got confused which Desktop goes with Space. In order to ensure the Desktop icons are always hidden, Hide Icons automatically makes a default black Desktop in case it runs into problems. If the black Desktop is showing, you know it ran into problems. Solution is the same as above.

79 |

Why does either of the above happen? This turns out to be rather subtle. One way for this to happen is rapidly switching Spaces. Essentially some core graphics routines may have some delay updating information that Hide Icons needs to make assignments between Spaces and Desktops. If that information is not correct, then we can run into problems. Hide Icons tries to validate the data returned from the graphics routines before using it and if there is a problem it polls those routines until the data is acceptable and if during that time the Space is changed, Hide Icons can get confused. This should all happen in less than a second, but sometimes that is too slow.

80 |

Sometimes I see the Desktop with gray/white areas... To be honest, I don't know why this happens. It shouldn't. Somehow the graphics routines are not redrawing completely. Seems more likely to happen when the machine is under heavy load or there are many high resolution displays connected. Ultimately, it's an Apple bug. Switching to another Space and back again often results in a correct redraw.

81 |

Nothing happens with "Check for update..."! After checking for an update, the menu item should either say "No update available" or to "Download" the new version. If it stays at "Check for update..." it means the server that hosts the update database is currently unreachable. If you have an internet connection, you'll simply have to wait until the server comes back online. Otherwise make sure you have an internet connection.

82 |

How is this different that others apps? Well, first it's free- both in price and code. Second, it works for any number of Desktops and Spaces. Third it tries to memorize which Desktop and Space go together so transitions between Spaces are smooth once that correlation is found. Regardless, you should use whatever app works best for you, hopefully Hide Icons will be that app.

83 | 84 |

7) Warning/Disclaimer/Licenses

85 |

Using this application won’t make you more attractive or get you rich. Regardless, Hide Icons will never affect your Desktop icons.

86 |

I wrote this for my personal use. I find it useful. I know others have also found it useful too. It’s free and you can give the distribution (i.e. as you got it) to anyone you want. You can’t sell it, though. And if you modify the script and don’t give me credit for the original, you’re simply evil (and are violating this license).

87 | 88 |

Contact and version history

89 | 90 | 91 | 92 |

93 | G.J. Parker- http://www.parker9.com (Entonos) 94 |

95 | 96 | 97 | -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome.jpg -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome1.jpg -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome2.jpg -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome3.jpg -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome4.jpg -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-entonos/Hide-Icons/ec69960e5d6b9967952dbe6d31b02d365a288d13/HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/Welcome5.jpg -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/basic.css: -------------------------------------------------------------------------------- 1 | .Normal { 2 | font-family: "HelveticaNeue","Helvetica Neue",sans-serif; 3 | font-size: 12.000000px; 4 | color: RGBA(58,58,58,1.000000); 5 | } 6 | .Normal_link { 7 | font-family: "HelveticaNeue","Helvetica Neue",sans-serif; 8 | font-size: 12.000000px; 9 | color: #0000ff; 10 | } 11 | .Code { 12 | font-family: "Courier","Courier",serif; 13 | font-size: 12.000000px; 14 | color: RGBA(58,58,58,1.000000); 15 | } 16 | .Heading2 { 17 | font-family: "HelveticaNeue","Helvetica Neue",sans-serif; 18 | font-size: 16.000000px; 19 | color: RGBA(58,58,58,1.000000); 20 | } 21 | .Heading1 { 22 | font-family: "HelveticaNeue-Light","Helvetica Neue",sans-serif; 23 | font-size: 27.000000px; 24 | color: RGBA(58,58,58,1.000000); 25 | } 26 | .Left { 27 | text-align: left; 28 | } 29 | .Right { 30 | text-align: right; 31 | } 32 | .Justify { 33 | text-align: justify; 34 | } 35 | .Center { 36 | text-align: center; 37 | width:100%; 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /HideIcons/Resources/HideIcons.help/Contents/Resources/en.lproj/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

index

12 |

Welcome

13 |

Contact and version history

14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /HideIcons/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // Hide Icons 4 | // 5 | // Created by G.J. Parker on 16/09/23. 6 | // 7 | 8 | 9 | import Cocoa 10 | let app = NSApplication.shared 11 | 12 | autoreleasepool { 13 | let delegate = AppDelegate() 14 | withExtendedLifetime(delegate, { 15 | app.delegate = delegate 16 | _ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Hide Icons 2 | 3 | ![Hide_256x256](https://user-images.githubusercontent.com/51520928/116168137-a0fb1400-a6b6-11eb-84ae-5248dab9d62a.png) 4 | 5 | Simple AppKit that's just a menu item that hides/shows Desktop icons. 6 | --------------------------------------------------------------------------------