<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Wayland on Tarragon</title><link>https://tarrragon.github.io/blog/tags/wayland/</link><description>Recent content in Wayland on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Thu, 02 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/wayland/index.xml" rel="self" type="application/rss+xml"/><item><title>桌面環境選型：整合度與組裝自由度的取捨</title><link>https://tarrragon.github.io/blog/linux/tools/gui/desktop-environment-selection/</link><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/tools/gui/desktop-environment-selection/</guid><description>&lt;p>桌面環境（desktop environment，DE）是一整套讓你能用圖形介面操作 Linux 的元件集合——它同時提供視窗管理、面板/工作列、應用啟動器、設定中心、通知、檔案管理員、鎖屏這些功能，並保證它們彼此整合、開箱即用。這跟只負責「畫視窗、管理視窗位置」的 window manager 或 compositor 是不同層次的東西：DE 通常內含一個 window manager，再把上面那一整圈桌面服務組裝好交給你。理解這個責任邊界，是選型的起點——你在選的不是「哪個比較漂亮」，是「別人幫你整合到什麼程度、你自己要組裝多少」。&lt;/p>
&lt;h2 id="選型的真正軸線整合度-vs-組裝自由度">選型的真正軸線：整合度 vs 組裝自由度&lt;/h2>
&lt;p>桌面環境的選擇，核心不是「輕或重」，是&lt;strong>別人幫你整合好多少、你保留多少自己組裝的自由&lt;/strong>。這條軸線的一端是 GNOME 這種高整合方案：面板、設定、通知、檔案管理全部設計成一致的整體，你開機就有一台能用的機器，代價是想改動它預設的行為要對抗它的設計哲學。另一端是 Hyprland 這種 compositor：它只負責畫面與視窗，面板、啟動器、鎖屏、通知你全部自己挑自己接，代價是要花時間組裝、每個元件都要自己維護。&lt;/p>
&lt;p>「輕/重」只是這條軸線的副產品。高整合方案因為要保證所有元件協同，通常帶較多常駐服務、吃較多記憶體；自己組裝的方案可以只裝你要的，所以輕——但如果你把面板、啟動器、通知、鎖屏一個個補齊，最後的資源佔用未必比一個現成 DE 省多少。所以判選型別問「哪個輕」，要問「我想花多少時間在組裝與維護、換到多少客製自由」。&lt;/p>
&lt;h2 id="五個主流選項的定位">五個主流選項的定位&lt;/h2>
&lt;p>下表是常見選項在「整合度」這條軸線上的位置與代價。每個選項底下有延伸說明，因為同樣一句「適合客製」在不同方案裡的實際體驗差很多：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>方案&lt;/th>
 &lt;th>定位&lt;/th>
 &lt;th>整合度&lt;/th>
 &lt;th>資源&lt;/th>
 &lt;th>客製自由&lt;/th>
 &lt;th>預設顯示協定&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>GNOME&lt;/td>
 &lt;td>高整合、意見鮮明的現代桌面&lt;/td>
 &lt;td>高&lt;/td>
 &lt;td>較高&lt;/td>
 &lt;td>低（要對抗設計）&lt;/td>
 &lt;td>Wayland&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>KDE Plasma&lt;/td>
 &lt;td>高整合但高度可調&lt;/td>
 &lt;td>高&lt;/td>
 &lt;td>中&lt;/td>
 &lt;td>高（內建設定深）&lt;/td>
 &lt;td>Wayland&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>XFCE&lt;/td>
 &lt;td>輕量傳統桌面&lt;/td>
 &lt;td>中&lt;/td>
 &lt;td>低&lt;/td>
 &lt;td>中&lt;/td>
 &lt;td>X11&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Cinnamon&lt;/td>
 &lt;td>傳統桌面隱喻、易上手&lt;/td>
 &lt;td>中高&lt;/td>
 &lt;td>中&lt;/td>
 &lt;td>中&lt;/td>
 &lt;td>X11&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Hyprland（WM）&lt;/td>
 &lt;td>自己組裝的平鋪式 compositor&lt;/td>
 &lt;td>無（自組）&lt;/td>
 &lt;td>最低（裸）&lt;/td>
 &lt;td>最高&lt;/td>
 &lt;td>Wayland&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="gnome把選擇替你做完的現代桌面">GNOME：把選擇替你做完的現代桌面&lt;/h3>
