免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Eww(ElKowar‘s Wacky Widgets)入门指南:在任意窗口管理器上构建自绘 Widget 系统

Eww(ElKowar‘s Wacky Widgets)入门指南:在任意窗口管理器上构建自绘 Widget 系统 EwwElKowars Wacky Widgets入门指南在任意窗口管理器上构建自绘 Widget 系统【免费下载链接】ewwElKowars wacky widgets项目地址: https://gitcode.com/gh_mirrors/ew/ewwEwwElKowars Wacky Widgets是一个基于 Rust 编写的独立 Widget 系统它让你可以像在 AwesomeWM 中那样自由创建自定义小组件而其关键优势在于与窗口管理器WM完全解耦——无论你使用 i3、bspwm、Hyprland 还是 KDE都能用同一套配置构建状态栏、桌面小组件或悬浮面板。本文以仓库根目录的 README.md 为骨架结合 docs/src/eww.md、docs/src/configuration.md 与源码实现完整讲解 Eww 的安装构建、yuck 配置语言、窗口与组件定义、动态变量体系以及命令行操作读完后你将能够独立搭建一套属于自己的 Eww Widget 环境。什么是 EwwEww 是ElKowars Wacky Widgets的缩写是一个用 Rust 编写的独立 Widget 系统允许你在任意窗口管理器中实现完全自定义的组件。它的核心理念与 AwesomeWM 类似但有一个本质区别它不依赖任何特定的窗口管理器。从仓库的 crates/eww/Cargo.toml 可以看到Eww 当前版本为0.6.0基于 GTK3 构建并针对 X11 与 Wayland 分别提供后端支持[features] default [x11, wayland] x11 [gdkx11, x11rb] wayland [gtk-layer-shell]X11 后端依赖gdkx11与x11rb后者带有randr特性用于多显示器管理Wayland 后端依赖gtk-layer-shell通过 Layer Shell 协议实现层叠窗口效果。整个项目是一个 Cargo workspace由多个 crate 组成其职责划分可以从根目录的 Cargo.toml 中看出crate作用crates/eww主程序包含 CLI、daemon、窗口管理与 widget 构建逻辑crates/yuckyuck 配置语言的解析器与 AST 处理crates/simplexpr内嵌的表达式语言用于{ ... }与${ ... }crates/notifier_host系统托盘systray的 StatusNotifier 宿主实现crates/eww_shared_util共享工具如 VarName、Span 等安装与构建前置依赖安装 Eww 需要rustc与cargo。官方文档强烈建议使用 rustup 安装 Rust 工具链而不是依赖系统包管理器提供的版本。此外Eww 在编译和运行时尚需若干动态库。不同发行版的包名可能不同以下是 Arch Linux 上对应的包名清单gtk3提供libgdk-3、libgtk-3gtk-layer-shell仅 Wayland 需要pangolibpangogdk-pixbuf2libgdk_pixbuf-2libdbusmenu-gtk3cairolibcairo、libcairo-gobjectglib2libgio、libglib-2、libgobject-2gcc-libslibgccglibc注意编译 Eww 时通常还需要对应发行版的-devel变体包包含头文件。编译与运行git clone https://github.com/elkowar/eww cd eww cargo build --release --no-default-features --features x11如果你使用 Wayland请改用以下命令构建cargo build --release --no-default-features --featureswayland构建完成后进入输出目录并赋予可执行权限cd target/release chmod x ./eww然后启动 daemon 并打开窗口./eww daemon ./eww open window_name这里的eww daemon会在后台启动常驻进程可在 crates/eww/src/opts.rs 的Action枚举中看到daemon子命令别名deww open则通知 daemon 渲染并显示指定窗口。编写 Eww 配置Eww 使用自研的yuck配置语言基于 S 表达式与 Lisp 系语言类似声明组件结构、窗口几何与行为以及动态数据。样式则使用CSS/SCSS定义。由于 Eww 依赖 GTK 自己的 CSS 引擎Web 上常见的 CSS 并非全部支持——动画特性以及大部分布局相关属性如 flexbox、float、绝对定位、width/height不受支持。配置需要两个文件eww.yuck与eww.scss也可以叫eww.css它们必须放在$XDG_CONFIG_HOME/eww下通常是~/.config/eww。仓库中的 examples/eww-bar/eww.yuck 与 examples/eww-bar/eww.scss 提供了一个完整可运行的状态栏示例下文将反复引用它。创建第一个窗口窗口是 Eww 的顶层容器你需要用defwindow定义它的名称、位置、几何与内容(defwindow example :monitor 0 :geometry (geometry :x 0% :y 20px :width 90% :height 30px :anchor top center) :stacking fg :reserve (struts :distance 40px :side top) :windowtype dock :wm-ignore false example content)定义完成后运行eww open example即可打开窗口。在 examples/eww-bar/eww.yuck 中可以看到一个真实的状态栏窗口定义——它使用了:monitor 0、dock窗口类型、struts预留空间reserve并将bar组件渲染为内容。defwindow属性一览属性说明monitor窗口显示在哪个显示器上详见下方说明geometry窗口的几何信息unfocus-close窗口失去键盘焦点时自动关闭monitor属性支持以下取值字符串primary让 Eww 尝试识别主显示器在 Wayland 上可能失败整数显示器索引显示器名称包含显示器匹配器 JSON 数组的字符串如[primary, HDMI-A-1, PHL 345B1C, 0]Eww 会按顺序尝试匹配并提供回退。geometry属性属性说明x、y窗口位置支持px或%相对于anchor计算width、height窗口尺寸支持px或%anchor窗口锚点取值为center或top/center/bottom与left/center/right的组合平台相关属性根据 X11 或 Waylanddefwindow还支持额外属性。X11 专属属性说明stacking窗口在层叠中的位置取值fg、bgwm-ignore是否让窗口管理器忽略该窗口适合仪表盘式组件true/false注意开启后部分其他属性将失效reserve让窗口管理器为窗口预留空间适合状态栏避免与其他窗口重叠windowtype窗口类型取值normal、dock、toolbar、dialog、desktop默认值为指定了reserve时为dock否则为normalWayland 专属属性说明stacking层叠位置取值fg、bg、overlay、bottomexclusive合成器是否自动为窗口预留空间true/false为true时:anchor必须包含centerfocusable窗口是否可聚焦取值none、exclusive、ondemand使用键盘交互的组件必须开启namespace设置 Wayland Layer Shell 的 namespace接受字符串定义自己的 Widget窗口内容由 widget 组成。用defwidget定义带参数的自定义组件(defwidget greeter [?text name] (box :orientation horizontal :halign center text (button :onclick notify-send Hello Hello, ${name} Greet)))然后在窗口中调用它(defwindow example ; ... 其他属性省略 (greeter :text Say hello! :name Tim))几个要点greeter接收两个属性text与name。?text声明该属性可选缺省时值为空字符串而name必须提供widget 定义体只能包含一个顶层 widget否则 Eww 无法确定排列方向与间距因此多子元素时必须用box包裹onclick中的${name}是字符串插值语法可以在字符串中引用任意变量${...}内还能写完整的表达式详见 docs/src/expression_language.md官方文档位置为docs/src/expression_language.md对应线上章节 Eww expressions。渲染子组件children占位符当配置变大时可以把通用结构抽成可复用的包裹型组件它也能像box、button一样接收子元素(defwidget labeled-container [name] (box :class container name (children)))使用方式(labeled-container :name foo (button :onclick notify-send hey ho click me))更复杂的结构可以用nth属性引用特定位置的子元素(defwidget two-boxes [] (box (box :class first (children :nth 0)) (box :class second (children :nth 1))))添加动态内容Eww 的变量体系Eww 的变量是全局可见的一旦变量值改变引用它的 widget 会自动刷新。变量分为四类基础变量、轮询变量、监听变量和内建 magic 变量。基础变量defvar(defvar foo initial value)基础变量不会自动变化必须显式通过eww update foonew value更新。适合低频变化、由外部脚本驱动的值也可以让组件内的按钮通过onclick调用eww update来改变界面内容。轮询变量defpoll(defvar time-visible false) ; 配合下方 :run-while 使用 ; 当它变为 true 时才开始轮询并更新 (defpoll time :interval 1s :initial initial-value ; 可选默认启动时立即轮询 :run-while time-visible ; 可选默认 true date %H:%M:%S)轮询变量按固定间隔反复执行提供的 shell 脚本是展示时间、日期、待更新软件包数量、天气、电量等信息的最常用类型。initial初始值可以避免启动时等待命令返回加快启动速度。除了eww update外部赋值外还可以用eww poll在常规间隔之外强制轮询即使变量当前未在轮询。在 examples/eww-bar/eww.yuck 中可以看到实际用法——用defpoll每 1 秒执行scripts/getvol获取音量、每 10 秒执行date获取时间。监听变量deflisten(deflisten foo :initial whatever tail -F /tmp/some_file)监听变量只运行一次脚本然后持续读取其输出每当脚本输出新的一行变量值就更新为该行。上述例子中foo初始为whatever之后每当/tmp/some_file追加新行即更新。监听变量适合需要即时响应变化且脚本自身能持续监控的场景例如音量、亮度、运行时增删的 workspace、当前聚焦的桌面/标签等。它非常高效应当优先使用。文档中给出的典型命令有xprop -spy -root _NET_CURRENT_DESKTOP监听当前桌面变化playerctl --follow metadata --format {{title}}监听正在播放的歌曲。examples/eww-bar/eww.yuck 中的music变量即用deflistenplayerctl --follow实现实时歌名展示。内建 magic 变量Eww 开箱即用地提供一些系统变量如 CPU、内存使用率多数以 JSON 形式承载数据可用 JSON 访问语法取值如示例中的EWW_RAM.used_mem_perc、EWW_DISK[/].free。完整的 magic 变量列表见 docs/src/magic-vars.md。用literal动态生成组件树当需要动态生成整个组件结构而非仅仅改变文本、颜色时例如展示数量未知的通知列表可以使用literal组件(defvar variable_containing_yuck (box (button foo) (button bar))) ; 然后在组件内使用 (literal :content variable_containing_yuck)literal接收一个包含单个 yuck 组件树的字符串Eww 会解析并渲染它内容变化时自动重渲染。注意此功能效率不高仅在必要时使用。窗口 ID 与窗口参数当需要用一个窗口配置生成多个实例时例如每个显示器一个状态栏ID 与参数系统非常有用。窗口 IDopen命令可通过--id指定 ID缺省时 ID 为窗口配置名eww open my_bar --screen 0 --id primary eww open my_bar --screen 1 --id secondaryopen-many使用名称:ID的结构省略 ID 时同样回退为配置名eww open-many my_config:primary my_config:secondary窗口参数参数用于让同一配置的多个窗口呈现差异如 1080p 与 4K 屏幕用不同 class、不同尺寸或位置。注意这些参数在窗口打开后是常量无法更新。窗口定义参数的方式与 widget 完全相同(defwindow my_bar [arg1 ?arg2] :geometry (geometry :x 0% :y 6px :width 100% :height { arg1 small ? 30px : 40px } :anchor top center) :stacking bg :windowtype dock :reserve (struts :distance 50px :side top) (my_widget :arg2 arg2))打开时用--arg传参可选参数可省略eww open my_bar --id primary --arg arg1some_value --arg arg2another_valueopen-many的写法是注意--arg必须放在所有窗口名之后# 注意--arg 必须放在所有窗口名称之后 eww open-many my_bar:primary --arg primary:arg1some_value --arg primary:arg2another_value在open命令中--screen、--anchor、--pos、--size等选项的效果也可以通过把同名参数写进--arg来实现。另外有两个特殊参数id若参数列表中出现id会被设置为--id指定的值缺省为配置名可在 Eww 命令中用它关闭当前窗口screen若指定screen会被设置为--screen的值供其他组件访问屏幕相关信息。open-many参数的更多细节open-many的--arg不要求每个参数都带 ID 前缀——不带 ID 的参数会应用到所有窗口eww open-many my_bar:primary my_bar:secondary --arg gui_sizesmall如果窗口没有显式指定 ID即 ID 回退为配置名也可以用配置名来定向传参eww open-many my_primary_bar --arg my_primary_bar:screen0从源码 crates/eww/src/opts.rs 可以看出open-many的窗口参数以(String, String, VarName, DynVal)四元组形式解析而parse_window_config_and_id使用split_once(:)解析名称:ID未含冒号时 ID 回退为名称本身见 crates/eww/src/opts.rs。用for从 JSON 生成组件列表如需展示一组值可用for元素从 JSON 数组生成子组件列表(defvar my-json [1, 2, 3]) ; 然后在组件内使用 (box (for entry in my-json (button :onclick notify-send click button ${entry} entry)))这在从 JSON 生成 workspace 列表等场景非常有用多数情况下可以替代literal且应优先使用。更复杂的数据结构示例见 examples/data-structures/eww.yuck。拆分你的配置配置变大后可以拆分成多个文件有两种方式使用include(include ./path/to/your/file.yuck)单个 yuck 文件可以用include指令导入任意其他 yuck 文件的内容。使用独立的配置目录如果希望进一步分离不同 widget 集合可以创建独立配置目录然后给每一个Eww 命令都加上--config /path/to/your/config/dir参数包括eww kill、eww logs等。这会在主配置之外启动一个拥有独立日志与状态的 daemon 实例。该参数在 crates/eww/src/opts.rs 中被定义为全局参数override path to configuration directory (directory that contains eww.yuck and eww.(s)css)。表达式语言速览yuck 内置一套表达式语言可放在配置中任意{ ... }位置或字符串插值foo ${ ... } bar内用于条件判断、数学运算与 JSON 访问。示例(box Some math: ${12 foo * 10} (button :class {button_active ? active : inactive} :onclick toggle_thing {button_active ? disable : enable}))支持的特性包括数学运算、-、*、/、%比较、!、、、、布尔运算||、、!正则匹配~Rust 正则风格左侧为正则、右侧为字符串如workspace.name ~ ^special:.$Elvis 运算符?:左侧为或 JSONnull时返回右侧否则返回左侧安全访问运算符?./?.[index]左侧为空字符串或 JSONnull时返回null注意对空 JSON 字符串做索引是错误且若左侧存在但不是对象/数组如 Number、String仍会报错条件表达式condition ? value : other value字面量与变量引用12、hi、true、some_variableJSON 访问object.field、array[12]、object[field]需要变量持有合法的 JSON 字符串常用函数包括round、floor、ceil、三角函数弧度制、min/max、powi/powf、log、degtorad/radtodeg、replace/search/matches/captures、strlength/arraylength/objectlength、jq内部基于 jaq、get_env、formattime与formatbytes。完整函数签名与参数说明见 docs/src/expression_language.md。Eww 命令行速查从 crates/eww/src/opts.rs 的Action枚举可以确认当前版本完整的子命令集合其中常用的包括命令别名作用eww daemond启动 Eww 常驻 daemoneww openo打开窗口支持--id、--screen、--pos、--size、--anchor、--toggle、--duration、--argeww open-many-一次打开多个窗口eww closec关闭窗口eww close-allca关闭所有窗口不杀 daemoneww updateu更新变量值eww poll-强制轮询轮询变量eww reloadr重载配置eww killk终止 daemoneww logs-查看并跟踪 Eww 日志eww state-打印当前所有打开的窗口使用的变量--all显示全部eww get-获取变量值eww list-windows-列出已配置窗口名eww active-windows-以window_id: window_name格式显示活动窗口 IDeww ping-探测 Eww server 是否可达eww inspectordebugger打开 GTK 调试器eww debug-打印 Eww 眼中的组件树结构排障、报 bug 时提供上下文eww graph-以 graphviz dot 格式输出 scope graph 结构全局参数还包括--debug输出调试日志、--force-wayland强制使用 Wayland 后端、--config指定配置目录、--logs执行命令后跟随日志输出、--no-daemonize不进行 daemon 化与--restart执行命令前完全重启 daemon。进阶阅读docs/src/configuration.mdyuck 配置语言的完整参考窗口属性、变量、literal、for、include等docs/src/expression_language.md表达式语言全量函数与运算符说明docs/src/widgets.md内建组件box、label、button、scale等文档docs/src/magic-vars.md内建 magic 变量列表docs/src/working_with_gtk.mdGTK 主题化技巧docs/src/troubleshooting.md常见问题排查examples/eww-bar/eww.yuck 与 examples/eww-bar/eww.scss完整的状态栏示例含 SCSS 样式examples/data-structures/eww.yuckJSON 数据结构在配置中的应用示例另外Eww 采用 MIT 许可证见根目录 LICENSE版本演进记录见 CHANGELOG.md。【免费下载链接】ewwElKowars wacky widgets项目地址: https://gitcode.com/gh_mirrors/ew/eww创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表