From 7f9264940ed161afd297a6255127fcb8b957865c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20C=C5=93ur?= Date: Mon, 25 Apr 2022 04:34:30 +0800 Subject: [PATCH] Compatibility to build on the last macOS 32 bit system with its last compatible Xcode (#2844) * Compatibility to build on the last macOS 32 bit system with its last compatible Xcode * Code review: Compatibility declarations * compatibility with `make` * Code review: headers * Avoiding dummy NSImageSymbolConfiguration implementation * clang-format * Don't force-include compat header * Remove compat header from pch header Co-authored-by: Charles Kerr Co-authored-by: Mike Gelfand --- Transmission.xcodeproj/project.pbxproj | 10 +++ macosx/CocoaCompatibility.h | 42 ++++++++++ macosx/Controller.mm | 108 +++++-------------------- macosx/NSImageAdditions.h | 2 + macosx/NSImageAdditions.mm | 15 ++++ macosx/PrefsController.mm | 64 ++------------- macosx/PrefsWindow.mm | 2 + macosx/TorrentTableView.mm | 2 + macosx/TrackerCell.mm | 2 + 9 files changed, 101 insertions(+), 146 deletions(-) create mode 100644 macosx/CocoaCompatibility.h diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index 4b9df2247..c2511467f 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -1139,6 +1139,7 @@ C3D9061827B7E1DE00EF2386 /* psl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = psl.c; path = src/psl.c; sourceTree = ""; }; C3D9061B27B7E31100EF2386 /* libpsl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libpsl.h; path = include/libpsl.h; sourceTree = ""; }; C3D9062127B7E3C900EF2386 /* libpsl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpsl.a; sourceTree = BUILT_PRODUCTS_DIR; }; + C81E411127F5BABD00652F56 /* CocoaCompatibility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CocoaCompatibility.h; sourceTree = ""; }; C88771A92803EE42005C7523 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; C88771AB2803EE53005C7523 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; }; C887BEC02807FCE900867D3C /* create.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = create.cc; sourceTree = ""; }; @@ -1353,6 +1354,7 @@ A2F7CF5E13035FFD0016FF10 /* URLSheetWindowController.mm */, A2966E8513DAF74C007B52DF /* GlobalOptionsPopoverViewController.h */, A2966E8613DAF74C007B52DF /* GlobalOptionsPopoverViewController.mm */, + C81E411027F5BA8300652F56 /* Compatibility */, A234D0D40C79FB6000A82373 /* Additions */, E1B6FBF80C0D719B0015FE4D /* Info Window */, A26AF2220D2DA42800FF7140 /* File Outline View */, @@ -1995,6 +1997,14 @@ path = "third-party/libpsl"; sourceTree = ""; }; + C81E411027F5BA8300652F56 /* Compatibility */ = { + isa = PBXGroup; + children = ( + C81E411127F5BABD00652F56 /* CocoaCompatibility.h */, + ); + name = Compatibility; + sourceTree = ""; + }; E1B6FBF80C0D719B0015FE4D /* Info Window */ = { isa = PBXGroup; children = ( diff --git a/macosx/CocoaCompatibility.h b/macosx/CocoaCompatibility.h new file mode 100644 index 000000000..d2a0cdc2f --- /dev/null +++ b/macosx/CocoaCompatibility.h @@ -0,0 +1,42 @@ +// This file Copyright © 2011-2022 Transmission authors and contributors. +// It may be used under the MIT (SPDX: MIT) license. +// License text can be found in the licenses/ folder. + +#import + +NS_ASSUME_NONNULL_BEGIN + +// Compatibility declarations to build `@available(macOS 11.0, *)` code with older Xcode 11.3.1 (the last 32-bit OS compatible Xcode) +#ifndef __MAC_11_0 + +typedef NS_ENUM(NSInteger, NSImageSymbolScale) +{ + NSImageSymbolScaleLarge = 3, +} API_AVAILABLE(macos(11.0)); + +@interface NSImage () ++ (nullable instancetype)imageWithSystemSymbolName:(NSString*)symbolName + accessibilityDescription:(nullable NSString*)description API_AVAILABLE(macos(11.0)); +@end + +typedef NS_ENUM(NSInteger, NSWindowToolbarStyle) +{ + NSWindowToolbarStylePreference = 2, +} API_AVAILABLE(macos(11.0)); + +@interface NSWindow () +@property NSWindowToolbarStyle toolbarStyle API_AVAILABLE(macos(11.0)); +@end + +typedef NS_ENUM(NSInteger, NSTableViewStyle) +{ + NSTableViewStyleFullWidth = 1, +} API_AVAILABLE(macos(11.0)); + +@interface NSTableView () +@property NSTableViewStyle style API_AVAILABLE(macos(11.0)); +@end + +#endif + +NS_ASSUME_NONNULL_END diff --git a/macosx/Controller.mm b/macosx/Controller.mm index 44d9126a3..f57573e83 100644 --- a/macosx/Controller.mm +++ b/macosx/Controller.mm @@ -19,6 +19,8 @@ #import "VDKQueue.h" +#import "CocoaCompatibility.h" + #import "Controller.h" #import "Torrent.h" #import "TorrentGroup.h" @@ -47,6 +49,7 @@ #import "Badger.h" #import "DragOverlayWindow.h" #import "NSApplicationAdditions.h" +#import "NSImageAdditions.h" #import "NSMutableArrayAdditions.h" #import "NSStringAdditions.h" #import "ExpandedPathToPathTransformer.h" @@ -4275,14 +4278,7 @@ static void removeKeRangerRansomware() item.label = NSLocalizedString(@"Create", "Create toolbar item -> label"); item.paletteLabel = NSLocalizedString(@"Create Torrent File", "Create toolbar item -> palette label"); item.toolTip = NSLocalizedString(@"Create torrent file", "Create toolbar item -> tooltip"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"doc.badge.plus" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:@"ToolbarCreateTemplate"]; - } + item.image = [NSImage systemSymbol:@"doc.badge.plus" withFallback:@"ToolbarCreateTemplate"]; item.target = self; item.action = @selector(createFile:); item.autovalidates = NO; @@ -4296,14 +4292,7 @@ static void removeKeRangerRansomware() item.label = NSLocalizedString(@"Open", "Open toolbar item -> label"); item.paletteLabel = NSLocalizedString(@"Open Torrent Files", "Open toolbar item -> palette label"); item.toolTip = NSLocalizedString(@"Open torrent files", "Open toolbar item -> tooltip"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"folder" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:@"ToolbarOpenTemplate"]; - } + item.image = [NSImage systemSymbol:@"folder" withFallback:@"ToolbarOpenTemplate"]; item.target = self; item.action = @selector(openShowSheet:); item.autovalidates = NO; @@ -4317,14 +4306,7 @@ static void removeKeRangerRansomware() item.label = NSLocalizedString(@"Open Address", "Open address toolbar item -> label"); item.paletteLabel = NSLocalizedString(@"Open Torrent Address", "Open address toolbar item -> palette label"); item.toolTip = NSLocalizedString(@"Open torrent web address", "Open address toolbar item -> tooltip"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"globe" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:@"ToolbarOpenWebTemplate"]; - } + item.image = [NSImage systemSymbol:@"globe" withFallback:@"ToolbarOpenWebTemplate"]; item.target = self; item.action = @selector(openURLShowSheet:); item.autovalidates = NO; @@ -4338,14 +4320,7 @@ static void removeKeRangerRansomware() item.label = NSLocalizedString(@"Remove", "Remove toolbar item -> label"); item.paletteLabel = NSLocalizedString(@"Remove Selected", "Remove toolbar item -> palette label"); item.toolTip = NSLocalizedString(@"Remove selected transfers", "Remove toolbar item -> tooltip"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"nosign" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:@"ToolbarRemoveTemplate"]; - } + item.image = [NSImage systemSymbol:@"nosign" withFallback:@"ToolbarRemoveTemplate"]; item.target = self; item.action = @selector(removeNoDelete:); item.visibilityPriority = NSToolbarItemVisibilityPriorityHigh; @@ -4360,14 +4335,7 @@ static void removeKeRangerRansomware() item.label = NSLocalizedString(@"Inspector", "Inspector toolbar item -> label"); item.paletteLabel = NSLocalizedString(@"Toggle Inspector", "Inspector toolbar item -> palette label"); item.toolTip = NSLocalizedString(@"Toggle the torrent inspector", "Inspector toolbar item -> tooltip"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"info.circle" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:@"ToolbarInfoTemplate"]; - } + item.image = [NSImage systemSymbol:@"info.circle" withFallback:@"ToolbarInfoTemplate"]; item.target = self; item.action = @selector(showInfo:); @@ -4405,32 +4373,14 @@ static void removeKeRangerRansomware() groupItem.identifiers = @[ TOOLBAR_PAUSE_ALL, TOOLBAR_RESUME_ALL ]; [segmentedCell setTag:TOOLBAR_PAUSE_TAG forSegment:TOOLBAR_PAUSE_TAG]; - if (@available(macOS 11.0, *)) - { - [segmentedControl setImage:[[NSImage imageWithSystemSymbolName:@"pause.circle.fill" accessibilityDescription:nil] - imageWithSymbolConfiguration:[NSImageSymbolConfiguration configurationWithScale:NSImageSymbolScaleLarge]] - forSegment:TOOLBAR_PAUSE_TAG]; - } - else - { - [segmentedControl setImage:[NSImage imageNamed:@"ToolbarPauseAllTemplate"] forSegment:TOOLBAR_PAUSE_TAG]; - } - [segmentedCell setToolTip:NSLocalizedString(@"Pause all transfers", "All toolbar item -> tooltip") - forSegment:TOOLBAR_PAUSE_TAG]; + [segmentedControl setImage:[NSImage largeSystemSymbol:@"pause.circle.fill" withFallback:@"ToolbarPauseAllTemplate"] + forSegment:TOOLBAR_PAUSE_TAG]; + [segmentedCell setToolTip:NSLocalizedString(@"Pause all transfers", "All toolbar item -> tooltip") forSegment:TOOLBAR_PAUSE_TAG]; [segmentedCell setTag:TOOLBAR_RESUME_TAG forSegment:TOOLBAR_RESUME_TAG]; [segmentedControl setImage:[NSImage imageNamed:@"ToolbarResumeAllTemplate"] forSegment:TOOLBAR_RESUME_TAG]; - if (@available(macOS 11.0, *)) - { - [segmentedControl - setImage:[[NSImage imageWithSystemSymbolName:@"arrow.clockwise.circle.fill" accessibilityDescription:nil] - imageWithSymbolConfiguration:[NSImageSymbolConfiguration configurationWithScale:NSImageSymbolScaleLarge]] - forSegment:TOOLBAR_RESUME_TAG]; - } - else - { - [segmentedControl setImage:[NSImage imageNamed:@"ToolbarResumeAllTemplate"] forSegment:TOOLBAR_RESUME_TAG]; - } + [segmentedControl setImage:[NSImage largeSystemSymbol:@"arrow.clockwise.circle.fill" withFallback:@"ToolbarResumeAllTemplate"] + forSegment:TOOLBAR_RESUME_TAG]; [segmentedCell setToolTip:NSLocalizedString(@"Resume all transfers", "All toolbar item -> tooltip") forSegment:TOOLBAR_RESUME_TAG]; @@ -4474,29 +4424,14 @@ static void removeKeRangerRansomware() groupItem.identifiers = @[ TOOLBAR_PAUSE_SELECTED, TOOLBAR_RESUME_SELECTED ]; [segmentedCell setTag:TOOLBAR_PAUSE_TAG forSegment:TOOLBAR_PAUSE_TAG]; - if (@available(macOS 11.0, *)) - { - [segmentedControl setImage:[[NSImage imageWithSystemSymbolName:@"pause" accessibilityDescription:nil] - imageWithSymbolConfiguration:[NSImageSymbolConfiguration configurationWithScale:NSImageSymbolScaleLarge]] - forSegment:TOOLBAR_PAUSE_TAG]; - } - else - { - [segmentedControl setImage:[NSImage imageNamed:@"ToolbarPauseSelectedTemplate"] forSegment:TOOLBAR_PAUSE_TAG]; - } + [segmentedControl setImage:[NSImage largeSystemSymbol:@"pause" withFallback:@"ToolbarPauseSelectedTemplate"] + forSegment:TOOLBAR_PAUSE_TAG]; [segmentedCell setToolTip:NSLocalizedString(@"Pause selected transfers", "Selected toolbar item -> tooltip") forSegment:TOOLBAR_PAUSE_TAG]; [segmentedCell setTag:TOOLBAR_RESUME_TAG forSegment:TOOLBAR_RESUME_TAG]; - if (@available(macOS 11.0, *)) - { - [segmentedControl setImage:[NSImage imageWithSystemSymbolName:@"arrow.clockwise" accessibilityDescription:nil] - forSegment:TOOLBAR_RESUME_TAG]; - } - else - { - [segmentedControl setImage:[NSImage imageNamed:@"ToolbarResumeSelectedTemplate"] forSegment:TOOLBAR_RESUME_TAG]; - } + [segmentedControl setImage:[NSImage systemSymbol:@"arrow.clockwise" withFallback:@"ToolbarResumeSelectedTemplate"] + forSegment:TOOLBAR_RESUME_TAG]; [segmentedCell setToolTip:NSLocalizedString(@"Resume selected transfers", "Selected toolbar item -> tooltip") forSegment:TOOLBAR_RESUME_TAG]; @@ -4517,14 +4452,7 @@ static void removeKeRangerRansomware() item.label = NSLocalizedString(@"Filter", "Filter toolbar item -> label"); item.paletteLabel = NSLocalizedString(@"Toggle Filter", "Filter toolbar item -> palette label"); item.toolTip = NSLocalizedString(@"Toggle the filter bar", "Filter toolbar item -> tooltip"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"magnifyingglass" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:@"ToolbarFilterTemplate"]; - } + item.image = [NSImage systemSymbol:@"magnifyingglass" withFallback:@"ToolbarFilterTemplate"]; item.target = self; item.action = @selector(toggleFilterBar:); diff --git a/macosx/NSImageAdditions.h b/macosx/NSImageAdditions.h index 0fd0d1675..fdb5b7da3 100644 --- a/macosx/NSImageAdditions.h +++ b/macosx/NSImageAdditions.h @@ -8,6 +8,8 @@ - (NSImage*)imageWithColor:(NSColor*)color; +/* macOS < 11 compatibility */ + (NSImage*)systemSymbol:(NSString*)symbolName withFallback:(NSString*)fallbackName; ++ (NSImage*)largeSystemSymbol:(NSString*)symbolName withFallback:(NSString*)fallbackName; @end diff --git a/macosx/NSImageAdditions.mm b/macosx/NSImageAdditions.mm index 03d818c26..90648bedd 100644 --- a/macosx/NSImageAdditions.mm +++ b/macosx/NSImageAdditions.mm @@ -2,6 +2,8 @@ // It may be used under the MIT (SPDX: MIT) license. // License text can be found in the licenses/ folder. +#import "CocoaCompatibility.h" + #import "NSImageAdditions.h" @implementation NSImage (NSImageAdditions) @@ -32,4 +34,17 @@ return [NSImage imageNamed:fallbackName]; } ++ (NSImage*)largeSystemSymbol:(NSString*)symbolName withFallback:(NSString*)fallbackName +{ +#ifdef __MAC_11_0 + if (@available(macOS 11.0, *)) + { + return [[NSImage imageWithSystemSymbolName:symbolName accessibilityDescription:nil] + imageWithSymbolConfiguration:[NSImageSymbolConfiguration configurationWithScale:NSImageSymbolScaleLarge]]; + } +#endif + + return [NSImage imageNamed:fallbackName]; +} + @end diff --git a/macosx/PrefsController.mm b/macosx/PrefsController.mm index 90fde3e10..2f516a6db 100644 --- a/macosx/PrefsController.mm +++ b/macosx/PrefsController.mm @@ -18,6 +18,7 @@ #import "PortChecker.h" #import "BonjourController.h" #import "NSApplicationAdditions.h" +#import "NSImageAdditions.h" #import "NSStringAdditions.h" #define DOWNLOAD_FOLDER 0 @@ -296,14 +297,7 @@ if ([ident isEqualToString:TOOLBAR_GENERAL]) { item.label = NSLocalizedString(@"General", "Preferences -> toolbar item title"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"gearshape" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:NSImageNamePreferencesGeneral]; - } + item.image = [NSImage systemSymbol:@"gearshape" withFallback:NSImageNamePreferencesGeneral]; item.target = self; item.action = @selector(setPrefView:); item.autovalidates = NO; @@ -311,14 +305,7 @@ else if ([ident isEqualToString:TOOLBAR_TRANSFERS]) { item.label = NSLocalizedString(@"Transfers", "Preferences -> toolbar item title"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"arrow.up.arrow.down" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:@"Transfers"]; - } + item.image = [NSImage systemSymbol:@"arrow.up.arrow.down" withFallback:@"Transfers"]; item.target = self; item.action = @selector(setPrefView:); item.autovalidates = NO; @@ -326,14 +313,7 @@ else if ([ident isEqualToString:TOOLBAR_GROUPS]) { item.label = NSLocalizedString(@"Groups", "Preferences -> toolbar item title"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"pin" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:@"Groups"]; - } + item.image = [NSImage systemSymbol:@"pin" withFallback:@"Groups"]; item.target = self; item.action = @selector(setPrefView:); item.autovalidates = NO; @@ -341,14 +321,7 @@ else if ([ident isEqualToString:TOOLBAR_BANDWIDTH]) { item.label = NSLocalizedString(@"Bandwidth", "Preferences -> toolbar item title"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"speedometer" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:@"Bandwidth"]; - } + item.image = [NSImage systemSymbol:@"speedometer" withFallback:@"Bandwidth"]; item.target = self; item.action = @selector(setPrefView:); item.autovalidates = NO; @@ -356,14 +329,7 @@ else if ([ident isEqualToString:TOOLBAR_PEERS]) { item.label = NSLocalizedString(@"Peers", "Preferences -> toolbar item title"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"person.2" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:NSImageNameUserGroup]; - } + item.image = [NSImage systemSymbol:@"person.2" withFallback:NSImageNameUserGroup]; item.target = self; item.action = @selector(setPrefView:); item.autovalidates = NO; @@ -371,14 +337,7 @@ else if ([ident isEqualToString:TOOLBAR_NETWORK]) { item.label = NSLocalizedString(@"Network", "Preferences -> toolbar item title"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"network" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:NSImageNameNetwork]; - } + item.image = [NSImage systemSymbol:@"network" withFallback:NSImageNameNetwork]; item.target = self; item.action = @selector(setPrefView:); item.autovalidates = NO; @@ -386,14 +345,7 @@ else if ([ident isEqualToString:TOOLBAR_REMOTE]) { item.label = NSLocalizedString(@"Remote", "Preferences -> toolbar item title"); - if (@available(macOS 11.0, *)) - { - item.image = [NSImage imageWithSystemSymbolName:@"antenna.radiowaves.left.and.right" accessibilityDescription:nil]; - } - else - { - item.image = [NSImage imageNamed:@"Remote"]; - } + item.image = [NSImage systemSymbol:@"antenna.radiowaves.left.and.right" withFallback:@"Remote"]; item.target = self; item.action = @selector(setPrefView:); item.autovalidates = NO; diff --git a/macosx/PrefsWindow.mm b/macosx/PrefsWindow.mm index 25e5ce82f..203dafcdf 100644 --- a/macosx/PrefsWindow.mm +++ b/macosx/PrefsWindow.mm @@ -2,6 +2,8 @@ // It may be used under the MIT (SPDX: MIT) license. // License text can be found in the licenses/ folder. +#import "CocoaCompatibility.h" + #import "PrefsWindow.h" @implementation PrefsWindow diff --git a/macosx/TorrentTableView.mm b/macosx/TorrentTableView.mm index 2c87f25a3..bd7557dc9 100644 --- a/macosx/TorrentTableView.mm +++ b/macosx/TorrentTableView.mm @@ -2,6 +2,8 @@ // It may be used under the MIT (SPDX: MIT) license. // License text can be found in the licenses/ folder. +#import "CocoaCompatibility.h" + #import "TorrentTableView.h" #import "Controller.h" #import "FileListNode.h" diff --git a/macosx/TrackerCell.mm b/macosx/TrackerCell.mm index 1bc3ce968..781b5ed3b 100644 --- a/macosx/TrackerCell.mm +++ b/macosx/TrackerCell.mm @@ -5,6 +5,8 @@ #include #include //tr_addressIsIP() +#import "CocoaCompatibility.h" + #import "TrackerCell.h" #import "TrackerNode.h"