&lt;p>GNOME 的定位是「一套有明確設計主張的完整桌面」——它預設一個不同於 Windows/macOS 的工作流（頂欄 + Activities 總覽 + 動態工作區），並且刻意收斂可調選項，讓多數人不用設定就有一致體驗。從 Windows/macOS 轉來、想要「裝好就能用、不想折騰」的人，GNOME 是穩妥選擇：它的整合度最高，通知、設定、線上帳號、檔案管理彼此協調。&lt;/p>
&lt;p>代價在客製。GNOME 把很多設定收進 extension 或需要另裝 &lt;code>gnome-tweaks&lt;/code>（Arch：&lt;code>pacman -S gnome-tweaks&lt;/code>）才改得動的角落，想把它調成傳統工作列風格是在對抗它的設計方向，而 extension 又會隨 GNOME 大版本更新而失效。所以 GNOME 適合「接受它的工作流」的人，不適合「想按自己習慣重排一切」的人。資源上它是這幾個裡偏吃的，老硬體上會感覺得到。&lt;/p>
&lt;h3 id="kde-plasma整合度高但幾乎每個角落都能調">KDE Plasma：整合度高、但幾乎每個角落都能調&lt;/h3>
&lt;p>KDE Plasma 少見地同時做到高整合與高可調：它像 GNOME 一樣開箱即用、元件協調，但幾乎每個行為都攤在設定介面裡讓你改——面板可以拆解重組、視窗規則、快捷鍵、視覺效果都有深度選項。從 Windows 轉來的人會覺得它的預設隱喻（底部工作列 + 開始選單）親切，又保留了往下鑽的空間。&lt;/p>
&lt;p>它的代價不在資源（現代 Plasma 已相當精實，中階機器順暢），在「選項多到需要自己收斂」——設定深意味著你可能花很多時間在調整上。想要「高整合又想保留大量客製、但不想從零組裝」的人，Plasma 通常是比 GNOME 和 Hyprland 都平衡的落點。它的 Wayland session 近年已是預設且成熟。&lt;/p>
&lt;h3 id="xfce老硬體與要傳統要穩要輕的預設">XFCE：老硬體與「要傳統、要穩、要輕」的預設&lt;/h3>
&lt;p>XFCE 的定位是輕量而傳統：它給你熟悉的桌面隱喻（工作列、選單、系統匣），資源佔用在這幾個裡最低，且以穩定少變著稱——它不追新，多年來介面與行為變動小。老硬體、低階 VM、或「我只要一個不吵不鬧、能穩定工作的桌面」的場景，XFCE 是可靠預設。&lt;/p>
&lt;p>它的取捨是現代感與顯示協定：XFCE 目前仍以 X11 為主，Wayland 化在進行但尚未是預設，所以想要 Wayland 的分數效益（見下節）目前要往別的方案找。客製自由度中等——比 GNOME 開放、但沒有 KDE 那種深度設定，也沒有 Hyprland 那種完全重組的自由。&lt;/p>
&lt;h3 id="cinnamon給要-windows-式熟悉感的轉移者">Cinnamon：給「要 Windows 式熟悉感」的轉移者&lt;/h3>
&lt;p>Cinnamon 出身 Linux Mint，定位是把傳統桌面隱喻做得順手好上手——底部工作列、開始選單式的應用選單、系統匣，對從 Windows 轉來的人幾乎零學習曲線。它比 XFCE 現代一點、視覺完整度高一些，整合度也高（自帶檔案管理員 Nemo、設定中心、特效）。&lt;/p>
&lt;p>代價與 XFCE 類似：以 X11 為主，資源比 XFCE 略高。它適合「要一台立刻上手、像 Windows 但是 Linux」的工作機，不適合追求 Wayland 或極致輕量的場景。附帶一提，Cinnamon 的檔案管理員 Nemo 假設 Cinnamon 桌面服務在旁邊，把它單獨裝進裸 window manager 會拖進整套 Cinnamon 元件——這正是&lt;a href="../gui-file-manager-dependencies/">加圖形檔案管理員那篇&lt;/a>講的桌面環境耦合。&lt;/p>
&lt;h3 id="hyprland不是-de是你自己組一個桌面">Hyprland：不是 DE，是你自己組一個桌面&lt;/h3>
&lt;p>Hyprland 嚴格說不是桌面環境，是一個平鋪式（tiling）Wayland compositor——它只負責畫面合成與視窗排列，面板、啟動器、鎖屏、通知、桌布、音量控制全部不含，要你自己挑元件接上去。選它意味著你接受「從零組裝一個桌面」這件事，換來的是最高的客製自由（每個元件都你選、佈局規則完全你定）和最低的裸資源佔用。&lt;/p>
&lt;p>它適合「把配置桌面當成一種投入、想要一套完全長成自己樣子的環境」的人，不適合「只想裝好開始工作」的人。組裝過程本身有相當的學習曲線與維護成本——這也是為什麼本系列用一整個 &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/06-rice-design/" data-link-title="模組六：桌面 Rice 設計" data-link-desc="Hyprland 桌面從能用到好看好用 — 狀態列、啟動器、通知、鎖屏、配色系統的設計與配置">Rice 設計模組&lt;/a>談「選了 Hyprland 之後怎麼把它組起來」。如果你還在「要不要走這條路」的階段，這篇就是那個模組的上游：先確認你要的是組裝自由、而不是開箱即用。&lt;/p>
&lt;h2 id="wayland-vs-x11選型時避不開的底層判斷">Wayland vs X11：選型時避不開的底層判斷&lt;/h2>
&lt;p>顯示協定是選型時的一條隱形軸線，因為它決定了一部分未來相容性。Wayland 是較新的顯示協定，設計上更安全、對高 DPI 與多螢幕不同刷新率支援更好，是 Linux 桌面的方向；X11 是沿用數十年的舊協定，相容性最廣但架構老舊、社群維護逐漸收斂到維持模式。GNOME、KDE Plasma、Hyprland 都已預設或原生 Wayland；XFCE、Cinnamon 目前仍以 X11 為主。&lt;/p>
&lt;p>實務判讀：如果你用 NVIDIA 專有驅動、或依賴某些只支援 X11 的老工具（部分螢幕錄製、遠端桌面、自動化工具），X11 方案目前可能更少驚喜；如果你要高 DPI 筆電、多螢幕混合刷新率、或想跟上長期方向，優先選 Wayland 方案。這不是非此即彼的道德選擇，是看你的硬體與工具鏈落在哪邊。&lt;/p></description><content:encoded><![CDATA[<p>桌面環境（desktop environment，DE）是一整套讓你能用圖形介面操作 Linux 的元件集合——它同時提供視窗管理、面板/工作列、應用啟動器、設定中心、通知、檔案管理員、鎖屏這些功能，並保證它們彼此整合、開箱即用。這跟只負責「畫視窗、管理視窗位置」的 window manager 或 compositor 是不同層次的東西：DE 通常內含一個 window manager，再把上面那一整圈桌面服務組裝好交給你。理解這個責任邊界，是選型的起點——你在選的不是「哪個比較漂亮」，是「別人幫你整合到什麼程度、你自己要組裝多少」。</p>
<h2 id="選型的真正軸線整合度-vs-組裝自由度">選型的真正軸線：整合度 vs 組裝自由度</h2>
<p>桌面環境的選擇，核心不是「輕或重」，是<strong>別人幫你整合好多少、你保留多少自己組裝的自由</strong>。這條軸線的一端是 GNOME 這種高整合方案：面板、設定、通知、檔案管理全部設計成一致的整體，你開機就有一台能用的機器，代價是想改動它預設的行為要對抗它的設計哲學。另一端是 Hyprland 這種 compositor：它只負責畫面與視窗，面板、啟動器、鎖屏、通知你全部自己挑自己接，代價是要花時間組裝、每個元件都要自己維護。</p>
<p>「輕/重」只是這條軸線的副產品。高整合方案因為要保證所有元件協同，通常帶較多常駐服務、吃較多記憶體；自己組裝的方案可以只裝你要的，所以輕——但如果你把面板、啟動器、通知、鎖屏一個個補齊，最後的資源佔用未必比一個現成 DE 省多少。所以判選型別問「哪個輕」，要問「我想花多少時間在組裝與維護、換到多少客製自由」。</p>
<h2 id="五個主流選項的定位">五個主流選項的定位</h2>
<p>下表是常見選項在「整合度」這條軸線上的位置與代價。每個選項底下有延伸說明，因為同樣一句「適合客製」在不同方案裡的實際體驗差很多：</p>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th>定位</th>
          <th>整合度</th>
          <th>資源</th>
          <th>客製自由</th>
          <th>預設顯示協定</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GNOME</td>
          <td>高整合、意見鮮明的現代桌面</td>
          <td>高</td>
          <td>較高</td>
          <td>低（要對抗設計）</td>
          <td>Wayland</td>
      </tr>
      <tr>
          <td>KDE Plasma</td>
          <td>高整合但高度可調</td>
          <td>高</td>
          <td>中</td>
          <td>高（內建設定深）</td>
          <td>Wayland</td>
      </tr>
      <tr>
          <td>XFCE</td>
          <td>輕量傳統桌面</td>
          <td>中</td>
          <td>低</td>
          <td>中</td>
          <td>X11</td>
      </tr>
      <tr>
          <td>Cinnamon</td>
          <td>傳統桌面隱喻、易上手</td>
          <td>中高</td>
          <td>中</td>
          <td>中</td>
          <td>X11</td>
      </tr>
      <tr>
          <td>Hyprland（WM）</td>
          <td>自己組裝的平鋪式 compositor</td>
          <td>無（自組）</td>
          <td>最低（裸）</td>
          <td>最高</td>
          <td>Wayland</td>
      </tr>
  </tbody>
</table>
<h3 id="gnome把選擇替你做完的現代桌面">GNOME：把選擇替你做完的現代桌面</h3>
<p>GNOME 的定位是「一套有明確設計主張的完整桌面」——它預設一個不同於 Windows/macOS 的工作流（頂欄 + Activities 總覽 + 動態工作區），並且刻意收斂可調選項，讓多數人不用設定就有一致體驗。從 Windows/macOS 轉來、想要「裝好就能用、不想折騰」的人，GNOME 是穩妥選擇：它的整合度最高，通知、設定、線上帳號、檔案管理彼此協調。</p>
<p>代價在客製。GNOME 把很多設定收進 extension 或需要另裝 <code>gnome-tweaks</code>（Arch：<code>pacman -S gnome-tweaks</code>）才改得動的角落，想把它調成傳統工作列風格是在對抗它的設計方向，而 extension 又會隨 GNOME 大版本更新而失效。所以 GNOME 適合「接受它的工作流」的人，不適合「想按自己習慣重排一切」的人。資源上它是這幾個裡偏吃的，老硬體上會感覺得到。</p>
<h3 id="kde-plasma整合度高但幾乎每個角落都能調">KDE Plasma：整合度高、但幾乎每個角落都能調</h3>
<p>KDE Plasma 少見地同時做到高整合與高可調：它像 GNOME 一樣開箱即用、元件協調，但幾乎每個行為都攤在設定介面裡讓你改——面板可以拆解重組、視窗規則、快捷鍵、視覺效果都有深度選項。從 Windows 轉來的人會覺得它的預設隱喻（底部工作列 + 開始選單）親切，又保留了往下鑽的空間。</p>
<p>它的代價不在資源（現代 Plasma 已相當精實，中階機器順暢），在「選項多到需要自己收斂」——設定深意味著你可能花很多時間在調整上。想要「高整合又想保留大量客製、但不想從零組裝」的人，Plasma 通常是比 GNOME 和 Hyprland 都平衡的落點。它的 Wayland session 近年已是預設且成熟。</p>
<h3 id="xfce老硬體與要傳統要穩要輕的預設">XFCE：老硬體與「要傳統、要穩、要輕」的預設</h3>
<p>XFCE 的定位是輕量而傳統：它給你熟悉的桌面隱喻（工作列、選單、系統匣），資源佔用在這幾個裡最低，且以穩定少變著稱——它不追新，多年來介面與行為變動小。老硬體、低階 VM、或「我只要一個不吵不鬧、能穩定工作的桌面」的場景，XFCE 是可靠預設。</p>
<p>它的取捨是現代感與顯示協定：XFCE 目前仍以 X11 為主，Wayland 化在進行但尚未是預設，所以想要 Wayland 的分數效益（見下節）目前要往別的方案找。客製自由度中等——比 GNOME 開放、但沒有 KDE 那種深度設定，也沒有 Hyprland 那種完全重組的自由。</p>
<h3 id="cinnamon給要-windows-式熟悉感的轉移者">Cinnamon：給「要 Windows 式熟悉感」的轉移者</h3>
<p>Cinnamon 出身 Linux Mint，定位是把傳統桌面隱喻做得順手好上手——底部工作列、開始選單式的應用選單、系統匣，對從 Windows 轉來的人幾乎零學習曲線。它比 XFCE 現代一點、視覺完整度高一些，整合度也高（自帶檔案管理員 Nemo、設定中心、特效）。</p>
<p>代價與 XFCE 類似：以 X11 為主，資源比 XFCE 略高。它適合「要一台立刻上手、像 Windows 但是 Linux」的工作機，不適合追求 Wayland 或極致輕量的場景。附帶一提，Cinnamon 的檔案管理員 Nemo 假設 Cinnamon 桌面服務在旁邊，把它單獨裝進裸 window manager 會拖進整套 Cinnamon 元件——這正是<a href="../gui-file-manager-dependencies/">加圖形檔案管理員那篇</a>講的桌面環境耦合。</p>
<h3 id="hyprland不是-de是你自己組一個桌面">Hyprland：不是 DE，是你自己組一個桌面</h3>
<p>Hyprland 嚴格說不是桌面環境，是一個平鋪式（tiling）Wayland compositor——它只負責畫面合成與視窗排列，面板、啟動器、鎖屏、通知、桌布、音量控制全部不含，要你自己挑元件接上去。選它意味著你接受「從零組裝一個桌面」這件事，換來的是最高的客製自由（每個元件都你選、佈局規則完全你定）和最低的裸資源佔用。</p>
<p>它適合「把配置桌面當成一種投入、想要一套完全長成自己樣子的環境」的人，不適合「只想裝好開始工作」的人。組裝過程本身有相當的學習曲線與維護成本——這也是為什麼本系列用一整個 <a href="/blog/linux/dotfile/06-rice-design/" data-link-title="模組六：桌面 Rice 設計" data-link-desc="Hyprland 桌面從能用到好看好用 — 狀態列、啟動器、通知、鎖屏、配色系統的設計與配置">Rice 設計模組</a>談「選了 Hyprland 之後怎麼把它組起來」。如果你還在「要不要走這條路」的階段，這篇就是那個模組的上游：先確認你要的是組裝自由、而不是開箱即用。</p>
<h2 id="wayland-vs-x11選型時避不開的底層判斷">Wayland vs X11：選型時避不開的底層判斷</h2>
<p>顯示協定是選型時的一條隱形軸線，因為它決定了一部分未來相容性。Wayland 是較新的顯示協定，設計上更安全、對高 DPI 與多螢幕不同刷新率支援更好，是 Linux 桌面的方向；X11 是沿用數十年的舊協定，相容性最廣但架構老舊、社群維護逐漸收斂到維持模式。GNOME、KDE Plasma、Hyprland 都已預設或原生 Wayland；XFCE、Cinnamon 目前仍以 X11 為主。</p>
<p>實務判讀：如果你用 NVIDIA 專有驅動、或依賴某些只支援 X11 的老工具（部分螢幕錄製、遠端桌面、自動化工具），X11 方案目前可能更少驚喜；如果你要高 DPI 筆電、多螢幕混合刷新率、或想跟上長期方向，優先選 Wayland 方案。這不是非此即彼的道德選擇，是看你的硬體與工具鏈落在哪邊。</p>
<h2 id="依情境選從你的處境倒推">依情境選：從你的處境倒推</h2>
<p>選型的最後一步是把上面的定位對回你自己的處境，不是背「哪個最好」：</p>
<ul>
<li><strong>剛從 Windows/macOS 轉來、只想要能用</strong>：KDE Plasma（熟悉隱喻 + 之後可深調）或 GNOME（接受新工作流、要最省心）。要極致熟悉感就 Cinnamon。</li>
<li><strong>老硬體 / 低階 VM / 要穩定不折騰的工作機</strong>：XFCE。資源最低、變動最少。</li>
<li><strong>想把桌面調成完全自己的樣子、願意投入組裝</strong>：Hyprland（或其他 WM）。先讀 <a href="/blog/linux/dotfile/06-rice-design/" data-link-title="模組六：桌面 Rice 設計" data-link-desc="Hyprland 桌面從能用到好看好用 — 狀態列、啟動器、通知、鎖屏、配色系統的設計與配置">Rice 設計模組</a> 確認你要的是這條路。</li>
<li><strong>要高整合又要大量客製、不想從零組裝</strong>：KDE Plasma，是這兩個需求的平衡點。</li>
<li><strong>硬體是 NVIDIA 或依賴 X11 工具</strong>：優先 X11 成熟的方案（XFCE / Cinnamon），或確認你的 Wayland 方案在該硬體上的狀況再決定。</li>
</ul>
<p>判準是把「我願意花多少時間在桌面本身、我對客製的需求有多強、我的硬體與工具落在 Wayland 還是 X11」三個問題答清楚，選項自然收斂。沒有一個 DE 對所有人最好——選錯最常見的原因是拿別人的推薦套自己不同的處境。</p>
<h2 id="桌面環境的擴充生態">桌面環境的擴充生態</h2>
<p>選好 DE 之後，各方案還有自己的擴充路徑，這是「選項之下還有選項」的一層：</p>
<ul>
<li><strong>GNOME</strong>：透過 GNOME Extensions 加面板、工作流、狀態列元件，但要注意 extension 綁 GNOME 版本、大版本更新可能失效。</li>
<li><strong>KDE Plasma</strong>：內建的 widget（plasmoid）、全域主題、視窗規則系統，多數擴充不需要離開設定介面。</li>
<li><strong>XFCE / Cinnamon</strong>：panel plugin、applet、主題，擴充幅度中等但穩定。</li>
<li><strong>Hyprland</strong>：因為本來就是自己組，擴充等於換元件——換 bar（waybar/其他）、換啟動器、換通知 daemon，自由度最高也最需要自己維護。這一整套怎麼組，是 <a href="/blog/linux/dotfile/06-rice-design/" data-link-title="模組六：桌面 Rice 設計" data-link-desc="Hyprland 桌面從能用到好看好用 — 狀態列、啟動器、通知、鎖屏、配色系統的設計與配置">Rice 設計模組</a> 的主題。</li>
</ul>
<h2 id="下一步">下一步</h2>
<ul>
<li>選了 Hyprland、要開始組裝：<a href="/blog/linux/dotfile/06-rice-design/" data-link-title="模組六：桌面 Rice 設計" data-link-desc="Hyprland 桌面從能用到好看好用 — 狀態列、啟動器、通知、鎖屏、配色系統的設計與配置">Dotfile 管理：桌面 Rice 設計</a> 是「選了之後怎麼把它長成自己的樣子」的完整模組。</li>
<li>桌面選好、要裝檔案管理員這類 GUI app 時的相依判讀：<a href="../gui-file-manager-dependencies/">在 Hyprland 加圖形檔案管理員</a>。</li>
<li>純終端機環境不需要桌面環境、但需要對應的 CLI 工具：<a href="../../cli/">CLI 環境工具</a>。</li>
<li>桌面裝好後遇到顯示、鎖屏、服務層的問題怎麼診斷：<a href="../../../debug/">除錯與診斷</a>。</li>
</ul>
]]></content:encoded></item><item><title>Hyprland 核心配置</title><link>https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/hyprland-core-config/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/hyprland-core-config/</guid><description>&lt;p>Hyprland v0.55+ 使用 Lua 作為配置語言。Lua 語法基礎見 &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/lua-scripting-language/" data-link-title="Lua 腳本語言" data-link-desc="在 Hyprland 或 Neovim 配置檔遇到 Lua 語法看不懂時回來讀 — 配置檔需要的最小 Lua 知識">Lua 腳本語言&lt;/a>。&lt;/p>
&lt;h2 id="配置檔位置與格式">配置檔位置與格式&lt;/h2>
&lt;p>Hyprland v0.55 起，配置格式從 hyprlang（&lt;code>.conf&lt;/code>）遷移到 &lt;strong>Lua&lt;/strong>（&lt;code>.lua&lt;/code>）。主配置檔是 &lt;code>~/.config/hypr/hyprland.lua&lt;/code>。如果 &lt;code>.lua&lt;/code> 不存在但 &lt;code>.conf&lt;/code> 存在，Hyprland 會回退讀取舊格式，但 hyprlang 已標記為棄用，後續版本會移除支援。&lt;/p>
&lt;p>修改後即時生效（不需要重新登入或重啟）。第一次啟動時如果沒有配置檔，Hyprland 會自動產生範例配置。即使配置有語法錯誤，緊急快捷鍵（SUPER+Q 開 terminal、SUPER+M 離開）仍然可用。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>[VM 可測試]&lt;/strong> 配置檔格式和載入行為在 VM 裡跟實機完全相同。&lt;/p>&lt;/blockquote>
&lt;h3 id="模組化拆分">模組化拆分&lt;/h3>
&lt;p>用 Lua 原生的 &lt;code>require()&lt;/code> 拆分配置：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1">-- ~/.config/hypr/hyprland.lua — 主入口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;monitors&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">-- 載入 monitors.lua&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;keybinds&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">-- 載入 keybinds.lua&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">-- 載入 rules.lua&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;autostart&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">-- 載入 autostart.lua&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;appearance&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">-- 載入 appearance.lua&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">&lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;env&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">-- 載入 env.lua&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>require(&amp;quot;monitors&amp;quot;)&lt;/code> 會從同目錄載入 &lt;code>monitors.lua&lt;/code>。拆分的理由是職責分離——改 keybind 不用在千行配置裡找位置，每個子檔案可以獨立 diff 和 rollback。&lt;/p>
&lt;h3 id="從舊格式遷移">從舊格式遷移&lt;/h3>
&lt;p>Hyprland 官方提供遷移工具：&lt;code>hyprlang2lua&lt;/code>（Go，也有瀏覽器版）和 &lt;code>hypr-migrate&lt;/code>。如果你是從零開始，直接用 Lua 格式。&lt;/p>
&lt;h2 id="monitor-設定">Monitor 設定&lt;/h2>
&lt;p>Monitor 設定是硬體相關的核心配置，每台機器都不同。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">-- ~/.config/hypr/monitors.lua&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="n">hl.config&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl"> &lt;span class="n">monitor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 語法：&amp;#34;name, resolution@refreshrate, position, scale&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;DP-1, 2560x1440@144, 0x0, 1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;HDMI-A-1, 1920x1080@60, 2560x0, 1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 筆電內建螢幕&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;eDP-1, preferred, auto, 1.5&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 預設規則（未明確列出的螢幕）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;, preferred, auto, 1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 鏡像模式（DP-2 鏡像 DP-1 的畫面）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- &amp;#34;DP-2, preferred, auto, 1, mirror, DP-1&amp;#34;,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="p">})&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>position&lt;/code> 決定多螢幕的空間排列——&lt;code>0x0&lt;/code> 是左上角原點，&lt;code>2560x0&lt;/code> 表示在第一個螢幕的右邊。&lt;code>scale&lt;/code> 處理 HiDPI 顯示（1.5 表示 150% 縮放）。&lt;/p>
&lt;p>查詢可用的 monitor 名稱：&lt;code>hyprctl monitors&lt;/code>&lt;/p>
&lt;p>其他選項：&lt;/p>
&lt;ul>
&lt;li>&lt;code>transform, 1&lt;/code> — 旋轉（0=正常、1=90 度、2=180 度、3=270 度）&lt;/li>
&lt;li>&lt;code>vrr, 1&lt;/code> — 可變更新率（1=開啟、2=僅全螢幕）&lt;/li>
&lt;li>&lt;code>bitdepth, 10&lt;/code> — 10-bit 色彩&lt;/li>
&lt;/ul>
&lt;h3 id="筆電合蓋行為">筆電合蓋行為&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1">-- 合蓋時關閉內建螢幕、開蓋時恢復&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c1">-- bindl = 即使輸入鎖定也能觸發（合蓋時需要）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="n">hl.bindl&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;switch:on:Lid Switch&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;exec&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;hyprctl keyword monitor &amp;#39;eDP-1, disable&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="n">hl.bindl&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;switch:off:Lid Switch&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;exec&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;hyprctl keyword monitor &amp;#39;eDP-1, preferred, auto, 1&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;strong>[需實機測試]&lt;/strong> Monitor 位置排列、HiDPI 縮放、VRR、旋轉、多螢幕熱插拔、合蓋行為。VM 通常只有一個虛擬螢幕。&lt;/p></description><content:encoded><![CDATA[<p>Hyprland v0.55+ 使用 Lua 作為配置語言。Lua 語法基礎見 <a href="/blog/linux/dotfile/knowledge-cards/lua-scripting-language/" data-link-title="Lua 腳本語言" data-link-desc="在 Hyprland 或 Neovim 配置檔遇到 Lua 語法看不懂時回來讀 — 配置檔需要的最小 Lua 知識">Lua 腳本語言</a>。</p>
<h2 id="配置檔位置與格式">配置檔位置與格式</h2>
<p>Hyprland v0.55 起，配置格式從 hyprlang（<code>.conf</code>）遷移到 <strong>Lua</strong>（<code>.lua</code>）。主配置檔是 <code>~/.config/hypr/hyprland.lua</code>。如果 <code>.lua</code> 不存在但 <code>.conf</code> 存在，Hyprland 會回退讀取舊格式，但 hyprlang 已標記為棄用，後續版本會移除支援。</p>
<p>修改後即時生效（不需要重新登入或重啟）。第一次啟動時如果沒有配置檔，Hyprland 會自動產生範例配置。即使配置有語法錯誤，緊急快捷鍵（SUPER+Q 開 terminal、SUPER+M 離開）仍然可用。</p>
<blockquote>
<p><strong>[VM 可測試]</strong> 配置檔格式和載入行為在 VM 裡跟實機完全相同。</p></blockquote>
<h3 id="模組化拆分">模組化拆分</h3>
<p>用 Lua 原生的 <code>require()</code> 拆分配置：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">-- ~/.config/hypr/hyprland.lua — 主入口</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">require</span><span class="p">(</span><span class="s2">&#34;monitors&#34;</span><span class="p">)</span>      <span class="c1">-- 載入 monitors.lua</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">require</span><span class="p">(</span><span class="s2">&#34;keybinds&#34;</span><span class="p">)</span>      <span class="c1">-- 載入 keybinds.lua</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">require</span><span class="p">(</span><span class="s2">&#34;rules&#34;</span><span class="p">)</span>         <span class="c1">-- 載入 rules.lua</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">require</span><span class="p">(</span><span class="s2">&#34;autostart&#34;</span><span class="p">)</span>     <span class="c1">-- 載入 autostart.lua</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="n">require</span><span class="p">(</span><span class="s2">&#34;appearance&#34;</span><span class="p">)</span>    <span class="c1">-- 載入 appearance.lua</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">require</span><span class="p">(</span><span class="s2">&#34;env&#34;</span><span class="p">)</span>           <span class="c1">-- 載入 env.lua</span></span></span></code></pre></div><p><code>require(&quot;monitors&quot;)</code> 會從同目錄載入 <code>monitors.lua</code>。拆分的理由是職責分離——改 keybind 不用在千行配置裡找位置，每個子檔案可以獨立 diff 和 rollback。</p>
<h3 id="從舊格式遷移">從舊格式遷移</h3>
<p>Hyprland 官方提供遷移工具：<code>hyprlang2lua</code>（Go，也有瀏覽器版）和 <code>hypr-migrate</code>。如果你是從零開始，直接用 Lua 格式。</p>
<h2 id="monitor-設定">Monitor 設定</h2>
<p>Monitor 設定是硬體相關的核心配置，每台機器都不同。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- ~/.config/hypr/monitors.lua</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="n">monitor</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="c1">-- 語法：&#34;name, resolution@refreshrate, position, scale&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;DP-1, 2560x1440@144, 0x0, 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;HDMI-A-1, 1920x1080@60, 2560x0, 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="c1">-- 筆電內建螢幕</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="s2">&#34;eDP-1, preferred, auto, 1.5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="c1">-- 預設規則（未明確列出的螢幕）</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="s2">&#34;, preferred, auto, 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="c1">-- 鏡像模式（DP-2 鏡像 DP-1 的畫面）</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="c1">-- &#34;DP-2, preferred, auto, 1, mirror, DP-1&#34;,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><p><code>position</code> 決定多螢幕的空間排列——<code>0x0</code> 是左上角原點，<code>2560x0</code> 表示在第一個螢幕的右邊。<code>scale</code> 處理 HiDPI 顯示（1.5 表示 150% 縮放）。</p>
<p>查詢可用的 monitor 名稱：<code>hyprctl monitors</code></p>
<p>其他選項：</p>
<ul>
<li><code>transform, 1</code> — 旋轉（0=正常、1=90 度、2=180 度、3=270 度）</li>
<li><code>vrr, 1</code> — 可變更新率（1=開啟、2=僅全螢幕）</li>
<li><code>bitdepth, 10</code> — 10-bit 色彩</li>
</ul>
<h3 id="筆電合蓋行為">筆電合蓋行為</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">-- 合蓋時關閉內建螢幕、開蓋時恢復</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1">-- bindl = 即使輸入鎖定也能觸發（合蓋時需要）</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">hl.bindl</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;switch:on:Lid Switch&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;hyprctl keyword monitor &#39;eDP-1, disable&#39;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">hl.bindl</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;switch:off:Lid Switch&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;hyprctl keyword monitor &#39;eDP-1, preferred, auto, 1&#39;&#34;</span><span class="p">)</span></span></span></code></pre></div><blockquote>
<p><strong>[需實機測試]</strong> Monitor 位置排列、HiDPI 縮放、VRR、旋轉、多螢幕熱插拔、合蓋行為。VM 通常只有一個虛擬螢幕。</p></blockquote>
<h3 id="dotfile-管理策略">Dotfile 管理策略</h3>
<p>Monitor 設定是典型的「機器專屬」配置。如果用 chezmoi，可以用 template 依機器名稱切換；如果用 stow，可以把 <code>monitors.lua</code> 排除在 Git 外、每台機器手動寫。</p>
<h2 id="輸入裝置配置">輸入裝置配置</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- ~/.config/hypr/hyprland.lua 或拆到獨立檔案</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="n">input</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="n">kb_layout</span> <span class="o">=</span> <span class="s2">&#34;us&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="c1">-- 多語系：kb_layout = &#34;us,de&#34;,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="c1">-- 切換：kb_options = &#34;grp:alt_shift_toggle&#34;,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="c1">-- Caps Lock 當 Escape：kb_options = &#34;caps:escape&#34;,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="n">kb_options</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="n">follow_mouse</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>         <span class="c1">-- 焦點跟隨滑鼠</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="n">sensitivity</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>          <span class="c1">-- -1.0 到 1.0（0 = 不修改）</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="n">accel_profile</span> <span class="o">=</span> <span class="s2">&#34;flat&#34;</span><span class="p">,</span>   <span class="c1">-- flat 或 adaptive</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="n">repeat_rate</span> <span class="o">=</span> <span class="mi">25</span><span class="p">,</span>         <span class="c1">-- 長按時每秒重複幾次</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="n">repeat_delay</span> <span class="o">=</span> <span class="mi">600</span><span class="p">,</span>       <span class="c1">-- 按住多久開始重複（毫秒）</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="n">touchpad</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">            <span class="n">natural_scroll</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">            <span class="n">disable_while_typing</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">            <span class="p">[</span><span class="s2">&#34;tap-to-click&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">            <span class="n">drag_lock</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">            <span class="n">scroll_factor</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><p>可用的 XKB options 查詢：<code>/usr/share/X11/xkb/rules/evdev.lst</code> 或 <code>localectl list-x11-keymap-options</code>。</p>
<blockquote>
<p><strong>[VM 可測試]</strong> 鍵盤 layout、repeat rate。<br>
<strong>[需實機測試]</strong> 觸控板設定、手勢、滑鼠靈敏度/加速曲線、多鍵盤配置。</p></blockquote>
<h2 id="keybind-設計">Keybind 設計</h2>
<h3 id="修飾鍵modifiersuper-是哪顆鍵">修飾鍵（Modifier）：<code>SUPER</code> 是哪顆鍵</h3>
<p>keybind 由「修飾鍵 + 按鍵」組成，Hyprland 配置裡最常當主修飾鍵的是 <code>SUPER</code>。<code>SUPER</code> 是 X11/Wayland 對 <strong>Meta 鍵</strong>的稱呼，在不同鍵盤上是不同的實體鍵：</p>
<ul>
<li><strong>PC 鍵盤</strong>：<strong>Windows 鍵</strong>（⊞，通常在 Ctrl 與 Alt 之間）。</li>
<li><strong>Mac 鍵盤</strong>：<strong>Command 鍵（⌘）</strong>。</li>
</ul>
<p>其他常見修飾鍵：<code>SHIFT</code>、<code>CTRL</code>（Control）、<code>ALT</code>（Mac 上是 Option ⌥）。組合寫法用空格串，例如 <code>&quot;SUPER SHIFT&quot;</code>。選 <code>SUPER</code> 當主修飾鍵是慣例——它幾乎不跟應用程式本身的快捷鍵衝突（應用多用 Ctrl / Alt）。</p>
<p>在 Mac 上跑虛擬機時，實體 ⌘ 會對應到 guest 的 <code>SUPER</code>，但 macOS 會先攔截部分 ⌘ 組合——這層 VM 專屬的坑見 <a href="../hyprland-vm-setup/">VM 環境設定</a>。</p>
<h3 id="bind-類型">Bind 類型</h3>
<p>Hyprland 提供多種 bind 函式，處理不同互動模式：</p>
<table>
  <thead>
      <tr>
          <th>函式</th>
          <th>行為</th>
          <th>適用場景</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>hl.bind()</code></td>
          <td>按一次觸發</td>
          <td>多數快捷鍵</td>
      </tr>
      <tr>
          <td><code>hl.binde()</code></td>
          <td>長按連續觸發</td>
          <td>調整視窗大小、音量</td>
      </tr>
      <tr>
          <td><code>hl.bindm()</code></td>
          <td>滑鼠綁定</td>
          <td>拖曳移動 / 調整視窗</td>
      </tr>
      <tr>
          <td><code>hl.bindr()</code></td>
          <td>放開時觸發</td>
          <td>切換模式</td>
      </tr>
      <tr>
          <td><code>hl.bindl()</code></td>
          <td>輸入鎖定也觸發</td>
          <td>合蓋開關、鎖屏時的媒體鍵</td>
      </tr>
      <tr>
          <td><code>hl.bindel()</code></td>
          <td>連續 + 鎖定</td>
          <td>鎖屏時的音量鍵（長按連續、鎖定可用）</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p><strong>[VM 可測試]</strong> 所有 keybind 邏輯和配置語法。</p></blockquote>
<h3 id="基本操作">基本操作</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- ~/.config/hypr/keybinds.lua</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1">-- 基本操作</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;Return&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;kitty&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;Q&#34;</span><span class="p">,</span> <span class="s2">&#34;killactive&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;D&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;wofi --show drun&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;F&#34;</span><span class="p">,</span> <span class="s2">&#34;fullscreen&#34;</span><span class="p">,</span> <span class="s2">&#34;0&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER SHIFT&#34;</span><span class="p">,</span> <span class="s2">&#34;Space&#34;</span><span class="p">,</span> <span class="s2">&#34;togglefloating&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1">-- 焦點移動（vim 風格）</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;H&#34;</span><span class="p">,</span> <span class="s2">&#34;movefocus&#34;</span><span class="p">,</span> <span class="s2">&#34;l&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;J&#34;</span><span class="p">,</span> <span class="s2">&#34;movefocus&#34;</span><span class="p">,</span> <span class="s2">&#34;d&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;K&#34;</span><span class="p">,</span> <span class="s2">&#34;movefocus&#34;</span><span class="p">,</span> <span class="s2">&#34;u&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;L&#34;</span><span class="p">,</span> <span class="s2">&#34;movefocus&#34;</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1">-- 視窗移動</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER SHIFT&#34;</span><span class="p">,</span> <span class="s2">&#34;H&#34;</span><span class="p">,</span> <span class="s2">&#34;movewindow&#34;</span><span class="p">,</span> <span class="s2">&#34;l&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER SHIFT&#34;</span><span class="p">,</span> <span class="s2">&#34;J&#34;</span><span class="p">,</span> <span class="s2">&#34;movewindow&#34;</span><span class="p">,</span> <span class="s2">&#34;d&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER SHIFT&#34;</span><span class="p">,</span> <span class="s2">&#34;K&#34;</span><span class="p">,</span> <span class="s2">&#34;movewindow&#34;</span><span class="p">,</span> <span class="s2">&#34;u&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER SHIFT&#34;</span><span class="p">,</span> <span class="s2">&#34;L&#34;</span><span class="p">,</span> <span class="s2">&#34;movewindow&#34;</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="c1">-- 視窗大小調整（長按連續觸發）</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="n">hl.binde</span><span class="p">(</span><span class="s2">&#34;SUPER CTRL&#34;</span><span class="p">,</span> <span class="s2">&#34;H&#34;</span><span class="p">,</span> <span class="s2">&#34;resizeactive&#34;</span><span class="p">,</span> <span class="s2">&#34;-20 0&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="n">hl.binde</span><span class="p">(</span><span class="s2">&#34;SUPER CTRL&#34;</span><span class="p">,</span> <span class="s2">&#34;J&#34;</span><span class="p">,</span> <span class="s2">&#34;resizeactive&#34;</span><span class="p">,</span> <span class="s2">&#34;0 20&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="n">hl.binde</span><span class="p">(</span><span class="s2">&#34;SUPER CTRL&#34;</span><span class="p">,</span> <span class="s2">&#34;K&#34;</span><span class="p">,</span> <span class="s2">&#34;resizeactive&#34;</span><span class="p">,</span> <span class="s2">&#34;0 -20&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="n">hl.binde</span><span class="p">(</span><span class="s2">&#34;SUPER CTRL&#34;</span><span class="p">,</span> <span class="s2">&#34;L&#34;</span><span class="p">,</span> <span class="s2">&#34;resizeactive&#34;</span><span class="p">,</span> <span class="s2">&#34;20 0&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="c1">-- 滑鼠綁定：SUPER + 左鍵拖曳移動、右鍵拖曳調整大小</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="n">hl.bindm</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;mouse:272&#34;</span><span class="p">,</span> <span class="s2">&#34;movewindow&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="n">hl.bindm</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;mouse:273&#34;</span><span class="p">,</span> <span class="s2">&#34;resizewindow&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="c1">-- Workspace 切換</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;workspace&#34;</span><span class="p">,</span> <span class="s2">&#34;1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;workspace&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">,</span> <span class="s2">&#34;workspace&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;4&#34;</span><span class="p">,</span> <span class="s2">&#34;workspace&#34;</span><span class="p">,</span> <span class="s2">&#34;4&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;5&#34;</span><span class="p">,</span> <span class="s2">&#34;workspace&#34;</span><span class="p">,</span> <span class="s2">&#34;5&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;6&#34;</span><span class="p">,</span> <span class="s2">&#34;workspace&#34;</span><span class="p">,</span> <span class="s2">&#34;6&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;7&#34;</span><span class="p">,</span> <span class="s2">&#34;workspace&#34;</span><span class="p">,</span> <span class="s2">&#34;7&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;8&#34;</span><span class="p">,</span> <span class="s2">&#34;workspace&#34;</span><span class="p">,</span> <span class="s2">&#34;8&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;9&#34;</span><span class="p">,</span> <span class="s2">&#34;workspace&#34;</span><span class="p">,</span> <span class="s2">&#34;9&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl">
</span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="c1">-- 把視窗送到指定 workspace</span>
</span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER SHIFT&#34;</span><span class="p">,</span> <span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;movetoworkspace&#34;</span><span class="p">,</span> <span class="s2">&#34;1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER SHIFT&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span> <span class="s2">&#34;movetoworkspace&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER SHIFT&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">,</span> <span class="s2">&#34;movetoworkspace&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="c1">-- 以此類推</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl">
</span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="c1">-- 螢幕截圖</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;Print&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;grimblast copy area&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;Print&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;grimblast copy output&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl">
</span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="c1">-- 多螢幕焦點切換</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;comma&#34;</span><span class="p">,</span> <span class="s2">&#34;focusmonitor&#34;</span><span class="p">,</span> <span class="s2">&#34;l&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;period&#34;</span><span class="p">,</span> <span class="s2">&#34;focusmonitor&#34;</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER SHIFT&#34;</span><span class="p">,</span> <span class="s2">&#34;comma&#34;</span><span class="p">,</span> <span class="s2">&#34;movewindow&#34;</span><span class="p">,</span> <span class="s2">&#34;mon:l&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER SHIFT&#34;</span><span class="p">,</span> <span class="s2">&#34;period&#34;</span><span class="p">,</span> <span class="s2">&#34;movewindow&#34;</span><span class="p">,</span> <span class="s2">&#34;mon:r&#34;</span><span class="p">)</span></span></span></code></pre></div><h3 id="設計原則">設計原則</h3>
<ul>
<li><strong>SUPER</strong>（Windows/Command 鍵）當 modifier，避免跟應用程式快捷鍵衝突</li>
<li><strong>方向操作</strong>統一用 vim 的 HJKL，降低記憶負擔</li>
<li><strong>modifier 分層</strong>：SUPER 是焦點、SUPER+SHIFT 是移動、SUPER+CTRL 是調整大小</li>
<li>常用操作（開 terminal、關視窗、切 workspace）放在最順手的位置</li>
</ul>
<h3 id="submap模態快捷鍵">Submap：模態快捷鍵</h3>
<p>Submap 類似 vim 的模式切換——進入某個 submap 後，快捷鍵的意義改變，直到離開。適合需要連續操作的場景（如調整大小）：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- 按 SUPER+R 進入 resize 模式</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="s2">&#34;R&#34;</span><span class="p">,</span> <span class="s2">&#34;submap&#34;</span><span class="p">,</span> <span class="s2">&#34;resize&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1">-- 定義 resize 模式的快捷鍵</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">hl.submap</span><span class="p">(</span><span class="s2">&#34;resize&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">hl.binde</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;H&#34;</span><span class="p">,</span> <span class="s2">&#34;resizeactive&#34;</span><span class="p">,</span> <span class="s2">&#34;-20 0&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">hl.binde</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;L&#34;</span><span class="p">,</span> <span class="s2">&#34;resizeactive&#34;</span><span class="p">,</span> <span class="s2">&#34;20 0&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">hl.binde</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;K&#34;</span><span class="p">,</span> <span class="s2">&#34;resizeactive&#34;</span><span class="p">,</span> <span class="s2">&#34;0 -20&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">hl.binde</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;J&#34;</span><span class="p">,</span> <span class="s2">&#34;resizeactive&#34;</span><span class="p">,</span> <span class="s2">&#34;0 20&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;escape&#34;</span><span class="p">,</span> <span class="s2">&#34;submap&#34;</span><span class="p">,</span> <span class="s2">&#34;reset&#34;</span><span class="p">)</span>   <span class="c1">-- Escape 離開</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">hl.submap</span><span class="p">(</span><span class="s2">&#34;reset&#34;</span><span class="p">)</span></span></span></code></pre></div><p>進入 resize 模式後，直接按 HJKL（不需要 modifier）就能持續調整大小，按 Escape 回到正常模式。</p>
<h3 id="媒體鍵與硬體鍵">媒體鍵與硬體鍵</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- 音量（鎖屏時也能用、長按連續觸發）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="n">hl.bindel</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;XF86AudioRaiseVolume&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">hl.bindel</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;XF86AudioLowerVolume&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">hl.bindl</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;XF86AudioMute&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">hl.bindl</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;XF86AudioMicMute&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1">-- 亮度</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">hl.bindel</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;XF86MonBrightnessUp&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;brightnessctl s 10%+&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">hl.bindel</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;XF86MonBrightnessDown&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;brightnessctl s 10%-&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1">-- 媒體播放</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">hl.bindl</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;XF86AudioPlay&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;playerctl play-pause&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">hl.bindl</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;XF86AudioNext&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;playerctl next&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">hl.bindl</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;XF86AudioPrev&#34;</span><span class="p">,</span> <span class="s2">&#34;exec&#34;</span><span class="p">,</span> <span class="s2">&#34;playerctl previous&#34;</span><span class="p">)</span></span></span></code></pre></div><blockquote>
<p><strong>[需實機測試]</strong> 媒體鍵（XF86Audio*）、亮度鍵（XF86MonBrightness*）、合蓋開關——這些依賴實體硬體送出正確的 keycode。VM 鍵盤通常沒有這些鍵。</p></blockquote>
<h2 id="環境變數">環境變數</h2>
<p>環境變數在 <code>hl.config()</code> 的 <code>env</code> 區段設定，影響 Hyprland 自身和其下執行的應用程式：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- ~/.config/hypr/env.lua</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="n">env</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="c1">-- 游標主題</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;XCURSOR_SIZE, 24&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;XCURSOR_THEME, Bibata-Modern-Classic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="s2">&#34;HYPRCURSOR_SIZE, 24&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="s2">&#34;HYPRCURSOR_THEME, Bibata-Modern-Classic&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="c1">-- Qt 應用程式</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="s2">&#34;QT_AUTO_SCREEN_SCALE_FACTOR, 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="s2">&#34;QT_QPA_PLATFORM, wayland;xcb&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="s2">&#34;QT_QPA_PLATFORMTHEME, qt5ct&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;QT_WAYLAND_DISABLE_WINDOWDECORATION, 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="c1">-- GTK 應用程式</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="s2">&#34;GDK_BACKEND, wayland,x11,*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl">        <span class="c1">-- XDG session</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="s2">&#34;XDG_CURRENT_DESKTOP, Hyprland&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">        <span class="s2">&#34;XDG_SESSION_TYPE, wayland&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">        <span class="s2">&#34;XDG_SESSION_DESKTOP, Hyprland&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">
</span></span><span class="line"><span class="ln">25</span><span class="cl">        <span class="c1">-- Electron 應用程式（VS Code, Discord 等）</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="s2">&#34;ELECTRON_OZONE_PLATFORM_HINT, auto&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">
</span></span><span class="line"><span class="ln">28</span><span class="cl">        <span class="c1">-- Firefox</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">        <span class="s2">&#34;MOZ_ENABLE_WAYLAND, 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><h3 id="nvidia-專用環境變數">NVIDIA 專用環境變數</h3>
<p>如果使用 NVIDIA 顯卡，需要額外設定（AMD 和 Intel 不需要）：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- 只在 NVIDIA 機器上加這些</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">env</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="s2">&#34;LIBVA_DRIVER_NAME, nvidia&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="s2">&#34;GBM_BACKEND, nvidia-drm&#34;</span><span class="p">,</span>             <span class="c1">-- Firefox 若崩潰就移除這行</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;__GLX_VENDOR_LIBRARY_NAME, nvidia&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;NVD_BACKEND, direct&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">cursor</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="n">no_hardware_cursors</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>             <span class="c1">-- NVIDIA 常見的游標問題修正</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="n">allow_dumb_copy</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><blockquote>
<p><strong>[VM 不適用]</strong> NVIDIA 環境變數和驅動設定在 VM 裡無意義——VM 使用 virtio-gpu 或軟體渲染。這些設定只在實體 NVIDIA 機器上測試。</p></blockquote>
<h3 id="vm-專用環境變數">VM 專用環境變數</h3>
<p>在 VM（UTM/QEMU）裡跑 Hyprland 需要額外的回退設定：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">-- 只在 VM 裡加，實機要移除</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="n">env</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="s2">&#34;WLR_RENDERER_ALLOW_SOFTWARE, 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">        <span class="s2">&#34;LIBGL_ALWAYS_SOFTWARE, 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="s2">&#34;WLR_NO_HARDWARE_CURSORS, 1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><blockquote>
<p><strong>[已驗證]</strong> Hyprland 0.55（Aquamarine 渲染後端）+ UTM virtio-gpu-gl-pci 實測：使用 GPU 加速時不需要 <code>WLR_RENDERER</code> 或 <code>LIBGL_ALWAYS_SOFTWARE</code>，Hyprland 自動走 VirGL/Venus 硬體路徑。<code>WLR_NO_HARDWARE_CURSORS</code> 仍需要（virtio-gpu 不支援硬體 cursor）。完整 VM 設定見 <a href="/blog/linux/dotfile/05-hyprland-config/hyprland-vm-setup/" data-link-title="Hyprland VM 環境設定與測試矩陣" data-link-desc="要在 VM 裡測試 Hyprland 配置、或判斷某個設定該在 VM 還是實機驗證時回來讀">VM 環境設定與測試矩陣</a>。</p></blockquote>
]]></content:encoded></item><item><title>Linux Tiling WM 生態</title><link>https://tarrragon.github.io/blog/linux/dotfile/04-window-management/linux-tiling-wm/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/04-window-management/linux-tiling-wm/</guid><description>&lt;p>Linux 桌面的視窗管理跑在**顯示協議（display protocol）**上，目前有兩套。&lt;/p>
&lt;p>&lt;strong>X11&lt;/strong>（X Window System）是用了三十多年的傳統協議。成熟、穩定、所有工具都支援。設計上的根本問題是安全性——任何 X11 應用程式都能讀取其他視窗的內容和鍵盤輸入，這是協議層的限制，不是 bug。&lt;/p>
&lt;p>&lt;strong>Wayland&lt;/strong> 是設計來取代 X11 的新協議。每個應用程式只看得到自己的視窗、效能更好、對現代硬體的支援更完整。多數主流發行版已經把 Wayland 設為預設，但部分老舊應用程式和特殊需求（某些螢幕錄製、遠端桌面工具）的支援還在追趕中，這些情境會透過 XWayland（相容層）跑 X11 應用程式。&lt;/p>
&lt;p>新的 tiling WM 主要基於 Wayland 開發，X11 上的老牌（i3, bspwm, dwm）仍然活躍但不再是未來方向。&lt;/p>
&lt;h2 id="主流-tiling-wm">主流 Tiling WM&lt;/h2>
&lt;p>&lt;strong>i3（X11）/ sway（Wayland）&lt;/strong> 是社群最大、文件最齊全、行為最可預測的選擇。i3 跑在 X11 上，sway 是它的 Wayland 移植，配置格式幾乎相同。配置檔用自己的語法，直覺的 &lt;code>key = action&lt;/code> 對應。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl"># sway/config 片段
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">set $mod Mod4
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">bindsym $mod+h focus left
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">bindsym $mod+j focus down
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">bindsym $mod+k focus up
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">bindsym $mod+l focus right
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">bindsym $mod+Shift+h move left
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">bindsym $mod+1 workspace number 1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">bindsym $mod+2 workspace number 2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>穩定性是 i3/sway 最大的賣點——配置寫好之後很少因為更新而壞掉。適合想要可靠的平鋪工作流、不需要華麗視覺效果的人。&lt;/p>
&lt;p>&lt;strong>Hyprland（Wayland）&lt;/strong> 吸引的是在意桌面視覺品質的平鋪使用者——看 r/unixporn 的 Hyprland 截圖就知道，流暢的視窗切換動畫、圓角、視窗模糊、漸層邊框，這些傳統 tiling WM 社群視為不必要的裝飾，Hyprland 做成內建功能並且認真打磨。配置檔改完即時生效（hot reload），迭代調教的回饋循環很短。&lt;/p>
&lt;p>這份視覺投入換來的 trade-off 是穩定性。開發節奏快意味著偶爾會有 breaking changes——某次更新後配置語法改了（2026 年 4 月的 Lua 遷移就是一例）、某個選項改名或移除。把它當主力桌面，要有「更新後可能要回來調配置」的心理準備。&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/" data-link-title="模組五：Hyprland 配置" data-link-desc="要在 Linux 上設定 Hyprland 平鋪式桌面時回來讀">Hyprland 配置&lt;/a>會詳細講它的設定。&lt;/p>
&lt;p>&lt;strong>bspwm（X11）&lt;/strong> 是純粹的 BSP 樹狀分割。它只做一件事：管理視窗的樹狀結構。所有操作透過 &lt;code>bspc&lt;/code> 命令列工具驅動，快捷鍵綁定交給 sxhkd（一個獨立的快捷鍵 daemon）。UNIX 哲學——每個工具只做一件事，組合起來用。&lt;/p>
&lt;p>&lt;strong>dwm（X11）&lt;/strong> 極簡到配置要改 C 原始碼然後重新編譯。不是給「想要方便配置」的人用的，而是給「想要完全理解自己桌面每一行程式碼」的人用的。&lt;/p>
&lt;h2 id="拼裝式桌面的代價">拼裝式桌面的代價&lt;/h2>
&lt;p>Linux tiling WM 的桌面是你自己拼出來的：compositor（Hyprland/sway）負責視窗管理、狀態列（waybar）負責頂部資訊條、啟動器（rofi/wofi）負責 app 搜尋啟動、通知（mako/dunst）負責通知彈窗、鎖屏另外裝。每一塊是不同專案、不同作者。&lt;/p>
&lt;p>好處是每一塊都可以換。壞處是當某件事壞了，你要自己判斷是哪一層的問題。藍牙選單不能點？可能是狀態列的 module 設定錯、可能是 blueman 沒跑、可能是 D-Bus session 有問題。完整桌面環境（KDE/GNOME）幫你整合測試過了，拼裝式桌面沒有這層保障。&lt;/p>
&lt;h2 id="多螢幕的處理">多螢幕的處理&lt;/h2>
&lt;p>多螢幕是自動平鋪比較能展現價值的場景。每個螢幕是獨立的平鋪區域，視窗在哪個螢幕就在那個螢幕的範圍內平鋪。&lt;/p>
&lt;p>快捷鍵跨螢幕操作是標配功能：把焦點跳到另一個螢幕、把當前視窗丟到另一個螢幕（丟過去後自動融入那邊的平鋪佈局）。三螢幕時這個便利性比單螢幕更明顯——純滑鼠拖視窗跨螢幕需要的移動距離很長。&lt;/p>
&lt;p>工作區跟螢幕的綁定方式是各工具差異最大的地方。&lt;/p>
&lt;p>macOS 的 Spaces 是綁定螢幕的——每個螢幕有自己獨立的一組 Spaces。yabai 沿用這個行為，切換工作區時只影響當前螢幕。AeroSpace 用自己的虛擬工作區繞過 macOS 原生 Spaces 的限制，多螢幕操作被普遍認為更穩定、更直覺。&lt;/p>
&lt;p>Hyprland 的 workspace 可以動態指派到不同螢幕——workspace 3 現在在螢幕 A，你可以把它移到螢幕 B。這種模型彈性最大，但也需要清楚的心智模型來管理「哪個 workspace 在哪」。&lt;/p>
&lt;p>熱插拔螢幕（接上、拔掉外接螢幕）是各工具的常見痛點。拔掉螢幕時，該螢幕上的視窗要搬到剩餘螢幕重新平鋪；插上螢幕時，佈局要擴展。多數工具有對應設定（記住螢幕配置、自動還原佈局），但體驗不見得完美，偶爾需要手動整理。&lt;/p>
&lt;h2 id="dotfile-中的視窗管理配置">Dotfile 中的視窗管理配置&lt;/h2>
&lt;p>視窗管理是 dotfile 管理裡「桌面層」的核心。WM 配置檔決定了整個桌面的操作邏輯——快捷鍵怎麼綁、視窗間距多大、哪些 app 要浮動、工作區怎麼分配。&lt;/p>
&lt;p>macOS 工具的配置檔通常是一個檔案：AeroSpace 的 &lt;code>~/.aerospace.toml&lt;/code>、yabai 的 &lt;code>~/.yabairc&lt;/code> + &lt;code>~/.skhdrc&lt;/code>、Amethyst 的 &lt;code>~/.amethyst.yml&lt;/code>。把這些檔案放進 dotfile repo，換 Mac 時就能還原整套視窗管理行為。&lt;/p>
&lt;p>Linux tiling WM 的配置在 &lt;code>~/.config/&lt;/code> 下，通常是一個資料夾：Hyprland 的 &lt;code>~/.config/hypr/&lt;/code>、sway 的 &lt;code>~/.config/sway/&lt;/code>、i3 的 &lt;code>~/.config/i3/&lt;/code>。除了 WM 本身，狀態列（waybar 的 &lt;code>~/.config/waybar/&lt;/code>）、啟動器（rofi 的 &lt;code>~/.config/rofi/&lt;/code>）、通知（mako 的 &lt;code>~/.config/mako/&lt;/code>）等周邊元件的配置也各自有檔案。一套完整的 Linux 平鋪桌面，dotfile repo 裡可能會有十幾個配置目錄——這也是為什麼 Linux 桌面客製化社群那麼依賴 dotfile 管理工具（見&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/01-dotfile-management/" data-link-title="模組一：管理工具與目錄結構" data-link-desc="要把散落在家目錄的配置檔集中版控時，選 bare repo、stow 還是 chezmoi、目錄該怎麼組織">管理工具與目錄結構&lt;/a>）。&lt;/p></description><content:encoded><![CDATA[<p>Linux 桌面的視窗管理跑在**顯示協議（display protocol）**上，目前有兩套。</p>
<p><strong>X11</strong>（X Window System）是用了三十多年的傳統協議。成熟、穩定、所有工具都支援。設計上的根本問題是安全性——任何 X11 應用程式都能讀取其他視窗的內容和鍵盤輸入，這是協議層的限制，不是 bug。</p>
<p><strong>Wayland</strong> 是設計來取代 X11 的新協議。每個應用程式只看得到自己的視窗、效能更好、對現代硬體的支援更完整。多數主流發行版已經把 Wayland 設為預設，但部分老舊應用程式和特殊需求（某些螢幕錄製、遠端桌面工具）的支援還在追趕中，這些情境會透過 XWayland（相容層）跑 X11 應用程式。</p>
<p>新的 tiling WM 主要基於 Wayland 開發，X11 上的老牌（i3, bspwm, dwm）仍然活躍但不再是未來方向。</p>
<h2 id="主流-tiling-wm">主流 Tiling WM</h2>
<p><strong>i3（X11）/ sway（Wayland）</strong> 是社群最大、文件最齊全、行為最可預測的選擇。i3 跑在 X11 上，sway 是它的 Wayland 移植，配置格式幾乎相同。配置檔用自己的語法，直覺的 <code>key = action</code> 對應。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl"># sway/config 片段
</span></span><span class="line"><span class="ln">2</span><span class="cl">set $mod Mod4
</span></span><span class="line"><span class="ln">3</span><span class="cl">bindsym $mod+h focus left
</span></span><span class="line"><span class="ln">4</span><span class="cl">bindsym $mod+j focus down
</span></span><span class="line"><span class="ln">5</span><span class="cl">bindsym $mod+k focus up
</span></span><span class="line"><span class="ln">6</span><span class="cl">bindsym $mod+l focus right
</span></span><span class="line"><span class="ln">7</span><span class="cl">bindsym $mod+Shift+h move left
</span></span><span class="line"><span class="ln">8</span><span class="cl">bindsym $mod+1 workspace number 1
</span></span><span class="line"><span class="ln">9</span><span class="cl">bindsym $mod+2 workspace number 2</span></span></code></pre></div><p>穩定性是 i3/sway 最大的賣點——配置寫好之後很少因為更新而壞掉。適合想要可靠的平鋪工作流、不需要華麗視覺效果的人。</p>
<p><strong>Hyprland（Wayland）</strong> 吸引的是在意桌面視覺品質的平鋪使用者——看 r/unixporn 的 Hyprland 截圖就知道，流暢的視窗切換動畫、圓角、視窗模糊、漸層邊框，這些傳統 tiling WM 社群視為不必要的裝飾，Hyprland 做成內建功能並且認真打磨。配置檔改完即時生效（hot reload），迭代調教的回饋循環很短。</p>
<p>這份視覺投入換來的 trade-off 是穩定性。開發節奏快意味著偶爾會有 breaking changes——某次更新後配置語法改了（2026 年 4 月的 Lua 遷移就是一例）、某個選項改名或移除。把它當主力桌面，要有「更新後可能要回來調配置」的心理準備。<a href="/blog/linux/dotfile/05-hyprland-config/" data-link-title="模組五：Hyprland 配置" data-link-desc="要在 Linux 上設定 Hyprland 平鋪式桌面時回來讀">Hyprland 配置</a>會詳細講它的設定。</p>
<p><strong>bspwm（X11）</strong> 是純粹的 BSP 樹狀分割。它只做一件事：管理視窗的樹狀結構。所有操作透過 <code>bspc</code> 命令列工具驅動，快捷鍵綁定交給 sxhkd（一個獨立的快捷鍵 daemon）。UNIX 哲學——每個工具只做一件事，組合起來用。</p>
<p><strong>dwm（X11）</strong> 極簡到配置要改 C 原始碼然後重新編譯。不是給「想要方便配置」的人用的，而是給「想要完全理解自己桌面每一行程式碼」的人用的。</p>
<h2 id="拼裝式桌面的代價">拼裝式桌面的代價</h2>
<p>Linux tiling WM 的桌面是你自己拼出來的：compositor（Hyprland/sway）負責視窗管理、狀態列（waybar）負責頂部資訊條、啟動器（rofi/wofi）負責 app 搜尋啟動、通知（mako/dunst）負責通知彈窗、鎖屏另外裝。每一塊是不同專案、不同作者。</p>
<p>好處是每一塊都可以換。壞處是當某件事壞了，你要自己判斷是哪一層的問題。藍牙選單不能點？可能是狀態列的 module 設定錯、可能是 blueman 沒跑、可能是 D-Bus session 有問題。完整桌面環境（KDE/GNOME）幫你整合測試過了，拼裝式桌面沒有這層保障。</p>
<h2 id="多螢幕的處理">多螢幕的處理</h2>
<p>多螢幕是自動平鋪比較能展現價值的場景。每個螢幕是獨立的平鋪區域，視窗在哪個螢幕就在那個螢幕的範圍內平鋪。</p>
<p>快捷鍵跨螢幕操作是標配功能：把焦點跳到另一個螢幕、把當前視窗丟到另一個螢幕（丟過去後自動融入那邊的平鋪佈局）。三螢幕時這個便利性比單螢幕更明顯——純滑鼠拖視窗跨螢幕需要的移動距離很長。</p>
<p>工作區跟螢幕的綁定方式是各工具差異最大的地方。</p>
<p>macOS 的 Spaces 是綁定螢幕的——每個螢幕有自己獨立的一組 Spaces。yabai 沿用這個行為，切換工作區時只影響當前螢幕。AeroSpace 用自己的虛擬工作區繞過 macOS 原生 Spaces 的限制，多螢幕操作被普遍認為更穩定、更直覺。</p>
<p>Hyprland 的 workspace 可以動態指派到不同螢幕——workspace 3 現在在螢幕 A，你可以把它移到螢幕 B。這種模型彈性最大，但也需要清楚的心智模型來管理「哪個 workspace 在哪」。</p>
<p>熱插拔螢幕（接上、拔掉外接螢幕）是各工具的常見痛點。拔掉螢幕時，該螢幕上的視窗要搬到剩餘螢幕重新平鋪；插上螢幕時，佈局要擴展。多數工具有對應設定（記住螢幕配置、自動還原佈局），但體驗不見得完美，偶爾需要手動整理。</p>
<h2 id="dotfile-中的視窗管理配置">Dotfile 中的視窗管理配置</h2>
<p>視窗管理是 dotfile 管理裡「桌面層」的核心。WM 配置檔決定了整個桌面的操作邏輯——快捷鍵怎麼綁、視窗間距多大、哪些 app 要浮動、工作區怎麼分配。</p>
<p>macOS 工具的配置檔通常是一個檔案：AeroSpace 的 <code>~/.aerospace.toml</code>、yabai 的 <code>~/.yabairc</code> + <code>~/.skhdrc</code>、Amethyst 的 <code>~/.amethyst.yml</code>。把這些檔案放進 dotfile repo，換 Mac 時就能還原整套視窗管理行為。</p>
<p>Linux tiling WM 的配置在 <code>~/.config/</code> 下，通常是一個資料夾：Hyprland 的 <code>~/.config/hypr/</code>、sway 的 <code>~/.config/sway/</code>、i3 的 <code>~/.config/i3/</code>。除了 WM 本身，狀態列（waybar 的 <code>~/.config/waybar/</code>）、啟動器（rofi 的 <code>~/.config/rofi/</code>）、通知（mako 的 <code>~/.config/mako/</code>）等周邊元件的配置也各自有檔案。一套完整的 Linux 平鋪桌面，dotfile repo 裡可能會有十幾個配置目錄——這也是為什麼 Linux 桌面客製化社群那麼依賴 dotfile 管理工具（見<a href="/blog/linux/dotfile/01-dotfile-management/" data-link-title="模組一：管理工具與目錄結構" data-link-desc="要把散落在家目錄的配置檔集中版控時，選 bare repo、stow 還是 chezmoi、目錄該怎麼組織">管理工具與目錄結構</a>）。</p>
<p>跟螢幕硬體綁定的設定（螢幕解析度、縮放比、螢幕排列順序）通常也寫在 WM 配置裡。這部分在跨機器搬移 dotfile 時需要調整——同一份 Hyprland 配置裡的 <code>monitor</code> 設定，在筆電上是一個螢幕、在桌機上可能是三個。常見做法是把硬體相關設定拆到單獨檔案（如 <code>monitors.lua</code>），主配置用 <code>require</code> 引入，這樣跨機器時只需要替換這一個檔案。<a href="/blog/linux/dotfile/08-sync-bootstrap/" data-link-title="模組八：同步、Bootstrap 與環境重建" data-link-desc="換機器或重灌時怎麼還原工作環境 — bootstrap script 設計、套件清單管理、跨機器同步策略、secret 排除，以及 VM 快照和 dotfile 重建兩種思路的場景判讀">同步與環境重建</a>會講跨機器搬移時怎麼處理這類硬體差異。</p>
]]></content:encoded></item><item><title>Workspace、Window Rules 與外觀</title><link>https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/workspace-rules-appearance/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/workspace-rules-appearance/</guid><description>&lt;p>本篇的配置範例使用 Lua 語法（Hyprland v0.55+）。Lua 基礎見 &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/lua-scripting-language/" data-link-title="Lua 腳本語言" data-link-desc="在 Hyprland 或 Neovim 配置檔遇到 Lua 語法看不懂時回來讀 — 配置檔需要的最小 Lua 知識">Lua 腳本語言&lt;/a>。&lt;/p>
&lt;h2 id="workspace-設定">Workspace 設定&lt;/h2>
&lt;p>Workspace 是平鋪式桌面的空間管理單位。Hyprland 的 workspace 是動態的——不需要預先定義多少個，按了不存在的 workspace 編號就會自動建立。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">-- 把特定 workspace 綁定到特定螢幕&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="n">hl.config&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> &lt;span class="n">workspace&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;1, monitor:DP-1, default:true&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;2, monitor:DP-1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;3, monitor:DP-1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;7, monitor:HDMI-A-1, default:true&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;8, monitor:HDMI-A-1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;9, monitor:HDMI-A-1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="p">})&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>常見的使用模式：&lt;/p>
&lt;ul>
&lt;li>Workspace 1-3 放在主螢幕（寫程式用）&lt;/li>
&lt;li>Workspace 7-9 放在副螢幕（瀏覽器、通訊軟體、監控）&lt;/li>
&lt;li>用鍵盤瞬間切換（SUPER + 數字鍵），比 alt-tab 在一堆視窗裡找快&lt;/li>
&lt;/ul>
&lt;h3 id="per-workspace-layout-覆寫">Per-workspace layout 覆寫&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="n">hl.config&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl"> &lt;span class="n">workspace&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;1, layoutopt:orientation:left&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">-- workspace 1 用左側 master&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;2, layoutopt:orientation:top&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">-- workspace 2 用頂部 master&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="p">})&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;strong>[VM 可測試]&lt;/strong> Workspace 切換、綁定邏輯、per-workspace layout。&lt;br>
&lt;strong>[需實機測試]&lt;/strong> Workspace 綁定到特定實體螢幕的行為。&lt;/p>&lt;/blockquote>
&lt;h2 id="window-rules">Window Rules&lt;/h2>
&lt;p>Window rules 讓特定應用程式在開啟時自動套用設定——指定 workspace、強制浮動、設定大小等。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="n">hl.config&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl"> &lt;span class="n">windowrule&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 特定 app 自動送到指定 workspace&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;workspace 8, class:^(firefox)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;workspace 9, class:^(Slack)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 設定面板、對話框等維持浮動（不進平鋪）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;float, class:^(pavucontrol)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;float, class:^(nm-connection-editor)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;float, title:^(Open File)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;float, title:^(Save As)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- Picture-in-picture 浮動 + 置頂 + 固定大小&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;float, title:^(Picture-in-Picture)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;pin, title:^(Picture-in-Picture)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;size 480 270, title:^(Picture-in-Picture)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;move 100%-490 50, title:^(Picture-in-Picture)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 視窗透明度（active inactive）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;opacity 0.9, class:^(kitty)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;opacity 0.85 0.75, class:^(Code)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 防止 Electron app 自動最大化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;suppressevent maximize, class:.*&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- XWayland video bridge（螢幕分享用）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;opacity 0.0 override, class:^(xwaylandvideobridge)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;noanim, class:^(xwaylandvideobridge)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;noinitialfocus, class:^(xwaylandvideobridge)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;maxsize 1 1, class:^(xwaylandvideobridge)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;noblur, class:^(xwaylandvideobridge)$&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="p">})&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="查詢應用程式的-class-和-title">查詢應用程式的 class 和 title&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">hyprctl clients &lt;span class="c1"># 列出所有開啟的視窗（含 class、title、PID 等）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">hyprctl activewindow &lt;span class="c1"># 當前焦點視窗的資訊&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Window rules 用 regex 匹配 &lt;code>class&lt;/code> 和 &lt;code>title&lt;/code>。靜態 rules 匹配的是視窗開啟時的初始值（&lt;code>initialTitle&lt;/code> / &lt;code>initialClass&lt;/code>）。&lt;/p></description><content:encoded><![CDATA[<p>本篇的配置範例使用 Lua 語法（Hyprland v0.55+）。Lua 基礎見 <a href="/blog/linux/dotfile/knowledge-cards/lua-scripting-language/" data-link-title="Lua 腳本語言" data-link-desc="在 Hyprland 或 Neovim 配置檔遇到 Lua 語法看不懂時回來讀 — 配置檔需要的最小 Lua 知識">Lua 腳本語言</a>。</p>
<h2 id="workspace-設定">Workspace 設定</h2>
<p>Workspace 是平鋪式桌面的空間管理單位。Hyprland 的 workspace 是動態的——不需要預先定義多少個，按了不存在的 workspace 編號就會自動建立。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- 把特定 workspace 綁定到特定螢幕</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">workspace</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="s2">&#34;1, monitor:DP-1, default:true&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="s2">&#34;2, monitor:DP-1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;3, monitor:DP-1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="s2">&#34;7, monitor:HDMI-A-1, default:true&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="s2">&#34;8, monitor:HDMI-A-1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="s2">&#34;9, monitor:HDMI-A-1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><p>常見的使用模式：</p>
<ul>
<li>Workspace 1-3 放在主螢幕（寫程式用）</li>
<li>Workspace 7-9 放在副螢幕（瀏覽器、通訊軟體、監控）</li>
<li>用鍵盤瞬間切換（SUPER + 數字鍵），比 alt-tab 在一堆視窗裡找快</li>
</ul>
<h3 id="per-workspace-layout-覆寫">Per-workspace layout 覆寫</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">workspace</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="s2">&#34;1, layoutopt:orientation:left&#34;</span><span class="p">,</span>     <span class="c1">-- workspace 1 用左側 master</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="s2">&#34;2, layoutopt:orientation:top&#34;</span><span class="p">,</span>      <span class="c1">-- workspace 2 用頂部 master</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><blockquote>
<p><strong>[VM 可測試]</strong> Workspace 切換、綁定邏輯、per-workspace layout。<br>
<strong>[需實機測試]</strong> Workspace 綁定到特定實體螢幕的行為。</p></blockquote>
<h2 id="window-rules">Window Rules</h2>
<p>Window rules 讓特定應用程式在開啟時自動套用設定——指定 workspace、強制浮動、設定大小等。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">windowrule</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="c1">-- 特定 app 自動送到指定 workspace</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="s2">&#34;workspace 8, class:^(firefox)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="s2">&#34;workspace 9, class:^(Slack)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="c1">-- 設定面板、對話框等維持浮動（不進平鋪）</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="s2">&#34;float, class:^(pavucontrol)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="s2">&#34;float, class:^(nm-connection-editor)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="s2">&#34;float, title:^(Open File)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">        <span class="s2">&#34;float, title:^(Save As)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="c1">-- Picture-in-picture 浮動 + 置頂 + 固定大小</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">        <span class="s2">&#34;float, title:^(Picture-in-Picture)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">        <span class="s2">&#34;pin, title:^(Picture-in-Picture)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="s2">&#34;size 480 270, title:^(Picture-in-Picture)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="s2">&#34;move 100%-490 50, title:^(Picture-in-Picture)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="c1">-- 視窗透明度（active inactive）</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">        <span class="s2">&#34;opacity 0.9, class:^(kitty)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="s2">&#34;opacity 0.85 0.75, class:^(Code)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl">        <span class="c1">-- 防止 Electron app 自動最大化</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">        <span class="s2">&#34;suppressevent maximize, class:.*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="c1">-- XWayland video bridge（螢幕分享用）</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">        <span class="s2">&#34;opacity 0.0 override, class:^(xwaylandvideobridge)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">        <span class="s2">&#34;noanim, class:^(xwaylandvideobridge)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">        <span class="s2">&#34;noinitialfocus, class:^(xwaylandvideobridge)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="s2">&#34;maxsize 1 1, class:^(xwaylandvideobridge)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">        <span class="s2">&#34;noblur, class:^(xwaylandvideobridge)$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><h3 id="查詢應用程式的-class-和-title">查詢應用程式的 class 和 title</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">hyprctl clients          <span class="c1"># 列出所有開啟的視窗（含 class、title、PID 等）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">hyprctl activewindow     <span class="c1"># 當前焦點視窗的資訊</span></span></span></code></pre></div><p>Window rules 用 regex 匹配 <code>class</code> 和 <code>title</code>。靜態 rules 匹配的是視窗開啟時的初始值（<code>initialTitle</code> / <code>initialClass</code>）。</p>
<p>Window rules 是讓平鋪式桌面「不只是把所有東西硬塞格子」的關鍵——識別哪些 app 適合浮動、哪些適合指定位置，需要累積使用經驗。</p>
<blockquote>
<p><strong>[VM 可測試]</strong> Window rules 邏輯、workspace 指派、float 規則。查 class/title 也在 VM 裡能做。</p></blockquote>
<h2 id="layout-配置">Layout 配置</h2>
<h3 id="dwindle">Dwindle</h3>
<p>每個新視窗把當前區域一分為二（螺旋式切分），適合不固定視窗數量的工作流：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">dwindle</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="n">pseudotile</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>       <span class="c1">-- 允許 app 請求 pseudo-tiling（保留原始大小）</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="n">preserve_split</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>   <span class="c1">-- 不自動改變分割方向</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">        <span class="n">force_split</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>         <span class="c1">-- 0=跟隨滑鼠, 1=永遠左/上, 2=永遠右/下</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="n">smart_split</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="n">smart_resizing</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><h3 id="master">Master</h3>
<p>一個主區域 + 其餘視窗堆疊在側邊，適合「一個主力視窗 + 多個參考視窗」的模式：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">master</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="n">new_on_top</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span>       <span class="c1">-- 新視窗放 master 還是 stack</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="n">orientation</span> <span class="o">=</span> <span class="s2">&#34;left&#34;</span><span class="p">,</span>     <span class="c1">-- master 區域位置：left / right / top / bottom / center</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">        <span class="n">mfact</span> <span class="o">=</span> <span class="mf">0.55</span><span class="p">,</span>             <span class="c1">-- master 區域佔螢幕的比例</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><p>在 <code>general</code> 裡設定預設 layout：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">general</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="n">layout</span> <span class="o">=</span> <span class="s2">&#34;dwindle&#34;</span><span class="p">,</span>       <span class="c1">-- 或 &#34;master&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><blockquote>
<p><strong>[VM 可測試]</strong> Layout 切換和參數調整的行為邏輯。</p></blockquote>
<h2 id="外觀設定">外觀設定</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">general</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="n">gaps_in</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="n">gaps_out</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="n">border_size</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="p">[</span><span class="s2">&#34;col.active_border&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;rgba(89b4faee) rgba(cba6f7ee) 45deg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="p">[</span><span class="s2">&#34;col.inactive_border&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;rgba(313244aa)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">decoration</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="n">rounding</span> <span class="o">=</span> <span class="mi">8</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="n">blur</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">            <span class="n">enabled</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="n">size</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span>             <span class="c1">-- 模糊半徑（越高越模糊、越吃 GPU）</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="n">passes</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>           <span class="c1">-- 模糊次數（越多越平滑、越重）</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">            <span class="n">vibrancy</span> <span class="o">=</span> <span class="mf">0.17</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">            <span class="n">noise</span> <span class="o">=</span> <span class="mf">0.02</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">            <span class="n">new_optimizations</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl">        <span class="n">shadow</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">            <span class="n">enabled</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">            <span class="n">range</span> <span class="o">=</span> <span class="mi">15</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">            <span class="n">render_power</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span>     <span class="c1">-- 1-4，衰減曲線</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">            <span class="n">color</span> <span class="o">=</span> <span class="s2">&#34;0xee1a1a2e&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">
</span></span><span class="line"><span class="ln">28</span><span class="cl">        <span class="n">dim_inactive</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">        <span class="n">dim_strength</span> <span class="o">=</span> <span class="mf">0.2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">
</span></span><span class="line"><span class="ln">31</span><span class="cl">        <span class="n">active_opacity</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">        <span class="n">inactive_opacity</span> <span class="o">=</span> <span class="mf">0.95</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><blockquote>
<p><strong>[需實機測試]</strong> blur 的效能影響和視覺品質——這是 Hyprland 最吃 GPU 的功能。VM 裡建議 <code>blur = { enabled = false }</code> 避免卡頓。shadow 和 rounding 在軟體渲染下可以動但會很慢。</p></blockquote>
<h2 id="動畫設定">動畫設定</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- 定義 bezier 曲線</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="n">hl.animation</span><span class="p">(</span><span class="s2">&#34;bezier&#34;</span><span class="p">,</span> <span class="s2">&#34;ease&#34;</span><span class="p">,</span> <span class="mf">0.25</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.25</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">hl.animation</span><span class="p">(</span><span class="s2">&#34;bezier&#34;</span><span class="p">,</span> <span class="s2">&#34;overshot&#34;</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">1.05</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1">-- Spring 物理動畫（較新的替代方案）</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">hl.animation</span><span class="p">(</span><span class="s2">&#34;spring&#34;</span><span class="p">,</span> <span class="s2">&#34;bouncy&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>   <span class="c1">-- damping, frequency, speed</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1">-- 套用動畫</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">hl.animation</span><span class="p">(</span><span class="s2">&#34;animation&#34;</span><span class="p">,</span> <span class="s2">&#34;windows&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="s2">&#34;ease&#34;</span><span class="p">,</span> <span class="s2">&#34;slide&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">hl.animation</span><span class="p">(</span><span class="s2">&#34;animation&#34;</span><span class="p">,</span> <span class="s2">&#34;windowsOut&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="s2">&#34;ease&#34;</span><span class="p">,</span> <span class="s2">&#34;popin 80%&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">hl.animation</span><span class="p">(</span><span class="s2">&#34;animation&#34;</span><span class="p">,</span> <span class="s2">&#34;fade&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">&#34;ease&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">hl.animation</span><span class="p">(</span><span class="s2">&#34;animation&#34;</span><span class="p">,</span> <span class="s2">&#34;workspaces&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="s2">&#34;ease&#34;</span><span class="p">,</span> <span class="s2">&#34;slide&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1">-- 關閉特定動畫</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">hl.animation</span><span class="p">(</span><span class="s2">&#34;animation&#34;</span><span class="p">,</span> <span class="s2">&#34;windowsMove&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span></span></span></code></pre></div><p>VM 裡跑 Hyprland 時，建議完全關閉動畫以維持可用的操作速度：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">animations</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="n">enabled</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><blockquote>
<p><strong>[需實機測試]</strong> 動畫流暢度是 Hyprland 的核心賣點，只有實機能評估。VM 裡的卡頓是 GPU 加速不足造成的，不代表 Hyprland 本身的效能。</p></blockquote>
<h2 id="autostart">Autostart</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">exec_once</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="c1">-- 桌面元件</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="s2">&#34;waybar&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="s2">&#34;mako&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        <span class="s2">&#34;hyprpaper&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="c1">-- 系統服務</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="s2">&#34;/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="s2">&#34;wl-paste --type text --watch cliphist store&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="c1">-- Idle daemon（閒置鎖屏，鎖屏安全模型見 session-lock 卡）</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="s2">&#34;hypridle&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><p><code>exec_once</code> 只在 Hyprland 啟動時跑一次（config reload 不會重複執行）。如果需要每次 reload 都重跑某個指令，用 <code>exec</code>（但多數情況不需要）。</p>
<h2 id="plugin-系統">Plugin 系統</h2>
<p>Hyprland 用 <code>hyprpm</code>（Hyprland Plugin Manager）管理 plugin：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">hyprpm update                                              <span class="c1"># 更新 plugin index</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">hyprpm add https://github.com/hyprwm/hyprland-plugins     <span class="c1"># 加入官方 plugin repo</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">hyprpm <span class="nb">enable</span> hyprexpo                                     <span class="c1"># 啟用 plugin</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">hyprpm disable hyprexpo                                    <span class="c1"># 停用 plugin</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">hyprpm list                                                <span class="c1"># 列出可用 plugin</span></span></span></code></pre></div><table>
  <thead>
      <tr>
          <th>Plugin</th>
          <th>功能</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>hyprexpo</strong></td>
          <td>workspace 鳥瞰（所有 workspace 縮圖一覽）</td>
      </tr>
      <tr>
          <td><strong>hy3</strong></td>
          <td>i3/sway 風格的手動 tiling layout（替代 dwindle）</td>
      </tr>
      <tr>
          <td><strong>hyprspace</strong></td>
          <td>類似 macOS Mission Control 的 workspace 切換動畫</td>
      </tr>
      <tr>
          <td><strong>hyprbars</strong></td>
          <td>視窗標題列（可自訂按鈕）</td>
      </tr>
      <tr>
          <td><strong>hyprtrails</strong></td>
          <td>游標拖尾特效</td>
      </tr>
  </tbody>
</table>
<p>Plugin 的配置寫在 hyprland.lua 裡，是 dotfile 的一部分。</p>
<blockquote>
<p><strong>[VM 可測試]</strong> 不依賴 GPU 的 plugin（hy3、hyprbars）。<br>
<strong>[需實機測試]</strong> 視覺特效類 plugin（hyprexpo、hyprspace、hyprtrails）。</p></blockquote>
<h2 id="dotfile-結構對應">Dotfile 結構對應</h2>
<p>Hyprland 的配置拆成多個 <code>.lua</code> 檔，全部放在同一個 stow package 裡。<code>monitors.lua</code> 是硬體相關的——跨機器搬移時可能要排除或用 template/local 機制處理（見<a href="/blog/linux/dotfile/01-dotfile-management/cross-platform-one-repo/" data-link-title="跨平台共用一個 Repo" data-link-desc="macOS 跟 Linux 要共用同一個 dotfile repo、不想維護兩份時回來讀">跨平台共用一個 Repo</a>）：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">~/dotfiles/
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">└── hyprland/
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    └── .config/
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        └── hypr/
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">            ├── hyprland.lua       # 主入口（只有 require 行）
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            ├── monitors.lua       # 硬體相關、可能排除或 template
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">            ├── keybinds.lua
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            ├── rules.lua
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            ├── autostart.lua
</span></span><span class="line"><span class="ln">10</span><span class="cl">            ├── appearance.lua
</span></span><span class="line"><span class="ln">11</span><span class="cl">            └── env.lua</span></span></code></pre></div><h2 id="穩定性與維護的務實面">穩定性與維護的務實面</h2>
<p>Hyprland 的開發節奏快、功能更新激進。v0.55 的 Lua 遷移就是一個典型案例——配置格式整個換掉，舊的 <code>.conf</code> 只會再支援一到兩個版本。配置檔的語法和可用選項會隨版本變動。</p>
<p>應對策略：</p>
<ul>
<li>更新前先看 Hyprland wiki 的 Configuring 頁面和 changelog</li>
<li>dotfile repo 的 commit message 記錄「因應 Hyprland vX.Y 改了什麼設定」</li>
<li>如果用 Arch 的 rolling release，<code>pacman -Syu</code> 前先確認 Hyprland 是否有 breaking change（Arch 社群通常會在論壇預警）</li>
<li>官方提供遷移工具（如 <code>hyprlang2lua</code>），格式變更時優先使用</li>
</ul>
<p>這是<a href="/blog/linux/dotfile/04-window-management/" data-link-title="模組四：視窗管理與平鋪式工作流" data-link-desc="同時開多個視窗時的排列策略 — 手動貼齊跟自動平鋪的差距在哪、macOS 和 Linux 各有哪些工具、多螢幕怎麼處理、什麼情境值得從浮動切換到平鋪">視窗管理與平鋪式工作流</a>提過的代價——把日常桌面建立在高速移動的專案上，持續的配置維護是實際成本。</p>
<h2 id="vm-與實機測試對照">VM 與實機測試對照</h2>
<table>
  <thead>
      <tr>
          <th>項目</th>
          <th>VM 可測試</th>
          <th>需實機測試</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>配置語法 / 結構</td>
          <td>可</td>
          <td></td>
      </tr>
      <tr>
          <td>Keybind 設計</td>
          <td>可</td>
          <td></td>
      </tr>
      <tr>
          <td>Window rules 邏輯</td>
          <td>可</td>
          <td></td>
      </tr>
      <tr>
          <td>Workspace 切換</td>
          <td>可</td>
          <td></td>
      </tr>
      <tr>
          <td>Layout 參數</td>
          <td>可</td>
          <td></td>
      </tr>
      <tr>
          <td>Autostart 順序</td>
          <td>可</td>
          <td></td>
      </tr>
      <tr>
          <td>Plugin 配置</td>
          <td>部分</td>
          <td>視覺類</td>
      </tr>
      <tr>
          <td>動畫流暢度</td>
          <td></td>
          <td>必要</td>
      </tr>
      <tr>
          <td>Blur 效能 / 品質</td>
          <td></td>
          <td>必要</td>
      </tr>
      <tr>
          <td>多螢幕排列</td>
          <td></td>
          <td>必要</td>
      </tr>
      <tr>
          <td>HiDPI 縮放</td>
          <td></td>
          <td>必要</td>
      </tr>
      <tr>
          <td>觸控板 / 手勢</td>
          <td></td>
          <td>必要</td>
      </tr>
      <tr>
          <td>媒體鍵 / 亮度鍵</td>
          <td></td>
          <td>必要</td>
      </tr>
      <tr>
          <td>NVIDIA 驅動設定</td>
          <td></td>
          <td>必要</td>
      </tr>
      <tr>
          <td>螢幕分享</td>
          <td></td>
          <td>必要</td>
      </tr>
      <tr>
          <td>休眠 / 喚醒</td>
          <td></td>
          <td>必要</td>
      </tr>
      <tr>
          <td>合蓋行為</td>
          <td></td>
          <td>必要</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item><item><title>Wayland 顯示協議：為什麼 Hyprland 不跑在 X11 上</title><link>https://tarrragon.github.io/blog/linux/dotfile/04-window-management/wayland-explainer/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/04-window-management/wayland-explainer/</guid><description>&lt;p>Wayland 是 Linux 圖形系統的顯示協議，定義了應用程式怎麼跟負責畫面合成的 compositor 溝通。Hyprland、Sway 這些 tiling WM 都是 Wayland compositor——理解 Wayland 的架構，才能理解這些工具為什麼存在、能做什麼、不能做什麼。&lt;/p>
&lt;h2 id="wayland-是協議不是軟體">Wayland 是協議，不是軟體&lt;/h2>
&lt;p>一個常見的誤解是把 Wayland 當成「一個程式」。Wayland 是一份協議規格（protocol specification），描述了 client（應用程式）和 compositor（負責合成畫面的東西）之間怎麼傳遞 buffer、怎麼處理輸入事件。&lt;/p>
&lt;p>每個 Wayland compositor 同時扮演三個角色：display server（管理顯示輸出）、window manager（管理視窗排列）、compositor（合成最終畫面）。X11 的世界裡這三個角色是分開的，Wayland 把它們統一成一個程式。這個「三合一」定位的濃縮版與它在故障排除中的責任邊界，見 &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/compositor/" data-link-title="Compositor（合成器）" data-link-desc="教材反覆出現 compositor / 合成器、想確認它到底負責什麼、跟 window manager 和桌面環境差在哪時讀 — Wayland 下把畫面合成與視窗管理合一的核心程式">Compositor 術語卡&lt;/a>。&lt;/p>
&lt;p>「Hyprland 是 Wayland compositor」這個說法的意思是：它不只是一個視窗管理器，它同時是整個圖形系統的核心。&lt;/p>
&lt;h2 id="x11-vs-wayland-架構差異">X11 vs Wayland 架構差異&lt;/h2>
&lt;h3 id="x11-的三角架構1984-年設計">X11 的三角架構（1984 年設計）&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">應用程式 ──→ X Server（中央仲介）──→ Compositor ──→ 螢幕
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl"> ↑ ↑
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl"> └── 輸入事件 ──────────────┘&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>X Server 是一個龐大的中央仲介，負責接收所有應用程式的繪圖指令、管理輸入事件、再把畫面交給 compositor 做最終合成。Compositing 是後來才加上去的（Compiz、picom 這些都是外掛的 compositor），不是 X11 原始設計的一部分。&lt;/p>
&lt;h3 id="wayland-的直接模型2008-年設計">Wayland 的直接模型（2008 年設計）&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">應用程式 ──→ Compositor（= display server + window manager）──→ 螢幕
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl"> ↑
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl"> └── 輸入事件&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>應用程式用 OpenGL/Vulkan 自己渲染畫面到 buffer，然後把 buffer 直接交給 compositor。沒有中間人。compositor 收到所有 client 的 buffer 後合成最終畫面輸出到螢幕。&lt;/p>
&lt;p>這個架構上的差異帶來三個實際影響：效能、安全、screen tearing。&lt;/p>
&lt;h2 id="安全性">安全性&lt;/h2>
&lt;p>X11 的安全模型有一個根本性的設計缺陷：任何連到同一個 X Server 的 client，都能監聽其他 client 的鍵盤輸入、擷取其他視窗的畫面、甚至注入假的輸入事件。這代表一個惡意程式可以輕易做到 keylogging——記錄你在其他視窗打的所有字，包括密碼。&lt;/p>
&lt;p>Wayland 從協議層就隔離了 client 之間的存取。每個應用程式只看得到自己的 buffer，無法存取其他視窗的內容或輸入。要做 screen capture 或 screen sharing，必須透過 xdg-desktop-portal 這個受控的中介機制，使用者會看到明確的授權提示。&lt;/p>
&lt;p>對 tiling WM 的使用者來說，這個安全差異特別有意義：平鋪式桌面通常同時開大量終端機視窗（有些跑 SSH、有些在 sudo 操作），X11 下任何一個視窗裡的惡意程式都能讀到其他視窗的鍵盤輸入。Wayland 阻斷了這條攻擊路徑。&lt;/p>
&lt;h2 id="效能與-screen-tearing">效能與 Screen Tearing&lt;/h2>
&lt;p>X11 的渲染路徑有多餘的記憶體複製——應用程式把繪圖指令送給 X Server，X Server 渲染後再交給 compositor，compositor 再合成。Wayland 省掉了中間那一步：應用程式直接渲染到 buffer、直接交給 compositor，記憶體複製更少。&lt;/p>
&lt;p>Screen tearing（畫面撕裂）在 X11 上是長年的老問題——需要 compositor + vsync 的各種 workaround。Wayland 在協議層就處理了 frame presentation 的時機，compositor 控制什麼時候把合成好的畫面送到螢幕，原生消除 tearing。這也是為什麼 Hyprland 的動畫能跑得流暢——直接 rendering + 原生 vsync 的組合，在 X11 上需要大量額外配置才能接近的效果。&lt;/p>
&lt;h2 id="xwaylandx11-相容層">XWayland：X11 相容層&lt;/h2>
&lt;p>很多應用程式仍然只支援 X11 協議。XWayland 是一個 X11 server，但它本身作為一個 Wayland client 運行——X11 應用程式連到 XWayland，以為自己在跟正常的 X Server 溝通；XWayland 把 X11 協議翻譯成 Wayland 協議，把 buffer 交給 compositor。&lt;/p></description><content:encoded><![CDATA[<p>Wayland 是 Linux 圖形系統的顯示協議，定義了應用程式怎麼跟負責畫面合成的 compositor 溝通。Hyprland、Sway 這些 tiling WM 都是 Wayland compositor——理解 Wayland 的架構，才能理解這些工具為什麼存在、能做什麼、不能做什麼。</p>
<h2 id="wayland-是協議不是軟體">Wayland 是協議，不是軟體</h2>
<p>一個常見的誤解是把 Wayland 當成「一個程式」。Wayland 是一份協議規格（protocol specification），描述了 client（應用程式）和 compositor（負責合成畫面的東西）之間怎麼傳遞 buffer、怎麼處理輸入事件。</p>
<p>每個 Wayland compositor 同時扮演三個角色：display server（管理顯示輸出）、window manager（管理視窗排列）、compositor（合成最終畫面）。X11 的世界裡這三個角色是分開的，Wayland 把它們統一成一個程式。這個「三合一」定位的濃縮版與它在故障排除中的責任邊界，見 <a href="/blog/linux/dotfile/knowledge-cards/compositor/" data-link-title="Compositor（合成器）" data-link-desc="教材反覆出現 compositor / 合成器、想確認它到底負責什麼、跟 window manager 和桌面環境差在哪時讀 — Wayland 下把畫面合成與視窗管理合一的核心程式">Compositor 術語卡</a>。</p>
<p>「Hyprland 是 Wayland compositor」這個說法的意思是：它不只是一個視窗管理器，它同時是整個圖形系統的核心。</p>
<h2 id="x11-vs-wayland-架構差異">X11 vs Wayland 架構差異</h2>
<h3 id="x11-的三角架構1984-年設計">X11 的三角架構（1984 年設計）</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">應用程式 ──→ X Server（中央仲介）──→ Compositor ──→ 螢幕
</span></span><span class="line"><span class="ln">2</span><span class="cl">             ↑                         ↑
</span></span><span class="line"><span class="ln">3</span><span class="cl">             └── 輸入事件 ──────────────┘</span></span></code></pre></div><p>X Server 是一個龐大的中央仲介，負責接收所有應用程式的繪圖指令、管理輸入事件、再把畫面交給 compositor 做最終合成。Compositing 是後來才加上去的（Compiz、picom 這些都是外掛的 compositor），不是 X11 原始設計的一部分。</p>
<h3 id="wayland-的直接模型2008-年設計">Wayland 的直接模型（2008 年設計）</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">應用程式 ──→ Compositor（= display server + window manager）──→ 螢幕
</span></span><span class="line"><span class="ln">2</span><span class="cl">             ↑
</span></span><span class="line"><span class="ln">3</span><span class="cl">             └── 輸入事件</span></span></code></pre></div><p>應用程式用 OpenGL/Vulkan 自己渲染畫面到 buffer，然後把 buffer 直接交給 compositor。沒有中間人。compositor 收到所有 client 的 buffer 後合成最終畫面輸出到螢幕。</p>
<p>這個架構上的差異帶來三個實際影響：效能、安全、screen tearing。</p>
<h2 id="安全性">安全性</h2>
<p>X11 的安全模型有一個根本性的設計缺陷：任何連到同一個 X Server 的 client，都能監聽其他 client 的鍵盤輸入、擷取其他視窗的畫面、甚至注入假的輸入事件。這代表一個惡意程式可以輕易做到 keylogging——記錄你在其他視窗打的所有字，包括密碼。</p>
<p>Wayland 從協議層就隔離了 client 之間的存取。每個應用程式只看得到自己的 buffer，無法存取其他視窗的內容或輸入。要做 screen capture 或 screen sharing，必須透過 xdg-desktop-portal 這個受控的中介機制，使用者會看到明確的授權提示。</p>
<p>對 tiling WM 的使用者來說，這個安全差異特別有意義：平鋪式桌面通常同時開大量終端機視窗（有些跑 SSH、有些在 sudo 操作），X11 下任何一個視窗裡的惡意程式都能讀到其他視窗的鍵盤輸入。Wayland 阻斷了這條攻擊路徑。</p>
<h2 id="效能與-screen-tearing">效能與 Screen Tearing</h2>
<p>X11 的渲染路徑有多餘的記憶體複製——應用程式把繪圖指令送給 X Server，X Server 渲染後再交給 compositor，compositor 再合成。Wayland 省掉了中間那一步：應用程式直接渲染到 buffer、直接交給 compositor，記憶體複製更少。</p>
<p>Screen tearing（畫面撕裂）在 X11 上是長年的老問題——需要 compositor + vsync 的各種 workaround。Wayland 在協議層就處理了 frame presentation 的時機，compositor 控制什麼時候把合成好的畫面送到螢幕，原生消除 tearing。這也是為什麼 Hyprland 的動畫能跑得流暢——直接 rendering + 原生 vsync 的組合，在 X11 上需要大量額外配置才能接近的效果。</p>
<h2 id="xwaylandx11-相容層">XWayland：X11 相容層</h2>
<p>很多應用程式仍然只支援 X11 協議。XWayland 是一個 X11 server，但它本身作為一個 Wayland client 運行——X11 應用程式連到 XWayland，以為自己在跟正常的 X Server 溝通；XWayland 把 X11 協議翻譯成 Wayland 協議，把 buffer 交給 compositor。</p>
<p>多數 Wayland compositor（包括 Hyprland）預設啟用 XWayland，X11 應用程式不需要任何設定就能運行。</p>
<h3 id="需要-xwayland-的常見應用">需要 XWayland 的常見應用</h3>
<ul>
<li>舊版 Electron 應用（新版可用 <code>--ozone-platform=wayland</code> 旗標切換到 Wayland 原生）</li>
<li>Java 應用程式（NetBeans 等）</li>
<li>舊的 GTK2 應用程式</li>
<li>部分 Wine/Proton 遊戲（但 XWayland 下的遊戲效能已經相當好）</li>
<li>未啟用 PGTK 的舊版 Emacs build（Emacs 29+ 的 PGTK 後端已原生支援 Wayland）</li>
</ul>
<h3 id="xwayland-的已知問題">XWayland 的已知問題</h3>
<p>最大的實務痛點是 <strong>HiDPI 非整數縮放</strong>。在 150%、125% 等非整數 scale 下，XWayland 應用程式可能出現模糊渲染，因為 XWayland 不支援 fractional scaling 協議。整數縮放（100%、200%）則沒有問題。</p>
<h2 id="關鍵-wayland-協議">關鍵 Wayland 協議</h2>
<h3 id="wlr-layer-shell">wlr-layer-shell</h3>
<p>Layer-shell 定義了 client 可以在螢幕的哪個「層」上建立畫面——background（最底）、bottom、top、overlay（最頂）。Status bar（waybar）、notification daemon（mako）、launcher（wofi）、wallpaper（hyprpaper）、lock screen（hyprlock）都透過 layer-shell 來佔據螢幕空間。</p>
<p>沒有 layer-shell 支援的 compositor，這些桌面元件就無法運作。這也是為什麼<a href="/blog/linux/dotfile/06-rice-design/" data-link-title="模組六：桌面 Rice 設計" data-link-desc="Hyprland 桌面從能用到好看好用 — 狀態列、啟動器、通知、鎖屏、配色系統的設計與配置">桌面 Rice 設計</a>的所有工具都只能在支援 layer-shell 的 Wayland compositor 上跑——它是可組裝式桌面的基礎設施。</p>
<h3 id="xdg-desktop-portal">xdg-desktop-portal</h3>
<p>Portal 是一個 D-Bus 介面，讓被隔離的 Wayland 應用程式可以請求特權操作：screen sharing、檔案對話框、螢幕截圖。每個 compositor 提供自己的 portal backend：</p>
<ul>
<li>Hyprland：<code>xdg-desktop-portal-hyprland</code></li>
<li>GNOME：<code>xdg-desktop-portal-gnome</code></li>
<li>KDE：<code>xdg-desktop-portal-kde</code></li>
<li>Sway/wlroots 系：<code>xdg-desktop-portal-wlr</code></li>
</ul>
<p>Screen sharing 的完整鏈路是：<code>PipeWire</code> + <code>xdg-desktop-portal-hyprland</code>。OBS 的 PipeWire source、瀏覽器的畫面分享，都走這條路。</p>
<h2 id="wlroots-與-hyprland-的關係">wlroots 與 Hyprland 的關係</h2>
<p>wlroots 是一個模組化的 C library，提供 Wayland compositor 的共用基礎建設——輸入處理、輸出管理、協議實作。Sway、river、wayfire 這些 compositor 都基於 wlroots 開發，共享同一套底層程式碼。</p>
<p>Hyprland 最初也基於 wlroots，但後來 fork 出去自己維護底層。這讓 Hyprland 可以更快地加入新功能（動畫、模糊、漸層邊框），不需要等 wlroots 上游審核。代價是 Hyprland 的更新不再跟 wlroots 生態同步，偶爾會有相容性差異。</p>
<h2 id="2026-年的-wayland-採用現況">2026 年的 Wayland 採用現況</h2>
<p>Wayland 在 2026 年已經從「取代 X11 的方向」變成「Linux 桌面的預設」：</p>
<table>
  <thead>
      <tr>
          <th>桌面環境 / 發行版</th>
          <th>狀態</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GNOME</td>
          <td>GNOME 49（2025）放棄 X11 session，計劃在 GNOME 50 永久移除</td>
      </tr>
      <tr>
          <td>KDE Plasma</td>
          <td>Plasma 6.0 起預設 Wayland，6.8（2026 末）將 Wayland-only</td>
      </tr>
      <tr>
          <td>Fedora</td>
          <td>Fedora 43 完全移除 X11</td>
      </tr>
      <tr>
          <td>Ubuntu</td>
          <td>Ubuntu 25.10 不再提供 X11 session</td>
      </tr>
      <tr>
          <td>整體趨勢</td>
          <td>主流發行版的預設 session 已切換到 Wayland，X11 session 逐步移除中</td>
      </tr>
      <tr>
          <td>NVIDIA 驅動</td>
          <td>driver 555+ 支援 GBM，590 系列（2025）修復了多數 HDR 和多螢幕問題</td>
      </tr>
  </tbody>
</table>
<p>X11 上的老牌 tiling WM（i3、bspwm、dwm）仍然活躍，但不再是新專案的主流方向。新的 tiling WM 幾乎都選擇 Wayland 作為基礎。</p>
<h2 id="x11-仍有優勢的場景">X11 仍有優勢的場景</h2>
<p>Wayland 並非在所有面向都超越 X11：</p>
<ul>
<li><strong>SSH X forwarding</strong>：X11 原生支援透過網路轉送 GUI 視窗（<code>ssh -X</code>）。Wayland 沒有對等機制，替代方案是 <code>waypipe</code>，但不是 drop-in replacement</li>
<li><strong>跨 compositor 的 GUI 自動化</strong>：<code>xdotool</code>、<code>wmctrl</code> 在 X11 上可以操控任何 WM 的視窗。Wayland 沒有跨 compositor 的通用對應方案——每個 compositor 提供自己的 IPC 工具。不過 Hyprland 的 <code>hyprctl</code> 在 Hyprland 環境內提供了比 xdotool 更豐富的能力：socket-based IPC、JSON 格式查詢所有視窗和工作區狀態、即時 dispatch 動作、event 監控（<code>hyprctl socket2</code>）。瓶頸在「跨 compositor 通用」，不在單一 compositor 內的功能深度</li>
<li><strong>VNC / 遠端桌面</strong>：X11 的網路透明性讓遠端桌面相對簡單。Wayland 需要 PipeWire + portal，設定複雜度更高</li>
<li><strong>Color management</strong>：專業色彩工作流（ICC profile 管理）在部分 Wayland compositor 上仍需手動配置</li>
</ul>
<p>這些場景如果是你的核心需求，目前 X11（或 X11-based 的 i3/sway 的 X11 版本）可能仍是更務實的選擇。</p>
<h2 id="為什麼-tiling-wm-使用者該關心-wayland">為什麼 Tiling WM 使用者該關心 Wayland</h2>
<p>平鋪式桌面是「自己從元件組裝桌面」的工作流。Wayland 的幾個特性讓這件事變得更好：</p>
<p><strong>layer-shell</strong> 給了 status bar、launcher、notification daemon 一個標準化的方式來佔據螢幕空間，不再需要各種 hack 讓這些元件「浮在視窗上面又不被平鋪規則管到」。</p>
<p><strong>安全隔離</strong>在多終端機場景特別有價值——平鋪式桌面通常同時開著 SSH session、密碼管理器、sudo 操作，Wayland 確保任何一個視窗裡的程式都無法偷看其他視窗的鍵盤輸入。</p>
<p><strong>直接 rendering</strong> 讓 Hyprland 能做到流暢的視窗動畫和即時模糊，這在 X11 上需要大量額外的 compositor 配置（picom + 各種 backend 選擇 + vsync 調校）才能接近。</p>
<p>從實務角度看：2026 年開始接觸 Linux tiling WM，選 Wayland-based 的工具（Hyprland、Sway）是順流而行。X11 不會立刻消失，但新功能、新工具、社群活力都在 Wayland 這一邊。</p>
]]></content:encoded></item><item><title>模組五：Hyprland 配置</title><link>https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/</guid><description>&lt;p>Hyprland 是 Wayland 上的動態平鋪式 compositor，在 tiling WM 裡少見地重視視覺效果——流暢的視窗動畫、圓角、模糊、漸層邊框。這個模組教它的配置檔怎麼寫、核心概念是什麼、以及常見的設定場景。&lt;/p>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/04-window-management/" data-link-title="模組四：視窗管理與平鋪式工作流" data-link-desc="同時開多個視窗時的排列策略 — 手動貼齊跟自動平鋪的差距在哪、macOS 和 Linux 各有哪些工具、多螢幕怎麼處理、什麼情境值得從浮動切換到平鋪">視窗管理與平鋪式工作流&lt;/a>講了平鋪概念和選型，這裡直接進入 Hyprland 的配置實務。之後的 VM 實測專案會用這些配置做實際安裝和驗證。&lt;/p>
&lt;p>macOS 讀者如果不打算在 Linux 或 VM 上跑 Hyprland，可以跳到&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/" data-link-title="模組八：同步、Bootstrap 與環境重建" data-link-desc="換機器或重灌時怎麼還原工作環境 — bootstrap script 設計、套件清單管理、跨機器同步策略、secret 排除，以及 VM 快照和 dotfile 重建兩種思路的場景判讀">同步、Bootstrap 與環境重建&lt;/a>——bootstrap script 和 secret 管理的概念對 macOS 同樣適用。&lt;/p>
&lt;h2 id="章節文章">章節文章&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>文章&lt;/th>
 &lt;th>主題&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/hyprland-installation/" data-link-title="Hyprland 安裝與環境建置" data-link-desc="要在 Arch Linux 上從零安裝 Hyprland 桌面環境時回來讀">安裝與環境建置&lt;/a>&lt;/td>
 &lt;td>Arch Linux 套件、GPU 驅動（AMD/Intel/NVIDIA 含完整設定）、配套工具、登入管理器、首次啟動除錯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/hyprland-core-config/" data-link-title="Hyprland 核心配置" data-link-desc="Hyprland 的配置檔該怎麼組織、monitor 怎麼設定、keybind 怎麼設計、輸入裝置和環境變數怎麼配時回來讀">Hyprland 核心配置&lt;/a>&lt;/td>
 &lt;td>配置檔位置與模組化拆分、monitor 設定、keybind 設計（含完整配置範例）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/workspace-rules-appearance/" data-link-title="Workspace、Window Rules 與外觀" data-link-desc="Hyprland 的 workspace 綁定螢幕、window rules 設定浮動例外、外觀動畫調教、layout 選型、autostart 和 plugin 管理時回來讀">Workspace、Window Rules 與外觀&lt;/a>&lt;/td>
 &lt;td>workspace 設定、window rules、外觀設定、兩種平鋪分割演算法（dwindle / master）、autostart、plugin、穩定性維護&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/hyprland-vm-setup/" data-link-title="Hyprland VM 環境設定與測試矩陣" data-link-desc="要在 VM 裡測試 Hyprland 配置、或判斷某個設定該在 VM 還是實機驗證時回來讀">VM 環境設定與測試矩陣&lt;/a>&lt;/td>
 &lt;td>UTM/QEMU 設定、VM 環境變數、效能預期、VM 可測試 vs 需實機測試的完整矩陣&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="跨分類引用">跨分類引用&lt;/h2>
&lt;ul>
&lt;li>→ &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/04-window-management/" data-link-title="模組四：視窗管理與平鋪式工作流" data-link-desc="同時開多個視窗時的排列策略 — 手動貼齊跟自動平鋪的差距在哪、macOS 和 Linux 各有哪些工具、多螢幕怎麼處理、什麼情境值得從浮動切換到平鋪">模組四：視窗管理與自動平鋪&lt;/a>：平鋪式 WM 的概念和選型&lt;/li>
&lt;li>→ &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/06-rice-design/" data-link-title="模組六：桌面 Rice 設計" data-link-desc="Hyprland 桌面從能用到好看好用 — 狀態列、啟動器、通知、鎖屏、配色系統的設計與配置">模組六：桌面 Rice 設計&lt;/a>：compositor 之上的狀態列、啟動器、通知、配色系統&lt;/li>
&lt;li>→ &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/07-desktop-maintenance/" data-link-title="模組七：桌面環境維護與故障排除" data-link-desc="桌面凍結、compositor 掛了、或某個工具不回應時回來讀 — Linux 桌面的故障隔離模型、常見故障場景的恢復操作、日誌判讀與診斷工具">模組七：桌面環境維護與故障排除&lt;/a>：Hyprland crash、GPU hang、config 寫錯時的診斷和恢復&lt;/li>
&lt;li>→ &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/" data-link-title="模組八：同步、Bootstrap 與環境重建" data-link-desc="換機器或重灌時怎麼還原工作環境 — bootstrap script 設計、套件清單管理、跨機器同步策略、secret 排除，以及 VM 快照和 dotfile 重建兩種思路的場景判讀">模組八：同步、Bootstrap 與環境重建&lt;/a>：跨機器搬移時硬體相關設定怎麼處理&lt;/li>
&lt;li>→ &lt;a href="https://tarrragon.github.io/blog/linux/tools/gui/" data-link-title="圖形桌面工具" data-link-desc="有圖形環境時要挑桌面應用（檔案管理員、桌面環境與擴充）、需要判斷不同實作的相依足跡與桌面環境耦合、以及在最小化 WM 上加一個 GUI app 的取捨時回來讀">Linux 工具選單：圖形桌面工具&lt;/a>：在 Hyprland 下加圖形檔案管理員（Thunar / Nemo / PCManFM-Qt）的相依取捨&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Hyprland 是 Wayland 上的動態平鋪式 compositor，在 tiling WM 裡少見地重視視覺效果——流暢的視窗動畫、圓角、模糊、漸層邊框。這個模組教它的配置檔怎麼寫、核心概念是什麼、以及常見的設定場景。</p>
<p><a href="/blog/linux/dotfile/04-window-management/" data-link-title="模組四：視窗管理與平鋪式工作流" data-link-desc="同時開多個視窗時的排列策略 — 手動貼齊跟自動平鋪的差距在哪、macOS 和 Linux 各有哪些工具、多螢幕怎麼處理、什麼情境值得從浮動切換到平鋪">視窗管理與平鋪式工作流</a>講了平鋪概念和選型，這裡直接進入 Hyprland 的配置實務。之後的 VM 實測專案會用這些配置做實際安裝和驗證。</p>
<p>macOS 讀者如果不打算在 Linux 或 VM 上跑 Hyprland，可以跳到<a href="/blog/linux/dotfile/08-sync-bootstrap/" data-link-title="模組八：同步、Bootstrap 與環境重建" data-link-desc="換機器或重灌時怎麼還原工作環境 — bootstrap script 設計、套件清單管理、跨機器同步策略、secret 排除，以及 VM 快照和 dotfile 重建兩種思路的場景判讀">同步、Bootstrap 與環境重建</a>——bootstrap script 和 secret 管理的概念對 macOS 同樣適用。</p>
<h2 id="章節文章">章節文章</h2>
<table>
  <thead>
      <tr>
          <th>文章</th>
          <th>主題</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/linux/dotfile/05-hyprland-config/hyprland-installation/" data-link-title="Hyprland 安裝與環境建置" data-link-desc="要在 Arch Linux 上從零安裝 Hyprland 桌面環境時回來讀">安裝與環境建置</a></td>
          <td>Arch Linux 套件、GPU 驅動（AMD/Intel/NVIDIA 含完整設定）、配套工具、登入管理器、首次啟動除錯</td>
      </tr>
      <tr>
          <td><a href="/blog/linux/dotfile/05-hyprland-config/hyprland-core-config/" data-link-title="Hyprland 核心配置" data-link-desc="Hyprland 的配置檔該怎麼組織、monitor 怎麼設定、keybind 怎麼設計、輸入裝置和環境變數怎麼配時回來讀">Hyprland 核心配置</a></td>
          <td>配置檔位置與模組化拆分、monitor 設定、keybind 設計（含完整配置範例）</td>
      </tr>
      <tr>
          <td><a href="/blog/linux/dotfile/05-hyprland-config/workspace-rules-appearance/" data-link-title="Workspace、Window Rules 與外觀" data-link-desc="Hyprland 的 workspace 綁定螢幕、window rules 設定浮動例外、外觀動畫調教、layout 選型、autostart 和 plugin 管理時回來讀">Workspace、Window Rules 與外觀</a></td>
          <td>workspace 設定、window rules、外觀設定、兩種平鋪分割演算法（dwindle / master）、autostart、plugin、穩定性維護</td>
      </tr>
      <tr>
          <td><a href="/blog/linux/dotfile/05-hyprland-config/hyprland-vm-setup/" data-link-title="Hyprland VM 環境設定與測試矩陣" data-link-desc="要在 VM 裡測試 Hyprland 配置、或判斷某個設定該在 VM 還是實機驗證時回來讀">VM 環境設定與測試矩陣</a></td>
          <td>UTM/QEMU 設定、VM 環境變數、效能預期、VM 可測試 vs 需實機測試的完整矩陣</td>
      </tr>
  </tbody>
</table>
<h2 id="跨分類引用">跨分類引用</h2>
<ul>
<li>→ <a href="/blog/linux/dotfile/04-window-management/" data-link-title="模組四：視窗管理與平鋪式工作流" data-link-desc="同時開多個視窗時的排列策略 — 手動貼齊跟自動平鋪的差距在哪、macOS 和 Linux 各有哪些工具、多螢幕怎麼處理、什麼情境值得從浮動切換到平鋪">模組四：視窗管理與自動平鋪</a>：平鋪式 WM 的概念和選型</li>
<li>→ <a href="/blog/linux/dotfile/06-rice-design/" data-link-title="模組六：桌面 Rice 設計" data-link-desc="Hyprland 桌面從能用到好看好用 — 狀態列、啟動器、通知、鎖屏、配色系統的設計與配置">模組六：桌面 Rice 設計</a>：compositor 之上的狀態列、啟動器、通知、配色系統</li>
<li>→ <a href="/blog/linux/dotfile/07-desktop-maintenance/" data-link-title="模組七：桌面環境維護與故障排除" data-link-desc="桌面凍結、compositor 掛了、或某個工具不回應時回來讀 — Linux 桌面的故障隔離模型、常見故障場景的恢復操作、日誌判讀與診斷工具">模組七：桌面環境維護與故障排除</a>：Hyprland crash、GPU hang、config 寫錯時的診斷和恢復</li>
<li>→ <a href="/blog/linux/dotfile/08-sync-bootstrap/" data-link-title="模組八：同步、Bootstrap 與環境重建" data-link-desc="換機器或重灌時怎麼還原工作環境 — bootstrap script 設計、套件清單管理、跨機器同步策略、secret 排除，以及 VM 快照和 dotfile 重建兩種思路的場景判讀">模組八：同步、Bootstrap 與環境重建</a>：跨機器搬移時硬體相關設定怎麼處理</li>
<li>→ <a href="/blog/linux/tools/gui/" data-link-title="圖形桌面工具" data-link-desc="有圖形環境時要挑桌面應用（檔案管理員、桌面環境與擴充）、需要判斷不同實作的相依足跡與桌面環境耦合、以及在最小化 WM 上加一個 GUI app 的取捨時回來讀">Linux 工具選單：圖形桌面工具</a>：在 Hyprland 下加圖形檔案管理員（Thunar / Nemo / PCManFM-Qt）的相依取捨</li>
</ul>
]]></content:encoded></item><item><title>Compositor（合成器）</title><link>https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/compositor/</link><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/compositor/</guid><description>&lt;p>Compositor（合成器）是 Wayland 下負責把各個應用視窗的畫面合成到螢幕、同時管理視窗位置與輸入的核心程式。它一個角色承擔了舊 X11 世界裡分給多個程式的責任——畫面合成、視窗管理、輸入處理，在 Wayland 架構裡合在同一個程式。&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/" data-link-title="模組五：Hyprland 配置" data-link-desc="要在 Linux 上設定 Hyprland 平鋪式桌面時回來讀">Hyprland&lt;/a> 就是一個 Wayland compositor。&lt;/p>
&lt;p>跟 X11 的分工對照能看清它的定位。X11 時代，X server 負責畫面、一個獨立的 window manager 負責視窗排列，兩者透過協定溝通；Wayland 取消這個分家，compositor 直接兼任兩者。所以在 Wayland 語境裡，「compositor」和「window manager」常指同一個東西——Hyprland 既是 compositor 也是 tiling window manager。&lt;/p>
&lt;p>它跟桌面環境（desktop environment）是不同層次。桌面環境（GNOME、KDE）是一整套元件（面板、設定、通知、檔案管理），其中內含一個 compositor；而 Hyprland 這類「只有 compositor」的方案不含那圈桌面服務，面板、啟動器、鎖屏都要另外自己接。這條「整合度 vs 自己組裝」的軸線，是&lt;a href="https://tarrragon.github.io/blog/linux/tools/gui/desktop-environment-selection/" data-link-title="桌面環境選型：整合度與組裝自由度的取捨" data-link-desc="從 Windows/macOS 轉來或要挑第一個 Linux 桌面、在 GNOME / KDE / Hyprland / XFCE / Cinnamon 之間拿不定、想知道各自的定位與代價（資源、客製自由、穩定性、Wayland 支援）時回來讀">桌面環境選型&lt;/a>的主題。&lt;/p>
&lt;p>compositor 在故障排除中是一個關鍵的責任邊界，因為多個系統狀態由它持有、而非別的層：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>它握著 DRM master&lt;/strong>：直接畫到顯示裝置的獨佔權由 compositor 持有，這是為什麼 compositor 必須從實體圖形 VT 起、不能從 SSH pty 起（SSH 連線裡沒有那個 seat 與 DRM 資源），也是為什麼它跟同樣要畫到 DRM 的 &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/tty/" data-link-title="TTY" data-link-desc="恢復操作提到切 TTY 但不知道 TTY 是什麼時讀 — Linux 核心直接提供的純文字終端機介面">kmscon 之類 userspace console&lt;/a> 會相衝。&lt;/li>
&lt;li>&lt;strong>它持有 session lock 狀態&lt;/strong>：Wayland 的 &lt;code>ext-session-lock&lt;/code> 鎖是 compositor 層的狀態、跟 logind 獨立，殺掉鎖屏程式 compositor 仍保持鎖定——詳見 &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/session-lock/" data-link-title="Wayland Session Lock（鎖屏安全狀態）" data-link-desc="hyprlock / swaylock 畫面卡住、pkill 後進不了桌面、或要在 VM / 自動化環境測試鎖屏時回來讀">Session Lock&lt;/a>。&lt;/li>
&lt;li>&lt;strong>它掛了、桌面才真的黑&lt;/strong>：反過來說，只要 kernel 還活著、compositor 以外的東西壞了，&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/tty/" data-link-title="TTY" data-link-desc="恢復操作提到切 TTY 但不知道 TTY 是什麼時讀 — Linux 核心直接提供的純文字終端機介面">TTY&lt;/a> 仍能登入操作。判斷「畫面黑」是 compositor 掛了、還是沒 getty、還是顯示輸出沒接，是桌面故障排除的第一個分岔。&lt;/li>
&lt;/ul>
&lt;p>相關概念：&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/tty/" data-link-title="TTY" data-link-desc="恢復操作提到切 TTY 但不知道 TTY 是什麼時讀 — Linux 核心直接提供的純文字終端機介面">TTY&lt;/a>（不依賴 compositor 的救生通道）、&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/session-lock/" data-link-title="Wayland Session Lock（鎖屏安全狀態）" data-link-desc="hyprlock / swaylock 畫面卡住、pkill 後進不了桌面、或要在 VM / 自動化環境測試鎖屏時回來讀">Session Lock&lt;/a>（compositor 持有的鎖定狀態）、&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/rice/" data-link-title="Rice（桌面視覺客製化）" data-link-desc="Linux 桌面文章裡看到 rice / ricing / ricer 不確定意思時回來讀">Rice&lt;/a>（在 compositor 上做視覺客製）。&lt;/p></description><content:encoded><![CDATA[<p>Compositor（合成器）是 Wayland 下負責把各個應用視窗的畫面合成到螢幕、同時管理視窗位置與輸入的核心程式。它一個角色承擔了舊 X11 世界裡分給多個程式的責任——畫面合成、視窗管理、輸入處理，在 Wayland 架構裡合在同一個程式。<a href="/blog/linux/dotfile/05-hyprland-config/" data-link-title="模組五：Hyprland 配置" data-link-desc="要在 Linux 上設定 Hyprland 平鋪式桌面時回來讀">Hyprland</a> 就是一個 Wayland compositor。</p>
<p>跟 X11 的分工對照能看清它的定位。X11 時代，X server 負責畫面、一個獨立的 window manager 負責視窗排列，兩者透過協定溝通；Wayland 取消這個分家，compositor 直接兼任兩者。所以在 Wayland 語境裡，「compositor」和「window manager」常指同一個東西——Hyprland 既是 compositor 也是 tiling window manager。</p>
<p>它跟桌面環境（desktop environment）是不同層次。桌面環境（GNOME、KDE）是一整套元件（面板、設定、通知、檔案管理），其中內含一個 compositor；而 Hyprland 這類「只有 compositor」的方案不含那圈桌面服務，面板、啟動器、鎖屏都要另外自己接。這條「整合度 vs 自己組裝」的軸線，是<a href="/blog/linux/tools/gui/desktop-environment-selection/" data-link-title="桌面環境選型：整合度與組裝自由度的取捨" data-link-desc="從 Windows/macOS 轉來或要挑第一個 Linux 桌面、在 GNOME / KDE / Hyprland / XFCE / Cinnamon 之間拿不定、想知道各自的定位與代價（資源、客製自由、穩定性、Wayland 支援）時回來讀">桌面環境選型</a>的主題。</p>
<p>compositor 在故障排除中是一個關鍵的責任邊界，因為多個系統狀態由它持有、而非別的層：</p>
<ul>
<li><strong>它握著 DRM master</strong>：直接畫到顯示裝置的獨佔權由 compositor 持有，這是為什麼 compositor 必須從實體圖形 VT 起、不能從 SSH pty 起（SSH 連線裡沒有那個 seat 與 DRM 資源），也是為什麼它跟同樣要畫到 DRM 的 <a href="/blog/linux/dotfile/knowledge-cards/tty/" data-link-title="TTY" data-link-desc="恢復操作提到切 TTY 但不知道 TTY 是什麼時讀 — Linux 核心直接提供的純文字終端機介面">kmscon 之類 userspace console</a> 會相衝。</li>
<li><strong>它持有 session lock 狀態</strong>：Wayland 的 <code>ext-session-lock</code> 鎖是 compositor 層的狀態、跟 logind 獨立，殺掉鎖屏程式 compositor 仍保持鎖定——詳見 <a href="/blog/linux/dotfile/knowledge-cards/session-lock/" data-link-title="Wayland Session Lock（鎖屏安全狀態）" data-link-desc="hyprlock / swaylock 畫面卡住、pkill 後進不了桌面、或要在 VM / 自動化環境測試鎖屏時回來讀">Session Lock</a>。</li>
<li><strong>它掛了、桌面才真的黑</strong>：反過來說，只要 kernel 還活著、compositor 以外的東西壞了，<a href="/blog/linux/dotfile/knowledge-cards/tty/" data-link-title="TTY" data-link-desc="恢復操作提到切 TTY 但不知道 TTY 是什麼時讀 — Linux 核心直接提供的純文字終端機介面">TTY</a> 仍能登入操作。判斷「畫面黑」是 compositor 掛了、還是沒 getty、還是顯示輸出沒接，是桌面故障排除的第一個分岔。</li>
</ul>
<p>相關概念：<a href="/blog/linux/dotfile/knowledge-cards/tty/" data-link-title="TTY" data-link-desc="恢復操作提到切 TTY 但不知道 TTY 是什麼時讀 — Linux 核心直接提供的純文字終端機介面">TTY</a>（不依賴 compositor 的救生通道）、<a href="/blog/linux/dotfile/knowledge-cards/session-lock/" data-link-title="Wayland Session Lock（鎖屏安全狀態）" data-link-desc="hyprlock / swaylock 畫面卡住、pkill 後進不了桌面、或要在 VM / 自動化環境測試鎖屏時回來讀">Session Lock</a>（compositor 持有的鎖定狀態）、<a href="/blog/linux/dotfile/knowledge-cards/rice/" data-link-title="Rice（桌面視覺客製化）" data-link-desc="Linux 桌面文章裡看到 rice / ricing / ricer 不確定意思時回來讀">Rice</a>（在 compositor 上做視覺客製）。</p>
]]></content:encoded></item><item><title>Wayland Session Lock（鎖屏安全狀態）</title><link>https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/session-lock/</link><pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/session-lock/</guid><description>&lt;h2 id="鎖屏是-compositor-持有的安全狀態">鎖屏是 compositor 持有的安全狀態&lt;/h2>
&lt;p>Wayland 下的 compositor（如 Hyprland、Sway）同時管理視窗排列與畫面輸出。鎖屏工具（Hyprlock、Swaylock）一旦啟動，桌面的「鎖定」狀態就由 compositor 透過 ext-session-lock-v1（Wayland 生態系的跨 compositor 鎖屏協議）持有。解鎖的正常動作是鎖屏 client 通過認證後呼叫 &lt;code>unlock_and_destroy&lt;/code>（協議定義的 request），compositor 收到這個信號才釋放鎖定。&lt;/p>
&lt;p>這個責任邊界在自動化測試、VM 演練、遠端操作時最容易出事，因為這些情境常用「殺 process」當「關掉一個東西」的通用手段。殺掉鎖屏 client 跳過了認證，compositor 不會釋放鎖——畫面會卡在失效保護狀態而非回到桌面。&lt;/p>
&lt;h2 id="logind-提示與-compositor-鎖的值可以不一致">logind 提示與 compositor 鎖的值可以不一致&lt;/h2>
&lt;p>鎖屏狀態牽涉兩個獨立的層，觸發方向和持有者不同：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>層&lt;/th>
 &lt;th>持有者&lt;/th>
 &lt;th>查看方式&lt;/th>
 &lt;th>語意&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>logind 會話鎖&lt;/td>
 &lt;td>systemd-logind&lt;/td>
 &lt;td>&lt;code>loginctl show-session &amp;lt;id&amp;gt; -p LockedHint&lt;/code>&lt;/td>
 &lt;td>會話的鎖定提示，給登入管理器 / 螢幕保護程式&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>compositor 鎖&lt;/td>
 &lt;td>Wayland compositor&lt;/td>
 &lt;td>畫面是否進得去、鎖屏 surface 是否在最上層&lt;/td>
 &lt;td>實際擋住畫面的那層&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;code>loginctl lock-session&lt;/code> 走 logind 層觸發鎖屏，鎖屏 client 收到信號後啟動、再向 compositor 取得 session lock。觸發方向是 logind → client → compositor；持有與強制執行方向是 compositor → 畫面。兩者方向相反，正好印證兩層是獨立的。&lt;/p>
