diff --git a/Postgres.xcodeproj/project.pbxproj b/Postgres.xcodeproj/project.pbxproj index bbf7abf99..7b6c50d24 100644 --- a/Postgres.xcodeproj/project.pbxproj +++ b/Postgres.xcodeproj/project.pbxproj @@ -8,9 +8,13 @@ /* Begin PBXBuildFile section */ 360079722A1B891000CF88B7 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360079712A1B891000CF88B7 /* main.swift */; }; + 3603EF172FAB6BBA00BDA576 /* MenuItemView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83C19C611D7D9C2500F4862D /* MenuItemView.xib */; }; + 3603EF182FAB6C2900BDA576 /* MenuItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83C19C5B1D7D9AAE00F4862D /* MenuItemView.swift */; }; 360E961C1DC20D5E005D8C69 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360E961B1DC20D5E005D8C69 /* UserDefaults.swift */; }; 360E961D1DC20EF2005D8C69 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360E961B1DC20D5E005D8C69 /* UserDefaults.swift */; }; - 360E961E1DC20EF3005D8C69 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360E961B1DC20D5E005D8C69 /* UserDefaults.swift */; }; + 361CAF8B2FAB551F00DCF309 /* OpenURLAsLoginItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 361CAF8A2FAB551C00DCF309 /* OpenURLAsLoginItem.m */; }; + 3623DDD12FAA229F00A33CB0 /* LegacyLoginItemRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = 3623DDD02FAA229F00A33CB0 /* LegacyLoginItemRegistration.m */; }; + 3623DDD32FAA22A800A33CB0 /* LegacyLoginItemRegistration.h in Sources */ = {isa = PBXBuildFile; fileRef = 3623DDD22FAA22A600A33CB0 /* LegacyLoginItemRegistration.h */; }; 3625F43E2DF5B24D001708B6 /* InternetAccessPolicy.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3625F43D2DF5B24D001708B6 /* InternetAccessPolicy.plist */; }; 3630E17C2B839A7E007875A9 /* PreferencesClientCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3630E17B2B839A7E007875A9 /* PreferencesClientCellView.swift */; }; 3634D7F62954BB2C005CE01C /* BinaryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3634D7F52954BB2C005CE01C /* BinaryManager.swift */; }; @@ -20,30 +24,26 @@ 3641083B296D7C2C00F79014 /* libpgport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3641083A296D7C2C00F79014 /* libpgport.a */; }; 36447A62282568BA00F5BB7A /* InstallHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36447A61282568BA00F5BB7A /* InstallHistory.swift */; }; 36447A63282568BA00F5BB7A /* InstallHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36447A61282568BA00F5BB7A /* InstallHistory.swift */; }; - 36447A64282568BA00F5BB7A /* InstallHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36447A61282568BA00F5BB7A /* InstallHistory.swift */; }; 3686D3362A963787003389DD /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 3686D3352A963787003389DD /* Credits.rtf */; }; 369189BA2A1E3D5F000A3C97 /* UnixProcessInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 369189B92A1E3D5F000A3C97 /* UnixProcessInfo.swift */; }; 369189BC2A1E5BE0000A3C97 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360E961B1DC20D5E005D8C69 /* UserDefaults.swift */; }; 369189BD2A1E7DAD000A3C97 /* PostgresPermissionDialog in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3600796F2A1B891000CF88B7 /* PostgresPermissionDialog */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 369344FC2FE16F1200762CF4 /* LaunchAtLoginManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 369344FB2FE16F0000762CF4 /* LaunchAtLoginManager.swift */; }; 369B82392CA41842008B994E /* libpgcommon_shlib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 369B82382CA41842008B994E /* libpgcommon_shlib.a */; }; 36C9D0482CC69746006ABA02 /* ConnectionDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36C9D0472CC69746006ABA02 /* ConnectionDialog.swift */; }; 36CC815829E6FF990080B0B4 /* ChangePasswordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CC815729E6FF990080B0B4 /* ChangePasswordViewController.swift */; }; 36D767B02729EFDE00161CF2 /* ProcessExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36D767AF2729EFDE00161CF2 /* ProcessExtensions.swift */; }; 36D767B32729F1AD00161CF2 /* ProcessExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36D767AF2729EFDE00161CF2 /* ProcessExtensions.swift */; }; - 36D767B62729F1AD00161CF2 /* ProcessExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36D767AF2729EFDE00161CF2 /* ProcessExtensions.swift */; }; 36EB76A62AC1E55A00580683 /* BundleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36EB76A52AC1E55A00580683 /* BundleExtensions.swift */; }; 36EB76A72AC1E77400580683 /* BundleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36EB76A52AC1E55A00580683 /* BundleExtensions.swift */; }; - 36EB76A82AC1E77400580683 /* BundleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36EB76A52AC1E55A00580683 /* BundleExtensions.swift */; }; 830658E51D536F2E00BA1752 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830658E41D536F2E00BA1752 /* Extensions.swift */; }; 830B4B261D1C132300F16762 /* ServerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830B4B251D1C132300F16762 /* ServerManager.swift */; }; 830B4B281D1C289A00F16762 /* Sidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830B4B271D1C289A00F16762 /* Sidebar.swift */; }; 830D62CC1D77297800570BFC /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830D62CB1D77297800570BFC /* Preferences.swift */; }; 8324D9AA1D9402A10066DCDB /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 831C84AC1D771B4800FA5F59 /* Sparkle.framework */; }; 8324D9AB1D9402A10066DCDB /* Sparkle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 831C84AC1D771B4800FA5F59 /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 834355B11D7D9DC8007CD457 /* ErrorRecoveryAttempter.m in Sources */ = {isa = PBXBuildFile; fileRef = 83543E271D2136E800F764CB /* ErrorRecoveryAttempter.m */; }; 8348A1ED1DB4ED5E0039A024 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = 8348A1EC1DB4ED5E0039A024 /* dsa_pub.pem */; }; 8348A1F11DB52E9A0039A024 /* ValueTransformers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8348A1F01DB52E9A0039A024 /* ValueTransformers.swift */; }; - 8348A1F21DB52E9A0039A024 /* ValueTransformers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8348A1F01DB52E9A0039A024 /* ValueTransformers.swift */; }; 8353FBDE1D1D57C8002F77E7 /* ServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8353FBDD1D1D57C8002F77E7 /* ServerView.swift */; }; 8353FBE01D1D5E4C002F77E7 /* SplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8353FBDF1D1D5E4C002F77E7 /* SplitView.swift */; }; 83543E281D2136E800F764CB /* ErrorRecoveryAttempter.m in Sources */ = {isa = PBXBuildFile; fileRef = 83543E271D2136E800F764CB /* ErrorRecoveryAttempter.m */; }; @@ -55,7 +55,6 @@ 838B8D371D649CB30050EF03 /* MainWindowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 838B8D361D649CB30050EF03 /* MainWindowModel.swift */; }; 83969DBB1D369BD1005B9F1C /* ClientLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83969DBA1D369BD1005B9F1C /* ClientLauncher.swift */; }; 83999C671D7DA3C300B8A1D6 /* PostgresLoginHelper.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83C19C2A1D7D977000F4862D /* PostgresLoginHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 83999C691D7DA42B00B8A1D6 /* PostgresMenuHelper.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83C19C4E1D7D9A7D00F4862D /* PostgresMenuHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 83999C6A1D7DA8DF00B8A1D6 /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8358D53B1D26EBE7007B7904 /* Server.swift */; }; 83999C6B1D7DA8E300B8A1D6 /* ServerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830B4B251D1C132300F16762 /* ServerManager.swift */; }; 83999C6C1D7DA8EA00B8A1D6 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830658E41D536F2E00BA1752 /* Extensions.swift */; }; @@ -65,14 +64,6 @@ 83BB115A1DB680DA00772E8D /* DnDArrayController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BB11591DB680DA00772E8D /* DnDArrayController.swift */; }; 83C19C2D1D7D977000F4862D /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83C19C2C1D7D977000F4862D /* main.swift */; }; 83C19C2F1D7D977000F4862D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83C19C2E1D7D977000F4862D /* Assets.xcassets */; }; - 83C19C511D7D9A7D00F4862D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83C19C501D7D9A7D00F4862D /* AppDelegate.swift */; }; - 83C19C561D7D9A7D00F4862D /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83C19C541D7D9A7D00F4862D /* MainMenu.xib */; }; - 83C19C5C1D7D9AAE00F4862D /* MenuItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83C19C5B1D7D9AAE00F4862D /* MenuItemView.swift */; }; - 83C19C621D7D9C2500F4862D /* MenuItemView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83C19C611D7D9C2500F4862D /* MenuItemView.xib */; }; - 83C19C671D7D9CCF00F4862D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83C19C661D7D9CCF00F4862D /* Assets.xcassets */; }; - 83C19C681D7D9D1900F4862D /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8358D53B1D26EBE7007B7904 /* Server.swift */; }; - 83C19C691D7D9D1E00F4862D /* ServerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830B4B251D1C132300F16762 /* ServerManager.swift */; }; - 83C19C6A1D7D9D2300F4862D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830658E41D536F2E00BA1752 /* Extensions.swift */; }; 83F3647E1D5204D30096F1F5 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F3647D1D5204D30096F1F5 /* SettingsView.swift */; }; 83FB571C1D1B05F000A903A3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83FB571B1D1B05F000A903A3 /* AppDelegate.swift */; }; 83FB57201D1B05F000A903A3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83FB571F1D1B05F000A903A3 /* Assets.xcassets */; }; @@ -118,7 +109,6 @@ dstPath = ""; dstSubfolderSpec = 6; files = ( - 83999C691D7DA42B00B8A1D6 /* PostgresMenuHelper.app in CopyFiles */, 369189BD2A1E7DAD000A3C97 /* PostgresPermissionDialog in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; @@ -129,6 +119,10 @@ 3600796F2A1B891000CF88B7 /* PostgresPermissionDialog */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = PostgresPermissionDialog; sourceTree = BUILT_PRODUCTS_DIR; }; 360079712A1B891000CF88B7 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 360E961B1DC20D5E005D8C69 /* UserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = ""; }; + 361CAF892FAB550800DCF309 /* OpenURLAsLoginItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OpenURLAsLoginItem.h; sourceTree = ""; }; + 361CAF8A2FAB551C00DCF309 /* OpenURLAsLoginItem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OpenURLAsLoginItem.m; sourceTree = ""; }; + 3623DDD02FAA229F00A33CB0 /* LegacyLoginItemRegistration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LegacyLoginItemRegistration.m; sourceTree = ""; }; + 3623DDD22FAA22A600A33CB0 /* LegacyLoginItemRegistration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LegacyLoginItemRegistration.h; sourceTree = ""; }; 3625F43D2DF5B24D001708B6 /* InternetAccessPolicy.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = InternetAccessPolicy.plist; sourceTree = ""; }; 3630E17B2B839A7E007875A9 /* PreferencesClientCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesClientCellView.swift; sourceTree = ""; }; 3634D7F52954BB2C005CE01C /* BinaryManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryManager.swift; sourceTree = ""; }; @@ -141,12 +135,12 @@ 3686D3352A963787003389DD /* Credits.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = ""; }; 369189B92A1E3D5F000A3C97 /* UnixProcessInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnixProcessInfo.swift; sourceTree = ""; }; 369189BB2A1E3DC1000A3C97 /* PostgresPermissionDialog-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PostgresPermissionDialog-Bridging-Header.h"; sourceTree = ""; }; + 369344FB2FE16F0000762CF4 /* LaunchAtLoginManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAtLoginManager.swift; sourceTree = ""; }; 369B82382CA41842008B994E /* libpgcommon_shlib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpgcommon_shlib.a; path = "src-staticlibs/libpgcommon_shlib.a"; sourceTree = ""; }; 36C9D0472CC69746006ABA02 /* ConnectionDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDialog.swift; sourceTree = ""; }; 36CC815729E6FF990080B0B4 /* ChangePasswordViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangePasswordViewController.swift; sourceTree = ""; }; 36D767AF2729EFDE00161CF2 /* ProcessExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessExtensions.swift; sourceTree = ""; }; 36EB76A52AC1E55A00580683 /* BundleExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleExtensions.swift; sourceTree = ""; }; - 830377B71E4C820A008E6896 /* PostgresApplication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PostgresApplication.h; sourceTree = ""; }; 830658E41D536F2E00BA1752 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 830B4B251D1C132300F16762 /* ServerManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerManager.swift; sourceTree = ""; }; 830B4B271D1C289A00F16762 /* Sidebar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Sidebar.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; @@ -175,14 +169,8 @@ 83C19C2C1D7D977000F4862D /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 83C19C2E1D7D977000F4862D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 83C19C331D7D977000F4862D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 83C19C4E1D7D9A7D00F4862D /* PostgresMenuHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PostgresMenuHelper.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 83C19C501D7D9A7D00F4862D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 83C19C551D7D9A7D00F4862D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 83C19C571D7D9A7D00F4862D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 83C19C5B1D7D9AAE00F4862D /* MenuItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuItemView.swift; sourceTree = ""; }; 83C19C611D7D9C2500F4862D /* MenuItemView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MenuItemView.xib; sourceTree = ""; }; - 83C19C631D7D9C6300F4862D /* PostgresMenuHelper-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PostgresMenuHelper-Bridging-Header.h"; sourceTree = ""; }; - 83C19C661D7D9CCF00F4862D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 83F3647D1D5204D30096F1F5 /* SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 83FB57181D1B05F000A903A3 /* Postgres.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Postgres.app; sourceTree = BUILT_PRODUCTS_DIR; }; 83FB571B1D1B05F000A903A3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -208,13 +196,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 83C19C4B1D7D9A7D00F4862D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 83FB57151D1B05F000A903A3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -256,6 +237,8 @@ 83C19C2B1D7D977000F4862D /* PostgresLoginHelper */ = { isa = PBXGroup; children = ( + 361CAF892FAB550800DCF309 /* OpenURLAsLoginItem.h */, + 361CAF8A2FAB551C00DCF309 /* OpenURLAsLoginItem.m */, 83C19C2C1D7D977000F4862D /* main.swift */, 83C19C2E1D7D977000F4862D /* Assets.xcassets */, 83C19C331D7D977000F4862D /* Info.plist */, @@ -264,27 +247,11 @@ path = PostgresLoginHelper; sourceTree = ""; }; - 83C19C4F1D7D9A7D00F4862D /* PostgresMenuHelper */ = { - isa = PBXGroup; - children = ( - 83C19C501D7D9A7D00F4862D /* AppDelegate.swift */, - 83C19C5B1D7D9AAE00F4862D /* MenuItemView.swift */, - 83C19C661D7D9CCF00F4862D /* Assets.xcassets */, - 83C19C541D7D9A7D00F4862D /* MainMenu.xib */, - 83C19C611D7D9C2500F4862D /* MenuItemView.xib */, - 83C19C571D7D9A7D00F4862D /* Info.plist */, - 83C19C631D7D9C6300F4862D /* PostgresMenuHelper-Bridging-Header.h */, - 830377B71E4C820A008E6896 /* PostgresApplication.h */, - ); - path = PostgresMenuHelper; - sourceTree = ""; - }; 83FB570F1D1B05F000A903A3 = { isa = PBXGroup; children = ( 83FB571A1D1B05F000A903A3 /* Postgres */, 83C19C2B1D7D977000F4862D /* PostgresLoginHelper */, - 83C19C4F1D7D9A7D00F4862D /* PostgresMenuHelper */, 360079702A1B891000CF88B7 /* PostgresPermissionDialog */, 83FB57191D1B05F000A903A3 /* Products */, 836CC37F1D2D6A0D000D0C13 /* Frameworks */, @@ -296,7 +263,6 @@ children = ( 83FB57181D1B05F000A903A3 /* Postgres.app */, 83C19C2A1D7D977000F4862D /* PostgresLoginHelper.app */, - 83C19C4E1D7D9A7D00F4862D /* PostgresMenuHelper.app */, 3600796F2A1B891000CF88B7 /* PostgresPermissionDialog */, ); name = Products; @@ -328,16 +294,21 @@ 830658E41D536F2E00BA1752 /* Extensions.swift */, 36D767AF2729EFDE00161CF2 /* ProcessExtensions.swift */, 830D62CB1D77297800570BFC /* Preferences.swift */, + 369344FB2FE16F0000762CF4 /* LaunchAtLoginManager.swift */, 3630E17B2B839A7E007875A9 /* PreferencesClientCellView.swift */, 83969DBA1D369BD1005B9F1C /* ClientLauncher.swift */, 8348A1F01DB52E9A0039A024 /* ValueTransformers.swift */, 83BB11591DB680DA00772E8D /* DnDArrayController.swift */, 83543E261D2136E800F764CB /* ErrorRecoveryAttempter.h */, 83543E271D2136E800F764CB /* ErrorRecoveryAttempter.m */, + 3623DDD02FAA229F00A33CB0 /* LegacyLoginItemRegistration.m */, + 3623DDD22FAA22A600A33CB0 /* LegacyLoginItemRegistration.h */, 835954271E4A301F00D1F0DF /* PostgresAppScriptable.sdef */, 835954291E4A30FD00D1F0DF /* ScriptCommands.swift */, 83FB571F1D1B05F000A903A3 /* Assets.xcassets */, 83FB57211D1B05F000A903A3 /* Main.storyboard */, + 83C19C5B1D7D9AAE00F4862D /* MenuItemView.swift */, + 83C19C611D7D9C2500F4862D /* MenuItemView.xib */, 83FB57241D1B05F000A903A3 /* Info.plist */, 3625F43D2DF5B24D001708B6 /* InternetAccessPolicy.plist */, 3686D3352A963787003389DD /* Credits.rtf */, @@ -386,23 +357,6 @@ productReference = 83C19C2A1D7D977000F4862D /* PostgresLoginHelper.app */; productType = "com.apple.product-type.application"; }; - 83C19C4D1D7D9A7D00F4862D /* PostgresMenuHelper */ = { - isa = PBXNativeTarget; - buildConfigurationList = 83C19C581D7D9A7D00F4862D /* Build configuration list for PBXNativeTarget "PostgresMenuHelper" */; - buildPhases = ( - 83C19C4A1D7D9A7D00F4862D /* Sources */, - 83C19C4B1D7D9A7D00F4862D /* Frameworks */, - 83C19C4C1D7D9A7D00F4862D /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = PostgresMenuHelper; - productName = PostgresMenuHelper; - productReference = 83C19C4E1D7D9A7D00F4862D /* PostgresMenuHelper.app */; - productType = "com.apple.product-type.application"; - }; 83FB57171D1B05F000A903A3 /* Postgres */ = { isa = PBXNativeTarget; buildConfigurationList = 83FB57271D1B05F000A903A3 /* Build configuration list for PBXNativeTarget "Postgres" */; @@ -443,11 +397,6 @@ LastSwiftMigration = 1130; ProvisioningStyle = Manual; }; - 83C19C4D1D7D9A7D00F4862D = { - CreatedOnToolsVersion = 8.0; - LastSwiftMigration = 1130; - ProvisioningStyle = Manual; - }; 83FB57171D1B05F000A903A3 = { CreatedOnToolsVersion = 8.0; LastSwiftMigration = 1130; @@ -470,7 +419,6 @@ targets = ( 83FB57171D1B05F000A903A3 /* Postgres */, 83C19C291D7D977000F4862D /* PostgresLoginHelper */, - 83C19C4D1D7D9A7D00F4862D /* PostgresMenuHelper */, 3600796E2A1B891000CF88B7 /* PostgresPermissionDialog */, ); }; @@ -485,20 +433,11 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 83C19C4C1D7D9A7D00F4862D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 83C19C561D7D9A7D00F4862D /* MainMenu.xib in Resources */, - 83C19C671D7D9CCF00F4862D /* Assets.xcassets in Resources */, - 83C19C621D7D9C2500F4862D /* MenuItemView.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 83FB57161D1B05F000A903A3 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3603EF172FAB6BBA00BDA576 /* MenuItemView.xib in Resources */, 8348A1ED1DB4ED5E0039A024 /* dsa_pub.pem in Resources */, 835954281E4A301F00D1F0DF /* PostgresAppScriptable.sdef in Resources */, 83FB57201D1B05F000A903A3 /* Assets.xcassets in Resources */, @@ -568,28 +507,11 @@ 36EB76A72AC1E77400580683 /* BundleExtensions.swift in Sources */, 83999C6B1D7DA8E300B8A1D6 /* ServerManager.swift in Sources */, 83C19C2D1D7D977000F4862D /* main.swift in Sources */, + 361CAF8B2FAB551F00DCF309 /* OpenURLAsLoginItem.m in Sources */, 83999C6C1D7DA8EA00B8A1D6 /* Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 83C19C4A1D7D9A7D00F4862D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 83C19C6A1D7D9D2300F4862D /* Extensions.swift in Sources */, - 834355B11D7D9DC8007CD457 /* ErrorRecoveryAttempter.m in Sources */, - 83C19C691D7D9D1E00F4862D /* ServerManager.swift in Sources */, - 36D767B62729F1AD00161CF2 /* ProcessExtensions.swift in Sources */, - 36447A64282568BA00F5BB7A /* InstallHistory.swift in Sources */, - 83C19C5C1D7D9AAE00F4862D /* MenuItemView.swift in Sources */, - 83C19C681D7D9D1900F4862D /* Server.swift in Sources */, - 360E961E1DC20EF3005D8C69 /* UserDefaults.swift in Sources */, - 8348A1F21DB52E9A0039A024 /* ValueTransformers.swift in Sources */, - 83C19C511D7D9A7D00F4862D /* AppDelegate.swift in Sources */, - 36EB76A82AC1E77400580683 /* BundleExtensions.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 83FB57141D1B05F000A903A3 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -603,17 +525,21 @@ 360E961C1DC20D5E005D8C69 /* UserDefaults.swift in Sources */, 830B4B281D1C289A00F16762 /* Sidebar.swift in Sources */, 3630E17C2B839A7E007875A9 /* PreferencesClientCellView.swift in Sources */, + 369344FC2FE16F1200762CF4 /* LaunchAtLoginManager.swift in Sources */, 83FB573C1D1B18C900A903A3 /* MainWindow.swift in Sources */, 8359542A1E4A30FD00D1F0DF /* ScriptCommands.swift in Sources */, 83F3647E1D5204D30096F1F5 /* SettingsView.swift in Sources */, 36CC815829E6FF990080B0B4 /* ChangePasswordViewController.swift in Sources */, 830D62CC1D77297800570BFC /* Preferences.swift in Sources */, + 3623DDD12FAA229F00A33CB0 /* LegacyLoginItemRegistration.m in Sources */, 8358D53C1D26EBE7007B7904 /* Server.swift in Sources */, + 3623DDD32FAA22A800A33CB0 /* LegacyLoginItemRegistration.h in Sources */, 3634D7F82954CD69005CE01C /* ServerManagerExtras.swift in Sources */, 83543E281D2136E800F764CB /* ErrorRecoveryAttempter.m in Sources */, 3634D7F62954BB2C005CE01C /* BinaryManager.swift in Sources */, 36447A62282568BA00F5BB7A /* InstallHistory.swift in Sources */, 36C9D0482CC69746006ABA02 /* ConnectionDialog.swift in Sources */, + 3603EF182FAB6C2900BDA576 /* MenuItemView.swift in Sources */, D7A2F0242DF044AA00F28AD0 /* CrashLogCollector.swift in Sources */, 8348A1F11DB52E9A0039A024 /* ValueTransformers.swift in Sources */, 83969DBB1D369BD1005B9F1C /* ClientLauncher.swift in Sources */, @@ -629,14 +555,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ - 83C19C541D7D9A7D00F4862D /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 83C19C551D7D9A7D00F4862D /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; 83FB57211D1B05F000A903A3 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -743,58 +661,6 @@ }; name = Release; }; - 83C19C591D7D9A7D00F4862D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = PostgresMenuHelper/Info.plist; - LATEST_STABLE_PG_VERSION = 15; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@executable_path/../../../../Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.postgresapp.Postgres2MenuHelper; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_OBJC_BRIDGING_HEADER = "PostgresMenuHelper/PostgresMenuHelper-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 83C19C5A1D7D9A7D00F4862D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = PostgresMenuHelper/Info.plist; - LATEST_STABLE_PG_VERSION = 15; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../../../../Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.postgresapp.Postgres2MenuHelper; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_OBJC_BRIDGING_HEADER = "PostgresMenuHelper/PostgresMenuHelper-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; 83FB57251D1B05F000A903A3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -839,7 +705,6 @@ "DEBUG=1", "$(inherited)", ); - GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -849,15 +714,14 @@ HEADER_SEARCH_PATHS = "\"$(SRCROOT)/src-staticlibs\""; IGNORE_MISSING_BINARIES = 1; LATEST_STABLE_PG_VERSION = ""; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_CODE_SIGN_FLAGS = "--prefix com.postgresapp."; - OTHER_LDFLAGS = "$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/macosx/libswiftAppKit.dylib"; PG_BINARIES_DIR = $HOME/PostgresApp/Binaries; PG_BINARIES_VERSIONS = $LATEST_STABLE_PG_VERSION; POSTGRESAPP_BUILD_VERSION = dev; - POSTGRESAPP_SHORT_VERSION = 2.9; + POSTGRESAPP_SHORT_VERSION = 3alpha; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -902,7 +766,6 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -912,14 +775,13 @@ HEADER_SEARCH_PATHS = "\"$(SRCROOT)/src-staticlibs\""; IGNORE_MISSING_BINARIES = ""; LATEST_STABLE_PG_VERSION = ""; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11; MTL_ENABLE_DEBUG_INFO = NO; OTHER_CODE_SIGN_FLAGS = "--prefix com.postgresapp."; - OTHER_LDFLAGS = "$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/macosx/libswiftAppKit.dylib"; PG_BINARIES_DIR = $HOME/PostgresApp/Binaries; PG_BINARIES_VERSIONS = $LATEST_STABLE_PG_VERSION; POSTGRESAPP_BUILD_VERSION = dev; - POSTGRESAPP_SHORT_VERSION = 2.9; + POSTGRESAPP_SHORT_VERSION = 3alpha; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; @@ -1010,15 +872,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 83C19C581D7D9A7D00F4862D /* Build configuration list for PBXNativeTarget "PostgresMenuHelper" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 83C19C591D7D9A7D00F4862D /* Debug */, - 83C19C5A1D7D9A7D00F4862D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 83FB57131D1B05F000A903A3 /* Build configuration list for PBXProject "Postgres" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Postgres/AppDelegate.swift b/Postgres/AppDelegate.swift index edb8c9cc1..f56ec472f 100644 --- a/Postgres/AppDelegate.swift +++ b/Postgres/AppDelegate.swift @@ -10,14 +10,16 @@ import Cocoa import Sparkle import ServiceManagement -class AppDelegate: NSObject, NSApplicationDelegate, SUUpdaterDelegate, NSAlertDelegate { +class AppDelegate: NSObject, NSApplicationDelegate, SUUpdaterDelegate, NSAlertDelegate, NSMenuDelegate { let serverManager: ServerManager = ServerManager.shared - var hideMenuHelperApp = UserDefaults.standard.bool(forKey: "HideMenuHelperApp") - var startLoginHelper = UserDefaults.standard.bool(forKey: "StartLoginHelper") + let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) + let statusIcon = NSImage(named: "statusicon")! + @IBOutlet var sparkleUpdater: SUUpdater! @IBOutlet var preferencesMenuItem: NSMenuItem! + @IBOutlet var mainWindowMenuItem: NSMenuItem! func isFirstLaunch() -> Bool { if UserDefaults.standard.bool(forKey: "alreadyLaunched") == false { @@ -26,13 +28,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, SUUpdaterDelegate, NSAlertDe } return false } - - func isTranslocated() -> Bool { - Bundle.main.bundlePath.contains("/AppTranslocation/") - } - + func applicationDidFinishLaunching(_ notification: Notification) { - CrashLogCollector.shared.scanInBackground() + if NSAppleEventManager.shared().currentAppleEvent?.paramDescriptor(forKeyword: keyAEPropData)?.enumCodeValue == keyAELaunchedAsLogInItem { + NSApp.setActivationPolicy(.accessory) + } else { + showMainWindow() + CrashLogCollector.shared.scanInBackground() + } let clientAppPath = UserDefaults.standard.string(forKey: "PreferredClientApplicationPath") ?? "" if clientAppPath.isEmpty { // Read the old setting, reverting to Terminal as default @@ -67,127 +70,213 @@ class AppDelegate: NSObject, NSApplicationDelegate, SUUpdaterDelegate, NSAlertDe DistributedNotificationCenter.default.addObserver(forName: Server.StatusChangedNotification, object: nil, queue: OperationQueue.main) { _ in self.serverManager.refreshServerStatuses() } - - NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: OperationQueue.main) { _ in - let hideMenuHelperApp = UserDefaults.standard.bool(forKey: "HideMenuHelperApp") - if self.hideMenuHelperApp != hideMenuHelperApp { - self.hideMenuHelperApp = hideMenuHelperApp - if self.hideMenuHelperApp { - let runningMenuHelperApps = NSRunningApplication.runningApplications(withBundleIdentifier: "com.postgresapp.Postgres2MenuHelper") - for app in runningMenuHelperApps where app.bundleURL!.path == Bundle.main.url(forAuxiliaryExecutable: "PostgresMenuHelper.app")!.path { - app.terminate() - } - } else { - let url = Bundle.main.url(forAuxiliaryExecutable: "PostgresMenuHelper.app")! - NSWorkspace.shared.launchApplication(url.path) + LaunchAtLoginManager.shared.configureLoginItem() + + for server in serverManager.servers where server.startOnLogin && server.serverStatus == .Startable { + server.start { _ in } + } + + statusMenu.addItem(withTitle: "Open Postgres", action: #selector(showMainWindow), keyEquivalent: "") + statusMenu.addItem(withTitle: "Settings…", action: #selector(showPreferences), keyEquivalent: "") + statusMenu.addItem(withTitle: "Check for Updates…", action: #selector(checkForUpdates), keyEquivalent: "") + statusMenu.addItem(withTitle: "Quit", action: #selector(NSApplication.terminate), keyEquivalent: "") + statusMenu.addItem(.separator()) + statusMenu.delegate = self + + statusItem.button!.image = statusIcon + statusItem.behavior = .removalAllowed // if we don't allow this, macOS Tahoe will disable the icon in system settings if the user drags the icon from the status bar + statusItem.isVisible = !UserDefaults.standard.bool(forKey: "HideMenuHelperApp") + UserDefaults.standard.addObserver(self, forKeyPath: "HideMenuHelperApp", context: nil) + statusItem.addObserver(self, forKeyPath: "isVisible", context: nil) + statusItem.menu = statusMenu + } + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + if let object = object as? AnyObject { + if object === statusItem && keyPath == "isVisible" { + // detect when the user hides icon by dragging away from menu bar + let hideMenuItem = !statusItem.isVisible + if UserDefaults.standard.bool(forKey: "HideMenuHelperApp") != hideMenuItem { + UserDefaults.standard.set(hideMenuItem, forKey: "HideMenuHelperApp") } + return } - if #available(macOS 13, *) { - // this setting was removed in macOS 13 - // since we try to register the login item in any case - // user can enable / disable login item in system settings - } else { - let startLoginHelper = UserDefaults.standard.bool(forKey: "StartLoginHelper") - if self.startLoginHelper != startLoginHelper { - self.startLoginHelper = startLoginHelper - if self.startLoginHelper { - self.createLaunchAgent() - } else { - self.destroyLaunchAgent() - } + if object is UserDefaults && keyPath == "HideMenuHelperApp" { + // detect when the user hides icon by changing user defaults + let statusItemIsVisible = !UserDefaults.standard.bool(forKey: "HideMenuHelperApp") + if statusItem.isVisible != statusItemIsVisible { + statusItem.isVisible = statusItemIsVisible } + return } } + super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) + } + + let statusMenu = NSMenu() + var menuItemViewControllers: [MenuItemViewController] = [] - if !isTranslocated() { - if #available(macOS 13, *) { - destroyLaunchAgent() - registerLoginItem() - } else { - if startLoginHelper { - createLaunchAgent() - } else { - destroyLaunchAgent() - } - } + func menuNeedsUpdate(_ menu: NSMenu) { + guard menu == statusMenu else { return } + + serverManager.refreshServerStatuses() + + menuItemViewControllers.removeAll() + + for item in statusMenu.items where item.view is MenuItemView { + statusMenu.removeItem(item) + } + + var maxStringWidth = CGFloat(0) + for server in serverManager.servers { + let stringWidth = (server.name as NSString).size(withAttributes: [NSAttributedString.Key.font: NSFont.systemFont(ofSize: 12)]).width + maxStringWidth = max(stringWidth, maxStringWidth) + } + + for server in serverManager.servers { + guard let menuItemViewController = MenuItemViewController(server) else { return } + menuItemViewControllers.append(menuItemViewController) + + let menuItem = NSMenuItem() - if UserDefaults.standard.bool(forKey: "HideMenuHelperApp") == false { - let url = Bundle.main.url(forAuxiliaryExecutable: "PostgresMenuHelper.app")! - NSWorkspace.shared.launchApplication(url.path) - NSApp.activate(ignoringOtherApps: true) + menuItemViewController.view.setFrameSize(NSSize(width: min(max(150+maxStringWidth, 200), 300), height: 32)) + menuItem.view = menuItemViewController.view + + statusMenu.addItem(menuItem) + } + } + + var hasVisibleWindowsThatCanBecomeKey: Bool { + return NSApp.windows.contains { $0.isVisible && $0.canBecomeKey } + } + + func applicationWillBecomeActive(_ notification: Notification) { + if #available(macOS 13, *) { + NSApp.setActivationPolicy(.regular) + } else { + // This is a workaround for a macOS 12 bug + // When the app is reopened (by double clicking in the Finder or Dock icon) while it is in .accessory mode, + // the menu bar becomes unresponsive. The workaround is to move the app to background, + // change the activation policy, then show it again + if NSApp.activationPolicy() == .accessory { + DispatchQueue.main.async { + NSApp.hide(nil) + DispatchQueue.main.async { + self.showMainWindow() + } + } + return } } - - for server in serverManager.servers where server.startOnLogin && server.serverStatus == .Startable { - server.start { _ in } + } + + func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows: Bool) -> Bool { + if #available(macOS 13, *) { + showMainWindow() + } else { + // This is a workaround for a macOS 12 bug + // See comment in applicationWillBecomeActive + if NSApp.activationPolicy() == .regular { + showMainWindow() + } } + return false } - + func applicationDidBecomeActive(_ notification: Notification) { DispatchQueue.main.async { self.serverManager.refreshServerStatuses() } } - func showPreferences() { - // The preference window is displayed by a storyboard segue hooked up to a menu item - // This seems to be the easiest way to trigger that segue programmatically - NSApp.sendAction(preferencesMenuItem.action!, to: preferencesMenuItem.target, from: preferencesMenuItem) - } - - @IBAction func openHelp(_ sender: AnyObject?) { - NSWorkspace.shared.open(URL(string: "https://postgresapp.com/l/help/")!) + func applicationWillTerminate(_ notification: Notification) { + for server in serverManager.servers where server.running { + try? server.stopSync() + } } - - @available(macOS 13, *) private func registerLoginItem() { - let loginHelper = SMAppService.loginItem(identifier:"com.postgresapp.Postgres2LoginHelper") - do { - try loginHelper.register() - } catch let error { - // This most likely means that the user disabled the login item in system setting - // We ignore the error, but print it to stdout for easier debugging - print("Failed to register login item because: \(error)") + @IBAction func quitWithConfirmation(_ sender: AnyObject?) { + let alert = NSAlert() + alert.messageText = "Do you want to completely quit Postgres.app?" + alert.informativeText = "This will stop servers and hide the menu bar icon.\n\nIf you want to continue using PostgreSQL servers, Postgres.app can move to the background instead." + alert.addButton(withTitle: "Quit") + alert.addButton(withTitle: "Move to background") + alert.addButton(withTitle: "Cancel") + switch alert.runModal() { + case .alertFirstButtonReturn: + NSApp.terminate(nil) + case .alertSecondButtonReturn: + for window in NSApp.windows where window.isVisible && window.canBecomeKey { + window.performClose(nil) + } + NSApp.hide(nil) + default: + break } } - private func createLaunchAgent() { - let laPath = NSHomeDirectory().appending("/Library/LaunchAgents") - let laName = "com.postgresapp.Postgres2LoginHelper" - if !FileManager.default.fileExists(atPath: laPath) { - do { - try FileManager.default.createDirectory(atPath: laPath, withIntermediateDirectories: true, attributes: nil) - } catch let error as NSError { - NSLog("Could not create directory at \(laPath): \(error)") - return + func mainWindowWillClose(_ notification: Notification) { + DispatchQueue.main.async { + // we don't want to suddenly hide the app when other windows are still open (about window, sparkle etc) + // so we check that no windows are visible + if !self.hasVisibleWindowsThatCanBecomeKey { + // This is a workaround in a macOS bug (last verified macOS 26) + // when setting the activation policy of the frontmost app to .accessory + // macOS brings all windows of the next app to the foreground + // Hiding the app does not trigger this behavior + // The activation policy will later be changed in applicationDidResignActive + NSApp.hide(nil) } } + } - let plistPath = laPath+"/"+laName+".plist" - let attributes: [FileAttributeKey: Any] = [.posixPermissions: 0o600] - do { - let data = try Data(contentsOf: Bundle.main.url(forResource: laName, withExtension: "plist")!) - if !FileManager.default.createFile(atPath: plistPath, contents: data, attributes: attributes) { - NSLog("Could not create plist file at \(plistPath)") - } - } catch let error as NSError { - NSLog("Error getting data of original plist file: \(error)") + func applicationDidResignActive(_ notification: Notification) { + if !hasVisibleWindowsThatCanBecomeKey { + NSApp.setActivationPolicy(.accessory) } } - private func destroyLaunchAgent() { - let laPath = NSHomeDirectory() + "/Library/LaunchAgents/com.postgresapp.Postgres2LoginHelper.plist" - if FileManager.default.fileExists(atPath: laPath) { - do { - try FileManager.default.removeItem(atPath: laPath) - } catch let error as NSError { - NSLog("Could not delete launch agent \(laPath): \(error)") - } + @IBAction func showMainWindow(_ sender: Any? = nil) { + if #available(macOS 14.0, *) { + // this seems to help with getting the app to activate + // i have no idea how the window server decides to allow postgres.app to activate + NSApp.yieldActivation(toApplicationWithBundleIdentifier: Bundle.main.bundleIdentifier!) } + NSApp.setActivationPolicy(.regular) + NSApp.activate(ignoringOtherApps: true) + // This is a workaround to trigger a storyboard segue programmatically + // If you come up with a better solution please let me know :) + NSApp.sendAction(mainWindowMenuItem.action!, to: mainWindowMenuItem.target, from: mainWindowMenuItem) +} + + @IBAction func showPreferences(_ sender: Any? = nil) { + if #available(macOS 14.0, *) { + // this seems to help with getting the app to activate + // i have no idea how the window server decides to allow postgres.app to activate + NSApp.yieldActivation(toApplicationWithBundleIdentifier: Bundle.main.bundleIdentifier!) + } + NSApp.setActivationPolicy(.regular) + NSApp.activate(ignoringOtherApps: true) + // The preference window is displayed by a storyboard segue hooked up to a menu item + // This seems to be the easiest way to trigger that segue programmatically + NSApp.sendAction(preferencesMenuItem.action!, to: preferencesMenuItem.target, from: preferencesMenuItem) } + @IBAction func checkForUpdates(_ sender: Any? = nil) { + if #available(macOS 14.0, *) { + // this seems to help with getting the app to activate + // i have no idea how the window server decides to allow postgres.app to activate + NSApp.yieldActivation(toApplicationWithBundleIdentifier: Bundle.main.bundleIdentifier!) + } + NSApp.setActivationPolicy(.regular) + NSApp.activate(ignoringOtherApps: true) + sparkleUpdater.checkForUpdates(sender) + } + @IBAction func openHelp(_ sender: AnyObject?) { + NSWorkspace.shared.open(URL(string: "https://postgresapp.com/l/help/")!) + } // SUUpdater delegate methods func updater(_ updater: SUUpdater, willInstallUpdate item: SUAppcastItem) { @@ -198,13 +287,4 @@ class AppDelegate: NSObject, NSApplicationDelegate, SUUpdaterDelegate, NSAlertDe menuApp.terminate() } } - - func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { - if isTranslocated() { - for server in serverManager.servers where server.running && server.binPath.hasPrefix(Bundle.main.bundlePath) { - try? server.stopSync() - } - } - return .terminateNow - } } diff --git a/PostgresMenuHelper/Assets.xcassets/icon-caution.imageset/Contents.json b/Postgres/Assets.xcassets/icon-caution.imageset/Contents.json similarity index 100% rename from PostgresMenuHelper/Assets.xcassets/icon-caution.imageset/Contents.json rename to Postgres/Assets.xcassets/icon-caution.imageset/Contents.json diff --git a/PostgresMenuHelper/Assets.xcassets/icon-caution.imageset/caution-icon.pdf b/Postgres/Assets.xcassets/icon-caution.imageset/caution-icon.pdf similarity index 100% rename from PostgresMenuHelper/Assets.xcassets/icon-caution.imageset/caution-icon.pdf rename to Postgres/Assets.xcassets/icon-caution.imageset/caution-icon.pdf diff --git a/PostgresMenuHelper/Assets.xcassets/statusicon.imageset/Contents.json b/Postgres/Assets.xcassets/statusicon.imageset/Contents.json similarity index 100% rename from PostgresMenuHelper/Assets.xcassets/statusicon.imageset/Contents.json rename to Postgres/Assets.xcassets/statusicon.imageset/Contents.json diff --git a/PostgresMenuHelper/Assets.xcassets/statusicon.imageset/statusicon.png b/Postgres/Assets.xcassets/statusicon.imageset/statusicon.png similarity index 100% rename from PostgresMenuHelper/Assets.xcassets/statusicon.imageset/statusicon.png rename to Postgres/Assets.xcassets/statusicon.imageset/statusicon.png diff --git a/PostgresMenuHelper/Assets.xcassets/statusicon.imageset/statusicon@2x.png b/Postgres/Assets.xcassets/statusicon.imageset/statusicon@2x.png similarity index 100% rename from PostgresMenuHelper/Assets.xcassets/statusicon.imageset/statusicon@2x.png rename to Postgres/Assets.xcassets/statusicon.imageset/statusicon@2x.png diff --git a/Postgres/Base.lproj/Main.storyboard b/Postgres/Base.lproj/Main.storyboard index 6441b1843..1dcd91459 100644 --- a/Postgres/Base.lproj/Main.storyboard +++ b/Postgres/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -10,7 +10,7 @@ - + @@ -108,7 +108,7 @@ - + @@ -212,7 +212,7 @@ @@ -340,6 +329,21 @@ + + + + + + + + + + + NSNegateBoolean + + + + @@ -352,6 +356,7 @@ + @@ -361,6 +366,7 @@ + @@ -443,7 +449,7 @@ - + @@ -453,6 +459,12 @@ + + + + + + @@ -581,6 +593,7 @@ + diff --git a/Postgres/ClientLauncher.swift b/Postgres/ClientLauncher.swift index 910e75142..7afde1874 100644 --- a/Postgres/ClientLauncher.swift +++ b/Postgres/ClientLauncher.swift @@ -126,17 +126,9 @@ class ClientLauncher: NSObject { let localizedName = bundle.localizedInfoDictionary?[kCFBundleNameKey as String] as? String ?? bundle.infoDictionary?[kCFBundleNameKey as String] as? String ?? appURL.deletingPathExtension().lastPathComponent let item = NSMenuItem(title: localizedName, action: nil, keyEquivalent: "") let attrTitle = NSMutableAttributedString() - if #available(macOS 11, *) { - attrTitle.append(NSAttributedString(string: localizedName, attributes: [ - .font: NSFont.systemFont(ofSize: NSFont.systemFontSize(for: .large)), - ])) - - } else { - attrTitle.append(NSAttributedString(string: localizedName, attributes: [ - .font: NSFont.systemFont(ofSize: NSFont.systemFontSize), - ])) - - } + attrTitle.append(NSAttributedString(string: localizedName, attributes: [ + .font: NSFont.systemFont(ofSize: NSFont.systemFontSize(for: .large)), + ])) attrTitle.append(NSAttributedString(string: "\n" + appURL.path, attributes: [ .font: NSFont.systemFont(ofSize: NSFont.smallSystemFontSize), .foregroundColor: NSColor.secondaryLabelColor diff --git a/Postgres/Info.plist b/Postgres/Info.plist index b51e09c3e..2a5b09fd0 100644 --- a/Postgres/Info.plist +++ b/Postgres/Info.plist @@ -38,7 +38,11 @@ https://postgresapp.com/sparkle/updates_$(PG_BINARIES_VERSIONS).xml SUPublicDSAKeyFile dsa_pub.pem + SUEnableAutomaticChecks + NSAppleEventsUsageDescription Postgres.app uses Apple Script so you can automatically connect to a database with a double click. + LSUIElement + diff --git a/Postgres/LaunchAtLoginManager.swift b/Postgres/LaunchAtLoginManager.swift new file mode 100644 index 000000000..c4b976b62 --- /dev/null +++ b/Postgres/LaunchAtLoginManager.swift @@ -0,0 +1,136 @@ +// +// LaunchAtLoginManager.swift +// Postgres +// +// +// Created by Jakob on 16.06.26. +// This code is released under the terms of the PostgreSQL License. +// + +import ServiceManagement + +extension UserDefaults { + static let LoginItemWasRegisteredKey = "LoginItemWasRegistered" +} + +class LaunchAtLoginManager { + static var shared = LaunchAtLoginManager() + + var requiresApproval : Bool { + if #available(macOS 13.0, *) { + if SMAppService.mainApp.status == .enabled { + return false + } + if SMAppService.loginItem(identifier:"com.postgresapp.Postgres2LoginHelper").status == .requiresApproval { + return true + } + } + return false + } + + var isLaunchAtLoginEnabled : Bool { + if #available(macOS 13, *) { + if SMAppService.mainApp.status == .enabled { + return true + } + if SMAppService.loginItem(identifier:"com.postgresapp.Postgres2LoginHelper").status == .enabled { + return true + } + return false + } else { + return IsLoginItemRegistered(Bundle.main.bundleURL as CFURL) + } + } + + func registerLoginItem() throws { + UserDefaults.standard.set(true, forKey: UserDefaults.LoginItemWasRegisteredKey) + if #available(macOS 13, *) { + try SMAppService.loginItem(identifier:"com.postgresapp.Postgres2LoginHelper").register() + } else { + RegisterLegacyLoginItem(Bundle.main.bundleURL as CFURL) + } + guard isLaunchAtLoginEnabled else { + throw LaunchAtLoginManagerError(errorDescription: "Registering login item failed", recoverySuggestion: "Make sure Postgres.app has permission to run in the background in system settings.") + } + } + + func unregisterLoginItem() throws { + UserDefaults.standard.set(true, forKey: UserDefaults.LoginItemWasRegisteredKey) + var errors = [Error]() + if #available(macOS 13, *) { + do { + try SMAppService.loginItem(identifier:"com.postgresapp.Postgres2LoginHelper").unregister() + } catch { + errors.append(error) + } + do { + try SMAppService.mainApp.unregister() + } catch { + errors.append(error) + } + } else { + UnregisterLegacyLoginItem(Bundle.main.bundleURL as CFURL) + } + guard !isLaunchAtLoginEnabled else { + for error in errors { + print("Unregistering login item: \(error)") + } + throw LaunchAtLoginManagerError(errorDescription: "Failed to unregister login item") + } + } + + struct LaunchAtLoginManagerError: LocalizedError { + var errorDescription: String? + var recoverySuggestion: String? + } + + func configureLoginItem() { + if Bundle.main.bundlePath.contains("/AppTranslocation/") { + return + } + + let laPath = NSHomeDirectory() + "/Library/LaunchAgents/com.postgresapp.Postgres2LoginHelper.plist" + if FileManager.default.fileExists(atPath: laPath) { + // found a legacy launch agent + // migrate it to the new system + do { + try FileManager.default.removeItem(atPath: laPath) + UserDefaults.standard.set(false, forKey: "StartLoginHelper") // prevent legacy postgres.app from re-adding the launch agent + } catch let error as NSError { + NSLog("Could not delete launch agent \(laPath): \(error)") + } + try? registerLoginItem() + return + } + + if UserDefaults.standard.bool(forKey: UserDefaults.LoginItemWasRegisteredKey) { + // we don't want to add it back if it was removed by the user + return + } + + if #available(macOS 13, *) { + let loginItemStatus = SMAppService.loginItem(identifier:"com.postgresapp.Postgres2LoginHelper").status + switch loginItemStatus { + case .enabled, .requiresApproval: + // just leave it like it is + UserDefaults.standard.set(true, forKey: UserDefaults.LoginItemWasRegisteredKey) + return + case .notFound, .notRegistered: + // we can still register it + break + @unknown default: + // not sure what we should do here + NSLog("Unknown login item status: \(loginItemStatus)") + break + } + } + + if UserDefaults.standard.bool(forKey: "StartLoginHelper") == false { + // this must have been set by a previous version of Postgres.app + // don't auto-add the login item + return + } + + try? registerLoginItem() + } +} diff --git a/Postgres/LegacyLoginItemRegistration.h b/Postgres/LegacyLoginItemRegistration.h new file mode 100644 index 000000000..bed8b8733 --- /dev/null +++ b/Postgres/LegacyLoginItemRegistration.h @@ -0,0 +1,13 @@ +// +// LegacyLoginItemRegistration.h +// Postgres +// +// +// Created by Jakob Egger on 05.05.26. +// This code is released under the terms of the PostgreSQL License. +// + + +void RegisterLegacyLoginItem(CFURLRef url); +void UnregisterLegacyLoginItem(CFURLRef url); +BOOL IsLoginItemRegistered(CFURLRef url); diff --git a/Postgres/LegacyLoginItemRegistration.m b/Postgres/LegacyLoginItemRegistration.m new file mode 100644 index 000000000..125bc5447 --- /dev/null +++ b/Postgres/LegacyLoginItemRegistration.m @@ -0,0 +1,56 @@ +// +// LegacyLoginItemRegistration.m +// Postgres +// +// +// Created by Jakob Egger on 05.05.26. +// This code is released under the terms of the PostgreSQL License. +// + + +#import + +void RegisterLegacyLoginItem(CFURLRef url) { + LSSharedFileListRef loginItemsList = LSSharedFileListCreate( nil, kLSSharedFileListSessionLoginItems, nil); + LSSharedFileListInsertItemURL(loginItemsList, kLSSharedFileListItemLast, nil, nil, url, nil, nil); + CFRelease(loginItemsList); +} + +BOOL IsLoginItemRegistered(CFURLRef url) { + LSSharedFileListRef loginItemsList = LSSharedFileListCreate( nil, kLSSharedFileListSessionLoginItems, nil); + CFArrayRef loginItems = LSSharedFileListCopySnapshot(loginItemsList, nil); + CFIndex count = CFArrayGetCount(loginItems); + BOOL foundMatch = NO; + for (CFIndex i=0; i - + - - + + + - + - - + + - + @@ -29,16 +30,16 @@ - PostgresMenuHelper.ServerStatusImageTransformer + Postgres.ServerStatusImageTransformer - + - - + + @@ -144,7 +145,7 @@ - + diff --git a/Postgres/Postgres-Bridging-Header.h b/Postgres/Postgres-Bridging-Header.h index 7d07554cb..c7942dce8 100644 --- a/Postgres/Postgres-Bridging-Header.h +++ b/Postgres/Postgres-Bridging-Header.h @@ -5,3 +5,4 @@ #import #import "libproc.h" #import "ErrorRecoveryAttempter.h" +#import "LegacyLoginItemRegistration.h" diff --git a/Postgres/Preferences.swift b/Postgres/Preferences.swift index 305e795bb..c3d0ff923 100644 --- a/Postgres/Preferences.swift +++ b/Postgres/Preferences.swift @@ -7,6 +7,7 @@ // import Cocoa +import ServiceManagement class PreferencesViewController: NSViewController { @IBOutlet var preferredClientMenu: NSPopUpButton! @@ -23,11 +24,27 @@ class PreferencesViewController: NSViewController { "Postico" ] - @objc dynamic var launchAgentCheckboxHidden: Bool { - if #available(macOS 13, *) { - return true - } else { - return false + @objc dynamic var launchAtLogin: Bool { + get { + LaunchAtLoginManager.shared.isLaunchAtLoginEnabled + } + set { + do { + if newValue { + try LaunchAtLoginManager.shared.registerLoginItem() + } else { + try LaunchAtLoginManager.shared.unregisterLoginItem() + } + } + catch { + self.presentError(error, modalFor: self.view.window!, delegate: nil, didPresent: nil, contextInfo: nil) + DispatchQueue.main.async { + // update UI + self.willChangeValue(forKey: "launchAtLogin") + self.didChangeValue(forKey: "launchAtLogin") + } + } + } } @@ -35,6 +52,14 @@ class PreferencesViewController: NSViewController { Bundle.main.bundlePath.contains("/AppTranslocation/") } + @objc dynamic var launchAtLoginRequiresApproval: Bool { + LaunchAtLoginManager.shared.requiresApproval + } + + @objc dynamic var isLaunchAtLoginCheckboxEnabled: Bool { + !isTranslocated && !launchAtLoginRequiresApproval + } + @IBAction func resetAppPermissions(_ sender: Any?) { UserDefaults.shared.set(nil, forKey: "ClientApplicationPermissions") } diff --git a/Postgres/PreferencesClientCellView.swift b/Postgres/PreferencesClientCellView.swift index 6809f14af..c4d148f9d 100644 --- a/Postgres/PreferencesClientCellView.swift +++ b/Postgres/PreferencesClientCellView.swift @@ -45,16 +45,4 @@ class PreferencesClientCellView: NSTableCellView { @objc dynamic var clientAppIcon: NSImage? @objc dynamic var clientDisplayName: String = "" @objc dynamic var localizedPolicy: String = "Ask" - - @IBOutlet weak var removeButton: NSButton! - override func awakeFromNib() { - super.awakeFromNib() - if #available(macOS 11, *) { - // button uses system trash can symbol - } else { - // trash can symbol not available - // use title instead - removeButton.imagePosition = .noImage - } - } } diff --git a/Postgres/Server.swift b/Postgres/Server.swift index 36f4406d5..64dd46380 100644 --- a/Postgres/Server.swift +++ b/Postgres/Server.swift @@ -919,11 +919,7 @@ class Server: NSObject { for i in fds.indices.reversed() { if (fds[i].revents & Int16(POLLIN)) != 0 { let availableData: Data - if #available(macOS 10.15.4, *) { - availableData = try handles[i].read(upToCount: Int.max) ?? Data() - } else { - availableData = handles[i].availableData - } + availableData = try handles[i].read(upToCount: Int.max) ?? Data() if availableData.count == 0 { // eof fds.remove(at: i) @@ -1163,12 +1159,7 @@ class Server: NSObject { let errorPipe = Pipe() process.standardError = errorPipe try process.launchAndCheckForRosetta() - if #available(macOS 10.15.4, *) { - try inputPipe.fileHandleForWriting.write(contentsOf: query.data(using: .utf8)!) - } else { - // Fallback on earlier versions - inputPipe.fileHandleForWriting.write(query.data(using: .utf8)!) - } + try inputPipe.fileHandleForWriting.write(contentsOf: query.data(using: .utf8)!) inputPipe.fileHandleForWriting.closeFile() let output = String(data: outputPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)! let errorDescription = String(data: errorPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? "(incorrectly encoded error message)" diff --git a/PostgresLoginHelper/OpenURLAsLoginItem.h b/PostgresLoginHelper/OpenURLAsLoginItem.h new file mode 100644 index 000000000..0a021acd9 --- /dev/null +++ b/PostgresLoginHelper/OpenURLAsLoginItem.h @@ -0,0 +1,10 @@ +// +// OpenURLAsLoginItem.h +// Postgres +// +// +// Created by Jakob Egger on 06.05.26. +// This code is released under the terms of the PostgreSQL License. +// + +BOOL OpenURLAsLoginItem(CFURLRef url); diff --git a/PostgresLoginHelper/OpenURLAsLoginItem.m b/PostgresLoginHelper/OpenURLAsLoginItem.m new file mode 100644 index 000000000..c6ebd5eef --- /dev/null +++ b/PostgresLoginHelper/OpenURLAsLoginItem.m @@ -0,0 +1,32 @@ +// +// OpenURLAsLoginItem.m +// Postgres +// +// +// Created by Jakob Egger on 06.05.26. +// This code is released under the terms of the PostgreSQL License. +// + +#import + +BOOL OpenURLAsLoginItem(CFURLRef url) { + struct LSLaunchURLSpec launchSpec = {}; + launchSpec.appURL = url; + struct AEDesc launchAsLoginItem = {}; + AEKeyword launchAsLoginItemKeyword = keyAELaunchedAsLogInItem; + OSErr err = AECreateDesc(typeEnumerated, &launchAsLoginItemKeyword, 4, &launchAsLoginItem); + if (err != noErr) { + NSLog(@"AECreateDesc() return OSErr %d", (int)err); + return NO; + } + NSLog(@"AECreateDesc: %d", (int)err); + launchSpec.passThruParams = &launchAsLoginItem; + CFURLRef launchedURL = NULL; + OSStatus status = LSOpenFromURLSpec(&launchSpec, &launchedURL); + AEDisposeDesc(&launchAsLoginItem); + if (status != noErr) { + NSLog(@"LSOpenFromURLSpec() return OSStatus %d", (int)status); + return NO; + } + return YES; +} diff --git a/PostgresLoginHelper/PostgresLoginHelper-Bridging-Header.h b/PostgresLoginHelper/PostgresLoginHelper-Bridging-Header.h index 7d07554cb..36b2cfd8f 100644 --- a/PostgresLoginHelper/PostgresLoginHelper-Bridging-Header.h +++ b/PostgresLoginHelper/PostgresLoginHelper-Bridging-Header.h @@ -5,3 +5,4 @@ #import #import "libproc.h" #import "ErrorRecoveryAttempter.h" +#import "OpenURLAsLoginItem.h" diff --git a/PostgresLoginHelper/main.swift b/PostgresLoginHelper/main.swift index 0f7dde68e..5e49992b6 100644 --- a/PostgresLoginHelper/main.swift +++ b/PostgresLoginHelper/main.swift @@ -1,45 +1,25 @@ // -// maine.swift +// main.swift // PostgresLoginHelper // -// Created by Chris on 05/09/2016. +// Created by jakob on May 6, 2026 // This code is released under the terms of the PostgreSQL License. // import Cocoa -if #available(macOS 13, *) { - // we only need the else clause -} else { - // on old macOS autostart only works when the app is in /Applications/Postgres.app - if !Bundle.main.bundlePath.hasPrefix("/Applications/Postgres.app") { - NSLog("Not in /Applications/Postgres.app") - exit(0) - } +guard let mainAppURL = Bundle.mainApp?.bundleURL else { + fatalError("Main app not found") } -// Launch the menu bar helper -if UserDefaults.shared.bool(forKey: "HideMenuHelperApp") == false { - if let menuHelperURL = Bundle.mainApp?.url(forAuxiliaryExecutable: "PostgresMenuHelper.app") { - if !NSWorkspace.shared.launchApplication(menuHelperURL.path) { - NSLog("Failed to launch PostgresMenuHelper.app") - } - } else { - NSLog("PostgresMenuHelper.app not found") +if let bundleIdentifier = Bundle.mainApp?.bundleIdentifier { + let matchingApplications = NSRunningApplication.runningApplications(withBundleIdentifier: bundleIdentifier) + guard matchingApplications.isEmpty else { + print("Main app is already running") + exit(0) } } -// Start PostgreSQL servers -// This may take a few seconds, so we do this after launching the menu bar helper -let serverManager = ServerManager.shared -serverManager.loadServers() -for server in serverManager.servers { - if server.startOnLogin { - do { - try server.startSync() - } - catch let error as NSError { - Swift.print("Failed to start server \(server.name): \(error.localizedDescription)") - } - } +guard OpenURLAsLoginItem(mainAppURL as CFURL) else { + fatalError("Could not open main app as login item") } diff --git a/PostgresMenuHelper/AppDelegate.swift b/PostgresMenuHelper/AppDelegate.swift deleted file mode 100644 index c4fa3ebba..000000000 --- a/PostgresMenuHelper/AppDelegate.swift +++ /dev/null @@ -1,131 +0,0 @@ -// -// AppDelegate.swift -// PostgresMenuHelper -// -// Created by Chris on 05/09/2016. -// This code is released under the terms of the PostgreSQL License. -// - -import Cocoa - -@NSApplicationMain -class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { - - let serverManager = ServerManager.shared - - let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) - let statusIcon = NSImage(named: "statusicon")! - - var menuItemViewControllers: [MenuItemViewController] = [] - - var mainApp: SBApplication { - let mainAppURL = Bundle.mainApp!.bundleURL - let mainApp = SBApplication(url: mainAppURL)! - return mainApp - } - - @IBOutlet var statusMenu: NSMenu! - - func applicationWillFinishLaunching(_ notification: Notification) { - if let myBundleVersion = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String { - for app in NSRunningApplication.runningApplications(withBundleIdentifier: Bundle.main.bundleIdentifier!) { - if app.bundleURL == Bundle.main.bundleURL { - continue - } - guard let bundleURL = app.bundleURL, - let bundle = Bundle(url: bundleURL), - let bundleVersion = bundle.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String - else { - print("Detected broken menu helper. Trying to quit it.") - app.terminate() - continue - } - - switch myBundleVersion.compare(bundleVersion, options: .numeric) { - case .orderedAscending: - // other app is newer - print("Detected newer menu helper is already running. Quitting.") - exit(1) - case .orderedDescending: - print("Detected older menu helper. Trying to quit it.") - app.terminate() - case .orderedSame: - print("Detected identical menu helper. Trying to quit it.") - app.terminate() - } - } - } - } - - func applicationDidFinishLaunching(_ notification: Notification) { - statusItem.menu = statusMenu - statusItem.button!.image = statusIcon - } - - - func menuNeedsUpdate(_ menu: NSMenu) { - guard menu == statusMenu else { return } - - serverManager.loadServers() - serverManager.refreshServerStatuses() - - menuItemViewControllers.removeAll() - - for item in statusMenu.items where item.view is MenuItemView { - statusMenu.removeItem(item) - } - - var maxStringWidth = CGFloat(0) - for server in serverManager.servers { - let stringWidth = (server.name as NSString).size(withAttributes: [NSAttributedString.Key.font: NSFont.systemFont(ofSize: 12)]).width - maxStringWidth = max(stringWidth, maxStringWidth) - } - - for server in serverManager.servers { - guard let menuItemViewController = MenuItemViewController(server) else { return } - menuItemViewControllers.append(menuItemViewController) - - let menuItem = NSMenuItem() - - menuItemViewController.view.setFrameSize(NSSize(width: min(max(150+maxStringWidth, 200), 300), height: 32)) - menuItem.view = menuItemViewController.view - - statusMenu.addItem(menuItem) - } - } - - - @IBAction func openPostgresApp(_ sender: AnyObject?) { - if #available(macOS 14.0, *) { - NSApp.yieldActivation(toApplicationWithBundleIdentifier: Bundle.mainApp!.bundleIdentifier!) - } - mainApp.activate() - } - - @IBAction func openPreferences(_ sender: AnyObject?) { - if #available(macOS 14.0, *) { - NSApp.yieldActivation(toApplicationWithBundleIdentifier: Bundle.mainApp!.bundleIdentifier!) - } - mainApp.openPreferences() - } - - @IBAction func checkForUpdates(_ sender: AnyObject?) { - if #available(macOS 14.0, *) { - NSApp.yieldActivation(toApplicationWithBundleIdentifier: Bundle.mainApp!.bundleIdentifier!) - } - mainApp.checkForUpdates() - } - - @IBAction func quitPostgresMenuHelper(_ sender: AnyObject?) { - for server in serverManager.servers where server.running { - try? server.stopSync() - } - - for app in NSRunningApplication.runningApplications(withBundleIdentifier: "com.postgresapp.Postgres2") { - app.terminate() - } - - NSApp.terminate(nil) - } - -} diff --git a/PostgresMenuHelper/Assets.xcassets/AppIcon.appiconset/Contents.json b/PostgresMenuHelper/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c7c..000000000 --- a/PostgresMenuHelper/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "images" : [ - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/PostgresMenuHelper/Assets.xcassets/Contents.json b/PostgresMenuHelper/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/PostgresMenuHelper/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/PostgresMenuHelper/Assets.xcassets/icon-running.imageset/Contents.json b/PostgresMenuHelper/Assets.xcassets/icon-running.imageset/Contents.json deleted file mode 100644 index 8be281874..000000000 --- a/PostgresMenuHelper/Assets.xcassets/icon-running.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "icon_running.pdf", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/PostgresMenuHelper/Assets.xcassets/icon-running.imageset/icon_running.pdf b/PostgresMenuHelper/Assets.xcassets/icon-running.imageset/icon_running.pdf deleted file mode 100644 index 2c70439da..000000000 Binary files a/PostgresMenuHelper/Assets.xcassets/icon-running.imageset/icon_running.pdf and /dev/null differ diff --git a/PostgresMenuHelper/Assets.xcassets/icon-stopped.imageset/Contents.json b/PostgresMenuHelper/Assets.xcassets/icon-stopped.imageset/Contents.json deleted file mode 100644 index 14ac8dd37..000000000 --- a/PostgresMenuHelper/Assets.xcassets/icon-stopped.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "icon_stopped.pdf", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/PostgresMenuHelper/Assets.xcassets/icon-stopped.imageset/icon_stopped.pdf b/PostgresMenuHelper/Assets.xcassets/icon-stopped.imageset/icon_stopped.pdf deleted file mode 100644 index 0e274ea3a..000000000 Binary files a/PostgresMenuHelper/Assets.xcassets/icon-stopped.imageset/icon_stopped.pdf and /dev/null differ diff --git a/PostgresMenuHelper/Base.lproj/MainMenu.xib b/PostgresMenuHelper/Base.lproj/MainMenu.xib deleted file mode 100644 index 7e5bc4826..000000000 --- a/PostgresMenuHelper/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/PostgresMenuHelper/Info.plist b/PostgresMenuHelper/Info.plist deleted file mode 100644 index 3a6d2a456..000000000 --- a/PostgresMenuHelper/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(POSTGRESAPP_SHORT_VERSION) - CFBundleVersion - $(POSTGRESAPP_BUILD_VERSION) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - LSUIElement - - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - NSAppleEventsUsageDescription - Postgres.app Menu Bar Helper uses Apple Script to control Postgres.app - - diff --git a/PostgresMenuHelper/PostgresApplication.h b/PostgresMenuHelper/PostgresApplication.h deleted file mode 100644 index c2dc97151..000000000 --- a/PostgresMenuHelper/PostgresApplication.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * PostgresApplication.h - */ - -#import -#import - -/* - * Standard Suite - */ - -@interface SBApplication(PostgresApplication) - -- (BOOL) openPreferences; // Opens the Preferences. -- (BOOL) checkForUpdates; // Checks for updates. - -@end diff --git a/PostgresMenuHelper/PostgresMenuHelper-Bridging-Header.h b/PostgresMenuHelper/PostgresMenuHelper-Bridging-Header.h deleted file mode 100644 index dbe7c03bb..000000000 --- a/PostgresMenuHelper/PostgresMenuHelper-Bridging-Header.h +++ /dev/null @@ -1,7 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - -#import "libproc.h" -#import "ErrorRecoveryAttempter.h" -#import "PostgresApplication.h" diff --git a/buildscripts/01-build.sh b/buildscripts/01-build.sh index ed04e5aea..5fe1d8dd1 100755 --- a/buildscripts/01-build.sh +++ b/buildscripts/01-build.sh @@ -119,7 +119,6 @@ done codesign --force --timestamp --options runtime --sign "$CODE_SIGN_IDENTITY" \ "$APP"/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/Autoupdate \ "$APP"/Contents/Frameworks/Sparkle.framework/Versions/A/Sparkle \ - "$APP"/Contents/MacOS/PostgresMenuHelper.app \ "$APP"/Contents/Library/LoginItems/PostgresLoginHelper.app \ >>"$LOG_DIR/04-codesign.log" 2>&1