Skip to content

Commit c2d0272

Browse files
committed
fix(settings): strip SCIKMS_LOCALE from env when respawning on restart
1 parent 8577b97 commit c2d0272

3 files changed

Lines changed: 81 additions & 9 deletions

File tree

scikms/gui/kms/pages/settings.py

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22

33
from __future__ import annotations
44

5+
import os
6+
import subprocess
7+
import sys
58
from typing import TYPE_CHECKING
69

7-
from PyQt6.QtCore import QSettings, Qt
8-
from PyQt6.QtWidgets import QFileDialog, QVBoxLayout, QWidget, QScrollArea
10+
from PyQt6.QtCore import QSettings, QTimer
11+
from PyQt6.QtWidgets import (
12+
QApplication, QFileDialog, QScrollArea, QVBoxLayout, QWidget,
13+
)
914
from qfluentwidgets import (
1015
BodyLabel, CardWidget, FluentIcon, InfoBar, InfoBarPosition, MessageBox,
1116
OptionsConfigItem, OptionsSettingCard, OptionsValidator, PlainTextEdit,
12-
PrimaryPushButton, PushButton, PushSettingCard, QConfig, SettingCardGroup,
17+
PrimaryPushButton, PushButton, PushSettingCard, SettingCardGroup,
1318
StrongBodyLabel, Theme, setTheme,
1419
)
1520

@@ -183,10 +188,8 @@ def _on_theme_change(self, item) -> None:
183188
def _on_lang_change(self, item) -> None:
184189
val = item.value if hasattr(item, "value") else str(item)
185190
self._qs.setValue("locale", val)
186-
InfoBar.info(
187-
title=t("kms-settings-language-restart"), content="",
188-
parent=self, position=InfoBarPosition.TOP_RIGHT, duration=3000,
189-
)
191+
self._qs.sync()
192+
self._prompt_restart()
190193

191194
def _on_clear_atlas(self) -> None:
192195
n = atlas_count()
@@ -213,10 +216,69 @@ def _on_clear_atlas(self) -> None:
213216
parent=self, position=InfoBarPosition.TOP_RIGHT, duration=2000)
214217

215218
def _on_change_data_root(self) -> None:
216-
new_path = QFileDialog.getExistingDirectory(self, t("kms-settings-data-change"), str(DATA_ROOT))
219+
new_path = QFileDialog.getExistingDirectory(
220+
self, t("kms-settings-data-change"), str(DATA_ROOT)
221+
)
217222
if new_path:
218223
self._qs.setValue("data_root", new_path)
224+
self._qs.sync()
225+
self._prompt_restart()
226+
227+
# ------------------------------------------------------------------
228+
def _prompt_restart(self) -> None:
229+
"""Confirm + restart the app so the new setting takes effect."""
230+
# Resolve top-level window so the MessageBox has the correct parent and
231+
# blocks the whole app while we ask, not just the settings scroll area.
232+
parent = self.window() or self
233+
box = MessageBox(
234+
t("kms-settings-restart-title"),
235+
t("kms-settings-restart-message"),
236+
parent,
237+
)
238+
# Customize button labels when available — MessageBox ships yes/cancel.
239+
if hasattr(box, "yesButton"):
240+
box.yesButton.setText(t("kms-settings-restart-now"))
241+
if hasattr(box, "cancelButton"):
242+
box.cancelButton.setText(t("kms-settings-restart-later"))
243+
if box.exec():
244+
# Delay the exec so Qt can finish paint + settings flush cleanly.
245+
QTimer.singleShot(0, self._restart_app)
246+
else:
219247
InfoBar.info(
220-
title=t("kms-settings-language-restart"), content=new_path,
248+
title=t("kms-settings-restart-later-banner"), content="",
221249
parent=self, position=InfoBarPosition.TOP_RIGHT, duration=3000,
222250
)
251+
252+
@staticmethod
253+
def _restart_app() -> None:
254+
"""Spawn a fresh process of ourselves, then exit this one.
255+
256+
``subprocess.Popen`` + ``sys.exit`` is preferred over ``os.execv``
257+
on macOS: re-exec'ing a Qt/Cocoa-initialized process makes the
258+
kernel reject its task-policy inheritance ("Task policy set failed:
259+
4 ((os/kern) invalid argument)"). A clean child process, started
260+
with ``start_new_session=True`` so the parent exit does not kill
261+
the child, avoids the warning entirely.
262+
263+
Works in both ``python -m scikms`` and the PyInstaller-bundled
264+
executable: when ``sys.frozen`` is set, ``sys.executable`` IS the
265+
bundle binary and its own argv is re-used; otherwise we re-invoke
266+
the Python interpreter with the current argv (the console script
267+
stub installed by ``uv sync`` is a plain Python script).
268+
"""
269+
if getattr(sys, "frozen", False):
270+
cmd = [sys.executable, *sys.argv[1:]]
271+
else:
272+
cmd = [sys.executable, *sys.argv]
273+
# The original process eagerly sets SCIKMS_LOCALE from QSettings at
274+
# startup so the i18n module picks it up. If we let the child inherit
275+
# that env var, it will ignore the freshly-saved QSettings value and
276+
# stay on the old locale after restart. Strip it so the child re-reads
277+
# QSettings on its own.
278+
env = os.environ.copy()
279+
env.pop("SCIKMS_LOCALE", None)
280+
subprocess.Popen(cmd, env=env, start_new_session=True)
281+
app = QApplication.instance()
282+
if app is not None:
283+
app.quit()
284+
sys.exit(0)

scikms/i18n/assets/en-US/kms.ftl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@ kms-settings-language = Language
178178
kms-settings-language-vi = Tiếng Việt
179179
kms-settings-language-en = English
180180
kms-settings-language-restart = Language change applies after restart.
181+
kms-settings-restart-title = Restart required
182+
kms-settings-restart-message = The change will take effect after restarting the app. Restart now?
183+
kms-settings-restart-now = Restart now
184+
kms-settings-restart-later = Later
185+
kms-settings-restart-later-banner = Change will apply on next launch.
181186
kms-settings-about = About SciKMS
182187
kms-settings-version = Version
183188

scikms/i18n/assets/vi-VN/kms.ftl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ kms-settings-language = Ngôn ngữ
181181
kms-settings-language-vi = Tiếng Việt
182182
kms-settings-language-en = English
183183
kms-settings-language-restart = Đổi ngôn ngữ sẽ áp dụng sau khi khởi động lại.
184+
kms-settings-restart-title = Cần khởi động lại
185+
kms-settings-restart-message = Thay đổi sẽ có hiệu lực sau khi khởi động lại ứng dụng. Khởi động lại ngay?
186+
kms-settings-restart-now = Khởi động lại ngay
187+
kms-settings-restart-later = Để sau
188+
kms-settings-restart-later-banner = Thay đổi sẽ có hiệu lực ở lần chạy kế.
184189
kms-settings-about = Về SciKMS
185190
kms-settings-version = Phiên bản
186191

0 commit comments

Comments
 (0)