&lt;p>實測會遇到 &lt;code>LockedHint=no&lt;/code>（logind 層說沒鎖）但畫面仍進不去——因為擋住畫面的是 compositor 的 ext-session-lock，跟 logind 提示是兩回事。判斷畫面進不進得去，看 compositor 層，不看 logind 層。&lt;/p>
&lt;h2 id="鎖屏-client-非正常結束時的失效保護">鎖屏 client 非正常結束時的失效保護&lt;/h2>
&lt;p>鎖屏 client 在持有鎖的狀態下死掉（被 &lt;code>kill&lt;/code>、crash），compositor 沒有收到認證通過的信號，只能維持鎖定並顯示失效保護畫面。Hyprland 的失效保護畫面會直接給恢復指令：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">hyprctl --instance 0 &amp;#39;keyword misc:allow_session_lock_restore 1&amp;#39;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">hyprctl --instance 0 &amp;#39;dispatch exec hyprlock&amp;#39;&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>allow_session_lock_restore&lt;/code> 允許新的鎖屏 client 接管既有的鎖（否則新 client 會因「已經鎖了」被拒）。接管後是乾淨的鎖屏 prompt，用密碼正常解鎖。&lt;/p>
&lt;p>備好 restore 路徑時，殺掉無回應的鎖屏 client 是合理操作——問題不在「殺」、在「以為殺完就回桌面」。restore 的前提是有另一個可操作的 session：另一個 TTY 或 SSH 連線。ext-session-lock 的安全語意允許 compositor 攔截 VT 切換快捷鍵（&lt;code>Ctrl+Alt+Fn&lt;/code>），遇到 TTY 切不過去的情況，SSH 是替代救援通道（事先配好 SSH server，見&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/07-desktop-maintenance/common-failures-recovery/" data-link-title="常見故障場景與恢復操作" data-link-desc="Hyprland 黑屏、waybar 消失、畫面凍結、記憶體爆掉或 config 寫錯導致進不了桌面時，按症狀查恢復操作">常見故障場景與恢復操作&lt;/a>的 GPU hang 段）。&lt;/p>
&lt;h2 id="判讀與操作">判讀與操作&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>判讀鎖定狀態&lt;/strong>：&lt;code>loginctl show-session $(loginctl show-user $USER -p Display --value) -p LockedHint&lt;/code> 查 logind 層；compositor 層看畫面能否操作。兩層不一致時以 compositor 層為準。&lt;/li>
&lt;li>&lt;strong>正常解鎖&lt;/strong>：通過鎖屏 client 的認證（密碼 / 指紋），client 呼叫 &lt;code>unlock_and_destroy&lt;/code>，compositor 釋放鎖。&lt;/li>
&lt;li>&lt;strong>失效保護恢復&lt;/strong>：從另一個 TTY 或 SSH 執行 &lt;code>hyprctl --instance 0 'keyword misc:allow_session_lock_restore 1'&lt;/code> + &lt;code>hyprctl --instance 0 'dispatch exec hyprlock'&lt;/code>，重新拉起鎖屏 prompt 後認證解鎖。&lt;/li>
&lt;li>&lt;strong>自動化流程的代價&lt;/strong>：啟動鎖屏後，畫面會留在鎖定狀態直到有人通過認證。自動化測試若會觸發鎖屏，要把「需人工解鎖」算進代價。&lt;/li>
&lt;li>&lt;strong>診斷路由&lt;/strong>：「畫面卡住 / 螢幕鎖了沒」當成一般 Linux 狀態判讀問題（跟判程式活著、判服務歸屬同類）時，見&lt;a href="https://tarrragon.github.io/blog/linux/debug/process-service-state-diagnosis/" data-link-title="程序、服務與狀態怎麼判" data-link-desc="要判斷一個程式活著沒、某個系統服務現在由誰提供、桌面 session 有沒有被鎖、或終端機多工器的 session 還在不在時，用對的權威來源而不是靠畫面或猜的名字">程序、服務與狀態怎麼判&lt;/a>——它把「判 session 有沒有被鎖」放進「讀權威狀態、別看畫面猜」的通用診斷紀律裡。&lt;/li>
&lt;li>&lt;strong>延伸閱讀&lt;/strong>：鎖屏的視覺配置（背景、輸入框、時鐘 label）見&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/06-rice-design/color-system-theming/" data-link-title="配色系統、鎖屏與 GTK 主題" data-link-desc="桌面配色散亂看起來雜、或要換主題不知道該改哪些檔案時回來讀">配色系統、鎖屏與 GTK 主題&lt;/a>的 Hyprlock 段；桌面故障恢復流程見&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/07-desktop-maintenance/common-failures-recovery/" data-link-title="常見故障場景與恢復操作" data-link-desc="Hyprland 黑屏、waybar 消失、畫面凍結、記憶體爆掉或 config 寫錯導致進不了桌面時，按症狀查恢復操作">常見故障場景與恢復操作&lt;/a>。持鎖的那個 compositor 到底是什麼、還握著哪些系統狀態，見 &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/compositor/" data-link-title="Compositor（合成器）" data-link-desc="教材反覆出現 compositor / 合成器、想確認它到底負責什麼、跟 window manager 和桌面環境差在哪時讀 — Wayland 下把畫面合成與視窗管理合一的核心程式">Compositor 術語卡&lt;/a>。&lt;/li>
&lt;/ul>
&lt;h2 id="邊界條件">邊界條件&lt;/h2>
&lt;p>正常認證解鎖（走 &lt;code>unlock_and_destroy&lt;/code>）後鎖屏 client 結束，compositor 已回到非鎖定狀態，不觸發失效保護。失效保護只在「持鎖中非正常結束」時出現。&lt;/p></description><content:encoded><![CDATA[<h2 id="鎖屏是-compositor-持有的安全狀態">鎖屏是 compositor 持有的安全狀態</h2>
<p>Wayland 下的 compositor（如 Hyprland、Sway）同時管理視窗排列與畫面輸出。鎖屏工具（Hyprlock、Swaylock）一旦啟動，桌面的「鎖定」狀態就由 compositor 透過 ext-session-lock-v1（Wayland 生態系的跨 compositor 鎖屏協議）持有。解鎖的正常動作是鎖屏 client 通過認證後呼叫 <code>unlock_and_destroy</code>（協議定義的 request），compositor 收到這個信號才釋放鎖定。</p>
<p>這個責任邊界在自動化測試、VM 演練、遠端操作時最容易出事，因為這些情境常用「殺 process」當「關掉一個東西」的通用手段。殺掉鎖屏 client 跳過了認證，compositor 不會釋放鎖——畫面會卡在失效保護狀態而非回到桌面。</p>
<h2 id="logind-提示與-compositor-鎖的值可以不一致">logind 提示與 compositor 鎖的值可以不一致</h2>
<p>鎖屏狀態牽涉兩個獨立的層，觸發方向和持有者不同：</p>
<table>
  <thead>
      <tr>
          <th>層</th>
          <th>持有者</th>
          <th>查看方式</th>
          <th>語意</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>logind 會話鎖</td>
          <td>systemd-logind</td>
          <td><code>loginctl show-session &lt;id&gt; -p LockedHint</code></td>
          <td>會話的鎖定提示，給登入管理器 / 螢幕保護程式</td>
      </tr>
      <tr>
          <td>compositor 鎖</td>
          <td>Wayland compositor</td>
          <td>畫面是否進得去、鎖屏 surface 是否在最上層</td>
          <td>實際擋住畫面的那層</td>
      </tr>
  </tbody>
</table>
<p><code>loginctl lock-session</code> 走 logind 層觸發鎖屏，鎖屏 client 收到信號後啟動、再向 compositor 取得 session lock。觸發方向是 logind → client → compositor；持有與強制執行方向是 compositor → 畫面。兩者方向相反，正好印證兩層是獨立的。</p>
<p>實測會遇到 <code>LockedHint=no</code>（logind 層說沒鎖）但畫面仍進不去——因為擋住畫面的是 compositor 的 ext-session-lock，跟 logind 提示是兩回事。判斷畫面進不進得去，看 compositor 層，不看 logind 層。</p>
<h2 id="鎖屏-client-非正常結束時的失效保護">鎖屏 client 非正常結束時的失效保護</h2>
<p>鎖屏 client 在持有鎖的狀態下死掉（被 <code>kill</code>、crash），compositor 沒有收到認證通過的信號，只能維持鎖定並顯示失效保護畫面。Hyprland 的失效保護畫面會直接給恢復指令：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">hyprctl --instance 0 &#39;keyword misc:allow_session_lock_restore 1&#39;
</span></span><span class="line"><span class="ln">2</span><span class="cl">hyprctl --instance 0 &#39;dispatch exec hyprlock&#39;</span></span></code></pre></div><p><code>allow_session_lock_restore</code> 允許新的鎖屏 client 接管既有的鎖（否則新 client 會因「已經鎖了」被拒）。接管後是乾淨的鎖屏 prompt，用密碼正常解鎖。</p>
<p>備好 restore 路徑時，殺掉無回應的鎖屏 client 是合理操作——問題不在「殺」、在「以為殺完就回桌面」。restore 的前提是有另一個可操作的 session：另一個 TTY 或 SSH 連線。ext-session-lock 的安全語意允許 compositor 攔截 VT 切換快捷鍵（<code>Ctrl+Alt+Fn</code>），遇到 TTY 切不過去的情況，SSH 是替代救援通道（事先配好 SSH server，見<a href="/blog/linux/dotfile/07-desktop-maintenance/common-failures-recovery/" data-link-title="常見故障場景與恢復操作" data-link-desc="Hyprland 黑屏、waybar 消失、畫面凍結、記憶體爆掉或 config 寫錯導致進不了桌面時，按症狀查恢復操作">常見故障場景與恢復操作</a>的 GPU hang 段）。</p>
<h2 id="判讀與操作">判讀與操作</h2>
<ul>
<li><strong>判讀鎖定狀態</strong>：<code>loginctl show-session $(loginctl show-user $USER -p Display --value) -p LockedHint</code> 查 logind 層；compositor 層看畫面能否操作。兩層不一致時以 compositor 層為準。</li>
<li><strong>正常解鎖</strong>：通過鎖屏 client 的認證（密碼 / 指紋），client 呼叫 <code>unlock_and_destroy</code>，compositor 釋放鎖。</li>
<li><strong>失效保護恢復</strong>：從另一個 TTY 或 SSH 執行 <code>hyprctl --instance 0 'keyword misc:allow_session_lock_restore 1'</code> + <code>hyprctl --instance 0 'dispatch exec hyprlock'</code>，重新拉起鎖屏 prompt 後認證解鎖。</li>
<li><strong>自動化流程的代價</strong>：啟動鎖屏後，畫面會留在鎖定狀態直到有人通過認證。自動化測試若會觸發鎖屏，要把「需人工解鎖」算進代價。</li>
<li><strong>診斷路由</strong>：「畫面卡住 / 螢幕鎖了沒」當成一般 Linux 狀態判讀問題（跟判程式活著、判服務歸屬同類）時，見<a href="/blog/linux/debug/process-service-state-diagnosis/" data-link-title="程序、服務與狀態怎麼判" data-link-desc="要判斷一個程式活著沒、某個系統服務現在由誰提供、桌面 session 有沒有被鎖、或終端機多工器的 session 還在不在時，用對的權威來源而不是靠畫面或猜的名字">程序、服務與狀態怎麼判</a>——它把「判 session 有沒有被鎖」放進「讀權威狀態、別看畫面猜」的通用診斷紀律裡。</li>
<li><strong>延伸閱讀</strong>：鎖屏的視覺配置（背景、輸入框、時鐘 label）見<a href="/blog/linux/dotfile/06-rice-design/color-system-theming/" data-link-title="配色系統、鎖屏與 GTK 主題" data-link-desc="桌面配色散亂看起來雜、或要換主題不知道該改哪些檔案時回來讀">配色系統、鎖屏與 GTK 主題</a>的 Hyprlock 段；桌面故障恢復流程見<a href="/blog/linux/dotfile/07-desktop-maintenance/common-failures-recovery/" data-link-title="常見故障場景與恢復操作" data-link-desc="Hyprland 黑屏、waybar 消失、畫面凍結、記憶體爆掉或 config 寫錯導致進不了桌面時，按症狀查恢復操作">常見故障場景與恢復操作</a>。持鎖的那個 compositor 到底是什麼、還握著哪些系統狀態，見 <a href="/blog/linux/dotfile/knowledge-cards/compositor/" data-link-title="Compositor（合成器）" data-link-desc="教材反覆出現 compositor / 合成器、想確認它到底負責什麼、跟 window manager 和桌面環境差在哪時讀 — Wayland 下把畫面合成與視窗管理合一的核心程式">Compositor 術語卡</a>。</li>
</ul>
<h2 id="邊界條件">邊界條件</h2>
<p>正常認證解鎖（走 <code>unlock_and_destroy</code>）後鎖屏 client 結束，compositor 已回到非鎖定狀態，不觸發失效保護。失效保護只在「持鎖中非正常結束」時出現。</p>
<p>Sway/swaylock 在 client 死掉時沒有畫面上的恢復提示（不像 Hyprland 會印指令），得預先知道走 TTY 或 SSH 執行 restore。「鎖是 compositor 持有、解鎖要認證」是 ext-session-lock 協議層的共通約束；失效保護的具體呈現方式因 compositor 而異。</p>
]]></content:encoded></item></channel></rss>