Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 47 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,20 @@ jobs:
with:
persist-credentials: false

- name: Assert Apple Silicon runner
run: |
set -euo pipefail
if [ "$(uname -m)" != "arm64" ]; then
echo "Release builds must run on Apple Silicon, got $(uname -m)" >&2
exit 1
fi

- name: Install mise
run: |
set -euo pipefail
MISE_VERSION="2026.6.0"
case "$(uname -m)" in
arm64) MISE_ARCH="arm64"; MISE_SHA256="8830cf720025583bfbc5ca77bcf15958bf6efb4743fb84be6b572fd85d3a6cd0" ;;
x86_64) MISE_ARCH="x64"; MISE_SHA256="fc2630a1cd4a9e16d097cc5d4feec8d868c8a014a9a419cdb41f817da022e8b2" ;;
*) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
esac
MISE_ARCH="arm64"
MISE_SHA256="8830cf720025583bfbc5ca77bcf15958bf6efb4743fb84be6b572fd85d3a6cd0"

MISE_TARBALL="mise-v${MISE_VERSION}-macos-${MISE_ARCH}.tar.gz"
curl -fsSLO "https://github.com/jdx/mise/releases/download/v${MISE_VERSION}/${MISE_TARBALL}"
Expand Down Expand Up @@ -59,6 +64,43 @@ jobs:
mise run clean
mise run build

- name: Verify Apple Silicon artifacts
run: |
set -euo pipefail

APP_PATH="build/Build/Products/Release/Glance.app"
test -d "$APP_PATH"
lipo -info HTMLConverter/htmlconverter.a | tee /tmp/htmlconverter-lipo.txt
if grep -q "x86_64" /tmp/htmlconverter-lipo.txt; then
echo "HTMLConverter archive contains x86_64" >&2
exit 1
fi
if ! grep -q "arm64" /tmp/htmlconverter-lipo.txt; then
echo "HTMLConverter archive does not contain arm64" >&2
exit 1
fi

found_macho=0
while IFS= read -r -d '' candidate; do
if info="$(lipo -info "$candidate" 2>/dev/null)"; then
found_macho=1
echo "$info"
if echo "$info" | grep -q "x86_64"; then
echo "Bundle artifact contains x86_64: $candidate" >&2
exit 1
fi
if ! echo "$info" | grep -q "arm64"; then
echo "Bundle artifact does not contain arm64: $candidate" >&2
exit 1
fi
fi
done < <(find "$APP_PATH" -type f -print0)

if [ "$found_macho" -eq 0 ]; then
echo "No Mach-O artifacts found in $APP_PATH" >&2
exit 1
fi

- name: Package DMG
env:
TAG_NAME: ${{ github.ref_name }}
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Xcode
project.xcworkspace/
!Glance.xcodeproj/project.xcworkspace/
!Glance.xcodeproj/project.xcworkspace/xcshareddata/
!Glance.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/
!Glance.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
xcuserdata/
build/
.DS_Store
Expand Down
4 changes: 3 additions & 1 deletion .swiftformat
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
--swiftversion 5.9
--swiftversion 6.0

--indent tab
--indentcase true
--maxwidth 100
--tabwidth 4
--exclude build

--disable hoistTry
21 changes: 0 additions & 21 deletions .woodpecker/lint.yaml

This file was deleted.

11 changes: 0 additions & 11 deletions .woodpecker/test.yaml

This file was deleted.

202 changes: 26 additions & 176 deletions Glance.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions Glance/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Cocoa

@main
@MainActor
class AppDelegate: NSObject, NSApplicationDelegate {
private var mainWindowController: NSWindowController?
private var statusItem: NSStatusItem?
Expand Down Expand Up @@ -79,7 +80,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}

