Skip to content

Commit 39e1994

Browse files
committed
Set up Swift/ObjC interop
1 parent 5bcb420 commit 39e1994

6 files changed

Lines changed: 121 additions & 44 deletions

File tree

‎Classes/GitX-Bridging-Header.h‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// GitX-Bridging-Header.h
3+
// GitX
4+
//
5+
// Exposes Objective-C headers to Swift.
6+
//
7+
// RULE: only add a header here when a Swift file actually needs to reference
8+
// the type/symbol. Do NOT bulk-import everything — it breaks archive builds.
9+
// External/ headers are imported via framework imports only (no bare filenames).
10+
//
11+
12+
// ── System ───────────────────────────────────────────────────────────────────
13+
#import <Cocoa/Cocoa.h>
14+
15+
// ── External frameworks (framework imports only — no bare filenames) ──────────
16+
#import <ObjectiveGit/ObjectiveGit.h>
17+
18+
// ── Converted files: headers kept so ObjC callers continue to compile ────────
19+
// NSAppearance+PBDarkMode.swift owns the implementations; .m only defines the constant.
20+
#import "NSAppearance+PBDarkMode.h"
21+
// NSColor+RGB.swift owns the implementation.
22+
#import "NSColor+RGB.h"
23+
// NSSplitView+GitX.swift owns the implementation.
24+
#import "NSSplitView+GitX.h"
25+
// GitXRelativeDateFormatter.swift owns the implementation.
26+
#import "GitXRelativeDateFormatter.h"
27+
28+
// ── Add further headers below only when a Swift source file needs them ────────

‎Classes/GitXSwift.swift‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// GitXSwift.swift
2+
//
3+
// Placeholder that activates the Swift compiler for the GitX target.
4+
// Actual Swift source files will be added here incrementally as
5+
// Objective-C files are converted one by one.
6+
//
7+
// Swift can call any Objective-C symbol that is imported in
8+
// Classes/GitX-Bridging-Header.h
9+
// Objective-C can call any Swift symbol that is visible in
10+
// GitX-Swift.h (generated automatically by the build system)
11+
12+
import Cocoa
13+

‎Classes/NSAppearance+PBDarkMode.m‎

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,13 @@
22
// NSAppearance+PBDarkMode.m
33
// GitX
44
//
5-
// Created by Etienne on 18/11/2018.
5+
// Only the global constant definition remains here — the category
6+
// implementations have been moved to NSAppearance+PBDarkMode.swift.
67
//
78

89
#import "NSAppearance+PBDarkMode.h"
910

11+
// This definition satisfies the `extern NSString *const` declaration in the
12+
// header for all Objective-C callers. The Swift side imports the same value
13+
// as a plain Swift String via the bridging header.
1014
NSString *const PBEffectiveAppearanceChanged = @"PBEffectiveAppearanceChanged";
11-
12-
@implementation NSAppearance (PBDarkMode)
13-
14-
- (BOOL)isDarkMode
15-
{
16-
if (@available(macOS 10.14, *)) {
17-
if ([self bestMatchFromAppearancesWithNames:@[ NSAppearanceNameDarkAqua, NSAppearanceNameAqua ]] == NSAppearanceNameDarkAqua)
18-
return YES;
19-
return NO;
20-
} else {
21-
return NO;
22-
}
23-
}
24-
25-
@end
26-
27-
@implementation NSApplication (PBDarkMode)
28-
29-
- (BOOL)isDarkMode
30-
{
31-
if (@available(macOS 10.14, *)) {
32-
return self.effectiveAppearance.isDarkMode;
33-
} else {
34-
return NO;
35-
}
36-
}
37-
38-
- (void)registerObserverForAppearanceChanges:(id)observer
39-
{
40-
if (@available(macOS 10.14, *)) {
41-
/* This leaks the observation, but since it's tied to the life of NSApp
42-
* it doesn't matter ;-) */
43-
[[NSApplication sharedApplication] addObserver:observer
44-
keyPath:@"effectiveAppearance"
45-
options:0
46-
block:^(MAKVONotification *notification) {
47-
[[NSNotificationCenter defaultCenter] postNotificationName:PBEffectiveAppearanceChanged object:observer];
48-
}];
49-
}
50-
}
51-
52-
@end
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//
2+
// NSAppearance+PBDarkMode.swift
3+
// GitX
4+
//
5+
// Converted from NSAppearance+PBDarkMode.m
6+
// Original by Etienne, 2018.
7+
//
8+
// Note: NSAppearance+PBDarkMode.m is still compiled solely to provide the
9+
// `extern NSString *const PBEffectiveAppearanceChanged` definition for ObjC
10+
// callers. The category implementations live here.
11+
//
12+
13+
import AppKit
14+
15+
// Swift-side alias so Swift code can use the constant by name.
16+
// The authoritative definition lives in NSAppearance+PBDarkMode.m.
17+
let PBEffectiveAppearanceChanged: String = "PBEffectiveAppearanceChanged"
18+
19+
// MARK: - NSAppearance
20+
21+
extension NSAppearance {
22+
/// Returns `true` when this appearance resolves to Dark Aqua.
23+
@objc var isDarkMode: Bool {
24+
bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
25+
}
26+
}
27+
28+
// MARK: - NSApplication
29+
30+
extension NSApplication {
31+
/// Returns `true` when the application's effective appearance is Dark Aqua.
32+
@objc var isDarkMode: Bool {
33+
effectiveAppearance.isDarkMode
34+
}
35+
36+
/// Registers `observer` for KVO on `effectiveAppearance` and re-posts
37+
/// `PBEffectiveAppearanceChanged` whenever it changes.
38+
/// The observation token is retained on `self` (i.e. NSApp) so it lives
39+
/// for the lifetime of the application — matching the original behaviour.
40+
@objc func registerObserverForAppearanceChanges(_ observer: Any) {
41+
let token = NSApp.observe(\.effectiveAppearance) { _, _ in
42+
NotificationCenter.default.post(
43+
name: Notification.Name(PBEffectiveAppearanceChanged),
44+
object: observer
45+
)
46+
}
47+
// Retain the token on NSApp so it lives for the lifetime of the app.
48+
objc_setAssociatedObject(
49+
self,
50+
&NSApplication.appearanceObservationKey,
51+
token,
52+
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
53+
)
54+
}
55+
56+
private static var appearanceObservationKey: UInt8 = 0
57+
}

