file association fixes macOS

This commit is contained in:
2026-08-13 14:34:51 -07:00
parent d2a595d0d0
commit 2f76622e52
4 changed files with 31 additions and 45 deletions
+6
View File
@@ -1,3 +1,9 @@
# Version 1.6.1
- Fixed an issue where file associations appeared to work but would not load the project on macOS
- Fixed an issue where file associations would refuse to assosciate on macOS
# Version 1.6.0
- This is potentially a save-changing release due to adding more data into the save file, renaming existing data, and changing what part of the code saves data. Please update your project files to ensure compatibility
+2 -41
View File
@@ -337,45 +337,6 @@ def _register_macos(ext: str, app_name: str, bundle_id: str) -> Tuple[bool, str]
if not app_bundle_path.endswith(".app"):
return False, "Could not locate outer .app bundle."
info_plist_path = os.path.join(app_bundle_path, "Contents", "Info.plist")
if not os.path.exists(info_plist_path):
return False, f"Info.plist not found at {info_plist_path}"
clean_ext = ext.lstrip('.')
uti = f"{bundle_id}.{clean_ext}"
try:
with open(info_plist_path, "rb") as f:
plist = plistlib.load(f)
# Tell macOS this app can open files with our UTI
doc_types = plist.get("CFBundleDocumentTypes", [])
if not any(uti in dt.get("LSItemContentTypes", []) for dt in doc_types):
doc_types.append({
"CFBundleTypeName": f"{app_name} Project File",
"CFBundleTypeRole": "Editor",
"LSHandlerRank": "Owner",
"LSItemContentTypes": [uti],
})
plist["CFBundleDocumentTypes"] = doc_types
# Declare the UTI itself (required — without this the type is unknown to LS)
exported_types = plist.get("UTExportedTypeDeclarations", [])
if not any(t.get("UTTypeIdentifier") == uti for t in exported_types):
exported_types.append({
"UTTypeIdentifier": uti,
"UTTypeDescription": f"{app_name} File",
"UTTypeConformsTo": ["public.data"],
"UTTypeTagSpecification": {"public.filename-extension": [clean_ext]},
})
plist["UTExportedTypeDeclarations"] = exported_types
with open(info_plist_path, "wb") as f:
plistlib.dump(plist, f)
except Exception as e:
return False, f"Failed to update Info.plist: {str(e)}"
try:
lsregister_path = (
"/System/Library/Frameworks/CoreServices.framework/Frameworks/"
@@ -385,9 +346,9 @@ def _register_macos(ext: str, app_name: str, bundle_id: str) -> Tuple[bool, str]
[lsregister_path, "-f", app_bundle_path],
check=True, capture_output=True,
)
return True, f"Registered {ext} with {app_bundle_path} via macOS Launch Services!"
return True, f"Refreshed Launch Services registration for {app_bundle_path}."
except subprocess.CalledProcessError as e:
stderr = e.stderr.decode(errors="ignore") if e.stderr else str(e)
return False, f"macOS Launch Services registration failed: {stderr}"
return False, f"macOS Launch Services refresh failed: {stderr}"
except Exception as e:
return False, f"macOS Registration failed: {str(e)}"
+22 -3
View File
@@ -28,7 +28,7 @@ from PySide6.QtWidgets import (
QApplication, QWidget, QMessageBox, QVBoxLayout, QHBoxLayout, QTextEdit, QScrollArea, QComboBox, QGridLayout, QSplitter, QDialogButtonBox, QHeaderView,
QPushButton, QMainWindow, QLabel, QLineEdit, QGroupBox, QDialog, QMenu, QSpinBox, QTableWidget, QTableWidgetItem
)
from PySide6.QtCore import Signal, Qt, QTimer
from PySide6.QtCore import QEvent, Signal, Qt, QTimer
from PySide6.QtGui import QAction, QFontMetrics, QKeySequence, QIcon
from PySide6.QtSvgWidgets import QSvgWidget # needed to show svgs when app is not frozen
@@ -488,7 +488,26 @@ class GroupAssignmentDialog(QDialog):
return mappings
class CustomApplication(QApplication):
"""
macOS delivers a file-open request (double-clicking a registered
file, or dropping one on the Dock icon — whether the app is already
running or being launched fresh) as an Apple Event, which Qt exposes
as QEvent.Type.FileOpen. Windows/Linux never send this; they pass
the path as a normal argv argument, which startup_args.initial_file
already handles. Without this override, double-clicking a project
file on macOS launches the app but it never learns which file to open.
"""
file_open_requested = Signal(str)
def event(self, e: QEvent) -> bool:
if e.type() == QEvent.Type.FileOpen:
self.file_open_requested.emit(e.file())
return True
return super().event(e)
class MainApplication(QMainWindow):
"""
@@ -1334,7 +1353,6 @@ class MainApplication(QMainWindow):
def apply_splitter_ratios(self):
"""Applies saved ratio positions to main_h_splitter and left_v_splitter."""
if hasattr(self, 'main_h_splitter'):
print("Splitter actual width:", self.main_h_splitter.width())
total_width = self.main_h_splitter.width()
if total_width > 0:
left_w = int(total_width * self.main_h_ratio)
@@ -2648,11 +2666,12 @@ if __name__ == "__main__":
# Only run GUI in the main process
if current_process().name == 'MainProcess':
app = QApplication(sys.argv)
app = CustomApplication(sys.argv)
finish_update_if_needed(PLATFORM_NAME, APP_NAME, cfg_path, startup_args.finish_update)
icon_ext = "icns" if PLATFORM_NAME == "darwin" else "ico"
app.setWindowIcon(QIcon(resource_path(f"icons/main.{icon_ext}")))
window = MainApplication(file_to_open=startup_args.initial_file)
app.file_open_requested.connect(window.project_manager.load_project)
window.setWindowIcon(QIcon(resource_path(f"icons/main.{icon_ext}")))
window.show()
sys.exit(app.exec())
+1 -1
View File
@@ -13,7 +13,7 @@ import sys
import platform
CURRENT_VERSION = "1.6.0"
CURRENT_VERSION = "1.6.1"
APP_NAME = "flares"
APP_NAME_EXPANDED = "fNIRS Lightweight Analysis, Research, & Evaluation Suite"
API_URL = f"https://git.research.dezeeuw.ca/api/v1/repos/tyler/{APP_NAME}/releases"