@objc private func openMainWindow() {
NSApp.activate(ignoringOtherApps: true)
NSApp.activate()

if let window = existingMainWindow() {
window.deminiaturize(nil)
Expand All @@ -96,7 +97,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}

@objc private func openSupportedFilesWindow() {
NSApp.activate(ignoringOtherApps: true)
NSApp.activate()
SupportedFilesWC.shared.showSupportedFilesWindow()
}

Expand Down Expand Up @@ -151,7 +152,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {

@objc private func windowWillClose(_: Notification) {
// Defer so the closing window is no longer visible when we check
DispatchQueue.main.async { [weak self] in
Task { @MainActor [weak self] in
self?.updateDockIconVisibility()
}
}
Expand Down
3 changes: 2 additions & 1 deletion Glance/Extensions/NSMenuItem.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Cocoa
import Foundation

/// Source: Gifski
/// v2.7.0
Expand Down Expand Up @@ -40,10 +39,12 @@ final class ObjectAssociation<T: Any> {
}
}

@MainActor
extension NSMenuItem {
typealias ActionClosure = (NSMenuItem) -> Void

private enum AssociatedKeys {
@MainActor
static let onActionClosure = ObjectAssociation<ActionClosure>()
}

Expand Down
1 change: 0 additions & 1 deletion Glance/Extensions/URL.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Cocoa
import Foundation

extension URL {
func open() {
Expand Down
2 changes: 1 addition & 1 deletion Glance/SettingsWC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ final class SettingsWC: NSWindowController {

func showSettingsWindow() {
syncState()
NSApp.activate(ignoringOtherApps: true)
NSApp.activate()
showWindow(nil)
window?.makeKeyAndOrderFront(nil)
}
Expand Down
4 changes: 2 additions & 2 deletions Glance/Shared/Utils/AppSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import Foundation
struct AppSettingsStore {
static let sharedDefaultsSuiteName = "group.com.chamburr.glance"

static let sharedDefaults: UserDefaults = {
nonisolated(unsafe) static let sharedDefaults: UserDefaults = {
guard let defaults = UserDefaults(suiteName: sharedDefaultsSuiteName) else {
fatalError("Failed to create UserDefaults with app group suite '\(sharedDefaultsSuiteName)'. Check that the app group is correctly configured.")
}
return defaults
}()
static let shared = AppSettingsStore(
nonisolated(unsafe) static let shared = AppSettingsStore(
defaults: sharedDefaults,
standardDefaults: .standard
)
Expand Down
7 changes: 6 additions & 1 deletion Glance/Utils/Menu.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import Cocoa
import Foundation

let feedbackURL = URL(string: "https://github.com/chamburr/glance/issues")!
let licenseURL = URL(string: "https://github.com/chamburr/glance/blob/main/LICENSE.md")!
let privacyPolicyURL = URL(string: "https://github.com/chamburr/glance/blob/main/PRIVACY.md")!
let websiteURL = URL(string: "https://github.com/chamburr/glance")!

/// Used as a subclass for the menu item in Interface Builder
@MainActor
final class SupportedFilesMenuItem: NSMenuItem {
required init(coder decoder: NSCoder) {
super.init(coder: decoder)
Expand All @@ -18,6 +18,7 @@ final class SupportedFilesMenuItem: NSMenuItem {
}

/// Used as a subclass for the menu item in Interface Builder
@MainActor
final class SettingsMenuItem: NSMenuItem {
required init(coder decoder: NSCoder) {
super.init(coder: decoder)
Expand All @@ -29,6 +30,7 @@ final class SettingsMenuItem: NSMenuItem {
}

/// Used as a subclass for the menu item in Interface Builder
@MainActor
final class FeedbackMenuItem: NSMenuItem {
required init(coder decoder: NSCoder) {
super.init(coder: decoder)
Expand All @@ -40,6 +42,7 @@ final class FeedbackMenuItem: NSMenuItem {
}

/// Used as a subclass for the menu item in Interface Builder
@MainActor
final class LicenseMenuItem: NSMenuItem {
required init(coder decoder: NSCoder) {
super.init(coder: decoder)
Expand All @@ -51,6 +54,7 @@ final class LicenseMenuItem: NSMenuItem {
}

/// Used as a subclass for the menu item in Interface Builder
@MainActor
final class PrivacyPolicyMenuItem: NSMenuItem {
required init(coder decoder: NSCoder) {
super.init(coder: decoder)
Expand All @@ -62,6 +66,7 @@ final class PrivacyPolicyMenuItem: NSMenuItem {
}

/// Used as a subclass for the menu item in Interface Builder
@MainActor
final class WebsiteMenuItem: NSMenuItem {
required init(coder decoder: NSCoder) {
super.init(coder: decoder)
Expand Down
Loading