写桌面小部件经常是一件繁琐的事:要处理窗口、事件循环,还要靠轮询拉状态,最后用一堆 bash 脚本把 UI 粘起来。Fabric 换了个思路:用 Python 定义部件,用信号驱动更新。本文从一个具体问题切入,记录它的信号工作流、取舍和可复现的启动配置片段。

它解决什么问题
Fabric 是一个 Python 的桌面小部件系统,目标明确:提供高级的、基于信号的工作流,让基本任务不再依赖轮询或 bash 脚本。
- 跨平台:支持 X11 和 Wayland。
- Python 集成:直接复用 Python 生态里的模块。
- 开发者体验:类型支持完整,代码可读性和可维护性都更好。
- 资源占用低:设计上刻意控制开销。
- 用 Python 代码替代 shell 脚本:减少资源密集的 bash 调用,维护也简单。
信号式工作流
Fabric 的事件处理基于信号。信号定义在 __gsignals__ 里,传入 SignalContainer,里面包着 Signal 对象。信号需要指定名称、运行标志、回调返回值类型和参数类型。
这段代码是可复现的最小示例:
from fabric.service import *
class MyUsefulService(Service):
__gsignals__ = SignalContainer(
Signal("my-really-useful-signal", "run-first", None, (object,))
# 信号名称,运行标志,回调函数返回值,回调函数参数类型
)
def __init__(self):
self.emit("my-really-useful-signal", "this is my super useful argument")
注意:继承 Service 类时,用 @Property(来自 fabric.service)替代 @property 装饰器,属性才是可通知的。
核心组件:Widget 和 Service
Fabric 的构建块是 Widget 和 Service。
- Widget:核心基类是
Widget(fabric.widgets.widget),其他 Widget 都继承它。改基类属性或方法,所有子类跟着变,维护成本低。 - Service:新服务应该继承
Service基类,用来封装状态和信号。
写 Widget 之前先查 GTK
如果 GTK 已经实现了你需要的 Widget,直接用,或者把它“Fabric化”。
直接使用 GTK Widget 简单方便,但失去 Fabric 特性,比如在构造函数里设置样式。Fabric化之后就能用整套 Fabric API。
普通 Widget 的 Fabric 化,继承 Widget 基类:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from fabric.widgets.widget import Widget
class MyFabricatedWidget(Gtk.MyWidget, Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
容器 Widget 则继承 Container 基类。
取舍
原文没有提供 Bar 与 Widget 的取舍说明。不过原文明确指出了另一组取舍:直接使用 GTK Widget,还是将其 Fabric 化。
- 直接使用:上手快,但没法用 Fabric 的构造期样式和信号机制。
- Fabric 化:要写继承关系,但换来统一的对象模型和完整的 Fabric 能力。
适用场景:想避开轮询和 bash,用 Python 统一逻辑,能接受学习信号机制的成本。不适用场景:原文未提供。Fabric 目前还在开发阶段,稳定性需要自己评估。
配置启动
原文只提到要准备开发环境:读文档、装依赖、配工具。具体的启动命令和配置文件原文未提供。上面的信号定义和 Widget 继承片段可以作为入手的最小骨架。
项目地址:https://github.com/Fabric-Development/fabric