Spaces:
Paused
Paused
opencode commited on
Commit ·
a1ec78c
1
Parent(s): 9565f33
修正桌面啟動時的 No session for pid:停用 lxpolkit/light-locker autostart
Browse files
README.md
CHANGED
|
@@ -53,6 +53,8 @@ OpenCode 在啟動時安裝,並重設使用者層級設定為預設值。
|
|
| 53 |
重複的程序會被清掉。
|
| 54 |
- 桌面裡永遠有一個標題為「共用終端機」的 xterm;把它關掉後看門狗會自動再開一個,
|
| 55 |
所以固定分頁裡永遠有 1 個可用的圖形終端機視窗(使用者自己另開的终端機不受影響)。
|
|
|
|
|
|
|
| 56 |
- 瀏覽器是透過 `/vnc` WebSocket 橋接到同一個桌面,所有裝置看到完全相同、可同時操作的
|
| 57 |
LXDE 畫面;關掉瀏覽器分頁不會終止桌面,重新整理或重新連線都會接回原畫面。
|
| 58 |
- 這個分頁是固定的:按它的 `×` 不會刪除分頁,而是重新啟動一份新的桌面
|
|
|
|
| 53 |
重複的程序會被清掉。
|
| 54 |
- 桌面裡永遠有一個標題為「共用終端機」的 xterm;把它關掉後看門狗會自動再開一個,
|
| 55 |
所以固定分頁裡永遠有 1 個可用的圖形終端機視窗(使用者自己另開的终端機不受影響)。
|
| 56 |
+
- 容器內沒有 systemd-logind session,因此會自動停用 `lxpolkit` 與 `light-locker`
|
| 57 |
+
autostart,避免桌面啟動時跳出「No session for pid …」的 Error 對話框。
|
| 58 |
- 瀏覽器是透過 `/vnc` WebSocket 橋接到同一個桌面,所有裝置看到完全相同、可同時操作的
|
| 59 |
LXDE 畫面;關掉瀏覽器分頁不會終止桌面,重新整理或重新連線都會接回原畫面。
|
| 60 |
- 這個分頁是固定的:按它的 `×` 不會刪除分頁,而是重新啟動一份新的桌面
|
app.py
CHANGED
|
@@ -1460,6 +1460,79 @@ class DesktopManager:
|
|
| 1460 |
def _term_binary(self):
|
| 1461 |
return shutil.which("xterm") or shutil.which("lxterminal")
|
| 1462 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1463 |
def _kill_pids(self, pids, sig=signal.SIGTERM):
|
| 1464 |
for pid in pids:
|
| 1465 |
if not self._pid_alive(pid):
|
|
@@ -1544,6 +1617,7 @@ class DesktopManager:
|
|
| 1544 |
return True
|
| 1545 |
|
| 1546 |
async def _start_session(self) -> bool:
|
|
|
|
| 1547 |
last_error = "找不到 startlxde / lxsession / openbox"
|
| 1548 |
for launcher in ("startlxde", "lxsession", "openbox"):
|
| 1549 |
path = shutil.which(launcher)
|
|
@@ -1563,6 +1637,8 @@ class DesktopManager:
|
|
| 1563 |
if pid:
|
| 1564 |
self.pids["session"] = pid
|
| 1565 |
self._log(f"LXDE session 就緒({launcher},pid {pid})")
|
|
|
|
|
|
|
| 1566 |
return True
|
| 1567 |
last_error = f"{launcher} 啟動後立即結束(returncode={proc.poll()})"
|
| 1568 |
self._log(last_error, logging.WARNING)
|
|
@@ -1601,7 +1677,8 @@ class DesktopManager:
|
|
| 1601 |
return True
|
| 1602 |
name = os.path.basename(binary)
|
| 1603 |
if name == "xterm":
|
| 1604 |
-
argv = [binary, "-u8", "-
|
|
|
|
| 1605 |
"-T", self.TERM_TITLE, "-e", "bash", "--login"]
|
| 1606 |
else:
|
| 1607 |
argv = [binary, "--title=" + self.TERM_TITLE, "-e", "bash --login"]
|
|
@@ -1633,6 +1710,7 @@ class DesktopManager:
|
|
| 1633 |
if not await self._start_vnc():
|
| 1634 |
return False
|
| 1635 |
await self._start_term()
|
|
|
|
| 1636 |
self.started_at = time.time()
|
| 1637 |
if self._healthy():
|
| 1638 |
self.last_error = ""
|
|
|
|
| 1460 |
def _term_binary(self):
|
| 1461 |
return shutil.which("xterm") or shutil.which("lxterminal")
|
| 1462 |
|
| 1463 |
+
def _prepare_session_config(self):
|
| 1464 |
+
"""關掉容器裡必然失敗的 polkit / 螢幕鎖定 autostart,避免出現
|
| 1465 |
+
「No session for pid …」的 Error 對話框(Xvfb 沒有 logind session)。"""
|
| 1466 |
+
autostart = os.path.join(HOME, ".config", "autostart")
|
| 1467 |
+
try:
|
| 1468 |
+
os.makedirs(autostart, exist_ok=True)
|
| 1469 |
+
for name in ("lxpolkit", "light-locker"):
|
| 1470 |
+
path = os.path.join(autostart, name + ".desktop")
|
| 1471 |
+
content = (
|
| 1472 |
+
"[Desktop Entry]\n"
|
| 1473 |
+
"Type=Application\n"
|
| 1474 |
+
f"Name={name}\n"
|
| 1475 |
+
"Exec=/bin/true\n"
|
| 1476 |
+
"Hidden=true\n"
|
| 1477 |
+
"NoDisplay=true\n"
|
| 1478 |
+
"X-GNOME-Autostart-enabled=false\n"
|
| 1479 |
+
)
|
| 1480 |
+
if not (os.path.isfile(path) and open(path).read() == content):
|
| 1481 |
+
with open(path, "w") as f:
|
| 1482 |
+
f.write(content)
|
| 1483 |
+
except OSError as exc:
|
| 1484 |
+
self._log(f"無法寫入 autostart 覆寫:{exc}", logging.WARNING)
|
| 1485 |
+
|
| 1486 |
+
system_conf = "/etc/xdg/lxsession/LXDE/desktop.conf"
|
| 1487 |
+
user_conf = os.path.join(HOME, ".config", "lxsession", "LXDE", "desktop.conf")
|
| 1488 |
+
source = user_conf if os.path.isfile(user_conf) else system_conf
|
| 1489 |
+
try:
|
| 1490 |
+
if not os.path.isfile(source):
|
| 1491 |
+
return
|
| 1492 |
+
with open(source) as f:
|
| 1493 |
+
lines = f.read().splitlines()
|
| 1494 |
+
changed = False
|
| 1495 |
+
out = []
|
| 1496 |
+
for line in lines:
|
| 1497 |
+
if line.startswith("polkit/command=") and line != "polkit/command=":
|
| 1498 |
+
line = "polkit/command="
|
| 1499 |
+
changed = True
|
| 1500 |
+
elif line.startswith("lock_manager/command=") and line != "lock_manager/command=":
|
| 1501 |
+
line = "lock_manager/command="
|
| 1502 |
+
changed = True
|
| 1503 |
+
out.append(line)
|
| 1504 |
+
if changed or source != user_conf:
|
| 1505 |
+
os.makedirs(os.path.dirname(user_conf), exist_ok=True)
|
| 1506 |
+
with open(user_conf, "w") as f:
|
| 1507 |
+
f.write("\n".join(out) + "\n")
|
| 1508 |
+
except OSError as exc:
|
| 1509 |
+
self._log(f"無法寫入 lxsession 設定:{exc}", logging.WARNING)
|
| 1510 |
+
|
| 1511 |
+
def _suppress_session_popups(self):
|
| 1512 |
+
"""保險:如果 lxpolkit / light-locker 還是被拉起來,直接關掉(不影響桌面)。"""
|
| 1513 |
+
pids = []
|
| 1514 |
+
try:
|
| 1515 |
+
entries = os.listdir("/proc")
|
| 1516 |
+
except OSError:
|
| 1517 |
+
return
|
| 1518 |
+
for entry in entries:
|
| 1519 |
+
if not entry.isdigit():
|
| 1520 |
+
continue
|
| 1521 |
+
pid = int(entry)
|
| 1522 |
+
if pid == os.getpid():
|
| 1523 |
+
continue
|
| 1524 |
+
cmd = self._cmdline(pid)
|
| 1525 |
+
if not cmd:
|
| 1526 |
+
continue
|
| 1527 |
+
low = cmd.lower()
|
| 1528 |
+
if not any(name in low for name in ("lxpolkit", "light-locker")):
|
| 1529 |
+
continue
|
| 1530 |
+
if DESKTOP_DISPLAY in cmd or self._has_display(pid):
|
| 1531 |
+
pids.append(pid)
|
| 1532 |
+
if pids:
|
| 1533 |
+
self._log(f"關閉容器內無效的 session 元件:{pids}")
|
| 1534 |
+
self._kill_pids(pids, signal.SIGKILL)
|
| 1535 |
+
|
| 1536 |
def _kill_pids(self, pids, sig=signal.SIGTERM):
|
| 1537 |
for pid in pids:
|
| 1538 |
if not self._pid_alive(pid):
|
|
|
|
| 1617 |
return True
|
| 1618 |
|
| 1619 |
async def _start_session(self) -> bool:
|
| 1620 |
+
self._prepare_session_config()
|
| 1621 |
last_error = "找不到 startlxde / lxsession / openbox"
|
| 1622 |
for launcher in ("startlxde", "lxsession", "openbox"):
|
| 1623 |
path = shutil.which(launcher)
|
|
|
|
| 1637 |
if pid:
|
| 1638 |
self.pids["session"] = pid
|
| 1639 |
self._log(f"LXDE session 就緒({launcher},pid {pid})")
|
| 1640 |
+
await asyncio.sleep(0.5)
|
| 1641 |
+
await asyncio.to_thread(self._suppress_session_popups)
|
| 1642 |
return True
|
| 1643 |
last_error = f"{launcher} 啟動後立即結束(returncode={proc.poll()})"
|
| 1644 |
self._log(last_error, logging.WARNING)
|
|
|
|
| 1677 |
return True
|
| 1678 |
name = os.path.basename(binary)
|
| 1679 |
if name == "xterm":
|
| 1680 |
+
argv = [binary, "-u8", "-fa", "DejaVu Sans Mono", "-fs", "11",
|
| 1681 |
+
"-geometry", "110x32+50+50",
|
| 1682 |
"-T", self.TERM_TITLE, "-e", "bash", "--login"]
|
| 1683 |
else:
|
| 1684 |
argv = [binary, "--title=" + self.TERM_TITLE, "-e", "bash --login"]
|
|
|
|
| 1710 |
if not await self._start_vnc():
|
| 1711 |
return False
|
| 1712 |
await self._start_term()
|
| 1713 |
+
await asyncio.to_thread(self._suppress_session_popups)
|
| 1714 |
self.started_at = time.time()
|
| 1715 |
if self._healthy():
|
| 1716 |
self.last_error = ""
|