‎Classes/git/PBGitLane.h‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#import <Cocoa/Cocoa.h>
1010

11+
#ifdef __cplusplus
12+
1113
class PBGitLane
1214
{
1315
git_oid d_sha;
@@ -38,4 +40,7 @@ class PBGitLane
3840
}
3941

4042
int index() const;
41-
};
43+
};
44+
45+
#endif // __cplusplus
46+

‎GitX.xcodeproj/project.pbxproj‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
/* Begin PBXBuildFile section */
2424
CC0000010000001 /* GitXScreenshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC0000020000002 /* GitXScreenshotTests.m */; };
25+
AABBCC0300000003 /* GitXSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABBCC0200000002 /* GitXSwift.swift */; };
2526
0A6858C711F7EA8A00AC2BE4 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A6858C611F7EA8A00AC2BE4 /* CoreServices.framework */; };
2627
2682AABB1929140E00271A4D /* GTOID+JavaScript.m in Sources */ = {isa = PBXBuildFile; fileRef = 2682AABA1929140E00271A4D /* GTOID+JavaScript.m */; };
2728
2DE9B60629ABEB450097873A /* GitX.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 2DE9B60529ABEB450097873A /* GitX.xcconfig */; };
@@ -440,6 +441,8 @@
440441
/* End PBXCopyFilesBuildPhase section */
441442

442443
/* Begin PBXFileReference section */
444+
AABBCC0100000001 /* GitX-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GitX-Bridging-Header.h"; sourceTree = "<group>"; };
445+
AABBCC0200000002 /* GitXSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GitXSwift.swift; sourceTree = "<group>"; };
443446
CC0000020000002 /* GitXScreenshotTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GitXScreenshotTests.m; sourceTree = "<group>"; };
444447
CC0000030000003 /* GitXUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GitXUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
445448
0A6858C611F7EA8A00AC2BE4 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
@@ -981,6 +984,8 @@
981984
4DF173E721A1D60A003CD3CE /* NSAppearance+PBDarkMode.h */,
982985
4DF173E821A1D60A003CD3CE /* NSAppearance+PBDarkMode.m */,
983986
A1021294218C5A2000D97D11 /* iTerm2GeneratedScriptingBridge.h */,
987+
AABBCC0100000001 /* GitX-Bridging-Header.h */,
988+
AABBCC0200000002 /* GitXSwift.swift */,
984989
);
985990
path = Classes;
986991
sourceTree = "<group>";
@@ -1749,6 +1754,7 @@
17491754
4A2125A417C0C78A00B5B582 /* NSColor+RGB.m in Sources */,
17501755
A2F8D0DF17AAB32500580B84 /* PBGitStash.m in Sources */,
17511756
A2F8D0EB17AAB95E00580B84 /* PBSourceViewGitStashItem.m in Sources */,
1757+
AABBCC0300000003 /* GitXSwift.swift in Sources */,
17521758
);
17531759
runOnlyForDeploymentPostprocessing = 0;
17541760
};
@@ -1902,11 +1908,14 @@
19021908
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
19031909
CODE_SIGN_ENTITLEMENTS = GitX.entitlements;
19041910
COMBINE_HIDPI_IMAGES = YES;
1911+
DEFINES_MODULE = YES;
19051912
FRAMEWORK_SEARCH_PATHS = "\"$(PROJECT_DIR)\"";
19061913
GCC_DYNAMIC_NO_PIC = NO;
19071914
GCC_PRECOMPILE_PREFIX_HEADER = YES;
19081915
GCC_PREFIX_HEADER = Resources/GitX_Prefix.pch;
19091916
INFOPLIST_FILE = Resources/Info.plist;
1917+
SWIFT_OBJC_BRIDGING_HEADER = Classes/GitX-Bridging-Header.h;
1918+
SWIFT_VERSION = 5.0;
19101919
INFOPLIST_KEY_CFBundleDisplayName = GitX;
19111920
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
19121921
INFOPLIST_OTHER_PREPROCESSOR_FLAGS = "-traditional";
@@ -1928,12 +1937,15 @@
19281937
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
19291938
CODE_SIGN_ENTITLEMENTS = GitX.entitlements;
19301939
COMBINE_HIDPI_IMAGES = YES;
1940+
DEFINES_MODULE = YES;
19311941
ENABLE_HARDENED_RUNTIME = YES;
19321942
FRAMEWORK_SEARCH_PATHS = "\"$(PROJECT_DIR)\"";
19331943
GCC_PRECOMPILE_PREFIX_HEADER = YES;
19341944
GCC_PREFIX_HEADER = Resources/GitX_Prefix.pch;
19351945
GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = "";
19361946
INFOPLIST_FILE = Resources/Info.plist;
1947+
SWIFT_OBJC_BRIDGING_HEADER = Classes/GitX-Bridging-Header.h;
1948+
SWIFT_VERSION = 5.0;
19371949
INFOPLIST_KEY_CFBundleDisplayName = GitX;
19381950
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
19391951
INFOPLIST_OTHER_PREPROCESSOR_FLAGS = "-traditional";

0 commit comments

Comments
 (0)